github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/function/elt.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 // Elt joins several strings together. 26 type Elt struct { 27 args []sql.Expression 28 } 29 30 var _ sql.FunctionExpression = (*Elt)(nil) 31 var _ sql.CollationCoercible = (*Elt)(nil) 32 33 // NewElt creates a new Elt UDF. 34 func NewElt(args ...sql.Expression) (sql.Expression, error) { 35 if len(args) < 2 { 36 return nil, sql.ErrInvalidArgumentNumber.New("ELT", "2 or more", len(args)) 37 } 38 39 return &Elt{args}, nil 40 } 41 42 // FunctionName implements sql.FunctionExpression 43 func (e *Elt) FunctionName() string { 44 return "elt" 45 } 46 47 // Description implements sql.FunctionExpression 48 func (e *Elt) Description() string { 49 return "returns the string at index number." 50 } 51 52 // Type implements the Expression interface. 53 func (e *Elt) Type() sql.Type { 54 return types.LongText 55 } 56 57 // CollationCoercibility implements the interface sql.CollationCoercible. 58 func (e *Elt) CollationCoercibility(ctx *sql.Context) (sql.CollationID, byte) { 59 if len(e.args) == 0 { 60 return sql.Collation_binary, 6 61 } 62 collation, coercibility := sql.GetCoercibility(ctx, e.args[0]) 63 for i := 1; i < len(e.args); i++ { 64 nextCollation, nextCoercibility := sql.GetCoercibility(ctx, e.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 (e *Elt) IsNullable() bool { 72 return true 73 } 74 75 // String implements the Stringer interface. 76 func (e *Elt) String() string { 77 var args = make([]string, len(e.args)) 78 for i, arg := range e.args { 79 args[i] = arg.String() 80 } 81 return fmt.Sprintf("%s(%s)", e.FunctionName(), strings.Join(args, ",")) 82 } 83 84 // WithChildren implements the Expression interface. 85 func (*Elt) WithChildren(children ...sql.Expression) (sql.Expression, error) { 86 return NewElt(children...) 87 } 88 89 // Resolved implements the Expression interface. 90 func (e *Elt) Resolved() bool { 91 for _, arg := range e.args { 92 if !arg.Resolved() { 93 return false 94 } 95 } 96 return true 97 } 98 99 // Children implements the Expression interface. 100 func (e *Elt) Children() []sql.Expression { 101 return e.args 102 } 103 104 // Eval implements the Expression interface. 105 func (e *Elt) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 106 if e.args[0] == nil { 107 return nil, nil 108 } 109 110 index, err := e.args[0].Eval(ctx, row) 111 if err != nil { 112 return nil, err 113 } 114 115 if index == nil { 116 return nil, nil 117 } 118 119 indexInt, _, err := types.Int64.Convert(index) 120 if err != nil { 121 // TODO: truncate 122 ctx.Warn(1292, "Truncated incorrect INTEGER value: '%v'", index) 123 indexInt = int64(0) 124 } 125 126 idx := int(indexInt.(int64)) 127 if idx <= 0 || idx >= len(e.args) { 128 return nil, nil 129 } 130 131 str, err := e.args[idx].Eval(ctx, row) 132 if err != nil { 133 return nil, err 134 } 135 136 res, _, err := types.Text.Convert(str) 137 if err != nil { 138 return nil, err 139 } 140 141 return res, nil 142 }