aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm
diff options
context:
space:
mode:
authorMeng-Ying Yang <garfield@dexon.org>2019-04-08 10:32:36 +0800
committerJhih-Ming Huang <jm.huang@cobinhood.com>2019-05-06 10:44:05 +0800
commitc07255382a10bdeaf7d5d2411e9c7c4cdc937694 (patch)
tree2a0fbb3fb3d6e0f546ee4cb09912c36bdb487953 /core/vm
parent64c440d58f8eea970487b39bf231696932464159 (diff)
downloaddexon-c07255382a10bdeaf7d5d2411e9c7c4cdc937694.tar
dexon-c07255382a10bdeaf7d5d2411e9c7c4cdc937694.tar.gz
dexon-c07255382a10bdeaf7d5d2411e9c7c4cdc937694.tar.bz2
dexon-c07255382a10bdeaf7d5d2411e9c7c4cdc937694.tar.lz
dexon-c07255382a10bdeaf7d5d2411e9c7c4cdc937694.tar.xz
dexon-c07255382a10bdeaf7d5d2411e9c7c4cdc937694.tar.zst
dexon-c07255382a10bdeaf7d5d2411e9c7c4cdc937694.zip
core: vm: sqlvm: add opConcat
Add `opConcat` supports dynamic bytes (string) concating.
Diffstat (limited to 'core/vm')
-rw-r--r--core/vm/sqlvm/runtime/instructions.go45
-rw-r--r--core/vm/sqlvm/runtime/instructions_op_test.go80
-rw-r--r--core/vm/sqlvm/runtime/instructions_tmpl_data.go68
-rw-r--r--core/vm/sqlvm/runtime/jumptable.go11
-rw-r--r--core/vm/sqlvm/runtime/opcodes.go1
5 files changed, 200 insertions, 5 deletions
diff --git a/core/vm/sqlvm/runtime/instructions.go b/core/vm/sqlvm/runtime/instructions.go
index 353701f8c..4b03b6494 100644
--- a/core/vm/sqlvm/runtime/instructions.go
+++ b/core/vm/sqlvm/runtime/instructions.go
@@ -359,6 +359,13 @@ func value2ColIdx(v decimal.Decimal) (idx uint16) {
return
}
+func metaDynBytes(dType ast.DataType) bool {
+ dMajor, _ := ast.DecomposeDataType(dType)
+ return dMajor == ast.DataTypeMajorDynamicBytes
+}
+
+func metaAllDynBytes(op *Operand) bool { return metaAll(op, metaDynBytes) }
+
func flowCheck(ctx *common.Context, v decimal.Decimal, dType ast.DataType) (err error) {
if !ctx.Opt.SafeMath {
return
@@ -1735,3 +1742,41 @@ func (r *Raw) shiftBytes(src []byte, l int, signed, rPadding bool) (tgr []byte)
}
return
}
+
+func opConcat(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 {
+ err = se.ErrorCodeDataLengthNotMatch
+ return
+ }
+ op, op2 := ops[0], ops[1]
+
+ if !metaAllEq(op, op2) {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ if !metaAllDynBytes(op) {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ op3 := op.clone(true)
+ op3.Data = make([]Tuple, len(op.Data))
+
+ for i := 0; i < len(op.Data); i++ {
+ op3.Data[i] = op.Data[i].concat(op2.Data[i])
+ }
+
+ registers[output] = op3
+ return
+}
+
+func (t Tuple) concat(t2 Tuple) (t3 Tuple) {
+ t3 = make(Tuple, len(t))
+ for i := 0; i < len(t); i++ {
+ t3[i] = &Raw{Bytes: make([]byte, len(t[i].Bytes)+len(t2[i].Bytes))}
+ copy(t3[i].Bytes[:len(t[i].Bytes)], t[i].Bytes)
+ copy(t3[i].Bytes[len(t[i].Bytes):], t2[i].Bytes)
+ }
+ return
+}
diff --git a/core/vm/sqlvm/runtime/instructions_op_test.go b/core/vm/sqlvm/runtime/instructions_op_test.go
index e0550006f..6c10a2e87 100644
--- a/core/vm/sqlvm/runtime/instructions_op_test.go
+++ b/core/vm/sqlvm/runtime/instructions_op_test.go
@@ -1321,6 +1321,86 @@ func (s *instructionSuite) TestOpMod() {
s.run(testcases, opMod)
}
+func (s *instructionSuite) TestOpConcat() {
+ testcases := []opTestcase{
+ {
+ "Concat bytes",
+ Instruction{
+ Op: CONCAT,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("abc-1")}, &Raw{Bytes: []byte("xyz-1")}},
+ {&Raw{Bytes: []byte("abc-2")}, &Raw{Bytes: []byte("xyz-2")}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("ABC-1")}, &Raw{Bytes: []byte("XYZ-1")}},
+ {&Raw{Bytes: []byte("ABC-2")}, &Raw{Bytes: []byte("XYZ-2")}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("abc-1ABC-1")}, &Raw{Bytes: []byte("xyz-1XYZ-1")}},
+ {&Raw{Bytes: []byte("abc-2ABC-2")}, &Raw{Bytes: []byte("xyz-2XYZ-2")}},
+ },
+ ),
+ nil,
+ },
+ {
+ "Invalid concat",
+ Instruction{
+ Op: CONCAT,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorBool, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("abc-1")}, rawTrue},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorBool, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("ABC-1")}, rawFalse},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeInvalidDataType,
+ },
+ }
+
+ s.run(testcases, opConcat)
+}
+
func (s *instructionSuite) TestOpLt() {
testcases := []opTestcase{
{
diff --git a/core/vm/sqlvm/runtime/instructions_tmpl_data.go b/core/vm/sqlvm/runtime/instructions_tmpl_data.go
index 7edc2c3e6..a55dab60a 100644
--- a/core/vm/sqlvm/runtime/instructions_tmpl_data.go
+++ b/core/vm/sqlvm/runtime/instructions_tmpl_data.go
@@ -773,6 +773,74 @@ var testData = &tmplData{
},
// -- end of MOD
{
+ TestName: "OpConcat", OpFunc: "opConcat",
+ Cases: []*tmplTestCase{
+ {
+ Name: "Concat bytes",
+ Error: "nil", OpCode: "CONCAT",
+ Inputs: []*tmplOp{
+ {
+ Im: false,
+ Metas: []*tmplOpMeta{
+ {Major: "DynamicBytes", Minor: 0},
+ {Major: "DynamicBytes", Minor: 0},
+ },
+ Data: []string{
+ `{B: "abc-1", B: "xyz-1"}`,
+ `{B: "abc-2", B: "xyz-2"}`,
+ },
+ },
+ {
+ Im: false,
+ Metas: []*tmplOpMeta{
+ {Major: "DynamicBytes", Minor: 0},
+ {Major: "DynamicBytes", Minor: 0},
+ },
+ Data: []string{
+ `{B: "ABC-1", B: "XYZ-1"}`,
+ `{B: "ABC-2", B: "XYZ-2"}`,
+ },
+ },
+ },
+ Output: &tmplOp{
+ Im: false,
+ Metas: []*tmplOpMeta{
+ {Major: "DynamicBytes", Minor: 0},
+ {Major: "DynamicBytes", Minor: 0},
+ },
+ Data: []string{
+ `{B: "abc-1ABC-1", B: "xyz-1XYZ-1"}`,
+ `{B: "abc-2ABC-2", B: "xyz-2XYZ-2"}`,
+ },
+ },
+ },
+ {
+ Name: "Invalid concat",
+ Error: "errors.ErrorCodeInvalidDataType", OpCode: "CONCAT",
+ Inputs: []*tmplOp{
+ {
+ Im: false,
+ Metas: []*tmplOpMeta{
+ {Major: "DynamicBytes", Minor: 0},
+ {Major: "Bool", Minor: 0},
+ },
+ Data: []string{`{B: "abc-1", T}`},
+ },
+ {
+ Im: false,
+ Metas: []*tmplOpMeta{
+ {Major: "DynamicBytes", Minor: 0},
+ {Major: "Bool", Minor: 0},
+ },
+ Data: []string{`{B: "ABC-1", F}`},
+ },
+ },
+ Output: &tmplOp{},
+ },
+ },
+ },
+ // -- end of CONCAT
+ {
TestName: "OpLt", OpFunc: "opLt",
Cases: []*tmplTestCase{
{
diff --git a/core/vm/sqlvm/runtime/jumptable.go b/core/vm/sqlvm/runtime/jumptable.go
index aab57225d..f6cad57e7 100644
--- a/core/vm/sqlvm/runtime/jumptable.go
+++ b/core/vm/sqlvm/runtime/jumptable.go
@@ -2,11 +2,12 @@ package runtime
var jumpTable = [256]OpFunction{
// 0x10
- ADD: opAdd,
- MUL: opMul,
- SUB: opSub,
- DIV: opDiv,
- MOD: opMod,
+ ADD: opAdd,
+ MUL: opMul,
+ SUB: opSub,
+ DIV: opDiv,
+ MOD: opMod,
+ CONCAT: opConcat,
// 0x20
LT: opLt,
diff --git a/core/vm/sqlvm/runtime/opcodes.go b/core/vm/sqlvm/runtime/opcodes.go
index 8827f0531..12a4dfefb 100644
--- a/core/vm/sqlvm/runtime/opcodes.go
+++ b/core/vm/sqlvm/runtime/opcodes.go
@@ -15,6 +15,7 @@ const (
SUB
DIV
MOD
+ CONCAT
)
// 0x20 range - comparison ops.