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  }