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 }