diff options
Diffstat (limited to 'core/vm/sqlvm/runtime/instructions.go')
-rw-r--r-- | core/vm/sqlvm/runtime/instructions.go | 109 |
1 files changed, 101 insertions, 8 deletions
diff --git a/core/vm/sqlvm/runtime/instructions.go b/core/vm/sqlvm/runtime/instructions.go index 668da692c..5a61d5f80 100644 --- a/core/vm/sqlvm/runtime/instructions.go +++ b/core/vm/sqlvm/runtime/instructions.go @@ -2,11 +2,14 @@ package runtime import ( "fmt" - "math/big" "strings" + "github.com/shopspring/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" + "github.com/dexon-foundation/dexon/core/vm/sqlvm/errors" ) var tupleJoin = "|" @@ -27,17 +30,12 @@ type Instruction struct { // Raw with embedded big.Int value or byte slice which represents the real value // of basic operand unit. type Raw struct { - MajorType ast.DataTypeMajor - MinorType ast.DataTypeMinor - - Value *big.Int + Value decimal.Decimal Bytes []byte } func (r *Raw) String() string { - return fmt.Sprintf( - "MajorType: %v, MinorType: %v, Value: %v, Bytes :%v", - r.MajorType, r.MinorType, r.Value, r.Bytes) + return fmt.Sprintf("Value: %v, Bytes: %v", r.Value, r.Bytes) } // Tuple is collection of Raw. @@ -59,3 +57,98 @@ type Operand struct { Data []Tuple RegisterIndex uint } + +func (o *Operand) toUint64() []uint64 { + result := make([]uint64, len(o.Data)) + for i, tuple := range o.Data { + result[i] = uint64(tuple[0].Value.IntPart()) + } + return result +} + +func (o *Operand) toUint8() []uint8 { + result := make([]uint8, len(o.Data)) + for i, tuple := range o.Data { + result[i] = uint8(tuple[0].Value.IntPart()) + } + return result +} + +func opLoad(ctx *common.Context, input []*Operand, registers []*Operand, output int) error { + tableIdx := input[0].Data[0][0].Value.IntPart() + if tableIdx >= int64(len(ctx.Storage.Schema)) { + return errors.ErrorCodeIndexOutOfRange + } + table := ctx.Storage.Schema[tableIdx] + + ids := input[1].toUint64() + fields := input[2].toUint8() + op := Operand{ + IsImmediate: false, + Data: make([]Tuple, len(ids)), + RegisterIndex: 0, + } + for i := range op.Data { + op.Data[i] = make([]*Raw, len(fields)) + } + meta, err := table.GetFieldType(fields) + if err != nil { + return err + } + op.Meta = meta + for i, id := range ids { + slotDataCache := make(map[dexCommon.Hash]dexCommon.Hash) + head := ctx.Storage.GetPrimaryKeyHash(table.Name, id) + for j := range fields { + col := table.Columns[int(fields[j])] + byteOffset := col.ByteOffset + slotOffset := col.SlotOffset + dt := 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.DataTypeMajorBool, + ast.DataTypeMajorAddress, ast.DataTypeMajorInt, + ast.DataTypeMajorUint: + d, err := ast.DecimalDecode(dt, bytes) + if err != nil { + return nil, err + } + rVal.Value = d + } + if major.IsFixedRange() || major.IsUfixedRange() { + d, err := ast.DecimalDecode(dt, bytes) + if err != nil { + return nil, err + } + rVal.Value = d + } + return rVal, nil +} |