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

     1  // Copyright 2021 - 2024 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  	"fmt"
    19  	"time"
    20  
    21  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    22  
    23  	"go.uber.org/zap"
    24  	"golang.org/x/sync/errgroup"
    25  
    26  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    27  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
    28  )
    29  
    30  // executeStatusStmt run the statement that responses status t
    31  func executeStatusStmt(ses *Session, execCtx *ExecCtx) (err error) {
    32  	var loadLocalErrGroup *errgroup.Group
    33  	var columns []interface{}
    34  
    35  	mrs := ses.GetMysqlResultSet()
    36  	ep := ses.GetExportConfig()
    37  	switch st := execCtx.stmt.(type) {
    38  	case *tree.Select:
    39  		if ep.needExportToFile() {
    40  
    41  			columns, err = execCtx.cw.GetColumns(execCtx.reqCtx)
    42  			if err != nil {
    43  				logError(ses, ses.GetDebugString(),
    44  					"Failed to get columns from computation handler",
    45  					zap.Error(err))
    46  				return
    47  			}
    48  			for _, c := range columns {
    49  				mysqlc := c.(Column)
    50  				mrs.AddColumn(mysqlc)
    51  			}
    52  
    53  			// open new file
    54  			ep.DefaultBufSize = getGlobalPu().SV.ExportDataDefaultFlushSize
    55  			initExportFileParam(ep, mrs)
    56  			if err = openNewFile(execCtx.reqCtx, ep, mrs); err != nil {
    57  				return
    58  			}
    59  
    60  			runBegin := time.Now()
    61  			/*
    62  				Start pipeline
    63  				Producing the data row and sending the data row
    64  			*/
    65  			// todo: add trace
    66  			if _, err = execCtx.runner.Run(0); err != nil {
    67  				return
    68  			}
    69  
    70  			// only log if run time is longer than 1s
    71  			if time.Since(runBegin) > time.Second {
    72  				logInfo(ses, ses.GetDebugString(), fmt.Sprintf("time of Exec.Run : %s", time.Since(runBegin).String()))
    73  			}
    74  
    75  			oq := NewOutputQueue(execCtx.reqCtx, ses, 0, nil, nil)
    76  			if err = exportAllData(oq); err != nil {
    77  				return
    78  			}
    79  			if err = ep.Writer.Flush(); err != nil {
    80  				return
    81  			}
    82  			if err = ep.File.Close(); err != nil {
    83  				return
    84  			}
    85  
    86  		} else {
    87  			return moerr.NewInternalError(execCtx.reqCtx, "select without it generates the result rows")
    88  		}
    89  	case *tree.CreateTable:
    90  		runBegin := time.Now()
    91  		if execCtx.runResult, err = execCtx.runner.Run(0); err != nil {
    92  			return
    93  		}
    94  		// only log if run time is longer than 1s
    95  		if time.Since(runBegin) > time.Second {
    96  			logInfo(ses, ses.GetDebugString(), fmt.Sprintf("time of Exec.Run : %s", time.Since(runBegin).String()))
    97  		}
    98  
    99  		// execute insert sql if this is a `create table as select` stmt
   100  		if st.IsAsSelect {
   101  			if txw, ok := execCtx.cw.(*TxnComputationWrapper); ok {
   102  				insertSql := txw.plan.GetDdl().GetDefinition().(*plan.DataDefinition_CreateTable).CreateTable.CreateAsSelectSql
   103  				ses.createAsSelectSql = insertSql
   104  			}
   105  			return
   106  		}
   107  
   108  		// Start the dynamic table daemon task
   109  		if st.IsDynamicTable {
   110  			if err = handleCreateDynamicTable(execCtx.reqCtx, ses, st); err != nil {
   111  				return
   112  			}
   113  		}
   114  	default:
   115  		//change privilege
   116  		switch execCtx.stmt.(type) {
   117  		case *tree.DropTable, *tree.DropDatabase, *tree.DropIndex, *tree.DropView, *tree.DropSequence,
   118  			*tree.CreateUser, *tree.DropUser, *tree.AlterUser,
   119  			*tree.CreateRole, *tree.DropRole,
   120  			*tree.Revoke, *tree.Grant,
   121  			*tree.SetDefaultRole, *tree.SetRole:
   122  			ses.InvalidatePrivilegeCache()
   123  		}
   124  		runBegin := time.Now()
   125  		/*
   126  			Step 1: Start
   127  		*/
   128  
   129  		if st, ok := execCtx.stmt.(*tree.Load); ok {
   130  			if st.Local {
   131  				loadLocalErrGroup = new(errgroup.Group)
   132  				loadLocalErrGroup.Go(func() error {
   133  					return processLoadLocal(ses, execCtx, st.Param, execCtx.loadLocalWriter)
   134  				})
   135  			}
   136  		}
   137  
   138  		if execCtx.runResult, err = execCtx.runner.Run(0); err != nil {
   139  			if loadLocalErrGroup != nil { // release resources
   140  				err2 := execCtx.proc.LoadLocalReader.Close()
   141  				if err2 != nil {
   142  					logError(ses, ses.GetDebugString(),
   143  						"processLoadLocal goroutine failed",
   144  						zap.Error(err2))
   145  				}
   146  				err2 = loadLocalErrGroup.Wait() // executor failed, but processLoadLocal is still running, wait for it
   147  				if err2 != nil {
   148  					logError(ses, ses.GetDebugString(),
   149  						"processLoadLocal goroutine failed",
   150  						zap.Error(err2))
   151  				}
   152  			}
   153  			return
   154  		}
   155  
   156  		if loadLocalErrGroup != nil {
   157  			if err = loadLocalErrGroup.Wait(); err != nil { //executor success, but processLoadLocal goroutine failed
   158  				return
   159  			}
   160  		}
   161  
   162  		// only log if run time is longer than 1s
   163  		if time.Since(runBegin) > time.Second {
   164  			logInfo(ses, ses.GetDebugString(), fmt.Sprintf("time of Exec.Run : %s", time.Since(runBegin).String()))
   165  		}
   166  
   167  		echoTime := time.Now()
   168  
   169  		logDebug(ses, ses.GetDebugString(), fmt.Sprintf("time of SendResponse %s", time.Since(echoTime).String()))
   170  	}
   171  
   172  	return
   173  }
   174  
   175  func respStatus(ses *Session,
   176  	execCtx *ExecCtx) (err error) {
   177  	if execCtx.skipRespClient {
   178  		return nil
   179  	}
   180  	var rspLen uint64
   181  	if execCtx.runResult != nil {
   182  		rspLen = execCtx.runResult.AffectRows
   183  	}
   184  
   185  	switch st := execCtx.stmt.(type) {
   186  	case *tree.Select:
   187  		//select ... into ...
   188  		if len(execCtx.proc.SessionInfo.SeqAddValues) != 0 {
   189  			ses.AddSeqValues(execCtx.proc)
   190  		}
   191  		ses.SetSeqLastValue(execCtx.proc)
   192  
   193  		resp := setResponse(ses, execCtx.isLastStmt, rspLen)
   194  		if err2 := ses.GetMysqlProtocol().SendResponse(execCtx.reqCtx, resp); err2 != nil {
   195  			err = moerr.NewInternalError(execCtx.reqCtx, "routine send response failed. error:%v ", err2)
   196  			logStatementStatus(execCtx.reqCtx, ses, execCtx.stmt, fail, err)
   197  			return err
   198  		}
   199  	case *tree.PrepareStmt, *tree.PrepareString:
   200  		if ses.GetCmd() == COM_STMT_PREPARE {
   201  			if err2 := ses.GetMysqlProtocol().SendPrepareResponse(execCtx.reqCtx, execCtx.prepareStmt); err2 != nil {
   202  				err = moerr.NewInternalError(execCtx.reqCtx, "routine send response failed. error:%v ", err2)
   203  				logStatementStatus(execCtx.reqCtx, ses, execCtx.stmt, fail, err)
   204  				return err
   205  			}
   206  		} else {
   207  			resp := setResponse(ses, execCtx.isLastStmt, rspLen)
   208  			if err2 := ses.GetMysqlProtocol().SendResponse(execCtx.reqCtx, resp); err2 != nil {
   209  				err = moerr.NewInternalError(execCtx.reqCtx, "routine send response failed. error:%v ", err2)
   210  				logStatementStatus(execCtx.reqCtx, ses, execCtx.stmt, fail, err)
   211  				return err
   212  			}
   213  		}
   214  
   215  	case *tree.Deallocate:
   216  		//we will not send response in COM_STMT_CLOSE command
   217  		if ses.GetCmd() != COM_STMT_CLOSE {
   218  			resp := setResponse(ses, execCtx.isLastStmt, rspLen)
   219  			if err2 := ses.GetMysqlProtocol().SendResponse(execCtx.reqCtx, resp); err2 != nil {
   220  				err = moerr.NewInternalError(execCtx.reqCtx, "routine send response failed. error:%v ", err2)
   221  				logStatementStatus(execCtx.reqCtx, ses, execCtx.stmt, fail, err)
   222  				return err
   223  			}
   224  		}
   225  	case *tree.CreateTable:
   226  		// skip create table as select
   227  		if st.IsAsSelect {
   228  			return nil
   229  		}
   230  		resp := setResponse(ses, execCtx.isLastStmt, rspLen)
   231  		if len(execCtx.proc.SessionInfo.SeqDeleteKeys) != 0 {
   232  			ses.DeleteSeqValues(execCtx.proc)
   233  		}
   234  		_ = doGrantPrivilegeImplicitly(execCtx.reqCtx, ses, st)
   235  		if err2 := ses.GetMysqlProtocol().SendResponse(execCtx.reqCtx, resp); err2 != nil {
   236  			err = moerr.NewInternalError(execCtx.reqCtx, "routine send response failed. error:%v ", err2)
   237  			logStatementStatus(execCtx.reqCtx, ses, execCtx.stmt, fail, err)
   238  			return err
   239  		}
   240  	default:
   241  		resp := setResponse(ses, execCtx.isLastStmt, rspLen)
   242  
   243  		if len(execCtx.proc.SessionInfo.SeqDeleteKeys) != 0 {
   244  			ses.DeleteSeqValues(execCtx.proc)
   245  		}
   246  
   247  		switch st := execCtx.stmt.(type) {
   248  		case *tree.Insert:
   249  			resp.lastInsertId = execCtx.proc.GetLastInsertID()
   250  			if execCtx.proc.GetLastInsertID() != 0 {
   251  				ses.SetLastInsertID(execCtx.proc.GetLastInsertID())
   252  			}
   253  		case *tree.CreateTable:
   254  			_ = doGrantPrivilegeImplicitly(execCtx.reqCtx, ses, st)
   255  		case *tree.DropTable:
   256  			// handle dynamic table drop, cancel all the running daemon task
   257  			_ = handleDropDynamicTable(execCtx.reqCtx, ses, st)
   258  			_ = doRevokePrivilegeImplicitly(execCtx.reqCtx, ses, st)
   259  		case *tree.CreateDatabase:
   260  			_ = insertRecordToMoMysqlCompatibilityMode(execCtx.reqCtx, ses, execCtx.stmt)
   261  			_ = doGrantPrivilegeImplicitly(execCtx.reqCtx, ses, st)
   262  		case *tree.DropDatabase:
   263  			_ = deleteRecordToMoMysqlCompatbilityMode(execCtx.reqCtx, ses, execCtx.stmt)
   264  			_ = doRevokePrivilegeImplicitly(execCtx.reqCtx, ses, st)
   265  			err = doDropFunctionWithDB(execCtx.reqCtx, ses, execCtx.stmt, func(path string) error {
   266  				return execCtx.proc.FileService.Delete(execCtx.reqCtx, path)
   267  			})
   268  		}
   269  
   270  		if err2 := ses.GetMysqlProtocol().SendResponse(execCtx.reqCtx, resp); err2 != nil {
   271  			err = moerr.NewInternalError(execCtx.reqCtx, "routine send response failed. error:%v ", err2)
   272  			logStatementStatus(execCtx.reqCtx, ses, execCtx.stmt, fail, err)
   273  			return err
   274  		}
   275  	}
   276  	return
   277  }