github.com/dolthub/go-mysql-server@v0.18.0/sql/core.go (about) 1 // Copyright 2020-2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package sql 16 17 import ( 18 "fmt" 19 "strconv" 20 "time" 21 22 "github.com/shopspring/decimal" 23 ) 24 25 // Expression is a combination of one or more SQL expressions. 26 type Expression interface { 27 Resolvable 28 fmt.Stringer 29 // Type returns the expression type. 30 Type() Type 31 // IsNullable returns whether the expression can be null. 32 IsNullable() bool 33 // Eval evaluates the given row and returns a result. 34 Eval(ctx *Context, row Row) (interface{}, error) 35 // Children returns the children expressions of this expression. 36 Children() []Expression 37 // WithChildren returns a copy of the expression with children replaced. 38 // It will return an error if the number of children is different than 39 // the current number of children. They must be given in the same order 40 // as they are returned by Children. 41 WithChildren(children ...Expression) (Expression, error) 42 } 43 44 // ExpressionWithNodes is an expression that contains nodes as children. 45 type ExpressionWithNodes interface { 46 Expression 47 // NodeChildren returns all node children. 48 NodeChildren() []Node 49 // WithNodeChildren returns a copy of the expression with its node children replaced. It will return an error if the 50 // number of children is different than the current number of children. They must be given in the same order as they 51 // are returned by NodeChildren. 52 WithNodeChildren(children ...Node) (ExpressionWithNodes, error) 53 } 54 55 // NonDeterministicExpression allows a way for expressions to declare that they are non-deterministic, which will 56 // signal the engine to not cache their results when this would otherwise appear to be safe. 57 type NonDeterministicExpression interface { 58 Expression 59 // IsNonDeterministic returns whether this expression returns a non-deterministic result. An expression is 60 // non-deterministic if it can return different results on subsequent evaluations. 61 IsNonDeterministic() bool 62 } 63 64 // Node is a node in the execution plan tree. 65 type Node interface { 66 Resolvable 67 fmt.Stringer 68 // Schema of the node. 69 Schema() Schema 70 // Children nodes. 71 Children() []Node 72 // WithChildren returns a copy of the node with children replaced. 73 // It will return an error if the number of children is different than 74 // the current number of children. They must be given in the same order 75 // as they are returned by Children. 76 WithChildren(children ...Node) (Node, error) 77 // CheckPrivileges passes the operations representative of this Node to the PrivilegedOperationChecker to determine 78 // whether a user (contained in the context, along with their active roles) has the necessary privileges to execute 79 // this node (and its children). 80 CheckPrivileges(ctx *Context, opChecker PrivilegedOperationChecker) bool 81 82 IsReadOnly() bool 83 } 84 85 // NodeExecBuilder converts a sql.Node tree into a RowIter. 86 type NodeExecBuilder interface { 87 Build(ctx *Context, n Node, r Row) (RowIter, error) 88 } 89 90 // ExecSourceRel is a node that has no children and is directly 91 // row generating. 92 type ExecSourceRel interface { 93 Node 94 RowIter(ctx *Context, r Row) (RowIter, error) 95 } 96 97 // Nameable is something that has a name. 98 type Nameable interface { 99 // Name returns the name. 100 Name() string 101 } 102 103 // RenameableNode is a Node that can be renamed. 104 type RenameableNode interface { 105 Nameable 106 Node 107 // WithName returns a copy of the node with the name changed. 108 WithName(string) Node 109 } 110 111 // Tableable is something that has a table. 112 type Tableable interface { 113 // Table returns the table name. 114 Table() string 115 } 116 117 // Resolvable is something that can be resolved or not. 118 type Resolvable interface { 119 // Resolved returns whether the node is resolved. 120 Resolved() bool 121 } 122 123 // BinaryNode is a Node with two children 124 type BinaryNode interface { 125 Left() Node 126 Right() Node 127 } 128 129 // UnaryNode is a Node with one child. 130 type UnaryNode interface { 131 Child() Node 132 } 133 134 // CommentedNode allows comments to be set and retrieved on it. Used primarily for join hint comments. 135 type CommentedNode interface { 136 Node 137 WithComment(string) Node 138 Comment() string 139 } 140 141 // OpaqueNode is a node that doesn't allow transformations to its children and 142 // acts as a black box. 143 type OpaqueNode interface { 144 Node 145 // Opaque reports whether the node is opaque or not. 146 Opaque() bool 147 } 148 149 // Projector is a node that projects expressions for parent nodes to consume (i.e. GroupBy, Window, Project). 150 type Projector interface { 151 // ProjectedExprs returns the list of expressions projected by this node. 152 ProjectedExprs() []Expression 153 } 154 155 // Expressioner is a node that contains expressions. 156 type Expressioner interface { 157 // Expressions returns the list of expressions contained by the node. 158 Expressions() []Expression 159 // WithExpressions returns a copy of the node with expressions replaced. 160 // It will return an error if the number of expressions is different than 161 // the current number of expressions. They must be given in the same order 162 // as they are returned by Expressions. 163 WithExpressions(...Expression) (Node, error) 164 } 165 166 // SchemaTarget is a node that has a target schema that can be set during analysis. This is necessary because some 167 // schema objects (things that involve expressions, column references, etc.) can only be reified during analysis. The 168 // target schema is the schema of a table under a DDL operation, not the schema of rows returned by this node. 169 type SchemaTarget interface { 170 // WithTargetSchema returns a copy of this node with the target schema set 171 WithTargetSchema(Schema) (Node, error) 172 // TargetSchema returns the target schema for this node 173 TargetSchema() Schema 174 } 175 176 // PrimaryKeySchemaTarget is a node that has a primary key target schema that can be set 177 type PrimaryKeySchemaTarget interface { 178 SchemaTarget 179 WithPrimaryKeySchema(schema PrimaryKeySchema) (Node, error) 180 } 181 182 // DynamicColumnsTable is a table with a schema that is variable depending 183 // on the tables in the database (information_schema.columns). 184 type DynamicColumnsTable interface { 185 // AllColumns returns all columns that need to be resolved 186 // for this particular table. 187 AllColumns(*Context) (Schema, error) 188 // WithDefaultsSchema returns a table with a fully resolved 189 // schema for every column in AllColumns. 190 WithDefaultsSchema(Schema) (Table, error) 191 // HasDynamicColumns indicates that a type implements the 192 // DynamicColumnsTable interface. 193 HasDynamicColumns() bool 194 } 195 196 // PartitionCounter can return the number of partitions. 197 type PartitionCounter interface { 198 // PartitionCount returns the number of partitions. 199 PartitionCount(*Context) (int64, error) 200 } 201 202 // Closer is a node that can be closed. 203 type Closer interface { 204 Close(*Context) error 205 } 206 207 // ExternalStoredProcedureProvider provides access to built-in stored procedures. These procedures are implemented 208 // as functions, instead of as SQL statements. The returned stored procedures cannot be modified or deleted. 209 type ExternalStoredProcedureProvider interface { 210 // ExternalStoredProcedure returns the external stored procedure details for the procedure with the specified name 211 // that is able to accept the specified number of parameters. If no matching external stored procedure is found, 212 // nil, nil is returned. If an unexpected error is encountered, it is returned as the error parameter. 213 ExternalStoredProcedure(ctx *Context, name string, numOfParams int) (*ExternalStoredProcedureDetails, error) 214 // ExternalStoredProcedures returns a slice of all external stored procedure details with the specified name. External 215 // stored procedures can overload the same name with different arguments, so this method enables a caller to see all 216 // available variants with the specified name. If no matching external stored procedures are found, an 217 // empty slice is returned, with a nil error. If an unexpected error is encountered, it is returned as the 218 // error parameter. 219 ExternalStoredProcedures(ctx *Context, name string) ([]ExternalStoredProcedureDetails, error) 220 } 221 222 type TransactionCharacteristic int 223 224 const ( 225 ReadWrite TransactionCharacteristic = iota 226 ReadOnly 227 ) 228 229 // Transaction is an opaque type implemented by an integrator to record necessary information at the start of a 230 // transaction. Active transactions will be recorded in the session. 231 type Transaction interface { 232 fmt.Stringer 233 IsReadOnly() bool 234 } 235 236 // Lockable should be implemented by tables that can be locked and unlocked. 237 type Lockable interface { 238 Nameable 239 // Lock locks the table either for reads or writes. Any session clients can 240 // read while the table is locked for read, but not write. 241 // When the table is locked for write, nobody can write except for the 242 // session client that requested the lock. 243 Lock(ctx *Context, write bool) error 244 // Unlock releases the lock for the current session client. It blocks until 245 // all reads or writes started during the lock are finished. 246 // Context may be nil if the unlock it's because the connection was closed. 247 // The id will always be provided, since in some cases context is not 248 // available. 249 Unlock(ctx *Context, id uint32) error 250 } 251 252 // ConvertToBool converts a value to a boolean. nil is considered false. 253 func ConvertToBool(ctx *Context, v interface{}) (bool, error) { 254 switch b := v.(type) { 255 case []uint8: 256 return ConvertToBool(ctx, string(b)) 257 case bool: 258 return b, nil 259 case int: 260 return b != 0, nil 261 case int64: 262 return b != 0, nil 263 case int32: 264 return b != 0, nil 265 case int16: 266 return b != 0, nil 267 case int8: 268 return b != 0, nil 269 case uint: 270 return b != 0, nil 271 case uint64: 272 return b != 0, nil 273 case uint32: 274 return b != 0, nil 275 case uint16: 276 return b != 0, nil 277 case uint8: 278 return b != 0, nil 279 case time.Duration: 280 return b != 0, nil 281 case time.Time: 282 return b.UnixNano() != 0, nil 283 case float32: 284 return b != 0, nil 285 case float64: 286 return b != 0, nil 287 case string: 288 bFloat, err := strconv.ParseFloat(b, 64) 289 if err != nil { 290 // In MySQL, if the string does not represent a float then it's false 291 ctx.Warn(1292, "Truncated incorrect DOUBLE value: '%s'", b) 292 return false, nil 293 } 294 return bFloat != 0, nil 295 case decimal.Decimal: 296 return !b.IsZero(), nil 297 case nil: 298 return false, fmt.Errorf("unable to cast nil to bool") 299 default: 300 return false, fmt.Errorf("unable to cast %#v of type %T to bool", v, v) 301 } 302 } 303 304 // EvaluateCondition evaluates a condition, which is an expression whose value 305 // will be nil or coerced boolean. 306 func EvaluateCondition(ctx *Context, cond Expression, row Row) (interface{}, error) { 307 v, err := cond.Eval(ctx, row) 308 if err != nil { 309 return false, err 310 } 311 if v == nil { 312 return nil, nil 313 } 314 res, err := ConvertToBool(ctx, v) 315 if err != nil { 316 return nil, err 317 } 318 return res, nil 319 } 320 321 // IsFalse coerces EvaluateCondition interface{} response to boolean 322 func IsFalse(val interface{}) bool { 323 res, ok := val.(bool) 324 return ok && !res 325 } 326 327 // IsTrue coerces EvaluateCondition interface{} response to boolean 328 func IsTrue(val interface{}) bool { 329 res, ok := val.(bool) 330 return ok && res 331 } 332 333 // DebugStringer is shared by implementors of Node and Expression, and is used for debugging the analyzer. It allows 334 // a node or expression to be printed in greater detail than its default String() representation. 335 type DebugStringer interface { 336 // DebugString prints a debug string of the node in question. 337 DebugString() string 338 } 339 340 // DebugString returns a debug string for the Node or Expression given. 341 func DebugString(nodeOrExpression interface{}) string { 342 if ds, ok := nodeOrExpression.(DebugStringer); ok { 343 return ds.DebugString() 344 } 345 if s, ok := nodeOrExpression.(fmt.Stringer); ok { 346 return s.String() 347 } 348 panic(fmt.Sprintf("Expected sql.DebugString or fmt.Stringer for %T", nodeOrExpression)) 349 } 350 351 // Expression2 is an experimental future interface alternative to Expression to provide faster access. 352 type Expression2 interface { 353 Expression 354 // Eval2 evaluates the given row frame and returns a result. 355 Eval2(ctx *Context, row Row2) (Value, error) 356 // Type2 returns the expression type. 357 Type2() Type2 358 } 359 360 var SystemVariables SystemVariableRegistry 361 362 // SystemVariableRegistry is a registry of system variables. Each session gets its own copy of all values via the 363 // SessionMap() method. 364 type SystemVariableRegistry interface { 365 // AddSystemVariables adds the given system variables to this registry 366 AddSystemVariables(sysVars []SystemVariable) 367 // AssignValues assigns the given values to the system variables in this registry 368 AssignValues(vals map[string]interface{}) error 369 // NewSessionMap returns a map of system variables values that can be used by a session 370 NewSessionMap() map[string]SystemVarValue 371 // GetGlobal returns the global value of the system variable with the given name 372 GetGlobal(name string) (SystemVariable, interface{}, bool) 373 // SetGlobal sets the global value of the system variable with the given name 374 SetGlobal(name string, val interface{}) error 375 // GetAllGlobalVariables returns a copy of all global variable values. 376 GetAllGlobalVariables() map[string]interface{} 377 } 378 379 // SystemVariable represents a system variable. 380 type SystemVariable struct { 381 // Name is the name of the system variable. 382 Name string 383 // Scope defines the scope of the system variable, which is either Global, Session, or Both. 384 Scope SystemVariableScope 385 // Dynamic defines whether the variable may be written to during runtime. Variables with this set to `false` will 386 // return an error if a user attempts to set a value. 387 Dynamic bool 388 // SetVarHintApplies defines if the variable may be set for a single query using SET_VAR(). 389 // https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-set-var 390 SetVarHintApplies bool 391 // Type defines the type of the system variable. This may be a special type not accessible to standard MySQL operations. 392 Type Type 393 // Default defines the default value of the system variable. 394 Default interface{} 395 // NotifyChanged is called by the engine if the value of this variable 396 // changes during runtime. It is typically |nil|, but can be used for 397 // system variables which control the behavior of the running server. 398 // For example, replication threads might need to be started or stopped 399 // when replication is enabled or disabled. This provides a scalable 400 // alternative to polling. 401 // 402 // Calls to NotifyChanged are serialized for a given system variable in 403 // the global context and in a particular session. They should never 404 // block. NotifyChanged is not called when a new system variable is 405 // registered. 406 NotifyChanged func(SystemVariableScope, SystemVarValue) error 407 // ValueFunction defines an optional function that is executed to provide 408 // the value of this system variable whenever it is requested. System variables 409 // that provide a ValueFunction should also set Dynamic to false, since they 410 // cannot be assigned a value and will return a read-only error if tried. 411 ValueFunction func() (interface{}, error) 412 } 413 414 // SystemVariableScope represents the scope of a system variable. 415 type SystemVariableScope byte 416 417 const ( 418 // SystemVariableScope_Global is set when the system variable exists only in the global context. 419 SystemVariableScope_Global SystemVariableScope = iota 420 // SystemVariableScope_Session is set when the system variable exists only in the session context. 421 SystemVariableScope_Session 422 // SystemVariableScope_Both is set when the system variable exists in both the global and session contexts. 423 SystemVariableScope_Both 424 // SystemVariableScope_Persist is set when the system variable is global and persisted. 425 SystemVariableScope_Persist 426 // SystemVariableScope_PersistOnly is set when the system variable is persisted outside of server context. 427 SystemVariableScope_PersistOnly 428 // SystemVariableScope_ResetPersist is used to remove a persisted variable 429 SystemVariableScope_ResetPersist 430 ) 431 432 // String returns the scope as an uppercase string. 433 func (s SystemVariableScope) String() string { 434 switch s { 435 case SystemVariableScope_Global: 436 return "GLOBAL" 437 case SystemVariableScope_Session: 438 return "SESSION" 439 case SystemVariableScope_Persist: 440 return "GLOBAL, PERSIST" 441 case SystemVariableScope_PersistOnly: 442 return "PERSIST" 443 case SystemVariableScope_ResetPersist: 444 return "RESET PERSIST" 445 case SystemVariableScope_Both: 446 return "GLOBAL, SESSION" 447 default: 448 return "UNKNOWN_SYSTEM_SCOPE" 449 } 450 } 451 452 type SystemVarValue struct { 453 Var SystemVariable 454 Val interface{} 455 } 456 457 type NameableNode interface { 458 Nameable 459 Node 460 }