github.com/dolthub/go-mysql-server@v0.18.0/engine.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 sqle 16 17 import ( 18 "fmt" 19 "os" 20 "strconv" 21 "strings" 22 "sync" 23 "sync/atomic" 24 25 "github.com/dolthub/vitess/go/sqltypes" 26 querypb "github.com/dolthub/vitess/go/vt/proto/query" 27 "github.com/dolthub/vitess/go/vt/sqlparser" 28 "github.com/pkg/errors" 29 30 "github.com/dolthub/go-mysql-server/eventscheduler" 31 "github.com/dolthub/go-mysql-server/sql" 32 "github.com/dolthub/go-mysql-server/sql/analyzer" 33 "github.com/dolthub/go-mysql-server/sql/expression" 34 "github.com/dolthub/go-mysql-server/sql/expression/function" 35 "github.com/dolthub/go-mysql-server/sql/plan" 36 "github.com/dolthub/go-mysql-server/sql/planbuilder" 37 "github.com/dolthub/go-mysql-server/sql/rowexec" 38 "github.com/dolthub/go-mysql-server/sql/transform" 39 "github.com/dolthub/go-mysql-server/sql/types" 40 _ "github.com/dolthub/go-mysql-server/sql/variables" 41 ) 42 43 const experimentalFlag = "GMS_EXPERIMENTAL" 44 45 var ExperimentalGMS bool 46 47 func init() { 48 ExperimentalGMS = os.Getenv(experimentalFlag) != "" 49 } 50 51 // Config for the Engine. 52 type Config struct { 53 // VersionPostfix to display with the `VERSION()` UDF. 54 VersionPostfix string 55 // IsReadOnly sets the engine to disallow modification queries. 56 IsReadOnly bool 57 IsServerLocked bool 58 // IncludeRootAccount adds the root account (with no password) to the list of accounts, and also enables 59 // authentication. 60 IncludeRootAccount bool 61 // TemporaryUsers adds any users that should be included when the engine is created. By default, authentication is 62 // disabled, and including any users here will enable authentication. All users in this list will have full access. 63 // This field is only temporary, and will be removed as development on users and authentication continues. 64 TemporaryUsers []TemporaryUser 65 } 66 67 // TemporaryUser is a user that will be added to the engine. This is for temporary use while the remaining features 68 // are implemented. Replaces the old "auth.New..." functions for adding a user. 69 type TemporaryUser struct { 70 Username string 71 Password string 72 } 73 74 // PreparedDataCache manages all the prepared data for every session for every query for an engine. 75 // There are two types of caching supported: 76 // 1. Prepared statements for MySQL, which are stored as sqlparser.Statements 77 // 2. Prepared statements for Postgres, which are stored as sql.Nodes 78 // TODO: move this into the session 79 type PreparedDataCache struct { 80 statements map[uint32]map[string]sqlparser.Statement 81 mu *sync.Mutex 82 } 83 84 func NewPreparedDataCache() *PreparedDataCache { 85 return &PreparedDataCache{ 86 statements: make(map[uint32]map[string]sqlparser.Statement), 87 mu: &sync.Mutex{}, 88 } 89 } 90 91 // GetCachedStmt retrieves the prepared statement associated with the ctx.SessionId and query. Returns nil, false if 92 // the query does not exist 93 func (p *PreparedDataCache) GetCachedStmt(sessId uint32, query string) (sqlparser.Statement, bool) { 94 p.mu.Lock() 95 defer p.mu.Unlock() 96 if sessData, ok := p.statements[sessId]; ok { 97 data, ok := sessData[query] 98 return data, ok 99 } 100 return nil, false 101 } 102 103 // CachedStatementsForSession returns all the prepared queries for a particular session 104 func (p *PreparedDataCache) CachedStatementsForSession(sessId uint32) map[string]sqlparser.Statement { 105 p.mu.Lock() 106 defer p.mu.Unlock() 107 return p.statements[sessId] 108 } 109 110 // DeleteSessionData clears a session along with all prepared queries for that session 111 func (p *PreparedDataCache) DeleteSessionData(sessId uint32) { 112 p.mu.Lock() 113 defer p.mu.Unlock() 114 delete(p.statements, sessId) 115 } 116 117 // CacheStmt saves the parsed statement and associates a ctx.SessionId and query to it 118 func (p *PreparedDataCache) CacheStmt(sessId uint32, query string, stmt sqlparser.Statement) { 119 p.mu.Lock() 120 defer p.mu.Unlock() 121 if _, ok := p.statements[sessId]; !ok { 122 p.statements[sessId] = make(map[string]sqlparser.Statement) 123 } 124 p.statements[sessId][query] = stmt 125 } 126 127 // UncacheStmt removes the prepared node associated with a ctx.SessionId and query to it 128 func (p *PreparedDataCache) UncacheStmt(sessId uint32, query string) { 129 p.mu.Lock() 130 defer p.mu.Unlock() 131 if _, ok := p.statements[sessId]; ok { 132 delete(p.statements[sessId], query) 133 } 134 } 135 136 // Engine is a SQL engine. 137 type Engine struct { 138 Analyzer *analyzer.Analyzer 139 LS *sql.LockSubsystem 140 ProcessList sql.ProcessList 141 MemoryManager *sql.MemoryManager 142 BackgroundThreads *sql.BackgroundThreads 143 ReadOnly atomic.Bool 144 IsServerLocked bool 145 PreparedDataCache *PreparedDataCache 146 mu *sync.Mutex 147 Version sql.AnalyzerVersion 148 EventScheduler *eventscheduler.EventScheduler 149 } 150 151 type ColumnWithRawDefault struct { 152 SqlColumn *sql.Column 153 Default string 154 } 155 156 // New creates a new Engine with custom configuration. To create an Engine with 157 // the default settings use `NewDefault`. Should call Engine.Close() to finalize 158 // dependency lifecycles. 159 func New(a *analyzer.Analyzer, cfg *Config) *Engine { 160 if cfg == nil { 161 cfg = &Config{} 162 } 163 164 if cfg.IncludeRootAccount { 165 a.Catalog.MySQLDb.AddRootAccount() 166 } 167 168 ls := sql.NewLockSubsystem() 169 170 emptyCtx := sql.NewEmptyContext() 171 a.Catalog.RegisterFunction(emptyCtx, sql.FunctionN{ 172 Name: "version", 173 Fn: function.NewVersion(cfg.VersionPostfix), 174 }) 175 a.Catalog.RegisterFunction(emptyCtx, function.GetLockingFuncs(ls)...) 176 177 ret := &Engine{ 178 Analyzer: a, 179 MemoryManager: sql.NewMemoryManager(sql.ProcessMemory), 180 ProcessList: NewProcessList(), 181 LS: ls, 182 BackgroundThreads: sql.NewBackgroundThreads(), 183 IsServerLocked: cfg.IsServerLocked, 184 PreparedDataCache: NewPreparedDataCache(), 185 mu: &sync.Mutex{}, 186 EventScheduler: nil, 187 } 188 ret.ReadOnly.Store(cfg.IsReadOnly) 189 return ret 190 } 191 192 // NewDefault creates a new default Engine. 193 func NewDefault(pro sql.DatabaseProvider) *Engine { 194 a := analyzer.NewDefaultWithVersion(pro) 195 return New(a, nil) 196 } 197 198 // AnalyzeQuery analyzes a query and returns its sql.Node 199 func (e *Engine) AnalyzeQuery( 200 ctx *sql.Context, 201 query string, 202 ) (sql.Node, error) { 203 query = planbuilder.RemoveSpaceAndDelimiter(query, ';') 204 parsed, err := planbuilder.Parse(ctx, e.Analyzer.Catalog, query) 205 if err != nil { 206 return nil, err 207 } 208 return e.Analyzer.Analyze(ctx, parsed, nil) 209 } 210 211 // PrepareQuery returns a partially analyzed query 212 func (e *Engine) PrepareQuery( 213 ctx *sql.Context, 214 query string, 215 ) (sql.Node, error) { 216 query = planbuilder.RemoveSpaceAndDelimiter(query, ';') 217 218 sqlMode := sql.LoadSqlMode(ctx) 219 stmt, _, err := sqlparser.ParseOneWithOptions(query, sqlMode.ParserOptions()) 220 if err != nil { 221 return nil, err 222 } 223 224 return e.PrepareParsedQuery(ctx, query, query, stmt) 225 } 226 227 // PrepareParsedQuery returns a partially analyzed query for the parsed statement provided 228 func (e *Engine) PrepareParsedQuery( 229 ctx *sql.Context, 230 statementKey, query string, 231 stmt sqlparser.Statement, 232 ) (sql.Node, error) { 233 binder := planbuilder.New(ctx, e.Analyzer.Catalog) 234 node, err := binder.BindOnly(stmt, query) 235 236 if err != nil { 237 return nil, err 238 } 239 240 e.PreparedDataCache.CacheStmt(ctx.Session.ID(), statementKey, stmt) 241 return node, nil 242 } 243 244 // Query executes a query. 245 func (e *Engine) Query(ctx *sql.Context, query string) (sql.Schema, sql.RowIter, error) { 246 return e.QueryWithBindings(ctx, query, nil, nil) 247 } 248 249 func bindingsToExprs(bindings map[string]*querypb.BindVariable) (map[string]sql.Expression, error) { 250 res := make(map[string]sql.Expression, len(bindings)) 251 for k, v := range bindings { 252 v, err := sqltypes.NewValue(v.Type, v.Value) 253 if err != nil { 254 return nil, err 255 } 256 switch { 257 case v.Type() == sqltypes.Year: 258 v, _, err := types.Year.Convert(string(v.ToBytes())) 259 if err != nil { 260 return nil, err 261 } 262 res[k] = expression.NewLiteral(v, types.Year) 263 case sqltypes.IsSigned(v.Type()): 264 v, err := strconv.ParseInt(string(v.ToBytes()), 0, 64) 265 if err != nil { 266 return nil, err 267 } 268 t := types.Int64 269 c, _, err := t.Convert(v) 270 if err != nil { 271 return nil, err 272 } 273 res[k] = expression.NewLiteral(c, t) 274 case sqltypes.IsUnsigned(v.Type()): 275 v, err := strconv.ParseUint(string(v.ToBytes()), 0, 64) 276 if err != nil { 277 return nil, err 278 } 279 t := types.Uint64 280 c, _, err := t.Convert(v) 281 if err != nil { 282 return nil, err 283 } 284 res[k] = expression.NewLiteral(c, t) 285 case sqltypes.IsFloat(v.Type()): 286 v, err := strconv.ParseFloat(string(v.ToBytes()), 64) 287 if err != nil { 288 return nil, err 289 } 290 t := types.Float64 291 c, _, err := t.Convert(v) 292 if err != nil { 293 return nil, err 294 } 295 res[k] = expression.NewLiteral(c, t) 296 case v.Type() == sqltypes.Decimal: 297 v, _, err := types.InternalDecimalType.Convert(string(v.ToBytes())) 298 if err != nil { 299 return nil, err 300 } 301 res[k] = expression.NewLiteral(v, types.InternalDecimalType) 302 case v.Type() == sqltypes.Bit: 303 t := types.MustCreateBitType(types.BitTypeMaxBits) 304 v, _, err := t.Convert(v.ToBytes()) 305 if err != nil { 306 return nil, err 307 } 308 res[k] = expression.NewLiteral(v, t) 309 case v.Type() == sqltypes.Null: 310 res[k] = expression.NewLiteral(nil, types.Null) 311 case v.Type() == sqltypes.Blob || v.Type() == sqltypes.VarBinary || v.Type() == sqltypes.Binary: 312 t, err := types.CreateBinary(v.Type(), int64(len(v.ToBytes()))) 313 if err != nil { 314 return nil, err 315 } 316 v, _, err := t.Convert(v.ToBytes()) 317 if err != nil { 318 return nil, err 319 } 320 res[k] = expression.NewLiteral(v, t) 321 case v.Type() == sqltypes.Text || v.Type() == sqltypes.VarChar || v.Type() == sqltypes.Char: 322 t, err := types.CreateStringWithDefaults(v.Type(), int64(len(v.ToBytes()))) 323 if err != nil { 324 return nil, err 325 } 326 v, _, err := t.Convert(v.ToBytes()) 327 if err != nil { 328 return nil, err 329 } 330 res[k] = expression.NewLiteral(v, t) 331 case v.Type() == sqltypes.Date || v.Type() == sqltypes.Datetime || v.Type() == sqltypes.Timestamp: 332 precision := 6 333 if v.Type() == sqltypes.Date { 334 precision = 0 335 } 336 t, err := types.CreateDatetimeType(v.Type(), precision) 337 if err != nil { 338 return nil, err 339 } 340 v, _, err := t.Convert(string(v.ToBytes())) 341 if err != nil { 342 return nil, err 343 } 344 res[k] = expression.NewLiteral(v, t) 345 case v.Type() == sqltypes.Time: 346 t := types.Time 347 v, _, err := t.Convert(string(v.ToBytes())) 348 if err != nil { 349 return nil, err 350 } 351 res[k] = expression.NewLiteral(v, t) 352 default: 353 return nil, sql.ErrUnsupportedFeature.New(v.Type().String()) 354 } 355 } 356 return res, nil 357 } 358 359 // QueryWithBindings executes the query given with the bindings provided. 360 // If parsed is non-nil, it will be used instead of parsing the query from text. 361 func (e *Engine) QueryWithBindings(ctx *sql.Context, query string, parsed sqlparser.Statement, bindings map[string]*querypb.BindVariable) (sql.Schema, sql.RowIter, error) { 362 query = planbuilder.RemoveSpaceAndDelimiter(query, ';') 363 364 parsed, binder, err := e.preparedStatement(ctx, query, parsed, bindings) 365 if err != nil { 366 return nil, nil, err 367 } 368 369 // Give the integrator a chance to reject the session before proceeding 370 // TODO: this check doesn't belong here 371 err = ctx.Session.ValidateSession(ctx) 372 if err != nil { 373 return nil, nil, err 374 } 375 376 err = e.beginTransaction(ctx) 377 if err != nil { 378 return nil, nil, err 379 } 380 381 bound, err := e.bindQuery(ctx, query, parsed, bindings, err, binder) 382 if err != nil { 383 return nil, nil, err 384 } 385 386 analyzed, err := e.analyzeNode(ctx, query, bound) 387 if err != nil { 388 return nil, nil, err 389 } 390 391 if bindCtx := binder.BindCtx(); bindCtx != nil { 392 if unused := bindCtx.UnusedBindings(); len(unused) > 0 { 393 return nil, nil, fmt.Errorf("invalid arguments. expected: %d, found: %d", len(bindCtx.Bindings)-len(unused), len(bindCtx.Bindings)) 394 } 395 } 396 397 err = e.readOnlyCheck(analyzed) 398 if err != nil { 399 return nil, nil, err 400 } 401 402 iter, err := e.Analyzer.ExecBuilder.Build(ctx, analyzed, nil) 403 if err != nil { 404 err2 := clearAutocommitTransaction(ctx) 405 if err2 != nil { 406 return nil, nil, errors.Wrap(err, "unable to clear autocommit transaction: "+err2.Error()) 407 } 408 409 return nil, nil, err 410 } 411 iter = rowexec.AddExpressionCloser(analyzed, iter) 412 413 return analyzed.Schema(), iter, nil 414 } 415 416 // PrepQueryPlanForExecution prepares a query plan for execution and returns the result schema with a row iterator to 417 // begin spooling results 418 func (e *Engine) PrepQueryPlanForExecution(ctx *sql.Context, query string, plan sql.Node) (sql.Schema, sql.RowIter, error) { 419 // Give the integrator a chance to reject the session before proceeding 420 // TODO: this check doesn't belong here 421 err := ctx.Session.ValidateSession(ctx) 422 if err != nil { 423 return nil, nil, err 424 } 425 426 err = e.beginTransaction(ctx) 427 if err != nil { 428 return nil, nil, err 429 } 430 431 err = e.readOnlyCheck(plan) 432 if err != nil { 433 return nil, nil, err 434 } 435 436 iter, err := e.Analyzer.ExecBuilder.Build(ctx, plan, nil) 437 if err != nil { 438 err2 := clearAutocommitTransaction(ctx) 439 if err2 != nil { 440 return nil, nil, errors.Wrap(err, "unable to clear autocommit transaction: "+err2.Error()) 441 } 442 443 return nil, nil, err 444 } 445 iter = rowexec.AddExpressionCloser(plan, iter) 446 447 return plan.Schema(), iter, nil 448 } 449 450 // BoundQueryPlan returns query plan for the given statement with the given bindings applied 451 func (e *Engine) BoundQueryPlan(ctx *sql.Context, query string, parsed sqlparser.Statement, bindings map[string]*querypb.BindVariable) (sql.Node, error) { 452 if parsed == nil { 453 return nil, errors.New("parsed statement must not be nil") 454 } 455 456 query = planbuilder.RemoveSpaceAndDelimiter(query, ';') 457 458 binder := planbuilder.New(ctx, e.Analyzer.Catalog) 459 binder.SetBindings(bindings) 460 461 // Begin a transaction if necessary (no-op if one is in flight) 462 err := e.beginTransaction(ctx) 463 if err != nil { 464 return nil, err 465 } 466 467 // TODO: we need to be more principled about when to clear auto commit transactions here 468 bound, err := e.bindQuery(ctx, query, parsed, bindings, err, binder) 469 if err != nil { 470 err2 := clearAutocommitTransaction(ctx) 471 if err2 != nil { 472 return nil, errors.Wrap(err, "unable to clear autocommit transaction: "+err2.Error()) 473 } 474 475 return nil, err 476 } 477 478 analyzed, err := e.analyzeNode(ctx, query, bound) 479 if err != nil { 480 err2 := clearAutocommitTransaction(ctx) 481 if err2 != nil { 482 return nil, errors.Wrap(err, "unable to clear autocommit transaction: "+err2.Error()) 483 } 484 return nil, err 485 } 486 487 if bindCtx := binder.BindCtx(); bindCtx != nil { 488 if unused := bindCtx.UnusedBindings(); len(unused) > 0 { 489 return nil, fmt.Errorf("invalid arguments. expected: %d, found: %d", len(bindCtx.Bindings)-len(unused), len(bindCtx.Bindings)) 490 } 491 } 492 493 return analyzed, nil 494 } 495 496 func (e *Engine) preparedStatement(ctx *sql.Context, query string, parsed sqlparser.Statement, bindings map[string]*querypb.BindVariable) (sqlparser.Statement, *planbuilder.Builder, error) { 497 preparedAst, preparedDataFound := e.PreparedDataCache.GetCachedStmt(ctx.Session.ID(), query) 498 499 // This means that we have bindings but no prepared statement cached, which occurs in tests and in the 500 // dolthub/driver package. We prepare the statement from the query string in this case 501 if !preparedDataFound && len(bindings) > 0 { 502 // TODO: pull this out into its own method for this specific use case 503 parsed = nil 504 _, err := e.PrepareQuery(ctx, query) 505 if err != nil { 506 return nil, nil, err 507 } 508 509 preparedAst, preparedDataFound = e.PreparedDataCache.GetCachedStmt(ctx.Session.ID(), query) 510 } 511 512 binder := planbuilder.New(ctx, e.Analyzer.Catalog) 513 if preparedDataFound { 514 parsed = preparedAst 515 binder.SetBindings(bindings) 516 } 517 518 return parsed, binder, nil 519 } 520 521 func (e *Engine) analyzeNode(ctx *sql.Context, query string, bound sql.Node) (sql.Node, error) { 522 switch n := bound.(type) { 523 case *plan.PrepareQuery: 524 sqlMode := sql.LoadSqlMode(ctx) 525 526 // we have to name-resolve to check for structural errors, but we do 527 // not to cache the name-bound query yet. 528 // todo(max): improve name resolution so we can cache post name-binding. 529 // this involves expression memoization, which currently screws up aggregation 530 // and order by aliases 531 prepStmt, _, err := sqlparser.ParseOneWithOptions(query, sqlMode.ParserOptions()) 532 if err != nil { 533 return nil, err 534 } 535 prepare, ok := prepStmt.(*sqlparser.Prepare) 536 if !ok { 537 return nil, fmt.Errorf("expected *sqlparser.Prepare, found %T", prepStmt) 538 } 539 cacheStmt, _, err := sqlparser.ParseOneWithOptions(prepare.Expr, sqlMode.ParserOptions()) 540 if err != nil && strings.HasPrefix(prepare.Expr, "@") { 541 val, err := expression.NewUserVar(strings.TrimPrefix(prepare.Expr, "@")).Eval(ctx, nil) 542 if err != nil { 543 return nil, err 544 } 545 valStr, ok := val.(string) 546 if !ok { 547 return nil, fmt.Errorf("expected string, found %T", val) 548 } 549 cacheStmt, _, err = sqlparser.ParseOneWithOptions(valStr, sqlMode.ParserOptions()) 550 if err != nil { 551 return nil, err 552 } 553 } else if err != nil { 554 return nil, err 555 } 556 e.PreparedDataCache.CacheStmt(ctx.Session.ID(), n.Name, cacheStmt) 557 return bound, nil 558 case *plan.DeallocateQuery: 559 if _, ok := e.PreparedDataCache.GetCachedStmt(ctx.Session.ID(), n.Name); !ok { 560 return nil, sql.ErrUnknownPreparedStatement.New(n.Name) 561 } 562 e.PreparedDataCache.UncacheStmt(ctx.Session.ID(), n.Name) 563 return bound, nil 564 default: 565 return e.Analyzer.Analyze(ctx, bound, nil) 566 } 567 } 568 569 // bindQuery binds any bind variables to the plan node or query given and returns it. 570 // |parsed| is the parsed AST without bindings applied, if the statement was previously parsed / prepared. 571 // If it wasn't (|parsed| is nil), then the query is parsed. 572 func (e *Engine) bindQuery(ctx *sql.Context, query string, parsed sqlparser.Statement, bindings map[string]*querypb.BindVariable, err error, binder *planbuilder.Builder) (sql.Node, error) { 573 var bound sql.Node 574 if parsed == nil { 575 bound, err = binder.ParseOne(query) 576 if err != nil { 577 clearAutocommitErr := clearAutocommitTransaction(ctx) 578 if clearAutocommitErr != nil { 579 return nil, errors.Wrap(err, "unable to clear autocommit transaction: "+clearAutocommitErr.Error()) 580 } 581 return nil, err 582 } 583 } else { 584 bound, err = binder.BindOnly(parsed, query) 585 if err != nil { 586 return nil, err 587 } 588 } 589 590 // ExecuteQuery nodes have their own special var binding step 591 eq, ok := bound.(*plan.ExecuteQuery) 592 if ok { 593 return e.bindExecuteQueryNode(ctx, query, eq, bindings, binder) 594 } 595 596 return bound, nil 597 } 598 599 // bindExecuteQueryNode returns the 600 func (e *Engine) bindExecuteQueryNode(ctx *sql.Context, query string, eq *plan.ExecuteQuery, bindings map[string]*querypb.BindVariable, binder *planbuilder.Builder) (sql.Node, error) { 601 prep, ok := e.PreparedDataCache.GetCachedStmt(ctx.Session.ID(), eq.Name) 602 if !ok { 603 return nil, sql.ErrUnknownPreparedStatement.New(eq.Name) 604 } 605 // todo validate expected and actual args -- not just count, by name 606 // if prep.ArgCount() < 1 { 607 // return nil, nil, fmt.Errorf("invalid bind variable count: expected %d, found %d", prep.ArgCount(), len(bindings)) 608 // } 609 for i, name := range eq.BindVars { 610 if bindings == nil { 611 bindings = make(map[string]*querypb.BindVariable) 612 } 613 if strings.HasPrefix(name.String(), "@") { 614 t, val, err := ctx.GetUserVariable(ctx, strings.TrimPrefix(name.String(), "@")) 615 if err != nil { 616 return nil, nil 617 } 618 if val != nil { 619 val, _, err = t.Promote().Convert(val) 620 if err != nil { 621 return nil, nil 622 } 623 } 624 bindings[fmt.Sprintf("v%d", i+1)], err = sqltypes.BuildBindVariable(val) 625 if err != nil { 626 return nil, nil 627 } 628 } else { 629 bindings[fmt.Sprintf("v%d", i)] = sqltypes.StringBindVariable(name.String()) 630 } 631 } 632 binder.SetBindings(bindings) 633 634 bound, err := binder.BindOnly(prep, query) 635 if err != nil { 636 clearAutocommitErr := clearAutocommitTransaction(ctx) 637 if clearAutocommitErr != nil { 638 return nil, errors.Wrap(err, "unable to clear autocommit transaction: "+clearAutocommitErr.Error()) 639 } 640 641 return nil, err 642 } 643 644 return bound, nil 645 } 646 647 // clearAutocommitTransaction unsets the transaction from the current session if it is an implicitly 648 // created autocommit transaction. This enables the next request to have an autocommit transaction 649 // correctly started. 650 func clearAutocommitTransaction(ctx *sql.Context) error { 651 // The GetIgnoreAutoCommit property essentially says the current transaction is an explicit, 652 // user-created transaction and we should not process autocommit. So, if it's set, then we 653 // don't need to do anything here to clear implicit transaction state. 654 // 655 // TODO: This logic would probably read more clearly if we could just ask the session/ctx if the 656 // current transaction is automatically created or explicitly created by the caller. 657 if ctx.GetIgnoreAutoCommit() { 658 return nil 659 } 660 661 autocommit, err := plan.IsSessionAutocommit(ctx) 662 if err != nil { 663 return err 664 } 665 666 if autocommit { 667 ctx.SetTransaction(nil) 668 } 669 670 return nil 671 } 672 673 // CloseSession deletes session specific prepared statement data 674 func (e *Engine) CloseSession(connID uint32) { 675 e.mu.Lock() 676 defer e.mu.Unlock() 677 e.PreparedDataCache.DeleteSessionData(connID) 678 } 679 680 // Count number of BindVars in given tree 681 func countBindVars(node sql.Node) int { 682 var bindVars map[string]bool 683 bindCntFunc := func(e sql.Expression) bool { 684 if bv, ok := e.(*expression.BindVar); ok { 685 if bindVars == nil { 686 bindVars = make(map[string]bool) 687 } 688 bindVars[bv.Name] = true 689 } 690 return true 691 } 692 transform.InspectExpressions(node, bindCntFunc) 693 694 // InsertInto.Source not a child of InsertInto, so also need to traverse those 695 transform.Inspect(node, func(n sql.Node) bool { 696 if in, ok := n.(*plan.InsertInto); ok { 697 transform.InspectExpressions(in.Source, bindCntFunc) 698 return false 699 } 700 return true 701 }) 702 return len(bindVars) 703 } 704 705 func (e *Engine) beginTransaction(ctx *sql.Context) error { 706 beginNewTransaction := ctx.GetTransaction() == nil || plan.ReadCommitted(ctx) 707 if beginNewTransaction { 708 ctx.GetLogger().Tracef("beginning new transaction") 709 ts, ok := ctx.Session.(sql.TransactionSession) 710 if ok { 711 tx, err := ts.StartTransaction(ctx, sql.ReadWrite) 712 if err != nil { 713 return err 714 } 715 716 ctx.SetTransaction(tx) 717 } 718 } 719 720 return nil 721 } 722 723 func (e *Engine) Close() error { 724 if e.EventScheduler != nil { 725 e.EventScheduler.Close() 726 } 727 for _, p := range e.ProcessList.Processes() { 728 e.ProcessList.Kill(p.Connection) 729 } 730 return e.BackgroundThreads.Shutdown() 731 } 732 733 func (e *Engine) WithBackgroundThreads(b *sql.BackgroundThreads) *Engine { 734 e.BackgroundThreads = b 735 return e 736 } 737 738 func (e *Engine) IsReadOnly() bool { 739 return e.ReadOnly.Load() 740 } 741 742 // readOnlyCheck checks to see if the query is valid with the modification setting of the engine. 743 func (e *Engine) readOnlyCheck(node sql.Node) error { 744 // Note: We only compute plan.IsReadOnly if the server is in one of 745 // these two modes, since otherwise it is simply wasted work. 746 if e.IsReadOnly() && !plan.IsReadOnly(node) { 747 return sql.ErrReadOnly.New() 748 } 749 if e.IsServerLocked && !plan.IsReadOnly(node) { 750 return sql.ErrDatabaseWriteLocked.New() 751 } 752 return nil 753 } 754 755 func (e *Engine) EnginePreparedDataCache() *PreparedDataCache { 756 return e.PreparedDataCache 757 } 758 759 func (e *Engine) EngineAnalyzer() *analyzer.Analyzer { 760 return e.Analyzer 761 } 762 763 // InitializeEventScheduler initializes the EventScheduler for the engine with the given sql.Context 764 // getter function, |ctxGetterFunc, the EventScheduler |status|, and the |period| for the event scheduler 765 // to check for events to execute. If |period| is less than 1, then it is ignored and the default period 766 // (30s currently) is used. This function also initializes the EventScheduler of the analyzer of this engine. 767 func (e *Engine) InitializeEventScheduler(ctxGetterFunc func() (*sql.Context, func() error, error), status eventscheduler.SchedulerStatus, period int) error { 768 var err error 769 e.EventScheduler, err = eventscheduler.InitEventScheduler(e.Analyzer, e.BackgroundThreads, ctxGetterFunc, status, e.executeEvent, period) 770 if err != nil { 771 return err 772 } 773 774 e.Analyzer.EventScheduler = e.EventScheduler 775 return nil 776 } 777 778 // executeEvent executes an event with this Engine. The event is executed against the |dbName| database, and by the 779 // account identified by |username| and |address|. The entire CREATE EVENT statement is passed in as the |createEventStatement| 780 // parameter, but only the body of the event is executed. (The CREATE EVENT statement is passed in to support event 781 // bodies that contain multiple statements in a BEGIN/END block.) If any problems are encounterd, the error return 782 // value will be populated. 783 func (e *Engine) executeEvent(ctx *sql.Context, dbName, createEventStatement, username, address string) error { 784 // the event must be executed against the correct database and with the definer's identity 785 ctx.SetCurrentDatabase(dbName) 786 ctx.Session.SetClient(sql.Client{User: username, Address: address}) 787 788 // Analyze the CREATE EVENT statement 789 planTree, err := e.AnalyzeQuery(ctx, createEventStatement) 790 if err != nil { 791 return err 792 } 793 794 // and pull out the event body/definition 795 createEventNode, err := findCreateEventNode(planTree) 796 if err != nil { 797 return err 798 } 799 definitionNode := createEventNode.DefinitionNode 800 801 // Build an iterator to execute the event body 802 iter, err := e.Analyzer.ExecBuilder.Build(ctx, definitionNode, nil) 803 if err != nil { 804 clearAutocommitErr := clearAutocommitTransaction(ctx) 805 if clearAutocommitErr != nil { 806 return clearAutocommitErr 807 } 808 return err 809 } 810 iter = rowexec.AddExpressionCloser(definitionNode, iter) 811 812 // Drain the iterate to execute the event body/definition 813 // NOTE: No row data is returned for an event; we just need to execute the statements 814 _, err = sql.RowIterToRows(ctx, iter) 815 return err 816 } 817 818 // findCreateEventNode searches |planTree| for the first plan.CreateEvent node and 819 // returns it. If no matching node was found, the returned CreateEvent node will be 820 // nil and an error will be populated. 821 func findCreateEventNode(planTree sql.Node) (*plan.CreateEvent, error) { 822 // Search through the node to find the first CREATE EVENT node, and then grab its body 823 var targetNode sql.Node 824 transform.Inspect(planTree, func(node sql.Node) bool { 825 if cen, ok := node.(*plan.CreateEvent); ok { 826 targetNode = cen 827 return false 828 } 829 return true 830 }) 831 832 if targetNode == nil { 833 return nil, fmt.Errorf("unable to find create event node in plan tree: %v", planTree) 834 } 835 836 createEventNode, ok := targetNode.(*plan.CreateEvent) 837 if !ok { 838 return nil, fmt.Errorf("unable to find create event node in plan tree: %v", planTree) 839 } 840 841 return createEventNode, nil 842 }