aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMeng-Ying Yang <garfield@dexon.org>2019-04-16 16:38:55 +0800
committerMeng-Ying Yang <garfield@dexon.org>2019-05-06 15:50:03 +0800
commit01e130a74e957a2415edbcd99612c6c21b1f64ad (patch)
tree5994356be4b7017d6a84fdd5c96144f062529dbc
parent2119d801bb3794ca9031bc290ce568df1bcd6541 (diff)
downloaddexon-01e130a74e957a2415edbcd99612c6c21b1f64ad.tar
dexon-01e130a74e957a2415edbcd99612c6c21b1f64ad.tar.gz
dexon-01e130a74e957a2415edbcd99612c6c21b1f64ad.tar.bz2
dexon-01e130a74e957a2415edbcd99612c6c21b1f64ad.tar.lz
dexon-01e130a74e957a2415edbcd99612c6c21b1f64ad.tar.xz
dexon-01e130a74e957a2415edbcd99612c6c21b1f64ad.tar.zst
dexon-01e130a74e957a2415edbcd99612c6c21b1f64ad.zip
core: vm: sqlvm: add built-in function BITAND()
-rw-r--r--core/vm/sqlvm/runtime/functions.go119
-rw-r--r--core/vm/sqlvm/runtime/instructions_op_test.go62
-rw-r--r--core/vm/sqlvm/runtime/instructions_tmpl_data.go62
3 files changed, 243 insertions, 0 deletions
diff --git a/core/vm/sqlvm/runtime/functions.go b/core/vm/sqlvm/runtime/functions.go
index 7aed05b19..6cdceb7fb 100644
--- a/core/vm/sqlvm/runtime/functions.go
+++ b/core/vm/sqlvm/runtime/functions.go
@@ -26,6 +26,7 @@ const (
TXORIGIN
NOW
RAND
+ BITAND
)
type fn func(*common.Context, []*Operand, uint64) (*Operand, error)
@@ -42,6 +43,7 @@ var (
MSGDATA: fnMsgData,
TXORIGIN: fnTxOrigin,
RAND: fnRand,
+ BITAND: fnBitAnd,
}
)
@@ -195,5 +197,122 @@ func fnRand(ctx *common.Context, ops []*Operand, length uint64) (result *Operand
fn, length,
)
return
+}
+
+func metaBitOp(dType ast.DataType) bool {
+ dMajor, _ := ast.DecomposeDataType(dType)
+ switch dMajor {
+ case ast.DataTypeMajorUint,
+ ast.DataTypeMajorInt,
+ ast.DataTypeMajorFixedBytes:
+ return true
+ }
+ return false
+}
+
+func metaAllBitOp(op *Operand) bool { return metaAll(op, metaBitOp) }
+
+func extractOps(ops []*Operand) (n int, op1, op2 *Operand, err error) {
+ if len(ops) < 2 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+
+ n, err = findMaxDataLength(ops)
+ if err != nil {
+ return
+ }
+ op1, op2 = ops[0], ops[1]
+
+ if !metaAllEq(op1, op2) || !metaAllBitOp(op1) {
+ err = se.ErrorCodeInvalidDataType
+ }
+ return
+}
+
+func (r *Raw) toBytes(dType ast.DataType) []byte {
+ dMajor, _ := ast.DecomposeDataType(dType)
+ switch dMajor {
+ case ast.DataTypeMajorFixedBytes,
+ ast.DataTypeMajorAddress,
+ ast.DataTypeMajorDynamicBytes:
+ return r.Bytes
+ case ast.DataTypeMajorUint,
+ ast.DataTypeMajorInt,
+ ast.DataTypeMajorFixed:
+ bytes, err := ast.DecimalEncode(dType, r.Value)
+ if err != nil {
+ panic(err)
+ }
+ return bytes
+ default:
+ panic(fmt.Errorf("unrecognized data type: %v", dType))
+ }
+}
+
+func (r *Raw) fromBytes(bytes []byte, dType ast.DataType) {
+ dMajor, _ := ast.DecomposeDataType(dType)
+ switch dMajor {
+ case ast.DataTypeMajorFixedBytes,
+ ast.DataTypeMajorAddress,
+ ast.DataTypeMajorDynamicBytes:
+ r.Bytes = bytes
+ case ast.DataTypeMajorUint,
+ ast.DataTypeMajorInt,
+ ast.DataTypeMajorFixed:
+ var err error
+ r.Value, err = ast.DecimalDecode(dType, bytes)
+ if err != nil {
+ panic(err)
+ }
+ default:
+ panic(fmt.Errorf("unrecognized data type: %v", dType))
+ }
+}
+
+type bitBinFunc func(b1, b2 byte) byte
+
+func fnBitAnd(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) {
+ n, op1, op2, err := extractOps(ops)
+ if err != nil {
+ return
+ }
+
+ result = op1.clone(true)
+ result.Data = make([]Tuple, n)
+ for i := 0; i < n; i++ {
+ result.Data[i] = op1.Data[i].bitBinOp(
+ op2.Data[i],
+ op1.Meta,
+ func(b1, b2 byte) byte { return b1 & b2 },
+ )
+ }
+ return
+}
+
+func (t Tuple) bitBinOp(t2 Tuple, meta []ast.DataType, bFn bitBinFunc) (t3 Tuple) {
+ t3 = make(Tuple, len(t))
+ for i := 0; i < len(t); i++ {
+ t3[i] = t[i].bitBinOp(t2[i], meta[i], bFn)
+ }
+ return
+}
+
+func (r *Raw) bitBinOp(r2 *Raw, dType ast.DataType, bFn bitBinFunc) (r3 *Raw) {
+ bytes1, bytes2 := r.toBytes(dType), r2.toBytes(dType)
+
+ if len(bytes1) != len(bytes2) {
+ panic(fmt.Errorf("bitwise operand on different length bits"))
+ }
+
+ n := len(bytes1)
+ bytes3 := make([]byte, n)
+ for i := 0; i < n; i++ {
+ bytes3[i] = bFn(bytes1[i], bytes2[i])
+ }
+
+ r3 = &Raw{}
+ r3.fromBytes(bytes3, dType)
+ return
}
diff --git a/core/vm/sqlvm/runtime/instructions_op_test.go b/core/vm/sqlvm/runtime/instructions_op_test.go
index 994c508ff..b2fec064e 100644
--- a/core/vm/sqlvm/runtime/instructions_op_test.go
+++ b/core/vm/sqlvm/runtime/instructions_op_test.go
@@ -3693,3 +3693,65 @@ func (s *instructionSuite) TestOpRange() {
s.run(testcases, opRange)
}
+
+func (s *instructionSuite) TestOpFuncBitAnd() {
+ testcases := []opTestcase{
+ {
+ "Func BitAnd",
+ 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(10)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(ast.DataTypeMajorUint, 0), ast.ComposeDataType(ast.DataTypeMajorUint, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorFixedBytes, 0), ast.ComposeDataType(ast.DataTypeMajorFixedBytes, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-128)}, &Raw{Bytes: []byte{0x12, 0x34}}, &Raw{Bytes: []byte{0x56, 0x78}}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(ast.DataTypeMajorUint, 0), ast.ComposeDataType(ast.DataTypeMajorUint, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorFixedBytes, 0), ast.ComposeDataType(ast.DataTypeMajorFixedBytes, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(5)}, &Raw{Value: decimal.NewFromFloat(6)}, &Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Bytes: []byte{0xff, 0xff}}, &Raw{Bytes: []byte{0x00, 0x00}}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(ast.DataTypeMajorUint, 0), ast.ComposeDataType(ast.DataTypeMajorUint, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorFixedBytes, 0), ast.ComposeDataType(ast.DataTypeMajorFixedBytes, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(-128)}, &Raw{Bytes: []byte{0x12, 0x34}}, &Raw{Bytes: []byte{0x00, 0x00}}},
+ },
+ ),
+ 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 23669d97a..c7a718cbf 100644
--- a/core/vm/sqlvm/runtime/instructions_tmpl_data.go
+++ b/core/vm/sqlvm/runtime/instructions_tmpl_data.go
@@ -2598,5 +2598,67 @@ var testData = &tmplData{
},
},
// -- end of RANGE
+ {
+ TestName: "OpFuncBitAnd", OpFunc: "opFunc",
+ Cases: []*tmplTestCase{
+ {
+ Name: "Func BitAnd",
+ 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: 10}`},
+ },
+ {
+ Im: false,
+ Metas: []*tmplOpMeta{
+ {Major: "Uint", Minor: 0},
+ {Major: "Uint", Minor: 0},
+ {Major: "Int", Minor: 0},
+ {Major: "Int", Minor: 0},
+ {Major: "FixedBytes", Minor: 0},
+ {Major: "FixedBytes", Minor: 0},
+ },
+ Data: []string{"{V: 1, V: 2, V: -1, V: -128, B: {0x12, 0x34}, B: {0x56, 0x78}}"},
+ },
+ {
+ Im: false,
+ Metas: []*tmplOpMeta{
+ {Major: "Uint", Minor: 0},
+ {Major: "Uint", Minor: 0},
+ {Major: "Int", Minor: 0},
+ {Major: "Int", Minor: 0},
+ {Major: "FixedBytes", Minor: 0},
+ {Major: "FixedBytes", Minor: 0},
+ },
+ Data: []string{"{V: 5, V: 6, V: -2, V: -2, B: {0xff, 0xff}, B:{0x00, 0x00}}"},
+ },
+ },
+ Output: &tmplOp{
+ Im: false,
+ Metas: []*tmplOpMeta{
+ {Major: "Uint", Minor: 0},
+ {Major: "Uint", Minor: 0},
+ {Major: "Int", Minor: 0},
+ {Major: "Int", Minor: 0},
+ {Major: "FixedBytes", Minor: 0},
+ {Major: "FixedBytes", Minor: 0},
+ },
+ Data: []string{`{V: 1, V: 2, V: -2, V: -128, B: {0x12, 0x34}, B: {0x00, 0x00}}`},
+ },
+ },
+ },
+ },
+ // -- end of FUNC BITAND
},
}