aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMeng-Ying Yang <garfield@dexon.org>2019-04-17 16:03:48 +0800
committerMeng-Ying Yang <garfield@dexon.org>2019-05-09 09:29:30 +0800
commitbef33b8735957f6c4bd48ad897f9448d91ddef70 (patch)
tree9caede61c1f95a8e219876886c8a5e765903f9d3
parent20458f206ccee4ff6beb86d07cef77061ec270b0 (diff)
downloaddexon-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.go51
-rw-r--r--core/vm/sqlvm/runtime/instructions_op_test.go71
-rw-r--r--core/vm/sqlvm/runtime/instructions_tmpl_data.go54
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
},
}