github.com/dolthub/go-mysql-server@v0.18.0/sql/columndefault.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 sql 16 17 import ( 18 "fmt" 19 ) 20 21 // ColumnDefaultValue is an expression representing the default value of a column. May represent both a default literal 22 // and a default expression. A nil pointer of this type represents an implicit default value and is thus valid, so all 23 // method calls will return without error. 24 type ColumnDefaultValue struct { 25 // Expression is the expression representing this default value 26 Expr Expression 27 // OutType converts the output of the expression into this type, when not nil 28 OutType Type 29 // Literal indicates whether the default value is a Literal value or expression 30 Literal bool 31 // ReturnNil indicates whether a nil value from the default value expression is returned as null or an error 32 ReturnNil bool 33 // Parenthesized indicates whether the value was specified in parens or not; this is typically the opposite of the Literal field, 34 // but they can both be false in the case of now/current_timestamp for datetimes and timestamps. 35 Parenthesized bool 36 // TODO: we need a generated marker here so we can tell them apart during analysis, maybe? 37 } 38 39 var _ Expression = (*ColumnDefaultValue)(nil) 40 var _ CollationCoercible = (*ColumnDefaultValue)(nil) 41 42 // NewColumnDefaultValue returns a new ColumnDefaultValue expression. 43 func NewColumnDefaultValue(expr Expression, outType Type, representsLiteral bool, parenthesized bool, mayReturnNil bool) (*ColumnDefaultValue, error) { 44 return &ColumnDefaultValue{ 45 Expr: expr, 46 OutType: outType, 47 Literal: representsLiteral, 48 ReturnNil: mayReturnNil, 49 Parenthesized: parenthesized, 50 }, nil 51 } 52 53 // NewUnresolvedColumnDefaultValue returns a column default 54 func NewUnresolvedColumnDefaultValue(expr string) *ColumnDefaultValue { 55 return &ColumnDefaultValue{ 56 Expr: &UnresolvedColumnDefault{ExprString: expr}, 57 } 58 } 59 60 // Children implements sql.Expression 61 func (e *ColumnDefaultValue) Children() []Expression { 62 if e == nil { 63 return nil 64 } 65 return []Expression{e.Expr} 66 } 67 68 // Eval implements sql.Expression 69 func (e *ColumnDefaultValue) Eval(ctx *Context, r Row) (interface{}, error) { 70 if e == nil { 71 return nil, nil 72 } 73 74 val, err := e.Expr.Eval(ctx, r) 75 if err != nil { 76 return nil, err 77 } 78 79 if val == nil && !e.ReturnNil { 80 return nil, ErrColumnDefaultReturnedNull.New() 81 } 82 83 if e.OutType != nil { 84 var inRange ConvertInRange 85 if val, inRange, err = e.OutType.Convert(val); err != nil { 86 return nil, ErrIncompatibleDefaultType.New() 87 } else if !inRange { 88 return nil, ErrValueOutOfRange.New(val, e.OutType) 89 } 90 } 91 92 return val, nil 93 } 94 95 // IsLiteral returns whether this expression represents a literal default value (otherwise it's an expression default value). 96 func (e *ColumnDefaultValue) IsLiteral() bool { 97 if e == nil { 98 return true // we return the literal nil, hence true 99 } 100 return e.Literal 101 } 102 103 // IsParenthesized returns whether this column default was specified in parentheses, using the expression default value form. 104 // It is almost always the opposite of IsLiteral, but there is one edge case where matching MySQL's behavior require that 105 // we can distinguish between a non-literal value in parens and a non-literal value not in parens. The edge case is using 106 // now/current_timestamp as a column default; now/current_timestamp can be specified without parens for datetime/timestamp 107 // fields, but it must be enclosed in parens to be used as the default for other types. 108 func (e *ColumnDefaultValue) IsParenthesized() bool { 109 if e == nil { 110 return false // we return the literal nil, hence false 111 } 112 return e.Parenthesized 113 } 114 115 // IsNullable implements sql.Expression 116 func (e *ColumnDefaultValue) IsNullable() bool { 117 if e == nil { 118 return true 119 } 120 if !e.ReturnNil { 121 return false 122 } 123 return e.Expr.IsNullable() 124 } 125 126 // Resolved implements sql.Expression 127 func (e *ColumnDefaultValue) Resolved() bool { 128 if e == nil { 129 return true 130 } 131 if e.OutType == nil { 132 return false 133 } 134 return e.Expr.Resolved() 135 } 136 137 // String implements sql.Expression 138 func (e *ColumnDefaultValue) String() string { 139 //TODO: currently (2+2)/2 will, when output as a string, give (2 + 2 / 2), which is clearly wrong 140 if e == nil { 141 return "" 142 } 143 144 // https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html 145 // The default value specified in a DEFAULT clause can be a literal constant or an expression. With one exception, 146 // enclose expression default values within parentheses to distinguish them from literal constant default values. 147 str := e.Expr.String() 148 if e.Literal { 149 return str 150 } 151 152 // There's a special case for NOW() 153 if str == "NOW()" || str == "NOW(0)" { 154 return "CURRENT_TIMESTAMP" 155 } 156 157 return fmt.Sprintf("(%s)", str) 158 } 159 160 func (e *ColumnDefaultValue) DebugString() string { 161 if e == nil { 162 return "" 163 } 164 165 if e.Literal { 166 return DebugString(e.Expr) 167 } else if e.Parenthesized { 168 return fmt.Sprintf("parenthesized(%s)", DebugString(e.Expr)) 169 } else { 170 return fmt.Sprintf("(%s)", DebugString(e.Expr)) 171 } 172 } 173 174 // Type implements sql.Expression 175 func (e *ColumnDefaultValue) Type() Type { 176 if e == nil { 177 return nil 178 } 179 if e.OutType == nil { 180 return e.Expr.Type() 181 } 182 return e.OutType 183 } 184 185 // CollationCoercibility implements the interface sql.CollationCoercible. 186 func (e *ColumnDefaultValue) CollationCoercibility(ctx *Context) (collation CollationID, coercibility byte) { 187 if e == nil { 188 return Collation_binary, 6 189 } 190 return GetCoercibility(ctx, e.Expr) 191 } 192 193 // WithChildren implements sql.Expression 194 func (e *ColumnDefaultValue) WithChildren(children ...Expression) (Expression, error) { 195 if e == nil && len(children) == 0 { 196 return e, nil 197 } 198 if len(children) != 1 { 199 return nil, ErrInvalidChildrenNumber.New(e, len(children), 1) 200 } 201 if e == nil { 202 isLiteral := len(children[0].Children()) == 0 //impossible to know, best guess 203 return NewColumnDefaultValue(children[0], e.OutType, isLiteral, !isLiteral, true) 204 } else { 205 return NewColumnDefaultValue(children[0], e.OutType, e.Literal, e.Parenthesized, e.ReturnNil) 206 } 207 } 208 209 // CheckType validates that the ColumnDefaultValue has the correct type. 210 func (e *ColumnDefaultValue) CheckType(ctx *Context) error { 211 if e.OutType != nil && e.Literal { 212 val, err := e.Expr.Eval(ctx, nil) 213 if err != nil { 214 return err 215 } 216 if val == nil && !e.ReturnNil { 217 return ErrIncompatibleDefaultType.New() 218 } 219 _, inRange, err := e.OutType.Convert(val) 220 if err != nil { 221 return ErrIncompatibleDefaultType.Wrap(err) 222 } else if !inRange { 223 return ErrIncompatibleDefaultType.Wrap(ErrValueOutOfRange.New(val, e.Expr)) 224 } 225 226 } 227 return nil 228 } 229 230 type UnresolvedColumnDefault struct { 231 ExprString string 232 } 233 234 var _ Expression = UnresolvedColumnDefault{} 235 var _ CollationCoercible = UnresolvedColumnDefault{} 236 237 func (u UnresolvedColumnDefault) Resolved() bool { 238 return false 239 } 240 241 func (u UnresolvedColumnDefault) String() string { 242 return u.ExprString 243 } 244 245 func (u UnresolvedColumnDefault) Type() Type { 246 panic("UnresolvedColumnDefault is a placeholder node, but Type() was called") 247 } 248 249 // CollationCoercibility implements the interface sql.CollationCoercible. 250 func (UnresolvedColumnDefault) CollationCoercibility(ctx *Context) (collation CollationID, coercibility byte) { 251 return Collation_binary, 7 252 } 253 254 func (u UnresolvedColumnDefault) IsNullable() bool { 255 return true 256 } 257 258 func (u UnresolvedColumnDefault) Eval(ctx *Context, row Row) (interface{}, error) { 259 panic("UnresolvedColumnDefault is a placeholder node, but Eval() was called") 260 } 261 262 func (u UnresolvedColumnDefault) Children() []Expression { 263 return nil 264 } 265 266 func (u UnresolvedColumnDefault) WithChildren(children ...Expression) (Expression, error) { 267 if len(children) != 0 { 268 return nil, ErrInvalidChildrenNumber.New(u, len(children), 0) 269 } 270 return u, nil 271 }