aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm/sqlvm/schema/schema.go
blob: 638b858179d26c7a3416680d58f73ba52a7fa7e4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
package schema

import (
    "errors"
    "io"

    "github.com/shopspring/decimal"

    "github.com/dexon-foundation/dexon/core/vm/sqlvm/ast"
    "github.com/dexon-foundation/dexon/rlp"
)

// Error defines for encode and decode.
var (
    ErrEncodeUnexpectedType = errors.New("encode unexpected type")
    ErrDecodeUnexpectedType = errors.New("decode unexpected type")
)

// ColumnAttr defines bit flags for describing column attribute.
type ColumnAttr uint16

const (
    // ColumnAttrPrimaryKey is a no-op. Primary key constraints are converted
    // to a unique index during contract creation.
    ColumnAttrPrimaryKey ColumnAttr = 1 << iota
    // ColumnAttrNotNull is a no-op. We have not supported NULL values so all
    // columns are implicitly non-null.
    ColumnAttrNotNull
    // ColumnAttrUnique is a no-op. Unique constraints are converted to unique
    // indices during contract creation.
    ColumnAttrUnique
    // ColumnAttrHasDefault indicates whether a column has a default value. The
    // default value does not affect the starting value of AUTOINCREMENT.
    ColumnAttrHasDefault
    // ColumnAttrHasForeignKey indicates whether a column references a column
    // on a different table.
    ColumnAttrHasForeignKey
    // ColumnAttrHasSequence indicates whether a column is declared with
    // AUTOINCREMENT. It is only valid on integer fields.
    ColumnAttrHasSequence
)

// TableRef defines the type for table index in Schema.
type TableRef uint8

// ColumnRef defines the type for column index in Table.Columns.
type ColumnRef uint8

// IndexRef defines the type for array index of Column.Indices.
type IndexRef uint8

// SequenceRef defines the type for sequence index in Table.
type SequenceRef uint8

// IndexAttr defines bit flags for describing index attribute.
type IndexAttr uint16

const (
    // IndexAttrUnique indicates whether an index is unique.
    IndexAttrUnique IndexAttr = 1 << iota
)

// Schema defines sqlvm schema struct.
type Schema []Table

// Table defiens sqlvm table struct.
type Table struct {
    Name    []byte
    Columns []Column
    Indices []Index
}

// Index defines sqlvm index struct.
type Index struct {
    Name    []byte
    Attr    IndexAttr
    Columns []ColumnRef // Columns must be sorted in ascending order.
}

type column struct {
    Name          []byte
    Type          ast.DataType
    Attr          ColumnAttr
    ForeignTable  TableRef
    ForeignColumn ColumnRef
    Sequence      SequenceRef
    Rest          interface{}
}

// Column defines sqlvm index struct.
type Column struct {
    column
    Default interface{} // decimal.Decimal, bool, []byte
}

var _ rlp.Decoder = (*Column)(nil)
var _ rlp.Encoder = Column{}

// EncodeRLP encodes column with rlp encode.
func (c Column) EncodeRLP(w io.Writer) error {
    if c.Default != nil {
        switch d := c.Default.(type) {
        case bool:
            v := byte(0)
            if d {
                v = byte(1)
            }
            c.Rest = []byte{v}
        case []byte:
            c.Rest = d
        case decimal.Decimal:
            var err error
            c.Rest, err = ast.DecimalEncode(c.Type, d)
            if err != nil {
                return err
            }
        default:
            return ErrEncodeUnexpectedType
        }
    } else {
        c.Rest = nil
    }

    return rlp.Encode(w, c.column)
}

// DecodeRLP decodes column with rlp decode.
func (c *Column) DecodeRLP(s *rlp.Stream) error {
    defer func() { c.Rest = nil }()

    err := s.Decode(&c.column)
    if err != nil {
        return err
    }

    switch rest := c.Rest.(type) {
    case []interface{}:
        // nil is converted to empty list by encoder, while empty list is
        // converted to []interface{} by decoder.
        // So we view this case as nil and skip it.
    case []byte:
        major, _ := ast.DecomposeDataType(c.Type)
        switch major {
        case ast.DataTypeMajorBool:
            if rest[0] == 1 {
                c.Default = true
            } else {
                c.Default = false
            }
        case ast.DataTypeMajorFixedBytes, ast.DataTypeMajorDynamicBytes:
            c.Default = rest
        default:
            d, err := ast.DecimalDecode(c.Type, rest)
            if err != nil {
                return err
            }
            c.Default = d
        }
    default:
        return ErrDecodeUnexpectedType
    }

    return nil
}