forked from dolthub/go-mysql-server
-
Notifications
You must be signed in to change notification settings - Fork 0
/
core.go
401 lines (360 loc) · 14.6 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
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
// Copyright 2020-2021 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sql
import (
"fmt"
"math"
"strconv"
"time"
)
// 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(ctx *Context, row 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(children ...Expression) (Expression, error)
}
// ExpressionWithNodes is an expression that contains nodes as children.
type ExpressionWithNodes interface {
Expression
// NodeChildren returns all node children.
NodeChildren() []Node
// WithNodeChildren returns a copy of the expression with its node 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 NodeChildren.
WithNodeChildren(children ...Node) (ExpressionWithNodes, error)
}
// NonDeterministicExpression allows a way for expressions to declare that they are non-deterministic, which will
// signal the engine to not cache their results when this would otherwise appear to be safe.
type NonDeterministicExpression interface {
Expression
// IsNonDeterministic returns whether this expression returns a non-deterministic result. An expression is
// non-deterministic if it can return different results on subsequent evaluations.
IsNonDeterministic() bool
}
// 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. The current row being evaluated is provided, as well the context
// of the query.
RowIter(ctx *Context, row Row) (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(children ...Node) (Node, error)
// CheckPrivileges passes the operations representative of this Node to the PrivilegedOperationChecker to determine
// whether a user (contained in the context, along with their active roles) has the necessary privileges to execute
// this node (and its children).
CheckPrivileges(ctx *Context, opChecker PrivilegedOperationChecker) bool
}
// 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
}
// BinaryNode is a Node with two children
type BinaryNode interface {
Left() Node
Right() Node
}
// UnaryNode is a Node with one child.
type UnaryNode interface {
Child() Node
}
// CommentedNode allows comments to be set and retrieved on it. Used primarily for join hint comments.
type CommentedNode interface {
Node
WithComment(string) Node
Comment() string
}
// OpaqueNode is a node that doesn't allow transformations to its children and
// acts as a black box.
type OpaqueNode interface {
Node
// Opaque reports whether the node is opaque or not.
Opaque() bool
}
// Projector is a node that projects expressions for parent nodes to consume (i.e. GroupBy, Window, Project).
type Projector interface {
// ProjectedExprs returns the list of expressions projected by this node.
ProjectedExprs() []Expression
// WithProjectedExprs returns a new Projector instance with the specified expressions set as its projected expressions.
WithProjectedExprs(...Expression) (Projector, error)
}
// 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)
}
// SchemaTarget is a node that has a target schema that can be set during analysis. This is necessary because some
// schema objects (things that involve expressions, column references, etc.) can only be reified during analysis. The
// target schema is the schema of a table under a DDL operation, not the schema of rows returned by this node.
type SchemaTarget interface {
// WithTargetSchema returns a copy of this node with the target schema set
WithTargetSchema(Schema) (Node, error)
// TargetSchema returns the target schema for this node
TargetSchema() Schema
}
// PrimaryKeySchemaTarget is a node that has a primary key target schema that can be set
type PrimaryKeySchemaTarget interface {
SchemaTarget
WithPrimaryKeySchema(schema PrimaryKeySchema) (Node, error)
}
// PartitionCounter can return the number of partitions.
type PartitionCounter interface {
// PartitionCount returns the number of partitions.
PartitionCount(*Context) (int64, error)
}
// Closer is a node that can be closed.
type Closer interface {
Close(*Context) error
}
// ExternalStoredProcedureProvider provides access to built-in stored procedures. These procedures are implemented
// as functions, instead of as SQL statements. The returned stored procedures cannot be modified or deleted.
type ExternalStoredProcedureProvider interface {
// ExternalStoredProcedure returns the external stored procedure details for the procedure with the specified name
// that is able to accept the specified number of parameters. If no matching external stored procedure is found,
// nil, nil is returned. If an unexpected error is encountered, it is returned as the error parameter.
ExternalStoredProcedure(ctx *Context, name string, numOfParams int) (*ExternalStoredProcedureDetails, error)
// ExternalStoredProcedures returns a slice of all external stored procedure details with the specified name. External
// stored procedures can overload the same name with different arguments, so this method enables a caller to see all
// available variants with the specified name. If no matching external stored procedures are found, an
// empty slice is returned, with a nil error. If an unexpected error is encountered, it is returned as the
// error parameter.
ExternalStoredProcedures(ctx *Context, name string) ([]ExternalStoredProcedureDetails, error)
}
type TransactionCharacteristic int
const (
ReadWrite TransactionCharacteristic = iota
ReadOnly
)
// Transaction is an opaque type implemented by an integrator to record necessary information at the start of a
// transaction. Active transactions will be recorded in the session.
type Transaction interface {
fmt.Stringer
IsReadOnly() bool
}
// 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 nil or coerced boolean.
func EvaluateCondition(ctx *Context, cond Expression, row Row) (interface{}, error) {
v, err := cond.Eval(ctx, row)
if err != nil {
return false, err
}
if v == nil {
return nil, nil
}
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
}
}
// IsFalse coerces EvaluateCondition interface{} response to boolean
func IsFalse(val interface{}) bool {
res, ok := val.(bool)
return ok && !res
}
// IsTrue coerces EvaluateCondition interface{} response to boolean
func IsTrue(val interface{}) bool {
res, ok := val.(bool)
return ok && res
}
// DebugStringer is shared by implementors of Node and Expression, and is used for debugging the analyzer. It allows
// a node or expression to be printed in greater detail than its default String() representation.
type DebugStringer interface {
// DebugString prints a debug string of the node in question.
DebugString() string
}
// DebugString returns a debug string for the Node or Expression given.
func DebugString(nodeOrExpression interface{}) string {
if ds, ok := nodeOrExpression.(DebugStringer); ok {
return ds.DebugString()
}
if s, ok := nodeOrExpression.(fmt.Stringer); ok {
return s.String()
}
panic(fmt.Sprintf("Expected sql.DebugString or fmt.Stringer for %T", nodeOrExpression))
}
// Expression2 is an experimental future interface alternative to Expression to provide faster access.
type Expression2 interface {
Expression
// Eval2 evaluates the given row frame and returns a result.
Eval2(ctx *Context, row Row2) (Value, error)
// Type2 returns the expression type.
Type2() Type2
}
// Node2 is an experimental future interface alternative to Node to provide faster access.
type Node2 interface {
Node
// RowIter2 produces a row iterator from this node. The current row frame being
// evaluated is provided, as well the context of the query.
RowIter2(ctx *Context, f *RowFrame) (RowIter2, error)
}
var SystemVariables SystemVariableRegistry
// SystemVariableRegistry is a registry of system variables. Each session gets its own copy of all values via the
// SessionMap() method.
type SystemVariableRegistry interface {
// AddSystemVariables adds the given system variables to this registry
AddSystemVariables(sysVars []SystemVariable)
// AssignValues assigns the given values to the system variables in this registry
AssignValues(vals map[string]interface{}) error
// NewSessionMap returns a map of system variables values that can be used by a session
NewSessionMap() map[string]SystemVarValue
// GetGlobal returns the global value of the system variable with the given name
GetGlobal(name string) (SystemVariable, interface{}, bool)
// SetGlobal sets the global value of the system variable with the given name
SetGlobal(name string, val interface{}) error
// GetAllGlobalVariables returns a copy of all global variable values.
GetAllGlobalVariables() map[string]interface{}
}
// SystemVariable represents a system variable.
type SystemVariable struct {
// Name is the name of the system variable.
Name string
// Scope defines the scope of the system variable, which is either Global, Session, or Both.
Scope SystemVariableScope
// Dynamic defines whether the variable may be written to during runtime. Variables with this set to `false` will
// return an error if a user attempts to set a value.
Dynamic bool
// SetVarHintApplies defines if the variable may be set for a single query using SET_VAR().
// https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-set-var
SetVarHintApplies bool
// Type defines the type of the system variable. This may be a special type not accessible to standard MySQL operations.
Type Type
// Default defines the default value of the system variable.
Default interface{}
}
// SystemVariableScope represents the scope of a system variable.
type SystemVariableScope byte
const (
// SystemVariableScope_Global is set when the system variable exists only in the global context.
SystemVariableScope_Global SystemVariableScope = iota
// SystemVariableScope_Session is set when the system variable exists only in the session context.
SystemVariableScope_Session
// SystemVariableScope_Both is set when the system variable exists in both the global and session contexts.
SystemVariableScope_Both
// SystemVariableScope_Persist is set when the system variable is global and persisted.
SystemVariableScope_Persist
// SystemVariableScope_PersistOnly is set when the system variable is persisted outside of server context.
SystemVariableScope_PersistOnly
// SystemVariableScope_ResetPersist is used to remove a persisted variable
SystemVariableScope_ResetPersist
)
// String returns the scope as an uppercase string.
func (s SystemVariableScope) String() string {
switch s {
case SystemVariableScope_Global:
return "GLOBAL"
case SystemVariableScope_Session:
return "SESSION"
case SystemVariableScope_Persist:
return "GLOBAL, PERSIST"
case SystemVariableScope_PersistOnly:
return "PERSIST"
case SystemVariableScope_ResetPersist:
return "RESET PERSIST"
case SystemVariableScope_Both:
return "GLOBAL, SESSION"
default:
return "UNKNOWN_SYSTEM_SCOPE"
}
}
type SystemVarValue struct {
Var SystemVariable
Val interface{}
}
type NameableNode interface {
Nameable
Node
}