diff options
author | yenlin.lai <yenlin.lai@cobinhood.com> | 2019-04-01 18:03:23 +0800 |
---|---|---|
committer | yenlin.lai <yenlin.lai@cobinhood.com> | 2019-04-03 16:59:48 +0800 |
commit | a1d8558dba947afd56d0cc4a0144537270c1a6fa (patch) | |
tree | 1b830f3066a6f6c960e481607d757ebb08269001 | |
parent | 14a72212c5d80ffdfe1e1a8068779212f5f2057e (diff) | |
download | dexon-a1d8558dba947afd56d0cc4a0144537270c1a6fa.tar.gz dexon-a1d8558dba947afd56d0cc4a0144537270c1a6fa.tar.zst dexon-a1d8558dba947afd56d0cc4a0144537270c1a6fa.zip |
sqlvm: planner: use ColumnDescriptor
-rw-r--r-- | core/vm/sqlvm/planner/planner.go | 74 | ||||
-rw-r--r-- | core/vm/sqlvm/planner/planner_test.go | 326 | ||||
-rw-r--r-- | core/vm/sqlvm/planner/types.go | 2 | ||||
-rw-r--r-- | core/vm/sqlvm/planner/utils.go | 62 | ||||
-rw-r--r-- | core/vm/sqlvm/planner/utils_test.go | 89 |
5 files changed, 386 insertions, 167 deletions
diff --git a/core/vm/sqlvm/planner/planner.go b/core/vm/sqlvm/planner/planner.go index 5f2f06e25..7b4ba4bb9 100644 --- a/core/vm/sqlvm/planner/planner.go +++ b/core/vm/sqlvm/planner/planner.go @@ -1,7 +1,7 @@ package planner import ( - "github.com/shopspring/decimal" + "github.com/dexon-foundation/decimal" "github.com/dexon-foundation/dexon/core/vm/sqlvm/ast" "github.com/dexon-foundation/dexon/core/vm/sqlvm/common" @@ -22,12 +22,9 @@ type planner struct { } func (planner *planner) planInsert(stmt *ast.InsertStmtNode) (PlanStep, error) { - tableIdx, ok := findTableIdxByName(planner.schema, stmt.Table.Name) - if !ok { - panic("Invalid table name.") - } - planner.tableRef = tableIdx - planner.table = &planner.schema[tableIdx] + tableDesc := stmt.Table.Desc.(*schema.TableDescriptor) + planner.tableRef = tableDesc.Table + planner.table = &planner.schema[planner.tableRef] plan := &InsertStep{} plan.Table = planner.tableRef @@ -36,11 +33,7 @@ func (planner *planner) planInsert(stmt *ast.InsertStmtNode) (PlanStep, error) { case *ast.InsertWithColumnOptionNode: plan.Columns = make([]schema.ColumnRef, len(node.Column)) for i, node := range node.Column { - columnIdx, ok := findColumnIdxByName(planner.table, node.Name) - if !ok { - panic("Invalid column name.") - } - plan.Columns[i] = columnIdx + plan.Columns[i] = node.Desc.(*schema.ColumnDescriptor).Column } plan.Values = node.Value case *ast.InsertWithDefaultOptionNode: @@ -67,10 +60,12 @@ func (planner *planner) mergeAndHashKeys(cl *clause) { rightColMap := make([]int, len(cl.SubCls[1].ColumnSet)) for i, j, k := 0, 0, 0; k < colNum; { switch { - case i < len(leftCols) && leftCols[i] == cl.ColumnSet[k]: + case i < len(leftCols) && + compareColumn(leftCols[i], cl.ColumnSet[k]) == 0: leftColMap[i] = k i++ - case j < len(rightCols) && rightCols[j] == cl.ColumnSet[k]: + case j < len(rightCols) && + compareColumn(rightCols[j], cl.ColumnSet[k]) == 0: rightColMap[j] = k j++ default: @@ -138,14 +133,15 @@ func (planner *planner) parseClause(node ast.ExprNode) (*clause, error) { switch op := node.(type) { case *ast.IdentifierNode: // Column. - // TODO(yenlin): bool column is directly enumerable. - colIdx, ok := findColumnIdxByName(planner.table, op.Name) - if !ok { + switch desc := op.Desc.(type) { + case *schema.ColumnDescriptor: + cl.ColumnSet = []*schema.ColumnDescriptor{desc} + default: // This is function name. // TODO(yenlin): distinguish function name from column names. break } - cl.ColumnSet = []schema.ColumnRef{colIdx} + // TODO(yenlin): bool column is directly enumerable. cl.Attr |= clauseAttrColumn case ast.Valuer: // Constant value. @@ -272,8 +268,14 @@ func (planner *planner) planWhereclause( for i, index := range planner.table.Indices { var plan PlanStep - // NOTICE: we need the index.Columns in ascending order. - columnSet := (ColumnSet)(index.Columns) + var columnSet ColumnSet + columnSet = make([]*schema.ColumnDescriptor, len(index.Columns)) + for i := range columnSet { + columnSet[i] = &schema.ColumnDescriptor{ + Table: planner.tableRef, + Column: index.Columns[i], + } + } if clause.Attr&clauseAttrEnumerable != 0 && columnSet.Equal(clause.ColumnSet) { // Values are known for hash. @@ -363,12 +365,9 @@ func (planner *planner) planSelect(stmt *ast.SelectStmtNode) (PlanStep, error) { if stmt.Table == nil { return planner.planSelectWithoutTable(stmt) } - tableIdx, ok := findTableIdxByName(planner.schema, stmt.Table.Name) - if !ok { - panic("Invalid table name.") - } - planner.tableRef = tableIdx - planner.table = &planner.schema[tableIdx] + tableDesc := stmt.Table.Desc.(*schema.TableDescriptor) + planner.tableRef = tableDesc.Table + planner.table = &planner.schema[planner.tableRef] wherePlan, err := planner.planWhere(stmt.Where) if err != nil { @@ -407,12 +406,9 @@ func (planner *planner) planSelect(stmt *ast.SelectStmtNode) (PlanStep, error) { } func (planner *planner) planUpdate(stmt *ast.UpdateStmtNode) (PlanStep, error) { - tableIdx, ok := findTableIdxByName(planner.schema, stmt.Table.Name) - if !ok { - panic("Invalid table name.") - } - planner.tableRef = tableIdx - planner.table = &planner.schema[tableIdx] + tableDesc := stmt.Table.Desc.(*schema.TableDescriptor) + planner.tableRef = tableDesc.Table + planner.table = &planner.schema[planner.tableRef] wherePlan, err := planner.planWhere(stmt.Where) if err != nil { @@ -428,10 +424,7 @@ func (planner *planner) planUpdate(stmt *ast.UpdateStmtNode) (PlanStep, error) { if err != nil { return nil, err } - columnIdx, ok := findColumnIdxByName(planner.table, as.Column.Name) - if !ok { - panic("Invalid column name.") - } + columnIdx := as.Column.Desc.(*schema.ColumnDescriptor).Column plan.Columns[i] = columnIdx plan.Values[i] = as.Expr plan.ColumnSet = plan.ColumnSet.Join(cl.ColumnSet) @@ -441,12 +434,9 @@ func (planner *planner) planUpdate(stmt *ast.UpdateStmtNode) (PlanStep, error) { } func (planner *planner) planDelete(stmt *ast.DeleteStmtNode) (PlanStep, error) { - tableIdx, ok := findTableIdxByName(planner.schema, stmt.Table.Name) - if !ok { - panic("Invalid table name.") - } - planner.tableRef = tableIdx - planner.table = &planner.schema[tableIdx] + tableDesc := stmt.Table.Desc.(*schema.TableDescriptor) + planner.tableRef = tableDesc.Table + planner.table = &planner.schema[planner.tableRef] wherePlan, err := planner.planWhere(stmt.Where) if err != nil { diff --git a/core/vm/sqlvm/planner/planner_test.go b/core/vm/sqlvm/planner/planner_test.go index a1065db1e..a13659a1d 100644 --- a/core/vm/sqlvm/planner/planner_test.go +++ b/core/vm/sqlvm/planner/planner_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/shopspring/decimal" + "github.com/dexon-foundation/decimal" "github.com/stretchr/testify/suite" "github.com/dexon-foundation/dexon/core/vm/sqlvm/ast" @@ -77,11 +77,20 @@ func (s *PlannerTestSuite) TestBasic() { } { stmt := &ast.InsertStmtNode{ - Table: &ast.IdentifierNode{Name: []byte("table1")}, + Table: &ast.IdentifierNode{ + Name: []byte("table1"), + Desc: &schema.TableDescriptor{Table: 0}, + }, Insert: &ast.InsertWithColumnOptionNode{ Column: []*ast.IdentifierNode{ - &ast.IdentifierNode{Name: []byte("a")}, - &ast.IdentifierNode{Name: []byte("b")}, + &ast.IdentifierNode{ + Name: []byte("a"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 0}, + }, + &ast.IdentifierNode{ + Name: []byte("b"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, }, Value: [][]ast.ExprNode{ []ast.ExprNode{ @@ -109,24 +118,38 @@ func (s *PlannerTestSuite) TestBasic() { { expr := &ast.AddOperatorNode{ BinaryOperatorNode: ast.BinaryOperatorNode{ - Object: &ast.IdentifierNode{Name: []byte("b")}, - Subject: &ast.IdentifierNode{Name: []byte("b")}, + Object: &ast.IdentifierNode{ + Name: []byte("b"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, + Subject: &ast.IdentifierNode{ + Name: []byte("b"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, }, } stmt := &ast.UpdateStmtNode{ - Table: &ast.IdentifierNode{Name: []byte("table1")}, + Table: &ast.IdentifierNode{ + Name: []byte("table1"), + Desc: &schema.TableDescriptor{Table: 0}, + }, Assignment: []*ast.AssignOperatorNode{ &ast.AssignOperatorNode{ - Column: &ast.IdentifierNode{Name: []byte("a")}, - Expr: expr, + Column: &ast.IdentifierNode{ + Name: []byte("a"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 0}, + }, + Expr: expr, }, }, } expectedPlan := &UpdateStep{ - Table: 0, - ColumnSet: ColumnSet{1}, - Columns: []schema.ColumnRef{0}, - Values: []ast.ExprNode{expr}, + Table: 0, + ColumnSet: ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, + Columns: []schema.ColumnRef{0}, + Values: []ast.ExprNode{expr}, // Children. PlanStepBase: PlanStepBase{ Operands: []PlanStep{ @@ -149,21 +172,36 @@ func (s *PlannerTestSuite) TestBasic() { offset := decimal.New(20, 0) stmt := &ast.SelectStmtNode{ Column: []ast.ExprNode{ - &ast.IdentifierNode{Name: []byte("a")}, - &ast.IdentifierNode{Name: []byte("b")}, + &ast.IdentifierNode{ + Name: []byte("a"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 0}, + }, + &ast.IdentifierNode{ + Name: []byte("b"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, + }, + Table: &ast.IdentifierNode{ + Name: []byte("table1"), + Desc: &schema.TableDescriptor{Table: 0}, }, - Table: &ast.IdentifierNode{Name: []byte("table1")}, Where: &ast.WhereOptionNode{ Condition: &ast.EqualOperatorNode{ BinaryOperatorNode: ast.BinaryOperatorNode{ - Object: &ast.IdentifierNode{Name: []byte("b")}, + Object: &ast.IdentifierNode{ + Name: []byte("b"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, Subject: &ast.BytesValueNode{V: []byte("valB")}, }, }, }, Order: []*ast.OrderOptionNode{ &ast.OrderOptionNode{ - Expr: &ast.IdentifierNode{Name: []byte("c")}, + Expr: &ast.IdentifierNode{ + Name: []byte("c"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 2}, + }, }, }, Limit: &ast.LimitOptionNode{ @@ -178,15 +216,28 @@ func (s *PlannerTestSuite) TestBasic() { }, } expectedPlan := &SelectStep{ - Table: 0, - ColumnSet: ColumnSet{0, 1, 2}, + Table: 0, + ColumnSet: ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + &schema.ColumnDescriptor{Table: 0, Column: 1}, + &schema.ColumnDescriptor{Table: 0, Column: 2}, + }, Columns: []ast.ExprNode{ - &ast.IdentifierNode{Name: []byte("a")}, - &ast.IdentifierNode{Name: []byte("b")}, + &ast.IdentifierNode{ + Name: []byte("a"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 0}, + }, + &ast.IdentifierNode{ + Name: []byte("b"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, }, Order: []*ast.OrderOptionNode{ &ast.OrderOptionNode{ - Expr: &ast.IdentifierNode{Name: []byte("c")}, + Expr: &ast.IdentifierNode{ + Name: []byte("c"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 2}, + }, }, }, Limit: &limit, @@ -277,11 +328,17 @@ func (s *PlannerTestSuite) TestBasic() { } { stmt := &ast.DeleteStmtNode{ - Table: &ast.IdentifierNode{Name: []byte("table1")}, + Table: &ast.IdentifierNode{ + Name: []byte("table1"), + Desc: &schema.TableDescriptor{Table: 0}, + }, Where: &ast.WhereOptionNode{ Condition: &ast.GreaterOperatorNode{ BinaryOperatorNode: ast.BinaryOperatorNode{ - Object: &ast.IdentifierNode{Name: []byte("b")}, + Object: &ast.IdentifierNode{ + Name: []byte("b"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, Subject: &ast.BytesValueNode{V: []byte("valB")}, }, }, @@ -297,7 +354,10 @@ func (s *PlannerTestSuite) TestBasic() { Index: 1, Condition: &ast.GreaterOperatorNode{ BinaryOperatorNode: ast.BinaryOperatorNode{ - Object: &ast.IdentifierNode{Name: []byte("b")}, + Object: &ast.IdentifierNode{ + Name: []byte("b"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, Subject: &ast.BytesValueNode{V: []byte("valB")}, }, }, @@ -368,12 +428,19 @@ func (s *PlannerTestSuite) TestHashKeys() { { // Test AND merge. cl := &clause{ - ColumnSet: []schema.ColumnRef{0, 1, 2}, - Attr: clauseAttrAnd | clauseAttrEnumerable, + ColumnSet: ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + &schema.ColumnDescriptor{Table: 0, Column: 1}, + &schema.ColumnDescriptor{Table: 0, Column: 2}, + }, + Attr: clauseAttrAnd | clauseAttrEnumerable, SubCls: []*clause{ &clause{ - ColumnSet: []schema.ColumnRef{0, 2}, - Attr: clauseAttrEnumerable, + ColumnSet: ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + &schema.ColumnDescriptor{Table: 0, Column: 2}, + }, + Attr: clauseAttrEnumerable, HashKeys: [][]ast.Valuer{ genCombination([]schema.ColumnRef{0, 2}, []int{0, 0}), genCombination([]schema.ColumnRef{0, 2}, []int{1, 1}), @@ -381,8 +448,10 @@ func (s *PlannerTestSuite) TestHashKeys() { }, }, &clause{ - ColumnSet: []schema.ColumnRef{1}, - Attr: clauseAttrEnumerable, + ColumnSet: ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, + Attr: clauseAttrEnumerable, HashKeys: [][]ast.Valuer{ genCombination([]schema.ColumnRef{1}, []int{0}), genCombination([]schema.ColumnRef{1}, []int{1}), @@ -404,17 +473,26 @@ func (s *PlannerTestSuite) TestHashKeys() { { // Test AND merge boundary with one size empty. cl := &clause{ - ColumnSet: []schema.ColumnRef{0, 1, 2}, - Attr: clauseAttrAnd | clauseAttrEnumerable, + ColumnSet: ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + &schema.ColumnDescriptor{Table: 0, Column: 1}, + &schema.ColumnDescriptor{Table: 0, Column: 2}, + }, + Attr: clauseAttrAnd | clauseAttrEnumerable, SubCls: []*clause{ &clause{ - ColumnSet: []schema.ColumnRef{0, 2}, - Attr: clauseAttrEnumerable, - HashKeys: [][]ast.Valuer{}, + ColumnSet: ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + &schema.ColumnDescriptor{Table: 0, Column: 2}, + }, + Attr: clauseAttrEnumerable, + HashKeys: [][]ast.Valuer{}, }, &clause{ - ColumnSet: []schema.ColumnRef{1}, - Attr: clauseAttrEnumerable, + ColumnSet: ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, + Attr: clauseAttrEnumerable, HashKeys: [][]ast.Valuer{ genCombination([]schema.ColumnRef{1}, []int{0}), genCombination([]schema.ColumnRef{1}, []int{1}), @@ -426,12 +504,19 @@ func (s *PlannerTestSuite) TestHashKeys() { expectedKeys := [][]ast.Valuer{} s.Require().Equal(expectedKeys, cl.HashKeys) cl = &clause{ - ColumnSet: []schema.ColumnRef{0, 1, 2}, - Attr: clauseAttrAnd | clauseAttrEnumerable, + ColumnSet: ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + &schema.ColumnDescriptor{Table: 0, Column: 1}, + &schema.ColumnDescriptor{Table: 0, Column: 2}, + }, + Attr: clauseAttrAnd | clauseAttrEnumerable, SubCls: []*clause{ &clause{ - ColumnSet: []schema.ColumnRef{0, 2}, - Attr: clauseAttrEnumerable, + ColumnSet: ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + &schema.ColumnDescriptor{Table: 0, Column: 2}, + }, + Attr: clauseAttrEnumerable, HashKeys: [][]ast.Valuer{ genCombination([]schema.ColumnRef{0, 2}, []int{0, 0}), genCombination([]schema.ColumnRef{0, 2}, []int{1, 1}), @@ -439,9 +524,11 @@ func (s *PlannerTestSuite) TestHashKeys() { }, }, &clause{ - ColumnSet: []schema.ColumnRef{1}, - Attr: clauseAttrEnumerable, - HashKeys: [][]ast.Valuer{}, + ColumnSet: ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, + Attr: clauseAttrEnumerable, + HashKeys: [][]ast.Valuer{}, }, }, } @@ -452,20 +539,29 @@ func (s *PlannerTestSuite) TestHashKeys() { { // Test OR merge. cl := &clause{ - ColumnSet: []schema.ColumnRef{0, 2}, - Attr: clauseAttrOr | clauseAttrEnumerable, + ColumnSet: ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + &schema.ColumnDescriptor{Table: 0, Column: 2}, + }, + Attr: clauseAttrOr | clauseAttrEnumerable, SubCls: []*clause{ &clause{ - ColumnSet: []schema.ColumnRef{0, 2}, - Attr: clauseAttrEnumerable, + ColumnSet: ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + &schema.ColumnDescriptor{Table: 0, Column: 2}, + }, + Attr: clauseAttrEnumerable, HashKeys: [][]ast.Valuer{ genCombination([]schema.ColumnRef{0, 2}, []int{0, 0}), genCombination([]schema.ColumnRef{0, 2}, []int{1, 1}), }, }, &clause{ - ColumnSet: []schema.ColumnRef{0, 2}, - Attr: clauseAttrEnumerable, + ColumnSet: ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + &schema.ColumnDescriptor{Table: 0, Column: 2}, + }, + Attr: clauseAttrEnumerable, HashKeys: [][]ast.Valuer{ genCombination([]schema.ColumnRef{0, 2}, []int{1, 2}), genCombination([]schema.ColumnRef{0, 2}, []int{2, 1}), @@ -487,7 +583,7 @@ func (s *PlannerTestSuite) TestHashKeys() { } func (s *PlannerTestSuite) TestClauseAttr() { - var schema schema.Schema = []schema.Table{ + var dbSchema schema.Schema = []schema.Table{ s.createTable( []byte("table1"), [][]byte{ @@ -503,16 +599,22 @@ func (s *PlannerTestSuite) TestClauseAttr() { ), } planner := planner{ - schema: schema, - table: &schema[0], + schema: dbSchema, + table: &dbSchema[0], + tableRef: 0, } { - node := &ast.IdentifierNode{Name: []byte("a")} + node := &ast.IdentifierNode{ + Name: []byte("a"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 0}, + } cl, err := planner.parseClause(node) s.Require().Nil(err) s.Require().Equal(clauseAttrColumn, cl.Attr) - s.Require().Equal(ColumnSet{0}, cl.ColumnSet) + s.Require().Equal(ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + }, cl.ColumnSet) s.Require().Zero(cl.HashKeys) } { @@ -527,27 +629,37 @@ func (s *PlannerTestSuite) TestClauseAttr() { valA := &ast.BytesValueNode{V: []byte("valA")} node := &ast.EqualOperatorNode{ BinaryOperatorNode: ast.BinaryOperatorNode{ - Object: &ast.IdentifierNode{Name: []byte("a")}, + Object: &ast.IdentifierNode{ + Name: []byte("a"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 0}, + }, Subject: valA, }, } cl, err := planner.parseClause(node) s.Require().Nil(err) s.Require().Equal(clauseAttrEnumerable, cl.Attr) - s.Require().Equal(ColumnSet{0}, cl.ColumnSet) + s.Require().Equal(ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + }, cl.ColumnSet) s.Require().Equal([][]ast.Valuer{[]ast.Valuer{valA}}, cl.HashKeys) } { node := &ast.GreaterOrEqualOperatorNode{ BinaryOperatorNode: ast.BinaryOperatorNode{ - Object: &ast.IdentifierNode{Name: []byte("a")}, + Object: &ast.IdentifierNode{ + Name: []byte("a"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 0}, + }, Subject: &ast.BytesValueNode{V: []byte("valA")}, }, } cl, err := planner.parseClause(node) s.Require().Nil(err) s.Require().Zero(cl.Attr) - s.Require().Equal(ColumnSet{0}, cl.ColumnSet) + s.Require().Equal(ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + }, cl.ColumnSet) s.Require().Zero(cl.HashKeys) } { @@ -557,13 +669,19 @@ func (s *PlannerTestSuite) TestClauseAttr() { BinaryOperatorNode: ast.BinaryOperatorNode{ Object: &ast.EqualOperatorNode{ BinaryOperatorNode: ast.BinaryOperatorNode{ - Object: &ast.IdentifierNode{Name: []byte("b")}, + Object: &ast.IdentifierNode{ + Name: []byte("b"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, Subject: valB, }, }, Subject: &ast.EqualOperatorNode{ BinaryOperatorNode: ast.BinaryOperatorNode{ - Object: &ast.IdentifierNode{Name: []byte("a")}, + Object: &ast.IdentifierNode{ + Name: []byte("a"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 0}, + }, Subject: valA, }, }, @@ -572,7 +690,10 @@ func (s *PlannerTestSuite) TestClauseAttr() { cl, err := planner.parseClause(node) s.Require().Nil(err) s.Require().Equal(clauseAttrEnumerable|clauseAttrAnd, cl.Attr) - s.Require().Equal(ColumnSet{0, 1}, cl.ColumnSet) + s.Require().Equal(ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, cl.ColumnSet) s.Require().Equal([][]ast.Valuer{ []ast.Valuer{valA, valB}, }, cl.HashKeys) @@ -582,13 +703,19 @@ func (s *PlannerTestSuite) TestClauseAttr() { BinaryOperatorNode: ast.BinaryOperatorNode{ Object: &ast.EqualOperatorNode{ BinaryOperatorNode: ast.BinaryOperatorNode{ - Object: &ast.IdentifierNode{Name: []byte("a")}, + Object: &ast.IdentifierNode{ + Name: []byte("a"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 0}, + }, Subject: &ast.BytesValueNode{V: []byte("valA")}, }, }, Subject: &ast.EqualOperatorNode{ BinaryOperatorNode: ast.BinaryOperatorNode{ - Object: &ast.IdentifierNode{Name: []byte("b")}, + Object: &ast.IdentifierNode{ + Name: []byte("b"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, Subject: &ast.BytesValueNode{V: []byte("valB")}, }, }, @@ -597,7 +724,10 @@ func (s *PlannerTestSuite) TestClauseAttr() { cl, err := planner.parseClause(node) s.Require().Nil(err) s.Require().Equal(clauseAttrOr, cl.Attr) - s.Require().Equal(ColumnSet{0, 1}, cl.ColumnSet) + s.Require().Equal(ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, cl.ColumnSet) s.Require().Zero(cl.HashKeys) } { @@ -607,13 +737,19 @@ func (s *PlannerTestSuite) TestClauseAttr() { BinaryOperatorNode: ast.BinaryOperatorNode{ Object: &ast.EqualOperatorNode{ BinaryOperatorNode: ast.BinaryOperatorNode{ - Object: &ast.IdentifierNode{Name: []byte("b")}, + Object: &ast.IdentifierNode{ + Name: []byte("b"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, Subject: valA, }, }, Subject: &ast.EqualOperatorNode{ BinaryOperatorNode: ast.BinaryOperatorNode{ - Object: &ast.IdentifierNode{Name: []byte("b")}, + Object: &ast.IdentifierNode{ + Name: []byte("b"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, Subject: valB, }, }, @@ -622,7 +758,9 @@ func (s *PlannerTestSuite) TestClauseAttr() { cl, err := planner.parseClause(node) s.Require().Nil(err) s.Require().Equal(clauseAttrOr|clauseAttrEnumerable, cl.Attr) - s.Require().Equal(ColumnSet{1}, cl.ColumnSet) + s.Require().Equal(ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, cl.ColumnSet) s.Require().Equal([][]ast.Valuer{ []ast.Valuer{valA}, []ast.Valuer{valB}, @@ -634,14 +772,20 @@ func (s *PlannerTestSuite) TestClauseAttr() { node := &ast.InOperatorNode{ Left: &ast.EqualOperatorNode{ BinaryOperatorNode: ast.BinaryOperatorNode{ - Object: &ast.IdentifierNode{Name: []byte("a")}, + Object: &ast.IdentifierNode{ + Name: []byte("a"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 0}, + }, Subject: valA, }, }, Right: []ast.ExprNode{ &ast.EqualOperatorNode{ BinaryOperatorNode: ast.BinaryOperatorNode{ - Object: &ast.IdentifierNode{Name: []byte("b")}, + Object: &ast.IdentifierNode{ + Name: []byte("b"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, Subject: valB, }, }, @@ -650,14 +794,20 @@ func (s *PlannerTestSuite) TestClauseAttr() { cl, err := planner.parseClause(node) s.Require().Nil(err) s.Require().Zero(cl.Attr) - s.Require().Equal(ColumnSet{0, 1}, cl.ColumnSet) + s.Require().Equal(ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, cl.ColumnSet) s.Require().Zero(cl.HashKeys) } { valA := &ast.BytesValueNode{V: []byte("valA")} valB := &ast.BytesValueNode{V: []byte("valB")} node := &ast.InOperatorNode{ - Left: &ast.IdentifierNode{Name: []byte("a")}, + Left: &ast.IdentifierNode{ + Name: []byte("a"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 0}, + }, Right: []ast.ExprNode{ valA, valB, }, @@ -665,7 +815,9 @@ func (s *PlannerTestSuite) TestClauseAttr() { cl, err := planner.parseClause(node) s.Require().Nil(err) s.Require().Equal(clauseAttrEnumerable, cl.Attr) - s.Require().Equal(ColumnSet{0}, cl.ColumnSet) + s.Require().Equal(ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + }, cl.ColumnSet) s.Require().Equal([][]ast.Valuer{ []ast.Valuer{valA}, []ast.Valuer{valB}, @@ -675,8 +827,14 @@ func (s *PlannerTestSuite) TestClauseAttr() { node := &ast.CastOperatorNode{ SourceExpr: &ast.AddOperatorNode{ BinaryOperatorNode: ast.BinaryOperatorNode{ - Object: &ast.IdentifierNode{Name: []byte("a")}, - Subject: &ast.IdentifierNode{Name: []byte("b")}, + Object: &ast.IdentifierNode{ + Name: []byte("a"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 0}, + }, + Subject: &ast.IdentifierNode{ + Name: []byte("b"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, }, }, TargetType: &ast.IntTypeNode{ @@ -687,13 +845,19 @@ func (s *PlannerTestSuite) TestClauseAttr() { cl, err := planner.parseClause(node) s.Require().Nil(err) s.Require().Zero(cl.Attr) - s.Require().Equal(ColumnSet{0, 1}, cl.ColumnSet) + s.Require().Equal(ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + &schema.ColumnDescriptor{Table: 0, Column: 1}, + }, cl.ColumnSet) s.Require().Zero(cl.HashKeys) } { node := &ast.EqualOperatorNode{ BinaryOperatorNode: ast.BinaryOperatorNode{ - Object: &ast.IdentifierNode{Name: []byte("a")}, + Object: &ast.IdentifierNode{ + Name: []byte("a"), + Desc: &schema.ColumnDescriptor{Table: 0, Column: 0}, + }, Subject: &ast.FunctionOperatorNode{ Name: &ast.IdentifierNode{Name: []byte("RAND")}, }, @@ -702,7 +866,9 @@ func (s *PlannerTestSuite) TestClauseAttr() { cl, err := planner.parseClause(node) s.Require().Nil(err) s.Require().Equal(clauseAttrForceScan, cl.Attr) - s.Require().Equal(ColumnSet{0}, cl.ColumnSet) + s.Require().Equal(ColumnSet{ + &schema.ColumnDescriptor{Table: 0, Column: 0}, + }, cl.ColumnSet) s.Require().Zero(cl.HashKeys) } } diff --git a/core/vm/sqlvm/planner/types.go b/core/vm/sqlvm/planner/types.go index eb5c4f3a0..d93c3e850 100644 --- a/core/vm/sqlvm/planner/types.go +++ b/core/vm/sqlvm/planner/types.go @@ -1,7 +1,7 @@ package planner import ( - "github.com/shopspring/decimal" + "github.com/dexon-foundation/decimal" "github.com/dexon-foundation/dexon/core/vm/sqlvm/ast" "github.com/dexon-foundation/dexon/core/vm/sqlvm/schema" diff --git a/core/vm/sqlvm/planner/utils.go b/core/vm/sqlvm/planner/utils.go index e1aad047a..912f32346 100644 --- a/core/vm/sqlvm/planner/utils.go +++ b/core/vm/sqlvm/planner/utils.go @@ -37,21 +37,55 @@ func findColumnIdxByName(table *schema.Table, name []byte) ( } // ColumnSet is a sorted slice of column idxs. -type ColumnSet []schema.ColumnRef +type ColumnSet []*schema.ColumnDescriptor + +func compareTableRef(a, b schema.TableRef) int { + switch { + case a > b: + return 1 + case a == b: + return 0 + default: + return -1 + } +} + +func compareColumnRef(a, b schema.ColumnRef) int { + switch { + case a > b: + return 1 + case a == b: + return 0 + default: + return -1 + } +} + +func compareColumn(a, b *schema.ColumnDescriptor) int { + comp := compareTableRef(a.Table, b.Table) + switch comp { + case 0: + return compareColumnRef(a.Column, b.Column) + default: + return comp + } +} // Join creates a new set which is the union of c and other. func (c ColumnSet) Join(other ColumnSet) ColumnSet { - ret := make([]schema.ColumnRef, 0, len(c)+len(other)) + ret := make([]*schema.ColumnDescriptor, 0, len(c)+len(other)) i, j := 0, 0 for i != len(c) && j != len(other) { - if c[i] == other[j] { + comp := compareColumn(c[i], other[j]) + switch comp { + case 0: ret = append(ret, c[i]) i++ j++ - } else if c[i] > other[j] { + case 1: ret = append(ret, other[j]) j++ - } else { + case -1: ret = append(ret, c[i]) i++ } @@ -73,7 +107,7 @@ func (c ColumnSet) Equal(other ColumnSet) bool { return false } for i := range c { - if c[i] != other[i] { + if compareColumn(c[i], other[i]) != 0 { return false } } @@ -84,12 +118,13 @@ func (c ColumnSet) Equal(other ColumnSet) bool { func (c ColumnSet) IsDisjoint(other ColumnSet) bool { i, j := 0, 0 for i != len(c) && j != len(other) { - if c[i] == other[j] { + comp := compareColumn(c[i], other[j]) + switch comp { + case 0: return false - } - if c[i] > other[j] { + case 1: j++ - } else { + case -1: i++ } } @@ -100,11 +135,12 @@ func (c ColumnSet) IsDisjoint(other ColumnSet) bool { func (c ColumnSet) Contains(other ColumnSet) bool { i, j := 0, 0 for i != len(c) && j != len(other) { - if c[i] > other[j] { + comp := compareColumn(c[i], other[j]) + switch comp { + case 1: // Found some item not in c. return false - } - if c[i] == other[j] { + case 0: j++ } i++ diff --git a/core/vm/sqlvm/planner/utils_test.go b/core/vm/sqlvm/planner/utils_test.go index 3e3d90a8d..6053a3180 100644 --- a/core/vm/sqlvm/planner/utils_test.go +++ b/core/vm/sqlvm/planner/utils_test.go @@ -4,28 +4,44 @@ import ( "testing" "github.com/stretchr/testify/suite" + + "github.com/dexon-foundation/dexon/core/vm/sqlvm/schema" ) type PlannerUtilsTestSuite struct{ suite.Suite } +func makeColumnSet(cols []uint8) ColumnSet { + var ret ColumnSet = make([]*schema.ColumnDescriptor, len(cols)) + for i := range ret { + ret[i] = &schema.ColumnDescriptor{ + Table: 0, + Column: schema.ColumnRef(cols[i]), + } + } + return ret +} + func (s *PlannerUtilsTestSuite) TestColumnSet() { { // Join. var columns, expected ColumnSet - columns = ColumnSet{1, 3, 5}.Join(ColumnSet{0, 1, 2, 4, 6}) - expected = ColumnSet{0, 1, 2, 3, 4, 5, 6} + columns = makeColumnSet([]uint8{1, 3, 5}).Join( + makeColumnSet([]uint8{0, 1, 2, 4, 6})) + expected = makeColumnSet([]uint8{0, 1, 2, 3, 4, 5, 6}) s.Require().Equal(expected, columns) - columns = ColumnSet{1, 3, 5}.Join(ColumnSet{3, 5}) - expected = ColumnSet{1, 3, 5} + columns = makeColumnSet([]uint8{1, 3, 5}).Join( + makeColumnSet([]uint8{3, 5})) + expected = makeColumnSet([]uint8{1, 3, 5}) s.Require().Equal(expected, columns) - columns = ColumnSet{}.Join(ColumnSet{0}) - expected = ColumnSet{0} + columns = ColumnSet{}.Join(makeColumnSet([]uint8{0})) + expected = makeColumnSet([]uint8{0}) s.Require().Equal(expected, columns) - columns = ColumnSet{1}.Join(ColumnSet{1, 3}) - expected = ColumnSet{1, 3} + columns = makeColumnSet([]uint8{1}).Join( + makeColumnSet([]uint8{1, 3})) + expected = makeColumnSet([]uint8{1, 3}) s.Require().Equal(expected, columns) - columns = ColumnSet{5}.Join(ColumnSet{1, 3}) - expected = ColumnSet{1, 3, 5} + columns = makeColumnSet([]uint8{5}).Join(makeColumnSet([]uint8{1, 3})) + expected = makeColumnSet([]uint8{1, 3, 5}) s.Require().Equal(expected, columns) } { @@ -34,18 +50,18 @@ func (s *PlannerUtilsTestSuite) TestColumnSet() { // True cases. equal = ColumnSet{}.Equal(ColumnSet{}) s.Require().True(equal) - equal = ColumnSet{1, 2}.Equal(ColumnSet{1, 2}) + equal = makeColumnSet([]uint8{1, 2}).Equal(makeColumnSet([]uint8{1, 2})) s.Require().True(equal) // False cases. - equal = ColumnSet{}.Equal(ColumnSet{1, 2}) + equal = ColumnSet{}.Equal(makeColumnSet([]uint8{1, 2})) s.Require().False(equal) - equal = ColumnSet{1, 2}.Equal(ColumnSet{}) + equal = makeColumnSet([]uint8{1, 2}).Equal(ColumnSet{}) s.Require().False(equal) - equal = ColumnSet{2}.Equal(ColumnSet{1}) + equal = makeColumnSet([]uint8{2}).Equal(makeColumnSet([]uint8{1})) s.Require().False(equal) - equal = ColumnSet{2}.Equal(ColumnSet{1, 3}) + equal = makeColumnSet([]uint8{2}).Equal(makeColumnSet([]uint8{1, 3})) s.Require().False(equal) - equal = ColumnSet{1, 3}.Equal(ColumnSet{2}) + equal = makeColumnSet([]uint8{1, 3}).Equal(makeColumnSet([]uint8{2})) s.Require().False(equal) } { @@ -54,22 +70,28 @@ func (s *PlannerUtilsTestSuite) TestColumnSet() { // True cases. contains = ColumnSet{}.Contains(ColumnSet{}) s.Require().True(contains) - contains = ColumnSet{1, 2}.Contains(ColumnSet{}) + contains = makeColumnSet([]uint8{1, 2}).Contains(ColumnSet{}) s.Require().True(contains) - contains = ColumnSet{1, 2}.Contains(ColumnSet{2}) + contains = makeColumnSet([]uint8{1, 2}).Contains( + makeColumnSet([]uint8{2})) s.Require().True(contains) - contains = ColumnSet{1, 2}.Contains(ColumnSet{1}) + contains = makeColumnSet([]uint8{1, 2}).Contains( + makeColumnSet([]uint8{1})) s.Require().True(contains) - contains = ColumnSet{1, 2, 3}.Contains(ColumnSet{1, 2}) + contains = makeColumnSet([]uint8{1, 2, 3}).Contains( + makeColumnSet([]uint8{1, 2})) s.Require().True(contains) // False cases. - contains = ColumnSet{1}.Contains(ColumnSet{2}) + contains = makeColumnSet([]uint8{1}).Contains(makeColumnSet([]uint8{2})) s.Require().False(contains) - contains = ColumnSet{2}.Contains(ColumnSet{1, 2}) + contains = makeColumnSet([]uint8{2}).Contains( + makeColumnSet([]uint8{1, 2})) s.Require().False(contains) - contains = ColumnSet{1}.Contains(ColumnSet{1, 2}) + contains = makeColumnSet([]uint8{1}).Contains( + makeColumnSet([]uint8{1, 2})) s.Require().False(contains) - contains = ColumnSet{1, 3, 5}.Contains(ColumnSet{4}) + contains = makeColumnSet([]uint8{1, 3, 5}).Contains( + makeColumnSet([]uint8{4})) s.Require().False(contains) } { @@ -78,20 +100,25 @@ func (s *PlannerUtilsTestSuite) TestColumnSet() { // True cases. disjoin = ColumnSet{}.IsDisjoint(ColumnSet{}) s.Require().True(disjoin) - disjoin = ColumnSet{}.IsDisjoint(ColumnSet{1}) + disjoin = ColumnSet{}.IsDisjoint(makeColumnSet([]uint8{1})) s.Require().True(disjoin) - disjoin = ColumnSet{1}.IsDisjoint(ColumnSet{}) + disjoin = makeColumnSet([]uint8{1}).IsDisjoint(ColumnSet{}) s.Require().True(disjoin) - disjoin = ColumnSet{1}.IsDisjoint(ColumnSet{2}) + disjoin = makeColumnSet([]uint8{1}).IsDisjoint( + makeColumnSet([]uint8{2})) s.Require().True(disjoin) // False cases. - disjoin = ColumnSet{1, 2}.IsDisjoint(ColumnSet{2}) + disjoin = makeColumnSet([]uint8{1, 2}).IsDisjoint( + makeColumnSet([]uint8{2})) s.Require().False(disjoin) - disjoin = ColumnSet{1, 2}.IsDisjoint(ColumnSet{1}) + disjoin = makeColumnSet([]uint8{1, 2}).IsDisjoint( + makeColumnSet([]uint8{1})) s.Require().False(disjoin) - disjoin = ColumnSet{1, 2}.IsDisjoint(ColumnSet{0, 2}) + disjoin = makeColumnSet([]uint8{1, 2}).IsDisjoint( + makeColumnSet([]uint8{0, 2})) s.Require().False(disjoin) - disjoin = ColumnSet{1, 7}.IsDisjoint(ColumnSet{5, 6, 7}) + disjoin = makeColumnSet([]uint8{1, 7}).IsDisjoint( + makeColumnSet([]uint8{5, 6, 7})) s.Require().False(disjoin) } } |