github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/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 "github.com/dolthub/go-mysql-server/sql/types" 23 24 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" 25 "github.com/dolthub/dolt/go/libraries/doltcore/merge" 26 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess" 27 ) 28 29 const DoltMergeBaseFuncName = "dolt_merge_base" 30 31 type MergeBase struct { 32 expression.BinaryExpressionStub 33 } 34 35 // NewMergeBase returns a MergeBase sql function. 36 func NewMergeBase(left, right sql.Expression) sql.Expression { 37 return &MergeBase{expression.BinaryExpressionStub{LeftChild: left, RightChild: right}} 38 } 39 40 // Eval implements the sql.Expression interface. 41 func (d MergeBase) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 42 if _, ok := d.Left().Type().(sql.StringType); !ok { 43 return nil, sql.ErrInvalidType.New(d.Left().Type()) 44 } 45 if _, ok := d.Right().Type().(sql.StringType); !ok { 46 return nil, sql.ErrInvalidType.New(d.Right().Type()) 47 } 48 49 leftSpec, err := d.Left().Eval(ctx, row) 50 if err != nil { 51 return nil, err 52 } 53 rightSpec, err := d.Right().Eval(ctx, row) 54 if err != nil { 55 return nil, err 56 } 57 58 if leftSpec == nil || rightSpec == nil { 59 return nil, nil 60 } 61 62 left, right, err := resolveRefSpecs(ctx, leftSpec.(string), rightSpec.(string)) 63 if err != nil { 64 return nil, err 65 } 66 67 mergeBase, err := merge.MergeBase(ctx, left, right) 68 if err != nil { 69 return nil, err 70 } 71 72 return mergeBase.String(), nil 73 } 74 75 func resolveRefSpecs(ctx *sql.Context, leftSpec, rightSpec string) (left, right *doltdb.Commit, err error) { 76 lcs, err := doltdb.NewCommitSpec(leftSpec) 77 if err != nil { 78 return nil, nil, err 79 } 80 rcs, err := doltdb.NewCommitSpec(rightSpec) 81 if err != nil { 82 return nil, nil, err 83 } 84 85 sess := dsess.DSessFromSess(ctx.Session) 86 dbName := ctx.GetCurrentDatabase() 87 88 dbData, ok := sess.GetDbData(ctx, dbName) 89 if !ok { 90 return nil, nil, sql.ErrDatabaseNotFound.New(dbName) 91 } 92 doltDB, ok := sess.GetDoltDB(ctx, dbName) 93 if !ok { 94 return nil, nil, sql.ErrDatabaseNotFound.New(dbName) 95 } 96 97 headRef, err := dbData.Rsr.CWBHeadRef() 98 if err != nil { 99 return nil, nil, err 100 } 101 102 optCmt, err := doltDB.Resolve(ctx, lcs, headRef) 103 if err != nil { 104 return nil, nil, err 105 } 106 left, ok = optCmt.ToCommit() 107 if !ok { 108 return nil, nil, doltdb.ErrGhostCommitEncountered 109 } 110 111 optCmt, err = doltDB.Resolve(ctx, rcs, headRef) 112 if err != nil { 113 return nil, nil, err 114 } 115 right, ok = optCmt.ToCommit() 116 if !ok { 117 return nil, nil, doltdb.ErrGhostCommitEncountered 118 } 119 120 return 121 } 122 123 // String implements the sql.Expression interface. 124 func (d MergeBase) String() string { 125 return fmt.Sprintf("DOLT_MERGE_BASE(%s,%s)", d.Left().String(), d.Right().String()) 126 } 127 128 // Type implements the sql.Expression interface. 129 func (d MergeBase) Type() sql.Type { 130 return types.Text 131 } 132 133 // WithChildren implements the sql.Expression interface. 134 func (d MergeBase) WithChildren(children ...sql.Expression) (sql.Expression, error) { 135 if len(children) != 2 { 136 return nil, sql.ErrInvalidChildrenNumber.New(d, len(children), 2) 137 } 138 return NewMergeBase(children[0], children[1]), nil 139 }