diff options
author | Ting-Wei Lan <lantw44@gmail.com> | 2019-05-07 12:03:42 +0800 |
---|---|---|
committer | Ting-Wei Lan <tingwei.lan@cobinhood.com> | 2019-05-14 11:04:15 +0800 |
commit | 9aa6fb4c7a219c4431f52eb241f36dc5cfe040d5 (patch) | |
tree | 44c427e41e371168c915daaf5b2753a690705f7d | |
parent | 1fb67a439f5725a7926592f55f59e82486641155 (diff) | |
download | dexon-9aa6fb4c7a219c4431f52eb241f36dc5cfe040d5.tar dexon-9aa6fb4c7a219c4431f52eb241f36dc5cfe040d5.tar.gz dexon-9aa6fb4c7a219c4431f52eb241f36dc5cfe040d5.tar.bz2 dexon-9aa6fb4c7a219c4431f52eb241f36dc5cfe040d5.tar.lz dexon-9aa6fb4c7a219c4431f52eb241f36dc5cfe040d5.tar.xz dexon-9aa6fb4c7a219c4431f52eb241f36dc5cfe040d5.tar.zst dexon-9aa6fb4c7a219c4431f52eb241f36dc5cfe040d5.zip |
code backup 34
-rw-r--r-- | core/vm/sqlvm/checker/expr.go | 124 |
1 files changed, 123 insertions, 1 deletions
diff --git a/core/vm/sqlvm/checker/expr.go b/core/vm/sqlvm/checker/expr.go index f9421a32e..01c673709 100644 --- a/core/vm/sqlvm/checker/expr.go +++ b/core/vm/sqlvm/checker/expr.go @@ -92,7 +92,7 @@ func checkExpr(n ast.ExprNode, return checkModOperator(n, s, o, c, el, tr, ta) case *ast.IsOperatorNode: - return n + return checkIsOperator(n, s, o, c, el, tr, ta) case *ast.LikeOperatorNode: return n @@ -1157,6 +1157,9 @@ func checkParenOperator(n *ast.ParenOperatorNode, r := n.GetTarget() r = checkExpr(r, s, o, c, el, tr, ta) + if r == nil { + return nil + } r.SetPosition(n.GetPosition()) r.SetLength(n.GetLength()) r.SetToken(n.GetToken()) @@ -2297,3 +2300,122 @@ func checkModOperator(n *ast.ModOperatorNode, return r }) } + +func checkIsOperator(n *ast.IsOperatorNode, + s schema.Schema, o CheckOptions, c *schemaCache, el *errors.ErrorList, + tr schema.TableRef, ta typeAction) ast.ExprNode { + + fn := "CheckIsOperator" + op := "binary operator IS" + + object := n.GetObject() + object = checkExpr(object, s, o, c, el, tr, nil) + if object == nil { + return nil + } + subject := n.GetSubject() + subject = checkExpr(subject, s, o, c, el, tr, nil) + if subject == nil { + return nil + } + n.SetObject(object) + n.SetSubject(subject) + r := ast.ExprNode(n) + + reportUnsupportedConstant := func(n ast.Valuer) { + el.Append(errors.Error{ + Position: n.GetPosition(), + Length: n.GetLength(), + Category: errors.ErrorCategorySemantic, + Code: errors.ErrorCodeTypeError, + Severity: errors.ErrorSeverityError, + Prefix: fn, + Message: fmt.Sprintf( + "the right-hand side of %s cannot be %s", + op, describeValueNodeType(n)), + }, nil) + } + reportNotConstant := func(n ast.ExprNode) { + el.Append(errors.Error{ + Position: n.GetPosition(), + Length: n.GetLength(), + Category: errors.ErrorCategorySemantic, + Code: errors.ErrorCodeNonConstantExpression, + Severity: errors.ErrorSeverityError, + Prefix: fn, + Message: fmt.Sprintf( + "the right-hand side of %s is not a constant", op), + }, nil) + } + var is ast.BoolValue + if sv, ok := subject.(ast.Valuer); ok { + switch sn := sv.(type) { + case *ast.BoolValueNode: + // IS TRUE / FALSE / UNKNOWN only works for bool. + if !validateBoolType(object.GetType(), el, object, fn, op) { + return nil + } + is = sn.V + op = "unary operator IS " + is.String() + case *ast.NullValueNode: + // IS NULL works for all types. + op = "unary operator IS NULL" + case *ast.AddressValueNode: + reportUnsupportedConstant(sv) + return nil + case *ast.IntegerValueNode: + reportUnsupportedConstant(sv) + return nil + case *ast.DecimalValueNode: + reportUnsupportedConstant(sv) + return nil + case *ast.BytesValueNode: + reportUnsupportedConstant(sv) + return nil + default: + panic(unknownValueNodeType(sv)) + } + } else { + reportNotConstant(subject) + return nil + } + dt := n.GetType() + + if object, ok := object.(ast.Valuer); ok { + var vo ast.BoolValue + if _, isBool := object.(*ast.BoolValueNode); isBool && !is.Valid() { + // Redirect IS NULL to IS UNKNOWN for bool. + is = ast.BoolValueUnknown + } + if is.Valid() { + // IS TRUE / FALSE / UNKNOWN + v, ok := extractBoolValue(object, el, fn, op) + if !ok { + return nil + } + vo = ast.NewBoolValueFromBool(v == is) + } else { + // IS NULL + _, isNull := object.(*ast.NullValueNode) + vo = ast.NewBoolValueFromBool(isNull) + } + node := &ast.BoolValueNode{} + node.SetPosition(n.GetPosition()) + node.SetLength(n.GetLength()) + node.SetToken(n.GetToken()) + node.V = vo + r = node + } + + switch a := ta.(type) { + case typeActionInferDefault: + case typeActionInferWithSize: + case typeActionInferWithMajor: + case typeActionAssign: + if !dt.Equal(a.dt) { + elAppendTypeErrorAssignDataType(el, n, fn, a.dt, dt) + return nil + } + } + return r +} |