aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJhih-Ming Huang <jm.huang@cobinhood.com>2019-03-15 17:39:20 +0800
committerJhih-Ming Huang <jm.huang@cobinhood.com>2019-05-06 10:44:04 +0800
commitd3fac9087206355c1efdb9eba1e5f57c78346c50 (patch)
tree621fbd25cb91f7fe97e85510fe7907d676bed407
parent6d6da8295a287039805e8ed070c8b57ec3e70caa (diff)
downloaddexon-d3fac9087206355c1efdb9eba1e5f57c78346c50.tar
dexon-d3fac9087206355c1efdb9eba1e5f57c78346c50.tar.gz
dexon-d3fac9087206355c1efdb9eba1e5f57c78346c50.tar.bz2
dexon-d3fac9087206355c1efdb9eba1e5f57c78346c50.tar.lz
dexon-d3fac9087206355c1efdb9eba1e5f57c78346c50.tar.xz
dexon-d3fac9087206355c1efdb9eba1e5f57c78346c50.tar.zst
dexon-d3fac9087206355c1efdb9eba1e5f57c78346c50.zip
core: vm: sqlvm: schema: implment get column field type and set offset
Since we have to packing our data in slot, it needs to calculate each column field's slot and byte offset.
-rw-r--r--core/vm/sqlvm/schema/schema.go56
-rw-r--r--core/vm/sqlvm/schema/schema_test.go189
2 files changed, 243 insertions, 2 deletions
diff --git a/core/vm/sqlvm/schema/schema.go b/core/vm/sqlvm/schema/schema.go
index e3e695663..f2a46631d 100644
--- a/core/vm/sqlvm/schema/schema.go
+++ b/core/vm/sqlvm/schema/schema.go
@@ -7,6 +7,7 @@ import (
"github.com/shopspring/decimal"
"github.com/dexon-foundation/dexon/core/vm/sqlvm/ast"
+ se "github.com/dexon-foundation/dexon/core/vm/sqlvm/errors"
"github.com/dexon-foundation/dexon/rlp"
)
@@ -102,6 +103,13 @@ func (a IndexAttr) GetDerivedFlags() IndexAttr {
// Schema defines sqlvm schema struct.
type Schema []Table
+// SetupColumnOffset set all tables' column offset.
+func (s Schema) SetupColumnOffset() {
+ for i := range s {
+ s[i].SetupColumnOffset()
+ }
+}
+
// Table defiens sqlvm table struct.
type Table struct {
Name []byte
@@ -109,6 +117,35 @@ type Table struct {
Indices []Index
}
+// GetFieldType return fields' data type.
+func (t *Table) GetFieldType(fields []uint8) ([]ast.DataType, error) {
+ types := make([]ast.DataType, len(fields))
+ columns := t.Columns
+ for i, f := range fields {
+ if int(f) < 0 || int(f) >= len(columns) {
+ return nil, se.ErrorCodeIndexOutOfRange
+ }
+ types[i] = columns[int(fields[i])].Type
+ }
+ return types, nil
+}
+
+// SetupColumnOffset set columns' slot and byte offset.
+func (t *Table) SetupColumnOffset() {
+ slotOffset := uint8(0)
+ byteOffset := uint8(0)
+ for i, col := range t.Columns {
+ size := col.Type.Size()
+ if size+byteOffset > 32 {
+ slotOffset++
+ byteOffset = 0
+ }
+ t.Columns[i].SlotOffset = slotOffset
+ t.Columns[i].ByteOffset = byteOffset
+ byteOffset += size
+ }
+}
+
// Index defines sqlvm index struct.
type Index struct {
Name []byte
@@ -124,6 +161,8 @@ type column struct {
ForeignColumn ColumnRef
Sequence SequenceRef
Rest interface{}
+ SlotOffset uint8
+ ByteOffset uint8
}
// Column defines sqlvm index struct.
@@ -132,6 +171,23 @@ type Column struct {
Default interface{} // decimal.Decimal, bool, []byte
}
+// NewColumn return a Column instance.
+func NewColumn(Name []byte, Type ast.DataType, Attr ColumnAttr, Sequence SequenceRef,
+ FT TableRef, FC ColumnRef) Column {
+ c := column{
+ Name: Name,
+ Type: Type,
+ Attr: Attr,
+ Sequence: Sequence,
+ ForeignTable: FT,
+ ForeignColumn: FC,
+ }
+
+ return Column{
+ column: c,
+ }
+}
+
var _ rlp.Decoder = (*Column)(nil)
var _ rlp.Encoder = Column{}
diff --git a/core/vm/sqlvm/schema/schema_test.go b/core/vm/sqlvm/schema/schema_test.go
index 8a9044857..0c75b0cb6 100644
--- a/core/vm/sqlvm/schema/schema_test.go
+++ b/core/vm/sqlvm/schema/schema_test.go
@@ -6,10 +6,12 @@ import (
"io/ioutil"
"testing"
- "github.com/dexon-foundation/dexon/core/vm/sqlvm/ast"
- "github.com/dexon-foundation/dexon/rlp"
"github.com/shopspring/decimal"
"github.com/stretchr/testify/suite"
+
+ "github.com/dexon-foundation/dexon/core/vm/sqlvm/ast"
+ "github.com/dexon-foundation/dexon/core/vm/sqlvm/errors"
+ "github.com/dexon-foundation/dexon/rlp"
)
type SchemaTestSuite struct{ suite.Suite }
@@ -122,6 +124,189 @@ func (s *SchemaTestSuite) TestEncodeAndDecodeSchema() {
}
}
+func (s *SchemaTestSuite) TestGetFieldType() {
+ type testCase struct {
+ fields []uint8
+ table *Table
+ expectedTypes []ast.DataType
+ expectedLenth int
+ expectedErr error
+ }
+ testCases := []testCase{
+ {
+ fields: []uint8{uint8(1), uint8(0)},
+ table: &Table{
+ Name: []byte("Table_A"),
+ Columns: []Column{
+ {
+ column{
+ Type: ast.ComposeDataType(ast.DataTypeMajorBool, 0),
+ },
+ nil,
+ },
+ {
+ column{
+ Type: ast.ComposeDataType(ast.DataTypeMajorUint, 7),
+ },
+ nil,
+ },
+ },
+ },
+ expectedTypes: []ast.DataType{
+ ast.ComposeDataType(ast.DataTypeMajorUint, 7),
+ ast.ComposeDataType(ast.DataTypeMajorBool, 0),
+ },
+ expectedLenth: 2,
+ expectedErr: nil,
+ },
+ {
+ fields: []uint8{uint8(8)},
+ table: &Table{
+ Name: []byte("Table_B"),
+ },
+ expectedLenth: 0,
+ expectedErr: errors.ErrorCodeIndexOutOfRange,
+ },
+ }
+ for _, t := range testCases {
+ length := t.expectedLenth
+ expectedErr := t.expectedErr
+ types, err := t.table.GetFieldType(t.fields)
+ s.Require().Equal(length, len(types))
+ s.Require().Equal(expectedErr, err)
+ for i, tt := range types {
+ s.Require().Equal(t.expectedTypes[i], tt)
+ }
+ }
+}
+
+func (s *SchemaTestSuite) TestSetupColumnOffset() {
+ type testCase struct {
+ name string
+ table *Table
+ expectedSlotOffest []uint8
+ expectedByteOffset []uint8
+ }
+ testCases := []testCase{
+ {
+ name: "Table_A",
+ table: &Table{
+ Columns: []Column{
+ {
+ column{
+ Type: ast.ComposeDataType(ast.DataTypeMajorBool, 0),
+ },
+ nil,
+ },
+ {
+ column{
+ Type: ast.ComposeDataType(ast.DataTypeMajorUint, 7),
+ },
+ nil,
+ },
+ },
+ },
+ expectedByteOffset: []uint8{0, 1},
+ expectedSlotOffest: []uint8{0, 0},
+ },
+ {
+ name: "Table_B",
+ table: &Table{
+ Columns: []Column{
+ {
+ column{
+ Type: ast.ComposeDataType(ast.DataTypeMajorBool, 0),
+ },
+ nil,
+ },
+ {
+ column{
+ Type: ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0),
+ },
+ nil,
+ },
+ {
+ column{
+ Type: ast.ComposeDataType(ast.DataTypeMajorBool, 0),
+ },
+ nil,
+ },
+ {
+ column{
+ Type: ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0),
+ },
+ nil,
+ },
+ },
+ },
+ expectedByteOffset: []uint8{0, 0, 0, 0},
+ expectedSlotOffest: []uint8{0, 1, 2, 3},
+ },
+ {
+ name: "Table_C",
+ table: &Table{
+ Columns: []Column{
+ {
+ column{
+ Type: ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0),
+ },
+ nil,
+ },
+ {
+ column{
+ Type: ast.ComposeDataType(ast.DataTypeMajorUint, 7),
+ },
+ nil,
+ },
+ {
+ column{
+ Type: ast.ComposeDataType(ast.DataTypeMajorUint, 7),
+ },
+ nil,
+ },
+ {
+ column{
+ Type: ast.ComposeDataType(ast.DataTypeMajorUint, 15),
+ },
+ nil,
+ },
+ {
+ column{
+ Type: ast.ComposeDataType(ast.DataTypeMajorFixedBytes, 30),
+ },
+ nil,
+ },
+ {
+ column{
+ Type: ast.ComposeDataType(ast.DataTypeMajorBool, 0),
+ },
+ nil,
+ },
+ {
+ column{
+ Type: ast.ComposeDataType(ast.DataTypeMajorFixedBytes, 31),
+ },
+ nil,
+ },
+ },
+ },
+ expectedByteOffset: []uint8{0, 0, 8, 16, 0, 31, 0},
+ expectedSlotOffest: []uint8{0, 1, 1, 1, 2, 2, 3},
+ },
+ }
+ for i, t := range testCases {
+ testCases[i].table.SetupColumnOffset()
+ shift := 0
+ for _, c := range testCases[i].table.Columns {
+ s.Require().Equalf(t.expectedSlotOffest[shift],
+ c.SlotOffset, "slotOffset not match. Name: %v, shift: %v", t.name, shift)
+ s.Require().Equalf(t.expectedByteOffset[shift],
+ c.ByteOffset, "byteOffset not match: Name: %v, shift: %v", t.name, shift)
+ shift++
+ }
+ }
+}
+
func TestSchema(t *testing.T) {
suite.Run(t, new(SchemaTestSuite))
}