diff options
author | Jhih-Ming Huang <jm.huang@cobinhood.com> | 2019-03-15 17:39:20 +0800 |
---|---|---|
committer | Jhih-Ming Huang <jm.huang@cobinhood.com> | 2019-03-26 17:48:23 +0800 |
commit | ec427716b8d8419f0f4bb2761d1465bf8fc68ab7 (patch) | |
tree | 8ef68c848e330f04d98618d3e31f07fa3d930b0c | |
parent | 6d039362787332877704901fd393505544555f1b (diff) | |
download | dexon-ec427716b8d8419f0f4bb2761d1465bf8fc68ab7.tar.gz dexon-ec427716b8d8419f0f4bb2761d1465bf8fc68ab7.tar.zst dexon-ec427716b8d8419f0f4bb2761d1465bf8fc68ab7.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.go | 56 | ||||
-rw-r--r-- | core/vm/sqlvm/schema/schema_test.go | 189 |
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)) } |