github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/function/ifnull.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 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 25 // IfNull function returns the specified value IF the expression is NULL, otherwise return the expression. 26 type IfNull struct { 27 expression.BinaryExpressionStub 28 } 29 30 var _ sql.FunctionExpression = (*IfNull)(nil) 31 var _ sql.CollationCoercible = (*IfNull)(nil) 32 33 // NewIfNull returns a new IFNULL UDF 34 func NewIfNull(ex, value sql.Expression) sql.Expression { 35 return &IfNull{ 36 expression.BinaryExpressionStub{ 37 LeftChild: ex, 38 RightChild: value, 39 }, 40 } 41 } 42 43 // FunctionName implements sql.FunctionExpression 44 func (f *IfNull) FunctionName() string { 45 return "ifnull" 46 } 47 48 // Description implements sql.FunctionExpression 49 func (f *IfNull) Description() string { 50 return "if expr1 is not NULL, it returns expr1; otherwise it returns expr2." 51 } 52 53 // Eval implements the Expression interface. 54 func (f *IfNull) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 55 left, err := f.LeftChild.Eval(ctx, row) 56 if err != nil { 57 return nil, err 58 } 59 if left != nil { 60 return left, nil 61 } 62 63 right, err := f.RightChild.Eval(ctx, row) 64 if err != nil { 65 return nil, err 66 } 67 return right, nil 68 } 69 70 // Type implements the Expression interface. 71 func (f *IfNull) Type() sql.Type { 72 if types.IsNull(f.LeftChild) { 73 if types.IsNull(f.RightChild) { 74 return types.Null 75 } 76 return f.RightChild.Type() 77 } 78 return f.LeftChild.Type() 79 } 80 81 // CollationCoercibility implements the interface sql.CollationCoercible. 82 func (f *IfNull) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 83 if types.IsNull(f.LeftChild) { 84 if types.IsNull(f.RightChild) { 85 return sql.Collation_binary, 6 86 } 87 return sql.GetCoercibility(ctx, f.RightChild) 88 } 89 return sql.GetCoercibility(ctx, f.LeftChild) 90 } 91 92 // IsNullable implements the Expression interface. 93 func (f *IfNull) IsNullable() bool { 94 if types.IsNull(f.LeftChild) { 95 if types.IsNull(f.RightChild) { 96 return true 97 } 98 return f.RightChild.IsNullable() 99 } 100 return f.LeftChild.IsNullable() 101 } 102 103 func (f *IfNull) String() string { 104 return fmt.Sprintf("ifnull(%s, %s)", f.LeftChild, f.RightChild) 105 } 106 107 // WithChildren implements the Expression interface. 108 func (f *IfNull) WithChildren(children ...sql.Expression) (sql.Expression, error) { 109 if len(children) != 2 { 110 return nil, sql.ErrInvalidChildrenNumber.New(f, len(children), 2) 111 } 112 return NewIfNull(children[0], children[1]), nil 113 }