vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletserver/query_executor.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package tabletserver
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"io"
    23  	"strings"
    24  	"sync"
    25  	"time"
    26  
    27  	"google.golang.org/protobuf/proto"
    28  
    29  	"vitess.io/vitess/go/mysql"
    30  	"vitess.io/vitess/go/mysql/collations"
    31  	"vitess.io/vitess/go/pools"
    32  	"vitess.io/vitess/go/sqltypes"
    33  	"vitess.io/vitess/go/trace"
    34  	"vitess.io/vitess/go/vt/callerid"
    35  	"vitess.io/vitess/go/vt/callinfo"
    36  	"vitess.io/vitess/go/vt/log"
    37  	"vitess.io/vitess/go/vt/schema"
    38  	"vitess.io/vitess/go/vt/sqlparser"
    39  	"vitess.io/vitess/go/vt/tableacl"
    40  	"vitess.io/vitess/go/vt/vterrors"
    41  	"vitess.io/vitess/go/vt/vtgate/evalengine"
    42  	"vitess.io/vitess/go/vt/vttablet/tabletserver/connpool"
    43  	p "vitess.io/vitess/go/vt/vttablet/tabletserver/planbuilder"
    44  	"vitess.io/vitess/go/vt/vttablet/tabletserver/rules"
    45  	"vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv"
    46  
    47  	querypb "vitess.io/vitess/go/vt/proto/query"
    48  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    49  	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
    50  )
    51  
    52  // QueryExecutor is used for executing a query request.
    53  type QueryExecutor struct {
    54  	query          string
    55  	marginComments sqlparser.MarginComments
    56  	bindVars       map[string]*querypb.BindVariable
    57  	connID         int64
    58  	options        *querypb.ExecuteOptions
    59  	plan           *TabletPlan
    60  	ctx            context.Context
    61  	logStats       *tabletenv.LogStats
    62  	tsv            *TabletServer
    63  	tabletType     topodatapb.TabletType
    64  	setting        *pools.Setting
    65  }
    66  
    67  const (
    68  	streamRowsSize         = 256
    69  	maxQueryBufferDuration = 10 * time.Second
    70  )
    71  
    72  var (
    73  	streamResultPool = sync.Pool{New: func() any {
    74  		return &sqltypes.Result{
    75  			Rows: make([][]sqltypes.Value, 0, streamRowsSize),
    76  		}
    77  	}}
    78  	sequenceFields = []*querypb.Field{
    79  		{
    80  			Name: "nextval",
    81  			Type: sqltypes.Int64,
    82  		},
    83  	}
    84  )
    85  
    86  func returnStreamResult(result *sqltypes.Result) error {
    87  	// only return large results slices to the pool
    88  	if cap(result.Rows) >= streamRowsSize {
    89  		rows := result.Rows[:0]
    90  		*result = sqltypes.Result{}
    91  		result.Rows = rows
    92  		streamResultPool.Put(result)
    93  	}
    94  	return nil
    95  }
    96  
    97  func allocStreamResult() *sqltypes.Result {
    98  	return streamResultPool.Get().(*sqltypes.Result)
    99  }
   100  
   101  func (qre *QueryExecutor) shouldConsolidate() bool {
   102  	co := qre.options.GetConsolidator()
   103  	switch co {
   104  	case querypb.ExecuteOptions_CONSOLIDATOR_DISABLED:
   105  		return false
   106  	case querypb.ExecuteOptions_CONSOLIDATOR_ENABLED:
   107  		return true
   108  	case querypb.ExecuteOptions_CONSOLIDATOR_ENABLED_REPLICAS:
   109  		return qre.tabletType != topodatapb.TabletType_PRIMARY
   110  	default:
   111  		cm := qre.tsv.qe.consolidatorMode.Get()
   112  		return cm == tabletenv.Enable || (cm == tabletenv.NotOnPrimary && qre.tabletType != topodatapb.TabletType_PRIMARY)
   113  	}
   114  }
   115  
   116  // Execute performs a non-streaming query execution.
   117  func (qre *QueryExecutor) Execute() (reply *sqltypes.Result, err error) {
   118  	planName := qre.plan.PlanID.String()
   119  	qre.logStats.PlanType = planName
   120  	defer func(start time.Time) {
   121  		duration := time.Since(start)
   122  		qre.tsv.stats.QueryTimings.Add(planName, duration)
   123  		qre.recordUserQuery("Execute", int64(duration))
   124  
   125  		mysqlTime := qre.logStats.MysqlResponseTime
   126  		tableName := qre.plan.TableName().String()
   127  		if tableName == "" {
   128  			tableName = "Join"
   129  		}
   130  
   131  		if reply == nil {
   132  			qre.tsv.qe.AddStats(qre.plan.PlanID, tableName, 1, duration, mysqlTime, 0, 0, 1)
   133  			qre.plan.AddStats(1, duration, mysqlTime, 0, 0, 1)
   134  			return
   135  		}
   136  		qre.tsv.qe.AddStats(qre.plan.PlanID, tableName, 1, duration, mysqlTime, int64(reply.RowsAffected), int64(len(reply.Rows)), 0)
   137  		qre.plan.AddStats(1, duration, mysqlTime, reply.RowsAffected, uint64(len(reply.Rows)), 0)
   138  		qre.logStats.RowsAffected = int(reply.RowsAffected)
   139  		qre.logStats.Rows = reply.Rows
   140  		qre.tsv.Stats().ResultHistogram.Add(int64(len(reply.Rows)))
   141  	}(time.Now())
   142  
   143  	if err = qre.checkPermissions(); err != nil {
   144  		return nil, err
   145  	}
   146  
   147  	if qre.plan.PlanID == p.PlanNextval {
   148  		return qre.execNextval()
   149  	}
   150  
   151  	if qre.connID != 0 {
   152  		var conn *StatefulConnection
   153  		// Need upfront connection for DMLs and transactions
   154  		conn, err = qre.tsv.te.txPool.GetAndLock(qre.connID, "for query")
   155  		if err != nil {
   156  			return nil, err
   157  		}
   158  		defer conn.Unlock()
   159  		if qre.setting != nil {
   160  			if err = conn.ApplySetting(qre.ctx, qre.setting); err != nil {
   161  				return nil, vterrors.Wrap(err, "failed to execute system setting on the connection")
   162  			}
   163  		}
   164  		return qre.txConnExec(conn)
   165  	}
   166  
   167  	switch qre.plan.PlanID {
   168  	case p.PlanSelect, p.PlanSelectImpossible, p.PlanShow:
   169  		maxrows := qre.getSelectLimit()
   170  		qre.bindVars["#maxLimit"] = sqltypes.Int64BindVariable(maxrows + 1)
   171  		if qre.bindVars[sqltypes.BvReplaceSchemaName] != nil {
   172  			qre.bindVars[sqltypes.BvSchemaName] = sqltypes.StringBindVariable(qre.tsv.config.DB.DBName)
   173  		}
   174  		qr, err := qre.execSelect()
   175  		if err != nil {
   176  			return nil, err
   177  		}
   178  		if err := qre.verifyRowCount(int64(len(qr.Rows)), maxrows); err != nil {
   179  			return nil, err
   180  		}
   181  		return qr, nil
   182  	case p.PlanOtherRead, p.PlanOtherAdmin, p.PlanFlush, p.PlanSavepoint, p.PlanRelease, p.PlanSRollback:
   183  		return qre.execOther()
   184  	case p.PlanInsert, p.PlanUpdate, p.PlanDelete, p.PlanInsertMessage, p.PlanDDL, p.PlanLoad:
   185  		return qre.execAutocommit(qre.txConnExec)
   186  	case p.PlanViewDDL:
   187  		switch qre.plan.FullStmt.(type) {
   188  		case *sqlparser.DropView:
   189  			return qre.execAutocommit(qre.execDropViewDDL)
   190  		default:
   191  			return qre.execAsTransaction(qre.execViewDDL)
   192  		}
   193  	case p.PlanUpdateLimit, p.PlanDeleteLimit:
   194  		return qre.execAsTransaction(qre.txConnExec)
   195  	case p.PlanCallProc:
   196  		return qre.execCallProc()
   197  	case p.PlanAlterMigration:
   198  		return qre.execAlterMigration()
   199  	case p.PlanRevertMigration:
   200  		return qre.execRevertMigration()
   201  	case p.PlanShowMigrationLogs:
   202  		return qre.execShowMigrationLogs()
   203  	case p.PlanShowThrottledApps:
   204  		return qre.execShowThrottledApps()
   205  	case p.PlanShowThrottlerStatus:
   206  		return qre.execShowThrottlerStatus()
   207  	case p.PlanSet:
   208  		if qre.setting == nil {
   209  			return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "[BUG] %s not allowed without setting connection", qre.query)
   210  		}
   211  		// The execution is not required as this setting will be applied when any other query type is executed.
   212  		return &sqltypes.Result{}, nil
   213  	}
   214  	return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "[BUG] %s unexpected plan type", qre.plan.PlanID.String())
   215  }
   216  
   217  func (qre *QueryExecutor) execAutocommit(f func(conn *StatefulConnection) (*sqltypes.Result, error)) (reply *sqltypes.Result, err error) {
   218  	if qre.options == nil {
   219  		qre.options = &querypb.ExecuteOptions{}
   220  	} else {
   221  		qre.options = proto.Clone(qre.options).(*querypb.ExecuteOptions)
   222  	}
   223  	qre.options.TransactionIsolation = querypb.ExecuteOptions_AUTOCOMMIT
   224  
   225  	conn, _, _, err := qre.tsv.te.txPool.Begin(qre.ctx, qre.options, false, 0, nil, qre.setting)
   226  
   227  	if err != nil {
   228  		return nil, err
   229  	}
   230  	defer qre.tsv.te.txPool.RollbackAndRelease(qre.ctx, conn)
   231  
   232  	return f(conn)
   233  }
   234  
   235  func (qre *QueryExecutor) execAsTransaction(f func(conn *StatefulConnection) (*sqltypes.Result, error)) (*sqltypes.Result, error) {
   236  	conn, beginSQL, _, err := qre.tsv.te.txPool.Begin(qre.ctx, qre.options, false, 0, nil, qre.setting)
   237  	if err != nil {
   238  		return nil, err
   239  	}
   240  	defer qre.tsv.te.txPool.RollbackAndRelease(qre.ctx, conn)
   241  	qre.logStats.AddRewrittenSQL(beginSQL, time.Now())
   242  
   243  	result, err := f(conn)
   244  	if err != nil {
   245  		// dbConn is nil, it means the transaction was aborted.
   246  		// If so, we should not relog the rollback.
   247  		// TODO(sougou): these txPool functions should take the logstats
   248  		// and log any statements they issue. This needs to be done as
   249  		// a separate refactor because it impacts lot of code.
   250  		if conn.IsInTransaction() {
   251  			defer qre.logStats.AddRewrittenSQL("rollback", time.Now())
   252  		}
   253  		return nil, err
   254  	}
   255  
   256  	defer qre.logStats.AddRewrittenSQL("commit", time.Now())
   257  	if _, err := qre.tsv.te.txPool.Commit(qre.ctx, conn); err != nil {
   258  		return nil, err
   259  	}
   260  	return result, nil
   261  }
   262  
   263  func (qre *QueryExecutor) txConnExec(conn *StatefulConnection) (*sqltypes.Result, error) {
   264  	switch qre.plan.PlanID {
   265  	case p.PlanInsert, p.PlanUpdate, p.PlanDelete, p.PlanSet:
   266  		return qre.txFetch(conn, true)
   267  	case p.PlanInsertMessage:
   268  		qre.bindVars["#time_now"] = sqltypes.Int64BindVariable(time.Now().UnixNano())
   269  		return qre.txFetch(conn, true)
   270  	case p.PlanUpdateLimit, p.PlanDeleteLimit:
   271  		return qre.execDMLLimit(conn)
   272  	case p.PlanOtherRead, p.PlanOtherAdmin, p.PlanFlush:
   273  		return qre.execStatefulConn(conn, qre.query, true)
   274  	case p.PlanSavepoint, p.PlanRelease, p.PlanSRollback:
   275  		return qre.execStatefulConn(conn, qre.query, true)
   276  	case p.PlanSelect, p.PlanSelectImpossible, p.PlanShow, p.PlanSelectLockFunc:
   277  		maxrows := qre.getSelectLimit()
   278  		qre.bindVars["#maxLimit"] = sqltypes.Int64BindVariable(maxrows + 1)
   279  		if qre.bindVars[sqltypes.BvReplaceSchemaName] != nil {
   280  			qre.bindVars[sqltypes.BvSchemaName] = sqltypes.StringBindVariable(qre.tsv.config.DB.DBName)
   281  		}
   282  		qr, err := qre.txFetch(conn, false)
   283  		if err != nil {
   284  			return nil, err
   285  		}
   286  		if err := qre.verifyRowCount(int64(len(qr.Rows)), maxrows); err != nil {
   287  			return nil, err
   288  		}
   289  		return qr, nil
   290  	case p.PlanDDL:
   291  		return qre.execDDL(conn)
   292  	case p.PlanLoad:
   293  		return qre.execLoad(conn)
   294  	case p.PlanCallProc:
   295  		return qre.execProc(conn)
   296  	}
   297  	return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "[BUG] %s unexpected plan type", qre.plan.PlanID.String())
   298  }
   299  
   300  func (qre *QueryExecutor) execViewDDL(conn *StatefulConnection) (*sqltypes.Result, error) {
   301  	var err error
   302  	switch stmt := qre.plan.FullStmt.(type) {
   303  	case *sqlparser.CreateView:
   304  		_, err = qre.execCreateViewDDL(conn, stmt)
   305  	case *sqlparser.AlterView:
   306  		_, err = qre.execAlterViewDDL(conn, stmt)
   307  	default:
   308  		err = vterrors.Errorf(vtrpcpb.Code_INTERNAL, "BUG: unexpected view DDL type: %T", qre.plan.FullStmt)
   309  	}
   310  	if err != nil {
   311  		return nil, err
   312  	}
   313  	// We need to use a different connection for executing the DDL on MySQL
   314  	// because the previous DMLs are running in a transaction and we don't want to autocommit
   315  	// those changes.
   316  	ddlConn, err := qre.getConn()
   317  	if err != nil {
   318  		return nil, err
   319  	}
   320  	defer ddlConn.Recycle()
   321  	// If MySQL fails, then we will Rollback the changes.
   322  	return ddlConn.Exec(qre.ctx, sqlparser.String(qre.plan.FullStmt), 1000, true)
   323  }
   324  
   325  func (qre *QueryExecutor) execCreateViewDDL(conn *StatefulConnection, stmt *sqlparser.CreateView) (*sqltypes.Result, error) {
   326  	bindVars := generateBindVarsForViewDDLInsert(stmt)
   327  	sql, _, err := qre.generateFinalSQL(qre.plan.FullQuery, bindVars)
   328  	if err != nil {
   329  		return nil, err
   330  	}
   331  	qr, err := execWithDDLView(qre.ctx, conn, sql)
   332  	if err != nil {
   333  		sqlErr, isSQLErr := mysql.NewSQLErrorFromError(err).(*mysql.SQLError)
   334  		// If it is a MySQL error and its code is of duplicate entry,
   335  		// then we would return duplicate create view error.
   336  		if isSQLErr && sqlErr.Number() == mysql.ERDupEntry {
   337  			return nil, vterrors.Errorf(vtrpcpb.Code_ALREADY_EXISTS, "Table '%s' already exists", stmt.ViewName.Name.String())
   338  		}
   339  		return nil, err
   340  	}
   341  	return qr, nil
   342  }
   343  
   344  func (qre *QueryExecutor) execAlterViewDDL(conn *StatefulConnection, stmt *sqlparser.AlterView) (*sqltypes.Result, error) {
   345  	createViewDDL := &sqlparser.CreateView{
   346  		ViewName:    stmt.ViewName,
   347  		Algorithm:   stmt.Algorithm,
   348  		Definer:     stmt.Definer,
   349  		Security:    stmt.Security,
   350  		Columns:     stmt.Columns,
   351  		Select:      stmt.Select,
   352  		CheckOption: stmt.CheckOption,
   353  		Comments:    stmt.Comments,
   354  	}
   355  	bindVars := generateBindVarsForViewDDLInsert(createViewDDL)
   356  	sql, _, err := qre.generateFinalSQL(qre.plan.FullQuery, bindVars)
   357  	if err != nil {
   358  		return nil, err
   359  	}
   360  	qr, err := execWithDDLView(qre.ctx, conn, sql)
   361  	if err != nil {
   362  		return nil, err
   363  	}
   364  	if qr.RowsAffected == 0 {
   365  		return nil, vterrors.Errorf(vtrpcpb.Code_NOT_FOUND, "Table '%s' does not exist", stmt.ViewName.Name.String())
   366  	}
   367  	return qr, nil
   368  }
   369  
   370  func (qre *QueryExecutor) execDropViewDDL(conn *StatefulConnection) (*sqltypes.Result, error) {
   371  	viewsMap := make(map[string]int)
   372  	stmt := qre.plan.FullStmt.(*sqlparser.DropView)
   373  	var viewNames []string
   374  	for pos, view := range stmt.FromTables {
   375  		viewName := view.Name.String()
   376  		if _, exists := viewsMap[viewName]; exists {
   377  			return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "Not unique view: '%s'", viewName)
   378  		}
   379  		viewNames = append(viewNames, viewName)
   380  		viewsMap[viewName] = pos
   381  	}
   382  	viewNamesBV, err := sqltypes.BuildBindVariable(viewNames)
   383  	if err != nil {
   384  		return nil, err
   385  	}
   386  	bindVars := map[string]*querypb.BindVariable{
   387  		"table_name": viewNamesBV,
   388  	}
   389  
   390  	sql, _, err := qre.generateFinalSQL(qre.plan.FullQuery, bindVars)
   391  	if err != nil {
   392  		return nil, err
   393  	}
   394  	_, err = execWithDDLView(qre.ctx, conn, sql)
   395  	if err != nil {
   396  		return nil, err
   397  	}
   398  
   399  	// Drop the view on MySQL too.
   400  	return conn.Exec(qre.ctx, sqlparser.String(qre.plan.FullStmt), 1000, true)
   401  }
   402  
   403  func execWithDDLView(ctx context.Context, conn *StatefulConnection, sql string) (*sqltypes.Result, error) {
   404  	return conn.Exec(ctx, sql, 10000, true)
   405  }
   406  
   407  // Stream performs a streaming query execution.
   408  func (qre *QueryExecutor) Stream(callback StreamCallback) error {
   409  	qre.logStats.PlanType = qre.plan.PlanID.String()
   410  
   411  	defer func(start time.Time) {
   412  		qre.tsv.stats.QueryTimings.Record(qre.plan.PlanID.String(), start)
   413  		qre.recordUserQuery("Stream", int64(time.Since(start)))
   414  	}(time.Now())
   415  
   416  	if err := qre.checkPermissions(); err != nil {
   417  		return err
   418  	}
   419  
   420  	switch qre.plan.PlanID {
   421  	case p.PlanSelectStream:
   422  		if qre.bindVars[sqltypes.BvReplaceSchemaName] != nil {
   423  			qre.bindVars[sqltypes.BvSchemaName] = sqltypes.StringBindVariable(qre.tsv.config.DB.DBName)
   424  		}
   425  	}
   426  
   427  	sql, sqlWithoutComments, err := qre.generateFinalSQL(qre.plan.FullQuery, qre.bindVars)
   428  	if err != nil {
   429  		return err
   430  	}
   431  
   432  	var replaceKeyspace string
   433  	if sqltypes.IncludeFieldsOrDefault(qre.options) == querypb.ExecuteOptions_ALL && qre.tsv.sm.target.Keyspace != qre.tsv.config.DB.DBName {
   434  		replaceKeyspace = qre.tsv.sm.target.Keyspace
   435  	}
   436  
   437  	if consolidator := qre.tsv.qe.streamConsolidator; consolidator != nil {
   438  		if qre.connID == 0 && qre.plan.PlanID == p.PlanSelectStream && qre.shouldConsolidate() {
   439  			return consolidator.Consolidate(qre.logStats, sqlWithoutComments, callback,
   440  				func(callback StreamCallback) error {
   441  					dbConn, err := qre.getStreamConn()
   442  					if err != nil {
   443  						return err
   444  					}
   445  					defer dbConn.Recycle()
   446  					return qre.execStreamSQL(dbConn, qre.connID != 0, sql, func(result *sqltypes.Result) error {
   447  						// this stream result is potentially used by more than one client, so
   448  						// the consolidator will return it to the pool once it knows it's no longer
   449  						// being shared
   450  
   451  						if replaceKeyspace != "" {
   452  							result.ReplaceKeyspace(replaceKeyspace)
   453  						}
   454  						return callback(result)
   455  					})
   456  				})
   457  		}
   458  	}
   459  
   460  	// if we have a transaction id, let's use the txPool for this query
   461  	var conn *connpool.DBConn
   462  	if qre.connID != 0 {
   463  		txConn, err := qre.tsv.te.txPool.GetAndLock(qre.connID, "for streaming query")
   464  		if err != nil {
   465  			return err
   466  		}
   467  		defer txConn.Unlock()
   468  		if qre.setting != nil {
   469  			if err = txConn.ApplySetting(qre.ctx, qre.setting); err != nil {
   470  				return vterrors.Wrap(err, "failed to execute system setting on the connection")
   471  			}
   472  		}
   473  		conn = txConn.UnderlyingDBConn()
   474  	} else {
   475  		dbConn, err := qre.getStreamConn()
   476  		if err != nil {
   477  			return err
   478  		}
   479  		defer dbConn.Recycle()
   480  		conn = dbConn
   481  	}
   482  
   483  	return qre.execStreamSQL(conn, qre.connID != 0, sql, func(result *sqltypes.Result) error {
   484  		// this stream result is only used by the calling client, so it can be
   485  		// returned to the pool once the callback has fully returned
   486  		defer returnStreamResult(result)
   487  
   488  		if replaceKeyspace != "" {
   489  			result.ReplaceKeyspace(replaceKeyspace)
   490  		}
   491  		return callback(result)
   492  	})
   493  }
   494  
   495  // MessageStream streams messages from a message table.
   496  func (qre *QueryExecutor) MessageStream(callback StreamCallback) error {
   497  	qre.logStats.OriginalSQL = qre.query
   498  	qre.logStats.PlanType = qre.plan.PlanID.String()
   499  
   500  	defer func(start time.Time) {
   501  		qre.tsv.stats.QueryTimings.Record(qre.plan.PlanID.String(), start)
   502  		qre.recordUserQuery("MessageStream", int64(time.Since(start)))
   503  	}(time.Now())
   504  
   505  	if err := qre.checkPermissions(); err != nil {
   506  		return err
   507  	}
   508  
   509  	done, err := qre.tsv.messager.Subscribe(qre.ctx, qre.plan.TableName().String(), func(r *sqltypes.Result) error {
   510  		select {
   511  		case <-qre.ctx.Done():
   512  			return io.EOF
   513  		default:
   514  		}
   515  		return callback(r)
   516  	})
   517  	if err != nil {
   518  		return err
   519  	}
   520  	<-done
   521  	return nil
   522  }
   523  
   524  // checkPermissions returns an error if the query does not pass all checks
   525  // (denied query, table ACL).
   526  func (qre *QueryExecutor) checkPermissions() error {
   527  	// Skip permissions check if the context is local.
   528  	if tabletenv.IsLocalContext(qre.ctx) {
   529  		return nil
   530  	}
   531  
   532  	// Check if the query relates to a table that is in the denylist.
   533  	remoteAddr := ""
   534  	username := ""
   535  	ci, ok := callinfo.FromContext(qre.ctx)
   536  	if ok {
   537  		remoteAddr = ci.RemoteAddr()
   538  		username = ci.Username()
   539  	}
   540  
   541  	bufferingTimeoutCtx, cancel := context.WithTimeout(qre.ctx, maxQueryBufferDuration)
   542  	defer cancel()
   543  
   544  	action, ruleCancelCtx, desc := qre.plan.Rules.GetAction(remoteAddr, username, qre.bindVars, qre.marginComments)
   545  	switch action {
   546  	case rules.QRFail:
   547  		return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "disallowed due to rule: %s", desc)
   548  	case rules.QRFailRetry:
   549  		return vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "disallowed due to rule: %s", desc)
   550  	case rules.QRBuffer:
   551  		if ruleCancelCtx != nil {
   552  			// We buffer up to some timeout. The timeout is determined by ctx.Done().
   553  			// If we're not at timeout yet, we fail the query
   554  			select {
   555  			case <-ruleCancelCtx.Done():
   556  				// good! We have buffered the query, and buffering is completed
   557  			case <-bufferingTimeoutCtx.Done():
   558  				// Sorry, timeout while waiting for buffering to complete
   559  				return vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "buffer timeout in rule: %s", desc)
   560  			}
   561  		}
   562  	default:
   563  		// no rules against this query. Good to proceed
   564  	}
   565  	// Skip ACL check for queries against the dummy dual table
   566  	if qre.plan.TableName().String() == "dual" {
   567  		return nil
   568  	}
   569  
   570  	// Skip the ACL check if the connecting user is an exempted superuser.
   571  	if qre.tsv.qe.exemptACL != nil && qre.tsv.qe.exemptACL.IsMember(&querypb.VTGateCallerID{Username: username}) {
   572  		qre.tsv.qe.tableaclExemptCount.Add(1)
   573  		return nil
   574  	}
   575  
   576  	callerID := callerid.ImmediateCallerIDFromContext(qre.ctx)
   577  	if callerID == nil {
   578  		if qre.tsv.qe.strictTableACL {
   579  			return vterrors.Errorf(vtrpcpb.Code_UNAUTHENTICATED, "missing caller id")
   580  		}
   581  		return nil
   582  	}
   583  
   584  	// Skip the ACL check if the caller id is an exempted superuser.
   585  	if qre.tsv.qe.exemptACL != nil && qre.tsv.qe.exemptACL.IsMember(callerID) {
   586  		qre.tsv.qe.tableaclExemptCount.Add(1)
   587  		return nil
   588  	}
   589  
   590  	for i, auth := range qre.plan.Authorized {
   591  		if err := qre.checkAccess(auth, qre.plan.Permissions[i].TableName, callerID); err != nil {
   592  			return err
   593  		}
   594  	}
   595  
   596  	return nil
   597  }
   598  
   599  func (qre *QueryExecutor) checkAccess(authorized *tableacl.ACLResult, tableName string, callerID *querypb.VTGateCallerID) error {
   600  	statsKey := []string{tableName, authorized.GroupName, qre.plan.PlanID.String(), callerID.Username}
   601  	if !authorized.IsMember(callerID) {
   602  		if qre.tsv.qe.enableTableACLDryRun {
   603  			qre.tsv.Stats().TableaclPseudoDenied.Add(statsKey, 1)
   604  			return nil
   605  		}
   606  
   607  		// Skip ACL check for queries against the dummy dual table
   608  		if tableName == "dual" {
   609  			return nil
   610  		}
   611  
   612  		if qre.tsv.qe.strictTableACL {
   613  			groupStr := ""
   614  			if len(callerID.Groups) > 0 {
   615  				groupStr = fmt.Sprintf(", in groups [%s],", strings.Join(callerID.Groups, ", "))
   616  			}
   617  			errStr := fmt.Sprintf("%s command denied to user '%s'%s for table '%s' (ACL check error)", qre.plan.PlanID.String(), callerID.Username, groupStr, tableName)
   618  			qre.tsv.Stats().TableaclDenied.Add(statsKey, 1)
   619  			qre.tsv.qe.accessCheckerLogger.Infof("%s", errStr)
   620  			return vterrors.Errorf(vtrpcpb.Code_PERMISSION_DENIED, "%s", errStr)
   621  		}
   622  		return nil
   623  	}
   624  	qre.tsv.Stats().TableaclAllowed.Add(statsKey, 1)
   625  	return nil
   626  }
   627  
   628  func (qre *QueryExecutor) execDDL(conn *StatefulConnection) (*sqltypes.Result, error) {
   629  	// Let's see if this is a normal DDL statement or an Online DDL statement.
   630  	// An Online DDL statement is identified by /*vt+ .. */ comment with expected directives, like uuid etc.
   631  	if onlineDDL, err := schema.OnlineDDLFromCommentedStatement(qre.plan.FullStmt); err == nil {
   632  		// Parsing is successful.
   633  		if !onlineDDL.Strategy.IsDirect() {
   634  			// This is an online DDL.
   635  			return qre.tsv.onlineDDLExecutor.SubmitMigration(qre.ctx, qre.plan.FullStmt)
   636  		}
   637  	}
   638  
   639  	isTemporaryTable := false
   640  	if ddlStmt, ok := qre.plan.FullStmt.(sqlparser.DDLStatement); ok {
   641  		isTemporaryTable = ddlStmt.IsTemporary()
   642  	}
   643  	if !isTemporaryTable {
   644  		// Temporary tables are limited to the session creating them. There is no need to Reload()
   645  		// the table because other connections will not be able to see the table anyway.
   646  		defer func() {
   647  			// Call se.Reload() with includeStats=false as obtaining table
   648  			// size stats involves joining `information_schema.tables`,
   649  			// which can be very costly on systems with a large number of
   650  			// tables.
   651  			//
   652  			// Instead of synchronously recalculating table size stats
   653  			// after every DDL, let them be outdated until the periodic
   654  			// schema reload fixes it.
   655  			if err := qre.tsv.se.ReloadAtEx(qre.ctx, mysql.Position{}, false); err != nil {
   656  				log.Errorf("failed to reload schema %v", err)
   657  			}
   658  		}()
   659  	}
   660  	sql := qre.query
   661  	// If FullQuery is not nil, then the DDL query was fully parsed
   662  	// and we should use the ast to generate the query instead.
   663  	if qre.plan.FullQuery != nil {
   664  		var err error
   665  		sql, _, err = qre.generateFinalSQL(qre.plan.FullQuery, qre.bindVars)
   666  		if err != nil {
   667  			return nil, err
   668  		}
   669  	}
   670  	result, err := qre.execStatefulConn(conn, sql, true)
   671  	if err != nil {
   672  		return nil, err
   673  	}
   674  	// Only perform this operation when the connection has transaction open.
   675  	// TODO: This actually does not retain the old transaction. We should see how to provide correct behaviour to client.
   676  	if conn.txProps != nil {
   677  		err = qre.BeginAgain(qre.ctx, conn)
   678  		if err != nil {
   679  			return nil, err
   680  		}
   681  	}
   682  	return result, nil
   683  }
   684  
   685  func (qre *QueryExecutor) execLoad(conn *StatefulConnection) (*sqltypes.Result, error) {
   686  	result, err := qre.execStatefulConn(conn, qre.query, true)
   687  	if err != nil {
   688  		return nil, err
   689  	}
   690  	return result, nil
   691  }
   692  
   693  // BeginAgain commits the existing transaction and begins a new one
   694  func (*QueryExecutor) BeginAgain(ctx context.Context, dc *StatefulConnection) error {
   695  	if dc.IsClosed() || dc.TxProperties().Autocommit {
   696  		return nil
   697  	}
   698  	if _, err := dc.Exec(ctx, "commit", 1, false); err != nil {
   699  		return err
   700  	}
   701  	if _, err := dc.Exec(ctx, "begin", 1, false); err != nil {
   702  		return err
   703  	}
   704  	return nil
   705  }
   706  
   707  func (qre *QueryExecutor) execNextval() (*sqltypes.Result, error) {
   708  	env := evalengine.EnvWithBindVars(qre.bindVars, collations.Unknown)
   709  	result, err := env.Evaluate(qre.plan.NextCount)
   710  	if err != nil {
   711  		return nil, err
   712  	}
   713  	tableName := qre.plan.TableName()
   714  	v := result.Value()
   715  	inc, err := v.ToInt64()
   716  	if err != nil || inc < 1 {
   717  		return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "invalid increment for sequence %s: %s", tableName, v.String())
   718  	}
   719  
   720  	t := qre.plan.Table
   721  	t.SequenceInfo.Lock()
   722  	defer t.SequenceInfo.Unlock()
   723  	if t.SequenceInfo.NextVal == 0 || t.SequenceInfo.NextVal+inc > t.SequenceInfo.LastVal {
   724  		_, err := qre.execAsTransaction(func(conn *StatefulConnection) (*sqltypes.Result, error) {
   725  			query := fmt.Sprintf("select next_id, cache from %s where id = 0 for update", sqlparser.String(tableName))
   726  			qr, err := qre.execStatefulConn(conn, query, false)
   727  			if err != nil {
   728  				return nil, err
   729  			}
   730  			if len(qr.Rows) != 1 {
   731  				return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "unexpected rows from reading sequence %s (possible mis-route): %d", tableName, len(qr.Rows))
   732  			}
   733  			nextID, err := evalengine.ToInt64(qr.Rows[0][0])
   734  			if err != nil {
   735  				return nil, vterrors.Wrapf(err, "error loading sequence %s", tableName)
   736  			}
   737  			// If LastVal does not match next ID, then either:
   738  			// VTTablet just started, and we're initializing the cache, or
   739  			// Someone reset the id underneath us.
   740  			if t.SequenceInfo.LastVal != nextID {
   741  				if nextID < t.SequenceInfo.LastVal {
   742  					log.Warningf("Sequence next ID value %v is below the currently cached max %v, updating it to max", nextID, t.SequenceInfo.LastVal)
   743  					nextID = t.SequenceInfo.LastVal
   744  				}
   745  				t.SequenceInfo.NextVal = nextID
   746  				t.SequenceInfo.LastVal = nextID
   747  			}
   748  			cache, err := evalengine.ToInt64(qr.Rows[0][1])
   749  			if err != nil {
   750  				return nil, vterrors.Wrapf(err, "error loading sequence %s", tableName)
   751  			}
   752  			if cache < 1 {
   753  				return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "invalid cache value for sequence %s: %d", tableName, cache)
   754  			}
   755  			newLast := nextID + cache
   756  			for newLast < t.SequenceInfo.NextVal+inc {
   757  				newLast += cache
   758  			}
   759  			query = fmt.Sprintf("update %s set next_id = %d where id = 0", sqlparser.String(tableName), newLast)
   760  			conn.TxProperties().RecordQuery(query)
   761  			_, err = qre.execStatefulConn(conn, query, false)
   762  			if err != nil {
   763  				return nil, err
   764  			}
   765  			t.SequenceInfo.LastVal = newLast
   766  			return nil, nil
   767  		})
   768  		if err != nil {
   769  			return nil, err
   770  		}
   771  	}
   772  	ret := t.SequenceInfo.NextVal
   773  	t.SequenceInfo.NextVal += inc
   774  	return &sqltypes.Result{
   775  		Fields: sequenceFields,
   776  		Rows: [][]sqltypes.Value{{
   777  			sqltypes.NewInt64(ret),
   778  		}},
   779  	}, nil
   780  }
   781  
   782  // execSelect sends a query to mysql only if another identical query is not running. Otherwise, it waits and
   783  // reuses the result. If the plan is missing field info, it sends the query to mysql requesting full info.
   784  func (qre *QueryExecutor) execSelect() (*sqltypes.Result, error) {
   785  	sql, sqlWithoutComments, err := qre.generateFinalSQL(qre.plan.FullQuery, qre.bindVars)
   786  	if err != nil {
   787  		return nil, err
   788  	}
   789  	// Check tablet type.
   790  	if qre.shouldConsolidate() {
   791  		q, original := qre.tsv.qe.consolidator.Create(sqlWithoutComments)
   792  		if original {
   793  			defer q.Broadcast()
   794  			conn, err := qre.getConn()
   795  
   796  			if err != nil {
   797  				q.Err = err
   798  			} else {
   799  				defer conn.Recycle()
   800  				q.Result, q.Err = qre.execDBConn(conn, sql, true)
   801  			}
   802  		} else {
   803  			qre.logStats.QuerySources |= tabletenv.QuerySourceConsolidator
   804  			startTime := time.Now()
   805  			q.Wait()
   806  			qre.tsv.stats.WaitTimings.Record("Consolidations", startTime)
   807  		}
   808  		if q.Err != nil {
   809  			return nil, q.Err
   810  		}
   811  		return q.Result.(*sqltypes.Result), nil
   812  	}
   813  	conn, err := qre.getConn()
   814  	if err != nil {
   815  		return nil, err
   816  	}
   817  	defer conn.Recycle()
   818  	res, err := qre.execDBConn(conn, sql, true)
   819  	if err != nil {
   820  		return nil, err
   821  	}
   822  	return res, nil
   823  }
   824  
   825  func (qre *QueryExecutor) execDMLLimit(conn *StatefulConnection) (*sqltypes.Result, error) {
   826  	maxrows := qre.tsv.qe.maxResultSize.Get()
   827  	qre.bindVars["#maxLimit"] = sqltypes.Int64BindVariable(maxrows + 1)
   828  	result, err := qre.txFetch(conn, true)
   829  	if err != nil {
   830  		return nil, err
   831  	}
   832  	if err := qre.verifyRowCount(int64(result.RowsAffected), maxrows); err != nil {
   833  		defer qre.logStats.AddRewrittenSQL("rollback", time.Now())
   834  		_ = qre.tsv.te.txPool.Rollback(qre.ctx, conn)
   835  		return nil, err
   836  	}
   837  	return result, nil
   838  }
   839  
   840  func (qre *QueryExecutor) verifyRowCount(count, maxrows int64) error {
   841  	if count > maxrows {
   842  		callerID := callerid.ImmediateCallerIDFromContext(qre.ctx)
   843  		return vterrors.Errorf(vtrpcpb.Code_ABORTED, "caller id: %s: row count exceeded %d", callerID.Username, maxrows)
   844  	}
   845  	warnThreshold := qre.tsv.qe.warnResultSize.Get()
   846  	if warnThreshold > 0 && count > warnThreshold {
   847  		callerID := callerid.ImmediateCallerIDFromContext(qre.ctx)
   848  		qre.tsv.Stats().Warnings.Add("ResultsExceeded", 1)
   849  		log.Warningf("caller id: %s row count %v exceeds warning threshold %v: %q", callerID.Username, count, warnThreshold, queryAsString(qre.plan.FullQuery.Query, qre.bindVars, qre.tsv.Config().SanitizeLogMessages))
   850  	}
   851  	return nil
   852  }
   853  
   854  func (qre *QueryExecutor) execOther() (*sqltypes.Result, error) {
   855  	conn, err := qre.getConn()
   856  	if err != nil {
   857  		return nil, err
   858  	}
   859  	defer conn.Recycle()
   860  	return qre.execDBConn(conn, qre.query, true)
   861  }
   862  
   863  func (qre *QueryExecutor) getConn() (*connpool.DBConn, error) {
   864  	span, ctx := trace.NewSpan(qre.ctx, "QueryExecutor.getConn")
   865  	defer span.Finish()
   866  
   867  	start := time.Now()
   868  	conn, err := qre.tsv.qe.conns.Get(ctx, qre.setting)
   869  
   870  	switch err {
   871  	case nil:
   872  		qre.logStats.WaitingForConnection += time.Since(start)
   873  		return conn, nil
   874  	case connpool.ErrConnPoolClosed:
   875  		return nil, err
   876  	}
   877  	return nil, err
   878  }
   879  
   880  func (qre *QueryExecutor) getStreamConn() (*connpool.DBConn, error) {
   881  	span, ctx := trace.NewSpan(qre.ctx, "QueryExecutor.getStreamConn")
   882  	defer span.Finish()
   883  
   884  	start := time.Now()
   885  	conn, err := qre.tsv.qe.streamConns.Get(ctx, qre.setting)
   886  	switch err {
   887  	case nil:
   888  		qre.logStats.WaitingForConnection += time.Since(start)
   889  		return conn, nil
   890  	case connpool.ErrConnPoolClosed:
   891  		return nil, err
   892  	}
   893  	return nil, err
   894  }
   895  
   896  // txFetch fetches from a TxConnection.
   897  func (qre *QueryExecutor) txFetch(conn *StatefulConnection, record bool) (*sqltypes.Result, error) {
   898  	sql, _, err := qre.generateFinalSQL(qre.plan.FullQuery, qre.bindVars)
   899  	if err != nil {
   900  		return nil, err
   901  	}
   902  	qr, err := qre.execStatefulConn(conn, sql, true)
   903  	if err != nil {
   904  		return nil, err
   905  	}
   906  	// Only record successful queries.
   907  	if record {
   908  		conn.TxProperties().RecordQuery(sql)
   909  	}
   910  	return qr, nil
   911  }
   912  
   913  func (qre *QueryExecutor) generateFinalSQL(parsedQuery *sqlparser.ParsedQuery, bindVars map[string]*querypb.BindVariable) (string, string, error) {
   914  	query, err := parsedQuery.GenerateQuery(bindVars, nil)
   915  	if err != nil {
   916  		return "", "", vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "%s", err)
   917  	}
   918  	if qre.tsv.config.AnnotateQueries {
   919  		username := callerid.GetPrincipal(callerid.EffectiveCallerIDFromContext(qre.ctx))
   920  		if username == "" {
   921  			username = callerid.GetUsername(callerid.ImmediateCallerIDFromContext(qre.ctx))
   922  		}
   923  		var buf strings.Builder
   924  		tabletTypeStr := qre.tsv.sm.target.TabletType.String()
   925  		buf.Grow(8 + len(username) + len(tabletTypeStr))
   926  		buf.WriteString("/* ")
   927  		buf.WriteString(username)
   928  		buf.WriteString("@")
   929  		buf.WriteString(tabletTypeStr)
   930  		buf.WriteString(" */ ")
   931  		buf.WriteString(qre.marginComments.Leading)
   932  		qre.marginComments.Leading = buf.String()
   933  	}
   934  
   935  	if qre.marginComments.Leading == "" && qre.marginComments.Trailing == "" {
   936  		return query, query, nil
   937  	}
   938  
   939  	var buf strings.Builder
   940  	buf.Grow(len(qre.marginComments.Leading) + len(query) + len(qre.marginComments.Trailing))
   941  	buf.WriteString(qre.marginComments.Leading)
   942  	buf.WriteString(query)
   943  	buf.WriteString(qre.marginComments.Trailing)
   944  	return buf.String(), query, nil
   945  }
   946  
   947  func rewriteOUTParamError(err error) error {
   948  	sqlErr, ok := err.(*mysql.SQLError)
   949  	if !ok {
   950  		return err
   951  	}
   952  	if sqlErr.Num == mysql.ErSPNotVarArg {
   953  		return vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "OUT and INOUT parameters are not supported")
   954  	}
   955  	return err
   956  }
   957  
   958  func (qre *QueryExecutor) execCallProc() (*sqltypes.Result, error) {
   959  	conn, err := qre.getConn()
   960  	if err != nil {
   961  		return nil, err
   962  	}
   963  	defer conn.Recycle()
   964  	sql, _, err := qre.generateFinalSQL(qre.plan.FullQuery, qre.bindVars)
   965  	if err != nil {
   966  		return nil, err
   967  	}
   968  
   969  	qr, err := qre.execDBConn(conn, sql, true)
   970  	if err != nil {
   971  		return nil, rewriteOUTParamError(err)
   972  	}
   973  	if !qr.IsMoreResultsExists() {
   974  		if qr.IsInTransaction() {
   975  			conn.Close()
   976  			return nil, vterrors.New(vtrpcpb.Code_CANCELED, "Transaction not concluded inside the stored procedure, leaking transaction from stored procedure is not allowed")
   977  		}
   978  		return qr, nil
   979  	}
   980  	err = qre.drainResultSetOnConn(conn)
   981  	if err != nil {
   982  		return nil, err
   983  	}
   984  	return nil, vterrors.New(vtrpcpb.Code_UNIMPLEMENTED, "Multi-Resultset not supported in stored procedure")
   985  }
   986  
   987  func (qre *QueryExecutor) execProc(conn *StatefulConnection) (*sqltypes.Result, error) {
   988  	beforeInTx := conn.IsInTransaction()
   989  	sql, _, err := qre.generateFinalSQL(qre.plan.FullQuery, qre.bindVars)
   990  	if err != nil {
   991  		return nil, err
   992  	}
   993  	qr, err := qre.execStatefulConn(conn, sql, true)
   994  	if err != nil {
   995  		return nil, rewriteOUTParamError(err)
   996  	}
   997  	if !qr.IsMoreResultsExists() {
   998  		afterInTx := qr.IsInTransaction()
   999  		if beforeInTx != afterInTx {
  1000  			conn.Close()
  1001  			return nil, vterrors.New(vtrpcpb.Code_CANCELED, "Transaction state change inside the stored procedure is not allowed")
  1002  		}
  1003  		return qr, nil
  1004  	}
  1005  	err = qre.drainResultSetOnConn(conn.UnderlyingDBConn())
  1006  	if err != nil {
  1007  		return nil, err
  1008  	}
  1009  	return nil, vterrors.New(vtrpcpb.Code_UNIMPLEMENTED, "Multi-Resultset not supported in stored procedure")
  1010  }
  1011  
  1012  func (qre *QueryExecutor) execAlterMigration() (*sqltypes.Result, error) {
  1013  	alterMigration, ok := qre.plan.FullStmt.(*sqlparser.AlterMigration)
  1014  	if !ok {
  1015  		return nil, vterrors.New(vtrpcpb.Code_INTERNAL, "Expecting ALTER VITESS_MIGRATION plan")
  1016  	}
  1017  
  1018  	switch alterMigration.Type {
  1019  	case sqlparser.RetryMigrationType:
  1020  		return qre.tsv.onlineDDLExecutor.RetryMigration(qre.ctx, alterMigration.UUID)
  1021  	case sqlparser.CleanupMigrationType:
  1022  		return qre.tsv.onlineDDLExecutor.CleanupMigration(qre.ctx, alterMigration.UUID)
  1023  	case sqlparser.LaunchMigrationType:
  1024  		return qre.tsv.onlineDDLExecutor.LaunchMigration(qre.ctx, alterMigration.UUID, alterMigration.Shards)
  1025  	case sqlparser.LaunchAllMigrationType:
  1026  		return qre.tsv.onlineDDLExecutor.LaunchMigrations(qre.ctx)
  1027  	case sqlparser.CompleteMigrationType:
  1028  		return qre.tsv.onlineDDLExecutor.CompleteMigration(qre.ctx, alterMigration.UUID)
  1029  	case sqlparser.CompleteAllMigrationType:
  1030  		return qre.tsv.onlineDDLExecutor.CompletePendingMigrations(qre.ctx)
  1031  	case sqlparser.CancelMigrationType:
  1032  		return qre.tsv.onlineDDLExecutor.CancelMigration(qre.ctx, alterMigration.UUID, "CANCEL issued by user", true)
  1033  	case sqlparser.CancelAllMigrationType:
  1034  		return qre.tsv.onlineDDLExecutor.CancelPendingMigrations(qre.ctx, "CANCEL ALL issued by user", true)
  1035  	case sqlparser.ThrottleMigrationType:
  1036  		return qre.tsv.onlineDDLExecutor.ThrottleMigration(qre.ctx, alterMigration.UUID, alterMigration.Expire, alterMigration.Ratio)
  1037  	case sqlparser.ThrottleAllMigrationType:
  1038  		return qre.tsv.onlineDDLExecutor.ThrottleAllMigrations(qre.ctx, alterMigration.Expire, alterMigration.Ratio)
  1039  	case sqlparser.UnthrottleMigrationType:
  1040  		return qre.tsv.onlineDDLExecutor.UnthrottleMigration(qre.ctx, alterMigration.UUID)
  1041  	case sqlparser.UnthrottleAllMigrationType:
  1042  		return qre.tsv.onlineDDLExecutor.UnthrottleAllMigrations(qre.ctx)
  1043  	}
  1044  	return nil, vterrors.New(vtrpcpb.Code_UNIMPLEMENTED, "ALTER VITESS_MIGRATION not implemented")
  1045  }
  1046  
  1047  func (qre *QueryExecutor) execRevertMigration() (*sqltypes.Result, error) {
  1048  	if _, ok := qre.plan.FullStmt.(*sqlparser.RevertMigration); !ok {
  1049  		return nil, vterrors.New(vtrpcpb.Code_INTERNAL, "Expecting REVERT VITESS_MIGRATION plan")
  1050  	}
  1051  	return qre.tsv.onlineDDLExecutor.SubmitMigration(qre.ctx, qre.plan.FullStmt)
  1052  }
  1053  
  1054  func (qre *QueryExecutor) execShowMigrationLogs() (*sqltypes.Result, error) {
  1055  	if showMigrationLogsStmt, ok := qre.plan.FullStmt.(*sqlparser.ShowMigrationLogs); ok {
  1056  		return qre.tsv.onlineDDLExecutor.ShowMigrationLogs(qre.ctx, showMigrationLogsStmt)
  1057  	}
  1058  	return nil, vterrors.New(vtrpcpb.Code_INTERNAL, "Expecting SHOW VITESS_MIGRATION plan")
  1059  }
  1060  
  1061  func (qre *QueryExecutor) execShowThrottledApps() (*sqltypes.Result, error) {
  1062  	if err := qre.tsv.lagThrottler.CheckIsReady(); err != nil {
  1063  		return nil, err
  1064  	}
  1065  	if _, ok := qre.plan.FullStmt.(*sqlparser.ShowThrottledApps); !ok {
  1066  		return nil, vterrors.New(vtrpcpb.Code_INTERNAL, "Expecting SHOW VITESS_THROTTLED_APPS plan")
  1067  	}
  1068  	result := &sqltypes.Result{
  1069  		Fields: []*querypb.Field{
  1070  			{
  1071  				Name: "app",
  1072  				Type: sqltypes.VarChar,
  1073  			},
  1074  			{
  1075  				Name: "expire_at",
  1076  				Type: sqltypes.Timestamp,
  1077  			},
  1078  			{
  1079  				Name: "ratio",
  1080  				Type: sqltypes.Decimal,
  1081  			},
  1082  		},
  1083  		Rows: [][]sqltypes.Value{},
  1084  	}
  1085  	for _, t := range qre.tsv.lagThrottler.ThrottledApps() {
  1086  		result.Rows = append(result.Rows,
  1087  			[]sqltypes.Value{
  1088  				sqltypes.NewVarChar(t.AppName),
  1089  				sqltypes.NewTimestamp(t.ExpireAt.Format(sqltypes.TimestampFormat)),
  1090  				sqltypes.NewDecimal(fmt.Sprintf("%v", t.Ratio)),
  1091  			})
  1092  	}
  1093  	return result, nil
  1094  }
  1095  
  1096  func (qre *QueryExecutor) execShowThrottlerStatus() (*sqltypes.Result, error) {
  1097  	if _, ok := qre.plan.FullStmt.(*sqlparser.ShowThrottlerStatus); !ok {
  1098  		return nil, vterrors.New(vtrpcpb.Code_INTERNAL, "Expecting SHOW VITESS_THROTTLER STATUS plan")
  1099  	}
  1100  	var enabled int32
  1101  	if err := qre.tsv.lagThrottler.CheckIsReady(); err == nil {
  1102  		enabled = 1
  1103  	}
  1104  	result := &sqltypes.Result{
  1105  		Fields: []*querypb.Field{
  1106  			{
  1107  				Name: "shard",
  1108  				Type: sqltypes.VarChar,
  1109  			},
  1110  			{
  1111  				Name: "enabled",
  1112  				Type: sqltypes.Int32,
  1113  			},
  1114  			{
  1115  				Name: "threshold",
  1116  				Type: sqltypes.Float64,
  1117  			},
  1118  			{
  1119  				Name: "query",
  1120  				Type: sqltypes.VarChar,
  1121  			},
  1122  		},
  1123  		Rows: [][]sqltypes.Value{
  1124  			{
  1125  				sqltypes.NewVarChar(qre.tsv.sm.target.Shard),
  1126  				sqltypes.NewInt32(enabled),
  1127  				sqltypes.NewFloat64(qre.tsv.lagThrottler.MetricsThreshold.Get()),
  1128  				sqltypes.NewVarChar(qre.tsv.lagThrottler.GetMetricsQuery()),
  1129  			},
  1130  		},
  1131  	}
  1132  	return result, nil
  1133  }
  1134  
  1135  func (qre *QueryExecutor) drainResultSetOnConn(conn *connpool.DBConn) error {
  1136  	more := true
  1137  	for more {
  1138  		qr, err := conn.FetchNext(qre.ctx, int(qre.getSelectLimit()), true)
  1139  		if err != nil {
  1140  			return err
  1141  		}
  1142  		more = qr.IsMoreResultsExists()
  1143  	}
  1144  	return nil
  1145  }
  1146  
  1147  func (qre *QueryExecutor) getSelectLimit() int64 {
  1148  	return qre.tsv.qe.maxResultSize.Get()
  1149  }
  1150  
  1151  func (qre *QueryExecutor) execDBConn(conn *connpool.DBConn, sql string, wantfields bool) (*sqltypes.Result, error) {
  1152  	span, ctx := trace.NewSpan(qre.ctx, "QueryExecutor.execDBConn")
  1153  	defer span.Finish()
  1154  
  1155  	defer qre.logStats.AddRewrittenSQL(sql, time.Now())
  1156  
  1157  	qd := NewQueryDetail(qre.logStats.Ctx, conn)
  1158  	qre.tsv.statelessql.Add(qd)
  1159  	defer qre.tsv.statelessql.Remove(qd)
  1160  
  1161  	return conn.Exec(ctx, sql, int(qre.tsv.qe.maxResultSize.Get()), wantfields)
  1162  }
  1163  
  1164  func (qre *QueryExecutor) execStatefulConn(conn *StatefulConnection, sql string, wantfields bool) (*sqltypes.Result, error) {
  1165  	span, ctx := trace.NewSpan(qre.ctx, "QueryExecutor.execStatefulConn")
  1166  	defer span.Finish()
  1167  
  1168  	defer qre.logStats.AddRewrittenSQL(sql, time.Now())
  1169  
  1170  	qd := NewQueryDetail(qre.logStats.Ctx, conn)
  1171  	qre.tsv.statefulql.Add(qd)
  1172  	defer qre.tsv.statefulql.Remove(qd)
  1173  
  1174  	return conn.Exec(ctx, sql, int(qre.tsv.qe.maxResultSize.Get()), wantfields)
  1175  }
  1176  
  1177  func (qre *QueryExecutor) execStreamSQL(conn *connpool.DBConn, isTransaction bool, sql string, callback func(*sqltypes.Result) error) error {
  1178  	span, ctx := trace.NewSpan(qre.ctx, "QueryExecutor.execStreamSQL")
  1179  	trace.AnnotateSQL(span, sqlparser.Preview(sql))
  1180  	callBackClosingSpan := func(result *sqltypes.Result) error {
  1181  		defer span.Finish()
  1182  		return callback(result)
  1183  	}
  1184  
  1185  	start := time.Now()
  1186  	defer qre.logStats.AddRewrittenSQL(sql, start)
  1187  
  1188  	// Add query detail object into QueryExecutor TableServer list w.r.t if it is a transactional or not. Previously we were adding it
  1189  	// to olapql list regardless but that resulted in problems, where long-running stream queries which can be stateful (or transactional)
  1190  	// weren't getting cleaned up during unserveCommon>handleShutdownGracePeriod in state_manager.go.
  1191  	// This change will ensure that long-running streaming stateful queries get gracefully shutdown during ServingTypeChange
  1192  	// once their grace period is over.
  1193  	qd := NewQueryDetail(qre.logStats.Ctx, conn)
  1194  	if isTransaction {
  1195  		qre.tsv.statefulql.Add(qd)
  1196  		defer qre.tsv.statefulql.Remove(qd)
  1197  		return conn.StreamOnce(ctx, sql, callBackClosingSpan, allocStreamResult, int(qre.tsv.qe.streamBufferSize.Get()), sqltypes.IncludeFieldsOrDefault(qre.options))
  1198  	}
  1199  	qre.tsv.olapql.Add(qd)
  1200  	defer qre.tsv.olapql.Remove(qd)
  1201  	return conn.Stream(ctx, sql, callBackClosingSpan, allocStreamResult, int(qre.tsv.qe.streamBufferSize.Get()), sqltypes.IncludeFieldsOrDefault(qre.options))
  1202  }
  1203  
  1204  func (qre *QueryExecutor) recordUserQuery(queryType string, duration int64) {
  1205  	username := callerid.GetPrincipal(callerid.EffectiveCallerIDFromContext(qre.ctx))
  1206  	if username == "" {
  1207  		username = callerid.GetUsername(callerid.ImmediateCallerIDFromContext(qre.ctx))
  1208  	}
  1209  	tableName := qre.plan.TableName().String()
  1210  	qre.tsv.Stats().UserTableQueryCount.Add([]string{tableName, username, queryType}, 1)
  1211  	qre.tsv.Stats().UserTableQueryTimesNs.Add([]string{tableName, username, queryType}, duration)
  1212  }
  1213  
  1214  func generateBindVarsForViewDDLInsert(createView *sqlparser.CreateView) map[string]*querypb.BindVariable {
  1215  	bindVars := make(map[string]*querypb.BindVariable)
  1216  	bindVars["table_name"] = sqltypes.StringBindVariable(createView.ViewName.Name.String())
  1217  	bindVars["create_statement"] = sqltypes.StringBindVariable(sqlparser.String(createView))
  1218  	return bindVars
  1219  }
  1220  
  1221  func (qre *QueryExecutor) GetSchemaDefinitions(tableType querypb.SchemaTableType, tableNames []string, callback func(schemaRes *querypb.GetSchemaResponse) error) error {
  1222  	switch tableType {
  1223  	case querypb.SchemaTableType_VIEWS:
  1224  		return qre.getViewDefinitions(tableNames, callback)
  1225  	}
  1226  	return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "invalid table type %v", tableType)
  1227  }
  1228  
  1229  func (qre *QueryExecutor) getViewDefinitions(viewNames []string, callback func(schemaRes *querypb.GetSchemaResponse) error) error {
  1230  	query := mysql.FetchViews
  1231  	var bindVars map[string]*querypb.BindVariable
  1232  	if len(viewNames) > 0 {
  1233  		query = mysql.FetchUpdatedViews
  1234  		bindVars = map[string]*querypb.BindVariable{
  1235  			"viewnames": sqltypes.StringBindVariable(strings.Join(viewNames, ",")),
  1236  		}
  1237  	}
  1238  	return qre.generateFinalQueryAndStreamExecute(query, bindVars, func(result *sqltypes.Result) error {
  1239  		schemaDef := make(map[string]string)
  1240  		for _, row := range result.Rows {
  1241  			schemaDef[row[0].ToString()] = row[1].ToString()
  1242  		}
  1243  		return callback(&querypb.GetSchemaResponse{TableDefinition: schemaDef})
  1244  	})
  1245  }
  1246  
  1247  func (qre *QueryExecutor) generateFinalQueryAndStreamExecute(query string, bindVars map[string]*querypb.BindVariable, callback func(result *sqltypes.Result) error) error {
  1248  	sql := query
  1249  	if len(bindVars) > 0 {
  1250  		stmt, err := sqlparser.Parse(query)
  1251  		if err != nil {
  1252  			return err
  1253  		}
  1254  		sql, _, err = qre.generateFinalSQL(sqlparser.NewParsedQuery(stmt), bindVars)
  1255  		if err != nil {
  1256  			return err
  1257  		}
  1258  	}
  1259  
  1260  	conn, err := qre.getStreamConn()
  1261  	if err != nil {
  1262  		return err
  1263  	}
  1264  	defer conn.Recycle()
  1265  
  1266  	return qre.execStreamSQL(conn, false /* isTransaction */, sql, callback)
  1267  }