github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/sqle/dfunctions/hashof.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 "errors" 19 "fmt" 20 "strings" 21 22 "github.com/dolthub/go-mysql-server/sql" 23 "github.com/dolthub/go-mysql-server/sql/expression" 24 "github.com/dolthub/go-mysql-server/sql/types" 25 26 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" 27 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess" 28 "github.com/dolthub/dolt/go/store/hash" 29 ) 30 31 const DeprecatedHashOfFuncName = "hashof" 32 const HashOfFuncName = "dolt_hashof" 33 34 type HashOf struct { 35 expression.UnaryExpression 36 name string 37 } 38 39 var _ sql.FunctionExpression = (*HashOf)(nil) 40 41 // NewHashOfFunc creates a constructor for a Hashof function which will properly initialize the name 42 func NewHashOfFunc(name string) sql.CreateFunc1Args { 43 return func(e sql.Expression) sql.Expression { 44 return newHashOf(e, name) 45 } 46 } 47 48 // newHashOf creates a new HashOf expression. 49 func newHashOf(e sql.Expression, name string) sql.Expression { 50 return &HashOf{expression.UnaryExpression{Child: e}, name} 51 } 52 53 // Eval implements the Expression interface. 54 func (t *HashOf) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 55 val, err := t.Child.Eval(ctx, row) 56 57 if err != nil { 58 return nil, err 59 } 60 61 if val == nil { 62 return nil, nil 63 } 64 65 paramStr, ok := val.(string) 66 67 if !ok { 68 return nil, errors.New("branch name is not a string") 69 } 70 71 name, as, err := doltdb.SplitAncestorSpec(paramStr) 72 if err != nil { 73 return nil, err 74 } 75 76 dbName := ctx.GetCurrentDatabase() 77 ddb, ok := dsess.DSessFromSess(ctx.Session).GetDoltDB(ctx, dbName) 78 if !ok { 79 return nil, sql.ErrDatabaseNotFound.New(dbName) 80 } 81 82 var cm *doltdb.Commit 83 if strings.ToUpper(name) == "HEAD" { 84 sess := dsess.DSessFromSess(ctx.Session) 85 86 // TODO: this should resolve the current DB through the analyzer so it can use the revision qualified name here 87 cm, err = sess.GetHeadCommit(ctx, dbName) 88 if err != nil { 89 return nil, err 90 } 91 } else { 92 ref, err := ddb.GetRefByNameInsensitive(ctx, name) 93 if err != nil { 94 hsh, parsed := hash.MaybeParse(name) 95 if parsed { 96 orgErr := err 97 optCmt, err := ddb.ReadCommit(ctx, hsh) 98 if err != nil { 99 return nil, orgErr 100 } 101 cm, ok = optCmt.ToCommit() 102 if !ok { 103 return nil, doltdb.ErrGhostCommitEncountered 104 } 105 } else { 106 return nil, err 107 } 108 } else { 109 cm, err = ddb.ResolveCommitRef(ctx, ref) 110 if err != nil { 111 return nil, err 112 } 113 } 114 } 115 116 optCmt, err := cm.GetAncestor(ctx, as) 117 if err != nil { 118 return nil, err 119 } 120 cm, ok = optCmt.ToCommit() 121 if !ok { 122 return nil, doltdb.ErrGhostCommitEncountered 123 } 124 125 h, err := cm.HashOf() 126 if err != nil { 127 return nil, err 128 } 129 130 return h.String(), nil 131 } 132 133 // String implements the Stringer interface. 134 func (t *HashOf) String() string { 135 return fmt.Sprintf("%s(%s)", t.name, t.Child.String()) 136 } 137 138 // FunctionName implements the FunctionExpression interface 139 func (t *HashOf) FunctionName() string { 140 return t.name 141 } 142 143 // Description implements the FunctionExpression interface 144 func (t *HashOf) Description() string { 145 return "returns the commit hash of a branch or other commit spec" 146 } 147 148 // IsNullable implements the Expression interface. 149 func (t *HashOf) IsNullable() bool { 150 return t.Child.IsNullable() 151 } 152 153 // WithChildren implements the Expression interface. 154 func (t *HashOf) WithChildren(children ...sql.Expression) (sql.Expression, error) { 155 if len(children) != 1 { 156 return nil, sql.ErrInvalidChildrenNumber.New(t, len(children), 1) 157 } 158 return newHashOf(children[0], t.name), nil 159 } 160 161 // Type implements the Expression interface. 162 func (t *HashOf) Type() sql.Type { 163 return types.Text 164 }