This repository was archived by the owner on Jan 28, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 109
/
Copy pathcore.go
310 lines (272 loc) · 9.45 KB
/
core.go
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
package sql
import (
"fmt"
"io"
"math"
"strconv"
"time"
"gopkg.in/src-d/go-errors.v1"
)
var (
// ErrInvalidType is thrown when there is an unexpected type at some part of
// the execution tree.
ErrInvalidType = errors.NewKind("invalid type: %s")
// ErrTableAlreadyExists is thrown when someone tries to create a
// table with a name of an existing one
ErrTableAlreadyExists = errors.NewKind("table with name %s already exists")
// ErrTableNotFound is returned when the table is not available from the
// current scope.
ErrTableNotFound = errors.NewKind("table not found: %s")
//ErrUnexpectedRowLength is thrown when the obtained row has more columns than the schema
ErrUnexpectedRowLength = errors.NewKind("expected %d values, got %d")
// ErrInvalidChildrenNumber is returned when the WithChildren method of a
// node or expression is called with an invalid number of arguments.
ErrInvalidChildrenNumber = errors.NewKind("%T: invalid children number, got %d, expected %d")
// ErrDeleteRowNotFound
ErrDeleteRowNotFound = errors.NewKind("row was not found when attempting to delete").New()
)
// Nameable is something that has a name.
type Nameable interface {
// Name returns the name.
Name() string
}
// Tableable is something that has a table.
type Tableable interface {
// Table returns the table name.
Table() string
}
// Resolvable is something that can be resolved or not.
type Resolvable interface {
// Resolved returns whether the node is resolved.
Resolved() bool
}
// TransformNodeFunc is a function that given a node will return that node
// as is or transformed along with an error, if any.
type TransformNodeFunc func(Node) (Node, error)
// TransformExprFunc is a function that given an expression will return that
// expression as is or transformed along with an error, if any.
type TransformExprFunc func(Expression) (Expression, error)
// Expression is a combination of one or more SQL expressions.
type Expression interface {
Resolvable
fmt.Stringer
// Type returns the expression type.
Type() Type
// IsNullable returns whether the expression can be null.
IsNullable() bool
// Eval evaluates the given row and returns a result.
Eval(*Context, Row) (interface{}, error)
// Children returns the children expressions of this expression.
Children() []Expression
// WithChildren returns a copy of the expression with children replaced.
// It will return an error if the number of children is different than
// the current number of children. They must be given in the same order
// as they are returned by Children.
WithChildren(...Expression) (Expression, error)
}
// Aggregation implements an aggregation expression, where an
// aggregation buffer is created for each grouping (NewBuffer) and rows in the
// grouping are fed to the buffer (Update). Multiple buffers can be merged
// (Merge), making partial aggregations possible.
// Note that Eval must be called with the final aggregation buffer in order to
// get the final result.
type Aggregation interface {
Expression
// NewBuffer creates a new aggregation buffer and returns it as a Row.
NewBuffer() Row
// Update updates the given buffer with the given row.
Update(ctx *Context, buffer, row Row) error
// Merge merges a partial buffer into a global one.
Merge(ctx *Context, buffer, partial Row) error
}
// Node is a node in the execution plan tree.
type Node interface {
Resolvable
fmt.Stringer
// Schema of the node.
Schema() Schema
// Children nodes.
Children() []Node
// RowIter produces a row iterator from this node.
RowIter(*Context) (RowIter, error)
// WithChildren returns a copy of the node with children replaced.
// It will return an error if the number of children is different than
// the current number of children. They must be given in the same order
// as they are returned by Children.
WithChildren(...Node) (Node, error)
}
// OpaqueNode is a node that doesn't allow transformations to its children and
// acts a a black box.
type OpaqueNode interface {
Node
// Opaque reports whether the node is opaque or not.
Opaque() bool
}
// AsyncNode is a node that can be executed asynchronously.
type AsyncNode interface {
// IsAsync reports whether the node is async or not.
IsAsync() bool
}
// Expressioner is a node that contains expressions.
type Expressioner interface {
// Expressions returns the list of expressions contained by the node.
Expressions() []Expression
// WithExpressions returns a copy of the node with expressions replaced.
// It will return an error if the number of expressions is different than
// the current number of expressions. They must be given in the same order
// as they are returned by Expressions.
WithExpressions(...Expression) (Node, error)
}
// Databaser is a node that contains a reference to a database.
type Databaser interface {
// Database the current database.
Database() Database
// WithDatabase returns a new node instance with the database replaced with
// the one given as parameter.
WithDatabase(Database) (Node, error)
}
// Partition represents a partition from a SQL table.
type Partition interface {
Key() []byte
}
// PartitionIter is an iterator that retrieves partitions.
type PartitionIter interface {
io.Closer
Next() (Partition, error)
}
// Table represents the backend of a SQL table.
type Table interface {
Nameable
String() string
Schema() Schema
Partitions(*Context) (PartitionIter, error)
PartitionRows(*Context, Partition) (RowIter, error)
}
// TableWrapper is a node that wraps the real table. This is needed because
// wrappers cannot implement some methods the table may implement.
type TableWrapper interface {
// Underlying returns the underlying table.
Underlying() Table
}
// PartitionCounter can return the number of partitions.
type PartitionCounter interface {
// PartitionCount returns the number of partitions.
PartitionCount(*Context) (int64, error)
}
//FilteredTable is a table that can produce a specific RowIter
// that's more optimized given the filters.
type FilteredTable interface {
Table
HandledFilters(filters []Expression) []Expression
WithFilters(filters []Expression) Table
Filters() []Expression
}
// ProjectedTable is a table that can produce a specific RowIter
// that's more optimized given the columns that are projected.
type ProjectedTable interface {
Table
WithProjection(colNames []string) Table
Projection() []string
}
// IndexableTable represents a table that supports being indexed and
// receiving indexes to be able to speed up its execution.
type IndexableTable interface {
Table
WithIndexLookup(IndexLookup) Table
IndexLookup() IndexLookup
IndexKeyValues(*Context, []string) (PartitionIndexKeyValueIter, error)
}
// Inserter allow rows to be inserted in them.
type Inserter interface {
// Insert the given row.
Insert(*Context, Row) error
}
// Deleter allow rows to be deleted from tables.
type Deleter interface {
// Delete the given row. Returns ErrDeleteRowNotFound if the row was not found.
Delete(*Context, Row) error
}
// Replacer allows rows to be replaced through a Delete (if applicable) then Insert.
type Replacer interface {
Deleter
Inserter
}
// Updater allows rows to be updated.
type Updater interface {
// Update the given row. Provides both the old and new rows.
Update(ctx *Context, old Row, new Row) error
}
// Database represents the database.
type Database interface {
Nameable
// Tables returns the information of all tables.
Tables() map[string]Table
}
// TableCreator should be implemented by databases that can create new tables.
type TableCreator interface {
CreateTable(ctx *Context, name string, schema Schema) error
}
// TableDropper should be implemented by databases that can drop tables.
type TableDropper interface {
DropTable(ctx *Context, name string) error
}
// Lockable should be implemented by tables that can be locked and unlocked.
type Lockable interface {
Nameable
// Lock locks the table either for reads or writes. Any session clients can
// read while the table is locked for read, but not write.
// When the table is locked for write, nobody can write except for the
// session client that requested the lock.
Lock(ctx *Context, write bool) error
// Unlock releases the lock for the current session client. It blocks until
// all reads or writes started during the lock are finished.
// Context may be nil if the unlock it's because the connection was closed.
// The id will always be provided, since in some cases context is not
// available.
Unlock(ctx *Context, id uint32) error
}
// EvaluateCondition evaluates a condition, which is an expression whose value
// will be coerced to boolean.
func EvaluateCondition(ctx *Context, cond Expression, row Row) (bool, error) {
v, err := cond.Eval(ctx, row)
if err != nil {
return false, err
}
switch b := v.(type) {
case bool:
return b, nil
case int:
return b != int(0), nil
case int64:
return b != int64(0), nil
case int32:
return b != int32(0), nil
case int16:
return b != int16(0), nil
case int8:
return b != int8(0), nil
case uint:
return b != uint(0), nil
case uint64:
return b != uint64(0), nil
case uint32:
return b != uint32(0), nil
case uint16:
return b != uint16(0), nil
case uint8:
return b != uint8(0), nil
case time.Duration:
return int64(b) != 0, nil
case time.Time:
return b.UnixNano() != 0, nil
case float64:
return int(math.Round(v.(float64))) != 0, nil
case float32:
return int(math.Round(float64(v.(float32)))) != 0, nil
case string:
parsed, err := strconv.ParseFloat(v.(string), 64)
return err == nil && int(parsed) != 0, nil
default:
return false, nil
}
}