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  }