github.com/matrixorigin/matrixone@v1.2.0/pkg/frontend/result_row_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 "go.uber.org/zap" 22 23 "github.com/matrixorigin/matrixone/pkg/common/moerr" 24 "github.com/matrixorigin/matrixone/pkg/pb/plan" 25 "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" 26 plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" 27 "github.com/matrixorigin/matrixone/pkg/sql/plan/explain" 28 ) 29 30 // executeResultRowStmt run the statemet that responses result rows 31 func executeResultRowStmt(ses *Session, execCtx *ExecCtx) (err error) { 32 var columns []interface{} 33 34 switch statement := execCtx.stmt.(type) { 35 case *tree.Select: 36 37 columns, err = execCtx.cw.GetColumns(execCtx.reqCtx) 38 if err != nil { 39 logError(ses, ses.GetDebugString(), 40 "Failed to get columns from computation handler", 41 zap.Error(err)) 42 return 43 } 44 if c, ok := execCtx.cw.(*TxnComputationWrapper); ok { 45 ses.rs = &plan.ResultColDef{ResultCols: plan2.GetResultColumnsFromPlan(c.plan)} 46 } 47 48 err = respColumnDefsWithoutFlush(ses, execCtx, columns) 49 if err != nil { 50 return 51 } 52 53 runBegin := time.Now() 54 /* 55 Step 2: Start pipeline 56 Producing the data row and sending the data row 57 */ 58 // todo: add trace 59 if _, err = execCtx.runner.Run(0); err != nil { 60 return 61 } 62 63 // only log if run time is longer than 1s 64 if time.Since(runBegin) > time.Second { 65 logInfo(ses, ses.GetDebugString(), fmt.Sprintf("time of Exec.Run : %s", time.Since(runBegin).String())) 66 } 67 68 case *tree.ExplainAnalyze: 69 explainColName := "QUERY PLAN" 70 columns, err = GetExplainColumns(execCtx.reqCtx, explainColName) 71 if err != nil { 72 logError(ses, ses.GetDebugString(), 73 "Failed to get columns from ExplainColumns handler", 74 zap.Error(err)) 75 return 76 } 77 78 err = respColumnDefsWithoutFlush(ses, execCtx, columns) 79 if err != nil { 80 return 81 } 82 83 runBegin := time.Now() 84 /* 85 Step 1: Start 86 */ 87 if _, err = execCtx.runner.Run(0); err != nil { 88 return 89 } 90 91 // only log if run time is longer than 1s 92 if time.Since(runBegin) > time.Second { 93 logInfo(ses, ses.GetDebugString(), fmt.Sprintf("time of Exec.Run : %s", time.Since(runBegin).String())) 94 } 95 96 default: 97 columns, err = execCtx.cw.GetColumns(execCtx.reqCtx) 98 if err != nil { 99 logError(ses, ses.GetDebugString(), 100 "Failed to get columns from computation handler", 101 zap.Error(err)) 102 return 103 } 104 if c, ok := execCtx.cw.(*TxnComputationWrapper); ok { 105 ses.rs = &plan.ResultColDef{ResultCols: plan2.GetResultColumnsFromPlan(c.plan)} 106 } 107 err = respColumnDefsWithoutFlush(ses, execCtx, columns) 108 if err != nil { 109 return 110 } 111 112 runBegin := time.Now() 113 /* 114 Step 2: Start pipeline 115 Producing the data row and sending the data row 116 */ 117 // todo: add trace 118 if _, err = execCtx.runner.Run(0); err != nil { 119 return 120 } 121 122 switch ses.GetShowStmtType() { 123 case ShowTableStatus: 124 if err = handleShowTableStatus(ses, execCtx, statement.(*tree.ShowTableStatus)); err != nil { 125 return 126 } 127 } 128 129 // only log if run time is longer than 1s 130 if time.Since(runBegin) > time.Second { 131 logInfo(ses, ses.GetDebugString(), fmt.Sprintf("time of Exec.Run : %s", time.Since(runBegin).String())) 132 } 133 } 134 return 135 } 136 137 func respColumnDefsWithoutFlush(ses *Session, execCtx *ExecCtx, columns []any) (err error) { 138 if execCtx.skipRespClient { 139 return nil 140 } 141 //!!!carefully to use 142 execCtx.proto.DisableAutoFlush() 143 defer execCtx.proto.EnableAutoFlush() 144 145 mrs := ses.GetMysqlResultSet() 146 /* 147 Step 1 : send column count and column definition. 148 */ 149 //send column count 150 colCnt := uint64(len(columns)) 151 err = execCtx.proto.SendColumnCountPacket(colCnt) 152 if err != nil { 153 return 154 } 155 //send columns 156 //column_count * Protocol::ColumnDefinition packets 157 cmd := ses.GetCmd() 158 for _, c := range columns { 159 mysqlc := c.(Column) 160 mrs.AddColumn(mysqlc) 161 /* 162 mysql COM_QUERY response: send the column definition per column 163 */ 164 err = execCtx.proto.SendColumnDefinitionPacket(execCtx.reqCtx, mysqlc, int(cmd)) 165 if err != nil { 166 return 167 } 168 } 169 170 /* 171 mysql COM_QUERY response: End after the column has been sent. 172 send EOF packet 173 */ 174 err = execCtx.proto.SendEOFPacketIf(0, ses.GetTxnHandler().GetServerStatus()) 175 if err != nil { 176 return 177 } 178 return 179 } 180 181 func respStreamResultRow(ses *Session, 182 execCtx *ExecCtx) (err error) { 183 if execCtx.skipRespClient { 184 return nil 185 } 186 switch statement := execCtx.stmt.(type) { 187 case *tree.Select: 188 if len(execCtx.proc.SessionInfo.SeqAddValues) != 0 { 189 ses.AddSeqValues(execCtx.proc) 190 } 191 ses.SetSeqLastValue(execCtx.proc) 192 err2 := execCtx.proto.sendEOFOrOkPacket(0, ses.getStatusAfterTxnIsEnded(execCtx.reqCtx)) 193 if err2 != nil { 194 err = moerr.NewInternalError(execCtx.reqCtx, "routine send response failed. error:%v ", err2) 195 logStatementStatus(execCtx.reqCtx, ses, execCtx.stmt, fail, err) 196 return 197 } 198 199 case *tree.ExplainAnalyze: 200 explainColName := "QUERY PLAN" 201 if cwft, ok := execCtx.cw.(*TxnComputationWrapper); ok { 202 queryPlan := cwft.plan 203 //if it is the plan from the EXECUTE, 204 // replace the plan by the plan generated by the PREPARE 205 if len(cwft.paramVals) != 0 { 206 queryPlan, err = plan2.FillValuesOfParamsInPlan(execCtx.reqCtx, queryPlan, cwft.paramVals) 207 if err != nil { 208 return 209 } 210 } 211 // generator query explain 212 explainQuery := explain.NewExplainQueryImpl(queryPlan.GetQuery()) 213 214 // build explain data buffer 215 buffer := explain.NewExplainDataBuffer() 216 var option *explain.ExplainOptions 217 option, err = getExplainOption(execCtx.reqCtx, statement.Options) 218 if err != nil { 219 return 220 } 221 222 err = explainQuery.ExplainPlan(execCtx.reqCtx, buffer, option) 223 if err != nil { 224 return 225 } 226 227 err = buildMoExplainQuery(execCtx, explainColName, buffer, ses, getDataFromPipeline) 228 if err != nil { 229 return 230 } 231 232 err = execCtx.proto.sendEOFOrOkPacket(0, ses.getStatusAfterTxnIsEnded(execCtx.reqCtx)) 233 if err != nil { 234 return 235 } 236 } 237 default: 238 err = execCtx.proto.sendEOFOrOkPacket(0, ses.getStatusAfterTxnIsEnded(execCtx.reqCtx)) 239 if err != nil { 240 return 241 } 242 } 243 244 return 245 } 246 247 func respPrebuildResultRow(ses *Session, 248 execCtx *ExecCtx) (err error) { 249 if execCtx.skipRespClient { 250 return nil 251 } 252 mer := NewMysqlExecutionResult(0, 0, 0, 0, ses.GetMysqlResultSet()) 253 resp := ses.SetNewResponse(ResultResponse, 0, int(COM_QUERY), mer, execCtx.isLastStmt) 254 if err := execCtx.proto.SendResponse(execCtx.reqCtx, resp); err != nil { 255 return moerr.NewInternalError(execCtx.reqCtx, "routine send response failed, error: %v ", err) 256 } 257 return err 258 } 259 260 func respMixedResultRow(ses *Session, 261 execCtx *ExecCtx) (err error) { 262 if execCtx.skipRespClient { 263 return nil 264 } 265 //!!!the columnDef has been sent after the compiling ends. It should not be sent here again. 266 //only the result rows need to be sent. 267 mrs := ses.GetMysqlResultSet() 268 if err := ses.GetMysqlProtocol().SendResultSetTextBatchRowSpeedup(mrs, mrs.GetRowCount()); err != nil { 269 logError(ses, ses.GetDebugString(), 270 "Failed to handle 'SHOW TABLE STATUS'", 271 zap.Error(err)) 272 return err 273 } 274 err = execCtx.proto.sendEOFOrOkPacket(0, ses.getStatusAfterTxnIsEnded(execCtx.reqCtx)) 275 if err != nil { 276 return 277 } 278 279 return err 280 }