diff options
author | Meng-Ying Yang <garfield@dexon.org> | 2019-04-17 14:56:16 +0800 |
---|---|---|
committer | Meng-Ying Yang <garfield@dexon.org> | 2019-05-06 15:50:03 +0800 |
commit | 53457a9448d68bf8468783ab854dca6ccc55b507 (patch) | |
tree | db9e2741be70509d8c08a3ca6a793e78d19c9a6b | |
parent | 8b6b72945d424b107f88f8cee55f2f84fab5be4b (diff) | |
download | dexon-53457a9448d68bf8468783ab854dca6ccc55b507.tar.gz dexon-53457a9448d68bf8468783ab854dca6ccc55b507.tar.zst dexon-53457a9448d68bf8468783ab854dca6ccc55b507.zip |
core: vm: sqlvm: add built-in function OCTET_LENGTH()
-rw-r--r-- | core/vm/sqlvm/runtime/functions.go | 38 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/instructions_op_test.go | 53 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/instructions_tmpl_data.go | 48 |
3 files changed, 137 insertions, 2 deletions
diff --git a/core/vm/sqlvm/runtime/functions.go b/core/vm/sqlvm/runtime/functions.go index d426c8a77..9a03d233c 100644 --- a/core/vm/sqlvm/runtime/functions.go +++ b/core/vm/sqlvm/runtime/functions.go @@ -30,6 +30,7 @@ const ( BITOR BITXOR BITNOT + OCTETLENGTH ) type fn func(*common.Context, []*Operand, uint64) (*Operand, error) @@ -50,6 +51,7 @@ var ( BITOR: fnBitOr, BITXOR: fnBitXor, BITNOT: fnBitNot, + OCTETLENGTH: fnOctetLength, } ) @@ -362,12 +364,12 @@ func fnBitXor(ctx *common.Context, ops []*Operand, length uint64) (result *Opera type bitUnFunc func(b byte) byte func fnBitNot(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) { - if len(ops) < 2 { + if len(ops) < 1 { err = se.ErrorCodeInvalidOperandNum return } - op := ops[1] + op := ops[0] if !metaAllBitOp(op) { err = se.ErrorCodeInvalidDataType return @@ -405,3 +407,35 @@ func (r *Raw) bitUnOp(dType ast.DataType, bFn bitUnFunc) (r2 *Raw) { r2.fromBytes(bytes2, dType) return } + +func fnOctetLength(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) { + if len(ops) < 1 { + err = se.ErrorCodeInvalidOperandNum + return + } + + op := ops[0] + + if !metaAllDynBytes(op) { + err = se.ErrorCodeInvalidDataType + return + } + + result = &Operand{ + Meta: make([]ast.DataType, len(op.Meta)), + Data: make([]Tuple, len(op.Data)), + } + + uint256Type := ast.ComposeDataType(ast.DataTypeMajorUint, 32) + for i := 0; i < len(op.Meta); i++ { + result.Meta[i] = uint256Type + } + + for i := 0; i < len(op.Data); i++ { + result.Data[i] = make(Tuple, len(op.Data[i])) + for j := 0; j < len(op.Data[i]); j++ { + result.Data[i][j] = &Raw{Value: decimal.New(int64(len(op.Data[i][j].Bytes)), 0)} + } + } + return +} diff --git a/core/vm/sqlvm/runtime/instructions_op_test.go b/core/vm/sqlvm/runtime/instructions_op_test.go index 088d889fb..ba993300b 100644 --- a/core/vm/sqlvm/runtime/instructions_op_test.go +++ b/core/vm/sqlvm/runtime/instructions_op_test.go @@ -3932,3 +3932,56 @@ func (s *instructionSuite) TestOpFuncBitNot() { s.run(testcases, opFunc) } + +func (s *instructionSuite) TestOpFuncOctetLength() { + testcases := []opTestcase{ + { + "Func octet length", + Instruction{ + Op: FUNC, + Input: []*Operand{ + makeOperand( + true, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorUint, 0), + }, + []Tuple{ + {&Raw{Value: decimal.NewFromFloat(2)}}, + }, + ), + makeOperand( + true, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorUint, 1), + }, + []Tuple{ + {&Raw{Value: decimal.NewFromFloat(14)}}, + }, + ), + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), + }, + []Tuple{ + {&Raw{Bytes: []byte{}}, &Raw{Bytes: []byte{1}}, &Raw{Bytes: []byte{1, 2}}, &Raw{Bytes: []byte{1, 2, 3}}, &Raw{Bytes: []byte{1, 2, 3, 4}}}, + }, + ), + }, + Output: 0, + }, + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorUint, 32), ast.ComposeDataType(ast.DataTypeMajorUint, 32), ast.ComposeDataType(ast.DataTypeMajorUint, 32), ast.ComposeDataType(ast.DataTypeMajorUint, 32), ast.ComposeDataType(ast.DataTypeMajorUint, 32), + }, + []Tuple{ + {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(3)}, &Raw{Value: decimal.NewFromFloat(4)}}, + }, + ), + nil, + }, + } + + s.run(testcases, opFunc) +} diff --git a/core/vm/sqlvm/runtime/instructions_tmpl_data.go b/core/vm/sqlvm/runtime/instructions_tmpl_data.go index 6cc1716eb..0b1b01aaf 100644 --- a/core/vm/sqlvm/runtime/instructions_tmpl_data.go +++ b/core/vm/sqlvm/runtime/instructions_tmpl_data.go @@ -2834,5 +2834,53 @@ var testData = &tmplData{ }, }, // -- end of FUNC BITNOT + { + TestName: "OpFuncOctetLength", OpFunc: "opFunc", + Cases: []*tmplTestCase{ + { + Name: "Func octet length", + Error: "nil", OpCode: "FUNC", + Inputs: []*tmplOp{ + { + Im: true, + Metas: []*tmplOpMeta{ + {Major: "Uint", Minor: 0}, + }, + Data: []string{`{V: 2}`}, + }, + { + Im: true, + Metas: []*tmplOpMeta{ + {Major: "Uint", Minor: 1}, + }, + Data: []string{`{V: 14}`}, + }, + { + Im: false, + Metas: []*tmplOpMeta{ + {Major: "DynamicBytes", Minor: 0}, + {Major: "DynamicBytes", Minor: 0}, + {Major: "DynamicBytes", Minor: 0}, + {Major: "DynamicBytes", Minor: 0}, + {Major: "DynamicBytes", Minor: 0}, + }, + Data: []string{"{B: {}, B: {1}, B: {1, 2}, B: {1, 2, 3}, B: {1, 2, 3, 4}}"}, + }, + }, + Output: &tmplOp{ + Im: false, + Metas: []*tmplOpMeta{ + {Major: "Uint", Minor: 32}, + {Major: "Uint", Minor: 32}, + {Major: "Uint", Minor: 32}, + {Major: "Uint", Minor: 32}, + {Major: "Uint", Minor: 32}, + }, + Data: []string{`{V: 0, V: 1, V: 2, V: 3, V: 4}`}, + }, + }, + }, + }, + // -- end of FUNC OCTETLENGTH }, } |