github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go (about) 1 // Copyright 2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package dfunctions 16 17 import ( 18 "fmt" 19 20 "github.com/dolthub/go-mysql-server/sql" 21 "github.com/dolthub/go-mysql-server/sql/expression" 22 23 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" 24 "github.com/dolthub/dolt/go/libraries/doltcore/merge" 25 "github.com/dolthub/dolt/go/libraries/doltcore/sqle" 26 ) 27 28 const DoltMergeBaseFuncName = "dolt_merge_base" 29 30 type MergeBase struct { 31 expression.BinaryExpression 32 } 33 34 // NewMergeBase returns a MergeBase sql function. 35 func NewMergeBase(ctx *sql.Context, left, right sql.Expression) sql.Expression { 36 return &MergeBase{expression.BinaryExpression{Left: left, Right: right}} 37 } 38 39 // Eval implements the sql.Expression interface. 40 func (d MergeBase) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 41 if _, ok := d.Left.Type().(sql.StringType); !ok { 42 return nil, sql.ErrInvalidType.New(d.Left.Type()) 43 } 44 if _, ok := d.Right.Type().(sql.StringType); !ok { 45 return nil, sql.ErrInvalidType.New(d.Right.Type()) 46 } 47 48 leftSpec, err := d.Left.Eval(ctx, row) 49 if err != nil { 50 return nil, err 51 } 52 rightSpec, err := d.Right.Eval(ctx, row) 53 if err != nil { 54 return nil, err 55 } 56 57 if leftSpec == nil || rightSpec == nil { 58 return nil, nil 59 } 60 61 left, right, err := resolveRefSpecs(ctx, leftSpec.(string), rightSpec.(string)) 62 if err != nil { 63 return nil, err 64 } 65 66 mergeBase, err := merge.MergeBase(ctx, left, right) 67 if err != nil { 68 return nil, err 69 } 70 71 return mergeBase.String(), nil 72 } 73 74 func resolveRefSpecs(ctx *sql.Context, leftSpec, rightSpec string) (left, right *doltdb.Commit, err error) { 75 lcs, err := doltdb.NewCommitSpec(leftSpec) 76 if err != nil { 77 return nil, nil, err 78 } 79 rcs, err := doltdb.NewCommitSpec(rightSpec) 80 if err != nil { 81 return nil, nil, err 82 } 83 84 sess := sqle.DSessFromSess(ctx.Session) 85 dbName := ctx.GetCurrentDatabase() 86 87 dbData, ok := sess.GetDbData(dbName) 88 if !ok { 89 return nil, nil, sql.ErrDatabaseNotFound.New(dbName) 90 } 91 doltDB, ok := sess.GetDoltDB(dbName) 92 if !ok { 93 return nil, nil, sql.ErrDatabaseNotFound.New(dbName) 94 } 95 96 left, err = doltDB.Resolve(ctx, lcs, dbData.Rsr.CWBHeadRef()) 97 if err != nil { 98 return nil, nil, err 99 } 100 right, err = doltDB.Resolve(ctx, rcs, dbData.Rsr.CWBHeadRef()) 101 if err != nil { 102 return nil, nil, err 103 } 104 105 return 106 } 107 108 // String implements the sql.Expression interface. 109 func (d MergeBase) String() string { 110 return fmt.Sprintf("DOLT_MERGE_BASE(%s,%s)", d.Left.String(), d.Right.String()) 111 } 112 113 // Type implements the sql.Expression interface. 114 func (d MergeBase) Type() sql.Type { 115 return sql.Text 116 } 117 118 // WithChildren implements the sql.Expression interface. 119 func (d MergeBase) WithChildren(ctx *sql.Context, children ...sql.Expression) (sql.Expression, error) { 120 if len(children) != 2 { 121 return nil, sql.ErrInvalidChildrenNumber.New(d, len(children), 2) 122 } 123 return NewMergeBase(ctx, children[0], children[1]), nil 124 }