github.com/matrixorigin/matrixone@v0.7.0/pkg/frontend/mysql_cmd_executor.go (about) 1 // Copyright 2021 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 "bytes" 19 "context" 20 "encoding/binary" 21 "encoding/json" 22 "fmt" 23 "io" 24 "math" 25 "os" 26 "reflect" 27 "sort" 28 "strconv" 29 "strings" 30 "sync" 31 "time" 32 33 "github.com/fagongzi/goetty/v2" 34 "github.com/matrixorigin/matrixone/pkg/sql/util" 35 "golang.org/x/sync/errgroup" 36 37 "github.com/matrixorigin/matrixone/pkg/common/mpool" 38 "github.com/matrixorigin/matrixone/pkg/common/runtime" 39 "github.com/matrixorigin/matrixone/pkg/txn/clock" 40 41 "github.com/matrixorigin/matrixone/pkg/catalog" 42 "github.com/matrixorigin/matrixone/pkg/pb/plan" 43 "github.com/matrixorigin/matrixone/pkg/sql/colexec" 44 45 "github.com/matrixorigin/matrixone/pkg/common/moerr" 46 logservicepb "github.com/matrixorigin/matrixone/pkg/pb/logservice" 47 "github.com/matrixorigin/matrixone/pkg/sql/compile" 48 plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" 49 "github.com/matrixorigin/matrixone/pkg/sql/plan/explain" 50 51 "github.com/matrixorigin/matrixone/pkg/container/batch" 52 "github.com/matrixorigin/matrixone/pkg/container/nulls" 53 "github.com/matrixorigin/matrixone/pkg/container/types" 54 "github.com/matrixorigin/matrixone/pkg/container/vector" 55 "github.com/matrixorigin/matrixone/pkg/defines" 56 "github.com/matrixorigin/matrixone/pkg/logutil" 57 "github.com/matrixorigin/matrixone/pkg/sql/parsers" 58 "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect" 59 "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect/mysql" 60 "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" 61 "github.com/matrixorigin/matrixone/pkg/util/metric" 62 "github.com/matrixorigin/matrixone/pkg/vm/engine" 63 "github.com/matrixorigin/matrixone/pkg/vm/engine/memoryengine" 64 "github.com/matrixorigin/matrixone/pkg/vm/process" 65 66 "github.com/matrixorigin/matrixone/pkg/util/trace" 67 "github.com/matrixorigin/matrixone/pkg/util/trace/impl/motrace" 68 69 "github.com/google/uuid" 70 ) 71 72 func onlyCreateStatementErrorInfo() string { 73 return "Only CREATE of DDL is supported in transactions" 74 } 75 76 func administrativeCommandIsUnsupportedInTxnErrorInfo() string { 77 return "administrative command is unsupported in transactions" 78 } 79 80 func parameterModificationInTxnErrorInfo() string { 81 return "Uncommitted transaction exists. Please commit or rollback first." 82 } 83 84 func unclassifiedStatementInUncommittedTxnErrorInfo() string { 85 return "unclassified statement appears in uncommitted transaction" 86 } 87 88 func abortTransactionErrorInfo() string { 89 return "Previous DML conflicts with existing constraints or data format. This transaction has to be aborted" 90 } 91 92 func writeWriteConflictsErrorInfo() string { 93 return "Write conflicts detected. Previous transaction need to be aborted." 94 } 95 96 const ( 97 prefixPrepareStmtName = "__mo_stmt_id" 98 prefixPrepareStmtSessionVar = "__mo_stmt_var" 99 ) 100 101 func getPrepareStmtName(stmtID uint32) string { 102 return fmt.Sprintf("%s_%d", prefixPrepareStmtName, stmtID) 103 } 104 105 func GetPrepareStmtID(ctx context.Context, name string) (int, error) { 106 idx := len(prefixPrepareStmtName) + 1 107 if idx >= len(name) { 108 return -1, moerr.NewInternalError(ctx, "can not get Prepare stmtID") 109 } 110 return strconv.Atoi(name[idx:]) 111 } 112 113 func getPrepareStmtSessionVarName(index int) string { 114 return fmt.Sprintf("%s_%d", prefixPrepareStmtSessionVar, index) 115 } 116 117 // TableInfoCache tableInfos of a database 118 type TableInfoCache struct { 119 db string 120 tableInfos map[string][]ColumnInfo 121 } 122 123 type MysqlCmdExecutor struct { 124 CmdExecutorImpl 125 126 //for cmd 0x4 127 TableInfoCache 128 129 //the count of sql has been processed 130 sqlCount uint64 131 132 ses *Session 133 134 routineMgr *RoutineManager 135 136 cancelRequestFunc context.CancelFunc 137 138 doQueryFunc doComQueryFunc 139 140 mu sync.Mutex 141 } 142 143 func (mce *MysqlCmdExecutor) CancelRequest() { 144 mce.mu.Lock() 145 defer mce.mu.Unlock() 146 if mce.cancelRequestFunc != nil { 147 mce.cancelRequestFunc() 148 } 149 } 150 151 func (mce *MysqlCmdExecutor) ChooseDoQueryFunc(choice bool) { 152 mce.mu.Lock() 153 defer mce.mu.Unlock() 154 if choice { 155 mce.doQueryFunc = mce.doComQueryInProgress 156 } else { 157 mce.doQueryFunc = mce.doComQuery 158 } 159 } 160 161 func (mce *MysqlCmdExecutor) GetDoQueryFunc() doComQueryFunc { 162 mce.mu.Lock() 163 defer mce.mu.Unlock() 164 if mce.doQueryFunc == nil { 165 mce.doQueryFunc = mce.doComQuery 166 } 167 return mce.doQueryFunc 168 } 169 170 func (mce *MysqlCmdExecutor) SetSession(ses *Session) { 171 mce.mu.Lock() 172 defer mce.mu.Unlock() 173 mce.ses = ses 174 } 175 176 func (mce *MysqlCmdExecutor) GetSession() *Session { 177 mce.mu.Lock() 178 defer mce.mu.Unlock() 179 return mce.ses 180 } 181 182 // get new process id 183 func (mce *MysqlCmdExecutor) getNextProcessId() string { 184 /* 185 temporary method: 186 routineId + sqlCount 187 */ 188 routineId := mce.GetSession().GetMysqlProtocol().ConnectionID() 189 return fmt.Sprintf("%d%d", routineId, mce.GetSqlCount()) 190 } 191 192 func (mce *MysqlCmdExecutor) GetSqlCount() uint64 { 193 mce.mu.Lock() 194 defer mce.mu.Unlock() 195 return mce.sqlCount 196 } 197 198 func (mce *MysqlCmdExecutor) addSqlCount(a uint64) { 199 mce.mu.Lock() 200 defer mce.mu.Unlock() 201 mce.sqlCount += a 202 } 203 204 func (mce *MysqlCmdExecutor) SetRoutineManager(mgr *RoutineManager) { 205 mce.mu.Lock() 206 defer mce.mu.Unlock() 207 mce.routineMgr = mgr 208 } 209 210 func (mce *MysqlCmdExecutor) GetRoutineManager() *RoutineManager { 211 mce.mu.Lock() 212 defer mce.mu.Unlock() 213 return mce.routineMgr 214 } 215 216 var RecordStatement = func(ctx context.Context, ses *Session, proc *process.Process, cw ComputationWrapper, envBegin time.Time, envStmt string, useEnv bool) context.Context { 217 if !motrace.GetTracerProvider().IsEnable() { 218 return ctx 219 } 220 sessInfo := proc.SessionInfo 221 tenant := ses.GetTenantInfo() 222 if tenant == nil { 223 tenant, _ = GetTenantInfo(ctx, "internal") 224 } 225 var txnID uuid.UUID 226 var txn TxnOperator 227 var err error 228 if handler := ses.GetTxnHandler(); handler.IsValidTxn() { 229 txn, err = handler.GetTxn() 230 if err != nil { 231 logutil.Errorf("RecordStatement. error:%v", err) 232 } else { 233 copy(txnID[:], txn.Txn().ID) 234 } 235 } 236 var sesID uuid.UUID 237 copy(sesID[:], ses.GetUUID()) 238 requestAt := envBegin 239 if !useEnv { 240 requestAt = time.Now() 241 } 242 var stmID uuid.UUID 243 var statement tree.Statement = nil 244 var text string 245 if cw != nil { 246 copy(stmID[:], cw.GetUUID()) 247 statement = cw.GetAst() 248 ses.ast = statement 249 fmtCtx := tree.NewFmtCtx(dialect.MYSQL, tree.WithQuoteString(true)) 250 statement.Format(fmtCtx) 251 text = SubStringFromBegin(fmtCtx.String(), int(ses.GetParameterUnit().SV.LengthOfQueryPrinted)) 252 } else { 253 stmID = uuid.New() 254 text = SubStringFromBegin(envStmt, int(ses.GetParameterUnit().SV.LengthOfQueryPrinted)) 255 } 256 stm := &motrace.StatementInfo{ 257 StatementID: stmID, 258 TransactionID: txnID, 259 SessionID: sesID, 260 Account: tenant.GetTenant(), 261 RoleId: proc.SessionInfo.RoleId, 262 User: tenant.GetUser(), 263 Host: sessInfo.GetHost(), 264 Database: ses.GetDatabaseName(), 265 Statement: text, 266 StatementFingerprint: "", // fixme: (Reserved) 267 StatementTag: "", // fixme: (Reserved) 268 SqlSourceType: ses.sqlSourceType, 269 RequestAt: requestAt, 270 StatementType: getStatementType(statement).GetStatementType(), 271 QueryType: getStatementType(statement).GetQueryType(), 272 } 273 if ses.sqlSourceType != "internal_sql" { 274 ses.tStmt = stm 275 ses.pushQueryId(types.Uuid(stmID).ToString()) 276 } 277 if !stm.IsZeroTxnID() { 278 stm.Report(ctx) 279 } 280 sc := trace.SpanContextWithID(trace.TraceID(stmID), trace.SpanKindStatement) 281 proc.WithSpanContext(sc) 282 reqCtx := ses.GetRequestContext() 283 ses.SetRequestContext(trace.ContextWithSpanContext(reqCtx, sc)) 284 return motrace.ContextWithStatement(trace.ContextWithSpanContext(ctx, sc), stm) 285 } 286 287 var RecordParseErrorStatement = func(ctx context.Context, ses *Session, proc *process.Process, envBegin time.Time, envStmt string) context.Context { 288 ctx = RecordStatement(ctx, ses, proc, nil, envBegin, envStmt, true) 289 tenant := ses.GetTenantInfo() 290 if tenant == nil { 291 tenant, _ = GetTenantInfo(ctx, "internal") 292 } 293 incStatementCounter(tenant.GetTenant(), nil) 294 incStatementErrorsCounter(tenant.GetTenant(), nil) 295 return ctx 296 } 297 298 // RecordStatementTxnID record txnID after TxnBegin or Compile(autocommit=1) 299 var RecordStatementTxnID = func(ctx context.Context, ses *Session) { 300 var err error 301 var txn TxnOperator 302 if stm := motrace.StatementFromContext(ctx); ses != nil && stm != nil && stm.IsZeroTxnID() { 303 if handler := ses.GetTxnHandler(); handler.IsValidTxn() { 304 txn, err = handler.GetTxn() 305 if err != nil { 306 logutil.Errorf("RecordStatementTxnID. error:%v", err) 307 } else { 308 stm.SetTxnID(txn.Txn().ID) 309 } 310 311 } 312 stm.Report(ctx) 313 } 314 } 315 316 // outputPool outputs the data 317 type outputPool interface { 318 resetLineStr() 319 320 reset() 321 322 getEmptyRow() ([]interface{}, error) 323 324 flush() error 325 } 326 327 var _ outputPool = &outputQueue{} 328 var _ outputPool = &fakeOutputQueue{} 329 330 type outputQueue struct { 331 ctx context.Context 332 proto MysqlProtocol 333 mrs *MysqlResultSet 334 rowIdx uint64 335 length uint64 336 ep *ExportParam 337 lineStr []byte 338 showStmtType ShowStatementType 339 340 getEmptyRowTime time.Duration 341 flushTime time.Duration 342 } 343 344 func (o *outputQueue) resetLineStr() { 345 o.lineStr = o.lineStr[:0] 346 } 347 348 func NewOutputQueue(ctx context.Context, proto MysqlProtocol, mrs *MysqlResultSet, length uint64, ep *ExportParam, showStatementType ShowStatementType) *outputQueue { 349 return &outputQueue{ 350 ctx: ctx, 351 proto: proto, 352 mrs: mrs, 353 rowIdx: 0, 354 length: length, 355 ep: ep, 356 showStmtType: showStatementType, 357 } 358 } 359 360 func (o *outputQueue) reset() { 361 o.getEmptyRowTime = 0 362 o.flushTime = 0 363 } 364 365 /* 366 getEmptyRow returns a empty space for filling data. 367 If there is no space, it flushes the data into the protocol 368 and returns an empty space then. 369 */ 370 func (o *outputQueue) getEmptyRow() ([]interface{}, error) { 371 if o.rowIdx >= o.length { 372 if err := o.flush(); err != nil { 373 return nil, err 374 } 375 } 376 377 row := o.mrs.Data[o.rowIdx] 378 o.rowIdx++ 379 return row, nil 380 } 381 382 /* 383 flush will force the data flushed into the protocol. 384 */ 385 func (o *outputQueue) flush() error { 386 if o.rowIdx <= 0 { 387 return nil 388 } 389 if o.ep.Outfile { 390 if err := exportDataToCSVFile(o); err != nil { 391 logutil.Errorf("export to csv file error %v", err) 392 return err 393 } 394 } else { 395 //send group of row 396 if o.showStmtType == ShowColumns || o.showStmtType == ShowTableStatus { 397 o.rowIdx = 0 398 return nil 399 } 400 401 if err := o.proto.SendResultSetTextBatchRowSpeedup(o.mrs, o.rowIdx); err != nil { 402 logutil.Errorf("flush error %v", err) 403 return err 404 } 405 } 406 o.rowIdx = 0 407 return nil 408 } 409 410 // fakeOutputQueue saves the data into the session. 411 type fakeOutputQueue struct { 412 mrs *MysqlResultSet 413 } 414 415 func newFakeOutputQueue(mrs *MysqlResultSet) outputPool { 416 return &fakeOutputQueue{mrs: mrs} 417 } 418 419 func (foq *fakeOutputQueue) resetLineStr() {} 420 421 func (foq *fakeOutputQueue) reset() {} 422 423 func (foq *fakeOutputQueue) getEmptyRow() ([]interface{}, error) { 424 row := make([]interface{}, foq.mrs.GetColumnCount()) 425 foq.mrs.AddRow(row) 426 return row, nil 427 } 428 429 func (foq *fakeOutputQueue) flush() error { 430 return nil 431 } 432 433 const ( 434 primaryKeyPos = 25 435 ) 436 437 /* 438 handle show columns from table in plan2 and tae 439 */ 440 func handleShowColumns(ses *Session, stmt *tree.ShowColumns) error { 441 data := ses.GetData() 442 mrs := ses.GetMysqlResultSet() 443 dbName := stmt.Table.GetDBName() 444 if len(dbName) == 0 { 445 dbName = ses.GetDatabaseName() 446 } 447 448 tableName := string(stmt.Table.ToTableName().ObjectName) 449 ctx := ses.GetTxnCompileCtx() 450 _, tableDef := ctx.Resolve(dbName, tableName) 451 if tableDef == nil { 452 return moerr.NewNoSuchTable(ctx.GetContext(), dbName, tableName) 453 } 454 455 colNameToColContent := make(map[string][]interface{}) 456 for _, d := range data { 457 colName := string(d[0].([]byte)) 458 if colName == catalog.Row_ID { 459 continue 460 } 461 //the non-sys account skips the column account_id of the cluster table 462 if util.IsClusterTableAttribute(colName) && 463 isClusterTable(dbName, tableName) && 464 ses.GetTenantInfo() != nil && 465 !ses.GetTenantInfo().IsSysTenant() { 466 continue 467 } 468 469 if len(d) == 7 { 470 row := make([]interface{}, 7) 471 row[0] = colName 472 typ := &types.Type{} 473 data := d[1].([]uint8) 474 if err := types.Decode(data, typ); err != nil { 475 return err 476 } 477 row[1] = typ.DescString() 478 row[2] = d[2] 479 row[3] = d[3] 480 if value, ok := row[3].([]uint8); ok { 481 if len(value) != 0 { 482 row[2] = "NO" 483 } 484 } 485 def := &plan.Default{} 486 defaultData := d[4].([]uint8) 487 if string(defaultData) == "" { 488 row[4] = "NULL" 489 } else { 490 if err := types.Decode(defaultData, def); err != nil { 491 return err 492 } 493 originString := def.GetOriginString() 494 switch originString { 495 case "uuid()": 496 row[4] = "UUID" 497 case "current_timestamp()": 498 row[4] = "CURRENT_TIMESTAMP" 499 case "now()": 500 row[4] = "CURRENT_TIMESTAMP" 501 case "": 502 row[4] = "NULL" 503 default: 504 row[4] = originString 505 } 506 } 507 508 row[5] = "" 509 row[6] = d[6] 510 colNameToColContent[colName] = row 511 } else { 512 row := make([]interface{}, 9) 513 row[0] = colName 514 typ := &types.Type{} 515 data := d[1].([]uint8) 516 if err := types.Decode(data, typ); err != nil { 517 return err 518 } 519 row[1] = typ.DescString() 520 row[2] = "NULL" 521 row[3] = d[3] 522 row[4] = d[4] 523 if value, ok := row[4].([]uint8); ok { 524 if len(value) != 0 { 525 row[3] = "NO" 526 } 527 } 528 def := &plan.Default{} 529 defaultData := d[5].([]uint8) 530 if string(defaultData) == "" { 531 row[5] = "NULL" 532 } else { 533 if err := types.Decode(defaultData, def); err != nil { 534 return err 535 } 536 originString := def.GetOriginString() 537 switch originString { 538 case "uuid()": 539 row[5] = "UUID" 540 case "current_timestamp()": 541 row[5] = "CURRENT_TIMESTAMP" 542 case "now()": 543 row[5] = "CURRENT_TIMESTAMP" 544 case "": 545 row[5] = "NULL" 546 default: 547 row[5] = originString 548 } 549 } 550 551 row[6] = "" 552 row[7] = d[7] 553 row[8] = d[8] 554 colNameToColContent[colName] = row 555 } 556 } 557 for _, col := range tableDef.Cols { 558 if row, ok := colNameToColContent[col.Name]; ok { 559 mrs.AddRow(row) 560 } 561 562 } 563 if err := ses.GetMysqlProtocol().SendResultSetTextBatchRowSpeedup(mrs, mrs.GetRowCount()); err != nil { 564 logErrorf(ses.GetConciseProfile(), "handleShowColumns error %v", err) 565 return err 566 } 567 return nil 568 } 569 570 func handleShowTableStatus(ses *Session, stmt *tree.ShowTableStatus, proc *process.Process) error { 571 db, err := ses.GetStorage().Database(ses.requestCtx, stmt.DbName, proc.TxnOperator) 572 if err != nil { 573 return err 574 } 575 mrs := ses.GetMysqlResultSet() 576 for _, row := range ses.data { 577 tableName := string(row[0].([]byte)) 578 r, err := db.Relation(ses.requestCtx, tableName) 579 if err != nil { 580 return err 581 } 582 _, err = r.Ranges(ses.requestCtx, nil) 583 if err != nil { 584 return err 585 } 586 row[3], err = r.Rows(ses.requestCtx) 587 if err != nil { 588 return err 589 } 590 mrs.AddRow(row) 591 } 592 if err := ses.GetMysqlProtocol().SendResultSetTextBatchRowSpeedup(mrs, mrs.GetRowCount()); err != nil { 593 logErrorf(ses.GetConciseProfile(), "handleShowTableStatus error %v", err) 594 return err 595 } 596 return nil 597 } 598 599 /* 600 extract the data from the pipeline. 601 obj: routine obj 602 TODO:Add error 603 Warning: The pipeline is the multi-thread environment. The getDataFromPipeline will 604 605 access the shared data. Be careful when it writes the shared data. 606 */ 607 func getDataFromPipeline(obj interface{}, bat *batch.Batch) error { 608 ses := obj.(*Session) 609 if openSaveQueryResult(ses) { 610 if bat == nil { 611 if err := saveQueryResultMeta(ses); err != nil { 612 return err 613 } 614 } else { 615 if err := saveQueryResult(ses, bat); err != nil { 616 return err 617 } 618 } 619 } 620 if bat == nil { 621 return nil 622 } 623 624 begin := time.Now() 625 626 proto := ses.GetMysqlProtocol() 627 proto.ResetStatistics() 628 629 //Create a new temporary resultset per pipeline thread. 630 mrs := &MysqlResultSet{} 631 //Warning: Don't change ResultColumns in this. 632 //Reference the shared ResultColumns of the session among multi-thread. 633 sesMrs := ses.GetMysqlResultSet() 634 mrs.Columns = sesMrs.Columns 635 mrs.Name2Index = sesMrs.Name2Index 636 637 begin3 := time.Now() 638 countOfResultSet := 1 639 //group row 640 mrs.Data = make([][]interface{}, countOfResultSet) 641 for i := 0; i < countOfResultSet; i++ { 642 mrs.Data[i] = make([]interface{}, len(bat.Vecs)) 643 } 644 allocateOutBufferTime := time.Since(begin3) 645 646 oq := NewOutputQueue(ses.GetRequestContext(), proto, mrs, uint64(countOfResultSet), ses.GetExportParam(), ses.GetShowStmtType()) 647 oq.reset() 648 649 row2colTime := time.Duration(0) 650 651 procBatchBegin := time.Now() 652 653 n := vector.Length(bat.Vecs[0]) 654 655 requestCtx := ses.GetRequestContext() 656 for j := 0; j < n; j++ { //row index 657 if oq.ep.Outfile { 658 select { 659 case <-requestCtx.Done(): 660 { 661 return nil 662 } 663 default: 664 { 665 } 666 } 667 } 668 669 if bat.Zs[j] <= 0 { 670 continue 671 } 672 row, err := extractRowFromEveryVector(ses, bat, int64(j), oq) 673 if err != nil { 674 return err 675 } 676 if oq.showStmtType == ShowColumns || oq.showStmtType == ShowTableStatus { 677 row2 := make([]interface{}, len(row)) 678 copy(row2, row) 679 ses.AppendData(row2) 680 } 681 } 682 683 //logutil.Debugf("row group -+> %v ", oq.getData()) 684 685 err := oq.flush() 686 if err != nil { 687 return err 688 } 689 690 procBatchTime := time.Since(procBatchBegin) 691 tTime := time.Since(begin) 692 logInfof(ses.GetConciseProfile(), "rowCount %v \n"+ 693 "time of getDataFromPipeline : %s \n"+ 694 "processBatchTime %v \n"+ 695 "row2colTime %v \n"+ 696 "allocateOutBufferTime %v \n"+ 697 "outputQueue.flushTime %v \n"+ 698 "processBatchTime - row2colTime - allocateOutbufferTime - flushTime %v \n"+ 699 "restTime(=tTime - row2colTime - allocateOutBufferTime) %v \n"+ 700 "protoStats %s", 701 n, 702 tTime, 703 procBatchTime, 704 row2colTime, 705 allocateOutBufferTime, 706 oq.flushTime, 707 procBatchTime-row2colTime-allocateOutBufferTime-oq.flushTime, 708 tTime-row2colTime-allocateOutBufferTime, 709 proto.GetStats()) 710 711 return nil 712 } 713 714 // extractRowFromEveryVector gets the j row from the every vector and outputs the row 715 func extractRowFromEveryVector(ses *Session, dataSet *batch.Batch, j int64, oq outputPool) ([]interface{}, error) { 716 row, err := oq.getEmptyRow() 717 if err != nil { 718 return nil, err 719 } 720 var rowIndex = int64(j) 721 for i, vec := range dataSet.Vecs { //col index 722 rowIndexBackup := rowIndex 723 if vec.IsScalarNull() { 724 row[i] = nil 725 continue 726 } 727 if vec.IsScalar() { 728 rowIndex = 0 729 } 730 731 err = extractRowFromVector(ses, vec, i, row, rowIndex) 732 if err != nil { 733 return nil, err 734 } 735 rowIndex = rowIndexBackup 736 } 737 //duplicate rows 738 for i := int64(0); i < dataSet.Zs[j]-1; i++ { 739 erow, rr := oq.getEmptyRow() 740 if rr != nil { 741 return nil, rr 742 } 743 for l := 0; l < len(dataSet.Vecs); l++ { 744 erow[l] = row[l] 745 } 746 } 747 return row, nil 748 } 749 750 func formatFloatNum[T types.Floats](num T, Typ types.Type) T { 751 if Typ.Precision == -1 || Typ.Width == 0 { 752 return num 753 } 754 pow := math.Pow10(int(Typ.Precision)) 755 t := math.Abs(float64(num)) 756 upperLimit := math.Pow10(int(Typ.Width)) 757 if t >= upperLimit { 758 t = upperLimit - 1 759 } else { 760 t *= pow 761 t = math.Round(t) 762 } 763 if t >= upperLimit { 764 t = upperLimit - 1 765 } 766 t /= pow 767 if num < 0 { 768 t = -1 * t 769 } 770 return T(t) 771 } 772 773 // extractRowFromVector gets the rowIndex row from the i vector 774 func extractRowFromVector(ses *Session, vec *vector.Vector, i int, row []interface{}, rowIndex int64) error { 775 timeZone := ses.GetTimeZone() 776 switch vec.Typ.Oid { //get col 777 case types.T_json: 778 if !nulls.Any(vec.Nsp) { 779 row[i] = types.DecodeJson(vec.GetBytes(rowIndex)) 780 } else { 781 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { 782 row[i] = nil 783 } else { 784 row[i] = types.DecodeJson(vec.GetBytes(rowIndex)) 785 } 786 } 787 case types.T_bool: 788 if !nulls.Any(vec.Nsp) { //all data in this column are not null 789 vs := vec.Col.([]bool) 790 row[i] = vs[rowIndex] 791 } else { 792 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { //is null 793 row[i] = nil 794 } else { 795 vs := vec.Col.([]bool) 796 row[i] = vs[rowIndex] 797 } 798 } 799 case types.T_int8: 800 if !nulls.Any(vec.Nsp) { //all data in this column are not null 801 vs := vec.Col.([]int8) 802 row[i] = vs[rowIndex] 803 } else { 804 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { //is null 805 row[i] = nil 806 } else { 807 vs := vec.Col.([]int8) 808 row[i] = vs[rowIndex] 809 } 810 } 811 case types.T_uint8: 812 if !nulls.Any(vec.Nsp) { //all data in this column are not null 813 vs := vec.Col.([]uint8) 814 row[i] = vs[rowIndex] 815 } else { 816 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { //is null 817 row[i] = nil 818 } else { 819 vs := vec.Col.([]uint8) 820 row[i] = vs[rowIndex] 821 } 822 } 823 case types.T_int16: 824 if !nulls.Any(vec.Nsp) { //all data in this column are not null 825 vs := vec.Col.([]int16) 826 row[i] = vs[rowIndex] 827 } else { 828 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { //is null 829 row[i] = nil 830 } else { 831 vs := vec.Col.([]int16) 832 row[i] = vs[rowIndex] 833 } 834 } 835 case types.T_uint16: 836 if !nulls.Any(vec.Nsp) { //all data in this column are not null 837 vs := vec.Col.([]uint16) 838 row[i] = vs[rowIndex] 839 } else { 840 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { //is null 841 row[i] = nil 842 } else { 843 vs := vec.Col.([]uint16) 844 row[i] = vs[rowIndex] 845 } 846 } 847 case types.T_int32: 848 if !nulls.Any(vec.Nsp) { //all data in this column are not null 849 vs := vec.Col.([]int32) 850 row[i] = vs[rowIndex] 851 } else { 852 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { //is null 853 row[i] = nil 854 } else { 855 vs := vec.Col.([]int32) 856 row[i] = vs[rowIndex] 857 } 858 } 859 case types.T_uint32: 860 if !nulls.Any(vec.Nsp) { //all data in this column are not null 861 vs := vec.Col.([]uint32) 862 row[i] = vs[rowIndex] 863 } else { 864 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { //is null 865 row[i] = nil 866 } else { 867 vs := vec.Col.([]uint32) 868 row[i] = vs[rowIndex] 869 } 870 } 871 case types.T_int64: 872 if !nulls.Any(vec.Nsp) { //all data in this column are not null 873 vs := vec.Col.([]int64) 874 row[i] = vs[rowIndex] 875 } else { 876 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { //is null 877 row[i] = nil 878 } else { 879 vs := vec.Col.([]int64) 880 row[i] = vs[rowIndex] 881 } 882 } 883 case types.T_uint64: 884 if !nulls.Any(vec.Nsp) { //all data in this column are not null 885 vs := vec.Col.([]uint64) 886 row[i] = vs[rowIndex] 887 } else { 888 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { //is null 889 row[i] = nil 890 } else { 891 vs := vec.Col.([]uint64) 892 row[i] = vs[rowIndex] 893 } 894 } 895 case types.T_float32: 896 if !nulls.Any(vec.Nsp) { //all data in this column are not null 897 vs := vec.Col.([]float32) 898 row[i] = formatFloatNum(vs[rowIndex], vec.Typ) 899 } else { 900 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { //is null 901 row[i] = nil 902 } else { 903 vs := vec.Col.([]float32) 904 row[i] = formatFloatNum(vs[rowIndex], vec.Typ) 905 } 906 } 907 case types.T_float64: 908 if !nulls.Any(vec.Nsp) { //all data in this column are not null 909 vs := vec.Col.([]float64) 910 row[i] = formatFloatNum(vs[rowIndex], vec.Typ) 911 } else { 912 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { //is null 913 row[i] = nil 914 } else { 915 vs := vec.Col.([]float64) 916 row[i] = formatFloatNum(vs[rowIndex], vec.Typ) 917 } 918 } 919 case types.T_char, types.T_varchar, types.T_blob, types.T_text: 920 if !nulls.Any(vec.Nsp) { //all data in this column are not null 921 row[i] = vec.GetBytes(rowIndex) 922 } else { 923 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { //is null 924 row[i] = nil 925 } else { 926 row[i] = vec.GetBytes(rowIndex) 927 } 928 } 929 case types.T_date: 930 if !nulls.Any(vec.Nsp) { //all data in this column are not null 931 vs := vec.Col.([]types.Date) 932 row[i] = vs[rowIndex] 933 } else { 934 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { //is null 935 row[i] = nil 936 } else { 937 vs := vec.Col.([]types.Date) 938 row[i] = vs[rowIndex] 939 } 940 } 941 case types.T_datetime: 942 precision := vec.Typ.Precision 943 if !nulls.Any(vec.Nsp) { //all data in this column are not null 944 vs := vec.Col.([]types.Datetime) 945 row[i] = vs[rowIndex].String2(precision) 946 } else { 947 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { //is null 948 row[i] = nil 949 } else { 950 vs := vec.Col.([]types.Datetime) 951 row[i] = vs[rowIndex].String2(precision) 952 } 953 } 954 case types.T_time: 955 precision := vec.Typ.Precision 956 if !nulls.Any(vec.Nsp) { //all data in this column are not null 957 vs := vec.Col.([]types.Time) 958 row[i] = vs[rowIndex].String2(precision) 959 } else { 960 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { //is null 961 row[i] = nil 962 } else { 963 vs := vec.Col.([]types.Time) 964 row[i] = vs[rowIndex].String2(precision) 965 } 966 } 967 case types.T_timestamp: 968 precision := vec.Typ.Precision 969 if !nulls.Any(vec.Nsp) { //all data in this column are not null 970 vs := vec.Col.([]types.Timestamp) 971 row[i] = vs[rowIndex].String2(timeZone, precision) 972 } else { 973 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { //is null 974 row[i] = nil 975 } else { 976 vs := vec.Col.([]types.Timestamp) 977 row[i] = vs[rowIndex].String2(timeZone, precision) 978 } 979 } 980 case types.T_decimal64: 981 scale := vec.Typ.Scale 982 if !nulls.Any(vec.Nsp) { //all data in this column are not null 983 vs := vec.Col.([]types.Decimal64) 984 row[i] = vs[rowIndex].ToStringWithScale(scale) 985 } else { 986 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { 987 row[i] = nil 988 } else { 989 vs := vec.Col.([]types.Decimal64) 990 row[i] = vs[rowIndex].ToStringWithScale(scale) 991 } 992 } 993 case types.T_decimal128: 994 scale := vec.Typ.Scale 995 if !nulls.Any(vec.Nsp) { //all data in this column are not null 996 vs := vec.Col.([]types.Decimal128) 997 row[i] = vs[rowIndex].ToStringWithScale(scale) 998 } else { 999 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { 1000 row[i] = nil 1001 } else { 1002 vs := vec.Col.([]types.Decimal128) 1003 row[i] = vs[rowIndex].ToStringWithScale(scale) 1004 } 1005 } 1006 case types.T_uuid: 1007 if !nulls.Any(vec.Nsp) { 1008 vs := vec.Col.([]types.Uuid) 1009 row[i] = vs[rowIndex].ToString() 1010 } else { 1011 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { //is null 1012 row[i] = nil 1013 } else { 1014 vs := vec.Col.([]types.Uuid) 1015 row[i] = vs[rowIndex].ToString() 1016 } 1017 } 1018 case types.T_Rowid: 1019 if !nulls.Any(vec.Nsp) { 1020 vs := vec.Col.([]types.Rowid) 1021 row[i] = vs[rowIndex] 1022 } else { 1023 if nulls.Contains(vec.Nsp, uint64(rowIndex)) { //is null 1024 row[i] = nil 1025 } else { 1026 vs := vec.Col.([]types.Rowid) 1027 row[i] = vs[rowIndex] 1028 } 1029 } 1030 default: 1031 logErrorf(ses.GetConciseProfile(), "extractRowFromVector : unsupported type %d", vec.Typ.Oid) 1032 return moerr.NewInternalError(ses.requestCtx, "extractRowFromVector : unsupported type %d", vec.Typ.Oid) 1033 } 1034 return nil 1035 } 1036 1037 func doUse(ctx context.Context, ses *Session, db string) error { 1038 txnHandler := ses.GetTxnHandler() 1039 var txn TxnOperator 1040 var err error 1041 txn, err = txnHandler.GetTxn() 1042 if err != nil { 1043 return err 1044 } 1045 //TODO: check meta data 1046 if _, err = ses.GetParameterUnit().StorageEngine.Database(ctx, db, txn); err != nil { 1047 //echo client. no such database 1048 return moerr.NewBadDB(ctx, db) 1049 } 1050 oldDB := ses.GetDatabaseName() 1051 ses.SetDatabaseName(db) 1052 1053 logInfof(ses.GetConciseProfile(), "User %s change database from [%s] to [%s]", ses.GetUserName(), oldDB, ses.GetDatabaseName()) 1054 1055 return nil 1056 } 1057 1058 func (mce *MysqlCmdExecutor) handleChangeDB(requestCtx context.Context, db string) error { 1059 return doUse(requestCtx, mce.GetSession(), db) 1060 } 1061 1062 func (mce *MysqlCmdExecutor) handleDump(requestCtx context.Context, dump *tree.MoDump) error { 1063 var err error 1064 if !dump.DumpDatabase { 1065 return doDumpQueryResult(requestCtx, mce.GetSession(), dump.ExportParams) 1066 } 1067 dump.OutFile = maybeAppendExtension(dump.OutFile) 1068 exists, err := fileExists(dump.OutFile) 1069 if exists { 1070 return moerr.NewFileAlreadyExists(requestCtx, dump.OutFile) 1071 } 1072 if err != nil { 1073 return err 1074 } 1075 if dump.MaxFileSize != 0 && dump.MaxFileSize < mpool.MB { 1076 return moerr.NewInvalidInput(requestCtx, "max file size must be larger than 1MB") 1077 } 1078 if len(dump.Database) == 0 { 1079 return moerr.NewInvalidInput(requestCtx, "No database selected") 1080 } 1081 return mce.dumpData(requestCtx, dump) 1082 } 1083 1084 func (mce *MysqlCmdExecutor) dumpData(requestCtx context.Context, dump *tree.MoDump) error { 1085 ses := mce.GetSession() 1086 txnHandler := ses.GetTxnHandler() 1087 bh := ses.GetBackgroundExec(requestCtx) 1088 defer bh.Close() 1089 dbName := string(dump.Database) 1090 var ( 1091 db engine.Database 1092 err error 1093 showDbDDL = false 1094 dbDDL string 1095 tables []string 1096 ) 1097 var txn TxnOperator 1098 txn, err = txnHandler.GetTxn() 1099 if err != nil { 1100 return err 1101 } 1102 if db, err = ses.GetParameterUnit().StorageEngine.Database(requestCtx, dbName, txn); err != nil { 1103 return moerr.NewBadDB(requestCtx, dbName) 1104 } 1105 err = bh.Exec(requestCtx, fmt.Sprintf("use `%s`", dbName)) 1106 if err != nil { 1107 return err 1108 } 1109 if len(dump.Tables) == 0 { 1110 dbDDL = fmt.Sprintf("DROP DATABASE IF EXISTS `%s`;\n", dbName) 1111 createSql, err := getDDL(bh, requestCtx, fmt.Sprintf("SHOW CREATE DATABASE `%s`;", dbName)) 1112 if err != nil { 1113 return err 1114 } 1115 dbDDL += createSql + "\n\nUSE `" + dbName + "`;\n\n" 1116 showDbDDL = true 1117 tables, err = db.Relations(requestCtx) 1118 if err != nil { 1119 return err 1120 } 1121 } else { 1122 tables = make([]string, len(dump.Tables)) 1123 for i, t := range dump.Tables { 1124 tables[i] = string(t.ObjectName) 1125 } 1126 } 1127 1128 params := make([]*dumpTable, 0, len(tables)) 1129 for _, tblName := range tables { 1130 if strings.HasPrefix(tblName, "%!%") { //skip hidden table 1131 continue 1132 } 1133 table, err := db.Relation(requestCtx, tblName) 1134 if err != nil { 1135 return err 1136 } 1137 tblDDL, err := getDDL(bh, requestCtx, fmt.Sprintf("SHOW CREATE TABLE `%s`;", tblName)) 1138 if err != nil { 1139 return err 1140 } 1141 tableDefs, err := table.TableDefs(requestCtx) 1142 if err != nil { 1143 return err 1144 } 1145 attrs, isView, err := getAttrFromTableDef(tableDefs) 1146 if err != nil { 1147 return err 1148 } 1149 if isView { 1150 tblDDL = fmt.Sprintf("DROP VIEW IF EXISTS `%s`;\n", tblName) + tblDDL + "\n\n" 1151 } else { 1152 tblDDL = fmt.Sprintf("DROP TABLE IF EXISTS `%s`;\n", tblName) + tblDDL + "\n\n" 1153 } 1154 params = append(params, &dumpTable{tblName, tblDDL, table, attrs, isView}) 1155 } 1156 return mce.dumpData2File(requestCtx, dump, dbDDL, params, showDbDDL) 1157 } 1158 1159 func (mce *MysqlCmdExecutor) dumpData2File(requestCtx context.Context, dump *tree.MoDump, dbDDL string, params []*dumpTable, showDbDDL bool) error { 1160 ses := mce.GetSession() 1161 var ( 1162 err error 1163 f *os.File 1164 curFileSize int64 = 0 1165 curFileIdx int64 = 1 1166 buf *bytes.Buffer 1167 rbat *batch.Batch 1168 ) 1169 f, err = createDumpFile(requestCtx, dump.OutFile) 1170 if err != nil { 1171 return err 1172 } 1173 defer func() { 1174 if err != nil { 1175 if f != nil { 1176 f.Close() 1177 } 1178 if buf != nil { 1179 buf.Reset() 1180 } 1181 if rbat != nil { 1182 rbat.Clean(ses.mp) 1183 } 1184 removeFile(dump.OutFile, curFileIdx) 1185 } 1186 }() 1187 buf = new(bytes.Buffer) 1188 if showDbDDL { 1189 _, err = buf.WriteString(dbDDL) 1190 if err != nil { 1191 return err 1192 } 1193 } 1194 f, curFileIdx, curFileSize, err = writeDump2File(requestCtx, buf, dump, f, curFileIdx, curFileSize) 1195 if err != nil { 1196 return err 1197 } 1198 for _, param := range params { 1199 if param.isView { 1200 continue 1201 } 1202 _, err = buf.WriteString(param.ddl) 1203 if err != nil { 1204 return err 1205 } 1206 f, curFileIdx, curFileSize, err = writeDump2File(requestCtx, buf, dump, f, curFileIdx, curFileSize) 1207 if err != nil { 1208 return err 1209 } 1210 rds, err := param.rel.NewReader(requestCtx, 1, nil, nil) 1211 if err != nil { 1212 return err 1213 } 1214 for { 1215 bat, err := rds[0].Read(requestCtx, param.attrs, nil, ses.mp) 1216 if err != nil { 1217 return err 1218 } 1219 if bat == nil { 1220 break 1221 } 1222 1223 buf.WriteString("INSERT INTO ") 1224 buf.WriteString(param.name) 1225 buf.WriteString(" VALUES ") 1226 rbat, err = convertValueBat2Str(requestCtx, bat, ses.mp, ses.GetTimeZone()) 1227 if err != nil { 1228 return err 1229 } 1230 for i := 0; i < rbat.Length(); i++ { 1231 if i != 0 { 1232 buf.WriteString(", ") 1233 } 1234 buf.WriteString("(") 1235 for j := 0; j < rbat.VectorCount(); j++ { 1236 if j != 0 { 1237 buf.WriteString(", ") 1238 } 1239 buf.WriteString(rbat.GetVector(int32(j)).GetString(int64(i))) 1240 } 1241 buf.WriteString(")") 1242 } 1243 buf.WriteString(";\n") 1244 f, curFileIdx, curFileSize, err = writeDump2File(requestCtx, buf, dump, f, curFileIdx, curFileSize) 1245 if err != nil { 1246 return err 1247 } 1248 } 1249 buf.WriteString("\n\n\n") 1250 } 1251 if !showDbDDL { 1252 return nil 1253 } 1254 for _, param := range params { 1255 if !param.isView { 1256 continue 1257 } 1258 _, err = buf.WriteString(param.ddl) 1259 if err != nil { 1260 return err 1261 } 1262 f, curFileIdx, curFileSize, err = writeDump2File(requestCtx, buf, dump, f, curFileIdx, curFileSize) 1263 if err != nil { 1264 return err 1265 } 1266 } 1267 return nil 1268 } 1269 1270 /* 1271 handle "SELECT @@xxx.yyyy" 1272 */ 1273 func (mce *MysqlCmdExecutor) handleSelectVariables(ve *tree.VarExpr) error { 1274 var err error = nil 1275 ses := mce.GetSession() 1276 mrs := ses.GetMysqlResultSet() 1277 proto := ses.GetMysqlProtocol() 1278 1279 col := new(MysqlColumn) 1280 col.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 1281 col.SetName("@@" + ve.Name) 1282 mrs.AddColumn(col) 1283 1284 row := make([]interface{}, 1) 1285 if ve.System { 1286 if ve.Global { 1287 val, err := ses.GetGlobalVar(ve.Name) 1288 if err != nil { 1289 return err 1290 } 1291 row[0] = val 1292 } else { 1293 val, err := ses.GetSessionVar(ve.Name) 1294 if err != nil { 1295 return err 1296 } 1297 row[0] = val 1298 } 1299 } else { 1300 //user defined variable 1301 _, val, err := ses.GetUserDefinedVar(ve.Name) 1302 if err != nil { 1303 return err 1304 } 1305 row[0] = val 1306 } 1307 1308 mrs.AddRow(row) 1309 1310 mer := NewMysqlExecutionResult(0, 0, 0, 0, mrs) 1311 resp := NewResponse(ResultResponse, 0, int(COM_QUERY), mer) 1312 1313 if err := proto.SendResponse(ses.GetRequestContext(), resp); err != nil { 1314 return moerr.NewInternalError(ses.GetRequestContext(), "routine send response failed. error:%v ", err) 1315 } 1316 return err 1317 } 1318 1319 func doLoadData(requestCtx context.Context, ses *Session, proc *process.Process, load *tree.Import) (*LoadResult, error) { 1320 var err error 1321 var txn TxnOperator 1322 var dbHandler engine.Database 1323 var tableHandler engine.Relation 1324 proto := ses.GetMysqlProtocol() 1325 1326 logInfof(ses.GetConciseProfile(), "+++++load data") 1327 /* 1328 TODO:support LOCAL 1329 */ 1330 if load.Local { 1331 return nil, moerr.NewInternalError(requestCtx, "LOCAL is unsupported now") 1332 } 1333 if load.Param.Tail.Fields == nil || len(load.Param.Tail.Fields.Terminated) == 0 { 1334 load.Param.Tail.Fields = &tree.Fields{Terminated: ","} 1335 } 1336 1337 if load.Param.Tail.Fields != nil && load.Param.Tail.Fields.EscapedBy != 0 { 1338 return nil, moerr.NewInternalError(requestCtx, "EscapedBy field is unsupported now") 1339 } 1340 1341 /* 1342 check file 1343 */ 1344 exist, isfile, err := PathExists(load.Param.Filepath) 1345 if err != nil || !exist { 1346 return nil, moerr.NewInternalError(requestCtx, "file %s does exist. err:%v", load.Param.Filepath, err) 1347 } 1348 1349 if !isfile { 1350 return nil, moerr.NewInternalError(requestCtx, "file %s is a directory", load.Param.Filepath) 1351 } 1352 1353 /* 1354 check database 1355 */ 1356 loadDb := string(load.Table.Schema()) 1357 loadTable := string(load.Table.Name()) 1358 if loadDb == "" { 1359 if proto.GetDatabaseName() == "" { 1360 return nil, moerr.NewInternalError(requestCtx, "load data need database") 1361 } 1362 1363 //then, it uses the database name in the session 1364 loadDb = ses.GetDatabaseName() 1365 } 1366 1367 txnHandler := ses.GetTxnHandler() 1368 if ses.InMultiStmtTransactionMode() { 1369 return nil, moerr.NewInternalError(requestCtx, "do not support the Load in a transaction started by BEGIN/START TRANSACTION statement") 1370 } 1371 txn, err = txnHandler.GetTxn() 1372 if err != nil { 1373 return nil, err 1374 } 1375 dbHandler, err = ses.GetStorage().Database(requestCtx, loadDb, txn) 1376 if err != nil { 1377 //echo client. no such database 1378 return nil, moerr.NewBadDB(requestCtx, loadDb) 1379 } 1380 1381 //change db to the database in the LOAD DATA statement if necessary 1382 if loadDb != ses.GetDatabaseName() { 1383 oldDB := ses.GetDatabaseName() 1384 ses.SetDatabaseName(loadDb) 1385 logInfof(ses.GetConciseProfile(), "User %s change database from [%s] to [%s] in LOAD DATA", ses.GetUserName(), oldDB, ses.GetDatabaseName()) 1386 } 1387 1388 /* 1389 check table 1390 */ 1391 if ses.IfInitedTempEngine() { 1392 requestCtx = context.WithValue(requestCtx, defines.TemporaryDN{}, ses.GetTempTableStorage()) 1393 } 1394 tableHandler, err = dbHandler.Relation(requestCtx, loadTable) 1395 if err != nil { 1396 txn, err = ses.txnHandler.GetTxn() 1397 if err != nil { 1398 return nil, err 1399 } 1400 dbHandler, err = ses.GetStorage().Database(requestCtx, defines.TEMPORARY_DBNAME, txn) 1401 if err != nil { 1402 return nil, moerr.NewNoSuchTable(requestCtx, loadDb, loadTable) 1403 } 1404 loadTable = engine.GetTempTableName(loadDb, loadTable) 1405 tableHandler, err = dbHandler.Relation(requestCtx, loadTable) 1406 if err != nil { 1407 //echo client. no such table 1408 return nil, moerr.NewNoSuchTable(requestCtx, loadDb, loadTable) 1409 } 1410 loadDb = defines.TEMPORARY_DBNAME 1411 load.Table.ObjectName = tree.Identifier(loadTable) 1412 } 1413 1414 /* 1415 execute load data 1416 */ 1417 return LoadLoop(requestCtx, ses, proc, load, dbHandler, tableHandler, loadDb) 1418 } 1419 1420 /* 1421 handle Load DataSource statement 1422 */ 1423 func (mce *MysqlCmdExecutor) handleLoadData(requestCtx context.Context, proc *process.Process, load *tree.Import) error { 1424 ses := mce.GetSession() 1425 result, err := doLoadData(requestCtx, ses, proc, load) 1426 if err != nil { 1427 return err 1428 } 1429 /* 1430 response 1431 */ 1432 info := moerr.NewLoadInfo(requestCtx, result.Records, result.Deleted, result.Skipped, result.Warnings, result.WriteTimeout).Error() 1433 resp := NewOkResponse(result.Records, 0, uint16(result.Warnings), 0, int(COM_QUERY), info) 1434 if err = ses.GetMysqlProtocol().SendResponse(requestCtx, resp); err != nil { 1435 return moerr.NewInternalError(requestCtx, "routine send response failed. error:%v ", err) 1436 } 1437 return nil 1438 } 1439 1440 func doCmdFieldList(requestCtx context.Context, ses *Session, icfl *InternalCmdFieldList) error { 1441 dbName := ses.GetDatabaseName() 1442 if dbName == "" { 1443 return moerr.NewNoDB(requestCtx) 1444 } 1445 1446 //Get table infos for the database from the cube 1447 //case 1: there are no table infos for the db 1448 //case 2: db changed 1449 //NOTE: it costs too much time. 1450 //It just reduces the information in the auto-completion (auto-rehash) of the mysql client. 1451 //var attrs []ColumnInfo 1452 // 1453 //if mce.tableInfos == nil || mce.db != dbName { 1454 // txnHandler := ses.GetTxnHandler() 1455 // eng := ses.GetStorage() 1456 // db, err := eng.Database(requestCtx, dbName, txnHandler.GetTxn()) 1457 // if err != nil { 1458 // return err 1459 // } 1460 // 1461 // names, err := db.Relations(requestCtx) 1462 // if err != nil { 1463 // return err 1464 // } 1465 // for _, name := range names { 1466 // table, err := db.Relation(requestCtx, name) 1467 // if err != nil { 1468 // return err 1469 // } 1470 // 1471 // defs, err := table.TableDefs(requestCtx) 1472 // if err != nil { 1473 // return err 1474 // } 1475 // for _, def := range defs { 1476 // if attr, ok := def.(*engine.AttributeDef); ok { 1477 // attrs = append(attrs, &engineColumnInfo{ 1478 // name: attr.Attr.Name, 1479 // typ: attr.Attr.Type, 1480 // }) 1481 // } 1482 // } 1483 // } 1484 // 1485 // if mce.tableInfos == nil { 1486 // mce.tableInfos = make(map[string][]ColumnInfo) 1487 // } 1488 // mce.tableInfos[tableName] = attrs 1489 //} 1490 // 1491 //cols, ok := mce.tableInfos[tableName] 1492 //if !ok { 1493 // //just give the empty info when there is no such table. 1494 // attrs = make([]ColumnInfo, 0) 1495 //} else { 1496 // attrs = cols 1497 //} 1498 // 1499 //for _, c := range attrs { 1500 // col := new(MysqlColumn) 1501 // col.SetName(c.GetName()) 1502 // err = convertEngineTypeToMysqlType(c.GetType(), col) 1503 // if err != nil { 1504 // return err 1505 // } 1506 // 1507 // /* 1508 // mysql CMD_FIELD_LIST response: send the column definition per column 1509 // */ 1510 // err = proto.SendColumnDefinitionPacket(col, int(COM_FIELD_LIST)) 1511 // if err != nil { 1512 // return err 1513 // } 1514 //} 1515 return nil 1516 } 1517 1518 /* 1519 handle cmd CMD_FIELD_LIST 1520 */ 1521 func (mce *MysqlCmdExecutor) handleCmdFieldList(requestCtx context.Context, icfl *InternalCmdFieldList) error { 1522 var err error 1523 ses := mce.GetSession() 1524 proto := ses.GetMysqlProtocol() 1525 1526 err = doCmdFieldList(requestCtx, ses, icfl) 1527 if err != nil { 1528 return err 1529 } 1530 1531 /* 1532 mysql CMD_FIELD_LIST response: End after the column has been sent. 1533 send EOF packet 1534 */ 1535 err = proto.sendEOFOrOkPacket(0, 0) 1536 if err != nil { 1537 return err 1538 } 1539 1540 return err 1541 } 1542 1543 func doSetVar(ctx context.Context, ses *Session, sv *tree.SetVar) error { 1544 var err error = nil 1545 setVarFunc := func(system, global bool, name string, value interface{}) error { 1546 if system { 1547 if global { 1548 err = ses.SetGlobalVar(name, value) 1549 if err != nil { 1550 return err 1551 } 1552 } else { 1553 err = ses.SetSessionVar(name, value) 1554 if err != nil { 1555 return err 1556 } 1557 } 1558 1559 if strings.ToLower(name) == "autocommit" { 1560 svbt := SystemVariableBoolType{} 1561 newValue, err2 := svbt.Convert(value) 1562 if err2 != nil { 1563 return err2 1564 } 1565 err = ses.SetAutocommit(svbt.IsTrue(newValue)) 1566 if err != nil { 1567 return err 1568 } 1569 } 1570 } else { 1571 err = ses.SetUserDefinedVar(name, value) 1572 if err != nil { 1573 return err 1574 } 1575 } 1576 return nil 1577 } 1578 for _, assign := range sv.Assignments { 1579 name := assign.Name 1580 var value interface{} 1581 1582 value, err = GetSimpleExprValue(assign.Value, ses) 1583 if err != nil { 1584 return err 1585 } 1586 1587 if systemVar, ok := gSysVarsDefs[name]; ok { 1588 if isDefault, ok := value.(bool); ok && isDefault { 1589 value = systemVar.Default 1590 } 1591 } 1592 1593 //TODO : fix SET NAMES after parser is ready 1594 if name == "names" { 1595 //replaced into three system variable: 1596 //character_set_client, character_set_connection, and character_set_results 1597 replacedBy := []string{ 1598 "character_set_client", "character_set_connection", "character_set_results", 1599 } 1600 for _, rb := range replacedBy { 1601 err = setVarFunc(assign.System, assign.Global, rb, value) 1602 if err != nil { 1603 return err 1604 } 1605 } 1606 } else { 1607 err = setVarFunc(assign.System, assign.Global, name, value) 1608 if err != nil { 1609 return err 1610 } 1611 } 1612 } 1613 return err 1614 } 1615 1616 /* 1617 handle setvar 1618 */ 1619 func (mce *MysqlCmdExecutor) handleSetVar(ctx context.Context, sv *tree.SetVar) error { 1620 ses := mce.GetSession() 1621 err := doSetVar(ctx, ses, sv) 1622 if err != nil { 1623 return err 1624 } 1625 1626 return nil 1627 } 1628 1629 func doShowErrors(ses *Session) error { 1630 var err error 1631 1632 levelCol := new(MysqlColumn) 1633 levelCol.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 1634 levelCol.SetName("Level") 1635 1636 CodeCol := new(MysqlColumn) 1637 CodeCol.SetColumnType(defines.MYSQL_TYPE_SHORT) 1638 CodeCol.SetName("Code") 1639 1640 MsgCol := new(MysqlColumn) 1641 MsgCol.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 1642 MsgCol.SetName("Message") 1643 1644 mrs := ses.GetMysqlResultSet() 1645 1646 mrs.AddColumn(levelCol) 1647 mrs.AddColumn(CodeCol) 1648 mrs.AddColumn(MsgCol) 1649 1650 info := ses.GetErrInfo() 1651 1652 for i := info.length() - 1; i >= 0; i-- { 1653 row := make([]interface{}, 3) 1654 row[0] = "Error" 1655 row[1] = info.codes[i] 1656 row[2] = info.msgs[i] 1657 mrs.AddRow(row) 1658 } 1659 1660 return err 1661 } 1662 1663 func (mce *MysqlCmdExecutor) handleShowErrors() error { 1664 var err error 1665 ses := mce.GetSession() 1666 proto := ses.GetMysqlProtocol() 1667 err = doShowErrors(ses) 1668 if err != nil { 1669 return err 1670 } 1671 1672 mer := NewMysqlExecutionResult(0, 0, 0, 0, ses.GetMysqlResultSet()) 1673 resp := NewResponse(ResultResponse, 0, int(COM_QUERY), mer) 1674 1675 if err := proto.SendResponse(ses.requestCtx, resp); err != nil { 1676 return moerr.NewInternalError(ses.requestCtx, "routine send response failed. error:%v ", err) 1677 } 1678 return err 1679 } 1680 1681 func doShowVariables(ses *Session, proc *process.Process, sv *tree.ShowVariables) error { 1682 if sv.Like != nil && sv.Where != nil { 1683 return moerr.NewSyntaxError(ses.GetRequestContext(), "like clause and where clause cannot exist at the same time") 1684 } 1685 1686 var err error = nil 1687 1688 col1 := new(MysqlColumn) 1689 col1.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 1690 col1.SetName("Variable_name") 1691 1692 col2 := new(MysqlColumn) 1693 col2.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 1694 col2.SetName("Value") 1695 1696 mrs := ses.GetMysqlResultSet() 1697 mrs.AddColumn(col1) 1698 mrs.AddColumn(col2) 1699 1700 var hasLike = false 1701 var likePattern = "" 1702 var isIlike = false 1703 if sv.Like != nil { 1704 hasLike = true 1705 if sv.Like.Op == tree.ILIKE { 1706 isIlike = true 1707 } 1708 likePattern = strings.ToLower(sv.Like.Right.String()) 1709 } 1710 1711 var sysVars map[string]interface{} 1712 if sv.Global { 1713 sysVars = make(map[string]interface{}) 1714 for k, v := range gSysVarsDefs { 1715 sysVars[k] = v.Default 1716 } 1717 } else { 1718 sysVars = ses.CopyAllSessionVars() 1719 } 1720 1721 rows := make([][]interface{}, 0, len(sysVars)) 1722 for name, value := range sysVars { 1723 if hasLike { 1724 s := name 1725 if isIlike { 1726 s = strings.ToLower(s) 1727 } 1728 if !WildcardMatch(likePattern, s) { 1729 continue 1730 } 1731 } 1732 row := make([]interface{}, 2) 1733 row[0] = name 1734 gsv, ok := GSysVariables.GetDefinitionOfSysVar(name) 1735 if !ok { 1736 return moerr.NewInternalError(ses.GetRequestContext(), errorSystemVariableDoesNotExist()) 1737 } 1738 row[1] = value 1739 if _, ok := gsv.GetType().(SystemVariableBoolType); ok { 1740 v, ok := value.(int8) 1741 if ok { 1742 if v == 1 { 1743 row[1] = "on" 1744 } else { 1745 row[1] = "off" 1746 } 1747 } 1748 } 1749 rows = append(rows, row) 1750 } 1751 1752 if sv.Where != nil { 1753 bat, err := constructVarBatch(ses, rows) 1754 if err != nil { 1755 return err 1756 } 1757 binder := plan2.NewDefaultBinder(proc.Ctx, nil, nil, &plan2.Type{Id: int32(types.T_varchar), Width: types.MaxVarcharLen}, []string{"variable_name", "value"}) 1758 planExpr, err := binder.BindExpr(sv.Where.Expr, 0, false) 1759 if err != nil { 1760 return err 1761 } 1762 1763 vec, err := colexec.EvalExpr(bat, proc, planExpr) 1764 if err != nil { 1765 return err 1766 } 1767 bs := vector.GetColumn[bool](vec) 1768 sels := proc.Mp().GetSels() 1769 for i, b := range bs { 1770 if b { 1771 sels = append(sels, int64(i)) 1772 } 1773 } 1774 bat.Shrink(sels) 1775 proc.Mp().PutSels(sels) 1776 v0 := vector.MustStrCols(bat.Vecs[0]) 1777 v1 := vector.MustStrCols(bat.Vecs[1]) 1778 rows = rows[:len(v0)] 1779 for i := range v0 { 1780 rows[i][0] = v0[i] 1781 rows[i][1] = v1[i] 1782 } 1783 bat.Clean(proc.Mp()) 1784 } 1785 1786 //sort by name 1787 sort.Slice(rows, func(i, j int) bool { 1788 return rows[i][0].(string) < rows[j][0].(string) 1789 }) 1790 1791 for _, row := range rows { 1792 mrs.AddRow(row) 1793 } 1794 1795 return err 1796 } 1797 1798 /* 1799 handle show variables 1800 */ 1801 func (mce *MysqlCmdExecutor) handleShowVariables(sv *tree.ShowVariables, proc *process.Process) error { 1802 ses := mce.GetSession() 1803 proto := ses.GetMysqlProtocol() 1804 err := doShowVariables(ses, proc, sv) 1805 if err != nil { 1806 return err 1807 } 1808 mer := NewMysqlExecutionResult(0, 0, 0, 0, ses.GetMysqlResultSet()) 1809 resp := NewResponse(ResultResponse, 0, int(COM_QUERY), mer) 1810 1811 if err := proto.SendResponse(ses.requestCtx, resp); err != nil { 1812 return moerr.NewInternalError(ses.requestCtx, "routine send response failed. error:%v ", err) 1813 } 1814 return err 1815 } 1816 1817 func constructVarBatch(ses *Session, rows [][]interface{}) (*batch.Batch, error) { 1818 bat := batch.New(true, []string{"Variable_name", "Value"}) 1819 typ := types.New(types.T_varchar, types.MaxVarcharLen, 0, 0) 1820 cnt := len(rows) 1821 bat.Zs = make([]int64, cnt) 1822 for i := range bat.Zs { 1823 bat.Zs[i] = 1 1824 } 1825 v0 := make([]string, cnt) 1826 v1 := make([]string, cnt) 1827 for i, row := range rows { 1828 v0[i] = row[0].(string) 1829 v1[i] = fmt.Sprintf("%v", row[1]) 1830 } 1831 bat.Vecs[0] = vector.NewWithStrings(typ, v0, nil, ses.GetMemPool()) 1832 bat.Vecs[1] = vector.NewWithStrings(typ, v1, nil, ses.GetMemPool()) 1833 return bat, nil 1834 } 1835 1836 func (mce *MysqlCmdExecutor) handleAnalyzeStmt(requestCtx context.Context, stmt *tree.AnalyzeStmt) error { 1837 // rewrite analyzeStmt to `select approx_count_distinct(col), .. from tbl` 1838 // IMO, this approach is simple and future-proof 1839 // Although this rewriting processing could have been handled in rewrite module, 1840 // `handleAnalyzeStmt` can be easily managed by cron jobs in the future 1841 ctx := tree.NewFmtCtx(dialect.MYSQL) 1842 ctx.WriteString("select ") 1843 for i, ident := range stmt.Cols { 1844 if i > 0 { 1845 ctx.WriteByte(',') 1846 } 1847 ctx.WriteString("approx_count_distinct(") 1848 ctx.WriteString(string(ident)) 1849 ctx.WriteByte(')') 1850 } 1851 ctx.WriteString(" from ") 1852 stmt.Table.Format(ctx) 1853 sql := ctx.String() 1854 return mce.GetDoQueryFunc()(requestCtx, sql) 1855 } 1856 1857 // Note: for pass the compile quickly. We will remove the comments in the future. 1858 func (mce *MysqlCmdExecutor) handleExplainStmt(requestCtx context.Context, stmt *tree.ExplainStmt) error { 1859 es, err := getExplainOption(requestCtx, stmt.Options) 1860 if err != nil { 1861 return err 1862 } 1863 1864 ses := mce.GetSession() 1865 1866 switch stmt.Statement.(type) { 1867 case *tree.Delete: 1868 ses.GetTxnCompileCtx().SetQueryType(TXN_DELETE) 1869 case *tree.Update: 1870 ses.GetTxnCompileCtx().SetQueryType(TXN_UPDATE) 1871 default: 1872 ses.GetTxnCompileCtx().SetQueryType(TXN_DEFAULT) 1873 } 1874 1875 //get query optimizer and execute Optimize 1876 plan, err := buildPlan(requestCtx, ses, ses.GetTxnCompileCtx(), stmt.Statement) 1877 if err != nil { 1878 return err 1879 } 1880 if plan.GetQuery() == nil { 1881 return moerr.NewNotSupported(requestCtx, "the sql query plan does not support explain.") 1882 } 1883 // generator query explain 1884 explainQuery := explain.NewExplainQueryImpl(plan.GetQuery()) 1885 1886 // build explain data buffer 1887 buffer := explain.NewExplainDataBuffer() 1888 err = explainQuery.ExplainPlan(requestCtx, buffer, es) 1889 if err != nil { 1890 return err 1891 } 1892 1893 protocol := ses.GetMysqlProtocol() 1894 1895 explainColName := "QUERY PLAN" 1896 columns, err := GetExplainColumns(requestCtx, explainColName) 1897 if err != nil { 1898 return err 1899 } 1900 1901 // Step 1 : send column count and column definition. 1902 //send column count 1903 colCnt := uint64(len(columns)) 1904 err = protocol.SendColumnCountPacket(colCnt) 1905 if err != nil { 1906 return err 1907 } 1908 //send columns 1909 //column_count * Protocol::ColumnDefinition packets 1910 cmd := ses.GetCmd() 1911 mrs := ses.GetMysqlResultSet() 1912 for _, c := range columns { 1913 mysqlc := c.(Column) 1914 mrs.AddColumn(mysqlc) 1915 // mysql COM_QUERY response: send the column definition per column 1916 err := protocol.SendColumnDefinitionPacket(requestCtx, mysqlc, int(cmd)) 1917 if err != nil { 1918 return err 1919 } 1920 } 1921 1922 // mysql COM_QUERY response: End after the column has been sent. 1923 // send EOF packet 1924 err = protocol.SendEOFPacketIf(0, 0) 1925 if err != nil { 1926 return err 1927 } 1928 1929 err = buildMoExplainQuery(explainColName, buffer, ses, getDataFromPipeline) 1930 if err != nil { 1931 return err 1932 } 1933 1934 err = protocol.sendEOFOrOkPacket(0, 0) 1935 if err != nil { 1936 return err 1937 } 1938 return nil 1939 } 1940 1941 func doPrepareStmt(ctx context.Context, ses *Session, st *tree.PrepareStmt) (*PrepareStmt, error) { 1942 switch st.Stmt.(type) { 1943 case *tree.Update: 1944 ses.GetTxnCompileCtx().SetQueryType(TXN_UPDATE) 1945 case *tree.Delete: 1946 ses.GetTxnCompileCtx().SetQueryType(TXN_DELETE) 1947 } 1948 preparePlan, err := buildPlan(ctx, ses, ses.GetTxnCompileCtx(), st) 1949 if err != nil { 1950 return nil, err 1951 } 1952 1953 prepareStmt := &PrepareStmt{ 1954 Name: preparePlan.GetDcl().GetPrepare().GetName(), 1955 PreparePlan: preparePlan, 1956 PrepareStmt: st.Stmt, 1957 } 1958 1959 err = ses.SetPrepareStmt(preparePlan.GetDcl().GetPrepare().GetName(), prepareStmt) 1960 return prepareStmt, err 1961 } 1962 1963 // handlePrepareStmt 1964 func (mce *MysqlCmdExecutor) handlePrepareStmt(ctx context.Context, st *tree.PrepareStmt) (*PrepareStmt, error) { 1965 return doPrepareStmt(ctx, mce.GetSession(), st) 1966 } 1967 1968 func doPrepareString(ctx context.Context, ses *Session, st *tree.PrepareString) (*PrepareStmt, error) { 1969 stmts, err := mysql.Parse(ctx, st.Sql) 1970 if err != nil { 1971 return nil, err 1972 } 1973 switch stmts[0].(type) { 1974 case *tree.Update: 1975 ses.GetTxnCompileCtx().SetQueryType(TXN_UPDATE) 1976 case *tree.Delete: 1977 ses.GetTxnCompileCtx().SetQueryType(TXN_DELETE) 1978 } 1979 1980 preparePlan, err := buildPlan(ses.GetRequestContext(), ses, ses.GetTxnCompileCtx(), st) 1981 if err != nil { 1982 return nil, err 1983 } 1984 1985 prepareStmt := &PrepareStmt{ 1986 Name: preparePlan.GetDcl().GetPrepare().GetName(), 1987 PreparePlan: preparePlan, 1988 PrepareStmt: stmts[0], 1989 } 1990 1991 err = ses.SetPrepareStmt(preparePlan.GetDcl().GetPrepare().GetName(), prepareStmt) 1992 return prepareStmt, err 1993 } 1994 1995 // handlePrepareString 1996 func (mce *MysqlCmdExecutor) handlePrepareString(ctx context.Context, st *tree.PrepareString) (*PrepareStmt, error) { 1997 return doPrepareString(ctx, mce.GetSession(), st) 1998 } 1999 2000 func doDeallocate(ctx context.Context, ses *Session, st *tree.Deallocate) error { 2001 deallocatePlan, err := buildPlan(ctx, ses, ses.GetTxnCompileCtx(), st) 2002 if err != nil { 2003 return err 2004 } 2005 ses.RemovePrepareStmt(deallocatePlan.GetDcl().GetDeallocate().GetName()) 2006 return nil 2007 } 2008 2009 func doReset(ctx context.Context, ses *Session, st *tree.Reset) error { 2010 return nil 2011 } 2012 2013 // handleDeallocate 2014 func (mce *MysqlCmdExecutor) handleDeallocate(ctx context.Context, st *tree.Deallocate) error { 2015 return doDeallocate(ctx, mce.GetSession(), st) 2016 } 2017 2018 // handleReset 2019 func (mce *MysqlCmdExecutor) handleReset(ctx context.Context, st *tree.Reset) error { 2020 return doReset(ctx, mce.GetSession(), st) 2021 } 2022 2023 // handleCreateAccount creates a new user-level tenant in the context of the tenant SYS 2024 // which has been initialized. 2025 func (mce *MysqlCmdExecutor) handleCreateAccount(ctx context.Context, ca *tree.CreateAccount) error { 2026 //step1 : create new account. 2027 return InitGeneralTenant(ctx, mce.GetSession(), ca) 2028 } 2029 2030 // handleDropAccount drops a new user-level tenant 2031 func (mce *MysqlCmdExecutor) handleDropAccount(ctx context.Context, da *tree.DropAccount) error { 2032 return doDropAccount(ctx, mce.GetSession(), da) 2033 } 2034 2035 // handleDropAccount drops a new user-level tenant 2036 func (mce *MysqlCmdExecutor) handleAlterAccount(ctx context.Context, aa *tree.AlterAccount) error { 2037 return doAlterAccount(ctx, mce.GetSession(), aa) 2038 } 2039 2040 // handleAlterDatabaseConfig alter a database's mysql_compatbility_mode 2041 func (mce *MysqlCmdExecutor) handleAlterDataBaseConfig(ctx context.Context, ad *tree.AlterDataBaseConfig) error { 2042 return doAlterDatabaseConfig(ctx, mce.GetSession(), ad) 2043 } 2044 2045 // handleAlterAccountConfig alter a account's mysql_compatbility_mode 2046 func (mce *MysqlCmdExecutor) handleAlterAccountConfig(ctx context.Context, st *tree.AlterDataBaseConfig) error { 2047 return doAlterAccountConfig(ctx, mce.GetSession(), st) 2048 } 2049 2050 // handleCreateUser creates the user for the tenant 2051 func (mce *MysqlCmdExecutor) handleCreateUser(ctx context.Context, cu *tree.CreateUser) error { 2052 ses := mce.GetSession() 2053 tenant := ses.GetTenantInfo() 2054 2055 //step1 : create the user 2056 return InitUser(ctx, ses, tenant, cu) 2057 } 2058 2059 // handleDropUser drops the user for the tenant 2060 func (mce *MysqlCmdExecutor) handleDropUser(ctx context.Context, du *tree.DropUser) error { 2061 return doDropUser(ctx, mce.GetSession(), du) 2062 } 2063 2064 // handleCreateRole creates the new role 2065 func (mce *MysqlCmdExecutor) handleCreateRole(ctx context.Context, cr *tree.CreateRole) error { 2066 ses := mce.GetSession() 2067 tenant := ses.GetTenantInfo() 2068 2069 //step1 : create the role 2070 return InitRole(ctx, ses, tenant, cr) 2071 } 2072 2073 // handleDropRole drops the role 2074 func (mce *MysqlCmdExecutor) handleDropRole(ctx context.Context, dr *tree.DropRole) error { 2075 return doDropRole(ctx, mce.GetSession(), dr) 2076 } 2077 2078 func (mce *MysqlCmdExecutor) handleCreateFunction(ctx context.Context, cf *tree.CreateFunction) error { 2079 ses := mce.GetSession() 2080 tenant := ses.GetTenantInfo() 2081 2082 return InitFunction(ctx, ses, tenant, cf) 2083 } 2084 2085 func (mce *MysqlCmdExecutor) handleDropFunction(ctx context.Context, df *tree.DropFunction) error { 2086 return doDropFunction(ctx, mce.GetSession(), df) 2087 } 2088 2089 // handleGrantRole grants the role 2090 func (mce *MysqlCmdExecutor) handleGrantRole(ctx context.Context, gr *tree.GrantRole) error { 2091 return doGrantRole(ctx, mce.GetSession(), gr) 2092 } 2093 2094 // handleRevokeRole revokes the role 2095 func (mce *MysqlCmdExecutor) handleRevokeRole(ctx context.Context, rr *tree.RevokeRole) error { 2096 return doRevokeRole(ctx, mce.GetSession(), rr) 2097 } 2098 2099 // handleGrantRole grants the privilege to the role 2100 func (mce *MysqlCmdExecutor) handleGrantPrivilege(ctx context.Context, gp *tree.GrantPrivilege) error { 2101 return doGrantPrivilege(ctx, mce.GetSession(), gp) 2102 } 2103 2104 // handleRevokePrivilege revokes the privilege from the user or role 2105 func (mce *MysqlCmdExecutor) handleRevokePrivilege(ctx context.Context, rp *tree.RevokePrivilege) error { 2106 return doRevokePrivilege(ctx, mce.GetSession(), rp) 2107 } 2108 2109 // handleSwitchRole switches the role to another role 2110 func (mce *MysqlCmdExecutor) handleSwitchRole(ctx context.Context, sr *tree.SetRole) error { 2111 return doSwitchRole(ctx, mce.GetSession(), sr) 2112 } 2113 2114 func doKill(ctx context.Context, rm *RoutineManager, ses *Session, k *tree.Kill) error { 2115 var err error 2116 //true: kill a connection 2117 //false: kill a query in a connection 2118 idThatKill := uint64(ses.GetConnectionID()) 2119 if !k.Option.Exist || k.Option.Typ == tree.KillTypeConnection { 2120 err = rm.kill(ctx, true, idThatKill, k.ConnectionId, "") 2121 } else { 2122 err = rm.kill(ctx, false, idThatKill, k.ConnectionId, k.StmtOption.StatementId) 2123 } 2124 return err 2125 } 2126 2127 // handleKill kill a connection or query 2128 func (mce *MysqlCmdExecutor) handleKill(ctx context.Context, k *tree.Kill) error { 2129 var err error 2130 ses := mce.GetSession() 2131 proto := ses.GetMysqlProtocol() 2132 err = doKill(ctx, mce.GetRoutineManager(), ses, k) 2133 if err != nil { 2134 return err 2135 } 2136 resp := NewGeneralOkResponse(COM_QUERY) 2137 if err = proto.SendResponse(ctx, resp); err != nil { 2138 return moerr.NewInternalError(ctx, "routine send response failed. error:%v ", err) 2139 } 2140 return err 2141 } 2142 2143 // handleShowAccounts lists the info of accounts 2144 func (mce *MysqlCmdExecutor) handleShowAccounts(ctx context.Context, sa *tree.ShowAccounts) error { 2145 var err error 2146 ses := mce.GetSession() 2147 proto := ses.GetMysqlProtocol() 2148 err = doShowAccounts(ctx, ses, sa) 2149 if err != nil { 2150 return err 2151 } 2152 mer := NewMysqlExecutionResult(0, 0, 0, 0, ses.GetMysqlResultSet()) 2153 resp := NewResponse(ResultResponse, 0, int(COM_QUERY), mer) 2154 2155 if err = proto.SendResponse(ctx, resp); err != nil { 2156 return moerr.NewInternalError(ctx, "routine send response failed. error:%v ", err) 2157 } 2158 return err 2159 } 2160 2161 func GetExplainColumns(ctx context.Context, explainColName string) ([]interface{}, error) { 2162 cols := []*plan2.ColDef{ 2163 {Typ: &plan2.Type{Id: int32(types.T_varchar)}, Name: explainColName}, 2164 } 2165 columns := make([]interface{}, len(cols)) 2166 var err error = nil 2167 for i, col := range cols { 2168 c := new(MysqlColumn) 2169 c.SetName(col.Name) 2170 err = convertEngineTypeToMysqlType(ctx, types.T(col.Typ.Id), c) 2171 if err != nil { 2172 return nil, err 2173 } 2174 columns[i] = c 2175 } 2176 return columns, err 2177 } 2178 2179 func getExplainOption(requestCtx context.Context, options []tree.OptionElem) (*explain.ExplainOptions, error) { 2180 es := explain.NewExplainDefaultOptions() 2181 if options == nil { 2182 return es, nil 2183 } else { 2184 for _, v := range options { 2185 if strings.EqualFold(v.Name, "VERBOSE") { 2186 if strings.EqualFold(v.Value, "TRUE") || v.Value == "NULL" { 2187 es.Verbose = true 2188 } else if strings.EqualFold(v.Value, "FALSE") { 2189 es.Verbose = false 2190 } else { 2191 return nil, moerr.NewInvalidInput(requestCtx, "invalid explain option '%s', valud '%s'", v.Name, v.Value) 2192 } 2193 } else if strings.EqualFold(v.Name, "ANALYZE") { 2194 if strings.EqualFold(v.Value, "TRUE") || v.Value == "NULL" { 2195 es.Analyze = true 2196 } else if strings.EqualFold(v.Value, "FALSE") { 2197 es.Analyze = false 2198 } else { 2199 return nil, moerr.NewInvalidInput(requestCtx, "invalid explain option '%s', valud '%s'", v.Name, v.Value) 2200 } 2201 } else if strings.EqualFold(v.Name, "FORMAT") { 2202 if strings.EqualFold(v.Value, "TEXT") { 2203 es.Format = explain.EXPLAIN_FORMAT_TEXT 2204 } else if strings.EqualFold(v.Value, "JSON") { 2205 return nil, moerr.NewNotSupported(requestCtx, "Unsupport explain format '%s'", v.Value) 2206 } else if strings.EqualFold(v.Value, "DOT") { 2207 return nil, moerr.NewNotSupported(requestCtx, "Unsupport explain format '%s'", v.Value) 2208 } else { 2209 return nil, moerr.NewInvalidInput(requestCtx, "invalid explain option '%s', valud '%s'", v.Name, v.Value) 2210 } 2211 } else { 2212 return nil, moerr.NewInvalidInput(requestCtx, "invalid explain option '%s', valud '%s'", v.Name, v.Value) 2213 } 2214 } 2215 return es, nil 2216 } 2217 } 2218 2219 func buildMoExplainQuery(explainColName string, buffer *explain.ExplainDataBuffer, session *Session, fill func(interface{}, *batch.Batch) error) error { 2220 bat := batch.New(true, []string{explainColName}) 2221 rs := buffer.Lines 2222 vs := make([][]byte, len(rs)) 2223 2224 count := 0 2225 for _, r := range rs { 2226 str := []byte(r) 2227 vs[count] = str 2228 count++ 2229 } 2230 vs = vs[:count] 2231 vec := vector.NewWithBytes(types.T_varchar.ToType(), vs, nil, session.GetMemPool()) 2232 bat.Vecs[0] = vec 2233 bat.InitZsOne(count) 2234 2235 err := fill(session, bat) 2236 vec.Free(session.GetMemPool()) 2237 return err 2238 } 2239 2240 var _ ComputationWrapper = &TxnComputationWrapper{} 2241 var _ ComputationWrapper = &NullComputationWrapper{} 2242 2243 type TxnComputationWrapper struct { 2244 stmt tree.Statement 2245 plan *plan2.Plan 2246 proc *process.Process 2247 ses *Session 2248 compile *compile.Compile 2249 2250 uuid uuid.UUID 2251 } 2252 2253 func InitTxnComputationWrapper(ses *Session, stmt tree.Statement, proc *process.Process) *TxnComputationWrapper { 2254 uuid, _ := uuid.NewUUID() 2255 return &TxnComputationWrapper{ 2256 stmt: stmt, 2257 proc: proc, 2258 ses: ses, 2259 uuid: uuid, 2260 } 2261 } 2262 2263 func (cwft *TxnComputationWrapper) GetAst() tree.Statement { 2264 return cwft.stmt 2265 } 2266 2267 func (cwft *TxnComputationWrapper) GetProcess() *process.Process { 2268 return cwft.proc 2269 } 2270 2271 func (cwft *TxnComputationWrapper) SetDatabaseName(db string) error { 2272 return nil 2273 } 2274 2275 func (cwft *TxnComputationWrapper) GetColumns() ([]interface{}, error) { 2276 var err error 2277 cols := plan2.GetResultColumnsFromPlan(cwft.plan) 2278 switch cwft.GetAst().(type) { 2279 case *tree.ShowColumns: 2280 if len(cols) == 7 { 2281 cols = []*plan2.ColDef{ 2282 {Typ: &plan2.Type{Id: int32(types.T_char)}, Name: "Field"}, 2283 {Typ: &plan2.Type{Id: int32(types.T_char)}, Name: "Type"}, 2284 {Typ: &plan2.Type{Id: int32(types.T_char)}, Name: "Null"}, 2285 {Typ: &plan2.Type{Id: int32(types.T_char)}, Name: "Key"}, 2286 {Typ: &plan2.Type{Id: int32(types.T_char)}, Name: "Default"}, 2287 {Typ: &plan2.Type{Id: int32(types.T_char)}, Name: "Extra"}, 2288 {Typ: &plan2.Type{Id: int32(types.T_char)}, Name: "Comment"}, 2289 } 2290 } else { 2291 cols = []*plan2.ColDef{ 2292 {Typ: &plan2.Type{Id: int32(types.T_char)}, Name: "Field"}, 2293 {Typ: &plan2.Type{Id: int32(types.T_char)}, Name: "Type"}, 2294 {Typ: &plan2.Type{Id: int32(types.T_char)}, Name: "Collation"}, 2295 {Typ: &plan2.Type{Id: int32(types.T_char)}, Name: "Null"}, 2296 {Typ: &plan2.Type{Id: int32(types.T_char)}, Name: "Key"}, 2297 {Typ: &plan2.Type{Id: int32(types.T_char)}, Name: "Default"}, 2298 {Typ: &plan2.Type{Id: int32(types.T_char)}, Name: "Extra"}, 2299 {Typ: &plan2.Type{Id: int32(types.T_char)}, Name: "Privileges"}, 2300 {Typ: &plan2.Type{Id: int32(types.T_char)}, Name: "Comment"}, 2301 } 2302 } 2303 } 2304 columns := make([]interface{}, len(cols)) 2305 for i, col := range cols { 2306 c := new(MysqlColumn) 2307 c.SetName(col.Name) 2308 c.SetOrgName(col.Name) 2309 c.SetTable(col.Typ.Table) 2310 c.SetOrgTable(col.Typ.Table) 2311 c.SetAutoIncr(col.Typ.AutoIncr) 2312 c.SetSchema(cwft.ses.GetTxnCompileCtx().DefaultDatabase()) 2313 err = convertEngineTypeToMysqlType(cwft.ses.requestCtx, types.T(col.Typ.Id), c) 2314 if err != nil { 2315 return nil, err 2316 } 2317 setColFlag(c) 2318 setColLength(c, col.Typ.Width) 2319 setCharacter(c) 2320 c.SetDecimal(uint8(col.Typ.Scale)) 2321 convertMysqlTextTypeToBlobType(c) 2322 columns[i] = c 2323 } 2324 return columns, err 2325 } 2326 2327 func (cwft *TxnComputationWrapper) GetClock() clock.Clock { 2328 rt := runtime.ProcessLevelRuntime() 2329 return rt.Clock() 2330 } 2331 2332 func (cwft *TxnComputationWrapper) GetAffectedRows() uint64 { 2333 return cwft.compile.GetAffectedRows() 2334 } 2335 2336 func (cwft *TxnComputationWrapper) Compile(requestCtx context.Context, u interface{}, fill func(interface{}, *batch.Batch) error) (interface{}, error) { 2337 var err error 2338 defer RecordStatementTxnID(requestCtx, cwft.ses) 2339 if cwft.ses.IfInitedTempEngine() { 2340 requestCtx = context.WithValue(requestCtx, defines.TemporaryDN{}, cwft.ses.GetTempTableStorage()) 2341 cwft.ses.SetRequestContext(requestCtx) 2342 cwft.proc.Ctx = context.WithValue(cwft.proc.Ctx, defines.TemporaryDN{}, cwft.ses.GetTempTableStorage()) 2343 } 2344 cacheHit := cwft.plan != nil 2345 if !cacheHit { 2346 cwft.plan, err = buildPlan(requestCtx, cwft.ses, cwft.ses.GetTxnCompileCtx(), cwft.stmt) 2347 } else if cwft.ses != nil && cwft.ses.GetTenantInfo() != nil { 2348 cwft.ses.accountId = getAccountId(requestCtx) 2349 err = authenticateCanExecuteStatementAndPlan(requestCtx, cwft.ses, cwft.stmt, cwft.plan) 2350 } 2351 if err != nil { 2352 return nil, err 2353 } 2354 cwft.ses.p = cwft.plan 2355 if ids := isResultQuery(cwft.plan); ids != nil { 2356 if err = checkPrivilege(ids, requestCtx, cwft.ses); err != nil { 2357 return nil, err 2358 } 2359 } 2360 if _, ok := cwft.stmt.(*tree.Execute); ok { 2361 executePlan := cwft.plan.GetDcl().GetExecute() 2362 stmtName := executePlan.GetName() 2363 prepareStmt, err := cwft.ses.GetPrepareStmt(stmtName) 2364 if err != nil { 2365 return nil, err 2366 } 2367 2368 // TODO check if schema change, obj.Obj is zero all the time in 0.6 2369 // for _, obj := range preparePlan.GetSchemas() { 2370 // newObj, _ := cwft.ses.txnCompileCtx.Resolve(obj.SchemaName, obj.ObjName) 2371 // if newObj == nil || newObj.Obj != obj.Obj { 2372 // return nil, moerr.NewInternalError("", fmt.Sprintf(ctx, "table '%s' has been changed, please reset Prepare statement '%s'", obj.ObjName, stmtName)) 2373 // } 2374 // } 2375 2376 preparePlan := prepareStmt.PreparePlan.GetDcl().GetPrepare() 2377 if len(executePlan.Args) != len(preparePlan.ParamTypes) { 2378 return nil, moerr.NewInvalidInput(requestCtx, "Incorrect arguments to EXECUTE") 2379 } 2380 newPlan := plan2.DeepCopyPlan(preparePlan.Plan) 2381 2382 // replace ? and @var with their values 2383 resetParamRule := plan2.NewResetParamRefRule(requestCtx, executePlan.Args) 2384 resetVarRule := plan2.NewResetVarRefRule(cwft.ses.GetTxnCompileCtx(), cwft.ses.GetTxnCompileCtx().GetProcess()) 2385 constantFoldRule := plan2.NewConstantFoldRule(cwft.ses.GetTxnCompileCtx()) 2386 vp := plan2.NewVisitPlan(newPlan, []plan2.VisitPlanRule{resetParamRule, resetVarRule, constantFoldRule}) 2387 err = vp.Visit(requestCtx) 2388 if err != nil { 2389 return nil, err 2390 } 2391 2392 // reset plan & stmt 2393 cwft.stmt = prepareStmt.PrepareStmt 2394 cwft.plan = newPlan 2395 // reset some special stmt for execute statement 2396 switch cwft.stmt.(type) { 2397 case *tree.ShowColumns: 2398 cwft.ses.SetShowStmtType(ShowColumns) 2399 cwft.ses.SetData(nil) 2400 case *tree.ShowTableStatus: 2401 cwft.ses.showStmtType = ShowTableStatus 2402 cwft.ses.SetData(nil) 2403 case *tree.SetVar, *tree.ShowVariables, *tree.ShowErrors, *tree.ShowWarnings: 2404 return nil, nil 2405 } 2406 2407 //check privilege 2408 err = authenticateUserCanExecutePrepareOrExecute(requestCtx, cwft.ses, prepareStmt.PrepareStmt, newPlan) 2409 if err != nil { 2410 return nil, err 2411 } 2412 } else { 2413 var vp *plan2.VisitPlan 2414 if cacheHit { 2415 vp = plan2.NewVisitPlan(cwft.plan, []plan2.VisitPlanRule{plan2.NewResetVarRefRule(cwft.ses.GetTxnCompileCtx(), cwft.ses.GetTxnCompileCtx().GetProcess()), plan2.NewRecomputeRealTimeRelatedFuncRule(cwft.ses.GetTxnCompileCtx().GetProcess())}) 2416 } else { 2417 vp = plan2.NewVisitPlan(cwft.plan, []plan2.VisitPlanRule{plan2.NewResetVarRefRule(cwft.ses.GetTxnCompileCtx(), cwft.ses.GetTxnCompileCtx().GetProcess())}) 2418 } 2419 err = vp.Visit(requestCtx) 2420 if err != nil { 2421 return nil, err 2422 } 2423 } 2424 2425 txnHandler := cwft.ses.GetTxnHandler() 2426 if cacheHit && cwft.plan.NeedImplicitTxn() { 2427 cwft.proc.TxnOperator, err = txnHandler.GetTxn() 2428 if err != nil { 2429 return nil, err 2430 } 2431 } else if cwft.plan.GetQuery().GetLoadTag() { 2432 cwft.proc.TxnOperator = txnHandler.GetTxnOnly() 2433 } else if cwft.plan.NeedImplicitTxn() { 2434 cwft.proc.TxnOperator, err = txnHandler.GetTxn() 2435 if err != nil { 2436 return nil, err 2437 } 2438 } 2439 addr := "" 2440 if len(cwft.ses.GetParameterUnit().ClusterNodes) > 0 { 2441 addr = cwft.ses.GetParameterUnit().ClusterNodes[0].Addr 2442 } 2443 cwft.proc.FileService = cwft.ses.GetParameterUnit().FileService 2444 cwft.compile = compile.New(addr, cwft.ses.GetDatabaseName(), cwft.ses.GetSql(), cwft.ses.GetUserName(), requestCtx, cwft.ses.GetStorage(), cwft.proc, cwft.stmt) 2445 2446 if _, ok := cwft.stmt.(*tree.ExplainAnalyze); ok { 2447 fill = func(obj interface{}, bat *batch.Batch) error { return nil } 2448 } 2449 err = cwft.compile.Compile(requestCtx, cwft.plan, cwft.ses, fill) 2450 if err != nil { 2451 return nil, err 2452 } 2453 // check if it is necessary to initialize the temporary engine 2454 if cwft.compile.NeedInitTempEngine(cwft.ses.IfInitedTempEngine()) { 2455 // 0. init memory-non-dist storage 2456 dnStore, err := cwft.ses.SetTempTableStorage(cwft.GetClock()) 2457 if err != nil { 2458 return nil, err 2459 } 2460 2461 // temporary storage is passed through Ctx 2462 requestCtx = context.WithValue(requestCtx, defines.TemporaryDN{}, cwft.ses.GetTempTableStorage()) 2463 2464 // 1. init memory-non-dist engine 2465 tempEngine := memoryengine.New( 2466 requestCtx, 2467 memoryengine.NewDefaultShardPolicy( 2468 mpool.MustNewZero(), 2469 ), 2470 func() (logservicepb.ClusterDetails, error) { 2471 return logservicepb.ClusterDetails{ 2472 DNStores: []logservicepb.DNStore{ 2473 *dnStore, 2474 }, 2475 }, nil 2476 }, 2477 memoryengine.RandomIDGenerator, 2478 ) 2479 2480 // 2. bind the temporary engine to the session and txnHandler 2481 cwft.ses.SetTempEngine(requestCtx, tempEngine) 2482 cwft.compile.SetTempEngine(requestCtx, tempEngine) 2483 txnHandler := cwft.ses.txnCompileCtx.txnHandler 2484 txnHandler.SetTempEngine(tempEngine) 2485 2486 // 3. init temp-db to store temporary relations 2487 err = tempEngine.Create(requestCtx, defines.TEMPORARY_DBNAME, cwft.ses.txnHandler.txn) 2488 if err != nil { 2489 return nil, err 2490 } 2491 2492 // 4. add auto_IncrementTable fortemp-db 2493 colexec.CreateAutoIncrTable(cwft.ses.GetStorage(), requestCtx, cwft.proc, defines.TEMPORARY_DBNAME) 2494 2495 cwft.ses.InitTempEngine = true 2496 } 2497 return cwft.compile, err 2498 } 2499 2500 func (cwft *TxnComputationWrapper) RecordExecPlan(ctx context.Context) error { 2501 if stm := motrace.StatementFromContext(ctx); stm != nil { 2502 stm.SetExecPlan(cwft.plan, SerializeExecPlan) 2503 } 2504 return nil 2505 } 2506 2507 func (cwft *TxnComputationWrapper) GetUUID() []byte { 2508 return cwft.uuid[:] 2509 } 2510 2511 func (cwft *TxnComputationWrapper) Run(ts uint64) error { 2512 logDebugf(cwft.ses.GetConciseProfile(), "compile.Run begin") 2513 defer func() { 2514 logDebugf(cwft.ses.GetConciseProfile(), "compile.Run end") 2515 }() 2516 err := cwft.compile.Run(ts) 2517 return err 2518 } 2519 2520 func (cwft *TxnComputationWrapper) GetLoadTag() bool { 2521 return cwft.plan.GetQuery().GetLoadTag() 2522 } 2523 2524 type NullComputationWrapper struct { 2525 *TxnComputationWrapper 2526 } 2527 2528 func InitNullComputationWrapper(ses *Session, stmt tree.Statement, proc *process.Process) *NullComputationWrapper { 2529 return &NullComputationWrapper{ 2530 TxnComputationWrapper: InitTxnComputationWrapper(ses, stmt, proc), 2531 } 2532 } 2533 2534 func (ncw *NullComputationWrapper) GetAst() tree.Statement { 2535 return ncw.stmt 2536 } 2537 2538 func (ncw *NullComputationWrapper) SetDatabaseName(db string) error { 2539 return nil 2540 } 2541 2542 func (ncw *NullComputationWrapper) GetColumns() ([]interface{}, error) { 2543 return []interface{}{}, nil 2544 } 2545 2546 func (ncw *NullComputationWrapper) GetAffectedRows() uint64 { 2547 return 0 2548 } 2549 2550 func (ncw *NullComputationWrapper) Compile(requestCtx context.Context, u interface{}, fill func(interface{}, *batch.Batch) error) (interface{}, error) { 2551 return nil, nil 2552 } 2553 2554 func (ncw *NullComputationWrapper) RecordExecPlan(ctx context.Context) error { 2555 return nil 2556 } 2557 2558 func (ncw *NullComputationWrapper) GetUUID() []byte { 2559 return ncw.uuid[:] 2560 } 2561 2562 func (ncw *NullComputationWrapper) Run(ts uint64) error { 2563 return nil 2564 } 2565 2566 func (ncw *NullComputationWrapper) GetLoadTag() bool { 2567 return false 2568 } 2569 2570 func buildPlan(requestCtx context.Context, ses *Session, ctx plan2.CompilerContext, stmt tree.Statement) (*plan2.Plan, error) { 2571 var ret *plan2.Plan 2572 var err error 2573 if ses != nil { 2574 ses.accountId = getAccountId(requestCtx) 2575 } 2576 if s, ok := stmt.(*tree.Insert); ok { 2577 if _, ok := s.Rows.Select.(*tree.ValuesClause); ok { 2578 ret, err = plan2.BuildPlan(ctx, stmt) 2579 if err != nil { 2580 return nil, err 2581 } 2582 } 2583 } 2584 if ret != nil { 2585 if ses != nil && ses.GetTenantInfo() != nil { 2586 err = authenticateCanExecuteStatementAndPlan(requestCtx, ses, stmt, ret) 2587 if err != nil { 2588 return nil, err 2589 } 2590 } 2591 return ret, err 2592 } 2593 switch stmt := stmt.(type) { 2594 case *tree.Select, *tree.ParenSelect, *tree.ValuesStatement, 2595 *tree.Update, *tree.Delete, *tree.Insert, 2596 *tree.ShowDatabases, *tree.ShowTables, *tree.ShowColumns, *tree.ShowColumnNumber, *tree.ShowTableNumber, 2597 *tree.ShowCreateDatabase, *tree.ShowCreateTable, *tree.ShowIndex, 2598 *tree.ExplainStmt, *tree.ExplainAnalyze: 2599 opt := plan2.NewBaseOptimizer(ctx) 2600 optimized, err := opt.Optimize(stmt) 2601 if err != nil { 2602 return nil, err 2603 } 2604 ret = &plan2.Plan{ 2605 Plan: &plan2.Plan_Query{ 2606 Query: optimized, 2607 }, 2608 } 2609 default: 2610 ret, err = plan2.BuildPlan(ctx, stmt) 2611 } 2612 if ret != nil { 2613 if ses != nil && ses.GetTenantInfo() != nil { 2614 err = authenticateCanExecuteStatementAndPlan(requestCtx, ses, stmt, ret) 2615 if err != nil { 2616 return nil, err 2617 } 2618 } 2619 } 2620 return ret, err 2621 } 2622 2623 /* 2624 GetComputationWrapper gets the execs from the computation engine 2625 */ 2626 var GetComputationWrapper = func(db, sql, user string, eng engine.Engine, proc *process.Process, ses *Session) ([]ComputationWrapper, error) { 2627 var cw []ComputationWrapper = nil 2628 if cached := ses.getCachedPlan(sql); cached != nil { 2629 for i, stmt := range cached.stmts { 2630 tcw := InitTxnComputationWrapper(ses, stmt, proc) 2631 tcw.plan = cached.plans[i] 2632 cw = append(cw, tcw) 2633 } 2634 return cw, nil 2635 } 2636 2637 var stmts []tree.Statement = nil 2638 var cmdFieldStmt *InternalCmdFieldList 2639 var err error 2640 if isCmdFieldListSql(sql) { 2641 cmdFieldStmt, err = parseCmdFieldList(proc.Ctx, sql) 2642 if err != nil { 2643 return nil, err 2644 } 2645 stmts = append(stmts, cmdFieldStmt) 2646 } else { 2647 stmts, err = parsers.Parse(proc.Ctx, dialect.MYSQL, sql) 2648 if err != nil { 2649 return nil, err 2650 } 2651 } 2652 2653 for _, stmt := range stmts { 2654 cw = append(cw, InitTxnComputationWrapper(ses, stmt, proc)) 2655 } 2656 return cw, nil 2657 } 2658 2659 func getStmtExecutor(ses *Session, proc *process.Process, base *baseStmtExecutor, stmt tree.Statement) (StmtExecutor, error) { 2660 var err error 2661 var ret StmtExecutor 2662 switch st := stmt.(type) { 2663 //PART 1: the statements with the result set 2664 case *tree.Select: 2665 ret = (&SelectExecutor{ 2666 resultSetStmtExecutor: &resultSetStmtExecutor{ 2667 base, 2668 }, 2669 sel: st, 2670 }) 2671 case *tree.ValuesStatement: 2672 ret = (&ValuesStmtExecutor{ 2673 resultSetStmtExecutor: &resultSetStmtExecutor{ 2674 base, 2675 }, 2676 sel: st, 2677 }) 2678 case *tree.ShowCreateTable: 2679 ret = (&ShowCreateTableExecutor{ 2680 resultSetStmtExecutor: &resultSetStmtExecutor{ 2681 base, 2682 }, 2683 sct: st, 2684 }) 2685 case *tree.ShowCreateDatabase: 2686 ret = (&ShowCreateDatabaseExecutor{ 2687 resultSetStmtExecutor: &resultSetStmtExecutor{ 2688 base, 2689 }, 2690 scd: st, 2691 }) 2692 case *tree.ShowTables: 2693 ret = (&ShowTablesExecutor{ 2694 resultSetStmtExecutor: &resultSetStmtExecutor{ 2695 base, 2696 }, 2697 st: st, 2698 }) 2699 case *tree.ShowDatabases: 2700 ret = (&ShowDatabasesExecutor{ 2701 resultSetStmtExecutor: &resultSetStmtExecutor{ 2702 base, 2703 }, 2704 sd: st, 2705 }) 2706 case *tree.ShowColumns: 2707 ret = (&ShowColumnsExecutor{ 2708 resultSetStmtExecutor: &resultSetStmtExecutor{ 2709 base, 2710 }, 2711 sc: st, 2712 }) 2713 case *tree.ShowProcessList: 2714 ret = (&ShowProcessListExecutor{ 2715 resultSetStmtExecutor: &resultSetStmtExecutor{ 2716 base, 2717 }, 2718 spl: st, 2719 }) 2720 case *tree.ShowStatus: 2721 ret = (&ShowStatusExecutor{ 2722 resultSetStmtExecutor: &resultSetStmtExecutor{ 2723 base, 2724 }, 2725 ss: st, 2726 }) 2727 case *tree.ShowTableStatus: 2728 ret = (&ShowTableStatusExecutor{ 2729 resultSetStmtExecutor: &resultSetStmtExecutor{ 2730 base, 2731 }, 2732 sts: st, 2733 }) 2734 case *tree.ShowGrants: 2735 ret = (&ShowGrantsExecutor{ 2736 resultSetStmtExecutor: &resultSetStmtExecutor{ 2737 base, 2738 }, 2739 sg: st, 2740 }) 2741 case *tree.ShowIndex: 2742 ret = (&ShowIndexExecutor{ 2743 resultSetStmtExecutor: &resultSetStmtExecutor{ 2744 base, 2745 }, 2746 si: st, 2747 }) 2748 case *tree.ShowCreateView: 2749 ret = (&ShowCreateViewExecutor{ 2750 resultSetStmtExecutor: &resultSetStmtExecutor{ 2751 base, 2752 }, 2753 scv: st, 2754 }) 2755 case *tree.ShowTarget: 2756 ret = (&ShowTargetExecutor{ 2757 resultSetStmtExecutor: &resultSetStmtExecutor{ 2758 base, 2759 }, 2760 st: st, 2761 }) 2762 case *tree.ExplainFor: 2763 ret = (&ExplainForExecutor{ 2764 resultSetStmtExecutor: &resultSetStmtExecutor{ 2765 base, 2766 }, 2767 ef: st, 2768 }) 2769 case *tree.ExplainStmt: 2770 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2771 ret = (&ExplainStmtExecutor{ 2772 resultSetStmtExecutor: &resultSetStmtExecutor{ 2773 base, 2774 }, 2775 es: st, 2776 }) 2777 case *tree.ShowVariables: 2778 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2779 ret = (&ShowVariablesExecutor{ 2780 resultSetStmtExecutor: &resultSetStmtExecutor{ 2781 base, 2782 }, 2783 sv: st, 2784 }) 2785 case *tree.ShowErrors: 2786 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2787 ret = (&ShowErrorsExecutor{ 2788 resultSetStmtExecutor: &resultSetStmtExecutor{ 2789 base, 2790 }, 2791 se: st, 2792 }) 2793 case *tree.ShowWarnings: 2794 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2795 ret = (&ShowWarningsExecutor{ 2796 resultSetStmtExecutor: &resultSetStmtExecutor{ 2797 base, 2798 }, 2799 sw: st, 2800 }) 2801 case *tree.AnalyzeStmt: 2802 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2803 ret = (&AnalyzeStmtExecutor{ 2804 resultSetStmtExecutor: &resultSetStmtExecutor{ 2805 base, 2806 }, 2807 as: st, 2808 }) 2809 case *tree.ExplainAnalyze: 2810 ret = (&ExplainAnalyzeExecutor{ 2811 resultSetStmtExecutor: &resultSetStmtExecutor{ 2812 base, 2813 }, 2814 ea: st, 2815 }) 2816 case *InternalCmdFieldList: 2817 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2818 ret = (&InternalCmdFieldListExecutor{ 2819 resultSetStmtExecutor: &resultSetStmtExecutor{ 2820 base, 2821 }, 2822 icfl: st, 2823 }) 2824 //PART 2: the statement with the status only 2825 case *tree.BeginTransaction: 2826 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2827 ret = (&BeginTxnExecutor{ 2828 statusStmtExecutor: &statusStmtExecutor{ 2829 base, 2830 }, 2831 bt: st, 2832 }) 2833 case *tree.CommitTransaction: 2834 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2835 ret = (&CommitTxnExecutor{ 2836 statusStmtExecutor: &statusStmtExecutor{ 2837 base, 2838 }, 2839 ct: st, 2840 }) 2841 case *tree.RollbackTransaction: 2842 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2843 ret = (&RollbackTxnExecutor{ 2844 statusStmtExecutor: &statusStmtExecutor{ 2845 base, 2846 }, 2847 rt: st, 2848 }) 2849 case *tree.SetRole: 2850 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2851 ret = (&SetRoleExecutor{ 2852 statusStmtExecutor: &statusStmtExecutor{ 2853 base, 2854 }, 2855 sr: st, 2856 }) 2857 case *tree.Use: 2858 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2859 ret = (&UseExecutor{ 2860 statusStmtExecutor: &statusStmtExecutor{ 2861 base, 2862 }, 2863 u: st, 2864 }) 2865 case *tree.MoDump: 2866 //TODO: 2867 err = moerr.NewInternalError(proc.Ctx, "needs to add modump") 2868 case *tree.DropDatabase: 2869 ret = (&DropDatabaseExecutor{ 2870 statusStmtExecutor: &statusStmtExecutor{ 2871 base, 2872 }, 2873 dd: st, 2874 }) 2875 case *tree.Import: 2876 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2877 ret = (&ImportExecutor{ 2878 statusStmtExecutor: &statusStmtExecutor{ 2879 base, 2880 }, 2881 i: st, 2882 }) 2883 case *tree.PrepareStmt: 2884 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2885 ret = (&PrepareStmtExecutor{ 2886 statusStmtExecutor: &statusStmtExecutor{ 2887 base, 2888 }, 2889 ps: st, 2890 }) 2891 case *tree.PrepareString: 2892 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2893 ret = (&PrepareStringExecutor{ 2894 statusStmtExecutor: &statusStmtExecutor{ 2895 base, 2896 }, 2897 ps: st, 2898 }) 2899 case *tree.Deallocate: 2900 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2901 ret = (&DeallocateExecutor{ 2902 statusStmtExecutor: &statusStmtExecutor{ 2903 base, 2904 }, 2905 d: st, 2906 }) 2907 case *tree.SetVar: 2908 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2909 ret = (&SetVarExecutor{ 2910 statusStmtExecutor: &statusStmtExecutor{ 2911 base, 2912 }, 2913 sv: st, 2914 }) 2915 case *tree.Delete: 2916 ret = (&DeleteExecutor{ 2917 statusStmtExecutor: &statusStmtExecutor{ 2918 base, 2919 }, 2920 d: st, 2921 }) 2922 case *tree.Update: 2923 ret = (&UpdateExecutor{ 2924 statusStmtExecutor: &statusStmtExecutor{ 2925 base, 2926 }, 2927 u: st, 2928 }) 2929 case *tree.CreateAccount: 2930 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2931 ret = (&CreateAccountExecutor{ 2932 statusStmtExecutor: &statusStmtExecutor{ 2933 base, 2934 }, 2935 ca: st, 2936 }) 2937 case *tree.DropAccount: 2938 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2939 ret = (&DropAccountExecutor{ 2940 statusStmtExecutor: &statusStmtExecutor{ 2941 base, 2942 }, 2943 da: st, 2944 }) 2945 case *tree.AlterAccount: 2946 ret = (&AlterAccountExecutor{ 2947 statusStmtExecutor: &statusStmtExecutor{ 2948 base, 2949 }, 2950 aa: st, 2951 }) 2952 case *tree.CreateUser: 2953 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2954 ret = (&CreateUserExecutor{ 2955 statusStmtExecutor: &statusStmtExecutor{ 2956 base, 2957 }, 2958 cu: st, 2959 }) 2960 case *tree.DropUser: 2961 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2962 ret = (&DropUserExecutor{ 2963 statusStmtExecutor: &statusStmtExecutor{ 2964 base, 2965 }, 2966 du: st, 2967 }) 2968 case *tree.AlterUser: 2969 ret = (&AlterUserExecutor{ 2970 statusStmtExecutor: &statusStmtExecutor{ 2971 base, 2972 }, 2973 au: st, 2974 }) 2975 case *tree.CreateRole: 2976 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2977 ret = (&CreateRoleExecutor{ 2978 statusStmtExecutor: &statusStmtExecutor{ 2979 base, 2980 }, 2981 cr: st, 2982 }) 2983 case *tree.DropRole: 2984 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2985 ret = (&DropRoleExecutor{ 2986 statusStmtExecutor: &statusStmtExecutor{ 2987 base, 2988 }, 2989 dr: st, 2990 }) 2991 case *tree.Grant: 2992 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 2993 ret = (&GrantExecutor{ 2994 statusStmtExecutor: &statusStmtExecutor{ 2995 base, 2996 }, 2997 g: st, 2998 }) 2999 case *tree.Revoke: 3000 base.ComputationWrapper = InitNullComputationWrapper(ses, st, proc) 3001 ret = (&RevokeExecutor{ 3002 statusStmtExecutor: &statusStmtExecutor{ 3003 base, 3004 }, 3005 r: st, 3006 }) 3007 case *tree.CreateTable: 3008 ret = (&CreateTableExecutor{ 3009 statusStmtExecutor: &statusStmtExecutor{ 3010 base, 3011 }, 3012 ct: st, 3013 }) 3014 case *tree.DropTable: 3015 ret = (&DropTableExecutor{ 3016 statusStmtExecutor: &statusStmtExecutor{ 3017 base, 3018 }, 3019 dt: st, 3020 }) 3021 case *tree.CreateDatabase: 3022 ret = (&CreateDatabaseExecutor{ 3023 statusStmtExecutor: &statusStmtExecutor{ 3024 base, 3025 }, 3026 cd: st, 3027 }) 3028 case *tree.CreateIndex: 3029 ret = (&CreateIndexExecutor{ 3030 statusStmtExecutor: &statusStmtExecutor{ 3031 base, 3032 }, 3033 ci: st, 3034 }) 3035 case *tree.DropIndex: 3036 ret = (&DropIndexExecutor{ 3037 statusStmtExecutor: &statusStmtExecutor{ 3038 base, 3039 }, 3040 di: st, 3041 }) 3042 case *tree.CreateView: 3043 ret = (&CreateViewExecutor{ 3044 statusStmtExecutor: &statusStmtExecutor{ 3045 base, 3046 }, 3047 cv: st, 3048 }) 3049 case *tree.AlterView: 3050 ret = (&AlterViewExecutor{ 3051 statusStmtExecutor: &statusStmtExecutor{ 3052 base, 3053 }, 3054 av: st, 3055 }) 3056 case *tree.DropView: 3057 ret = (&DropViewExecutor{ 3058 statusStmtExecutor: &statusStmtExecutor{ 3059 base, 3060 }, 3061 dv: st, 3062 }) 3063 case *tree.Insert: 3064 ret = (&InsertExecutor{ 3065 statusStmtExecutor: &statusStmtExecutor{ 3066 base, 3067 }, 3068 i: st, 3069 }) 3070 case *tree.Load: 3071 ret = (&LoadExecutor{ 3072 statusStmtExecutor: &statusStmtExecutor{ 3073 base, 3074 }, 3075 l: st, 3076 }) 3077 case *tree.SetDefaultRole: 3078 ret = (&SetDefaultRoleExecutor{ 3079 statusStmtExecutor: &statusStmtExecutor{ 3080 base, 3081 }, 3082 sdr: st, 3083 }) 3084 case *tree.SetPassword: 3085 ret = (&SetPasswordExecutor{ 3086 statusStmtExecutor: &statusStmtExecutor{ 3087 base, 3088 }, 3089 sp: st, 3090 }) 3091 case *tree.TruncateTable: 3092 ret = (&TruncateTableExecutor{ 3093 statusStmtExecutor: &statusStmtExecutor{ 3094 base, 3095 }, 3096 tt: st, 3097 }) 3098 //PART 3: hybrid 3099 case *tree.Execute: 3100 ret = &ExecuteExecutor{ 3101 baseStmtExecutor: base, 3102 e: st, 3103 } 3104 default: 3105 return nil, moerr.NewInternalError(proc.Ctx, "no such statement %s", stmt.String()) 3106 } 3107 return ret, err 3108 } 3109 3110 var GetStmtExecList = func(db, sql, user string, eng engine.Engine, proc *process.Process, ses *Session) ([]StmtExecutor, error) { 3111 var stmtExecList []StmtExecutor = nil 3112 var stmtExec StmtExecutor 3113 var stmts []tree.Statement = nil 3114 var cmdFieldStmt *InternalCmdFieldList 3115 var err error 3116 3117 appendStmtExec := func(se StmtExecutor) { 3118 stmtExecList = append(stmtExecList, se) 3119 } 3120 3121 if isCmdFieldListSql(sql) { 3122 cmdFieldStmt, err = parseCmdFieldList(proc.Ctx, sql) 3123 if err != nil { 3124 return nil, err 3125 } 3126 stmts = append(stmts, cmdFieldStmt) 3127 } else { 3128 stmts, err = parsers.Parse(proc.Ctx, dialect.MYSQL, sql) 3129 if err != nil { 3130 return nil, err 3131 } 3132 } 3133 3134 for _, stmt := range stmts { 3135 cw := InitTxnComputationWrapper(ses, stmt, proc) 3136 base := &baseStmtExecutor{} 3137 base.ComputationWrapper = cw 3138 stmtExec, err = getStmtExecutor(ses, proc, base, stmt) 3139 if err != nil { 3140 return nil, err 3141 } 3142 appendStmtExec(stmtExec) 3143 } 3144 return stmtExecList, nil 3145 } 3146 3147 func incStatementCounter(tenant string, stmt tree.Statement) { 3148 metric.StatementCounter(tenant, getStatementType(stmt).GetQueryType()).Inc() 3149 } 3150 3151 func incTransactionCounter(tenant string) { 3152 metric.TransactionCounter(tenant).Inc() 3153 } 3154 3155 func incTransactionErrorsCounter(tenant string, t metric.SQLType) { 3156 if t == metric.SQLTypeRollback { 3157 return 3158 } 3159 metric.TransactionErrorsCounter(tenant, t).Inc() 3160 } 3161 3162 func incStatementErrorsCounter(tenant string, stmt tree.Statement) { 3163 metric.StatementErrorsCounter(tenant, getStatementType(stmt).GetQueryType()).Inc() 3164 } 3165 3166 type unknownStatementType struct { 3167 tree.StatementType 3168 } 3169 3170 func (unknownStatementType) GetStatementType() string { return "Unknown" } 3171 func (unknownStatementType) GetQueryType() string { return tree.QueryTypeOth } 3172 3173 func getStatementType(stmt tree.Statement) tree.StatementType { 3174 switch stmt.(type) { 3175 case tree.StatementType: 3176 return stmt 3177 default: 3178 return unknownStatementType{} 3179 } 3180 } 3181 3182 // authenticateUserCanExecuteStatement checks the user can execute the statement 3183 func authenticateUserCanExecuteStatement(requestCtx context.Context, ses *Session, stmt tree.Statement) error { 3184 requestCtx, span := trace.Debug(requestCtx, "authenticateUserCanExecuteStatement") 3185 defer span.End() 3186 if ses.skipCheckPrivilege() { 3187 return nil 3188 } 3189 if ses.skipAuthForSpecialUser() { 3190 return nil 3191 } 3192 var havePrivilege bool 3193 var err error 3194 if ses.GetTenantInfo() != nil { 3195 ses.SetPrivilege(determinePrivilegeSetOfStatement(stmt)) 3196 havePrivilege, err = authenticateUserCanExecuteStatementWithObjectTypeAccountAndDatabase(requestCtx, ses, stmt) 3197 if err != nil { 3198 return err 3199 } 3200 3201 if !havePrivilege { 3202 err = moerr.NewInternalError(requestCtx, "do not have privilege to execute the statement") 3203 return err 3204 } 3205 3206 havePrivilege, err = authenticateUserCanExecuteStatementWithObjectTypeNone(requestCtx, ses, stmt) 3207 if err != nil { 3208 return err 3209 } 3210 3211 if !havePrivilege { 3212 err = moerr.NewInternalError(requestCtx, "do not have privilege to execute the statement") 3213 return err 3214 } 3215 } 3216 return err 3217 } 3218 3219 // authenticateCanExecuteStatementAndPlan checks the user can execute the statement and its plan 3220 func authenticateCanExecuteStatementAndPlan(requestCtx context.Context, ses *Session, stmt tree.Statement, p *plan.Plan) error { 3221 if ses.skipCheckPrivilege() { 3222 return nil 3223 } 3224 if ses.skipAuthForSpecialUser() { 3225 return nil 3226 } 3227 yes, err := authenticateUserCanExecuteStatementWithObjectTypeDatabaseAndTable(requestCtx, ses, stmt, p) 3228 if err != nil { 3229 return err 3230 } 3231 if !yes { 3232 return moerr.NewInternalError(requestCtx, "do not have privilege to execute the statement") 3233 } 3234 return nil 3235 } 3236 3237 // authenticatePrivilegeOfPrepareAndExecute checks the user can execute the Prepare or Execute statement 3238 func authenticateUserCanExecutePrepareOrExecute(requestCtx context.Context, ses *Session, stmt tree.Statement, p *plan.Plan) error { 3239 err := authenticateUserCanExecuteStatement(requestCtx, ses, stmt) 3240 if err != nil { 3241 return err 3242 } 3243 err = authenticateCanExecuteStatementAndPlan(requestCtx, ses, stmt, p) 3244 if err != nil { 3245 return err 3246 } 3247 return err 3248 } 3249 3250 // canExecuteStatementInUncommittedTxn checks the user can execute the statement in an uncommitted transaction 3251 func (mce *MysqlCmdExecutor) canExecuteStatementInUncommittedTransaction(requestCtx context.Context, stmt tree.Statement) error { 3252 can, err := StatementCanBeExecutedInUncommittedTransaction(mce.GetSession(), stmt) 3253 if err != nil { 3254 return err 3255 } 3256 if !can { 3257 //is ddl statement 3258 if IsDDL(stmt) { 3259 return moerr.NewInternalError(requestCtx, onlyCreateStatementErrorInfo()) 3260 } else if IsAdministrativeStatement(stmt) { 3261 return moerr.NewInternalError(requestCtx, administrativeCommandIsUnsupportedInTxnErrorInfo()) 3262 } else if IsParameterModificationStatement(stmt) { 3263 return moerr.NewInternalError(requestCtx, parameterModificationInTxnErrorInfo()) 3264 } else { 3265 return moerr.NewInternalError(requestCtx, unclassifiedStatementInUncommittedTxnErrorInfo()) 3266 } 3267 } 3268 return nil 3269 } 3270 3271 func (ses *Session) getSqlType(sql string) { 3272 tenant := ses.GetTenantInfo() 3273 if tenant == nil || strings.HasPrefix(sql, cmdFieldListSql) { 3274 ses.sqlSourceType = intereSql 3275 return 3276 } 3277 flag, _, _ := isSpecialUser(tenant.User) 3278 if flag { 3279 ses.sqlSourceType = intereSql 3280 return 3281 } 3282 p1 := strings.Index(sql, "/*") 3283 p2 := strings.Index(sql, "*/") 3284 if p1 < 0 || p2 < 0 || p2 <= p1+1 { 3285 ses.sqlSourceType = externSql 3286 return 3287 } 3288 source := strings.TrimSpace(sql[p1+2 : p2]) 3289 if source == cloudUserTag { 3290 ses.sqlSourceType = cloudUserSql 3291 } else if source == cloudNoUserTag { 3292 ses.sqlSourceType = cloudNoUserSql 3293 } else { 3294 ses.sqlSourceType = externSql 3295 } 3296 } 3297 3298 func (mce *MysqlCmdExecutor) processLoadLocal(ctx context.Context, param *tree.ExternParam, writer *io.PipeWriter) (err error) { 3299 ses := mce.GetSession() 3300 proto := ses.GetMysqlProtocol() 3301 defer func() { 3302 err2 := writer.Close() 3303 if err == nil { 3304 err = err2 3305 } 3306 }() 3307 err = plan2.InitInfileParam(param) 3308 if err != nil { 3309 return 3310 } 3311 err = proto.sendLocalInfileRequest(param.Filepath) 3312 if err != nil { 3313 return 3314 } 3315 start := time.Now() 3316 var msg interface{} 3317 msg, err = proto.GetTcpConnection().Read(goetty.ReadOptions{}) 3318 if err != nil { 3319 if moerr.IsMoErrCode(err, moerr.ErrInvalidInput) { 3320 err = moerr.NewFileNotFound(ctx, param.Filepath) 3321 } 3322 proto.SetSequenceID(proto.GetSequenceId() + 1) 3323 return 3324 } 3325 3326 packet, ok := msg.(*Packet) 3327 if !ok { 3328 proto.SetSequenceID(proto.GetSequenceId() + 1) 3329 err = moerr.NewInvalidInput(ctx, "invalid packet") 3330 return 3331 } 3332 3333 proto.SetSequenceID(uint8(packet.SequenceID + 1)) 3334 seq := uint8(packet.SequenceID + 1) 3335 length := packet.Length 3336 if length == 0 { 3337 return 3338 } 3339 3340 skipWrite := false 3341 // If inner error occurs(unexpected or expected(ctrl-c)), proc.LoadLocalReader will be closed. 3342 // Then write will return error, but we need to read the rest of the data and not write it to pipe. 3343 // So we need a flag[skipWrite] to tell us whether we need to write the data to pipe. 3344 // https://github.com/matrixorigin/matrixone/issues/6665#issuecomment-1422236478 3345 3346 _, err = writer.Write(packet.Payload) 3347 if err != nil { 3348 skipWrite = true // next, we just need read the rest of the data,no need to write it to pipe. 3349 logErrorf(ses.GetConciseProfile(), "load local '%s', write error: %v", param.Filepath, err) 3350 } 3351 epoch, printEvery, minReadTime, maxReadTime, minWriteTime, maxWriteTime := uint64(0), uint64(1024), 24*time.Hour, time.Nanosecond, 24*time.Hour, time.Nanosecond 3352 for { 3353 readStart := time.Now() 3354 msg, err = proto.GetTcpConnection().Read(goetty.ReadOptions{}) 3355 if err != nil { 3356 if moerr.IsMoErrCode(err, moerr.ErrInvalidInput) { 3357 seq += 1 3358 proto.SetSequenceID(seq) 3359 err = nil 3360 } 3361 break 3362 } 3363 readTime := time.Since(readStart) 3364 if readTime > maxReadTime { 3365 maxReadTime = readTime 3366 } 3367 if readTime < minReadTime { 3368 minReadTime = readTime 3369 } 3370 packet, ok = msg.(*Packet) 3371 if !ok { 3372 err = moerr.NewInvalidInput(ctx, "invalid packet") 3373 seq += 1 3374 proto.SetSequenceID(seq) 3375 break 3376 } 3377 seq = uint8(packet.SequenceID + 1) 3378 proto.SetSequenceID(seq) 3379 3380 writeStart := time.Now() 3381 if !skipWrite { 3382 _, err = writer.Write(packet.Payload) 3383 if err != nil { 3384 logErrorf(ses.GetConciseProfile(), "load local '%s', epoch: %d, write error: %v", param.Filepath, epoch, err) 3385 skipWrite = true 3386 } 3387 writeTime := time.Since(writeStart) 3388 if writeTime > maxWriteTime { 3389 maxWriteTime = writeTime 3390 } 3391 if writeTime < minWriteTime { 3392 minWriteTime = writeTime 3393 } 3394 } 3395 if epoch%printEvery == 0 { 3396 logInfof(ses.GetConciseProfile(), "load local '%s', epoch: %d, skipWrite: %v, minReadTime: %s, maxReadTime: %s, minWriteTime: %s, maxWriteTime: %s,", param.Filepath, epoch, skipWrite, minReadTime.String(), maxReadTime.String(), minWriteTime.String(), maxWriteTime.String()) 3397 minReadTime, maxReadTime, minWriteTime, maxWriteTime = 24*time.Hour, time.Nanosecond, 24*time.Hour, time.Nanosecond 3398 } 3399 epoch += 1 3400 } 3401 logInfof(ses.GetConciseProfile(), "load local '%s', read&write all data from client cost: %s", param.Filepath, time.Since(start)) 3402 return 3403 } 3404 3405 // execute query 3406 func (mce *MysqlCmdExecutor) doComQuery(requestCtx context.Context, sql string) (retErr error) { 3407 beginInstant := time.Now() 3408 ses := mce.GetSession() 3409 ses.getSqlType(sql) 3410 ses.SetShowStmtType(NotShowStatement) 3411 proto := ses.GetMysqlProtocol() 3412 ses.SetSql(sql) 3413 ses.GetExportParam().Outfile = false 3414 pu := ses.GetParameterUnit() 3415 proc := process.New( 3416 requestCtx, 3417 ses.GetMemPool(), 3418 ses.GetTxnHandler().GetTxnClient(), 3419 ses.GetTxnHandler().GetTxnOperator(), 3420 pu.FileService, 3421 pu.GetClusterDetails, 3422 ) 3423 proc.Id = mce.getNextProcessId() 3424 proc.Lim.Size = pu.SV.ProcessLimitationSize 3425 proc.Lim.BatchRows = pu.SV.ProcessLimitationBatchRows 3426 proc.Lim.MaxMsgSize = pu.SV.MaxMessageSize 3427 proc.Lim.PartitionRows = pu.SV.ProcessLimitationPartitionRows 3428 proc.SessionInfo = process.SessionInfo{ 3429 User: ses.GetUserName(), 3430 Host: pu.SV.Host, 3431 ConnectionID: uint64(proto.ConnectionID()), 3432 Database: ses.GetDatabaseName(), 3433 Version: pu.SV.ServerVersionPrefix + serverVersion.Load().(string), 3434 TimeZone: ses.GetTimeZone(), 3435 StorageEngine: pu.StorageEngine, 3436 LastInsertID: ses.GetLastInsertID(), 3437 AutoIncrCaches: ses.GetAutoIncrCaches(), 3438 AutoIncrCacheSize: ses.pu.SV.AutoIncrCacheSize, 3439 } 3440 if ses.GetTenantInfo() != nil { 3441 proc.SessionInfo.Account = ses.GetTenantInfo().GetTenant() 3442 proc.SessionInfo.AccountId = ses.GetTenantInfo().GetTenantID() 3443 proc.SessionInfo.Role = ses.GetTenantInfo().GetDefaultRole() 3444 proc.SessionInfo.RoleId = ses.GetTenantInfo().GetDefaultRoleID() 3445 proc.SessionInfo.UserId = ses.GetTenantInfo().GetUserID() 3446 3447 if len(ses.GetTenantInfo().GetVersion()) != 0 { 3448 proc.SessionInfo.Version = ses.GetTenantInfo().GetVersion() 3449 } 3450 } else { 3451 proc.SessionInfo.Account = sysAccountName 3452 proc.SessionInfo.AccountId = sysAccountID 3453 proc.SessionInfo.RoleId = moAdminRoleID 3454 proc.SessionInfo.UserId = rootID 3455 } 3456 proc.SessionInfo.QueryId = ses.QueryId 3457 ses.txnCompileCtx.SetProcess(proc) 3458 cws, err := GetComputationWrapper(ses.GetDatabaseName(), 3459 sql, 3460 ses.GetUserName(), 3461 pu.StorageEngine, 3462 proc, ses) 3463 if err != nil { 3464 requestCtx = RecordParseErrorStatement(requestCtx, ses, proc, beginInstant, sql) 3465 retErr = err 3466 if _, ok := err.(*moerr.Error); !ok { 3467 retErr = moerr.NewParseError(requestCtx, err.Error()) 3468 } 3469 logStatementStringStatus(requestCtx, ses, sql, fail, retErr) 3470 return retErr 3471 } 3472 3473 defer func() { 3474 ses.SetMysqlResultSet(nil) 3475 }() 3476 3477 var cmpBegin time.Time 3478 var ret interface{} 3479 var runner ComputationRunner 3480 var selfHandle bool 3481 var fromLoadData = false 3482 var txnErr error 3483 var rspLen uint64 3484 var prepareStmt *PrepareStmt 3485 var err2 error 3486 var columns []interface{} 3487 var mrs *MysqlResultSet 3488 canCache := true 3489 var loadLocalErrGroup *errgroup.Group 3490 var loadLocalWriter *io.PipeWriter 3491 3492 singleStatement := len(cws) == 1 3493 for i, cw := range cws { 3494 if cwft, ok := cw.(*TxnComputationWrapper); ok { 3495 if cwft.stmt.GetQueryType() == tree.QueryTypeDDL || cwft.stmt.GetQueryType() == tree.QueryTypeDCL || 3496 cwft.stmt.GetQueryType() == tree.QueryTypeOth || 3497 cwft.stmt.GetQueryType() == tree.QueryTypeTCL { 3498 if _, ok := cwft.stmt.(*tree.SetVar); !ok { 3499 ses.cleanCache() 3500 } 3501 canCache = false 3502 } 3503 } 3504 3505 ses.SetMysqlResultSet(&MysqlResultSet{}) 3506 stmt := cw.GetAst() 3507 requestCtx = RecordStatement(requestCtx, ses, proc, cw, beginInstant, sql, singleStatement) 3508 tenant := ses.GetTenantName(stmt) 3509 //skip PREPARE statement here 3510 if ses.GetTenantInfo() != nil && !IsPrepareStatement(stmt) { 3511 err = authenticateUserCanExecuteStatement(requestCtx, ses, stmt) 3512 if err != nil { 3513 logStatementStatus(requestCtx, ses, stmt, fail, err) 3514 return err 3515 } 3516 } 3517 3518 /* 3519 if it is in an active or multi-statement transaction, we check the type of the statement. 3520 Then we decide that if we can execute the statement. 3521 3522 If we check the active transaction, it will generate the case below. 3523 case: 3524 set autocommit = 0; <- no active transaction 3525 <- no active transaction 3526 drop table test1; <- no active transaction, no error 3527 <- has active transaction 3528 drop table test1; <- has active transaction, error 3529 <- has active transaction 3530 */ 3531 if ses.InActiveTransaction() { 3532 err = mce.canExecuteStatementInUncommittedTransaction(requestCtx, stmt) 3533 if err != nil { 3534 logStatementStatus(requestCtx, ses, stmt, fail, err) 3535 return err 3536 } 3537 } 3538 3539 //check transaction states 3540 switch stmt.(type) { 3541 case *tree.BeginTransaction: 3542 err = ses.TxnBegin() 3543 if err != nil { 3544 goto handleFailed 3545 } 3546 RecordStatementTxnID(requestCtx, ses) 3547 case *tree.CommitTransaction: 3548 err = ses.TxnCommit() 3549 if err != nil { 3550 goto handleFailed 3551 } 3552 case *tree.RollbackTransaction: 3553 err = ses.TxnRollback() 3554 if err != nil { 3555 goto handleFailed 3556 } 3557 } 3558 3559 switch st := stmt.(type) { 3560 case *tree.Select: 3561 if st.Ep != nil { 3562 ses.SetExportParam(st.Ep) 3563 } 3564 } 3565 3566 selfHandle = false 3567 ses.GetTxnCompileCtx().SetQueryType(TXN_DEFAULT) 3568 3569 switch st := stmt.(type) { 3570 case *tree.BeginTransaction, *tree.CommitTransaction, *tree.RollbackTransaction: 3571 selfHandle = true 3572 case *tree.SetRole: 3573 selfHandle = true 3574 ses.InvalidatePrivilegeCache() 3575 //switch role 3576 err = mce.handleSwitchRole(requestCtx, st) 3577 if err != nil { 3578 goto handleFailed 3579 } 3580 case *tree.Use: 3581 selfHandle = true 3582 //use database 3583 err = mce.handleChangeDB(requestCtx, st.Name) 3584 if err != nil { 3585 goto handleFailed 3586 } 3587 err = changeVersion(requestCtx, ses, st.Name) 3588 if err != nil { 3589 goto handleFailed 3590 } 3591 case *tree.MoDump: 3592 selfHandle = true 3593 //dump 3594 err = mce.handleDump(requestCtx, st) 3595 if err != nil { 3596 goto handleFailed 3597 } 3598 case *tree.DropDatabase: 3599 ses.InvalidatePrivilegeCache() 3600 // if the droped database is the same as the one in use, database must be reseted to empty. 3601 if string(st.Name) == ses.GetDatabaseName() { 3602 ses.SetDatabaseName("") 3603 } 3604 case *tree.Import: 3605 fromLoadData = true 3606 selfHandle = true 3607 err = mce.handleLoadData(requestCtx, proc, st) 3608 if err != nil { 3609 goto handleFailed 3610 } 3611 case *tree.PrepareStmt: 3612 selfHandle = true 3613 prepareStmt, err = mce.handlePrepareStmt(requestCtx, st) 3614 if err != nil { 3615 goto handleFailed 3616 } 3617 err = authenticateUserCanExecutePrepareOrExecute(requestCtx, ses, prepareStmt.PrepareStmt, prepareStmt.PreparePlan.GetDcl().GetPrepare().GetPlan()) 3618 if err != nil { 3619 goto handleFailed 3620 } 3621 case *tree.PrepareString: 3622 selfHandle = true 3623 prepareStmt, err = mce.handlePrepareString(requestCtx, st) 3624 if err != nil { 3625 goto handleFailed 3626 } 3627 err = authenticateUserCanExecutePrepareOrExecute(requestCtx, ses, prepareStmt.PrepareStmt, prepareStmt.PreparePlan.GetDcl().GetPrepare().GetPlan()) 3628 if err != nil { 3629 goto handleFailed 3630 } 3631 case *tree.Deallocate: 3632 selfHandle = true 3633 err = mce.handleDeallocate(requestCtx, st) 3634 if err != nil { 3635 goto handleFailed 3636 } 3637 case *tree.Reset: 3638 selfHandle = true 3639 err = mce.handleReset(requestCtx, st) 3640 if err != nil { 3641 goto handleFailed 3642 } 3643 case *tree.SetVar: 3644 selfHandle = true 3645 err = mce.handleSetVar(requestCtx, st) 3646 if err != nil { 3647 goto handleFailed 3648 } 3649 case *tree.ShowVariables: 3650 selfHandle = true 3651 err = mce.handleShowVariables(st, proc) 3652 if err != nil { 3653 goto handleFailed 3654 } 3655 case *tree.ShowErrors, *tree.ShowWarnings: 3656 selfHandle = true 3657 err = mce.handleShowErrors() 3658 if err != nil { 3659 goto handleFailed 3660 } 3661 case *tree.AnalyzeStmt: 3662 selfHandle = true 3663 if err = mce.handleAnalyzeStmt(requestCtx, st); err != nil { 3664 goto handleFailed 3665 } 3666 case *tree.ExplainStmt: 3667 selfHandle = true 3668 if err = mce.handleExplainStmt(requestCtx, st); err != nil { 3669 goto handleFailed 3670 } 3671 case *tree.ExplainAnalyze: 3672 ses.SetData(nil) 3673 switch st.Statement.(type) { 3674 case *tree.Delete: 3675 ses.GetTxnCompileCtx().SetQueryType(TXN_DELETE) 3676 case *tree.Update: 3677 ses.GetTxnCompileCtx().SetQueryType(TXN_UPDATE) 3678 default: 3679 ses.GetTxnCompileCtx().SetQueryType(TXN_DEFAULT) 3680 } 3681 case *tree.ShowColumns: 3682 ses.SetShowStmtType(ShowColumns) 3683 ses.SetData(nil) 3684 case *tree.ShowTableStatus: 3685 ses.SetShowStmtType(ShowTableStatus) 3686 ses.SetData(nil) 3687 case *tree.Delete: 3688 ses.GetTxnCompileCtx().SetQueryType(TXN_DELETE) 3689 case *tree.Update: 3690 ses.GetTxnCompileCtx().SetQueryType(TXN_UPDATE) 3691 case *InternalCmdFieldList: 3692 selfHandle = true 3693 if err = mce.handleCmdFieldList(requestCtx, st); err != nil { 3694 goto handleFailed 3695 } 3696 case *tree.CreateAccount: 3697 selfHandle = true 3698 ses.InvalidatePrivilegeCache() 3699 if err = mce.handleCreateAccount(requestCtx, st); err != nil { 3700 goto handleFailed 3701 } 3702 case *tree.DropAccount: 3703 selfHandle = true 3704 ses.InvalidatePrivilegeCache() 3705 if err = mce.handleDropAccount(requestCtx, st); err != nil { 3706 goto handleFailed 3707 } 3708 case *tree.AlterAccount: 3709 ses.InvalidatePrivilegeCache() 3710 selfHandle = true 3711 if err = mce.handleAlterAccount(requestCtx, st); err != nil { 3712 goto handleFailed 3713 } 3714 case *tree.AlterDataBaseConfig: 3715 ses.InvalidatePrivilegeCache() 3716 selfHandle = true 3717 if st.IsAccountLevel { 3718 if err = mce.handleAlterAccountConfig(requestCtx, st); err != nil { 3719 goto handleFailed 3720 } 3721 } else { 3722 if err = mce.handleAlterDataBaseConfig(requestCtx, st); err != nil { 3723 goto handleFailed 3724 } 3725 } 3726 case *tree.CreateUser: 3727 selfHandle = true 3728 ses.InvalidatePrivilegeCache() 3729 if err = mce.handleCreateUser(requestCtx, st); err != nil { 3730 goto handleFailed 3731 } 3732 case *tree.DropUser: 3733 selfHandle = true 3734 ses.InvalidatePrivilegeCache() 3735 if err = mce.handleDropUser(requestCtx, st); err != nil { 3736 goto handleFailed 3737 } 3738 case *tree.AlterView: 3739 ses.InvalidatePrivilegeCache() 3740 case *tree.AlterUser: //TODO 3741 ses.InvalidatePrivilegeCache() 3742 case *tree.CreateRole: 3743 selfHandle = true 3744 ses.InvalidatePrivilegeCache() 3745 if err = mce.handleCreateRole(requestCtx, st); err != nil { 3746 goto handleFailed 3747 } 3748 case *tree.DropRole: 3749 selfHandle = true 3750 ses.InvalidatePrivilegeCache() 3751 if err = mce.handleDropRole(requestCtx, st); err != nil { 3752 goto handleFailed 3753 } 3754 case *tree.CreateFunction: 3755 selfHandle = true 3756 if err = mce.handleCreateFunction(requestCtx, st); err != nil { 3757 goto handleFailed 3758 } 3759 case *tree.DropFunction: 3760 selfHandle = true 3761 if err = mce.handleDropFunction(requestCtx, st); err != nil { 3762 goto handleFailed 3763 } 3764 case *tree.Grant: 3765 selfHandle = true 3766 ses.InvalidatePrivilegeCache() 3767 switch st.Typ { 3768 case tree.GrantTypeRole: 3769 if err = mce.handleGrantRole(requestCtx, &st.GrantRole); err != nil { 3770 goto handleFailed 3771 } 3772 case tree.GrantTypePrivilege: 3773 if err = mce.handleGrantPrivilege(requestCtx, &st.GrantPrivilege); err != nil { 3774 goto handleFailed 3775 } 3776 } 3777 case *tree.Revoke: 3778 selfHandle = true 3779 ses.InvalidatePrivilegeCache() 3780 switch st.Typ { 3781 case tree.RevokeTypeRole: 3782 if err = mce.handleRevokeRole(requestCtx, &st.RevokeRole); err != nil { 3783 goto handleFailed 3784 } 3785 case tree.RevokeTypePrivilege: 3786 if err = mce.handleRevokePrivilege(requestCtx, &st.RevokePrivilege); err != nil { 3787 goto handleFailed 3788 } 3789 } 3790 case *tree.Kill: 3791 selfHandle = true 3792 ses.InvalidatePrivilegeCache() 3793 if err = mce.handleKill(requestCtx, st); err != nil { 3794 goto handleFailed 3795 } 3796 case *tree.ShowAccounts: 3797 selfHandle = true 3798 if err = mce.handleShowAccounts(requestCtx, st); err != nil { 3799 goto handleFailed 3800 } 3801 case *tree.Load: 3802 if st.Local { 3803 proc.LoadLocalReader, loadLocalWriter = io.Pipe() 3804 } 3805 } 3806 3807 if selfHandle { 3808 goto handleSucceeded 3809 } 3810 if err = cw.SetDatabaseName(ses.GetDatabaseName()); err != nil { 3811 goto handleFailed 3812 } 3813 3814 cmpBegin = time.Now() 3815 3816 if ret, err = cw.Compile(requestCtx, ses, ses.GetOutputCallback()); err != nil { 3817 goto handleFailed 3818 } 3819 stmt = cw.GetAst() 3820 // reset some special stmt for execute statement 3821 switch st := stmt.(type) { 3822 case *tree.SetVar: 3823 err = mce.handleSetVar(requestCtx, st) 3824 if err != nil { 3825 goto handleFailed 3826 } else { 3827 goto handleSucceeded 3828 } 3829 case *tree.ShowVariables: 3830 err = mce.handleShowVariables(st, proc) 3831 if err != nil { 3832 goto handleFailed 3833 } else { 3834 goto handleSucceeded 3835 } 3836 case *tree.ShowErrors, *tree.ShowWarnings: 3837 err = mce.handleShowErrors() 3838 if err != nil { 3839 goto handleFailed 3840 } else { 3841 goto handleSucceeded 3842 } 3843 } 3844 3845 runner = ret.(ComputationRunner) 3846 3847 logInfof(ses.GetConciseProfile(), "time of Exec.Build : %s", time.Since(cmpBegin).String()) 3848 3849 mrs = ses.GetMysqlResultSet() 3850 // cw.Compile might rewrite sql, here we fetch the latest version 3851 switch statement := cw.GetAst().(type) { 3852 //produce result set 3853 case *tree.Select, 3854 *tree.ShowCreateTable, *tree.ShowCreateDatabase, *tree.ShowTables, *tree.ShowDatabases, *tree.ShowColumns, 3855 *tree.ShowProcessList, *tree.ShowStatus, *tree.ShowTableStatus, *tree.ShowGrants, 3856 *tree.ShowIndex, *tree.ShowCreateView, *tree.ShowTarget, *tree.ShowCollation, *tree.ValuesStatement, 3857 *tree.ExplainFor, *tree.ExplainStmt, *tree.ShowTableNumber, *tree.ShowColumnNumber, *tree.ShowTableValues, *tree.ShowLocks, *tree.ShowNodeList, *tree.ShowFunctionStatus: 3858 columns, err = cw.GetColumns() 3859 if err != nil { 3860 logErrorf(ses.GetConciseProfile(), "GetColumns from Computation handler failed. error: %v", err) 3861 goto handleFailed 3862 } 3863 if c, ok := cw.(*TxnComputationWrapper); ok { 3864 ses.rs = &plan.ResultColDef{ResultCols: plan2.GetResultColumnsFromPlan(c.plan)} 3865 } 3866 /* 3867 Step 1 : send column count and column definition. 3868 */ 3869 //send column count 3870 colCnt := uint64(len(columns)) 3871 err = proto.SendColumnCountPacket(colCnt) 3872 if err != nil { 3873 goto handleFailed 3874 } 3875 //send columns 3876 //column_count * Protocol::ColumnDefinition packets 3877 cmd := ses.GetCmd() 3878 for _, c := range columns { 3879 mysqlc := c.(Column) 3880 mrs.AddColumn(mysqlc) 3881 3882 //logutil.Infof("doComQuery col name %v type %v ",col.Name(),col.ColumnType()) 3883 /* 3884 mysql COM_QUERY response: send the column definition per column 3885 */ 3886 err = proto.SendColumnDefinitionPacket(requestCtx, mysqlc, int(cmd)) 3887 if err != nil { 3888 goto handleFailed 3889 } 3890 } 3891 3892 /* 3893 mysql COM_QUERY response: End after the column has been sent. 3894 send EOF packet 3895 */ 3896 err = proto.SendEOFPacketIf(0, 0) 3897 if err != nil { 3898 goto handleFailed 3899 } 3900 3901 runBegin := time.Now() 3902 /* 3903 Step 2: Start pipeline 3904 Producing the data row and sending the data row 3905 */ 3906 ep := ses.GetExportParam() 3907 if ep.Outfile { 3908 ep.DefaultBufSize = pu.SV.ExportDataDefaultFlushSize 3909 initExportFileParam(ep, mrs) 3910 if err = openNewFile(requestCtx, ep, mrs); err != nil { 3911 goto handleFailed 3912 } 3913 } 3914 if err = runner.Run(0); err != nil { 3915 goto handleFailed 3916 } 3917 3918 switch ses.GetShowStmtType() { 3919 case ShowColumns: 3920 if err = handleShowColumns(ses, statement.(*tree.ShowColumns)); err != nil { 3921 goto handleFailed 3922 } 3923 case ShowTableStatus: 3924 if err = handleShowTableStatus(ses, statement.(*tree.ShowTableStatus), proc); err != nil { 3925 goto handleFailed 3926 } 3927 } 3928 3929 if ep.Outfile { 3930 if err = ep.Writer.Flush(); err != nil { 3931 goto handleFailed 3932 } 3933 if err = ep.File.Close(); err != nil { 3934 goto handleFailed 3935 } 3936 } 3937 3938 logInfof(ses.GetConciseProfile(), "time of Exec.Run : %s", time.Since(runBegin).String()) 3939 3940 /* 3941 Step 3: Say goodbye 3942 mysql COM_QUERY response: End after the data row has been sent. 3943 After all row data has been sent, it sends the EOF or OK packet. 3944 */ 3945 err = proto.sendEOFOrOkPacket(0, 0) 3946 if err != nil { 3947 goto handleFailed 3948 } 3949 3950 /* 3951 Step 4: Serialize the execution plan by json 3952 */ 3953 if cwft, ok := cw.(*TxnComputationWrapper); ok { 3954 _ = cwft.RecordExecPlan(requestCtx) 3955 } 3956 //just status, no result set 3957 case *tree.CreateTable, *tree.DropTable, *tree.CreateDatabase, *tree.DropDatabase, 3958 *tree.CreateIndex, *tree.DropIndex, 3959 *tree.CreateView, *tree.DropView, 3960 *tree.AlterView, 3961 *tree.Insert, *tree.Update, 3962 *tree.BeginTransaction, *tree.CommitTransaction, *tree.RollbackTransaction, 3963 *tree.SetVar, 3964 *tree.Load, 3965 *tree.CreateUser, *tree.DropUser, *tree.AlterUser, 3966 *tree.CreateRole, *tree.DropRole, 3967 *tree.Revoke, *tree.Grant, 3968 *tree.SetDefaultRole, *tree.SetRole, *tree.SetPassword, 3969 *tree.Delete, *tree.TruncateTable: 3970 //change privilege 3971 switch cw.GetAst().(type) { 3972 case *tree.DropTable, *tree.DropDatabase, *tree.DropIndex, *tree.DropView, 3973 *tree.CreateUser, *tree.DropUser, *tree.AlterUser, 3974 *tree.CreateRole, *tree.DropRole, 3975 *tree.Revoke, *tree.Grant, 3976 *tree.SetDefaultRole, *tree.SetRole: 3977 ses.InvalidatePrivilegeCache() 3978 } 3979 runBegin := time.Now() 3980 /* 3981 Step 1: Start 3982 */ 3983 3984 if st, ok := cw.GetAst().(*tree.Load); ok { 3985 if st.Local { 3986 loadLocalErrGroup = new(errgroup.Group) 3987 loadLocalErrGroup.Go(func() error { 3988 return mce.processLoadLocal(proc.Ctx, st.Param, loadLocalWriter) 3989 }) 3990 } 3991 } 3992 3993 if err = runner.Run(0); err != nil { 3994 if loadLocalErrGroup != nil { // release resources 3995 err2 := proc.LoadLocalReader.Close() 3996 if err2 != nil { 3997 logErrorf(ses.GetConciseProfile(), "processLoadLocal reader close failed: %s", err2.Error()) 3998 } 3999 err2 = loadLocalErrGroup.Wait() // executor failed, but processLoadLocal is still running, wait for it 4000 if err2 != nil { 4001 logErrorf(ses.GetConciseProfile(), "processLoadLocal goroutine failed: %s", err2.Error()) 4002 } 4003 } 4004 goto handleFailed 4005 } 4006 4007 if loadLocalErrGroup != nil { 4008 if err = loadLocalErrGroup.Wait(); err != nil { //executor success, but processLoadLocal goroutine failed 4009 goto handleFailed 4010 } 4011 } 4012 4013 logInfof(ses.GetConciseProfile(), "time of Exec.Run : %s", time.Since(runBegin).String()) 4014 4015 rspLen = cw.GetAffectedRows() 4016 echoTime := time.Now() 4017 4018 logInfof(ses.GetConciseProfile(), "time of SendResponse %s", time.Since(echoTime).String()) 4019 4020 /* 4021 Step 4: Serialize the execution plan by json 4022 */ 4023 if cwft, ok := cw.(*TxnComputationWrapper); ok { 4024 _ = cwft.RecordExecPlan(requestCtx) 4025 } 4026 case *tree.ExplainAnalyze: 4027 explainColName := "QUERY PLAN" 4028 columns, err = GetExplainColumns(requestCtx, explainColName) 4029 if err != nil { 4030 logErrorf(ses.GetConciseProfile(), "GetColumns from ExplainColumns handler failed, error: %v", err) 4031 goto handleFailed 4032 } 4033 /* 4034 Step 1 : send column count and column definition. 4035 */ 4036 //send column count 4037 colCnt := uint64(len(columns)) 4038 err = proto.SendColumnCountPacket(colCnt) 4039 if err != nil { 4040 goto handleFailed 4041 } 4042 //send columns 4043 //column_count * Protocol::ColumnDefinition packets 4044 cmd := ses.GetCmd() 4045 for _, c := range columns { 4046 mysqlc := c.(Column) 4047 mrs.AddColumn(mysqlc) 4048 /* 4049 mysql COM_QUERY response: send the column definition per column 4050 */ 4051 err = proto.SendColumnDefinitionPacket(requestCtx, mysqlc, int(cmd)) 4052 if err != nil { 4053 goto handleFailed 4054 } 4055 } 4056 /* 4057 mysql COM_QUERY response: End after the column has been sent. 4058 send EOF packet 4059 */ 4060 err = proto.SendEOFPacketIf(0, 0) 4061 if err != nil { 4062 goto handleFailed 4063 } 4064 4065 runBegin := time.Now() 4066 /* 4067 Step 1: Start 4068 */ 4069 if err = runner.Run(0); err != nil { 4070 goto handleFailed 4071 } 4072 4073 logInfof(ses.GetConciseProfile(), "time of Exec.Run : %s", time.Since(runBegin).String()) 4074 4075 if cwft, ok := cw.(*TxnComputationWrapper); ok { 4076 queryPlan := cwft.plan 4077 // generator query explain 4078 explainQuery := explain.NewExplainQueryImpl(queryPlan.GetQuery()) 4079 4080 // build explain data buffer 4081 buffer := explain.NewExplainDataBuffer() 4082 var option *explain.ExplainOptions 4083 option, err = getExplainOption(requestCtx, statement.Options) 4084 if err != nil { 4085 goto handleFailed 4086 } 4087 4088 err = explainQuery.ExplainPlan(requestCtx, buffer, option) 4089 if err != nil { 4090 goto handleFailed 4091 } 4092 4093 err = buildMoExplainQuery(explainColName, buffer, ses, getDataFromPipeline) 4094 if err != nil { 4095 goto handleFailed 4096 } 4097 4098 /* 4099 Step 3: Say goodbye 4100 mysql COM_QUERY response: End after the data row has been sent. 4101 After all row data has been sent, it sends the EOF or OK packet. 4102 */ 4103 err = proto.sendEOFOrOkPacket(0, 0) 4104 if err != nil { 4105 goto handleFailed 4106 } 4107 } 4108 } 4109 handleSucceeded: 4110 //load data handle txn failure internally 4111 incStatementCounter(tenant, stmt) 4112 if !fromLoadData { 4113 txnErr = ses.TxnCommitSingleStatement(stmt) 4114 if txnErr != nil { 4115 logStatementStatus(requestCtx, ses, stmt, fail, txnErr) 4116 return txnErr 4117 } 4118 } 4119 switch stmt.(type) { 4120 case *tree.CreateTable, *tree.DropTable, 4121 *tree.CreateIndex, *tree.DropIndex, *tree.Insert, *tree.Update, 4122 *tree.CreateView, *tree.DropView, *tree.AlterView, *tree.Load, *tree.MoDump, 4123 *tree.CreateAccount, *tree.DropAccount, *tree.AlterAccount, *tree.AlterDataBaseConfig, 4124 *tree.CreateFunction, *tree.DropFunction, 4125 *tree.CreateUser, *tree.DropUser, *tree.AlterUser, 4126 *tree.CreateRole, *tree.DropRole, *tree.Revoke, *tree.Grant, 4127 *tree.SetDefaultRole, *tree.SetRole, *tree.SetPassword, *tree.Delete, *tree.TruncateTable, *tree.Use, 4128 *tree.BeginTransaction, *tree.CommitTransaction, *tree.RollbackTransaction: 4129 resp := mce.setResponse(i, len(cws), rspLen) 4130 if _, ok := stmt.(*tree.Insert); ok { 4131 resp.lastInsertId = proc.GetLastInsertID() 4132 if proc.GetLastInsertID() != 0 { 4133 ses.SetLastInsertID(proc.GetLastInsertID()) 4134 } 4135 } 4136 if err2 = mce.GetSession().GetMysqlProtocol().SendResponse(requestCtx, resp); err2 != nil { 4137 retErr = moerr.NewInternalError(requestCtx, "routine send response failed. error:%v ", err2) 4138 logStatementStatus(requestCtx, ses, stmt, fail, retErr) 4139 return retErr 4140 } 4141 4142 case *tree.CreateDatabase: 4143 insertRecordToMoMysqlCompatbilityMode(requestCtx, ses, stmt) 4144 resp := mce.setResponse(i, len(cws), rspLen) 4145 if err2 = mce.GetSession().GetMysqlProtocol().SendResponse(requestCtx, resp); err2 != nil { 4146 retErr = moerr.NewInternalError(requestCtx, "routine send response failed. error:%v ", err2) 4147 logStatementStatus(requestCtx, ses, stmt, fail, retErr) 4148 return retErr 4149 } 4150 4151 case *tree.DropDatabase: 4152 deleteRecordToMoMysqlCompatbilityMode(requestCtx, ses, stmt) 4153 resp := mce.setResponse(i, len(cws), rspLen) 4154 if err2 = mce.GetSession().GetMysqlProtocol().SendResponse(requestCtx, resp); err2 != nil { 4155 retErr = moerr.NewInternalError(requestCtx, "routine send response failed. error:%v ", err2) 4156 logStatementStatus(requestCtx, ses, stmt, fail, retErr) 4157 return retErr 4158 } 4159 4160 case *tree.PrepareStmt, *tree.PrepareString: 4161 if ses.GetCmd() == COM_STMT_PREPARE { 4162 if err2 = mce.GetSession().GetMysqlProtocol().SendPrepareResponse(requestCtx, prepareStmt); err2 != nil { 4163 retErr = moerr.NewInternalError(requestCtx, "routine send response failed. error:%v ", err2) 4164 logStatementStatus(requestCtx, ses, stmt, fail, retErr) 4165 return retErr 4166 } 4167 } else { 4168 resp := mce.setResponse(i, len(cws), rspLen) 4169 if err2 = mce.GetSession().GetMysqlProtocol().SendResponse(requestCtx, resp); err2 != nil { 4170 retErr = moerr.NewInternalError(requestCtx, "routine send response failed. error:%v ", err2) 4171 logStatementStatus(requestCtx, ses, stmt, fail, retErr) 4172 return retErr 4173 } 4174 } 4175 4176 case *tree.SetVar: 4177 resp := mce.setResponse(i, len(cws), rspLen) 4178 if err = proto.SendResponse(requestCtx, resp); err != nil { 4179 return moerr.NewInternalError(requestCtx, "routine send response failed. error:%v ", err) 4180 } 4181 4182 case *tree.Deallocate: 4183 //we will not send response in COM_STMT_CLOSE command 4184 if ses.GetCmd() != COM_STMT_CLOSE { 4185 resp := mce.setResponse(i, len(cws), rspLen) 4186 if err2 = mce.GetSession().GetMysqlProtocol().SendResponse(requestCtx, resp); err2 != nil { 4187 retErr = moerr.NewInternalError(requestCtx, "routine send response failed. error:%v ", err2) 4188 logStatementStatus(requestCtx, ses, stmt, fail, retErr) 4189 return retErr 4190 } 4191 } 4192 4193 case *tree.Reset: 4194 resp := mce.setResponse(i, len(cws), rspLen) 4195 if err2 = mce.GetSession().GetMysqlProtocol().SendResponse(requestCtx, resp); err2 != nil { 4196 retErr = moerr.NewInternalError(requestCtx, "routine send response failed. error:%v ", err2) 4197 logStatementStatus(requestCtx, ses, stmt, fail, retErr) 4198 return retErr 4199 } 4200 } 4201 logStatementStatus(requestCtx, ses, stmt, success, nil) 4202 goto handleNext 4203 handleFailed: 4204 incStatementCounter(tenant, stmt) 4205 incStatementErrorsCounter(tenant, stmt) 4206 /* 4207 Cases | set Autocommit = 1/0 | BEGIN statement | 4208 --------------------------------------------------- 4209 Case1 1 Yes 4210 Case2 1 No 4211 Case3 0 Yes 4212 Case4 0 No 4213 --------------------------------------------------- 4214 update error message in Case1,Case3,Case4. 4215 */ 4216 if ses.InMultiStmtTransactionMode() && ses.InActiveTransaction() { 4217 ses.cleanCache() 4218 ses.SetOptionBits(OPTION_ATTACH_ABORT_TRANSACTION_ERROR) 4219 } 4220 logError(ses.GetConciseProfile(), err.Error()) 4221 if !fromLoadData { 4222 txnErr = ses.TxnRollbackSingleStatement(stmt) 4223 if txnErr != nil { 4224 logStatementStatus(requestCtx, ses, stmt, fail, txnErr) 4225 return txnErr 4226 } 4227 } 4228 logStatementStatus(requestCtx, ses, stmt, fail, err) 4229 return err 4230 handleNext: 4231 } // end of for 4232 4233 if canCache && !ses.isCached(sql) { 4234 plans := make([]*plan.Plan, len(cws)) 4235 stmts := make([]tree.Statement, len(cws)) 4236 for i, cw := range cws { 4237 if cwft, ok := cw.(*TxnComputationWrapper); ok && checkNodeCanCache(cwft.plan) { 4238 plans[i] = cwft.plan 4239 stmts[i] = cwft.stmt 4240 } else { 4241 return nil 4242 } 4243 } 4244 ses.cachePlan(sql, stmts, plans) 4245 } 4246 4247 return nil 4248 } 4249 4250 func checkNodeCanCache(p *plan2.Plan) bool { 4251 if p == nil { 4252 return true 4253 } 4254 if q, ok := p.Plan.(*plan2.Plan_Query); ok { 4255 for _, node := range q.Query.Nodes { 4256 if node.NotCacheable { 4257 return false 4258 } 4259 } 4260 } 4261 return true 4262 } 4263 4264 // execute query. Currently, it is developing. Finally, it will replace the doComQuery. 4265 func (mce *MysqlCmdExecutor) doComQueryInProgress(requestCtx context.Context, sql string) (retErr error) { 4266 var stmtExecs []StmtExecutor 4267 var err error 4268 beginInstant := time.Now() 4269 ses := mce.GetSession() 4270 ses.SetShowStmtType(NotShowStatement) 4271 proto := ses.GetMysqlProtocol() 4272 ses.SetSql(sql) 4273 ses.GetExportParam().Outfile = false 4274 pu := ses.GetParameterUnit() 4275 proc := process.New( 4276 requestCtx, 4277 ses.GetMemPool(), 4278 pu.TxnClient, 4279 ses.GetTxnHandler().GetTxnOperator(), 4280 pu.FileService, 4281 pu.GetClusterDetails, 4282 ) 4283 proc.Id = mce.getNextProcessId() 4284 proc.Lim.Size = pu.SV.ProcessLimitationSize 4285 proc.Lim.BatchRows = pu.SV.ProcessLimitationBatchRows 4286 proc.Lim.PartitionRows = pu.SV.ProcessLimitationPartitionRows 4287 proc.SessionInfo = process.SessionInfo{ 4288 User: ses.GetUserName(), 4289 Host: pu.SV.Host, 4290 ConnectionID: uint64(proto.ConnectionID()), 4291 Database: ses.GetDatabaseName(), 4292 Version: pu.SV.ServerVersionPrefix + serverVersion.Load().(string), 4293 TimeZone: ses.GetTimeZone(), 4294 StorageEngine: pu.StorageEngine, 4295 AutoIncrCaches: ses.GetAutoIncrCaches(), 4296 AutoIncrCacheSize: ses.pu.SV.AutoIncrCacheSize, 4297 } 4298 4299 if ses.GetTenantInfo() != nil { 4300 proc.SessionInfo.Account = ses.GetTenantInfo().GetTenant() 4301 proc.SessionInfo.AccountId = ses.GetTenantInfo().GetTenantID() 4302 proc.SessionInfo.RoleId = ses.GetTenantInfo().GetDefaultRoleID() 4303 proc.SessionInfo.UserId = ses.GetTenantInfo().GetUserID() 4304 } else { 4305 proc.SessionInfo.Account = sysAccountName 4306 proc.SessionInfo.AccountId = sysAccountID 4307 proc.SessionInfo.RoleId = moAdminRoleID 4308 proc.SessionInfo.UserId = rootID 4309 } 4310 4311 stmtExecs, err = GetStmtExecList(ses.GetDatabaseName(), 4312 sql, 4313 ses.GetUserName(), 4314 pu.StorageEngine, 4315 proc, ses) 4316 if err != nil { 4317 requestCtx = RecordParseErrorStatement(requestCtx, ses, proc, beginInstant, sql) 4318 retErr = moerr.NewParseError(requestCtx, err.Error()) 4319 logStatementStringStatus(requestCtx, ses, sql, fail, retErr) 4320 return retErr 4321 } 4322 4323 singleStatement := len(stmtExecs) == 1 4324 for _, exec := range stmtExecs { 4325 err = Execute(requestCtx, ses, proc, exec, beginInstant, sql, singleStatement) 4326 if err != nil { 4327 return err 4328 } 4329 } 4330 return err 4331 } 4332 4333 func (mce *MysqlCmdExecutor) setResponse(cwIndex, cwsLen int, rspLen uint64) *Response { 4334 4335 //if the stmt has next stmt, should set the server status equals to 10 4336 if cwIndex < cwsLen-1 { 4337 return NewOkResponse(rspLen, 0, 0, SERVER_MORE_RESULTS_EXISTS, int(COM_QUERY), "") 4338 } else { 4339 return NewOkResponse(rspLen, 0, 0, 0, int(COM_QUERY), "") 4340 } 4341 4342 } 4343 4344 // ExecRequest the server execute the commands from the client following the mysql's routine 4345 func (mce *MysqlCmdExecutor) ExecRequest(requestCtx context.Context, ses *Session, req *Request) (resp *Response, err error) { 4346 defer func() { 4347 if e := recover(); e != nil { 4348 moe, ok := e.(*moerr.Error) 4349 if !ok { 4350 err = moerr.ConvertPanicError(requestCtx, e) 4351 resp = NewGeneralErrorResponse(COM_QUERY, err) 4352 } else { 4353 resp = NewGeneralErrorResponse(COM_QUERY, moe) 4354 } 4355 } 4356 }() 4357 4358 var sql string 4359 logDebugf(ses.GetCompleteProfile(), "cmd %v", req.GetCmd()) 4360 ses.SetCmd(req.GetCmd()) 4361 doComQuery := mce.GetDoQueryFunc() 4362 switch req.GetCmd() { 4363 case COM_QUIT: 4364 /*resp = NewResponse( 4365 OkResponse, 4366 0, 4367 int(COM_QUIT), 4368 nil, 4369 )*/ 4370 return resp, nil 4371 case COM_QUERY: 4372 var query = string(req.GetData().([]byte)) 4373 mce.addSqlCount(1) 4374 logInfo(ses.GetConciseProfile(), "query trace", logutil.ConnectionIdField(ses.GetConnectionID()), logutil.QueryField(SubStringFromBegin(query, int(ses.GetParameterUnit().SV.LengthOfQueryPrinted)))) 4375 err = doComQuery(requestCtx, query) 4376 if err != nil { 4377 resp = NewGeneralErrorResponse(COM_QUERY, err) 4378 } 4379 return resp, nil 4380 case COM_INIT_DB: 4381 var dbname = string(req.GetData().([]byte)) 4382 mce.addSqlCount(1) 4383 query := "use `" + dbname + "`" 4384 err = doComQuery(requestCtx, query) 4385 if err != nil { 4386 resp = NewGeneralErrorResponse(COM_INIT_DB, err) 4387 } 4388 4389 return resp, nil 4390 case COM_FIELD_LIST: 4391 var payload = string(req.GetData().([]byte)) 4392 mce.addSqlCount(1) 4393 query := makeCmdFieldListSql(payload) 4394 err = doComQuery(requestCtx, query) 4395 if err != nil { 4396 resp = NewGeneralErrorResponse(COM_FIELD_LIST, err) 4397 } 4398 4399 return resp, nil 4400 case COM_PING: 4401 resp = NewGeneralOkResponse(COM_PING) 4402 4403 return resp, nil 4404 4405 case COM_STMT_PREPARE: 4406 ses.SetCmd(COM_STMT_PREPARE) 4407 sql = string(req.GetData().([]byte)) 4408 mce.addSqlCount(1) 4409 4410 // rewrite to "Prepare stmt_name from 'xxx'" 4411 newLastStmtID := ses.GenNewStmtId() 4412 newStmtName := getPrepareStmtName(newLastStmtID) 4413 sql = fmt.Sprintf("prepare %s from %s", newStmtName, sql) 4414 logInfo(ses.GetConciseProfile(), "query trace", logutil.ConnectionIdField(ses.GetConnectionID()), logutil.QueryField(sql)) 4415 4416 err = doComQuery(requestCtx, sql) 4417 if err != nil { 4418 resp = NewGeneralErrorResponse(COM_STMT_PREPARE, err) 4419 } 4420 return resp, nil 4421 4422 case COM_STMT_EXECUTE: 4423 ses.SetCmd(COM_STMT_EXECUTE) 4424 data := req.GetData().([]byte) 4425 sql, err = mce.parseStmtExecute(requestCtx, data) 4426 if err != nil { 4427 return NewGeneralErrorResponse(COM_STMT_EXECUTE, err), nil 4428 } 4429 err = doComQuery(requestCtx, sql) 4430 if err != nil { 4431 resp = NewGeneralErrorResponse(COM_STMT_EXECUTE, err) 4432 } 4433 return resp, nil 4434 4435 case COM_STMT_CLOSE: 4436 data := req.GetData().([]byte) 4437 4438 // rewrite to "deallocate Prepare stmt_name" 4439 stmtID := binary.LittleEndian.Uint32(data[0:4]) 4440 stmtName := getPrepareStmtName(stmtID) 4441 sql = fmt.Sprintf("deallocate prepare %s", stmtName) 4442 logInfo(ses.GetConciseProfile(), "query trace", logutil.ConnectionIdField(ses.GetConnectionID()), logutil.QueryField(sql)) 4443 4444 err = doComQuery(requestCtx, sql) 4445 if err != nil { 4446 resp = NewGeneralErrorResponse(COM_STMT_CLOSE, err) 4447 } 4448 return resp, nil 4449 4450 case COM_STMT_RESET: 4451 data := req.GetData().([]byte) 4452 4453 //Payload of COM_STMT_RESET 4454 stmtID := binary.LittleEndian.Uint32(data[0:4]) 4455 stmtName := getPrepareStmtName(stmtID) 4456 sql = fmt.Sprintf("reset prepare %s", stmtName) 4457 logInfo(ses.GetConciseProfile(), "query trace", logutil.ConnectionIdField(ses.GetConnectionID()), logutil.QueryField(sql)) 4458 err = doComQuery(requestCtx, sql) 4459 if err != nil { 4460 resp = NewGeneralErrorResponse(COM_STMT_RESET, err) 4461 } 4462 return resp, nil 4463 4464 default: 4465 resp = NewGeneralErrorResponse(req.GetCmd(), moerr.NewInternalError(requestCtx, "unsupported command. 0x%x", req.GetCmd())) 4466 } 4467 return resp, nil 4468 } 4469 4470 func (mce *MysqlCmdExecutor) parseStmtExecute(requestCtx context.Context, data []byte) (string, error) { 4471 // see https://dev.mysql.com/doc/internals/en/com-stmt-execute.html 4472 pos := 0 4473 if len(data) < 4 { 4474 return "", moerr.NewInvalidInput(requestCtx, "sql command contains malformed packet") 4475 } 4476 stmtID := binary.LittleEndian.Uint32(data[0:4]) 4477 pos += 4 4478 4479 stmtName := fmt.Sprintf("%s_%d", prefixPrepareStmtName, stmtID) 4480 ses := mce.GetSession() 4481 preStmt, err := ses.GetPrepareStmt(stmtName) 4482 if err != nil { 4483 return "", err 4484 } 4485 names, vars, err := ses.GetMysqlProtocol().ParseExecuteData(requestCtx, preStmt, data, pos) 4486 if err != nil { 4487 return "", err 4488 } 4489 sql := fmt.Sprintf("execute %s", stmtName) 4490 varStrings := make([]string, len(names)) 4491 if len(names) > 0 { 4492 sql = sql + fmt.Sprintf(" using @%s", strings.Join(names, ",@")) 4493 for i := 0; i < len(names); i++ { 4494 varStrings[i] = fmt.Sprintf("%v", vars[i]) 4495 err := ses.SetUserDefinedVar(names[i], vars[i]) 4496 if err != nil { 4497 return "", err 4498 } 4499 } 4500 } 4501 logInfo(ses.GetConciseProfile(), "query trace", logutil.ConnectionIdField(ses.GetConnectionID()), logutil.QueryField(sql), logutil.VarsField(strings.Join(varStrings, " , "))) 4502 return sql, nil 4503 } 4504 4505 func (mce *MysqlCmdExecutor) SetCancelFunc(cancelFunc context.CancelFunc) { 4506 mce.mu.Lock() 4507 defer mce.mu.Unlock() 4508 mce.cancelRequestFunc = cancelFunc 4509 } 4510 4511 func (mce *MysqlCmdExecutor) Close() {} 4512 4513 /* 4514 StatementCanBeExecutedInUncommittedTransaction checks the statement can be executed in an active transaction. 4515 */ 4516 func StatementCanBeExecutedInUncommittedTransaction(ses *Session, stmt tree.Statement) (bool, error) { 4517 switch st := stmt.(type) { 4518 //ddl statement 4519 case *tree.CreateTable, *tree.CreateDatabase, *tree.CreateIndex, *tree.CreateView, *tree.AlterView: 4520 return true, nil 4521 //dml statement 4522 case *tree.Insert, *tree.Update, *tree.Delete, *tree.Select, *tree.Load, *tree.MoDump, *tree.ValuesStatement: 4523 return true, nil 4524 //transaction 4525 case *tree.BeginTransaction, *tree.CommitTransaction, *tree.RollbackTransaction: 4526 return true, nil 4527 //show 4528 case *tree.ShowCreateTable, 4529 *tree.ShowCreateView, 4530 *tree.ShowCreateDatabase, 4531 *tree.ShowColumns, 4532 *tree.ShowDatabases, 4533 *tree.ShowTarget, 4534 *tree.ShowTableStatus, 4535 *tree.ShowGrants, 4536 *tree.ShowTables, 4537 *tree.ShowProcessList, 4538 *tree.ShowErrors, 4539 *tree.ShowWarnings, 4540 *tree.ShowCollation, 4541 *tree.ShowVariables, 4542 *tree.ShowStatus, 4543 *tree.ShowIndex, 4544 *tree.ShowFunctionStatus, 4545 *tree.ShowNodeList, 4546 *tree.ShowLocks, 4547 *tree.ShowTableNumber, 4548 *tree.ShowColumnNumber, 4549 *tree.ShowTableValues, 4550 *tree.ShowAccounts: 4551 return true, nil 4552 //others 4553 case *tree.ExplainStmt, *tree.ExplainAnalyze, *tree.ExplainFor, *InternalCmdFieldList: 4554 return true, nil 4555 case *tree.PrepareStmt: 4556 return StatementCanBeExecutedInUncommittedTransaction(ses, st.Stmt) 4557 case *tree.PrepareString: 4558 preStmt, err := mysql.ParseOne(ses.requestCtx, st.Sql) 4559 if err != nil { 4560 return false, err 4561 } 4562 return StatementCanBeExecutedInUncommittedTransaction(ses, preStmt) 4563 case *tree.Execute: 4564 preName := string(st.Name) 4565 preStmt, err := ses.GetPrepareStmt(preName) 4566 if err != nil { 4567 return false, err 4568 } 4569 return StatementCanBeExecutedInUncommittedTransaction(ses, preStmt.PrepareStmt) 4570 case *tree.Deallocate, *tree.Reset: 4571 return true, nil 4572 case *tree.Use: 4573 /* 4574 These statements can not be executed in an uncommitted transaction: 4575 USE SECONDARY ROLE { ALL | NONE } 4576 USE ROLE role; 4577 */ 4578 return !st.IsUseRole(), nil 4579 case *tree.DropTable, *tree.DropDatabase, *tree.DropIndex, *tree.DropView: 4580 //background transaction can execute the DROPxxx in one transaction 4581 return ses.IsBackgroundSession(), nil 4582 } 4583 4584 return false, nil 4585 } 4586 4587 // IsDDL checks the statement is the DDL statement. 4588 func IsDDL(stmt tree.Statement) bool { 4589 switch stmt.(type) { 4590 case *tree.CreateTable, *tree.DropTable, 4591 *tree.CreateView, *tree.DropView, *tree.AlterView, 4592 *tree.CreateDatabase, *tree.DropDatabase, 4593 *tree.CreateIndex, *tree.DropIndex, *tree.TruncateTable: 4594 return true 4595 } 4596 return false 4597 } 4598 4599 // IsDropStatement checks the statement is the drop statement. 4600 func IsDropStatement(stmt tree.Statement) bool { 4601 switch stmt.(type) { 4602 case *tree.DropDatabase, *tree.DropTable, *tree.DropView, *tree.DropIndex: 4603 return true 4604 } 4605 return false 4606 } 4607 4608 // IsAdministrativeStatement checks the statement is the administrative statement. 4609 func IsAdministrativeStatement(stmt tree.Statement) bool { 4610 switch st := stmt.(type) { 4611 case *tree.CreateAccount, *tree.DropAccount, *tree.AlterAccount, 4612 *tree.CreateUser, *tree.DropUser, *tree.AlterUser, 4613 *tree.CreateRole, *tree.DropRole, 4614 *tree.Revoke, *tree.Grant, 4615 *tree.SetDefaultRole, *tree.SetRole, *tree.SetPassword: 4616 return true 4617 case *tree.Use: 4618 return st.IsUseRole() 4619 } 4620 return false 4621 } 4622 4623 // IsParameterModificationStatement checks the statement is the statement of parameter modification statement. 4624 func IsParameterModificationStatement(stmt tree.Statement) bool { 4625 switch stmt.(type) { 4626 case *tree.SetVar: 4627 return true 4628 } 4629 return false 4630 } 4631 4632 // IsPrepareStatement checks the statement is the Prepare statement. 4633 func IsPrepareStatement(stmt tree.Statement) bool { 4634 switch stmt.(type) { 4635 case *tree.PrepareStmt, *tree.PrepareString: 4636 return true 4637 } 4638 return false 4639 } 4640 4641 /* 4642 NeedToBeCommittedInActiveTransaction checks the statement that need to be committed 4643 in an active transaction. 4644 4645 Currently, it includes the drop statement, the administration statement , 4646 4647 the parameter modification statement. 4648 */ 4649 func NeedToBeCommittedInActiveTransaction(stmt tree.Statement) bool { 4650 if stmt == nil { 4651 return false 4652 } 4653 return IsDropStatement(stmt) || IsAdministrativeStatement(stmt) || IsParameterModificationStatement(stmt) 4654 } 4655 4656 func NewMysqlCmdExecutor() *MysqlCmdExecutor { 4657 return &MysqlCmdExecutor{} 4658 } 4659 4660 /* 4661 convert the type in computation engine to the type in mysql. 4662 */ 4663 func convertEngineTypeToMysqlType(ctx context.Context, engineType types.T, col *MysqlColumn) error { 4664 switch engineType { 4665 case types.T_any: 4666 col.SetColumnType(defines.MYSQL_TYPE_NULL) 4667 case types.T_json: 4668 col.SetColumnType(defines.MYSQL_TYPE_JSON) 4669 case types.T_bool: 4670 col.SetColumnType(defines.MYSQL_TYPE_BOOL) 4671 case types.T_int8: 4672 col.SetColumnType(defines.MYSQL_TYPE_TINY) 4673 case types.T_uint8: 4674 col.SetColumnType(defines.MYSQL_TYPE_TINY) 4675 col.SetSigned(false) 4676 case types.T_int16: 4677 col.SetColumnType(defines.MYSQL_TYPE_SHORT) 4678 case types.T_uint16: 4679 col.SetColumnType(defines.MYSQL_TYPE_SHORT) 4680 col.SetSigned(false) 4681 case types.T_int32: 4682 col.SetColumnType(defines.MYSQL_TYPE_LONG) 4683 case types.T_uint32: 4684 col.SetColumnType(defines.MYSQL_TYPE_LONG) 4685 col.SetSigned(false) 4686 case types.T_int64: 4687 col.SetColumnType(defines.MYSQL_TYPE_LONGLONG) 4688 case types.T_uint64: 4689 col.SetColumnType(defines.MYSQL_TYPE_LONGLONG) 4690 col.SetSigned(false) 4691 case types.T_float32: 4692 col.SetColumnType(defines.MYSQL_TYPE_FLOAT) 4693 case types.T_float64: 4694 col.SetColumnType(defines.MYSQL_TYPE_DOUBLE) 4695 case types.T_char: 4696 col.SetColumnType(defines.MYSQL_TYPE_STRING) 4697 case types.T_varchar: 4698 col.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 4699 case types.T_date: 4700 col.SetColumnType(defines.MYSQL_TYPE_DATE) 4701 case types.T_datetime: 4702 col.SetColumnType(defines.MYSQL_TYPE_DATETIME) 4703 case types.T_time: 4704 col.SetColumnType(defines.MYSQL_TYPE_TIME) 4705 case types.T_timestamp: 4706 col.SetColumnType(defines.MYSQL_TYPE_TIMESTAMP) 4707 case types.T_decimal64: 4708 col.SetColumnType(defines.MYSQL_TYPE_DECIMAL) 4709 case types.T_decimal128: 4710 col.SetColumnType(defines.MYSQL_TYPE_DECIMAL) 4711 case types.T_blob: 4712 col.SetColumnType(defines.MYSQL_TYPE_BLOB) 4713 case types.T_text: 4714 col.SetColumnType(defines.MYSQL_TYPE_TEXT) 4715 case types.T_uuid: 4716 col.SetColumnType(defines.MYSQL_TYPE_UUID) 4717 default: 4718 return moerr.NewInternalError(ctx, "RunWhileSend : unsupported type %d", engineType) 4719 } 4720 return nil 4721 } 4722 4723 func convertMysqlTextTypeToBlobType(col *MysqlColumn) { 4724 if col.ColumnType() == defines.MYSQL_TYPE_TEXT { 4725 col.SetColumnType(defines.MYSQL_TYPE_BLOB) 4726 } 4727 } 4728 4729 // build plan json when marhal plan error 4730 func buildErrorJsonPlan(uuid uuid.UUID, errcode uint16, msg string) []byte { 4731 explainData := explain.ExplainData{ 4732 Code: errcode, 4733 Message: msg, 4734 Success: false, 4735 Uuid: uuid.String(), 4736 } 4737 buffer := &bytes.Buffer{} 4738 encoder := json.NewEncoder(buffer) 4739 encoder.SetEscapeHTML(false) 4740 encoder.Encode(explainData) 4741 return buffer.Bytes() 4742 } 4743 4744 func serializePlanToJson(ctx context.Context, queryPlan *plan2.Plan, uuid uuid.UUID) (jsonBytes []byte, statsJonsBytes []byte, stats motrace.Statistic) { 4745 if queryPlan != nil && queryPlan.GetQuery() != nil { 4746 explainQuery := explain.NewExplainQueryImpl(queryPlan.GetQuery()) 4747 options := &explain.ExplainOptions{ 4748 Verbose: true, 4749 Analyze: true, 4750 Format: explain.EXPLAIN_FORMAT_TEXT, 4751 } 4752 marshalPlan := explainQuery.BuildJsonPlan(ctx, uuid, options) 4753 stats.RowsRead, stats.BytesScan = marshalPlan.StatisticsRead() 4754 // data transform to json datastruct 4755 buffer := &bytes.Buffer{} 4756 encoder := json.NewEncoder(buffer) 4757 encoder.SetEscapeHTML(false) 4758 err := encoder.Encode(marshalPlan) 4759 if err != nil { 4760 moError := moerr.NewInternalError(ctx, "serialize plan to json error: %s", err.Error()) 4761 jsonBytes = buildErrorJsonPlan(uuid, moError.ErrorCode(), moError.Error()) 4762 } else { 4763 jsonBytes = buffer.Bytes() 4764 } 4765 // data transform Global to json 4766 if len(marshalPlan.Steps) > 0 { 4767 if len(marshalPlan.Steps) > 1 { 4768 logutil.Fatalf("need handle multi execPlan trees, cnt: %d", len(marshalPlan.Steps)) 4769 } 4770 buffer := &bytes.Buffer{} 4771 encoder := json.NewEncoder(buffer) 4772 encoder.SetEscapeHTML(false) 4773 global := marshalPlan.Steps[0].GraphData.Global 4774 err = encoder.Encode(&global) 4775 if err != nil { 4776 statsJonsBytes = []byte(fmt.Sprintf(`{"code":200,"message":"%q"}`, err.Error())) 4777 } else { 4778 statsJonsBytes = buffer.Bytes() 4779 } 4780 } 4781 } else { 4782 jsonBytes = buildErrorJsonPlan(uuid, moerr.ErrWarn, "sql query no record execution plan") 4783 } 4784 return jsonBytes, statsJonsBytes, stats 4785 } 4786 4787 // SerializeExecPlan Serialize the execution plan by json 4788 var SerializeExecPlan = func(ctx context.Context, plan any, uuid uuid.UUID) ([]byte, []byte, motrace.Statistic) { 4789 if plan == nil { 4790 return serializePlanToJson(ctx, nil, uuid) 4791 } else if queryPlan, ok := plan.(*plan2.Plan); !ok { 4792 moError := moerr.NewInternalError(ctx, "execPlan not type of plan2.Plan: %s", reflect.ValueOf(plan).Type().Name()) 4793 return buildErrorJsonPlan(uuid, moError.ErrorCode(), moError.Error()), []byte{}, motrace.Statistic{} 4794 } else { 4795 // data transform to json dataStruct 4796 return serializePlanToJson(ctx, queryPlan, uuid) 4797 } 4798 } 4799 4800 func init() { 4801 motrace.SetDefaultSerializeExecPlan(SerializeExecPlan) 4802 } 4803 4804 func getAccountId(ctx context.Context) uint32 { 4805 var accountId uint32 4806 4807 if v := ctx.Value(defines.TenantIDKey{}); v != nil { 4808 accountId = v.(uint32) 4809 } 4810 return accountId 4811 } 4812 4813 func changeVersion(ctx context.Context, ses *Session, db string) error { 4814 var err error 4815 version, _ := GetVersionCompatbility(ctx, ses, db) 4816 if ses.GetTenantInfo() != nil { 4817 ses.GetTenantInfo().SetVersion(version) 4818 } 4819 return err 4820 }