aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm/sqlvm/schema
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 /core/vm/sqlvm/schema
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.
Diffstat (limited to 'core/vm/sqlvm/schema')
-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))
}