github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/function/concat.go (about) 1 // Copyright 2020-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 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 // Concat joins several strings together. 26 type Concat struct { 27 args []sql.Expression 28 } 29 30 var _ sql.FunctionExpression = (*Concat)(nil) 31 var _ sql.CollationCoercible = (*Concat)(nil) 32 33 // NewConcat creates a new Concat UDF. 34 func NewConcat(args ...sql.Expression) (sql.Expression, error) { 35 if len(args) == 0 { 36 return nil, sql.ErrInvalidArgumentNumber.New("CONCAT", "1 or more", 0) 37 } 38 39 return &Concat{args}, nil 40 } 41 42 // FunctionName implements sql.FunctionExpression 43 func (c *Concat) FunctionName() string { 44 return "concat" 45 } 46 47 // Description implements sql.FunctionExpression 48 func (c *Concat) Description() string { 49 return "concatenates any group of fields into a single string." 50 } 51 52 // Type implements the Expression interface. 53 func (c *Concat) Type() sql.Type { return types.LongText } 54 55 // CollationCoercibility implements the interface sql.CollationCoercible. 56 func (c *Concat) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 57 if len(c.args) == 0 { 58 return sql.Collation_binary, 6 59 } 60 collation, coercibility = sql.GetCoercibility(ctx, c.args[0]) 61 for i := 1; i < len(c.args); i++ { 62 nextCollation, nextCoercibility := sql.GetCoercibility(ctx, c.args[i]) 63 collation, coercibility = sql.ResolveCoercibility(collation, coercibility, nextCollation, nextCoercibility) 64 } 65 return collation, coercibility 66 } 67 68 // IsNullable implements the Expression interface. 69 func (c *Concat) IsNullable() bool { 70 for _, arg := range c.args { 71 if arg.IsNullable() { 72 return true 73 } 74 } 75 return false 76 } 77 78 func (c *Concat) String() string { 79 var args = make([]string, len(c.args)) 80 for i, arg := range c.args { 81 args[i] = arg.String() 82 } 83 return fmt.Sprintf("%s(%s)", c.FunctionName(), strings.Join(args, ",")) 84 } 85 86 func (c *Concat) DebugString() string { 87 var args = make([]string, len(c.args)) 88 for i, arg := range c.args { 89 args[i] = sql.DebugString(arg) 90 } 91 return fmt.Sprintf("%s(%s)", c.FunctionName(), strings.Join(args, ",")) 92 } 93 94 // WithChildren implements the Expression interface. 95 func (*Concat) WithChildren(children ...sql.Expression) (sql.Expression, error) { 96 return NewConcat(children...) 97 } 98 99 // Resolved implements the Expression interface. 100 func (c *Concat) Resolved() bool { 101 for _, arg := range c.args { 102 if !arg.Resolved() { 103 return false 104 } 105 } 106 return true 107 } 108 109 // Children implements the Expression interface. 110 func (c *Concat) Children() []sql.Expression { return c.args } 111 112 // Eval implements the Expression interface. 113 func (c *Concat) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 114 var parts []string 115 116 for _, arg := range c.args { 117 val, err := arg.Eval(ctx, row) 118 if err != nil { 119 return nil, err 120 } 121 122 if val == nil { 123 return nil, nil 124 } 125 126 val, _, err = types.LongText.Convert(val) 127 if err != nil { 128 return nil, err 129 } 130 131 parts = append(parts, val.(string)) 132 } 133 134 return strings.Join(parts, ""), nil 135 }