github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/function/field.go (about) 1 // Copyright 2024 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 function 16 17 import ( 18 "fmt" 19 "strings" 20 21 "github.com/dolthub/go-mysql-server/sql" 22 "github.com/dolthub/go-mysql-server/sql/types" 23 ) 24 25 // Field joins several strings together. 26 type Field struct { 27 args []sql.Expression 28 } 29 30 var _ sql.FunctionExpression = (*Field)(nil) 31 var _ sql.CollationCoercible = (*Field)(nil) 32 33 // NewField creates a new Field UDF. 34 func NewField(args ...sql.Expression) (sql.Expression, error) { 35 if len(args) < 2 { 36 return nil, sql.ErrInvalidArgumentNumber.New("FIELD", "2 or more", len(args)) 37 } 38 39 return &Field{args}, nil 40 } 41 42 // FunctionName implements sql.FunctionExpression 43 func (f *Field) FunctionName() string { 44 return "field" 45 } 46 47 // Description implements sql.FunctionExpression 48 func (f *Field) Description() string { 49 return "returns the string at index number." 50 } 51 52 // Type implements the Expression interface. 53 func (f *Field) Type() sql.Type { 54 return types.Int64 55 } 56 57 // CollationCoercibility implements the interface sql.CollationCoercible. 58 func (f *Field) CollationCoercibility(ctx *sql.Context) (sql.CollationID, byte) { 59 if len(f.args) == 0 { 60 return sql.Collation_binary, 6 61 } 62 collation, coercibility := sql.GetCoercibility(ctx, f.args[0]) 63 for i := 1; i < len(f.args); i++ { 64 nextCollation, nextCoercibility := sql.GetCoercibility(ctx, f.args[i]) 65 collation, coercibility = sql.ResolveCoercibility(collation, coercibility, nextCollation, nextCoercibility) 66 } 67 return collation, coercibility 68 } 69 70 // IsNullable implements the Expression interface. 71 func (f *Field) IsNullable() bool { 72 return false 73 } 74 75 // String implements the Stringer interface. 76 func (f *Field) String() string { 77 var args = make([]string, len(f.args)) 78 for i, arg := range f.args { 79 args[i] = arg.String() 80 } 81 return fmt.Sprintf("%s(%s)", f.FunctionName(), strings.Join(args, ",")) 82 } 83 84 // WithChildren implements the Expression interface. 85 func (*Field) WithChildren(children ...sql.Expression) (sql.Expression, error) { 86 return NewField(children...) 87 } 88 89 // Resolved implements the Expression interface. 90 func (f *Field) Resolved() bool { 91 for _, arg := range f.args { 92 if !arg.Resolved() { 93 return false 94 } 95 } 96 return true 97 } 98 99 // Children implements the Expression interface. 100 func (f *Field) Children() []sql.Expression { 101 return f.args 102 } 103 104 // Eval implements the Expression interface. 105 func (f *Field) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 106 if f.args[0] == nil { 107 return int64(0), nil 108 } 109 110 key, err := f.args[0].Eval(ctx, row) 111 if err != nil { 112 return nil, err 113 } 114 115 if key == nil { 116 return int64(0), nil 117 } 118 119 key, _, err = types.Text.Convert(key) 120 if err != nil { 121 return nil, err 122 } 123 124 var val interface{} 125 for i := 1; i < len(f.args); i++ { 126 if f.args[i] == nil { 127 continue 128 } 129 130 val, err = f.args[i].Eval(ctx, row) 131 if err != nil { 132 return nil, err 133 } 134 135 if val == nil { 136 continue 137 } 138 139 val, _, err = types.Text.Convert(val) 140 if err != nil { 141 return nil, err 142 } 143 144 if strings.EqualFold(key.(string), val.(string)) { 145 return int64(i), nil 146 } 147 } 148 149 return int64(0), nil 150 }