diff options
Diffstat (limited to 'core/vm/sqlvm')
-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 }, } |