aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMeng-Ying Yang <garfield@dexon.org>2019-04-17 14:56:16 +0800
committerMeng-Ying Yang <garfield@dexon.org>2019-05-06 15:50:03 +0800
commit53457a9448d68bf8468783ab854dca6ccc55b507 (patch)
treedb9e2741be70509d8c08a3ca6a793e78d19c9a6b
parent8b6b72945d424b107f88f8cee55f2f84fab5be4b (diff)
downloaddexon-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.go38
-rw-r--r--core/vm/sqlvm/runtime/instructions_op_test.go53
-rw-r--r--core/vm/sqlvm/runtime/instructions_tmpl_data.go48
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
},
}