package runtime
import (
"bytes"
"errors"
"fmt"
"math/big"
"regexp"
"sort"
"strings"
"github.com/dexon-foundation/decimal"
dexCommon "github.com/dexon-foundation/dexon/common"
"github.com/dexon-foundation/dexon/core/vm/sqlvm/ast"
"github.com/dexon-foundation/dexon/core/vm/sqlvm/common"
dec "github.com/dexon-foundation/dexon/core/vm/sqlvm/common/decimal"
se "github.com/dexon-foundation/dexon/core/vm/sqlvm/errors"
"github.com/dexon-foundation/dexon/core/vm/sqlvm/schema"
)
var (
byteLikeP = byte('%')
byteLikeU = byte('_')
byteDot = byte('.')
bytesLikeReg = []byte{'.', '*', '?'}
bytesStart = []byte{'^'}
bytesEnd = []byte{'$'}
tupleJoin = "|"
)
// OpFunction type
// data could be fields Fields, pattern []byte, order Orders
type OpFunction func(ctx *common.Context, ops, registers []*Operand, output uint) error
// Instruction represents single instruction with essential information
// collection.
type Instruction struct {
Op OpCode
Input []*Operand
Output uint
Position uint32 // ast tree position
}
// Raw with embedded big.Int value or byte slice which represents the real value
// of basic operand unit.
type Raw struct {
Value decimal.Decimal
Bytes []byte
}
func (r *Raw) String() string {
return fmt.Sprintf("Value: %v, Bytes: %v", r.Value, r.Bytes)
}
func (r *Raw) isTrue() bool { return dec.IsTrue(r.Value) }
func (r *Raw) isFalse() bool { return dec.IsFalse(r.Value) }
func (r *Raw) clone() *Raw {
r2 := &Raw{}
if len(r.Bytes) != 0 {
r2.Bytes = make([]byte, len(r.Bytes))
copy(r2.Bytes, r.Bytes)
} else {
r2.Value = r.Value
}
return r2
}
// Tuple is collection of Raw.
type Tuple []*Raw
func (t Tuple) String() string {
rawStr := []string{}
for i := 0; i < len(t); i++ {
rawStr = append(rawStr, t[i].String())
}
return fmt.Sprintf("\n%v\n", strings.Join(rawStr, tupleJoin))
}
// Operand would be array-based value associated with meta to describe type of
// array element.
type Operand struct {
IsImmediate bool
Meta []ast.DataType
Data []Tuple
RegisterIndex uint
}
func (op *Operand) toUint64() (result []uint64, err error) {
result = make([]uint64, len(op.Data))
for i, tuple := range op.Data {
result[i], err = ast.DecimalToUint64(tuple[0].Value)
if err != nil {
return
}
}
return
}
func (op *Operand) toTableRef() (schema.TableRef, error) {
t, err := op.toUint8()
if err != nil {
return 0, err
}
return schema.TableRef(t[0]), nil
}
func (op *Operand) toUint8() ([]uint8, error) {
result := make([]uint8, len(op.Data))
for i, tuple := range op.Data {
u, err := ast.DecimalToUint64(tuple[0].Value)
if err != nil {
return nil, err
}
result[i] = uint8(u)
}
return result, nil
}
func opLoad(ctx *common.Context, input []*Operand, registers []*Operand, output uint) error {
tableIdx := input[0].Data[0][0].Value.IntPart()
if tableIdx >= int64(len(ctx.Storage.Schema)) {
return se.ErrorCodeIndexOutOfRange
}
table := ctx.Storage.Schema[tableIdx]
tableRef := schema.TableRef(tableIdx)
ids, err := input[1].toUint64()
if err != nil {
return err
}
fields, err := input[2].toUint8()
if err != nil {
return err
}
op := Operand{
IsImmediate: false,
Data: make([]Tuple, len(ids)),
RegisterIndex: 0,
}
for i := range op.Data {
op.Data[i] = make([]*Raw, len(fields))
}
op.Meta, err = table.GetFieldType(fields)
if err != nil {
return err
}
for i, id := range ids {
slotDataCache := make(map[dexCommon.Hash]dexCommon.Hash)
head := ctx.Storage.GetRowPathHash(tableRef, id)
for j := range fields {
col := table.Columns[int(fields[j])]
byteOffset := col.ByteOffset
slotOffset := col.SlotOffset
dt := op.Meta[j]
size := dt.Size()
slot := ctx.Storage.ShiftHashUint64(head, uint64(slotOffset))
slotData := getSlotData(ctx, slot, slotDataCache)
bytes := slotData.Bytes()[byteOffset : byteOffset+size]
op.Data[i][j], err = decode(ctx, dt, slot, bytes)
if err != nil {
return err
}
}
}
registers[output] = &op
return nil
}
func getSlotData(ctx *common.Context, slot dexCommon.Hash,
cache map[dexCommon.Hash]dexCommon.Hash) dexCommon.Hash {
if d, exist := cache[slot]; exist {
return d
}
cache[slot] = ctx.Storage.GetState(ctx.Contract.Address(), slot)
return cache[slot]
}
// decode byte data to Raw format
func decode(ctx *common.Context, dt ast.DataType, slot dexCommon.Hash, bytes []byte) (*Raw, error) {
rVal := &Raw{}
major, _ := ast.DecomposeDataType(dt)
switch major {
case ast.DataTypeMajorDynamicBytes:
rVal.Bytes = ctx.Storage.DecodeDByteBySlot(ctx.Contract.Address(), slot)
case ast.DataTypeMajorFixedBytes, ast.DataTypeMajorAddress:
rVal.Bytes = bytes
case ast.DataTypeMajorBool, ast.DataTypeMajorInt, ast.DataTypeMajorUint:
d, ok := ast.DecimalDecode(dt, bytes)
if !ok {
panic(fmt.Sprintf("DecimalDecode does not handle %v", dt))
}
rVal.Value = d
}
if major.IsFixedRange() || major.IsUfixedRange() {
d, ok := ast.DecimalDecode(dt, bytes)
if !ok {
panic(fmt.Sprintf("DecimalDecode does not handle %v", dt))
}
rVal.Value = d
}
return rVal, nil
}
func (op *Operand) clone(metaOnly bool) (op2 *Operand) {
op2 = &Operand{
Meta: op.cloneMeta(),
// skip RegisterIndex since is only used when loading
// skip IsImmediate flag since is only set by codegen
}
if metaOnly {
return
}
op2.Data = make([]Tuple, len(op.Data))
for i := 0; i < len(op.Data); i++ {
op2.Data[i] = append(Tuple{}, op.Data[i]...)
}
return
}
func (op *Operand) cloneMeta() (meta []ast.DataType) {
meta = make([]ast.DataType, len(op.Meta))
copy(meta, op.Meta)
return
}
// Equal compares underlying data level-by-level.
func (op *Operand) Equal(op2 *Operand) (equal bool) {
if op2 == nil {
return
}
equal = op.IsImmediate == op2.IsImmediate
if !equal {
return
}
equal = metaAllEq(op, op2)
if !equal {
return
}
equal = len(op.Data) == len(op2.Data)
if !equal {
return
}
for i := 0; i < len(op.Data); i++ {
equal = op.Data[i].Equal(op2.Data[i], op.Meta)
if !equal {
return
}
}
return
}
// Equal compares tuple values one by one.
func (t Tuple) Equal(t2 Tuple, meta []ast.DataType) (equal bool) {
equal = len(t) == len(t2)
if !equal {
return
}
for i := 0; i < len(t); i++ {
equal = t[i].Equal(t2[i], meta[i])
if !equal {
return
}
}
return
}
// Equal compares raw by type.
func (r *Raw) Equal(r2 *Raw, dType ast.DataType) (equal bool) {
major, _ := ast.DecomposeDataType(dType)
switch major {
case ast.DataTypeMajorDynamicBytes,
ast.DataTypeMajorFixedBytes,
ast.DataTypeMajorAddress:
equal = bytes.Equal(r.Bytes, r2.Bytes)
default:
equal = r.Value.Cmp(r2.Value) == 0
}
return
}
var (
rawFalse = &Raw{Value: dec.False}
rawTrue = &Raw{Value: dec.True}
)
func metaAllEq(op1, op2 *Operand) bool {
if len(op1.Meta) != len(op2.Meta) {
return false
}
for i := 0; i < len(op1.Meta); i++ {
if op1.Meta[i] != op2.Meta[i] {
return false
}
}
return true
}
func metaAll(op *Operand, fn func(ast.DataType) bool) bool {
for i := 0; i < len(op.Meta); i++ {
if !fn(op.Meta[i]) {
return false
}
}
return true
}
func metaBool(dType ast.DataType) bool {
dMajor, _ := ast.DecomposeDataType(dType)
return dMajor == ast.DataTypeMajorBool
}
func metaAllBool(op *Operand) bool { return metaAll(op, metaBool) }
func metaArith(dType ast.DataType) bool {
major, _ := ast.DecomposeDataType(dType)
if major == ast.DataTypeMajorInt ||
major == ast.DataTypeMajorUint {
return true
}
return false
}
func metaAllArith(op *Operand) bool { return metaAll(op, metaArith) }
func findMaxDataLength(ops []*Operand) (l int, err error) {
l = -1
for i := 0; i < len(ops); i++ {
if ops[i].IsImmediate {
continue
}
if l == -1 {
l = len(ops[i].Data)
continue
}
if len(ops[i].Data) != l {
err = se.ErrorCodeDataLengthNotMatch
l = -1
return
}
}
if l == -1 {
l = 1
}
return
}
func bool2Raw(b bool) (r *Raw) {
if b {
r = rawTrue
} else {
r = rawFalse
}
return
}
func value2ColIdx(v decimal.Decimal) (idx uint16) {
if v.GreaterThan(dec.MaxUint16) {
panic(errors.New("field index greater than uint16 max"))
} else if v.LessThan(decimal.Zero) {
panic(errors.New("field index less than 0"))
}
idx = uint16(v.IntPart())
return
}
func metaDynBytes(dType ast.DataType) bool {
dMajor, _ := ast.DecomposeDataType(dType)
return dMajor == ast.DataTypeMajorDynamicBytes
}
func metaAllDynBytes(op *Operand) bool { return metaAll(op, metaDynBytes) }
func metaSignedNumeric(dType ast.DataType) bool {
major, _ := ast.DecomposeDataType(dType)
if major == ast.DataTypeMajorInt ||
major == ast.DataTypeMajorFixed {
return true
}
return false
}
func metaAllSignedNumeric(op *Operand) bool { return metaAll(op, metaSignedNumeric) }
func flowCheck(ctx *common.Context, v decimal.Decimal, dType ast.DataType) (err error) {
if !ctx.Opt.SafeMath {
return
}
min, max, ok := dType.GetMinMax()
if !ok {
err = se.ErrorCodeInvalidDataType
return
}
if v.Cmp(max) > 0 || v.Cmp(min) < 0 {
err = se.ErrorCodeOverflow
}
return
}
func opAdd(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op1, op2 := ops[0], ops[1]
if !metaAllEq(op1, op2) || !metaAllArith(op1) {
err = se.ErrorCodeInvalidDataType
return
}
l, err := findMaxDataLength(ops)
if err != nil {
return
}
data := make([]Tuple, l)
for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
if op1.IsImmediate {
j = 0
}
if op2.IsImmediate {
k = 0
}
raw, iErr := op1.Data[j].add(ctx, op2.Data[k], op1.Meta)
if iErr != nil {
err = iErr
return
}
data[i] = raw
}
registers[output] = &Operand{Meta: op1.cloneMeta(), Data: data}
return
}
func (t Tuple) add(ctx *common.Context, t2 Tuple, meta []ast.DataType) (t3 Tuple, err error) {
t3 = make(Tuple, len(t))
for i := 0; i < len(t); i++ {
raw := t[i].add(t2[i])
err = flowCheck(ctx, raw.Value, meta[i])
if err != nil {
return
}
t3[i] = raw
}
return
}
func (r *Raw) add(r2 *Raw) (r3 *Raw) {
r3 = &Raw{Value: r.Value.Add(r2.Value)}
return
}
func opMul(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op1, op2 := ops[0], ops[1]
if !metaAllEq(op1, op2) || !metaAllArith(op1) {
err = se.ErrorCodeInvalidDataType
return
}
l, err := findMaxDataLength(ops)
if err != nil {
return
}
data := make([]Tuple, l)
for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
if op1.IsImmediate {
j = 0
}
if op2.IsImmediate {
k = 0
}
raw, iErr := op1.Data[j].mul(ctx, op2.Data[k], op1.Meta)
if iErr != nil {
err = iErr
return
}
data[i] = raw
}
registers[output] = &Operand{Meta: op1.cloneMeta(), Data: data}
return
}
func (t Tuple) mul(ctx *common.Context, t2 Tuple, meta []ast.DataType) (t3 Tuple, err error) {
t3 = make(Tuple, len(t))
for i := 0; i < len(t); i++ {
raw := t[i].mul(t2[i])
err = flowCheck(ctx, raw.Value, meta[i])
if err != nil {
return
}
t3[i] = raw
}
return
}
func (r *Raw) mul(r2 *Raw) (r3 *Raw) {
r3 = &Raw{Value: r.Value.Mul(r2.Value)}
return
}
func opSub(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op1, op2 := ops[0], ops[1]
if !metaAllEq(op1, op2) || !metaAllArith(op1) {
err = se.ErrorCodeInvalidDataType
return
}
l, err := findMaxDataLength(ops)
if err != nil {
return
}
data := make([]Tuple, l)
for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
if op1.IsImmediate {
j = 0
}
if op2.IsImmediate {
k = 0
}
raw, iErr := op1.Data[j].sub(ctx, op2.Data[k], op1.Meta)
if iErr != nil {
err = iErr
return
}
data[i] = raw
}
registers[output] = &Operand{Meta: op1.cloneMeta(), Data: data}
return
}
func (t Tuple) sub(ctx *common.Context, t2 Tuple, meta []ast.DataType) (t3 Tuple, err error) {
t3 = make(Tuple, len(t))
for i := 0; i < len(t); i++ {
raw := t[i].sub(t2[i])
err = flowCheck(ctx, raw.Value, meta[i])
if err != nil {
return
}
t3[i] = raw
}
return
}
func (r *Raw) sub(r2 *Raw) (r3 *Raw) {
r3 = &Raw{Value: r.Value.Sub(r2.Value)}
return
}
func opDiv(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op1, op2 := ops[0], ops[1]
if !metaAllEq(op1, op2) || !metaAllArith(op1) {
err = se.ErrorCodeInvalidDataType
return
}
l, err := findMaxDataLength(ops)
if err != nil {
return
}
data := make([]Tuple, l)
for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
if op1.IsImmediate {
j = 0
}
if op2.IsImmediate {
k = 0
}
raw, iErr := op1.Data[j].div(ctx, op2.Data[k], op1.Meta)
if iErr != nil {
err = iErr
return
}
data[i] = raw
}
registers[output] = &Operand{Meta: op1.cloneMeta(), Data: data}
return
}
func (t Tuple) div(ctx *common.Context, t2 Tuple, meta []ast.DataType) (t3 Tuple, err error) {
t3 = make(Tuple, len(t))
for i := 0; i < len(t); i++ {
raw, iErr := t[i].div(t2[i])
if iErr != nil {
err = iErr
return
}
iErr = flowCheck(ctx, raw.Value, meta[i])
if iErr != nil {
err = iErr
return
}
t3[i] = raw
}
return
}
func (r *Raw) div(r2 *Raw) (r3 *Raw, err error) {
if r2.Value.IsZero() {
err = se.ErrorCodeDividedByZero
return
}
q, _ := r.Value.QuoRem(r2.Value, 0)
r3 = &Raw{Value: q}
return
}
func opMod(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op1, op2 := ops[0], ops[1]
if !metaAllEq(op1, op2) || !metaAllArith(op1) {
err = se.ErrorCodeInvalidDataType
return
}
l, err := findMaxDataLength(ops)
if err != nil {
return
}
data := make([]Tuple, l)
for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
if op1.IsImmediate {
j = 0
}
if op2.IsImmediate {
k = 0
}
raw, iErr := op1.Data[j].mod(ctx, op2.Data[k], op1.Meta)
if iErr != nil {
err = iErr
return
}
data[i] = raw
}
registers[output] = &Operand{Meta: op1.cloneMeta(), Data: data}
return
}
func (t Tuple) mod(ctx *common.Context, t2 Tuple, meta []ast.DataType) (t3 Tuple, err error) {
t3 = make(Tuple, len(t))
for i := 0; i < len(t); i++ {
raw, iErr := t[i].mod(t2[i])
if iErr != nil {
err = iErr
return
}
t3[i] = raw
}
return
}
func (r *Raw) mod(r2 *Raw) (r3 *Raw, err error) {
if r2.Value.IsZero() {
err = se.ErrorCodeDividedByZero
return
}
_, qr := r.Value.QuoRem(r2.Value, 0)
r3 = &Raw{Value: qr}
return
}
func opLt(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op1, op2 := ops[0], ops[1]
if !metaAllEq(op1, op2) {
err = se.ErrorCodeInvalidDataType
return
}
l, err := findMaxDataLength(ops)
if err != nil {
return
}
data := make([]Tuple, l)
for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
if op1.IsImmediate {
j = 0
}
if op2.IsImmediate {
k = 0
}
data[i] = op1.Data[j].lt(op2.Data[k])
}
boolType := ast.ComposeDataType(ast.DataTypeMajorBool, 0)
meta := make([]ast.DataType, len(op1.Meta))
for i := 0; i < len(op1.Meta); i++ {
meta[i] = boolType
}
registers[output] = &Operand{Meta: meta, Data: data}
return
}
func (t Tuple) lt(t2 Tuple) (t3 Tuple) {
t3 = make(Tuple, len(t))
for i := 0; i < len(t); i++ {
t3[i] = bool2Raw(t[i].lt(t2[i]))
}
return
}
func (r *Raw) lt(r2 *Raw) (lt bool) {
if r.Bytes == nil {
lt = r.Value.Cmp(r2.Value) < 0
} else {
lt = bytes.Compare(r.Bytes, r2.Bytes) < 0
}
return
}
func opGt(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op1, op2 := ops[0], ops[1]
if !metaAllEq(op1, op2) {
err = se.ErrorCodeInvalidDataType
return
}
l, err := findMaxDataLength(ops)
if err != nil {
return
}
data := make([]Tuple, l)
for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
if op1.IsImmediate {
j = 0
}
if op2.IsImmediate {
k = 0
}
data[i] = op1.Data[j].gt(op2.Data[k])
}
boolType := ast.ComposeDataType(ast.DataTypeMajorBool, 0)
meta := make([]ast.DataType, len(op1.Meta))
for i := 0; i < len(op1.Meta); i++ {
meta[i] = boolType
}
registers[output] = &Operand{Meta: meta, Data: data}
return
}
func (t Tuple) gt(t2 Tuple) (t3 Tuple) {
t3 = make(Tuple, len(t))
for i := 0; i < len(t); i++ {
t3[i] = bool2Raw(t[i].gt(t2[i]))
}
return
}
func (r *Raw) gt(r2 *Raw) (gt bool) {
if r.Bytes == nil {
gt = r.Value.Cmp(r2.Value) > 0
} else {
gt = bytes.Compare(r.Bytes, r2.Bytes) > 0
}
return
}
func opEq(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op1, op2 := ops[0], ops[1]
if !metaAllEq(op1, op2) {
err = se.ErrorCodeInvalidDataType
return
}
l, err := findMaxDataLength(ops)
if err != nil {
return
}
data := make([]Tuple, l)
for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
if op1.IsImmediate {
j = 0
}
if op2.IsImmediate {
k = 0
}
data[i] = op1.Data[j].eq(op2.Data[k], op1.Meta)
}
boolType := ast.ComposeDataType(ast.DataTypeMajorBool, 0)
meta := make([]ast.DataType, len(op1.Meta))
for i := 0; i < len(op1.Meta); i++ {
meta[i] = boolType
}
registers[output] = &Operand{Meta: meta, Data: data}
return
}
func (t Tuple) eq(t2 Tuple, meta []ast.DataType) (t3 Tuple) {
t3 = make(Tuple, len(t))
for i := 0; i < len(t); i++ {
t3[i] = bool2Raw(t[i].Equal(t2[i], meta[i]))
}
return
}
func opAnd(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op1, op2 := ops[0], ops[1]
if !metaAllEq(op1, op2) {
err = se.ErrorCodeInvalidDataType
return
}
if !metaAllBool(op1) {
err = se.ErrorCodeInvalidDataType
return
}
l, err := findMaxDataLength(ops)
if err != nil {
return
}
data := make([]Tuple, l)
for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
if op1.IsImmediate {
j = 0
}
if op2.IsImmediate {
k = 0
}
data[i] = op1.Data[j].and(op2.Data[k])
}
boolType := ast.ComposeDataType(ast.DataTypeMajorBool, 0)
meta := make([]ast.DataType, l)
for i := 0; i < l; i++ {
meta[i] = boolType
}
registers[output] = &Operand{Meta: meta, Data: data}
return
}
func (t Tuple) and(t2 Tuple) (t3 Tuple) {
t3 = make(Tuple, len(t))
for i := 0; i < len(t); i++ {
t3[i] = t[i].and(t2[i])
}
return
}
func (r *Raw) and(r2 *Raw) (r3 *Raw) {
r3 = bool2Raw(r.isTrue() && r2.isTrue())
return
}
func opOr(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op1, op2 := ops[0], ops[1]
if !metaAllEq(op1, op2) {
err = se.ErrorCodeInvalidDataType
return
}
if !metaAllBool(op1) {
err = se.ErrorCodeInvalidDataType
return
}
l, err := findMaxDataLength(ops)
if err != nil {
return
}
data := make([]Tuple, l)
for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
if op1.IsImmediate {
j = 0
}
if op2.IsImmediate {
k = 0
}
data[i] = op1.Data[j].or(op2.Data[k])
}
boolType := ast.ComposeDataType(ast.DataTypeMajorBool, 0)
meta := make([]ast.DataType, l)
for i := 0; i < l; i++ {
meta[i] = boolType
}
registers[output] = &Operand{Meta: meta, Data: data}
return
}
func (t Tuple) or(t2 Tuple) (t3 Tuple) {
t3 = make(Tuple, len(t))
for i := 0; i < len(t); i++ {
t3[i] = t[i].or(t2[i])
}
return
}
func (r *Raw) or(r2 *Raw) (r3 *Raw) {
r3 = bool2Raw(r.Value.Equal(dec.True) || r2.Value.Equal(dec.True))
return
}
func opNot(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 1 {
err = se.ErrorCodeInvalidOperandNum
return
}
op := ops[0]
if !metaAllBool(op) {
err = se.ErrorCodeInvalidDataType
return
}
data := make([]Tuple, len(op.Data))
for i := 0; i < len(op.Data); i++ {
data[i] = op.Data[i].not()
}
registers[output] = &Operand{Meta: op.cloneMeta(), Data: data}
return
}
func (t Tuple) not() (t2 Tuple) {
t2 = make(Tuple, len(t))
for i := 0; i < len(t); i++ {
t2[i] = t[i].not()
}
return
}
func (r *Raw) not() (r2 *Raw) {
r2 = bool2Raw(r.Value.IsZero())
return
}
func opUnion(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op1, op2 := ops[0], ops[1]
if !metaAllEq(op1, op2) {
err = se.ErrorCodeInvalidDataType
return
}
if len(op1.Data) > len(op2.Data) {
op1, op2 = op2, op1
}
tmpMap := make(map[string]struct{})
for i := 0; i < len(op1.Data); i++ {
tmpMap[op1.Data[i].String()] = struct{}{}
}
op3 := op1.clone(false)
for i := 0; i < len(op2.Data); i++ {
if _, ok := tmpMap[op2.Data[i].String()]; !ok {
op3.Data = append(op3.Data, append(Tuple{}, op2.Data[i]...))
}
}
orders := make([]sortOption, len(op3.Meta))
for i := 0; i < len(orders); i++ {
orders[i] = sortOption{Asc: true, Field: uint(i)}
}
sort.SliceStable(
op3.Data,
func(i, j int) bool { return op3.Data[i].less(op3.Data[j], orders) },
)
registers[output] = op3
return
}
func opIntxn(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op1, op2 := ops[0], ops[1]
if !metaAllEq(op1, op2) {
err = se.ErrorCodeInvalidDataType
return
}
if len(op1.Data) > len(op2.Data) {
op1, op2 = op2, op1
}
tmpMap := make(map[string]struct{})
for i := 0; i < len(op1.Data); i++ {
tmpMap[op1.Data[i].String()] = struct{}{}
}
op3 := &Operand{Meta: op1.cloneMeta(), Data: []Tuple{}}
for i := 0; i < len(op2.Data); i++ {
if _, ok := tmpMap[op2.Data[i].String()]; ok {
op3.Data = append(op3.Data, append(Tuple{}, op2.Data[i]...))
}
}
orders := make([]sortOption, len(op3.Meta))
for i := 0; i < len(orders); i++ {
orders[i] = sortOption{Asc: true, Field: uint(i)}
}
sort.SliceStable(
op3.Data,
func(i, j int) bool { return op3.Data[i].less(op3.Data[j], orders) },
)
registers[output] = op3
return
}
func opLike(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 && len(ops) != 3 {
err = se.ErrorCodeInvalidOperandNum
return
}
op, pattern := ops[0], ops[1]
var escape *Operand
if len(ops) > 2 {
escape = ops[2]
}
var cReg *regexp.Regexp
matchWithI := pattern.IsImmediate && (escape == nil || escape.IsImmediate)
if matchWithI {
var escapeBytes []byte
if escape != nil && len(escape.Data) > 0 {
escapeBytes = escape.Data[0][0].Bytes
}
if len(escapeBytes) > 1 {
err = se.ErrorCodeMultipleEscapeByte
return
}
cReg, err = like2regexp(pattern.Data[0][0].Bytes, escapeBytes)
if err != nil {
return
}
}
data := make([]Tuple, len(op.Data))
if matchWithI {
for i := 0; i < len(op.Data); i++ {
raw, iErr := op.Data[i].like(cReg)
if iErr != nil {
err = iErr
return
}
data[i] = raw
}
} else {
var (
pat []byte
esc []byte
)
for i := 0; i < len(op.Data); i++ {
if pattern.IsImmediate {
pat = pattern.Data[0][0].Bytes
} else {
pat = pattern.Data[i][0].Bytes
}
if escape != nil {
if escape.IsImmediate {
esc = escape.Data[0][0].Bytes
} else {
esc = escape.Data[i][0].Bytes
}
} else {
esc = []byte{}
}
if len(esc) > 1 {
err = se.ErrorCodeMultipleEscapeByte
return
}
reg, iErr := like2regexp(pat, esc)
if iErr != nil {
err = iErr
return
}
raw, iErr := op.Data[i].like(reg)
if iErr != nil {
err = iErr
return
}
data[i] = raw
}
}
boolType := ast.ComposeDataType(ast.DataTypeMajorBool, 0)
meta := make([]ast.DataType, len(op.Meta))
for i := 0; i < len(meta); i++ {
meta[i] = boolType
}
registers[output] = &Operand{Meta: meta, Data: data}
return
}
// check parser/parser.go comment for string encoding
func encB(b []byte) []byte {
encBuf := bytes.Buffer{}
for _, c := range b {
encBuf.WriteRune(rune(c))
}
return encBuf.Bytes()
}
func writeC2Buf(buf *bytes.Buffer, c byte) {
if c < 0x80 {
// quote for valid ascii
buf.WriteString(regexp.QuoteMeta(string(c)))
} else {
buf.WriteRune(rune(c))
}
}
func like2regexp(pattern []byte, escape []byte) (reg *regexp.Regexp, err error) {
var (
buf = &bytes.Buffer{}
escMode = len(escape) > 0
isEsc = false
c byte
)
for i := 0; i < len(pattern); i++ {
c = pattern[i]
if escMode && !isEsc && c == escape[0] {
isEsc = true
continue
}
if escMode && isEsc {
isEsc = false
writeC2Buf(buf, c)
continue
}
switch c {
case byteLikeP:
buf.Write(bytesLikeReg)
case byteLikeU:
buf.WriteByte(byteDot)
default:
writeC2Buf(buf, c)
}
}
if isEsc {
err = se.ErrorCodePendingEscapeByte
return
}
rPattern := buf.Bytes()
if !bytes.HasPrefix(rPattern, bytesLikeReg) {
rPattern = append(bytesStart, rPattern...)
}
if !bytes.HasSuffix(rPattern, bytesLikeReg) {
rPattern = append(rPattern, bytesEnd...)
}
reg, err = regexp.Compile(string(rPattern))
return
}
func (t Tuple) like(reg *regexp.Regexp) (t2 Tuple, err error) {
t2 = make(Tuple, len(t))
for i := 0; i < len(t); i++ {
t2[i] = t[i].like(reg)
}
return
}
func (r *Raw) like(reg *regexp.Regexp) (r2 *Raw) {
r2 = bool2Raw(reg.Match(encB(r.Bytes)))
return
}
func opZip(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) == 0 {
err = se.ErrorCodeInvalidOperandNum
return
}
l, err := findMaxDataLength(ops)
if err != nil {
return
}
op3 := &Operand{Meta: make([]ast.DataType, 0), Data: make([]Tuple, l)}
for i := 0; i < len(ops); i++ {
op3.Meta = append(op3.Meta, ops[i].Meta...)
}
for i := 0; i < l; i++ {
if ops[0].IsImmediate {
op3.Data[i] = append(Tuple{}, ops[0].Data[0]...)
} else {
op3.Data[i] = append(Tuple{}, ops[0].Data[i]...)
}
for j := 1; j < len(ops); j++ {
if ops[j].IsImmediate {
op3.Data[i] = append(op3.Data[i], ops[j].Data[0]...)
} else {
op3.Data[i] = append(op3.Data[i], ops[j].Data[i]...)
}
}
}
registers[output] = op3
return
}
func opField(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op, fields := ops[0], ops[1].Data[0]
fLen := len(fields)
var fieldIdx uint16
meta, fieldIdxs := make([]ast.DataType, fLen), make([]uint16, fLen)
for i := 0; i < fLen; i++ {
fieldIdx = value2ColIdx(fields[i].Value)
if len(op.Meta) <= int(fieldIdx) {
err = se.ErrorCodeIndexOutOfRange
return
}
meta[i], fieldIdxs[i] = op.Meta[fieldIdx], fieldIdx
}
data := make([]Tuple, len(op.Data))
for i := 0; i < len(op.Data); i++ {
tuple := make(Tuple, fLen)
for j := 0; j < fLen; j++ {
tuple[j] = op.Data[i][fieldIdxs[j]]
}
data[i] = tuple
}
registers[output] = &Operand{Meta: meta, Data: data}
return
}
// in-place Op
func opPrune(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op, fields := ops[0], ops[1].Data[0]
fLen := len(fields)
var fieldIdx uint16
fieldIdxs := make([]int, fLen)
for i := 0; i < fLen; i++ {
fieldIdx = value2ColIdx(fields[i].Value)
if len(op.Meta) <= int(fieldIdx) {
err = se.ErrorCodeIndexOutOfRange
return
}
fieldIdxs[i] = int(fieldIdx)
}
op.Meta = pruneMeta(op.Meta, fieldIdxs)
for i := 0; i < len(op.Data); i++ {
op.Data[i] = pruneTuple(op.Data[i], fieldIdxs)
}
return
}
func pruneMeta(meta []ast.DataType, prune []int) []ast.DataType {
for src, dst, pruneIdx := 0, 0, 0; src < len(meta); src++ {
if pruneIdx < len(prune) && src == prune[pruneIdx] {
pruneIdx++
continue
}
meta[dst] = meta[src]
dst++
}
return meta[:len(meta)-len(prune)]
}
func pruneTuple(t Tuple, prune []int) Tuple {
for src, dst, pruneIdx := 0, 0, 0; src < len(t); src++ {
if pruneIdx < len(prune) && src == prune[pruneIdx] {
pruneIdx++
continue
}
t[dst] = t[src]
dst++
}
return t[:len(t)-len(prune)]
}
// in-place Op
func opCut(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op, slice := ops[0], ops[1].Data[0]
maxL := uint16(len(op.Meta))
start, end := value2ColIdx(slice[0].Value), maxL
if len(slice) > 1 {
end = value2ColIdx(slice[1].Value) + 1
}
if start > maxL || end > maxL || start > end {
err = se.ErrorCodeIndexOutOfRange
return
}
op.Meta = append(op.Meta[:start], op.Meta[end:]...)
for i := 0; i < len(op.Data); i++ {
op.Data[i] = append(op.Data[i][:start], op.Data[i][end:]...)
}
registers[output] = op
return
}
// in-place Op
func opRange(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op, slice := ops[0], ops[1].Data[0]
offset, err := ast.DecimalToUint64(slice[0].Value)
if err != nil {
return
}
if offset < uint64(len(op.Data)) {
op.Data = op.Data[offset:]
} else {
op.Data = op.Data[:0]
}
if len(slice) > 1 && len(op.Data) > 0 {
var limit uint64
limit, err = ast.DecimalToUint64(slice[1].Value)
if err != nil {
return
}
if limit < uint64(len(op.Data)) {
op.Data = op.Data[:limit]
}
}
registers[output] = op
return
}
// in-place Op
func opSort(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op := ops[0]
// orders (ascending bool, field)
orders := make([]sortOption, len(ops[1].Data))
for i, o := range ops[1].Data {
orders[i] = sortOption{
Asc: o[0].isTrue(),
Field: uint(value2ColIdx(o[1].Value)),
}
}
sort.SliceStable(
op.Data,
func(i, j int) bool { return op.Data[i].less(op.Data[j], orders) },
)
return
}
type sortOption struct {
Asc bool
Field uint
}
func (t Tuple) less(t2 Tuple, orders []sortOption) bool {
var r int
for _, o := range orders {
r = 0
if o.Asc {
r = t[o.Field].cmp(t2[o.Field])
} else {
r = t2[o.Field].cmp(t[o.Field])
}
switch r {
case -1:
return true
case 1:
return false
}
}
return false
}
func (r *Raw) cmp(r2 *Raw) (v int) {
if r.Bytes != nil {
v = bytes.Compare(r.Bytes, r2.Bytes)
} else {
v = r.Value.Cmp(r2.Value)
}
return
}
func opFilter(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op, filters := ops[0], ops[1]
op2 := &Operand{Meta: op.cloneMeta(), Data: make([]Tuple, 0)}
for i := 0; i < len(filters.Data); i++ {
if filters.Data[i][0].isTrue() {
op2.Data = append(op2.Data, append(Tuple{}, op.Data[i]...))
}
}
registers[output] = op2
return
}
// Type check will ensure all cast is valid
func opCast(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
op := ops[0]
dTypes := ops[1].Meta
if len(dTypes) != len(op.Meta) {
err = se.ErrorCodeInvalidDataType
return
}
op2 := &Operand{Meta: ops[1].cloneMeta(), Data: make([]Tuple, len(op.Data))}
for i := 0; i < len(op.Data); i++ {
op2.Data[i] = append(Tuple{}, op.Data[i]...)
for j, dType := range dTypes {
if op.Meta[j] == dType {
continue
}
err = op2.Data[i][j].cast(ctx, op.Meta[j], dType)
if err != nil {
return
}
}
}
registers[output] = op2
return
}
func (r *Raw) cast(ctx *common.Context, origin, target ast.DataType) (err error) {
oMajor, _ := ast.DecomposeDataType(origin)
// conversion table
switch oMajor {
case ast.DataTypeMajorInt, ast.DataTypeMajorUint:
err = r.castInt(ctx, origin, target)
case ast.DataTypeMajorFixedBytes:
err = r.castFixedBytes(ctx, origin, target)
case ast.DataTypeMajorAddress:
err = r.castAddress(ctx, origin, target)
case ast.DataTypeMajorBool:
err = r.castBool(origin, target)
case ast.DataTypeMajorDynamicBytes:
err = r.castDynBytes(origin, target)
default:
err = se.ErrorCodeInvalidCastType
}
return
}
func (r *Raw) castValue(
ctx *common.Context,
origin, target ast.DataType,
l int, signed, rPadding bool) (err error) {
oBytes, ok := ast.DecimalEncode(origin, r.Value)
if !ok {
panic(fmt.Sprintf("DecimalEncode does not handle %v", origin))
}
bytes2 := r.shiftBytes(oBytes, l, signed, rPadding)
r.Value, ok = ast.DecimalDecode(target, bytes2)
if !ok {
panic(fmt.Sprintf("DecimalDecode does not handle %v", target))
}
err = flowCheck(ctx, r.Value, target)
return
}
func (r *Raw) castInt(ctx *common.Context, origin, target ast.DataType) (err error) {
oMajor, oMinor := ast.DecomposeDataType(origin)
tMajor, tMinor := ast.DecomposeDataType(target)
signed := oMajor == ast.DataTypeMajorInt
switch tMajor {
case ast.DataTypeMajorInt, ast.DataTypeMajorUint:
err = r.castValue(ctx, origin, target, int(tMinor)+1, signed, false)
case ast.DataTypeMajorAddress:
var mockDt ast.DataType
if signed {
mockDt = ast.ComposeDataType(ast.DataTypeMajorInt, 19)
} else {
mockDt = ast.ComposeDataType(ast.DataTypeMajorUint, 19)
}
if ctx.Opt.SafeMath && flowCheck(ctx, r.Value, mockDt) != nil {
err = se.ErrorCodeOverflow
return
}
var ok bool
r.Bytes, ok = ast.DecimalEncode(mockDt, r.Value)
if !ok {
panic(fmt.Sprintf("DecimalEncode does not handle %v", origin))
}
r.Value = decimal.Zero
case ast.DataTypeMajorFixedBytes:
if tMinor != oMinor {
err = se.ErrorCodeInvalidCastType
return
}
var ok bool
r.Bytes, ok = ast.DecimalEncode(origin, r.Value)
if !ok {
panic(fmt.Sprintf("DecimalEncode does not handle %v", origin))
}
r.Value = decimal.Zero
case ast.DataTypeMajorBool:
r.Value = dec.Val2Bool(r.Value)
default:
err = se.ErrorCodeInvalidCastType
}
return
}
func (r *Raw) castFixedBytes(ctx *common.Context, origin, target ast.DataType) (err error) {
_, oMinor := ast.DecomposeDataType(origin)
tMajor, tMinor := ast.DecomposeDataType(target)
switch tMajor {
case ast.DataTypeMajorDynamicBytes:
case ast.DataTypeMajorInt, ast.DataTypeMajorUint:
if tMinor != oMinor {
err = se.ErrorCodeInvalidCastType
return
}
var ok bool
r.Value, ok = ast.DecimalDecode(target, r.Bytes)
if !ok {
panic(fmt.Sprintf("DecimalDecode does not handle %v", target))
}
r.Bytes = nil
case ast.DataTypeMajorFixedBytes:
r.Bytes = r.shiftBytes(r.Bytes, int(tMinor)+1, false, true)
case ast.DataTypeMajorAddress:
if oMinor != (dexCommon.AddressLength - 1) {
err = se.ErrorCodeInvalidCastType
return
}
default:
err = se.ErrorCodeInvalidCastType
}
return
}
func (r *Raw) castAddress(ctx *common.Context, origin, target ast.DataType) (err error) {
tMajor, tMinor := ast.DecomposeDataType(target)
switch tMajor {
case ast.DataTypeMajorAddress:
case ast.DataTypeMajorInt, ast.DataTypeMajorUint:
var ok bool
r.Value, ok = ast.DecimalDecode(
target,
r.shiftBytes(r.Bytes, int(tMinor)+1, false, false),
)
if !ok {
panic(fmt.Sprintf("DecimalDecode does not handle %v", target))
}
err = flowCheck(ctx, r.Value, target)
if err != nil {
return
}
r.Bytes = nil
case ast.DataTypeMajorFixedBytes:
if tMinor != (dexCommon.AddressLength - 1) {
err = se.ErrorCodeInvalidCastType
return
}
default:
err = se.ErrorCodeInvalidCastType
}
return
}
func (r *Raw) castBool(origin, target ast.DataType) (err error) {
tMajor, _ := ast.DecomposeDataType(target)
switch tMajor {
case ast.DataTypeMajorBool, ast.DataTypeMajorInt, ast.DataTypeMajorUint:
default:
err = se.ErrorCodeInvalidCastType
}
return
}
func (r *Raw) castDynBytes(origin, target ast.DataType) (err error) {
tMajor, tMinor := ast.DecomposeDataType(target)
switch tMajor {
case ast.DataTypeMajorDynamicBytes:
case ast.DataTypeMajorFixedBytes:
r.Bytes = r.shiftBytes(r.Bytes, int(tMinor)+1, false, true)
default:
err = se.ErrorCodeInvalidCastType
}
return
}
func (r *Raw) shiftBytes(src []byte, l int, signed, rPadding bool) (tgr []byte) {
if len(src) >= l {
if rPadding {
tgr = src[:l]
} else {
tgr = src[len(src)-l:]
}
return
}
tgr = make([]byte, l)
if rPadding {
copy(tgr, src)
return
}
copy(tgr[l-len(src):], src)
if signed && src[0]&0x80 != 0 {
for i := 0; i < l-len(src); i++ {
tgr[i] = 0xff
}
}
return
}
func opConcat(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 2 {
err = se.ErrorCodeDataLengthNotMatch
return
}
op, op2 := ops[0], ops[1]
if !metaAllEq(op, op2) {
err = se.ErrorCodeInvalidDataType
return
}
if !metaAllDynBytes(op) {
err = se.ErrorCodeInvalidDataType
return
}
op3 := op.clone(true)
op3.Data = make([]Tuple, len(op.Data))
for i := 0; i < len(op.Data); i++ {
op3.Data[i] = op.Data[i].concat(op2.Data[i])
}
registers[output] = op3
return
}
func (t Tuple) concat(t2 Tuple) (t3 Tuple) {
t3 = make(Tuple, len(t))
for i := 0; i < len(t); i++ {
t3[i] = &Raw{Bytes: make([]byte, len(t[i].Bytes)+len(t2[i].Bytes))}
copy(t3[i].Bytes[:len(t[i].Bytes)], t[i].Bytes)
copy(t3[i].Bytes[len(t[i].Bytes):], t2[i].Bytes)
}
return
}
func opNeg(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) != 1 {
err = se.ErrorCodeDataLengthNotMatch
return
}
op := ops[0]
if !metaAllSignedNumeric(op) {
err = se.ErrorCodeInvalidDataType
return
}
op2 := op.clone(true)
op2.Data = make([]Tuple, len(op.Data))
for i := 0; i < len(op.Data); i++ {
op2.Data[i], err = op.Data[i].neg(ctx, op2.Meta)
if err != nil {
return
}
}
registers[output] = op2
return
}
func (t Tuple) neg(ctx *common.Context, meta []ast.DataType) (t2 Tuple, err error) {
t2 = make(Tuple, len(t))
for i := 0; i < len(t); i++ {
t2[i] = &Raw{Value: t[i].Value.Neg()}
err = flowCheck(ctx, t2[i].Value, meta[i])
if err != nil {
return
}
}
return
}
func opFunc(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
if len(ops) < 2 {
err = se.ErrorCodeInvalidOperandNum
return
}
var (
opLength, opFuncID = ops[0], ops[1]
result *Operand
length uint64
)
if opLength.IsImmediate {
length, err = ast.DecimalToUint64(opLength.Data[0][0].Value)
if err != nil {
return
}
} else {
length = uint64(len(opLength.Data))
}
funcID, err := ast.DecimalToUint64(opFuncID.Data[0][0].Value)
if err != nil {
return
}
id := uint16(funcID)
if uint64(id) != funcID {
err = se.ErrorCodeIndexOutOfRange
return
}
result, err = fnTable[id](ctx, ops[2:], length)
if err != nil {
return
}
registers[output] = result
return
}
func uint64ToOperands(numbers []uint64) (*Operand, error) {
result := &Operand{
Meta: []ast.DataType{ast.ComposeDataType(ast.DataTypeMajorUint, 7)},
Data: []Tuple{},
}
result.Data = make([]Tuple, len(numbers))
for i, n := range numbers {
result.Data[i] = []*Raw{
{
Value: decimal.NewFromBigInt(new(big.Int).SetUint64(n), 0),
Bytes: nil,
},
}
}
return result, nil
}
func opRepeatPK(ctx *common.Context, input []*Operand, registers []*Operand, output int) (err error) {
tableRef, err := input[0].toTableRef()
if err != nil {
return err
}
IDs := ctx.Storage.RepeatPK(ctx.Contract.Address(), tableRef)
registers[output], err = uint64ToOperands(IDs)
return
}
// fillAutoInc returns the operand reference with incremented value.
func fillAutoInc(
ctx *common.Context,
col schema.Column,
tableRef schema.TableRef,
) (*Operand, error) {
dVal := ctx.Storage.IncSequence(ctx.Contract.Address(),
tableRef, uint8(col.Sequence), 1)
_, max, ok := col.Type.GetMinMax()
if !ok {
return nil, se.ErrorCodeInvalidDataType
}
if dVal.Cmp(max) > 0 {
return nil, se.ErrorCodeOverflow
}
op := &Operand{
Meta: []ast.DataType{col.Type},
Data: []Tuple{
{
&Raw{
Value: dVal,
Bytes: nil,
},
},
},
}
return op, nil
}
// fillDefault returns the operand reference with default value.
func fillDefault(
ctx *common.Context,
col schema.Column,
) (*Operand, error) {
var r Raw
major, _ := ast.DecomposeDataType(col.Type)
switch major {
case ast.DataTypeMajorDynamicBytes, ast.DataTypeMajorAddress:
r = Raw{
Bytes: col.Default.([]byte),
}
case ast.DataTypeMajorBool:
b := col.Default.(bool)
if b {
r = Raw{Value: dec.True}
} else {
r = Raw{Value: dec.False}
}
default:
r = Raw{Value: col.Default.(decimal.Decimal)}
}
op := &Operand{
Meta: []ast.DataType{col.Type},
Data: []Tuple{
{
&r,
},
},
}
return op, nil
}