diff options
author | Meng-Ying Yang <garfield@dexon.org> | 2019-04-08 10:20:21 +0800 |
---|---|---|
committer | Jhih-Ming Huang <jm.huang@cobinhood.com> | 2019-05-06 10:44:04 +0800 |
commit | 7fa7af1678bcca79484b7e1b11bf9efdb3ae999c (patch) | |
tree | fd003a777518f6e9478cc3639a13255ef4ac93af | |
parent | b35152c24e637d0e26b6a061466999faadcaa7e4 (diff) | |
download | dexon-7fa7af1678bcca79484b7e1b11bf9efdb3ae999c.tar.gz dexon-7fa7af1678bcca79484b7e1b11bf9efdb3ae999c.tar.zst dexon-7fa7af1678bcca79484b7e1b11bf9efdb3ae999c.zip |
core: vm: sqlvm: add opCut
Add `opCut` which supports slice cutting.
-rw-r--r-- | core/vm/sqlvm/runtime/instructions.go | 29 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/instructions_op_test.go | 229 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/instructions_tmpl_data.go | 202 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/jumptable.go | 1 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/opcodes.go | 1 |
5 files changed, 462 insertions, 0 deletions
diff --git a/core/vm/sqlvm/runtime/instructions.go b/core/vm/sqlvm/runtime/instructions.go index e3a414123..cc00f741e 100644 --- a/core/vm/sqlvm/runtime/instructions.go +++ b/core/vm/sqlvm/runtime/instructions.go @@ -1369,6 +1369,35 @@ func pruneTuple(t Tuple, prune []int) Tuple { } // in-place Op +func opCut(ctx *common.Context, ops, registers []*Operand, output uint) (err error) { + if len(ops) != 2 { + err = se.ErrorCodeInvalidOperandNum + return + } + op, slice := ops[0], ops[1].Data[0] + + maxL := uint16(len(op.Meta)) + start, end := value2ColIdx(slice[0].Value), maxL + if len(slice) > 1 { + end = value2ColIdx(slice[1].Value) + 1 + } + + if start > maxL || end > maxL || start > end { + err = se.ErrorCodeIndexOutOfRange + return + } + + op.Meta = append(op.Meta[:start], op.Meta[end:]...) + + for i := 0; i < len(op.Data); i++ { + op.Data[i] = append(op.Data[i][:start], op.Data[i][end:]...) + } + + registers[output] = op + return +} + +// in-place Op func opSort(ctx *common.Context, ops, registers []*Operand, output uint) (err error) { if len(ops) != 2 { err = se.ErrorCodeInvalidOperandNum diff --git a/core/vm/sqlvm/runtime/instructions_op_test.go b/core/vm/sqlvm/runtime/instructions_op_test.go index a3f84037b..0255e74cf 100644 --- a/core/vm/sqlvm/runtime/instructions_op_test.go +++ b/core/vm/sqlvm/runtime/instructions_op_test.go @@ -2448,6 +2448,235 @@ func (s *instructionSuite) TestOpPrune() { s.run(testcases, opPrune) } +func (s *instructionSuite) TestOpCut() { + testcases := []opTestcase{ + { + "Cut 2nd to 4th columns", + Instruction{ + Op: CUT, + Input: []*Operand{ + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorBool, 0), ast.ComposeDataType(ast.DataTypeMajorBool, 0), + }, + []Tuple{ + {&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(1)}, rawFalse, rawTrue}, + {&Raw{Bytes: []byte("abcdefg-2")}, &Raw{Bytes: []byte("gfedcba-2")}, &Raw{Value: decimal.NewFromFloat(2)}, rawTrue, rawFalse}, + }, + ), + makeOperand( + true, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), + }, + []Tuple{ + {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(3)}}, + }, + ), + }, + Output: 0, + }, + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorBool, 0), + }, + []Tuple{ + {&Raw{Bytes: []byte("abcdefg-1")}, rawTrue}, + {&Raw{Bytes: []byte("abcdefg-2")}, rawFalse}, + }, + ), + nil, + }, + { + "Cut 1st column", + Instruction{ + Op: CUT, + Input: []*Operand{ + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorBool, 0), ast.ComposeDataType(ast.DataTypeMajorBool, 0), + }, + []Tuple{ + {&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(1)}, rawFalse, rawTrue}, + {&Raw{Bytes: []byte("abcdefg-2")}, &Raw{Bytes: []byte("gfedcba-2")}, &Raw{Value: decimal.NewFromFloat(2)}, rawTrue, rawFalse}, + }, + ), + makeOperand( + true, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), + }, + []Tuple{ + {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}}, + }, + ), + }, + Output: 0, + }, + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorBool, 0), ast.ComposeDataType(ast.DataTypeMajorBool, 0), + }, + []Tuple{ + {&Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(1)}, rawFalse, rawTrue}, + {&Raw{Bytes: []byte("gfedcba-2")}, &Raw{Value: decimal.NewFromFloat(2)}, rawTrue, rawFalse}, + }, + ), + nil, + }, + { + "Cut since 2nd column", + Instruction{ + Op: CUT, + Input: []*Operand{ + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorBool, 0), + }, + []Tuple{ + {&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(1)}, rawTrue}, + {&Raw{Bytes: []byte("abcdefg-2")}, &Raw{Bytes: []byte("gfedcba-2")}, &Raw{Value: decimal.NewFromFloat(2)}, rawFalse}, + }, + ), + makeOperand( + true, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorInt, 0), + }, + []Tuple{ + {&Raw{Value: decimal.NewFromFloat(1)}}, + }, + ), + }, + Output: 0, + }, + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), + }, + []Tuple{ + {&Raw{Bytes: []byte("abcdefg-1")}}, + {&Raw{Bytes: []byte("abcdefg-2")}}, + }, + ), + nil, + }, + { + "Cut all columns", + Instruction{ + Op: CUT, + Input: []*Operand{ + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorBool, 0), + }, + []Tuple{ + {&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(1)}, rawTrue}, + {&Raw{Bytes: []byte("abcdefg-2")}, &Raw{Bytes: []byte("gfedcba-2")}, &Raw{Value: decimal.NewFromFloat(2)}, rawFalse}, + }, + ), + makeOperand( + true, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorInt, 0), + }, + []Tuple{ + {&Raw{Value: decimal.NewFromFloat(0)}}, + }, + ), + }, + Output: 0, + }, + makeOperand( + false, + []ast.DataType{}, + []Tuple{ + {}, + {}, + }, + ), + nil, + }, + { + "Cut error range - 1", + Instruction{ + Op: CUT, + Input: []*Operand{ + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorBool, 0), + }, + []Tuple{ + {&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(1)}, rawTrue}, + {&Raw{Bytes: []byte("abcdefg-2")}, &Raw{Bytes: []byte("gfedcba-2")}, &Raw{Value: decimal.NewFromFloat(2)}, rawFalse}, + }, + ), + makeOperand( + true, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorInt, 0), + }, + []Tuple{ + {&Raw{Value: decimal.NewFromFloat(5)}}, + }, + ), + }, + Output: 0, + }, + makeOperand( + false, + []ast.DataType{}, + []Tuple{}, + ), + errors.ErrorCodeIndexOutOfRange, + }, + { + "Cut error range - 2", + Instruction{ + Op: CUT, + Input: []*Operand{ + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorBool, 0), + }, + []Tuple{ + {&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(1)}, rawTrue}, + {&Raw{Bytes: []byte("abcdefg-2")}, &Raw{Bytes: []byte("gfedcba-2")}, &Raw{Value: decimal.NewFromFloat(2)}, rawFalse}, + }, + ), + makeOperand( + true, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), + }, + []Tuple{ + {&Raw{Value: decimal.NewFromFloat(15)}, &Raw{Value: decimal.NewFromFloat(17)}}, + }, + ), + }, + Output: 0, + }, + makeOperand( + false, + []ast.DataType{}, + []Tuple{}, + ), + errors.ErrorCodeIndexOutOfRange, + }, + } + + s.run(testcases, opCut) +} + func (s *instructionSuite) TestOpFilter() { testcases := []opTestcase{ { diff --git a/core/vm/sqlvm/runtime/instructions_tmpl_data.go b/core/vm/sqlvm/runtime/instructions_tmpl_data.go index 210adafed..c4a7ac4a7 100644 --- a/core/vm/sqlvm/runtime/instructions_tmpl_data.go +++ b/core/vm/sqlvm/runtime/instructions_tmpl_data.go @@ -1543,6 +1543,208 @@ var testData = &tmplData{ }, // -- end of PRUNE { + TestName: "OpCut", OpFunc: "opCut", + Cases: []*tmplTestCase{ + { + Name: "Cut 2nd to 4th columns", + Error: "nil", OpCode: "CUT", + Inputs: []*tmplOp{ + { + Im: false, + Metas: []*tmplOpMeta{ + {Major: "DynamicBytes", Minor: 0}, + {Major: "DynamicBytes", Minor: 0}, + {Major: "Int", Minor: 0}, + {Major: "Bool", Minor: 0}, + {Major: "Bool", Minor: 0}, + }, + Data: []string{ + `{B: "abcdefg-1", B: "gfedcba-1", V: 1, F, T}`, + `{B: "abcdefg-2", B: "gfedcba-2", V: 2, T, F}`, + }, + }, + { + Im: true, + Metas: []*tmplOpMeta{ + {Major: "Int", Minor: 0}, + {Major: "Int", Minor: 0}, + }, + Data: []string{"{V: 1, V: 3}"}, + }, + }, + Output: &tmplOp{ + Im: false, + Metas: []*tmplOpMeta{ + {Major: "DynamicBytes", Minor: 0}, + {Major: "Bool", Minor: 0}, + }, + Data: []string{ + `{B: "abcdefg-1", T}`, + `{B: "abcdefg-2", F}`, + }, + }, + }, + { + Name: "Cut 1st column", + Error: "nil", OpCode: "CUT", + Inputs: []*tmplOp{ + { + Im: false, + Metas: []*tmplOpMeta{ + {Major: "DynamicBytes", Minor: 0}, + {Major: "DynamicBytes", Minor: 0}, + {Major: "Int", Minor: 0}, + {Major: "Bool", Minor: 0}, + {Major: "Bool", Minor: 0}, + }, + Data: []string{ + `{B: "abcdefg-1", B: "gfedcba-1", V: 1, F, T}`, + `{B: "abcdefg-2", B: "gfedcba-2", V: 2, T, F}`, + }, + }, + { + Im: true, + Metas: []*tmplOpMeta{ + {Major: "Int", Minor: 0}, + {Major: "Int", Minor: 0}, + }, + Data: []string{"{V: 0, V: 0}"}, + }, + }, + Output: &tmplOp{ + Im: false, + Metas: []*tmplOpMeta{ + {Major: "DynamicBytes", Minor: 0}, + {Major: "Int", Minor: 0}, + {Major: "Bool", Minor: 0}, + {Major: "Bool", Minor: 0}, + }, + Data: []string{ + `{B: "gfedcba-1", V: 1, F, T}`, + `{B: "gfedcba-2", V: 2, T, F}`, + }, + }, + }, + { + Name: "Cut since 2nd column", + Error: "nil", OpCode: "CUT", + Inputs: []*tmplOp{ + { + Im: false, + Metas: []*tmplOpMeta{ + {Major: "DynamicBytes", Minor: 0}, + {Major: "DynamicBytes", Minor: 0}, + {Major: "Int", Minor: 0}, + {Major: "Bool", Minor: 0}, + }, + Data: []string{ + `{B: "abcdefg-1", B: "gfedcba-1", V: 1, T}`, + `{B: "abcdefg-2", B: "gfedcba-2", V: 2, F}`, + }, + }, + { + Im: true, + Metas: []*tmplOpMeta{{Major: "Int", Minor: 0}}, + Data: []string{"{V: 1}"}, + }, + }, + Output: &tmplOp{ + Im: false, + Metas: []*tmplOpMeta{ + {Major: "DynamicBytes", Minor: 0}, + }, + Data: []string{ + `{B: "abcdefg-1"}`, + `{B: "abcdefg-2"}`, + }, + }, + }, + { + Name: "Cut all columns", + Error: "nil", OpCode: "CUT", + Inputs: []*tmplOp{ + { + Im: false, + Metas: []*tmplOpMeta{ + {Major: "DynamicBytes", Minor: 0}, + {Major: "DynamicBytes", Minor: 0}, + {Major: "Int", Minor: 0}, + {Major: "Bool", Minor: 0}, + }, + Data: []string{ + `{B: "abcdefg-1", B: "gfedcba-1", V: 1, T}`, + `{B: "abcdefg-2", B: "gfedcba-2", V: 2, F}`, + }, + }, + { + Im: true, + Metas: []*tmplOpMeta{{Major: "Int", Minor: 0}}, + Data: []string{"{V: 0}"}, + }, + }, + Output: &tmplOp{ + Im: false, + Metas: []*tmplOpMeta{}, + Data: []string{"{}", "{}"}, + }, + }, + { + Name: "Cut error range - 1", + Error: "errors.ErrorCodeIndexOutOfRange", OpCode: "CUT", + Inputs: []*tmplOp{ + { + Im: false, + Metas: []*tmplOpMeta{ + {Major: "DynamicBytes", Minor: 0}, + {Major: "DynamicBytes", Minor: 0}, + {Major: "Int", Minor: 0}, + {Major: "Bool", Minor: 0}, + }, + Data: []string{ + `{B: "abcdefg-1", B: "gfedcba-1", V: 1, T}`, + `{B: "abcdefg-2", B: "gfedcba-2", V: 2, F}`, + }, + }, + { + Im: true, + Metas: []*tmplOpMeta{{Major: "Int", Minor: 0}}, + Data: []string{"{V: 5}"}, + }, + }, + Output: &tmplOp{}, + }, + { + Name: "Cut error range - 2", + Error: "errors.ErrorCodeIndexOutOfRange", OpCode: "CUT", + Inputs: []*tmplOp{ + { + Im: false, + Metas: []*tmplOpMeta{ + {Major: "DynamicBytes", Minor: 0}, + {Major: "DynamicBytes", Minor: 0}, + {Major: "Int", Minor: 0}, + {Major: "Bool", Minor: 0}, + }, + Data: []string{ + `{B: "abcdefg-1", B: "gfedcba-1", V: 1, T}`, + `{B: "abcdefg-2", B: "gfedcba-2", V: 2, F}`, + }, + }, + { + Im: true, + Metas: []*tmplOpMeta{ + {Major: "Int", Minor: 0}, + {Major: "Int", Minor: 0}, + }, + Data: []string{"{V: 15, V: 17}"}, + }, + }, + Output: &tmplOp{}, + }, + }, + }, + // -- end of CUT + { TestName: "OpFilter", OpFunc: "opFilter", Cases: []*tmplTestCase{ { diff --git a/core/vm/sqlvm/runtime/jumptable.go b/core/vm/sqlvm/runtime/jumptable.go index 415a4e62b..2408ee0f4 100644 --- a/core/vm/sqlvm/runtime/jumptable.go +++ b/core/vm/sqlvm/runtime/jumptable.go @@ -26,6 +26,7 @@ var jumpTable = [256]OpFunction{ SORT: opSort, FILTER: opFilter, CAST: opCast, + CUT: opCut, // 0x60 LOAD: opLoad, diff --git a/core/vm/sqlvm/runtime/opcodes.go b/core/vm/sqlvm/runtime/opcodes.go index 88bc039e1..07b30bdc3 100644 --- a/core/vm/sqlvm/runtime/opcodes.go +++ b/core/vm/sqlvm/runtime/opcodes.go @@ -45,6 +45,7 @@ const ( SORT FILTER CAST + CUT ) // 0x60 range - storage ops |