aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorTing-Wei Lan <tingwei.lan@cobinhood.com>2019-04-25 16:17:06 +0800
committerTing-Wei Lan <tingwei.lan@cobinhood.com>2019-05-14 11:04:15 +0800
commit06266ab9f5f5491fed858a1cee668d37d2b3a44c (patch)
tree73504a8940f2da100a31357a5b57233723fbfb77 /core
parent9f277bb0d0ebdff13dc77e9b8e83a1dee93d6a7b (diff)
downloaddexon-06266ab9f5f5491fed858a1cee668d37d2b3a44c.tar
dexon-06266ab9f5f5491fed858a1cee668d37d2b3a44c.tar.gz
dexon-06266ab9f5f5491fed858a1cee668d37d2b3a44c.tar.bz2
dexon-06266ab9f5f5491fed858a1cee668d37d2b3a44c.tar.lz
dexon-06266ab9f5f5491fed858a1cee668d37d2b3a44c.tar.xz
dexon-06266ab9f5f5491fed858a1cee668d37d2b3a44c.tar.zst
dexon-06266ab9f5f5491fed858a1cee668d37d2b3a44c.zip
code backup 20
Diffstat (limited to 'core')
-rw-r--r--core/vm/sqlvm/checker/actions.go (renamed from core/vm/sqlvm/checkers/actions.go)2
-rw-r--r--core/vm/sqlvm/checker/checker.go (renamed from core/vm/sqlvm/checkers/checkers.go)189
-rw-r--r--core/vm/sqlvm/checker/utils.go (renamed from core/vm/sqlvm/checkers/utils.go)24
-rw-r--r--core/vm/sqlvm/cmd/ast-checker/main.go45
4 files changed, 212 insertions, 48 deletions
diff --git a/core/vm/sqlvm/checkers/actions.go b/core/vm/sqlvm/checker/actions.go
index c15029d9a..6adb9b912 100644
--- a/core/vm/sqlvm/checkers/actions.go
+++ b/core/vm/sqlvm/checker/actions.go
@@ -1,4 +1,4 @@
-package checkers
+package checker
import (
"fmt"
diff --git a/core/vm/sqlvm/checkers/checkers.go b/core/vm/sqlvm/checker/checker.go
index 7881aa149..dbdad68fa 100644
--- a/core/vm/sqlvm/checkers/checkers.go
+++ b/core/vm/sqlvm/checker/checker.go
@@ -1,4 +1,4 @@
-package checkers
+package checker
import (
"fmt"
@@ -841,7 +841,7 @@ func checkExpr(n ast.ExprNode,
return checkPosOperator(n, s, o, c, el, tr, ta)
case *ast.NegOperatorNode:
- return n
+ return checkNegOperator(n, s, o, c, el, tr, ta)
case *ast.NotOperatorNode:
return n
@@ -947,7 +947,7 @@ func checkVariable(n *ast.IdentifierNode,
}
cn := string(n.Name)
- cd, found := c.FindColumnInBase(tr, cn)
+ cd, found := c.FindColumnInBaseWithFallback(tr, cn, s)
if !found {
el.Append(errors.Error{
Position: n.GetPosition(),
@@ -1492,8 +1492,7 @@ func elAppendTypeErrorOperatorValueNode(el *errors.ErrorList, n ast.Valuer,
}
func elAppendTypeErrorOperatorDataType(el *errors.ErrorList, n ast.ExprNode,
- fn string, op string) {
- dt := n.GetType()
+ fn string, op string, dt ast.DataType) {
el.Append(errors.Error{
Position: n.GetPosition(),
Length: n.GetLength(),
@@ -1518,23 +1517,56 @@ func checkPosOperator(n *ast.PosOperatorNode,
if target == nil {
return nil
}
+ r := ast.ExprNode(target)
- if v, ok := target.(ast.Valuer); ok {
- switch v := v.(type) {
+ dtTarget := target.GetType()
+ if !dtTarget.Pending() {
+ major, _ := ast.DecomposeDataType(dtTarget)
+ switch {
+ case major == ast.DataTypeMajorInt,
+ major == ast.DataTypeMajorUint,
+ major.IsFixedRange(),
+ major.IsUfixedRange():
+ default:
+ elAppendTypeErrorOperatorDataType(el, target, fn, op, dtTarget)
+ return nil
+ }
+ }
+ dt := dtTarget
+
+ if target, ok := target.(ast.Valuer); ok {
+ switch v := target.(type) {
case *ast.IntegerValueNode:
- // Clone the node to reset IsAddress to false.
- if v.IsAddress {
- result := &ast.IntegerValueNode{}
- result.SetPosition(v.GetPosition())
- result.SetLength(v.GetLength())
- result.SetToken(v.GetToken())
- result.SetType(v.GetType())
- result.IsAddress = false
- result.V = v.V
- target = result
- }
+ node := &ast.IntegerValueNode{}
+ node.SetPosition(n.GetPosition())
+ node.SetLength(n.GetLength())
+ node.SetToken(n.GetToken())
+ node.SetType(dt)
+ node.IsAddress = false
+ node.V = v.V
+ r = node
+
case *ast.DecimalValueNode:
- // Do nothing because the result is the same as the input.
+ node := &ast.DecimalValueNode{}
+ node.SetPosition(n.GetPosition())
+ node.SetLength(n.GetLength())
+ node.SetToken(n.GetToken())
+ node.SetType(dt)
+ node.V = v.V
+ r = node
+
+ case *ast.NullValueNode:
+ if dt.Pending() {
+ elAppendTypeErrorOperatorValueNode(el, v, fn, op)
+ return nil
+ }
+ node := &ast.NullValueNode{}
+ node.SetPosition(n.GetPosition())
+ node.SetLength(n.GetLength())
+ node.SetToken(n.GetToken())
+ node.SetType(dt)
+ r = node
+
case *ast.BoolValueNode:
elAppendTypeErrorOperatorValueNode(el, v, fn, op)
return nil
@@ -1544,36 +1576,139 @@ func checkPosOperator(n *ast.PosOperatorNode,
case *ast.BytesValueNode:
elAppendTypeErrorOperatorValueNode(el, v, fn, op)
return nil
- case *ast.NullValueNode:
- elAppendTypeErrorOperatorValueNode(el, v, fn, op)
- return nil
default:
panic(unknownValueNodeType(v))
}
}
- dt := target.GetType()
if dt.Pending() {
- target = checkExpr(target, s, o, c, el, tr, ta)
+ r = checkExpr(r, s, o, c, el, tr, ta)
} else {
- major, _ := ast.DecomposeDataType(dt)
+ switch a := ta.(type) {
+ case typeActionInferDefault:
+ case typeActionInferWithSize:
+ case typeActionAssign:
+ if !dt.Equal(a.dt) {
+ elAppendTypeErrorMismatch(el, n, fn, a.dt, dt)
+ return nil
+ }
+ }
+ }
+ return r
+}
+
+func checkNegOperator(n *ast.NegOperatorNode,
+ s schema.Schema, o CheckOptions, c *schemaCache, el *errors.ErrorList,
+ tr schema.TableRef, ta typeAction) ast.ExprNode {
+
+ fn := "CheckNegOperator"
+ op := "unary operator -"
+
+ target := n.GetTarget()
+ target = checkExpr(target, s, o, c, el, tr, nil)
+ if target == nil {
+ return nil
+ }
+ n.SetTarget(target)
+ r := ast.ExprNode(n)
+
+ dtTarget := target.GetType()
+ if !dtTarget.Pending() {
+ major, _ := ast.DecomposeDataType(dtTarget)
switch {
case major == ast.DataTypeMajorInt,
major == ast.DataTypeMajorUint,
major.IsFixedRange(),
major.IsUfixedRange():
default:
- elAppendTypeErrorOperatorDataType(el, target, fn, op)
+ elAppendTypeErrorOperatorDataType(el, target, fn, op, dtTarget)
return nil
}
+ }
+ dt := dtTarget
+
+ eval := func(n ast.Valuer, v decimal.Decimal) (decimal.Decimal, bool) {
+ r := v.Neg()
+ if !dt.Pending() {
+ min, max := mustGetMinMax(dt)
+ if r.LessThan(min) || r.GreaterThan(max) {
+ if (o & CheckWithSafeMath) != 0 {
+ elAppendOverflowError(el, n, fn, dt, r, min, max)
+ return r, false
+ }
+ cropped := cropDecimal(dt, r)
+ elAppendOverflowWarning(el, n, fn, dt, r, cropped)
+ r = cropped
+ }
+ }
+ normalizeDecimal(&r)
+ return r, true
+ }
+ if target, ok := target.(ast.Valuer); ok {
+ switch v := target.(type) {
+ case *ast.IntegerValueNode:
+ node := &ast.IntegerValueNode{}
+ node.SetPosition(n.GetPosition())
+ node.SetLength(n.GetLength())
+ node.SetToken(n.GetToken())
+ node.SetType(dt)
+ node.IsAddress = false
+ node.V, ok = eval(node, v.V)
+ if !ok {
+ return nil
+ }
+ r = node
+
+ case *ast.DecimalValueNode:
+ node := &ast.DecimalValueNode{}
+ node.SetPosition(n.GetPosition())
+ node.SetLength(n.GetLength())
+ node.SetToken(n.GetToken())
+ node.SetType(dt)
+ node.V, ok = eval(node, v.V)
+ if !ok {
+ return nil
+ }
+ r = node
+
+ case *ast.NullValueNode:
+ if dt.Pending() {
+ elAppendTypeErrorOperatorValueNode(el, v, fn, op)
+ return nil
+ }
+ node := &ast.NullValueNode{}
+ node.SetPosition(n.GetPosition())
+ node.SetLength(n.GetLength())
+ node.SetToken(n.GetToken())
+ node.SetType(dt)
+ r = node
+
+ case *ast.BoolValueNode:
+ elAppendTypeErrorOperatorValueNode(el, v, fn, op)
+ return nil
+ case *ast.AddressValueNode:
+ elAppendTypeErrorOperatorValueNode(el, v, fn, op)
+ return nil
+ case *ast.BytesValueNode:
+ elAppendTypeErrorOperatorValueNode(el, v, fn, op)
+ return nil
+ default:
+ panic(unknownValueNodeType(v))
+ }
+ }
+
+ if dt.Pending() {
+ r = checkExpr(r, s, o, c, el, tr, ta)
+ } else {
switch a := ta.(type) {
case typeActionInferDefault:
case typeActionInferWithSize:
case typeActionAssign:
if !dt.Equal(a.dt) {
elAppendTypeErrorMismatch(el, n, fn, a.dt, dt)
+ return nil
}
}
}
- return target
+ return r
}
diff --git a/core/vm/sqlvm/checkers/utils.go b/core/vm/sqlvm/checker/utils.go
index 4a8bbd96e..34b73af4a 100644
--- a/core/vm/sqlvm/checkers/utils.go
+++ b/core/vm/sqlvm/checker/utils.go
@@ -1,4 +1,4 @@
-package checkers
+package checker
import (
"github.com/dexon-foundation/decimal"
@@ -52,6 +52,9 @@ func safeDecimalRange(d decimal.Decimal) bool {
return d.GreaterThanOrEqual(MinConstant) && d.LessThanOrEqual(MaxConstant)
}
+// schemaCache is a multi-layer symbol table used to support the checker.
+// It allows changes to be easily rolled back by keeping modifications in a
+// separate layer, providing an experience similar to a database transaction.
type schemaCache struct {
base schemaCacheBase
scopes []schemaCacheScope
@@ -401,6 +404,8 @@ func (c *schemaCache) DeleteColumn(tr schema.TableRef, n string) bool {
return true
}
+// columnRefSlice implements sort.Interface. It allows sorting a slice of
+// schema.ColumnRef while keeping references to AST nodes they originate from.
type columnRefSlice struct {
columns []schema.ColumnRef
nodes []uint8
@@ -431,11 +436,20 @@ func (s columnRefSlice) Swap(i, j int) {
s.nodes[i], s.nodes[j] = s.nodes[j], s.nodes[i]
}
+// typeAction represents an action on type inference requested from the parent
+// node. An action is usually only applied on a single node. It is seldom
+// propagated to child nodes because we want to delay the assignment of types
+// until it is necessary, making constant operations easier to use without
+// being restricted by data types.
//go-sumtype:decl typeAction
type typeAction interface {
ˉtypeAction()
}
+// typeActionInferDefault requests the node to infer the type using its default
+// rule. It usually means that the parent node does not care the data type,
+// such as the select list in a SELECT statement. It is an advisory request.
+// If the type of the node is already determined, it should ignore the request.
type typeActionInferDefault struct{}
func newTypeActionInferDefaultSize() typeActionInferDefault {
@@ -446,6 +460,11 @@ var _ typeAction = typeActionInferDefault{}
func (typeActionInferDefault) ˉtypeAction() {}
+// typeActionInferWithSize requests the node to infer the type with size
+// requirement. The size is measured in bytes. It is indented to be used in
+// CAST to support conversion between integer and fixed-size bytes types.
+// It is an advisory request. If the type is already determined, the request is
+// ignored and the parent node should be able to handle the problem by itself.
type typeActionInferWithSize struct {
size int
}
@@ -462,6 +481,9 @@ type typeActionAssign struct {
dt ast.DataType
}
+// newTypeActionAssign requests the node to have a specific type. It is a
+// mandatory request. If the node is unable to meet the requirement, it should
+// throw an error. It is not allowed to ignore the request.
func newTypeActionAssign(expected ast.DataType) typeActionAssign {
return typeActionAssign{dt: expected}
}
diff --git a/core/vm/sqlvm/cmd/ast-checker/main.go b/core/vm/sqlvm/cmd/ast-checker/main.go
index c02b58f0f..1c90d5028 100644
--- a/core/vm/sqlvm/cmd/ast-checker/main.go
+++ b/core/vm/sqlvm/cmd/ast-checker/main.go
@@ -7,18 +7,18 @@ import (
"fmt"
"os"
- "github.com/dexon-foundation/dexon/core/vm/sqlvm/checkers"
+ "github.com/dexon-foundation/dexon/core/vm/sqlvm/checker"
"github.com/dexon-foundation/dexon/core/vm/sqlvm/parser"
"github.com/dexon-foundation/dexon/core/vm/sqlvm/schema"
"github.com/dexon-foundation/dexon/rlp"
)
-func create(sql string, o checkers.CheckOptions) int {
+func create(sql string, o checker.CheckOptions) int {
n, parseErr := parser.Parse([]byte(sql))
if parseErr != nil {
fmt.Fprintf(os.Stderr, "Parse error:\n%+v\n", parseErr)
}
- s, checkErr := checkers.CheckCreate(n, o)
+ s, checkErr := checker.CheckCreate(n, o)
if checkErr != nil {
fmt.Fprintf(os.Stderr, "Check error:\n%+v\n", checkErr)
}
@@ -52,42 +52,49 @@ func decode(ss string) int {
return 0
}
-func query(ss, sql string, o checkers.CheckOptions) int {
+func query(ss, sql string, o checker.CheckOptions) int {
fmt.Fprintln(os.Stderr, "Function not implemented")
return 1
}
-func exec(ss, sql string, o checkers.CheckOptions) int {
+func exec(ss, sql string, o checker.CheckOptions) int {
fmt.Fprintln(os.Stderr, "Function not implemented")
return 1
}
func main() {
- var noSafeMath bool
- var noSafeCast bool
- flag.BoolVar(&noSafeMath, "no-safe-math", false, "disable safe math")
- flag.BoolVar(&noSafeCast, "no-safe-cast", false, "disable safe cast")
+ var safeMath bool
+ var safeCast bool
+ var constantOnly bool
+ flag.BoolVar(&safeMath, "safe-math", true, "")
+ flag.BoolVar(&safeCast, "safe-cast", true, "")
+ flag.BoolVar(&constantOnly, "constant-only", false, " (default false)")
flag.Parse()
if flag.NArg() < 1 {
fmt.Fprintf(os.Stderr,
- "Usage: %s <action> <arguments>\n"+
+ "Usage: %s [options] <action> <arguments>\n"+
+ "Options:\n"+
+ " -help Show options\n"+
"Actions:\n"+
- " create <SQL> returns schema\n"+
- " decode <schema> returns SQL\n"+
- " query <schema> <SQL> returns AST\n"+
- " exec <schema> <SQL> returns AST\n",
+ " create (SQL) -> schema\n"+
+ " decode (schema) -> SQL\n"+
+ " query (schema, SQL) -> AST\n"+
+ " exec (schema, SQL) -> AST\n",
os.Args[0])
os.Exit(1)
}
- o := checkers.CheckWithSafeMath | checkers.CheckWithSafeCast
- if noSafeMath {
- o &= ^(checkers.CheckWithSafeMath)
+ var o checker.CheckOptions
+ if safeMath {
+ o |= checker.CheckWithSafeMath
}
- if noSafeCast {
- o &= ^(checkers.CheckWithSafeCast)
+ if safeCast {
+ o |= checker.CheckWithSafeCast
+ }
+ if constantOnly {
+ o |= checker.CheckWithConstantOnly
}
action := flag.Arg(0)