diff options
author | Meng-Ying Yang <garfield@dexon.org> | 2019-04-17 16:03:48 +0800 |
---|---|---|
committer | Meng-Ying Yang <garfield@dexon.org> | 2019-05-09 09:29:30 +0800 |
commit | bef33b8735957f6c4bd48ad897f9448d91ddef70 (patch) | |
tree | 9caede61c1f95a8e219876886c8a5e765903f9d3 | |
parent | 20458f206ccee4ff6beb86d07cef77061ec270b0 (diff) | |
download | dexon-bef33b8735957f6c4bd48ad897f9448d91ddef70.tar.gz dexon-bef33b8735957f6c4bd48ad897f9448d91ddef70.tar.zst dexon-bef33b8735957f6c4bd48ad897f9448d91ddef70.zip |
core: vm: sqlvm: add built-in function SUBSTRING()
-rw-r--r-- | core/vm/sqlvm/runtime/functions.go | 51 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/instructions_op_test.go | 71 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/instructions_tmpl_data.go | 54 |
3 files changed, 176 insertions, 0 deletions
diff --git a/core/vm/sqlvm/runtime/functions.go b/core/vm/sqlvm/runtime/functions.go index 9a03d233c..a05c791e7 100644 --- a/core/vm/sqlvm/runtime/functions.go +++ b/core/vm/sqlvm/runtime/functions.go @@ -31,6 +31,7 @@ const ( BITXOR BITNOT OCTETLENGTH + SUBSTRING ) type fn func(*common.Context, []*Operand, uint64) (*Operand, error) @@ -52,6 +53,7 @@ var ( BITXOR: fnBitXor, BITNOT: fnBitNot, OCTETLENGTH: fnOctetLength, + SUBSTRING: fnSubString, } ) @@ -439,3 +441,52 @@ func fnOctetLength(ctx *common.Context, ops []*Operand, length uint64) (result * } return } + +func fnSubString(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) { + if len(ops) < 3 { + err = se.ErrorCodeInvalidOperandNum + return + } + + op := ops[0] + + if !metaAllDynBytes(op) { + err = se.ErrorCodeInvalidDataType + } + + result = &Operand{ + Meta: make([]ast.DataType, len(op.Meta)), + Data: make([]Tuple, len(op.Data)), + } + + dynBytesType := ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0) + for i := 0; i < len(op.Meta); i++ { + result.Meta[i] = dynBytesType + } + + starts, err := ops[1].toUint64() + if err == nil && len(starts) != 1 { + err = se.ErrorCodeIndexOutOfRange + } + if err != nil { + return + } + + lens, err := ops[2].toUint64() + if err == nil && len(lens) != 1 { + err = se.ErrorCodeIndexOutOfRange + } + if err != nil { + return + } + + start, end := starts[0], starts[0]+lens[0] + + 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{Bytes: op.Data[i][j].Bytes[start:end]} + } + } + return +} diff --git a/core/vm/sqlvm/runtime/instructions_op_test.go b/core/vm/sqlvm/runtime/instructions_op_test.go index ba993300b..979adf5f6 100644 --- a/core/vm/sqlvm/runtime/instructions_op_test.go +++ b/core/vm/sqlvm/runtime/instructions_op_test.go @@ -3985,3 +3985,74 @@ func (s *instructionSuite) TestOpFuncOctetLength() { s.run(testcases, opFunc) } + +func (s *instructionSuite) TestOpFuncSubString() { + testcases := []opTestcase{ + { + "Func sub string", + 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(15)}}, + }, + ), + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), + }, + []Tuple{ + {&Raw{Bytes: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}}}, + }, + ), + makeOperand( + true, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorUint, 7), + }, + []Tuple{ + {&Raw{Value: decimal.NewFromFloat(2)}}, + }, + ), + makeOperand( + true, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorUint, 7), + }, + []Tuple{ + {&Raw{Value: decimal.NewFromFloat(5)}}, + }, + ), + }, + Output: 0, + }, + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), + }, + []Tuple{ + {&Raw{Bytes: []byte{3, 4, 5, 6, 7}}}, + }, + ), + 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 0b1b01aaf..1917b8c64 100644 --- a/core/vm/sqlvm/runtime/instructions_tmpl_data.go +++ b/core/vm/sqlvm/runtime/instructions_tmpl_data.go @@ -2882,5 +2882,59 @@ var testData = &tmplData{ }, }, // -- end of FUNC OCTETLENGTH + { + TestName: "OpFuncSubString", OpFunc: "opFunc", + Cases: []*tmplTestCase{ + { + Name: "Func sub string", + 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: 15}`}, + }, + { + Im: false, + Metas: []*tmplOpMeta{ + {Major: "DynamicBytes", Minor: 0}, + }, + Data: []string{"{B: {1, 2, 3, 4, 5, 6, 7, 8, 9}}"}, + }, + { + Im: true, + Metas: []*tmplOpMeta{ + {Major: "Uint", Minor: 7}, + }, + Data: []string{`{V: 2}`}, + }, + { + Im: true, + Metas: []*tmplOpMeta{ + {Major: "Uint", Minor: 7}, + }, + Data: []string{`{V: 5}`}, + }, + }, + Output: &tmplOp{ + Im: false, + Metas: []*tmplOpMeta{ + {Major: "DynamicBytes", Minor: 0}, + }, + Data: []string{"{B: {3, 4, 5, 6, 7}}"}, + }, + }, + }, + }, + // -- end of FUNC SUBSTRING }, } |