aboutsummaryrefslogtreecommitdiffstats
path: root/core
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-03-26 17:48:23 +0800
commitec427716b8d8419f0f4bb2761d1465bf8fc68ab7 (patch)
tree8ef68c848e330f04d98618d3e31f07fa3d930b0c /core
parent6d039362787332877704901fd393505544555f1b (diff)
downloaddexon-ec427716b8d8419f0f4bb2761d1465bf8fc68ab7.tar
dexon-ec427716b8d8419f0f4bb2761d1465bf8fc68ab7.tar.gz
dexon-ec427716b8d8419f0f4bb2761d1465bf8fc68ab7.tar.bz2
dexon-ec427716b8d8419f0f4bb2761d1465bf8fc68ab7.tar.lz
dexon-ec427716b8d8419f0f4bb2761d1465bf8fc68ab7.tar.xz
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.
Diffstat (limited to 'core')
-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))
}