github.com/matrixorigin/matrixone@v1.2.0/pkg/frontend/back_exec.go (about)

     1  // Copyright 2022 Matrix Origin
     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 frontend
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"strings"
    21  	"time"
    22  
    23  	"github.com/matrixorigin/matrixone/pkg/pb/timestamp"
    24  	"github.com/matrixorigin/matrixone/pkg/sql/compile"
    25  
    26  	"github.com/google/uuid"
    27  
    28  	"github.com/matrixorigin/matrixone/pkg/common/buffer"
    29  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    30  	"github.com/matrixorigin/matrixone/pkg/common/mpool"
    31  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    32  	"github.com/matrixorigin/matrixone/pkg/defines"
    33  	"github.com/matrixorigin/matrixone/pkg/logutil"
    34  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    35  	"github.com/matrixorigin/matrixone/pkg/sql/parsers"
    36  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect/mysql"
    37  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
    38  	plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan"
    39  	"github.com/matrixorigin/matrixone/pkg/util/trace"
    40  	"github.com/matrixorigin/matrixone/pkg/util/trace/impl/motrace"
    41  	"github.com/matrixorigin/matrixone/pkg/vm/engine"
    42  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    43  )
    44  
    45  type backExec struct {
    46  	backSes *backSession
    47  }
    48  
    49  func (back *backExec) Close() {
    50  	back.Clear()
    51  	back.backSes.Close()
    52  	back.backSes.Clear()
    53  	back.backSes = nil
    54  }
    55  
    56  func (back *backExec) Exec(ctx context.Context, sql string) error {
    57  	if ctx == nil {
    58  		return moerr.NewInternalError(context.Background(), "context is nil")
    59  	}
    60  	_, err := defines.GetAccountId(ctx)
    61  	if err != nil {
    62  		return err
    63  	}
    64  
    65  	// For determine this is a background sql.
    66  	ctx = context.WithValue(ctx, defines.BgKey{}, true)
    67  	//logutil.Debugf("-->bh:%s", sql)
    68  	v, err := back.backSes.GetGlobalVar(ctx, "lower_case_table_names")
    69  	if err != nil {
    70  		return err
    71  	}
    72  	statements, err := mysql.Parse(ctx, sql, v.(int64), 0)
    73  	if err != nil {
    74  		return err
    75  	}
    76  	defer func() {
    77  		for _, stmt := range statements {
    78  			stmt.Free()
    79  		}
    80  	}()
    81  	if len(statements) > 1 {
    82  		return moerr.NewInternalError(ctx, "Exec() can run one statement at one time. but get '%d' statements now, sql = %s", len(statements), sql)
    83  	}
    84  	//share txn can not run transaction statement
    85  	if back.backSes.GetTxnHandler().IsShareTxn() {
    86  		for _, stmt := range statements {
    87  			switch stmt.(type) {
    88  			case *tree.BeginTransaction, *tree.CommitTransaction, *tree.RollbackTransaction:
    89  				return moerr.NewInternalError(ctx, "Exec() can not run transaction statement in share transaction, sql = %s", sql)
    90  			}
    91  		}
    92  	}
    93  	execCtx := ExecCtx{
    94  		reqCtx: ctx,
    95  		ses:    back.backSes,
    96  	}
    97  	return doComQueryInBack(back.backSes, &execCtx, &UserInput{sql: sql})
    98  }
    99  
   100  func (back *backExec) ExecRestore(ctx context.Context, sql string, opAccount uint32, toAccount uint32) error {
   101  	if ctx == nil {
   102  		return moerr.NewInternalError(context.Background(), "context is nil")
   103  	}
   104  	_, err := defines.GetAccountId(ctx)
   105  	if err != nil {
   106  		return err
   107  	}
   108  
   109  	// For determine this is a background sql.
   110  	ctx = context.WithValue(ctx, defines.BgKey{}, true)
   111  	//logutil.Debugf("-->bh:%s", sql)
   112  	v, err := back.backSes.GetGlobalVar(ctx, "lower_case_table_names")
   113  	if err != nil {
   114  		return err
   115  	}
   116  	statements, err := mysql.Parse(ctx, sql, v.(int64), 0)
   117  	if err != nil {
   118  		return err
   119  	}
   120  	defer func() {
   121  		for _, stmt := range statements {
   122  			stmt.Free()
   123  		}
   124  	}()
   125  	if len(statements) > 1 {
   126  		return moerr.NewInternalError(ctx, "Exec() can run one statement at one time. but get '%d' statements now, sql = %s", len(statements), sql)
   127  	}
   128  	//share txn can not run transaction statement
   129  	if back.backSes.GetTxnHandler().IsShareTxn() {
   130  		for _, stmt := range statements {
   131  			switch stmt.(type) {
   132  			case *tree.BeginTransaction, *tree.CommitTransaction, *tree.RollbackTransaction:
   133  				return moerr.NewInternalError(ctx, "Exec() can not run transaction statement in share transaction, sql = %s", sql)
   134  			}
   135  		}
   136  	}
   137  
   138  	userInput := &UserInput{
   139  		sql:       sql,
   140  		isRestore: true,
   141  		opAccount: opAccount,
   142  		toAccount: toAccount,
   143  	}
   144  
   145  	execCtx := ExecCtx{
   146  		reqCtx: ctx,
   147  		ses:    back.backSes,
   148  	}
   149  	return doComQueryInBack(back.backSes, &execCtx, userInput)
   150  }
   151  
   152  func (back *backExec) ExecStmt(ctx context.Context, statement tree.Statement) error {
   153  	return nil
   154  }
   155  
   156  func (back *backExec) GetExecResultSet() []interface{} {
   157  	mrs := back.backSes.allResultSet
   158  	ret := make([]interface{}, len(mrs))
   159  	for i, mr := range mrs {
   160  		ret[i] = mr
   161  	}
   162  	return ret
   163  }
   164  
   165  func (back *backExec) ClearExecResultSet() {
   166  	back.backSes.allResultSet = nil
   167  }
   168  
   169  func (back *backExec) GetExecResultBatches() []*batch.Batch {
   170  	return back.backSes.resultBatches
   171  }
   172  
   173  func (back *backExec) ClearExecResultBatches() {
   174  	back.backSes.resultBatches = nil
   175  }
   176  
   177  func (back *backExec) Clear() {
   178  	back.backSes.Clear()
   179  }
   180  
   181  // execute query
   182  func doComQueryInBack(backSes *backSession, execCtx *ExecCtx,
   183  	input *UserInput) (retErr error) {
   184  	backSes.GetTxnCompileCtx().SetExecCtx(execCtx)
   185  	backSes.SetSql(input.getSql())
   186  	//the ses.GetUserName returns the user_name with the account_name.
   187  	//here,we only need the user_name.
   188  	userNameOnly := rootName
   189  	proc := process.New(
   190  		execCtx.reqCtx,
   191  		backSes.pool,
   192  		getGlobalPu().TxnClient,
   193  		nil,
   194  		getGlobalPu().FileService,
   195  		getGlobalPu().LockService,
   196  		getGlobalPu().QueryClient,
   197  		getGlobalPu().HAKeeperClient,
   198  		getGlobalPu().UdfService,
   199  		getGlobalAic())
   200  	proc.Id = backSes.getNextProcessId()
   201  	proc.Lim.Size = getGlobalPu().SV.ProcessLimitationSize
   202  	proc.Lim.BatchRows = getGlobalPu().SV.ProcessLimitationBatchRows
   203  	proc.Lim.MaxMsgSize = getGlobalPu().SV.MaxMessageSize
   204  	proc.Lim.PartitionRows = getGlobalPu().SV.ProcessLimitationPartitionRows
   205  	proc.SessionInfo = process.SessionInfo{
   206  		User:          backSes.proto.GetUserName(),
   207  		Host:          getGlobalPu().SV.Host,
   208  		Database:      backSes.proto.GetDatabaseName(),
   209  		Version:       makeServerVersion(getGlobalPu(), serverVersion.Load().(string)),
   210  		TimeZone:      backSes.GetTimeZone(),
   211  		StorageEngine: getGlobalPu().StorageEngine,
   212  		Buf:           backSes.buf,
   213  	}
   214  	proc.SetStmtProfile(&backSes.stmtProfile)
   215  	proc.SetResolveVariableFunc(backSes.txnCompileCtx.ResolveVariable)
   216  	//!!!does not init sequence in the background exec
   217  	if backSes.tenant != nil {
   218  		proc.SessionInfo.Account = backSes.tenant.GetTenant()
   219  		proc.SessionInfo.AccountId = backSes.tenant.GetTenantID()
   220  		proc.SessionInfo.Role = backSes.tenant.GetDefaultRole()
   221  		proc.SessionInfo.RoleId = backSes.tenant.GetDefaultRoleID()
   222  		proc.SessionInfo.UserId = backSes.tenant.GetUserID()
   223  
   224  		if len(backSes.tenant.GetVersion()) != 0 {
   225  			proc.SessionInfo.Version = backSes.tenant.GetVersion()
   226  		}
   227  		userNameOnly = backSes.tenant.GetUser()
   228  	} else {
   229  		var accountId uint32
   230  		accountId, retErr = defines.GetAccountId(execCtx.reqCtx)
   231  		if retErr != nil {
   232  			return retErr
   233  		}
   234  		proc.SessionInfo.AccountId = accountId
   235  		proc.SessionInfo.UserId = defines.GetUserId(execCtx.reqCtx)
   236  		proc.SessionInfo.RoleId = defines.GetRoleId(execCtx.reqCtx)
   237  	}
   238  	var span trace.Span
   239  	execCtx.reqCtx, span = trace.Start(execCtx.reqCtx, "backExec.doComQueryInBack",
   240  		trace.WithKind(trace.SpanKindStatement))
   241  	defer span.End()
   242  	execCtx.input = input
   243  
   244  	proc.SessionInfo.User = userNameOnly
   245  	cws, err := GetComputationWrapperInBack(execCtx, backSes.proto.GetDatabaseName(),
   246  		input,
   247  		backSes.proto.GetUserName(),
   248  		getGlobalPu().StorageEngine,
   249  		proc, backSes)
   250  
   251  	if err != nil {
   252  		retErr = err
   253  		if _, ok := err.(*moerr.Error); !ok {
   254  			retErr = moerr.NewParseError(execCtx.reqCtx, err.Error())
   255  		}
   256  		return retErr
   257  	}
   258  
   259  	defer func() {
   260  		backSes.SetMysqlResultSet(nil)
   261  	}()
   262  
   263  	defer func() {
   264  		execCtx.stmt = nil
   265  		execCtx.cw = nil
   266  		execCtx.cws = nil
   267  		for i := 0; i < len(cws); i++ {
   268  			cws[i].Free()
   269  		}
   270  	}()
   271  
   272  	sqlRecord := parsers.HandleSqlForRecord(input.getSql())
   273  
   274  	for i, cw := range cws {
   275  		backSes.mrs = &MysqlResultSet{}
   276  		stmt := cw.GetAst()
   277  
   278  		if insertStmt, ok := stmt.(*tree.Insert); ok && input.isRestore {
   279  			insertStmt.IsRestore = true
   280  			insertStmt.FromDataTenantID = input.opAccount
   281  		}
   282  
   283  		tenant := backSes.GetTenantNameWithStmt(stmt)
   284  
   285  		/*
   286  				if it is in an active or multi-statement transaction, we check the type of the statement.
   287  				Then we decide that if we can execute the statement.
   288  
   289  			If we check the active transaction, it will generate the case below.
   290  			case:
   291  			set autocommit = 0;  <- no active transaction
   292  			                     <- no active transaction
   293  			drop table test1;    <- no active transaction, no error
   294  			                     <- has active transaction
   295  			drop table test1;    <- has active transaction, error
   296  			                     <- has active transaction
   297  		*/
   298  		if backSes.GetTxnHandler().InActiveTxn() {
   299  			err = canExecuteStatementInUncommittedTransaction(execCtx.reqCtx, backSes, stmt)
   300  			if err != nil {
   301  				return err
   302  			}
   303  		}
   304  
   305  		execCtx.stmt = stmt
   306  		execCtx.isLastStmt = i >= len(cws)-1
   307  		execCtx.tenant = tenant
   308  		execCtx.userName = userNameOnly
   309  		execCtx.sqlOfStmt = sqlRecord[i]
   310  		execCtx.cw = cw
   311  		execCtx.proc = proc
   312  		execCtx.ses = backSes
   313  		execCtx.cws = cws
   314  		err = executeStmtWithTxn(backSes, execCtx)
   315  		if err != nil {
   316  			return err
   317  		}
   318  	} // end of for
   319  
   320  	return nil
   321  }
   322  
   323  func executeStmtInBack(backSes *backSession,
   324  	execCtx *ExecCtx,
   325  ) (err error) {
   326  	var cmpBegin time.Time
   327  	var ret interface{}
   328  
   329  	switch execCtx.stmt.StmtKind().ExecLocation() {
   330  	case tree.EXEC_IN_FRONTEND:
   331  		return execInFrontendInBack(backSes, execCtx)
   332  	case tree.EXEC_IN_ENGINE:
   333  	}
   334  
   335  	switch st := execCtx.stmt.(type) {
   336  	case *tree.CreateDatabase:
   337  		err = inputNameIsInvalid(execCtx.reqCtx, string(st.Name))
   338  		if err != nil {
   339  			return
   340  		}
   341  		if st.SubscriptionOption != nil && backSes.tenant != nil && !backSes.tenant.IsAdminRole() {
   342  			err = moerr.NewInternalError(execCtx.reqCtx, "only admin can create subscription")
   343  			return
   344  		}
   345  		st.Sql = execCtx.sqlOfStmt
   346  	case *tree.DropDatabase:
   347  		err = inputNameIsInvalid(execCtx.reqCtx, string(st.Name))
   348  		if err != nil {
   349  			return
   350  		}
   351  		// if the droped database is the same as the one in use, database must be reseted to empty.
   352  		if string(st.Name) == backSes.GetDatabaseName() {
   353  			backSes.SetDatabaseName("")
   354  		}
   355  	}
   356  
   357  	cmpBegin = time.Now()
   358  
   359  	if ret, err = execCtx.cw.Compile(execCtx, backSes.GetOutputCallback(execCtx)); err != nil {
   360  		return
   361  	}
   362  
   363  	defer func() {
   364  		if c, ok := ret.(*compile.Compile); ok {
   365  			c.Release()
   366  		}
   367  	}()
   368  
   369  	// cw.Compile may rewrite the stmt in the EXECUTE statement, we fetch the latest version
   370  	//need to check again.
   371  	execCtx.stmt = execCtx.cw.GetAst()
   372  	switch execCtx.stmt.StmtKind().ExecLocation() {
   373  	case tree.EXEC_IN_FRONTEND:
   374  		return execInFrontendInBack(backSes, execCtx)
   375  	case tree.EXEC_IN_ENGINE:
   376  
   377  	}
   378  
   379  	execCtx.runner = ret.(ComputationRunner)
   380  
   381  	// only log if build time is longer than 1s
   382  	if time.Since(cmpBegin) > time.Second {
   383  		logInfo(backSes, backSes.GetDebugString(), fmt.Sprintf("time of Exec.Build : %s", time.Since(cmpBegin).String()))
   384  	}
   385  
   386  	StmtKind := execCtx.stmt.StmtKind().OutputType()
   387  	switch StmtKind {
   388  	case tree.OUTPUT_RESULT_ROW:
   389  		err = executeResultRowStmtInBack(backSes, execCtx)
   390  		if err != nil {
   391  			return err
   392  		}
   393  	case tree.OUTPUT_STATUS:
   394  		err = executeStatusStmtInBack(backSes, execCtx)
   395  		if err != nil {
   396  			return err
   397  		}
   398  	case tree.OUTPUT_UNDEFINED:
   399  		isExecute := false
   400  		switch execCtx.stmt.(type) {
   401  		case *tree.Execute:
   402  			isExecute = true
   403  		}
   404  		if !isExecute {
   405  			return moerr.NewInternalError(execCtx.reqCtx, "need set result type for %s", execCtx.sqlOfStmt)
   406  		}
   407  	}
   408  
   409  	return
   410  }
   411  
   412  var GetComputationWrapperInBack = func(execCtx *ExecCtx, db string, input *UserInput, user string, eng engine.Engine, proc *process.Process, ses FeSession) ([]ComputationWrapper, error) {
   413  	var cw []ComputationWrapper = nil
   414  
   415  	var stmts []tree.Statement = nil
   416  	var cmdFieldStmt *InternalCmdFieldList
   417  	var err error
   418  	// if the input is an option ast, we should use it directly
   419  	if input.getStmt() != nil {
   420  		stmts = append(stmts, input.getStmt())
   421  	} else if isCmdFieldListSql(input.getSql()) {
   422  		cmdFieldStmt, err = parseCmdFieldList(execCtx.reqCtx, input.getSql())
   423  		if err != nil {
   424  			return nil, err
   425  		}
   426  		stmts = append(stmts, cmdFieldStmt)
   427  	} else {
   428  		stmts, err = parseSql(execCtx)
   429  		if err != nil {
   430  			return nil, err
   431  		}
   432  	}
   433  
   434  	for _, stmt := range stmts {
   435  		cw = append(cw, InitTxnComputationWrapper(ses, stmt, proc))
   436  	}
   437  	return cw, nil
   438  }
   439  
   440  var NewBackgroundExec = func(
   441  	reqCtx context.Context,
   442  	upstream FeSession,
   443  	mp *mpool.MPool) BackgroundExec {
   444  	txnHandler := InitTxnHandler(getGlobalPu().StorageEngine, upstream.GetTxnHandler().GetConnCtx(), nil)
   445  	backSes := &backSession{
   446  		feSessionImpl: feSessionImpl{
   447  			pool:           mp,
   448  			proto:          &FakeProtocol{},
   449  			buf:            buffer.New(),
   450  			stmtProfile:    process.StmtProfile{},
   451  			tenant:         nil,
   452  			txnHandler:     txnHandler,
   453  			txnCompileCtx:  InitTxnCompilerContext(""),
   454  			mrs:            nil,
   455  			outputCallback: fakeDataSetFetcher2,
   456  			allResultSet:   nil,
   457  			resultBatches:  nil,
   458  			derivedStmt:    false,
   459  			gSysVars:       GSysVariables,
   460  			label:          make(map[string]string),
   461  			timeZone:       time.Local,
   462  		},
   463  	}
   464  	backSes.uuid, _ = uuid.NewV7()
   465  	bh := &backExec{
   466  		backSes: backSes,
   467  	}
   468  
   469  	return bh
   470  }
   471  
   472  // executeSQLInBackgroundSession executes the sql in an independent session and transaction.
   473  // It sends nothing to the client.
   474  func executeSQLInBackgroundSession(reqCtx context.Context, upstream *Session, mp *mpool.MPool, sql string) ([]ExecResult, error) {
   475  	bh := NewBackgroundExec(reqCtx, upstream, mp)
   476  	defer bh.Close()
   477  	logutil.Debugf("background exec sql:%v", sql)
   478  	err := bh.Exec(reqCtx, sql)
   479  	logutil.Debugf("background exec sql done")
   480  	if err != nil {
   481  		return nil, err
   482  	}
   483  	return getResultSet(reqCtx, bh)
   484  }
   485  
   486  // executeStmtInSameSession executes the statement in the same session.
   487  // To be clear, only for the select statement derived from the set_var statement
   488  // in an independent transaction
   489  func executeStmtInSameSession(ctx context.Context, ses *Session, execCtx *ExecCtx, stmt tree.Statement) error {
   490  	switch stmt.(type) {
   491  	case *tree.Select, *tree.ParenSelect:
   492  	default:
   493  		return moerr.NewInternalError(ctx, "executeStmtInSameSession can not run non select statement in the same session")
   494  	}
   495  
   496  	if ses.GetTxnHandler() == nil {
   497  		panic("need txn handler 3")
   498  	}
   499  
   500  	prevDB := ses.GetDatabaseName()
   501  	prevOptionBits := ses.GetTxnHandler().GetOptionBits()
   502  	prevServerStatus := ses.GetTxnHandler().GetServerStatus()
   503  	//autocommit = on
   504  	ses.GetTxnHandler().setAutocommitOn()
   505  	//1. replace output callback by batchFetcher.
   506  	// the result batch will be saved in the session.
   507  	// you can get the result batch by calling GetResultBatches()
   508  	ses.SetOutputCallback(batchFetcher)
   509  	//2. replace protocol by FakeProtocol.
   510  	// Any response yielded during running query will be dropped by the FakeProtocol.
   511  	// The client will not receive any response from the FakeProtocol.
   512  	prevProto := ses.ReplaceProtocol(&FakeProtocol{})
   513  	//3. replace the derived stmt
   514  	prevDerivedStmt := ses.ReplaceDerivedStmt(true)
   515  	// inherit database
   516  	ses.SetDatabaseName(prevDB)
   517  	proc := ses.GetTxnCompileCtx().GetProcess()
   518  	//restore normal protocol and output callback
   519  	defer func() {
   520  		ses.ReplaceDerivedStmt(prevDerivedStmt)
   521  		//@todo we need to improve: make one session, one proc, one txnOperator
   522  		p := ses.GetTxnCompileCtx().GetProcess()
   523  		p.FreeVectors()
   524  		execCtx.proc = proc
   525  		ses.GetTxnHandler().SetOptionBits(prevOptionBits)
   526  		ses.GetTxnHandler().SetServerStatus(prevServerStatus)
   527  		ses.SetOutputCallback(getDataFromPipeline)
   528  		ses.ReplaceProtocol(prevProto)
   529  		if ses.GetTxnHandler() == nil {
   530  			panic("need txn handler 4")
   531  		}
   532  	}()
   533  	logDebug(ses, ses.GetDebugString(), "query trace(ExecStmtInSameSession)",
   534  		logutil.ConnectionIdField(ses.GetConnectionID()))
   535  	//3. execute the statement
   536  	return doComQuery(ses, execCtx, &UserInput{stmt: stmt})
   537  }
   538  
   539  // fakeDataSetFetcher2 gets the result set from the pipeline and save it in the session.
   540  // It will not send the result to the client.
   541  func fakeDataSetFetcher2(handle FeSession, execCtx *ExecCtx, dataSet *batch.Batch) error {
   542  	if handle == nil || dataSet == nil {
   543  		return nil
   544  	}
   545  
   546  	back := handle.(*backSession)
   547  	oq := newFakeOutputQueue(back.mrs)
   548  	err := fillResultSet(execCtx.reqCtx, oq, dataSet, back)
   549  	if err != nil {
   550  		return err
   551  	}
   552  	back.SetMysqlResultSetOfBackgroundTask(back.mrs)
   553  	return nil
   554  }
   555  
   556  func fillResultSet(ctx context.Context, oq outputPool, dataSet *batch.Batch, ses FeSession) error {
   557  	n := dataSet.RowCount()
   558  	for j := 0; j < n; j++ { //row index
   559  		//needCopyBytes = true. we need to copy the bytes from the batch.Batch
   560  		//to avoid the data being changed after the batch.Batch returned to the
   561  		//pipeline.
   562  		_, err := extractRowFromEveryVector(ctx, ses, dataSet, j, oq, true)
   563  		if err != nil {
   564  			return err
   565  		}
   566  	}
   567  	return oq.flush()
   568  }
   569  
   570  // batchFetcher2 gets the result batches from the pipeline and save the origin batches in the session.
   571  // It will not send the result to the client.
   572  func batchFetcher2(handle FeSession, _ *ExecCtx, dataSet *batch.Batch) error {
   573  	if handle == nil {
   574  		return nil
   575  	}
   576  	back := handle.(*backSession)
   577  	back.SaveResultSet()
   578  	if dataSet == nil {
   579  		return nil
   580  	}
   581  	return back.AppendResultBatch(dataSet)
   582  }
   583  
   584  // batchFetcher gets the result batches from the pipeline and save the origin batches in the session.
   585  // It will not send the result to the client.
   586  func batchFetcher(handle FeSession, _ *ExecCtx, dataSet *batch.Batch) error {
   587  	if handle == nil {
   588  		return nil
   589  	}
   590  	ses := handle.(*Session)
   591  	ses.SaveResultSet()
   592  	if dataSet == nil {
   593  		return nil
   594  	}
   595  	return ses.AppendResultBatch(dataSet)
   596  }
   597  
   598  // getResultSet extracts the result set
   599  func getResultSet(ctx context.Context, bh BackgroundExec) ([]ExecResult, error) {
   600  	results := bh.GetExecResultSet()
   601  	rsset := make([]ExecResult, len(results))
   602  	for i, value := range results {
   603  		if er, ok := value.(ExecResult); ok {
   604  			rsset[i] = er
   605  		} else {
   606  			return nil, moerr.NewInternalError(ctx, "it is not the type of result set")
   607  		}
   608  	}
   609  	return rsset, nil
   610  }
   611  
   612  type backSession struct {
   613  	feSessionImpl
   614  }
   615  
   616  func (backSes *backSession) getCachedPlan(sql string) *cachedPlan {
   617  	return nil
   618  }
   619  
   620  func (backSes *backSession) Close() {
   621  	backSes.feSessionImpl.Close()
   622  }
   623  
   624  func (backSes *backSession) Clear() {
   625  	backSes.feSessionImpl.Clear()
   626  }
   627  
   628  func (backSes *backSession) GetOutputCallback(execCtx *ExecCtx) func(*batch.Batch) error {
   629  	return func(bat *batch.Batch) error {
   630  		return backSes.outputCallback(backSes, execCtx, bat)
   631  	}
   632  }
   633  
   634  func (backSes *backSession) SetTStmt(stmt *motrace.StatementInfo) {
   635  
   636  }
   637  func (backSes *backSession) SendRows() int64 {
   638  	return 0
   639  }
   640  
   641  func (backSes *backSession) GetTxnInfo() string {
   642  	txnH := backSes.GetTxnHandler()
   643  	if txnH == nil {
   644  		return ""
   645  	}
   646  	txnOp := txnH.GetTxn()
   647  	if txnOp == nil {
   648  		return ""
   649  	}
   650  	meta := txnOp.Txn()
   651  	return meta.DebugString()
   652  }
   653  
   654  func (backSes *backSession) GetStmtInfo() *motrace.StatementInfo {
   655  	return nil
   656  }
   657  
   658  func (backSes *backSession) getNextProcessId() string {
   659  	/*
   660  		temporary method:
   661  		routineId + sqlCount
   662  	*/
   663  	routineId := backSes.GetMysqlProtocol().ConnectionID()
   664  	return fmt.Sprintf("%d%d", routineId, backSes.GetSqlCount())
   665  }
   666  
   667  func (backSes *backSession) cleanCache() {
   668  }
   669  
   670  func (backSes *backSession) GetUpstream() FeSession {
   671  	return backSes.upstream
   672  }
   673  
   674  func (backSes *backSession) getCNLabels() map[string]string {
   675  	return backSes.label
   676  }
   677  
   678  func (backSes *backSession) SetData(i [][]interface{}) {
   679  
   680  }
   681  
   682  func (backSes *backSession) GetIsInternal() bool {
   683  	return false
   684  }
   685  
   686  func (backSes *backSession) SetPlan(plan *plan.Plan) {
   687  }
   688  
   689  func (backSes *backSession) GetRawBatchBackgroundExec(ctx context.Context) BackgroundExec {
   690  	//TODO implement me
   691  	panic("implement me")
   692  }
   693  
   694  func (backSes *backSession) GetConnectionID() uint32 {
   695  	return 0
   696  }
   697  
   698  func (backSes *backSession) getQueryId(internal bool) []string {
   699  	return nil
   700  }
   701  
   702  func (backSes *backSession) CopySeqToProc(proc *process.Process) {
   703  
   704  }
   705  
   706  func (backSes *backSession) GetSqlHelper() *SqlHelper {
   707  	return nil
   708  }
   709  
   710  func (backSes *backSession) GetProc() *process.Process {
   711  	return nil
   712  }
   713  
   714  func (backSes *backSession) GetLastInsertID() uint64 {
   715  	return 0
   716  }
   717  
   718  func (backSes *backSession) SetShowStmtType(statement ShowStatementType) {
   719  }
   720  
   721  func (backSes *backSession) RemovePrepareStmt(name string) {
   722  
   723  }
   724  
   725  func (backSes *backSession) CountPayload(i int) {
   726  
   727  }
   728  
   729  func (backSes *backSession) GetPrepareStmt(ctx context.Context, name string) (*PrepareStmt, error) {
   730  	return nil, moerr.NewInternalError(ctx, "do not support prepare in background exec")
   731  }
   732  
   733  func (backSes *backSession) IsBackgroundSession() bool {
   734  	return true
   735  }
   736  
   737  func (backSes *backSession) GetCmd() CommandType {
   738  	return COM_QUERY
   739  }
   740  
   741  func (backSes *backSession) SetNewResponse(category int, affectedRows uint64, cmd int, d interface{}, isLastStmt bool) *Response {
   742  	return nil
   743  }
   744  
   745  func (backSes *backSession) GetSqlOfStmt() string {
   746  	return ""
   747  }
   748  
   749  func (backSes *backSession) GetStmtId() uuid.UUID {
   750  	return [16]byte{}
   751  }
   752  
   753  // GetTenantName return tenant name according to GetTenantInfo and stmt.
   754  //
   755  // With stmt = nil, should be only called in TxnHandler.NewTxn, TxnHandler.CommitTxn, TxnHandler.RollbackTxn
   756  func (backSes *backSession) GetTenantNameWithStmt(stmt tree.Statement) string {
   757  	tenant := sysAccountName
   758  	if backSes.GetTenantInfo() != nil && (stmt == nil || !IsPrepareStatement(stmt)) {
   759  		tenant = backSes.GetTenantInfo().GetTenant()
   760  	}
   761  	return tenant
   762  }
   763  
   764  func (backSes *backSession) GetTenantName() string {
   765  	return backSes.GetTenantNameWithStmt(nil)
   766  }
   767  
   768  func (backSes *backSession) GetFromRealUser() bool {
   769  	return false
   770  }
   771  
   772  func (backSes *backSession) GetDebugString() string {
   773  	return ""
   774  }
   775  
   776  func (backSes *backSession) GetUserDefinedVar(name string) (SystemVariableType, *UserDefinedVar, error) {
   777  	return nil, nil, moerr.NewInternalError(context.Background(), "do not support user defined var in background exec")
   778  }
   779  
   780  func (backSes *backSession) GetSessionVar(ctx context.Context, name string) (interface{}, error) {
   781  	switch strings.ToLower(name) {
   782  	case "autocommit":
   783  		return true, nil
   784  	}
   785  	return nil, nil
   786  }
   787  
   788  func (backSes *backSession) GetGlobalSystemVariableValue(ctx context.Context, name string) (interface{}, error) {
   789  	return nil, moerr.NewInternalError(ctx, "do not support system variable in background exec")
   790  }
   791  
   792  func (backSes *backSession) GetBackgroundExec(ctx context.Context) BackgroundExec {
   793  	return NewBackgroundExec(
   794  		ctx,
   795  		backSes,
   796  		backSes.GetMemPool())
   797  }
   798  
   799  func (backSes *backSession) GetStorage() engine.Engine {
   800  	return getGlobalPu().StorageEngine
   801  }
   802  
   803  func (backSes *backSession) GetStatsCache() *plan2.StatsCache {
   804  	return nil
   805  }
   806  
   807  func (backSes *backSession) GetGlobalVar(ctx context.Context, name string) (interface{}, error) {
   808  	if def, val, ok := backSes.gSysVars.GetGlobalSysVar(name); ok {
   809  		if def.GetScope() == ScopeSession {
   810  			//empty
   811  			return nil, moerr.NewInternalError(ctx, errorSystemVariableSessionEmpty())
   812  		}
   813  		return val, nil
   814  	}
   815  	return nil, moerr.NewInternalError(ctx, errorSystemVariableDoesNotExist())
   816  }
   817  
   818  type SqlHelper struct {
   819  	ses *Session
   820  }
   821  
   822  func (sh *SqlHelper) GetCompilerContext() any {
   823  	return sh.ses.txnCompileCtx
   824  }
   825  
   826  func (sh *SqlHelper) GetSubscriptionMeta(dbName string) (*plan.SubscriptionMeta, error) {
   827  	return sh.ses.txnCompileCtx.GetSubscriptionMeta(dbName, plan2.Snapshot{TS: &timestamp.Timestamp{}})
   828  }
   829  
   830  // Made for sequence func. nextval, setval.
   831  func (sh *SqlHelper) ExecSql(sql string) (ret []interface{}, err error) {
   832  	var erArray []ExecResult
   833  
   834  	ctx := sh.ses.txnCompileCtx.execCtx.reqCtx
   835  	/*
   836  		if we run the transaction statement (BEGIN, ect) here , it creates an independent transaction.
   837  		if we do not run the transaction statement (BEGIN, ect) here, it runs the sql in the share transaction
   838  		and committed outside this function.
   839  		!!!NOTE: wen can not execute the transaction statement(BEGIN,COMMIT,ROLLBACK,START TRANSACTION ect) here.
   840  	*/
   841  	bh := sh.ses.GetShareTxnBackgroundExec(ctx, false)
   842  	defer bh.Close()
   843  
   844  	bh.ClearExecResultSet()
   845  	err = bh.Exec(ctx, sql)
   846  	if err != nil {
   847  		return nil, err
   848  	}
   849  
   850  	erArray, err = getResultSet(ctx, bh)
   851  	if err != nil {
   852  		return nil, err
   853  	}
   854  
   855  	if len(erArray) == 0 {
   856  		return nil, nil
   857  	}
   858  
   859  	return erArray[0].(*MysqlResultSet).Data[0], nil
   860  }