github.com/matrixorigin/matrixone@v1.2.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 "errors" 23 "fmt" 24 "io" 25 gotrace "runtime/trace" 26 "sort" 27 "strconv" 28 "strings" 29 "sync" 30 "time" 31 32 "github.com/confluentinc/confluent-kafka-go/v2/kafka" 33 "github.com/fagongzi/goetty/v2" 34 "github.com/google/uuid" 35 "go.uber.org/zap" 36 37 "github.com/matrixorigin/matrixone/pkg/clusterservice" 38 "github.com/matrixorigin/matrixone/pkg/common/moerr" 39 "github.com/matrixorigin/matrixone/pkg/common/runtime" 40 "github.com/matrixorigin/matrixone/pkg/common/util" 41 "github.com/matrixorigin/matrixone/pkg/container/batch" 42 "github.com/matrixorigin/matrixone/pkg/container/types" 43 "github.com/matrixorigin/matrixone/pkg/container/vector" 44 "github.com/matrixorigin/matrixone/pkg/defines" 45 "github.com/matrixorigin/matrixone/pkg/frontend/constant" 46 "github.com/matrixorigin/matrixone/pkg/logutil" 47 "github.com/matrixorigin/matrixone/pkg/pb/metadata" 48 "github.com/matrixorigin/matrixone/pkg/pb/plan" 49 "github.com/matrixorigin/matrixone/pkg/pb/timestamp" 50 "github.com/matrixorigin/matrixone/pkg/sql/colexec" 51 "github.com/matrixorigin/matrixone/pkg/sql/compile" 52 "github.com/matrixorigin/matrixone/pkg/sql/parsers" 53 "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect" 54 "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect/mysql" 55 "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" 56 plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" 57 "github.com/matrixorigin/matrixone/pkg/sql/plan/explain" 58 "github.com/matrixorigin/matrixone/pkg/txn/client" 59 txnTrace "github.com/matrixorigin/matrixone/pkg/txn/trace" 60 "github.com/matrixorigin/matrixone/pkg/util/metric" 61 v2 "github.com/matrixorigin/matrixone/pkg/util/metric/v2" 62 "github.com/matrixorigin/matrixone/pkg/util/trace" 63 "github.com/matrixorigin/matrixone/pkg/util/trace/impl/motrace" 64 "github.com/matrixorigin/matrixone/pkg/util/trace/impl/motrace/statistic" 65 "github.com/matrixorigin/matrixone/pkg/vm/engine" 66 "github.com/matrixorigin/matrixone/pkg/vm/engine/disttae" 67 "github.com/matrixorigin/matrixone/pkg/vm/engine/disttae/route" 68 "github.com/matrixorigin/matrixone/pkg/vm/process" 69 ) 70 71 func createDropDatabaseErrorInfo() string { 72 return "CREATE/DROP of database is not supported in transactions" 73 } 74 75 func onlyCreateStatementErrorInfo() string { 76 return "Only CREATE of DDL is supported in transactions" 77 } 78 79 func administrativeCommandIsUnsupportedInTxnErrorInfo() string { 80 return "administrative command is unsupported in transactions" 81 } 82 83 func unclassifiedStatementInUncommittedTxnErrorInfo() string { 84 return "unclassified statement appears in uncommitted transaction" 85 } 86 87 func writeWriteConflictsErrorInfo() string { 88 return "Write conflicts detected. Previous transaction need to be aborted." 89 } 90 91 const ( 92 prefixPrepareStmtName = "__mo_stmt_id" 93 prefixPrepareStmtSessionVar = "__mo_stmt_var" 94 ) 95 96 func getPrepareStmtName(stmtID uint32) string { 97 return fmt.Sprintf("%s_%d", prefixPrepareStmtName, stmtID) 98 } 99 100 func parsePrepareStmtID(s string) uint32 { 101 if strings.HasPrefix(s, prefixPrepareStmtName) { 102 ss := strings.Split(s, "_") 103 v, err := strconv.ParseUint(ss[len(ss)-1], 10, 64) 104 if err != nil { 105 return 0 106 } 107 return uint32(v) 108 } 109 return 0 110 } 111 112 func GetPrepareStmtID(ctx context.Context, name string) (int, error) { 113 idx := len(prefixPrepareStmtName) + 1 114 if idx >= len(name) { 115 return -1, moerr.NewInternalError(ctx, "can not get Prepare stmtID") 116 } 117 return strconv.Atoi(name[idx:]) 118 } 119 120 func transferSessionConnType2StatisticConnType(c ConnType) statistic.ConnType { 121 switch c { 122 case ConnTypeUnset: 123 return statistic.ConnTypeUnknown 124 case ConnTypeInternal: 125 return statistic.ConnTypeInternal 126 case ConnTypeExternal: 127 return statistic.ConnTypeExternal 128 default: 129 panic("unknown connection type") 130 } 131 } 132 133 var RecordStatement = func(ctx context.Context, ses *Session, proc *process.Process, cw ComputationWrapper, envBegin time.Time, envStmt, sqlType string, useEnv bool) (context.Context, error) { 134 // set StatementID 135 var stmID uuid.UUID 136 var statement tree.Statement = nil 137 var text string 138 if cw != nil { 139 copy(stmID[:], cw.GetUUID()) 140 statement = cw.GetAst() 141 142 ses.ast = statement 143 144 execSql := makeExecuteSql(ctx, ses, statement) 145 if len(execSql) != 0 { 146 bb := strings.Builder{} 147 bb.WriteString(envStmt) 148 bb.WriteString(" // ") 149 bb.WriteString(execSql) 150 text = SubStringFromBegin(bb.String(), int(getGlobalPu().SV.LengthOfQueryPrinted)) 151 } else { 152 text = SubStringFromBegin(envStmt, int(getGlobalPu().SV.LengthOfQueryPrinted)) 153 } 154 } else { 155 stmID, _ = uuid.NewV7() 156 text = SubStringFromBegin(envStmt, int(getGlobalPu().SV.LengthOfQueryPrinted)) 157 } 158 ses.SetStmtId(stmID) 159 ses.SetStmtType(getStatementType(statement).GetStatementType()) 160 ses.SetQueryType(getStatementType(statement).GetQueryType()) 161 ses.SetSqlSourceType(sqlType) 162 ses.SetSqlOfStmt(text) 163 164 //note: txn id here may be empty 165 if sqlType != constant.InternalSql { 166 ses.pushQueryId(types.Uuid(stmID).ToString()) 167 } 168 169 if !motrace.GetTracerProvider().IsEnable() { 170 return ctx, nil 171 } 172 tenant := ses.GetTenantInfo() 173 if tenant == nil { 174 tenant, _ = GetTenantInfo(ctx, "internal") 175 } 176 stm := motrace.NewStatementInfo() 177 // set TransactionID 178 var txn TxnOperator 179 var err error 180 if handler := ses.GetTxnHandler(); handler.InActiveTxn() { 181 txn = handler.GetTxn() 182 if err != nil { 183 return nil, err 184 } 185 copy(stm.TransactionID[:], txn.Txn().ID) 186 } 187 // set SessionID 188 copy(stm.SessionID[:], ses.GetUUID()) 189 requestAt := envBegin 190 if !useEnv { 191 requestAt = time.Now() 192 } 193 194 copy(stm.StatementID[:], stmID[:]) 195 // END> set StatementID 196 stm.Account = tenant.GetTenant() 197 stm.RoleId = proc.SessionInfo.RoleId 198 stm.User = tenant.GetUser() 199 stm.Host = ses.proto.Peer() 200 stm.Database = ses.GetDatabaseName() 201 stm.Statement = text 202 stm.StatementFingerprint = "" // fixme= (Reserved) 203 stm.StatementTag = "" // fixme= (Reserved) 204 stm.SqlSourceType = sqlType 205 stm.RequestAt = requestAt 206 stm.StatementType = getStatementType(statement).GetStatementType() 207 stm.QueryType = getStatementType(statement).GetQueryType() 208 stm.ConnType = transferSessionConnType2StatisticConnType(ses.connType) 209 if sqlType == constant.InternalSql && isCmdFieldListSql(envStmt) { 210 // fix original issue #8165 211 stm.User = "" 212 } 213 if sqlType != constant.InternalSql { 214 ses.SetTStmt(stm) 215 } 216 if !stm.IsZeroTxnID() { 217 stm.Report(ctx) 218 } 219 if stm.IsMoLogger() && stm.StatementType == "Load" && len(stm.Statement) > 128 { 220 stm.Statement = envStmt[:40] + "..." + envStmt[len(envStmt)-45:] 221 } 222 223 return motrace.ContextWithStatement(ctx, stm), nil 224 } 225 226 var RecordParseErrorStatement = func(ctx context.Context, ses *Session, proc *process.Process, envBegin time.Time, 227 envStmt []string, sqlTypes []string, err error) (context.Context, error) { 228 retErr := moerr.NewParseError(ctx, err.Error()) 229 /* 230 !!!NOTE: the sql may be empty string. 231 So, the sqlTypes may be empty slice. 232 */ 233 sqlType := "" 234 if len(sqlTypes) > 0 { 235 sqlType = sqlTypes[0] 236 } else { 237 sqlType = constant.ExternSql 238 } 239 if len(envStmt) > 0 { 240 for i, sql := range envStmt { 241 if i < len(sqlTypes) { 242 sqlType = sqlTypes[i] 243 } 244 ctx, err = RecordStatement(ctx, ses, proc, nil, envBegin, sql, sqlType, true) 245 if err != nil { 246 return nil, err 247 } 248 motrace.EndStatement(ctx, retErr, 0, 0, 0) 249 } 250 } else { 251 ctx, err = RecordStatement(ctx, ses, proc, nil, envBegin, "", sqlType, true) 252 if err != nil { 253 return nil, err 254 } 255 motrace.EndStatement(ctx, retErr, 0, 0, 0) 256 } 257 258 tenant := ses.GetTenantInfo() 259 if tenant == nil { 260 tenant, _ = GetTenantInfo(ctx, "internal") 261 } 262 incStatementErrorsCounter(tenant.GetTenant(), nil) 263 return ctx, nil 264 } 265 266 // RecordStatementTxnID record txnID after TxnBegin or Compile(autocommit=1) 267 var RecordStatementTxnID = func(ctx context.Context, fses FeSession) error { 268 var ses *Session 269 var ok bool 270 if ses, ok = fses.(*Session); !ok { 271 return nil 272 } 273 var txn TxnOperator 274 var err error 275 if stm := motrace.StatementFromContext(ctx); ses != nil && stm != nil && stm.IsZeroTxnID() { 276 if handler := ses.GetTxnHandler(); handler.InActiveTxn() { 277 // simplify the logic of TxnOperator. refer to https://github.com/matrixorigin/matrixone/pull/13436#pullrequestreview-1779063200 278 txn = handler.GetTxn() 279 if err != nil { 280 return err 281 } 282 stm.SetTxnID(txn.Txn().ID) 283 ses.SetTxnId(txn.Txn().ID) 284 } 285 stm.Report(ctx) 286 } 287 288 // set frontend statement's txn-id 289 if upSes := ses.upstream; upSes != nil && upSes.tStmt != nil && upSes.tStmt.IsZeroTxnID() /* not record txn-id */ { 290 // background session has valid txn 291 if handler := ses.GetTxnHandler(); handler.InActiveTxn() { 292 txn = handler.GetTxn() 293 if err != nil { 294 return err 295 } 296 // set upstream (the frontend session) statement's txn-id 297 // PS: only skip ONE txn 298 if stmt := upSes.tStmt; stmt.NeedSkipTxn() /* normally set by determineUserHasPrivilegeSet */ { 299 // need to skip the whole txn, so it records the skipped txn-id 300 stmt.SetSkipTxn(false) 301 stmt.SetSkipTxnId(txn.Txn().ID) 302 } else if txnId := txn.Txn().ID; !stmt.SkipTxnId(txnId) { 303 upSes.tStmt.SetTxnID(txnId) 304 } 305 } 306 } 307 return nil 308 } 309 310 func handleShowTableStatus(ses *Session, execCtx *ExecCtx, stmt *tree.ShowTableStatus) error { 311 var db engine.Database 312 var err error 313 314 txnOp := ses.GetTxnHandler().GetTxn() 315 ctx := execCtx.reqCtx 316 // get db info as current account 317 if db, err = ses.GetTxnHandler().GetStorage().Database(ctx, stmt.DbName, txnOp); err != nil { 318 return err 319 } 320 321 if db.IsSubscription(ctx) { 322 // get global unique (pubAccountName, pubName) 323 var pubAccountName, pubName string 324 if _, pubAccountName, pubName, err = getSubInfoFromSql(ctx, ses, db.GetCreateSql(ctx)); err != nil { 325 return err 326 } 327 328 bh := GetRawBatchBackgroundExec(ctx, ses) 329 ctx = context.WithValue(ctx, defines.TenantIDKey{}, uint32(sysAccountID)) 330 var pubAccountId int32 331 if pubAccountId = getAccountIdByName(ctx, ses, bh, pubAccountName); pubAccountId == -1 { 332 return moerr.NewInternalError(ctx, "publish account does not exist") 333 } 334 335 // get publication record 336 var pubs []*published 337 if pubs, err = getPubs(ctx, ses, bh, pubAccountId, pubAccountName, pubName, ses.GetTenantName()); err != nil { 338 return err 339 } 340 if len(pubs) != 1 { 341 return moerr.NewInternalError(ctx, "no satisfied publication") 342 } 343 344 // as pub account 345 ctx = context.WithValue(ctx, defines.TenantIDKey{}, uint32(pubAccountId)) 346 // get db as pub account 347 if db, err = ses.GetTxnHandler().GetStorage().Database(ctx, pubs[0].pubDatabase, txnOp); err != nil { 348 return err 349 } 350 } 351 352 getRoleName := func(roleId uint32) (roleName string, err error) { 353 sql := getSqlForRoleNameOfRoleId(int64(roleId)) 354 355 var rets []ExecResult 356 if rets, err = executeSQLInBackgroundSession(ctx, ses, ses.GetMemPool(), sql); err != nil { 357 return "", err 358 } 359 360 if !execResultArrayHasData(rets) { 361 return "", moerr.NewInternalError(ctx, "get role name failed") 362 } 363 364 if roleName, err = rets[0].GetString(ctx, 0, 0); err != nil { 365 return "", err 366 } 367 return roleName, nil 368 } 369 370 mrs := ses.GetMysqlResultSet() 371 for _, row := range ses.data { 372 tableName := string(row[0].([]byte)) 373 r, err := db.Relation(ctx, tableName, nil) 374 if err != nil { 375 return err 376 } 377 if row[3], err = r.Rows(ctx); err != nil { 378 return err 379 } 380 if row[5], err = r.Size(ctx, disttae.AllColumns); err != nil { 381 return err 382 } 383 roleId := row[17].(uint32) 384 // role name 385 if row[18], err = getRoleName(roleId); err != nil { 386 return err 387 } 388 mrs.AddRow(row) 389 } 390 return nil 391 } 392 393 // getDataFromPipeline: extract the data from the pipeline. 394 // obj: session 395 func getDataFromPipeline(obj FeSession, execCtx *ExecCtx, bat *batch.Batch) error { 396 _, task := gotrace.NewTask(context.TODO(), "frontend.WriteDataToClient") 397 defer task.End() 398 ses := obj.(*Session) 399 if openSaveQueryResult(execCtx.reqCtx, ses) { 400 if bat == nil { 401 if err := saveQueryResultMeta(execCtx.reqCtx, ses); err != nil { 402 return err 403 } 404 } else { 405 if err := saveQueryResult(execCtx.reqCtx, ses, bat); err != nil { 406 return err 407 } 408 } 409 } 410 if bat == nil { 411 return nil 412 } 413 414 begin := time.Now() 415 proto := ses.GetMysqlProtocol() 416 417 ec := ses.GetExportConfig() 418 oq := NewOutputQueue(execCtx.reqCtx, ses, len(bat.Vecs), nil, nil) 419 row2colTime := time.Duration(0) 420 procBatchBegin := time.Now() 421 n := bat.Vecs[0].Length() 422 423 if ec.needExportToFile() { 424 initExportFirst(oq) 425 } 426 427 for j := 0; j < n; j++ { //row index 428 if ec.needExportToFile() { 429 select { 430 case <-execCtx.reqCtx.Done(): 431 return nil 432 default: 433 } 434 continue 435 } 436 437 row, err := extractRowFromEveryVector(execCtx.reqCtx, ses, bat, j, oq, true) 438 if err != nil { 439 return err 440 } 441 if oq.showStmtType == ShowTableStatus { 442 row2 := make([]interface{}, len(row)) 443 copy(row2, row) 444 ses.AppendData(row2) 445 } 446 } 447 448 if ec.needExportToFile() { 449 oq.rowIdx = uint64(n) 450 bat2 := preCopyBat(obj, bat) 451 go constructByte(execCtx.reqCtx, obj, bat2, oq.ep.Index, oq.ep.ByteChan, oq) 452 } 453 err := oq.flush() 454 if err != nil { 455 return err 456 } 457 458 procBatchTime := time.Since(procBatchBegin) 459 tTime := time.Since(begin) 460 ses.sentRows.Add(int64(n)) 461 logDebugf(ses.GetDebugString(), "rowCount %v \n"+ 462 "time of getDataFromPipeline : %s \n"+ 463 "processBatchTime %v \n"+ 464 "row2colTime %v \n"+ 465 "restTime(=totalTime - row2colTime) %v \n"+ 466 "protoStats %s", 467 n, 468 tTime, 469 procBatchTime, 470 row2colTime, 471 tTime-row2colTime, 472 proto.GetStats()) 473 474 return nil 475 } 476 477 func doUse(ctx context.Context, ses FeSession, db string) error { 478 defer RecordStatementTxnID(ctx, ses) 479 txnHandler := ses.GetTxnHandler() 480 var txn TxnOperator 481 var err error 482 var dbMeta engine.Database 483 txn = txnHandler.GetTxn() 484 //TODO: check meta data 485 if dbMeta, err = getGlobalPu().StorageEngine.Database(ctx, db, txn); err != nil { 486 //echo client. no such database 487 return moerr.NewBadDB(ctx, db) 488 } 489 if dbMeta.IsSubscription(ctx) { 490 _, err = checkSubscriptionValid(ctx, ses, dbMeta.GetCreateSql(ctx)) 491 if err != nil { 492 return err 493 } 494 } 495 oldDB := ses.GetDatabaseName() 496 ses.SetDatabaseName(db) 497 498 logDebugf(ses.GetDebugString(), "User %s change database from [%s] to [%s]", ses.GetUserName(), oldDB, ses.GetDatabaseName()) 499 500 return nil 501 } 502 503 func handleChangeDB(ses FeSession, execCtx *ExecCtx, db string) error { 504 return doUse(execCtx.reqCtx, ses, db) 505 } 506 507 func handleDump(ses FeSession, execCtx *ExecCtx, dump *tree.MoDump) error { 508 return doDumpQueryResult(execCtx.reqCtx, ses.(*Session), dump.ExportParams) 509 } 510 511 func doCmdFieldList(reqCtx context.Context, ses *Session, _ *InternalCmdFieldList) error { 512 dbName := ses.GetDatabaseName() 513 if dbName == "" { 514 return moerr.NewNoDB(reqCtx) 515 } 516 517 //Get table infos for the database from the cube 518 //case 1: there are no table infos for the db 519 //case 2: db changed 520 //NOTE: it costs too much time. 521 //It just reduces the information in the auto-completion (auto-rehash) of the mysql client. 522 //var attrs []ColumnInfo 523 // 524 //if tableInfos == nil || db != dbName { 525 // txnHandler := ses.GetTxnHandler() 526 // eng := ses.GetStorage() 527 // db, err := eng.Database(reqCtx, dbName, txnHandler.GetTxn()) 528 // if err != nil { 529 // return err 530 // } 531 // 532 // names, err := db.Relations(reqCtx) 533 // if err != nil { 534 // return err 535 // } 536 // for _, name := range names { 537 // table, err := db.Relation(reqCtx, name) 538 // if err != nil { 539 // return err 540 // } 541 // 542 // defs, err := table.TableDefs(reqCtx) 543 // if err != nil { 544 // return err 545 // } 546 // for _, def := range defs { 547 // if attr, ok := def.(*engine.AttributeDef); ok { 548 // attrs = append(attrs, &engineColumnInfo{ 549 // name: attr.Attr.Name, 550 // typ: attr.Attr.Type, 551 // }) 552 // } 553 // } 554 // } 555 // 556 // if tableInfos == nil { 557 // tableInfos = make(map[string][]ColumnInfo) 558 // } 559 // tableInfos[tableName] = attrs 560 //} 561 // 562 //cols, ok := tableInfos[tableName] 563 //if !ok { 564 // //just give the empty info when there is no such table. 565 // attrs = make([]ColumnInfo, 0) 566 //} else { 567 // attrs = cols 568 //} 569 // 570 //for _, c := range attrs { 571 // col := new(MysqlColumn) 572 // col.SetName(c.GetName()) 573 // err = convertEngineTypeToMysqlType(c.GetType(), col) 574 // if err != nil { 575 // return err 576 // } 577 // 578 // /* 579 // mysql CMD_FIELD_LIST response: send the column definition per column 580 // */ 581 // err = proto.SendColumnDefinitionPacket(col, int(COM_FIELD_LIST)) 582 // if err != nil { 583 // return err 584 // } 585 //} 586 return nil 587 } 588 589 /* 590 handle cmd CMD_FIELD_LIST 591 */ 592 func handleCmdFieldList(ses FeSession, execCtx *ExecCtx, icfl *InternalCmdFieldList) error { 593 var err error 594 proto := ses.GetMysqlProtocol() 595 596 ses.SetMysqlResultSet(nil) 597 err = doCmdFieldList(execCtx.reqCtx, ses.(*Session), icfl) 598 if err != nil { 599 return err 600 } 601 602 /* 603 mysql CMD_FIELD_LIST response: End after the column has been sent. 604 send EOF packet 605 */ 606 err = proto.sendEOFOrOkPacket(0, ses.GetTxnHandler().GetServerStatus()) 607 if err != nil { 608 return err 609 } 610 611 return err 612 } 613 614 func doSetVar(ses *Session, execCtx *ExecCtx, sv *tree.SetVar, sql string) error { 615 var err error = nil 616 var ok bool 617 setVarFunc := func(system, global bool, name string, value interface{}, sql string) error { 618 var oldValueRaw interface{} 619 if system { 620 if global { 621 err = doCheckRole(execCtx.reqCtx, ses) 622 if err != nil { 623 return err 624 } 625 err = ses.SetGlobalVar(execCtx.reqCtx, name, value) 626 if err != nil { 627 return err 628 } 629 err = doSetGlobalSystemVariable(execCtx.reqCtx, ses, name, value) 630 if err != nil { 631 return err 632 } 633 } else { 634 if strings.ToLower(name) == "autocommit" { 635 oldValueRaw, err = ses.GetSessionVar(execCtx.reqCtx, "autocommit") 636 if err != nil { 637 return err 638 } 639 } 640 err = ses.SetSessionVar(execCtx.reqCtx, name, value) 641 if err != nil { 642 return err 643 } 644 } 645 646 if strings.ToLower(name) == "autocommit" { 647 oldValue, err := valueIsBoolTrue(oldValueRaw) 648 if err != nil { 649 return err 650 } 651 newValue, err := valueIsBoolTrue(value) 652 if err != nil { 653 return err 654 } 655 err = ses.GetTxnHandler().SetAutocommit(execCtx, oldValue, newValue) 656 if err != nil { 657 return err 658 } 659 } 660 } else { 661 err = ses.SetUserDefinedVar(name, value, sql) 662 if err != nil { 663 return err 664 } 665 } 666 return nil 667 } 668 for _, assign := range sv.Assignments { 669 name := assign.Name 670 var value interface{} 671 672 value, err = getExprValue(assign.Value, ses, execCtx) 673 if err != nil { 674 return err 675 } 676 677 if systemVar, ok := gSysVarsDefs[name]; ok { 678 if isDefault, ok := value.(bool); ok && isDefault { 679 value = systemVar.Default 680 } 681 } 682 683 //TODO : fix SET NAMES after parser is ready 684 if name == "names" { 685 //replaced into three system variable: 686 //character_set_client, character_set_connection, and character_set_results 687 replacedBy := []string{ 688 "character_set_client", "character_set_connection", "character_set_results", 689 } 690 for _, rb := range replacedBy { 691 err = setVarFunc(assign.System, assign.Global, rb, value, sql) 692 if err != nil { 693 return err 694 } 695 } 696 } else if name == "syspublications" { 697 if !ses.GetTenantInfo().IsSysTenant() { 698 return moerr.NewInternalError(execCtx.reqCtx, "only system account can set system variable syspublications") 699 } 700 err = setVarFunc(assign.System, assign.Global, name, value, sql) 701 if err != nil { 702 return err 703 } 704 } else if name == "clear_privilege_cache" { 705 //if it is global variable, it does nothing. 706 if !assign.Global { 707 //if the value is 'on or off', just invalidate the privilege cache 708 ok, err = valueIsBoolTrue(value) 709 if err != nil { 710 return err 711 } 712 713 if ok { 714 cache := ses.GetPrivilegeCache() 715 if cache != nil { 716 cache.invalidate() 717 } 718 } 719 err = setVarFunc(assign.System, assign.Global, name, value, sql) 720 if err != nil { 721 return err 722 } 723 } 724 } else if name == "enable_privilege_cache" { 725 ok, err = valueIsBoolTrue(value) 726 if err != nil { 727 return err 728 } 729 730 //disable privilege cache. clean the cache. 731 if !ok { 732 cache := ses.GetPrivilegeCache() 733 if cache != nil { 734 cache.invalidate() 735 } 736 } 737 err = setVarFunc(assign.System, assign.Global, name, value, sql) 738 if err != nil { 739 return err 740 } 741 } else if name == "optimizer_hints" { 742 err = setVarFunc(assign.System, assign.Global, name, value, sql) 743 if err != nil { 744 return err 745 } 746 runtime.ProcessLevelRuntime().SetGlobalVariables("optimizer_hints", value) 747 } else if name == "runtime_filter_limit_in" { 748 err = setVarFunc(assign.System, assign.Global, name, value, sql) 749 if err != nil { 750 return err 751 } 752 runtime.ProcessLevelRuntime().SetGlobalVariables("runtime_filter_limit_in", value) 753 } else if name == "runtime_filter_limit_bloom_filter" { 754 err = setVarFunc(assign.System, assign.Global, name, value, sql) 755 if err != nil { 756 return err 757 } 758 runtime.ProcessLevelRuntime().SetGlobalVariables("runtime_filter_limit_bloom_filter", value) 759 } else { 760 err = setVarFunc(assign.System, assign.Global, name, value, sql) 761 if err != nil { 762 return err 763 } 764 } 765 } 766 return err 767 } 768 769 /* 770 handle setvar 771 */ 772 func handleSetVar(ses FeSession, execCtx *ExecCtx, sv *tree.SetVar, sql string) error { 773 err := doSetVar(ses.(*Session), execCtx, sv, sql) 774 if err != nil { 775 return err 776 } 777 778 return nil 779 } 780 781 func doShowErrors(ses *Session) error { 782 var err error 783 784 levelCol := new(MysqlColumn) 785 levelCol.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 786 levelCol.SetName("Level") 787 788 CodeCol := new(MysqlColumn) 789 CodeCol.SetColumnType(defines.MYSQL_TYPE_SHORT) 790 CodeCol.SetName("Code") 791 792 MsgCol := new(MysqlColumn) 793 MsgCol.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 794 MsgCol.SetName("Message") 795 796 mrs := ses.GetMysqlResultSet() 797 798 mrs.AddColumn(levelCol) 799 mrs.AddColumn(CodeCol) 800 mrs.AddColumn(MsgCol) 801 802 info := ses.GetErrInfo() 803 804 for i := info.length() - 1; i >= 0; i-- { 805 row := make([]interface{}, 3) 806 row[0] = "Error" 807 row[1] = info.codes[i] 808 row[2] = info.msgs[i] 809 mrs.AddRow(row) 810 } 811 812 return err 813 } 814 815 func handleShowErrors(ses FeSession) error { 816 err := doShowErrors(ses.(*Session)) 817 if err != nil { 818 return err 819 } 820 return err 821 } 822 823 func doShowVariables(ses *Session, execCtx *ExecCtx, sv *tree.ShowVariables) error { 824 if sv.Like != nil && sv.Where != nil { 825 return moerr.NewSyntaxError(execCtx.reqCtx, "like clause and where clause cannot exist at the same time") 826 } 827 828 var err error = nil 829 830 col1 := new(MysqlColumn) 831 col1.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 832 col1.SetName("Variable_name") 833 834 col2 := new(MysqlColumn) 835 col2.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 836 col2.SetName("Value") 837 838 mrs := ses.GetMysqlResultSet() 839 mrs.AddColumn(col1) 840 mrs.AddColumn(col2) 841 842 var hasLike = false 843 var likePattern = "" 844 var isIlike = false 845 if sv.Like != nil { 846 hasLike = true 847 if sv.Like.Op == tree.ILIKE { 848 isIlike = true 849 } 850 likePattern = strings.ToLower(sv.Like.Right.String()) 851 } 852 853 var sysVars map[string]interface{} 854 if sv.Global { 855 sysVars, err = doGetGlobalSystemVariable(execCtx.reqCtx, ses) 856 if err != nil { 857 return err 858 } 859 } else { 860 sysVars = ses.CopyAllSessionVars() 861 } 862 863 rows := make([][]interface{}, 0, len(sysVars)) 864 for name, value := range sysVars { 865 if hasLike { 866 s := name 867 if isIlike { 868 s = strings.ToLower(s) 869 } 870 if !WildcardMatch(likePattern, s) { 871 continue 872 } 873 } 874 row := make([]interface{}, 2) 875 row[0] = name 876 gsv, ok := GSysVariables.GetDefinitionOfSysVar(name) 877 if !ok { 878 return moerr.NewInternalError(execCtx.reqCtx, errorSystemVariableDoesNotExist()) 879 } 880 row[1] = value 881 if svbt, ok2 := gsv.GetType().(SystemVariableBoolType); ok2 { 882 if svbt.IsTrue(value) { 883 row[1] = "on" 884 } else { 885 row[1] = "off" 886 } 887 } 888 rows = append(rows, row) 889 } 890 891 if sv.Where != nil { 892 bat, err := constructVarBatch(ses, rows) 893 if err != nil { 894 return err 895 } 896 binder := plan2.NewDefaultBinder(execCtx.reqCtx, nil, nil, plan2.Type{Id: int32(types.T_varchar), Width: types.MaxVarcharLen}, []string{"variable_name", "value"}) 897 planExpr, err := binder.BindExpr(sv.Where.Expr, 0, false) 898 if err != nil { 899 return err 900 } 901 902 executor, err := colexec.NewExpressionExecutor(execCtx.proc, planExpr) 903 if err != nil { 904 return err 905 } 906 vec, err := executor.Eval(execCtx.proc, []*batch.Batch{bat}) 907 if err != nil { 908 executor.Free() 909 return err 910 } 911 912 bs := vector.MustFixedCol[bool](vec) 913 sels := execCtx.proc.Mp().GetSels() 914 for i, b := range bs { 915 if b { 916 sels = append(sels, int64(i)) 917 } 918 } 919 executor.Free() 920 921 bat.Shrink(sels, false) 922 execCtx.proc.Mp().PutSels(sels) 923 v0 := vector.MustStrCol(bat.Vecs[0]) 924 v1 := vector.MustStrCol(bat.Vecs[1]) 925 rows = rows[:len(v0)] 926 for i := range v0 { 927 rows[i][0] = v0[i] 928 rows[i][1] = v1[i] 929 } 930 bat.Clean(execCtx.proc.Mp()) 931 } 932 933 //sort by name 934 sort.Slice(rows, func(i, j int) bool { 935 return rows[i][0].(string) < rows[j][0].(string) 936 }) 937 938 for _, row := range rows { 939 mrs.AddRow(row) 940 } 941 942 return err 943 } 944 945 /* 946 handle show variables 947 */ 948 func handleShowVariables(ses FeSession, execCtx *ExecCtx, sv *tree.ShowVariables) error { 949 err := doShowVariables(ses.(*Session), execCtx, sv) 950 if err != nil { 951 return err 952 } 953 return err 954 } 955 956 func constructVarBatch(ses *Session, rows [][]interface{}) (*batch.Batch, error) { 957 bat := batch.New(true, []string{"Variable_name", "Value"}) 958 typ := types.New(types.T_varchar, types.MaxVarcharLen, 0) 959 cnt := len(rows) 960 bat.SetRowCount(cnt) 961 v0 := make([]string, cnt) 962 v1 := make([]string, cnt) 963 for i, row := range rows { 964 v0[i] = row[0].(string) 965 v1[i] = fmt.Sprintf("%v", row[1]) 966 } 967 bat.Vecs[0] = vector.NewVec(typ) 968 vector.AppendStringList(bat.Vecs[0], v0, nil, ses.GetMemPool()) 969 bat.Vecs[1] = vector.NewVec(typ) 970 vector.AppendStringList(bat.Vecs[1], v1, nil, ses.GetMemPool()) 971 return bat, nil 972 } 973 974 func constructCollationBatch(ses *Session, rows [][]interface{}) (*batch.Batch, error) { 975 bat := batch.New(true, []string{"Collation", "Charset", "Id", "Default", "Compiled", "Sortlen", "Pad_attribute"}) 976 typ := types.New(types.T_varchar, types.MaxVarcharLen, 0) 977 longlongTyp := types.New(types.T_int64, 0, 0) 978 longTyp := types.New(types.T_int32, 0, 0) 979 cnt := len(rows) 980 bat.SetRowCount(cnt) 981 v0 := make([]string, cnt) 982 v1 := make([]string, cnt) 983 v2 := make([]int64, cnt) 984 v3 := make([]string, cnt) 985 v4 := make([]string, cnt) 986 v5 := make([]int32, cnt) 987 v6 := make([]string, cnt) 988 for i, row := range rows { 989 v0[i] = row[0].(string) 990 v1[i] = row[1].(string) 991 v2[i] = row[2].(int64) 992 v3[i] = row[3].(string) 993 v4[i] = row[4].(string) 994 v5[i] = row[5].(int32) 995 v6[i] = row[6].(string) 996 } 997 bat.Vecs[0] = vector.NewVec(typ) 998 vector.AppendStringList(bat.Vecs[0], v0, nil, ses.GetMemPool()) 999 bat.Vecs[1] = vector.NewVec(typ) 1000 vector.AppendStringList(bat.Vecs[1], v1, nil, ses.GetMemPool()) 1001 bat.Vecs[2] = vector.NewVec(longlongTyp) 1002 vector.AppendFixedList[int64](bat.Vecs[2], v2, nil, ses.GetMemPool()) 1003 bat.Vecs[3] = vector.NewVec(typ) 1004 vector.AppendStringList(bat.Vecs[3], v3, nil, ses.GetMemPool()) 1005 bat.Vecs[4] = vector.NewVec(typ) 1006 vector.AppendStringList(bat.Vecs[4], v4, nil, ses.GetMemPool()) 1007 bat.Vecs[5] = vector.NewVec(longTyp) 1008 vector.AppendFixedList[int32](bat.Vecs[5], v5, nil, ses.GetMemPool()) 1009 bat.Vecs[6] = vector.NewVec(typ) 1010 vector.AppendStringList(bat.Vecs[6], v6, nil, ses.GetMemPool()) 1011 return bat, nil 1012 } 1013 1014 func handleAnalyzeStmt(ses *Session, execCtx *ExecCtx, stmt *tree.AnalyzeStmt) error { 1015 // rewrite analyzeStmt to `select approx_count_distinct(col), .. from tbl` 1016 // IMO, this approach is simple and future-proof 1017 // Although this rewriting processing could have been handled in rewrite module, 1018 // `handleAnalyzeStmt` can be easily managed by cron jobs in the future 1019 ctx := tree.NewFmtCtx(dialect.MYSQL) 1020 ctx.WriteString("select ") 1021 for i, ident := range stmt.Cols { 1022 if i > 0 { 1023 ctx.WriteByte(',') 1024 } 1025 ctx.WriteString("approx_count_distinct(") 1026 ctx.WriteString(string(ident)) 1027 ctx.WriteByte(')') 1028 } 1029 ctx.WriteString(" from ") 1030 stmt.Table.Format(ctx) 1031 sql := ctx.String() 1032 //backup the inside statement 1033 prevInsideStmt := ses.ReplaceDerivedStmt(true) 1034 defer func() { 1035 //restore the inside statement 1036 ses.ReplaceDerivedStmt(prevInsideStmt) 1037 }() 1038 tempExecCtx := ExecCtx{ 1039 ses: ses, 1040 reqCtx: execCtx.reqCtx, 1041 } 1042 return doComQuery(ses, &tempExecCtx, &UserInput{sql: sql}) 1043 } 1044 1045 func doExplainStmt(reqCtx context.Context, ses *Session, stmt *tree.ExplainStmt) error { 1046 1047 //1. generate the plan 1048 es, err := getExplainOption(reqCtx, stmt.Options) 1049 if err != nil { 1050 return err 1051 } 1052 1053 //get query optimizer and execute Optimize 1054 exPlan, err := buildPlan(reqCtx, ses, ses.GetTxnCompileCtx(), stmt.Statement) 1055 if err != nil { 1056 return err 1057 } 1058 if exPlan.GetDcl() != nil && exPlan.GetDcl().GetExecute() != nil { 1059 //replace the plan of the EXECUTE by the plan generated by the PREPARE 1060 execPlan := exPlan.GetDcl().GetExecute() 1061 replaced, _, err := ses.GetTxnCompileCtx().ReplacePlan(execPlan) 1062 if err != nil { 1063 return err 1064 } 1065 1066 exPlan = replaced 1067 paramVals := ses.GetTxnCompileCtx().tcw.paramVals 1068 if len(paramVals) > 0 { 1069 //replace the param var in the plan by the param value 1070 exPlan, err = plan2.FillValuesOfParamsInPlan(reqCtx, exPlan, paramVals) 1071 if err != nil { 1072 return err 1073 } 1074 if exPlan == nil { 1075 return moerr.NewInternalError(reqCtx, "failed to copy exPlan") 1076 } 1077 } 1078 } 1079 if exPlan.GetQuery() == nil { 1080 return moerr.NewNotSupported(reqCtx, "the sql query plan does not support explain.") 1081 } 1082 // generator query explain 1083 explainQuery := explain.NewExplainQueryImpl(exPlan.GetQuery()) 1084 1085 // build explain data buffer 1086 buffer := explain.NewExplainDataBuffer() 1087 err = explainQuery.ExplainPlan(reqCtx, buffer, es) 1088 if err != nil { 1089 return err 1090 } 1091 1092 //2. fill the result set 1093 explainColName := "QUERY PLAN" 1094 //column 1095 col1 := new(MysqlColumn) 1096 col1.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) 1097 col1.SetName(explainColName) 1098 1099 mrs := ses.GetMysqlResultSet() 1100 mrs.AddColumn(col1) 1101 1102 for _, line := range buffer.Lines { 1103 mrs.AddRow([]any{line}) 1104 } 1105 ses.rs = mysqlColDef2PlanResultColDef(mrs) 1106 1107 if openSaveQueryResult(reqCtx, ses) { 1108 //3. fill the batch for saving the query result 1109 bat, err := fillQueryBatch(ses, explainColName, buffer.Lines) 1110 defer bat.Clean(ses.GetMemPool()) 1111 if err != nil { 1112 return err 1113 } 1114 1115 // save query result 1116 err = maySaveQueryResult(reqCtx, ses, bat) 1117 if err != nil { 1118 1119 return err 1120 } 1121 } 1122 return nil 1123 } 1124 1125 func fillQueryBatch(ses *Session, explainColName string, lines []string) (*batch.Batch, error) { 1126 bat := batch.New(true, []string{explainColName}) 1127 typ := types.New(types.T_varchar, types.MaxVarcharLen, 0) 1128 1129 cnt := len(lines) 1130 bat.SetRowCount(cnt) 1131 bat.Vecs[0] = vector.NewVec(typ) 1132 err := vector.AppendStringList(bat.Vecs[0], lines, nil, ses.GetMemPool()) 1133 if err != nil { 1134 return nil, err 1135 } 1136 return bat, nil 1137 } 1138 1139 // Note: for pass the compile quickly. We will remove the comments in the future. 1140 func handleExplainStmt(ses FeSession, execCtx *ExecCtx, stmt *tree.ExplainStmt) error { 1141 return doExplainStmt(execCtx.reqCtx, ses.(*Session), stmt) 1142 } 1143 1144 func doPrepareStmt(ctx context.Context, ses *Session, st *tree.PrepareStmt, sql string, paramTypes []byte) (*PrepareStmt, error) { 1145 preparePlan, err := buildPlan(ctx, ses, ses.GetTxnCompileCtx(), st) 1146 if err != nil { 1147 return nil, err 1148 } 1149 1150 prepareStmt := &PrepareStmt{ 1151 Name: preparePlan.GetDcl().GetPrepare().GetName(), 1152 Sql: sql, 1153 PreparePlan: preparePlan, 1154 PrepareStmt: st.Stmt, 1155 getFromSendLongData: make(map[int]struct{}), 1156 } 1157 if len(paramTypes) > 0 { 1158 prepareStmt.ParamTypes = paramTypes 1159 } 1160 prepareStmt.InsertBat = ses.GetTxnCompileCtx().GetProcess().GetPrepareBatch() 1161 err = ses.SetPrepareStmt(ctx, preparePlan.GetDcl().GetPrepare().GetName(), prepareStmt) 1162 1163 return prepareStmt, err 1164 } 1165 1166 // handlePrepareStmt 1167 func handlePrepareStmt(ses FeSession, execCtx *ExecCtx, st *tree.PrepareStmt) (*PrepareStmt, error) { 1168 return doPrepareStmt(execCtx.reqCtx, ses.(*Session), st, execCtx.sqlOfStmt, execCtx.executeParamTypes) 1169 } 1170 1171 func doPrepareString(ses *Session, execCtx *ExecCtx, st *tree.PrepareString) (*PrepareStmt, error) { 1172 v, err := ses.GetGlobalVar(execCtx.reqCtx, "lower_case_table_names") 1173 if err != nil { 1174 return nil, err 1175 } 1176 1177 origin, err := ses.GetGlobalVar(execCtx.reqCtx, "keep_user_target_list_in_result") 1178 if err != nil { 1179 return nil, err 1180 } 1181 1182 stmts, err := mysql.Parse(execCtx.reqCtx, st.Sql, v.(int64), origin.(int64)) 1183 if err != nil { 1184 return nil, err 1185 } 1186 1187 preparePlan, err := buildPlan(execCtx.reqCtx, ses, ses.GetTxnCompileCtx(), st) 1188 if err != nil { 1189 return nil, err 1190 } 1191 prepareStmt := &PrepareStmt{ 1192 Name: preparePlan.GetDcl().GetPrepare().GetName(), 1193 Sql: st.Sql, 1194 PreparePlan: preparePlan, 1195 PrepareStmt: stmts[0], 1196 } 1197 prepareStmt.InsertBat = ses.GetTxnCompileCtx().GetProcess().GetPrepareBatch() 1198 err = ses.SetPrepareStmt(execCtx.reqCtx, preparePlan.GetDcl().GetPrepare().GetName(), prepareStmt) 1199 return prepareStmt, err 1200 } 1201 1202 // handlePrepareString 1203 func handlePrepareString(ses FeSession, execCtx *ExecCtx, st *tree.PrepareString) (*PrepareStmt, error) { 1204 return doPrepareString(ses.(*Session), execCtx, st) 1205 } 1206 1207 func doDeallocate(ses *Session, execCtx *ExecCtx, st *tree.Deallocate) error { 1208 deallocatePlan, err := buildPlan(execCtx.reqCtx, ses, ses.GetTxnCompileCtx(), st) 1209 if err != nil { 1210 return err 1211 } 1212 ses.RemovePrepareStmt(deallocatePlan.GetDcl().GetDeallocate().GetName()) 1213 return nil 1214 } 1215 1216 func doReset(_ context.Context, _ *Session, _ *tree.Reset) error { 1217 return nil 1218 } 1219 1220 // handleDeallocate 1221 func handleDeallocate(ses FeSession, execCtx *ExecCtx, st *tree.Deallocate) error { 1222 return doDeallocate(ses.(*Session), execCtx, st) 1223 } 1224 1225 // handleReset 1226 func handleReset(ses FeSession, execCtx *ExecCtx, st *tree.Reset) error { 1227 return doReset(execCtx.reqCtx, ses.(*Session), st) 1228 } 1229 1230 func handleCreatePublication(ses FeSession, execCtx *ExecCtx, cp *tree.CreatePublication) error { 1231 return doCreatePublication(execCtx.reqCtx, ses.(*Session), cp) 1232 } 1233 1234 func handleAlterPublication(ses FeSession, execCtx *ExecCtx, ap *tree.AlterPublication) error { 1235 return doAlterPublication(execCtx.reqCtx, ses.(*Session), ap) 1236 } 1237 1238 func handleDropPublication(ses FeSession, execCtx *ExecCtx, dp *tree.DropPublication) error { 1239 return doDropPublication(execCtx.reqCtx, ses.(*Session), dp) 1240 } 1241 1242 func handleCreateStage(ses FeSession, execCtx *ExecCtx, cs *tree.CreateStage) error { 1243 return doCreateStage(execCtx.reqCtx, ses.(*Session), cs) 1244 } 1245 1246 func handleAlterStage(ses FeSession, execCtx *ExecCtx, as *tree.AlterStage) error { 1247 return doAlterStage(execCtx.reqCtx, ses.(*Session), as) 1248 } 1249 1250 func handleDropStage(ses FeSession, execCtx *ExecCtx, ds *tree.DropStage) error { 1251 return doDropStage(execCtx.reqCtx, ses.(*Session), ds) 1252 } 1253 1254 func handleCreateSnapshot(ses *Session, execCtx *ExecCtx, ct *tree.CreateSnapShot) error { 1255 return doCreateSnapshot(execCtx.reqCtx, ses, ct) 1256 } 1257 1258 func handleDropSnapshot(ses *Session, execCtx *ExecCtx, ct *tree.DropSnapShot) error { 1259 return doDropSnapshot(execCtx.reqCtx, ses, ct) 1260 } 1261 1262 func handleRestoreSnapshot(ses *Session, execCtx *ExecCtx, rs *tree.RestoreSnapShot) error { 1263 return doRestoreSnapshot(execCtx.reqCtx, ses, rs) 1264 } 1265 1266 // handleCreateAccount creates a new user-level tenant in the context of the tenant SYS 1267 // which has been initialized. 1268 func handleCreateAccount(ses FeSession, execCtx *ExecCtx, ca *tree.CreateAccount, proc *process.Process) error { 1269 //step1 : create new account. 1270 create := &createAccount{ 1271 IfNotExists: ca.IfNotExists, 1272 IdentTyp: ca.AuthOption.IdentifiedType.Typ, 1273 StatusOption: ca.StatusOption, 1274 Comment: ca.Comment, 1275 } 1276 1277 b := strParamBinder{ 1278 ctx: execCtx.reqCtx, 1279 params: proc.GetPrepareParams(), 1280 } 1281 create.Name = b.bind(ca.Name) 1282 create.AdminName = b.bind(ca.AuthOption.AdminName) 1283 create.IdentStr = b.bindIdentStr(&ca.AuthOption.IdentifiedType) 1284 if b.err != nil { 1285 return b.err 1286 } 1287 1288 return InitGeneralTenant(execCtx.reqCtx, ses.(*Session), create) 1289 } 1290 1291 func handleDropAccount(ses FeSession, execCtx *ExecCtx, da *tree.DropAccount, proc *process.Process) error { 1292 drop := &dropAccount{ 1293 IfExists: da.IfExists, 1294 } 1295 1296 b := strParamBinder{ 1297 ctx: execCtx.reqCtx, 1298 params: proc.GetPrepareParams(), 1299 } 1300 drop.Name = b.bind(da.Name) 1301 if b.err != nil { 1302 return b.err 1303 } 1304 1305 return doDropAccount(execCtx.reqCtx, ses.(*Session), drop) 1306 } 1307 1308 // handleDropAccount drops a new user-level tenant 1309 func handleAlterAccount(ses FeSession, execCtx *ExecCtx, st *tree.AlterAccount, proc *process.Process) error { 1310 aa := &alterAccount{ 1311 IfExists: st.IfExists, 1312 StatusOption: st.StatusOption, 1313 Comment: st.Comment, 1314 } 1315 1316 b := strParamBinder{ 1317 ctx: execCtx.reqCtx, 1318 params: proc.GetPrepareParams(), 1319 } 1320 1321 aa.Name = b.bind(st.Name) 1322 if st.AuthOption.Exist { 1323 aa.AuthExist = true 1324 aa.AdminName = b.bind(st.AuthOption.AdminName) 1325 aa.IdentTyp = st.AuthOption.IdentifiedType.Typ 1326 aa.IdentStr = b.bindIdentStr(&st.AuthOption.IdentifiedType) 1327 } 1328 if b.err != nil { 1329 return b.err 1330 } 1331 1332 return doAlterAccount(execCtx.reqCtx, ses.(*Session), aa) 1333 } 1334 1335 // handleAlterDatabaseConfig alter a database's mysql_compatibility_mode 1336 func handleAlterDataBaseConfig(ses FeSession, execCtx *ExecCtx, ad *tree.AlterDataBaseConfig) error { 1337 return doAlterDatabaseConfig(execCtx.reqCtx, ses.(*Session), ad) 1338 } 1339 1340 // handleAlterAccountConfig alter a account's mysql_compatibility_mode 1341 func handleAlterAccountConfig(ses FeSession, execCtx *ExecCtx, st *tree.AlterDataBaseConfig) error { 1342 return doAlterAccountConfig(execCtx.reqCtx, ses.(*Session), st) 1343 } 1344 1345 // handleCreateUser creates the user for the tenant 1346 func handleCreateUser(ses FeSession, execCtx *ExecCtx, st *tree.CreateUser) error { 1347 tenant := ses.GetTenantInfo() 1348 1349 cu := &createUser{ 1350 IfNotExists: st.IfNotExists, 1351 Role: st.Role, 1352 Users: make([]*user, 0, len(st.Users)), 1353 MiscOpt: st.MiscOpt, 1354 CommentOrAttribute: st.CommentOrAttribute, 1355 } 1356 1357 for _, u := range st.Users { 1358 v := user{ 1359 Username: u.Username, 1360 Hostname: u.Hostname, 1361 } 1362 if u.AuthOption != nil { 1363 v.AuthExist = true 1364 v.IdentTyp = u.AuthOption.Typ 1365 switch v.IdentTyp { 1366 case tree.AccountIdentifiedByPassword, 1367 tree.AccountIdentifiedWithSSL: 1368 var err error 1369 v.IdentStr, err = unboxExprStr(execCtx.reqCtx, u.AuthOption.Str) 1370 if err != nil { 1371 return err 1372 } 1373 } 1374 } 1375 cu.Users = append(cu.Users, &v) 1376 } 1377 1378 //step1 : create the user 1379 return InitUser(execCtx.reqCtx, ses.(*Session), tenant, cu) 1380 } 1381 1382 // handleDropUser drops the user for the tenant 1383 func handleDropUser(ses FeSession, execCtx *ExecCtx, du *tree.DropUser) error { 1384 return doDropUser(execCtx.reqCtx, ses.(*Session), du) 1385 } 1386 1387 func handleAlterUser(ses FeSession, execCtx *ExecCtx, st *tree.AlterUser) error { 1388 au := &alterUser{ 1389 IfExists: st.IfExists, 1390 Users: make([]*user, 0, len(st.Users)), 1391 Role: st.Role, 1392 MiscOpt: st.MiscOpt, 1393 1394 CommentOrAttribute: st.CommentOrAttribute, 1395 } 1396 1397 for _, su := range st.Users { 1398 u := &user{ 1399 Username: su.Username, 1400 Hostname: su.Hostname, 1401 } 1402 if su.AuthOption != nil { 1403 u.AuthExist = true 1404 u.IdentTyp = su.AuthOption.Typ 1405 switch u.IdentTyp { 1406 case tree.AccountIdentifiedByPassword, 1407 tree.AccountIdentifiedWithSSL: 1408 var err error 1409 u.IdentStr, err = unboxExprStr(execCtx.reqCtx, su.AuthOption.Str) 1410 if err != nil { 1411 return err 1412 } 1413 } 1414 } 1415 au.Users = append(au.Users, u) 1416 } 1417 return doAlterUser(execCtx.reqCtx, ses.(*Session), au) 1418 } 1419 1420 // handleCreateRole creates the new role 1421 func handleCreateRole(ses FeSession, execCtx *ExecCtx, cr *tree.CreateRole) error { 1422 tenant := ses.GetTenantInfo() 1423 1424 //step1 : create the role 1425 return InitRole(execCtx.reqCtx, ses.(*Session), tenant, cr) 1426 } 1427 1428 // handleDropRole drops the role 1429 func handleDropRole(ses FeSession, execCtx *ExecCtx, dr *tree.DropRole) error { 1430 return doDropRole(execCtx.reqCtx, ses.(*Session), dr) 1431 } 1432 1433 func handleCreateFunction(ses FeSession, execCtx *ExecCtx, cf *tree.CreateFunction) error { 1434 tenant := ses.GetTenantInfo() 1435 return InitFunction(ses.(*Session), execCtx, tenant, cf) 1436 } 1437 1438 func handleDropFunction(ses FeSession, execCtx *ExecCtx, df *tree.DropFunction, proc *process.Process) error { 1439 return doDropFunction(execCtx.reqCtx, ses.(*Session), df, func(path string) error { 1440 return proc.FileService.Delete(execCtx.reqCtx, path) 1441 }) 1442 } 1443 func handleCreateProcedure(ses FeSession, execCtx *ExecCtx, cp *tree.CreateProcedure) error { 1444 tenant := ses.GetTenantInfo() 1445 1446 return InitProcedure(execCtx.reqCtx, ses.(*Session), tenant, cp) 1447 } 1448 1449 func handleDropProcedure(ses FeSession, execCtx *ExecCtx, dp *tree.DropProcedure) error { 1450 return doDropProcedure(execCtx.reqCtx, ses.(*Session), dp) 1451 } 1452 1453 func handleCallProcedure(ses FeSession, execCtx *ExecCtx, call *tree.CallStmt, proc *process.Process) error { 1454 proto := ses.GetMysqlProtocol() 1455 results, err := doInterpretCall(execCtx.reqCtx, ses.(*Session), call) 1456 if err != nil { 1457 return err 1458 } 1459 1460 ses.SetMysqlResultSet(nil) 1461 1462 resp := NewGeneralOkResponse(COM_QUERY, ses.GetTxnHandler().GetServerStatus()) 1463 1464 if len(results) == 0 { 1465 if err := proto.SendResponse(execCtx.reqCtx, resp); err != nil { 1466 return moerr.NewInternalError(execCtx.reqCtx, "routine send response failed. error:%v ", err) 1467 } 1468 } else { 1469 for i, result := range results { 1470 mer := NewMysqlExecutionResult(0, 0, 0, 0, result.(*MysqlResultSet)) 1471 resp = ses.SetNewResponse(ResultResponse, 0, int(COM_QUERY), mer, i == len(results)-1) 1472 if err := proto.SendResponse(execCtx.reqCtx, resp); err != nil { 1473 return moerr.NewInternalError(execCtx.reqCtx, "routine send response failed. error:%v ", err) 1474 } 1475 } 1476 } 1477 return nil 1478 } 1479 1480 // handleGrantRole grants the role 1481 func handleGrantRole(ses FeSession, execCtx *ExecCtx, gr *tree.GrantRole) error { 1482 return doGrantRole(execCtx.reqCtx, ses.(*Session), gr) 1483 } 1484 1485 // handleRevokeRole revokes the role 1486 func handleRevokeRole(ses FeSession, execCtx *ExecCtx, rr *tree.RevokeRole) error { 1487 return doRevokeRole(execCtx.reqCtx, ses.(*Session), rr) 1488 } 1489 1490 // handleGrantRole grants the privilege to the role 1491 func handleGrantPrivilege(ses FeSession, execCtx *ExecCtx, gp *tree.GrantPrivilege) error { 1492 return doGrantPrivilege(execCtx.reqCtx, ses, gp) 1493 } 1494 1495 // handleRevokePrivilege revokes the privilege from the user or role 1496 func handleRevokePrivilege(ses FeSession, execCtx *ExecCtx, rp *tree.RevokePrivilege) error { 1497 return doRevokePrivilege(execCtx.reqCtx, ses, rp) 1498 } 1499 1500 // handleSwitchRole switches the role to another role 1501 func handleSwitchRole(ses FeSession, execCtx *ExecCtx, sr *tree.SetRole) error { 1502 return doSwitchRole(execCtx.reqCtx, ses.(*Session), sr) 1503 } 1504 1505 func doKill(ses *Session, execCtx *ExecCtx, k *tree.Kill) error { 1506 var err error 1507 //true: kill a connection 1508 //false: kill a query in a connection 1509 idThatKill := uint64(ses.GetConnectionID()) 1510 if !k.Option.Exist || k.Option.Typ == tree.KillTypeConnection { 1511 err = getGlobalRtMgr().kill(execCtx.reqCtx, true, idThatKill, k.ConnectionId, "") 1512 } else { 1513 err = getGlobalRtMgr().kill(execCtx.reqCtx, false, idThatKill, k.ConnectionId, k.StmtOption.StatementId) 1514 } 1515 return err 1516 } 1517 1518 // handleKill kill a connection or query 1519 func handleKill(ses *Session, execCtx *ExecCtx, k *tree.Kill) error { 1520 err := doKill(ses, execCtx, k) 1521 if err != nil { 1522 return err 1523 } 1524 return err 1525 } 1526 1527 // handleShowAccounts lists the info of accounts 1528 func handleShowAccounts(ses FeSession, execCtx *ExecCtx, sa *tree.ShowAccounts) error { 1529 err := doShowAccounts(execCtx.reqCtx, ses.(*Session), sa) 1530 if err != nil { 1531 return err 1532 } 1533 return err 1534 } 1535 1536 // handleShowCollation lists the info of collation 1537 func handleShowCollation(ses FeSession, execCtx *ExecCtx, sc *tree.ShowCollation) error { 1538 err := doShowCollation(ses.(*Session), execCtx, execCtx.proc, sc) 1539 if err != nil { 1540 return err 1541 } 1542 return err 1543 } 1544 1545 func doShowCollation(ses *Session, execCtx *ExecCtx, proc *process.Process, sc *tree.ShowCollation) error { 1546 var err error 1547 var bat *batch.Batch 1548 // var outputBatches []*batch.Batch 1549 1550 // Construct the columns. 1551 col1 := new(MysqlColumn) 1552 col1.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) 1553 col1.SetName("Collation") 1554 1555 col2 := new(MysqlColumn) 1556 col2.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) 1557 col2.SetName("Charset") 1558 1559 col3 := new(MysqlColumn) 1560 col3.SetColumnType(defines.MYSQL_TYPE_LONGLONG) 1561 col3.SetName("Id") 1562 1563 col4 := new(MysqlColumn) 1564 col4.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) 1565 col4.SetName("Default") 1566 1567 col5 := new(MysqlColumn) 1568 col5.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) 1569 col5.SetName("Compiled") 1570 1571 col6 := new(MysqlColumn) 1572 col6.SetColumnType(defines.MYSQL_TYPE_LONG) 1573 col6.SetName("Sortlen") 1574 1575 col7 := new(MysqlColumn) 1576 col7.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) 1577 col7.SetName("Pad_attribute") 1578 1579 mrs := ses.GetMysqlResultSet() 1580 mrs.AddColumn(col1) 1581 mrs.AddColumn(col2) 1582 mrs.AddColumn(col3) 1583 mrs.AddColumn(col4) 1584 mrs.AddColumn(col5) 1585 mrs.AddColumn(col6) 1586 mrs.AddColumn(col7) 1587 1588 var hasLike = false 1589 var likePattern = "" 1590 var isIlike = false 1591 if sc.Like != nil { 1592 hasLike = true 1593 if sc.Like.Op == tree.ILIKE { 1594 isIlike = true 1595 } 1596 likePattern = strings.ToLower(sc.Like.Right.String()) 1597 } 1598 1599 // Construct the rows. 1600 rows := make([][]interface{}, 0, len(Collations)) 1601 for _, collation := range Collations { 1602 if hasLike { 1603 s := collation.collationName 1604 if isIlike { 1605 s = strings.ToLower(s) 1606 } 1607 if !WildcardMatch(likePattern, s) { 1608 continue 1609 } 1610 } 1611 row := make([]interface{}, 7) 1612 row[0] = collation.collationName 1613 row[1] = collation.charset 1614 row[2] = collation.id 1615 row[3] = collation.isDefault 1616 row[4] = collation.isCompiled 1617 row[5] = collation.sortLen 1618 row[6] = collation.padAttribute 1619 rows = append(rows, row) 1620 } 1621 1622 bat, err = constructCollationBatch(ses, rows) 1623 defer bat.Clean(proc.Mp()) 1624 if err != nil { 1625 return err 1626 } 1627 1628 if sc.Where != nil { 1629 binder := plan2.NewDefaultBinder(execCtx.reqCtx, nil, nil, plan2.Type{Id: int32(types.T_varchar), Width: types.MaxVarcharLen}, []string{"collation", "charset", "id", "default", "compiled", "sortlen", "pad_attribute"}) 1630 planExpr, err := binder.BindExpr(sc.Where.Expr, 0, false) 1631 if err != nil { 1632 return err 1633 } 1634 1635 executor, err := colexec.NewExpressionExecutor(proc, planExpr) 1636 if err != nil { 1637 return err 1638 } 1639 vec, err := executor.Eval(proc, []*batch.Batch{bat}) 1640 if err != nil { 1641 executor.Free() 1642 return err 1643 } 1644 1645 bs := vector.MustFixedCol[bool](vec) 1646 sels := proc.Mp().GetSels() 1647 for i, b := range bs { 1648 if b { 1649 sels = append(sels, int64(i)) 1650 } 1651 } 1652 executor.Free() 1653 1654 bat.Shrink(sels, false) 1655 proc.Mp().PutSels(sels) 1656 v0 := vector.MustStrCol(bat.Vecs[0]) 1657 v1 := vector.MustStrCol(bat.Vecs[1]) 1658 v2 := vector.MustFixedCol[int64](bat.Vecs[2]) 1659 v3 := vector.MustStrCol(bat.Vecs[3]) 1660 v4 := vector.MustStrCol(bat.Vecs[4]) 1661 v5 := vector.MustFixedCol[int32](bat.Vecs[5]) 1662 v6 := vector.MustStrCol(bat.Vecs[6]) 1663 rows = rows[:len(v0)] 1664 for i := range v0 { 1665 rows[i][0] = v0[i] 1666 rows[i][1] = v1[i] 1667 rows[i][2] = v2[i] 1668 rows[i][3] = v3[i] 1669 rows[i][4] = v4[i] 1670 rows[i][5] = v5[i] 1671 rows[i][6] = v6[i] 1672 } 1673 } 1674 1675 //sort by name 1676 sort.Slice(rows, func(i, j int) bool { 1677 return rows[i][0].(string) < rows[j][0].(string) 1678 }) 1679 1680 for _, row := range rows { 1681 mrs.AddRow(row) 1682 } 1683 1684 // oq := newFakeOutputQueue(mrs) 1685 // if err = fillResultSet(oq, bat, ses); err != nil { 1686 // return err 1687 // } 1688 1689 ses.SetMysqlResultSet(mrs) 1690 ses.rs = mysqlColDef2PlanResultColDef(mrs) 1691 1692 // save query result 1693 if openSaveQueryResult(execCtx.reqCtx, ses) { 1694 if err := saveQueryResult(execCtx.reqCtx, ses, bat); err != nil { 1695 return err 1696 } 1697 if err := saveQueryResultMeta(execCtx.reqCtx, ses); err != nil { 1698 return err 1699 } 1700 } 1701 1702 return err 1703 } 1704 1705 func handleShowSubscriptions(ses FeSession, execCtx *ExecCtx, ss *tree.ShowSubscriptions) error { 1706 err := doShowSubscriptions(execCtx.reqCtx, ses.(*Session), ss) 1707 if err != nil { 1708 return err 1709 } 1710 return err 1711 } 1712 1713 func doShowBackendServers(ses *Session) error { 1714 // Construct the columns. 1715 col1 := new(MysqlColumn) 1716 col1.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 1717 col1.SetName("UUID") 1718 1719 col2 := new(MysqlColumn) 1720 col2.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 1721 col2.SetName("Address") 1722 1723 col3 := new(MysqlColumn) 1724 col3.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 1725 col3.SetName("Work State") 1726 1727 col4 := new(MysqlColumn) 1728 col4.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 1729 col4.SetName("Labels") 1730 1731 mrs := ses.GetMysqlResultSet() 1732 mrs.AddColumn(col1) 1733 mrs.AddColumn(col2) 1734 mrs.AddColumn(col3) 1735 mrs.AddColumn(col4) 1736 1737 var filterLabels = func(labels map[string]string) map[string]string { 1738 var reservedLabels = map[string]struct{}{ 1739 "os_user": {}, 1740 "os_sudouser": {}, 1741 "program_name": {}, 1742 } 1743 for k := range labels { 1744 if _, ok := reservedLabels[k]; ok || strings.HasPrefix(k, "_") { 1745 delete(labels, k) 1746 } 1747 } 1748 return labels 1749 } 1750 1751 var appendFn = func(s *metadata.CNService) { 1752 row := make([]interface{}, 4) 1753 row[0] = s.ServiceID 1754 row[1] = s.SQLAddress 1755 row[2] = s.WorkState.String() 1756 var labelStr string 1757 for key, value := range s.Labels { 1758 labelStr += fmt.Sprintf("%s:%s;", key, strings.Join(value.Labels, ",")) 1759 } 1760 row[3] = labelStr 1761 mrs.AddRow(row) 1762 } 1763 1764 tenant := ses.GetTenantInfo().GetTenant() 1765 var se clusterservice.Selector 1766 labels, err := ParseLabel(getLabelPart(ses.GetUserName())) 1767 if err != nil { 1768 return err 1769 } 1770 labels["account"] = tenant 1771 se = clusterservice.NewSelector().SelectByLabel( 1772 filterLabels(labels), clusterservice.Contain) 1773 if isSysTenant(tenant) { 1774 u := ses.GetTenantInfo().GetUser() 1775 // For super use dump and root, we should list all servers. 1776 if isSuperUser(u) { 1777 clusterservice.GetMOCluster().GetCNService( 1778 clusterservice.NewSelectAll(), func(s metadata.CNService) bool { 1779 appendFn(&s) 1780 return true 1781 }) 1782 } else { 1783 route.RouteForSuperTenant(se, u, nil, appendFn) 1784 } 1785 } else { 1786 route.RouteForCommonTenant(se, nil, appendFn) 1787 } 1788 return nil 1789 } 1790 1791 func handleShowBackendServers(ses FeSession, execCtx *ExecCtx) error { 1792 var err error 1793 if err := doShowBackendServers(ses.(*Session)); err != nil { 1794 return err 1795 } 1796 return err 1797 } 1798 1799 func handleEmptyStmt(ses FeSession, execCtx *ExecCtx, stmt *tree.EmptyStmt) error { 1800 var err error 1801 return err 1802 } 1803 1804 func GetExplainColumns(ctx context.Context, explainColName string) ([]interface{}, error) { 1805 cols := []*plan2.ColDef{ 1806 {Typ: plan2.Type{Id: int32(types.T_varchar)}, Name: explainColName}, 1807 } 1808 columns := make([]interface{}, len(cols)) 1809 var err error = nil 1810 for i, col := range cols { 1811 c := new(MysqlColumn) 1812 c.SetName(col.Name) 1813 err = convertEngineTypeToMysqlType(ctx, types.T(col.Typ.Id), c) 1814 if err != nil { 1815 return nil, err 1816 } 1817 columns[i] = c 1818 } 1819 return columns, err 1820 } 1821 1822 func getExplainOption(reqCtx context.Context, options []tree.OptionElem) (*explain.ExplainOptions, error) { 1823 es := explain.NewExplainDefaultOptions() 1824 if options == nil { 1825 return es, nil 1826 } else { 1827 for _, v := range options { 1828 if strings.EqualFold(v.Name, "VERBOSE") { 1829 if strings.EqualFold(v.Value, "TRUE") || v.Value == "NULL" { 1830 es.Verbose = true 1831 } else if strings.EqualFold(v.Value, "FALSE") { 1832 es.Verbose = false 1833 } else { 1834 return nil, moerr.NewInvalidInput(reqCtx, "invalid explain option '%s', valud '%s'", v.Name, v.Value) 1835 } 1836 } else if strings.EqualFold(v.Name, "ANALYZE") { 1837 if strings.EqualFold(v.Value, "TRUE") || v.Value == "NULL" { 1838 es.Analyze = true 1839 } else if strings.EqualFold(v.Value, "FALSE") { 1840 es.Analyze = false 1841 } else { 1842 return nil, moerr.NewInvalidInput(reqCtx, "invalid explain option '%s', valud '%s'", v.Name, v.Value) 1843 } 1844 } else if strings.EqualFold(v.Name, "FORMAT") { 1845 if strings.EqualFold(v.Value, "TEXT") { 1846 es.Format = explain.EXPLAIN_FORMAT_TEXT 1847 } else if strings.EqualFold(v.Value, "JSON") { 1848 return nil, moerr.NewNotSupported(reqCtx, "Unsupport explain format '%s'", v.Value) 1849 } else if strings.EqualFold(v.Value, "DOT") { 1850 return nil, moerr.NewNotSupported(reqCtx, "Unsupport explain format '%s'", v.Value) 1851 } else { 1852 return nil, moerr.NewInvalidInput(reqCtx, "invalid explain option '%s', valud '%s'", v.Name, v.Value) 1853 } 1854 } else { 1855 return nil, moerr.NewInvalidInput(reqCtx, "invalid explain option '%s', valud '%s'", v.Name, v.Value) 1856 } 1857 } 1858 return es, nil 1859 } 1860 } 1861 1862 func buildMoExplainQuery(execCtx *ExecCtx, explainColName string, buffer *explain.ExplainDataBuffer, session *Session, fill outputCallBackFunc) error { 1863 bat := batch.New(true, []string{explainColName}) 1864 rs := buffer.Lines 1865 vs := make([][]byte, len(rs)) 1866 1867 count := 0 1868 for _, r := range rs { 1869 str := []byte(r) 1870 vs[count] = str 1871 count++ 1872 } 1873 vs = vs[:count] 1874 vec := vector.NewVec(types.T_varchar.ToType()) 1875 defer vec.Free(session.GetMemPool()) 1876 vector.AppendBytesList(vec, vs, nil, session.GetMemPool()) 1877 bat.Vecs[0] = vec 1878 bat.SetRowCount(count) 1879 1880 err := fill(session, execCtx, bat) 1881 if err != nil { 1882 return err 1883 } 1884 // to trigger save result meta 1885 err = fill(session, execCtx, nil) 1886 return err 1887 } 1888 1889 func buildPlan(reqCtx context.Context, ses FeSession, ctx plan2.CompilerContext, stmt tree.Statement) (*plan2.Plan, error) { 1890 var ret *plan2.Plan 1891 var err error 1892 1893 txnOp := ctx.GetProcess().TxnOperator 1894 start := time.Now() 1895 seq := uint64(0) 1896 if txnOp != nil { 1897 seq = txnOp.NextSequence() 1898 txnTrace.GetService().AddTxnDurationAction( 1899 txnOp, 1900 client.BuildPlanEvent, 1901 seq, 1902 0, 1903 0, 1904 err) 1905 } 1906 1907 defer func() { 1908 cost := time.Since(start) 1909 1910 if txnOp != nil { 1911 txnTrace.GetService().AddTxnDurationAction( 1912 txnOp, 1913 client.BuildPlanEvent, 1914 seq, 1915 0, 1916 cost, 1917 err) 1918 } 1919 v2.TxnStatementBuildPlanDurationHistogram.Observe(cost.Seconds()) 1920 }() 1921 1922 stats := statistic.StatsInfoFromContext(reqCtx) 1923 stats.PlanStart() 1924 defer stats.PlanEnd() 1925 1926 isPrepareStmt := false 1927 if ses != nil { 1928 var accId uint32 1929 accId, err = defines.GetAccountId(reqCtx) 1930 if err != nil { 1931 return nil, err 1932 } 1933 ses.SetAccountId(accId) 1934 if len(ses.GetSql()) > 8 { 1935 prefix := strings.ToLower(ses.GetSql()[:8]) 1936 isPrepareStmt = prefix == "execute " || prefix == "prepare " 1937 } 1938 } 1939 if s, ok := stmt.(*tree.Insert); ok { 1940 if _, ok := s.Rows.Select.(*tree.ValuesClause); ok { 1941 ret, err = plan2.BuildPlan(ctx, stmt, isPrepareStmt) 1942 if err != nil { 1943 return nil, err 1944 } 1945 } 1946 } 1947 if ret != nil { 1948 if ses != nil && ses.GetTenantInfo() != nil && !ses.IsBackgroundSession() { 1949 err = authenticateCanExecuteStatementAndPlan(reqCtx, ses.(*Session), stmt, ret) 1950 if err != nil { 1951 return nil, err 1952 } 1953 } 1954 return ret, err 1955 } 1956 switch stmt := stmt.(type) { 1957 case *tree.Select, *tree.ParenSelect, *tree.ValuesStatement, 1958 *tree.Update, *tree.Delete, *tree.Insert, 1959 *tree.ShowDatabases, *tree.ShowTables, *tree.ShowSequences, *tree.ShowColumns, *tree.ShowColumnNumber, *tree.ShowTableNumber, 1960 *tree.ShowCreateDatabase, *tree.ShowCreateTable, *tree.ShowIndex, 1961 *tree.ExplainStmt, *tree.ExplainAnalyze: 1962 opt := plan2.NewBaseOptimizer(ctx) 1963 optimized, err := opt.Optimize(stmt, isPrepareStmt) 1964 if err != nil { 1965 return nil, err 1966 } 1967 ret = &plan2.Plan{ 1968 Plan: &plan2.Plan_Query{ 1969 Query: optimized, 1970 }, 1971 } 1972 default: 1973 ret, err = plan2.BuildPlan(ctx, stmt, isPrepareStmt) 1974 } 1975 if ret != nil { 1976 ret.IsPrepare = isPrepareStmt 1977 if ses != nil && ses.GetTenantInfo() != nil && !ses.IsBackgroundSession() { 1978 err = authenticateCanExecuteStatementAndPlan(reqCtx, ses.(*Session), stmt, ret) 1979 if err != nil { 1980 return nil, err 1981 } 1982 } 1983 } 1984 return ret, err 1985 } 1986 1987 func checkModify(plan0 *plan.Plan, ses FeSession) bool { 1988 if plan0 == nil { 1989 return true 1990 } 1991 checkFn := func(db string, tableName string, tableId uint64, version uint32) bool { 1992 _, tableDef := ses.GetTxnCompileCtx().Resolve(db, tableName, plan.Snapshot{TS: ×tamp.Timestamp{}}) 1993 if tableDef == nil { 1994 return true 1995 } 1996 if tableDef.Version != version || tableDef.TblId != tableId { 1997 return true 1998 } 1999 return false 2000 } 2001 switch p := plan0.Plan.(type) { 2002 case *plan.Plan_Query: 2003 for i := range p.Query.Nodes { 2004 if def := p.Query.Nodes[i].TableDef; def != nil { 2005 if p.Query.Nodes[i].ObjRef == nil || checkFn(p.Query.Nodes[i].ObjRef.SchemaName, def.Name, def.TblId, def.Version) { 2006 return true 2007 } 2008 } 2009 if ctx := p.Query.Nodes[i].InsertCtx; ctx != nil { 2010 if ctx.Ref == nil || checkFn(ctx.Ref.SchemaName, ctx.TableDef.Name, ctx.TableDef.TblId, ctx.TableDef.Version) { 2011 return true 2012 } 2013 } 2014 if ctx := p.Query.Nodes[i].ReplaceCtx; ctx != nil { 2015 if ctx.Ref == nil || checkFn(ctx.Ref.SchemaName, ctx.TableDef.Name, ctx.TableDef.TblId, ctx.TableDef.Version) { 2016 return true 2017 } 2018 } 2019 if ctx := p.Query.Nodes[i].DeleteCtx; ctx != nil { 2020 if ctx.Ref == nil || checkFn(ctx.Ref.SchemaName, ctx.TableDef.Name, ctx.TableDef.TblId, ctx.TableDef.Version) { 2021 return true 2022 } 2023 } 2024 if ctx := p.Query.Nodes[i].PreInsertCtx; ctx != nil { 2025 if ctx.Ref == nil || checkFn(ctx.Ref.SchemaName, ctx.TableDef.Name, ctx.TableDef.TblId, ctx.TableDef.Version) { 2026 return true 2027 } 2028 } 2029 if ctx := p.Query.Nodes[i].PreInsertCtx; ctx != nil { 2030 if ctx.Ref == nil || checkFn(ctx.Ref.SchemaName, ctx.TableDef.Name, ctx.TableDef.TblId, ctx.TableDef.Version) { 2031 return true 2032 } 2033 } 2034 if ctx := p.Query.Nodes[i].OnDuplicateKey; ctx != nil { 2035 if p.Query.Nodes[i].ObjRef == nil || checkFn(p.Query.Nodes[i].ObjRef.SchemaName, ctx.TableName, ctx.TableId, ctx.TableVersion) { 2036 return true 2037 } 2038 } 2039 } 2040 default: 2041 } 2042 return false 2043 } 2044 2045 var GetComputationWrapper = func(execCtx *ExecCtx, db string, user string, eng engine.Engine, proc *process.Process, ses *Session) ([]ComputationWrapper, error) { 2046 var cws []ComputationWrapper = nil 2047 if cached := ses.getCachedPlan(execCtx.input.getSql()); cached != nil { 2048 for i, stmt := range cached.stmts { 2049 tcw := InitTxnComputationWrapper(ses, stmt, proc) 2050 tcw.plan = cached.plans[i] 2051 cws = append(cws, tcw) 2052 } 2053 2054 return cws, nil 2055 } 2056 2057 var stmts []tree.Statement = nil 2058 var cmdFieldStmt *InternalCmdFieldList 2059 var err error 2060 // if the input is an option ast, we should use it directly 2061 if execCtx.input.getStmt() != nil { 2062 stmts = append(stmts, execCtx.input.getStmt()) 2063 } else if isCmdFieldListSql(execCtx.input.getSql()) { 2064 cmdFieldStmt, err = parseCmdFieldList(execCtx.reqCtx, execCtx.input.getSql()) 2065 if err != nil { 2066 return nil, err 2067 } 2068 stmts = append(stmts, cmdFieldStmt) 2069 } else { 2070 stmts, err = parseSql(execCtx) 2071 if err != nil { 2072 return nil, err 2073 } 2074 } 2075 2076 for _, stmt := range stmts { 2077 cws = append(cws, InitTxnComputationWrapper(ses, stmt, proc)) 2078 } 2079 return cws, nil 2080 } 2081 2082 func parseSql(execCtx *ExecCtx) (stmts []tree.Statement, err error) { 2083 var v interface{} 2084 var origin interface{} 2085 v, err = execCtx.ses.GetGlobalVar(execCtx.reqCtx, "lower_case_table_names") 2086 if err != nil { 2087 v = int64(1) 2088 } 2089 origin, err = execCtx.ses.GetGlobalVar(execCtx.reqCtx, "keep_user_target_list_in_result") 2090 if err != nil { 2091 origin = int64(0) 2092 } 2093 stmts, err = parsers.Parse(execCtx.reqCtx, dialect.MYSQL, execCtx.input.getSql(), v.(int64), origin.(int64)) 2094 if err != nil { 2095 return nil, err 2096 } 2097 return 2098 } 2099 2100 func incTransactionCounter(tenant string) { 2101 metric.TransactionCounter(tenant).Inc() 2102 } 2103 2104 func incTransactionErrorsCounter(tenant string, t metric.SQLType) { 2105 if t == metric.SQLTypeRollback { 2106 return 2107 } 2108 metric.TransactionErrorsCounter(tenant, t).Inc() 2109 } 2110 2111 func incStatementErrorsCounter(tenant string, stmt tree.Statement) { 2112 metric.StatementErrorsCounter(tenant, getStatementType(stmt).GetQueryType()).Inc() 2113 } 2114 2115 // authenticateUserCanExecuteStatement checks the user can execute the statement 2116 func authenticateUserCanExecuteStatement(reqCtx context.Context, ses *Session, stmt tree.Statement) error { 2117 reqCtx, span := trace.Debug(reqCtx, "authenticateUserCanExecuteStatement") 2118 defer span.End() 2119 if getGlobalPu().SV.SkipCheckPrivilege { 2120 return nil 2121 } 2122 2123 if ses.skipAuthForSpecialUser() { 2124 return nil 2125 } 2126 var havePrivilege bool 2127 var err error 2128 if ses.GetTenantInfo() != nil { 2129 ses.SetPrivilege(determinePrivilegeSetOfStatement(stmt)) 2130 2131 // can or not execute in retricted status 2132 if ses.getRoutine() != nil && ses.getRoutine().isRestricted() && !ses.GetPrivilege().canExecInRestricted { 2133 return moerr.NewInternalError(reqCtx, "do not have privilege to execute the statement") 2134 } 2135 2136 havePrivilege, err = authenticateUserCanExecuteStatementWithObjectTypeAccountAndDatabase(reqCtx, ses, stmt) 2137 if err != nil { 2138 return err 2139 } 2140 2141 if !havePrivilege { 2142 err = moerr.NewInternalError(reqCtx, "do not have privilege to execute the statement") 2143 return err 2144 } 2145 2146 havePrivilege, err = authenticateUserCanExecuteStatementWithObjectTypeNone(reqCtx, ses, stmt) 2147 if err != nil { 2148 return err 2149 } 2150 2151 if !havePrivilege { 2152 err = moerr.NewInternalError(reqCtx, "do not have privilege to execute the statement") 2153 return err 2154 } 2155 } 2156 return err 2157 } 2158 2159 // authenticateCanExecuteStatementAndPlan checks the user can execute the statement and its plan 2160 func authenticateCanExecuteStatementAndPlan(reqCtx context.Context, ses *Session, stmt tree.Statement, p *plan.Plan) error { 2161 _, task := gotrace.NewTask(reqCtx, "frontend.authenticateCanExecuteStatementAndPlan") 2162 defer task.End() 2163 if getGlobalPu().SV.SkipCheckPrivilege { 2164 return nil 2165 } 2166 2167 if ses.skipAuthForSpecialUser() { 2168 return nil 2169 } 2170 yes, err := authenticateUserCanExecuteStatementWithObjectTypeDatabaseAndTable(reqCtx, ses, stmt, p) 2171 if err != nil { 2172 return err 2173 } 2174 if !yes { 2175 return moerr.NewInternalError(reqCtx, "do not have privilege to execute the statement") 2176 } 2177 return nil 2178 } 2179 2180 // authenticatePrivilegeOfPrepareAndExecute checks the user can execute the Prepare or Execute statement 2181 func authenticateUserCanExecutePrepareOrExecute(reqCtx context.Context, ses *Session, stmt tree.Statement, p *plan.Plan) error { 2182 _, task := gotrace.NewTask(reqCtx, "frontend.authenticateUserCanExecutePrepareOrExecute") 2183 defer task.End() 2184 if getGlobalPu().SV.SkipCheckPrivilege { 2185 return nil 2186 } 2187 err := authenticateUserCanExecuteStatement(reqCtx, ses, stmt) 2188 if err != nil { 2189 return err 2190 } 2191 err = authenticateCanExecuteStatementAndPlan(reqCtx, ses, stmt, p) 2192 if err != nil { 2193 return err 2194 } 2195 return err 2196 } 2197 2198 // canExecuteStatementInUncommittedTxn checks the user can execute the statement in an uncommitted transaction 2199 func canExecuteStatementInUncommittedTransaction(reqCtx context.Context, ses FeSession, stmt tree.Statement) error { 2200 can, err := statementCanBeExecutedInUncommittedTransaction(reqCtx, ses, stmt) 2201 if err != nil { 2202 return err 2203 } 2204 if !can { 2205 //is ddl statement 2206 if IsCreateDropDatabase(stmt) { 2207 return moerr.NewInternalError(reqCtx, createDropDatabaseErrorInfo()) 2208 } else if IsDDL(stmt) { 2209 return moerr.NewInternalError(reqCtx, onlyCreateStatementErrorInfo()) 2210 } else if IsAdministrativeStatement(stmt) { 2211 return moerr.NewInternalError(reqCtx, administrativeCommandIsUnsupportedInTxnErrorInfo()) 2212 } else { 2213 return moerr.NewInternalError(reqCtx, unclassifiedStatementInUncommittedTxnErrorInfo()) 2214 } 2215 } 2216 return nil 2217 } 2218 2219 func processLoadLocal(ses FeSession, execCtx *ExecCtx, param *tree.ExternParam, writer *io.PipeWriter) (err error) { 2220 proto := ses.GetMysqlProtocol() 2221 defer func() { 2222 err2 := writer.Close() 2223 if err == nil { 2224 err = err2 2225 } 2226 }() 2227 err = plan2.InitInfileParam(param) 2228 if err != nil { 2229 return 2230 } 2231 err = proto.sendLocalInfileRequest(param.Filepath) 2232 if err != nil { 2233 return 2234 } 2235 start := time.Now() 2236 var msg interface{} 2237 msg, err = proto.GetTcpConnection().Read(goetty.ReadOptions{}) 2238 if err != nil { 2239 proto.SetSequenceID(proto.GetSequenceId() + 1) 2240 if errors.Is(err, errorInvalidLength0) { 2241 return nil 2242 } 2243 if moerr.IsMoErrCode(err, moerr.ErrInvalidInput) { 2244 err = moerr.NewInvalidInput(execCtx.reqCtx, "cannot read '%s' from client,please check the file path, user privilege and if client start with --local-infile", param.Filepath) 2245 } 2246 return 2247 } 2248 2249 packet, ok := msg.(*Packet) 2250 if !ok { 2251 proto.SetSequenceID(proto.GetSequenceId() + 1) 2252 err = moerr.NewInvalidInput(execCtx.reqCtx, "invalid packet") 2253 return 2254 } 2255 2256 proto.SetSequenceID(uint8(packet.SequenceID + 1)) 2257 seq := uint8(packet.SequenceID + 1) 2258 length := packet.Length 2259 if length == 0 { 2260 return 2261 } 2262 ses.CountPayload(len(packet.Payload)) 2263 2264 skipWrite := false 2265 // If inner error occurs(unexpected or expected(ctrl-c)), proc.LoadLocalReader will be closed. 2266 // Then write will return error, but we need to read the rest of the data and not write it to pipe. 2267 // So we need a flag[skipWrite] to tell us whether we need to write the data to pipe. 2268 // https://github.com/matrixorigin/matrixone/issues/6665#issuecomment-1422236478 2269 2270 _, err = writer.Write(packet.Payload) 2271 if err != nil { 2272 skipWrite = true // next, we just need read the rest of the data,no need to write it to pipe. 2273 logError(ses, ses.GetDebugString(), 2274 "Failed to load local file", 2275 zap.String("path", param.Filepath), 2276 zap.Error(err)) 2277 } 2278 epoch, printEvery, minReadTime, maxReadTime, minWriteTime, maxWriteTime := uint64(0), uint64(1024), 24*time.Hour, time.Nanosecond, 24*time.Hour, time.Nanosecond 2279 for { 2280 readStart := time.Now() 2281 msg, err = proto.GetTcpConnection().Read(goetty.ReadOptions{}) 2282 if err != nil { 2283 if moerr.IsMoErrCode(err, moerr.ErrInvalidInput) { 2284 seq += 1 2285 proto.SetSequenceID(seq) 2286 err = nil 2287 } 2288 break 2289 } 2290 readTime := time.Since(readStart) 2291 if readTime > maxReadTime { 2292 maxReadTime = readTime 2293 } 2294 if readTime < minReadTime { 2295 minReadTime = readTime 2296 } 2297 packet, ok = msg.(*Packet) 2298 if !ok { 2299 err = moerr.NewInvalidInput(execCtx.reqCtx, "invalid packet") 2300 seq += 1 2301 proto.SetSequenceID(seq) 2302 break 2303 } 2304 seq = uint8(packet.SequenceID + 1) 2305 proto.SetSequenceID(seq) 2306 ses.CountPayload(len(packet.Payload)) 2307 2308 writeStart := time.Now() 2309 if !skipWrite { 2310 _, err = writer.Write(packet.Payload) 2311 if err != nil { 2312 logError(ses, ses.GetDebugString(), 2313 "Failed to load local file", 2314 zap.String("path", param.Filepath), 2315 zap.Uint64("epoch", epoch), 2316 zap.Error(err)) 2317 skipWrite = true 2318 } 2319 writeTime := time.Since(writeStart) 2320 if writeTime > maxWriteTime { 2321 maxWriteTime = writeTime 2322 } 2323 if writeTime < minWriteTime { 2324 minWriteTime = writeTime 2325 } 2326 } 2327 if epoch%printEvery == 0 { 2328 logDebugf(ses.GetDebugString(), "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()) 2329 minReadTime, maxReadTime, minWriteTime, maxWriteTime = 24*time.Hour, time.Nanosecond, 24*time.Hour, time.Nanosecond 2330 } 2331 epoch += 1 2332 } 2333 logDebugf(ses.GetDebugString(), "load local '%s', read&write all data from client cost: %s", param.Filepath, time.Since(start)) 2334 return 2335 } 2336 2337 func executeStmtWithResponse(ses *Session, 2338 execCtx *ExecCtx, 2339 ) (err error) { 2340 var span trace.Span 2341 execCtx.reqCtx, span = trace.Start(execCtx.reqCtx, "executeStmtWithResponse", 2342 trace.WithKind(trace.SpanKindStatement)) 2343 defer span.End(trace.WithStatementExtra(ses.GetTxnId(), ses.GetStmtId(), ses.GetSqlOfStmt())) 2344 2345 ses.SetQueryInProgress(true) 2346 ses.SetQueryStart(time.Now()) 2347 ses.SetQueryInExecute(true) 2348 defer ses.SetQueryEnd(time.Now()) 2349 defer ses.SetQueryInProgress(false) 2350 2351 err = executeStmtWithTxn(ses, execCtx) 2352 if err != nil { 2353 return err 2354 } 2355 2356 // TODO put in one txn 2357 // insert data after create table in "create table ... as select ..." stmt 2358 if ses.createAsSelectSql != "" { 2359 sql := ses.createAsSelectSql 2360 ses.createAsSelectSql = "" 2361 tempExecCtx := ExecCtx{ 2362 ses: ses, 2363 reqCtx: execCtx.reqCtx, 2364 } 2365 if err = doComQuery(ses, &tempExecCtx, &UserInput{sql: sql}); err != nil { 2366 return err 2367 } 2368 } 2369 2370 err = respClientWhenSuccess(ses, execCtx) 2371 if err != nil { 2372 return err 2373 } 2374 2375 return 2376 } 2377 2378 func executeStmtWithTxn(ses FeSession, 2379 execCtx *ExecCtx, 2380 ) (err error) { 2381 if !ses.IsDerivedStmt() { 2382 err = executeStmtWithWorkspace(ses, execCtx) 2383 } else { 2384 2385 txnOp := ses.GetTxnHandler().GetTxn() 2386 //refresh proc txnOp 2387 execCtx.proc.TxnOperator = txnOp 2388 2389 err = dispatchStmt(ses, execCtx) 2390 } 2391 return 2392 } 2393 2394 func executeStmtWithWorkspace(ses FeSession, 2395 execCtx *ExecCtx, 2396 ) (err error) { 2397 if ses.IsDerivedStmt() { 2398 return 2399 } 2400 var autocommit bool 2401 //derived stmt shares the same txn with ancestor. 2402 //it only executes select statements. 2403 2404 //7. pass or commit or rollback txn 2405 // defer transaction state management. 2406 defer func() { 2407 err = finishTxnFunc(ses, err, execCtx) 2408 }() 2409 2410 //1. start txn 2411 //special BEGIN,COMMIT,ROLLBACK 2412 beginStmt := false 2413 switch execCtx.stmt.(type) { 2414 case *tree.BeginTransaction: 2415 execCtx.txnOpt.byBegin = true 2416 beginStmt = true 2417 case *tree.CommitTransaction: 2418 execCtx.txnOpt.byCommit = true 2419 return nil 2420 case *tree.RollbackTransaction: 2421 execCtx.txnOpt.byRollback = true 2422 return nil 2423 } 2424 2425 autocommit, err = autocommitValue(execCtx.reqCtx, ses) 2426 if err != nil { 2427 return err 2428 } 2429 2430 execCtx.txnOpt.autoCommit = autocommit 2431 err = ses.GetTxnHandler().Create(execCtx) 2432 if err != nil { 2433 return err 2434 } 2435 2436 //skip BEGIN stmt 2437 if beginStmt { 2438 return err 2439 } 2440 2441 if ses.GetTxnHandler() == nil { 2442 panic("need txn handler") 2443 } 2444 2445 txnOp := ses.GetTxnHandler().GetTxn() 2446 2447 //refresh proc txnOp 2448 execCtx.proc.TxnOperator = txnOp 2449 2450 //!!!NOTE!!!: statement management 2451 //2. start statement on workspace 2452 txnOp.GetWorkspace().StartStatement() 2453 //3. end statement on workspace 2454 // defer Start/End Statement management, called after finishTxnFunc() 2455 defer func() { 2456 if ses.GetTxnHandler() == nil { 2457 panic("need txn handler 2") 2458 } 2459 2460 txnOp = ses.GetTxnHandler().GetTxn() 2461 if txnOp != nil { 2462 //most of the cases, txnOp will not nil except that "set autocommit = 1" 2463 //commit the txn immediately then the txnOp is nil. 2464 txnOp.GetWorkspace().EndStatement() 2465 } 2466 }() 2467 2468 err = executeStmtWithIncrStmt(ses, execCtx, txnOp) 2469 2470 return 2471 } 2472 2473 func executeStmtWithIncrStmt(ses FeSession, 2474 execCtx *ExecCtx, 2475 txnOp TxnOperator, 2476 ) (err error) { 2477 if ses.IsDerivedStmt() { 2478 return 2479 } 2480 //3. increase statement id 2481 err = txnOp.GetWorkspace().IncrStatementID(execCtx.reqCtx, false) 2482 if err != nil { 2483 return err 2484 } 2485 2486 defer func() { 2487 if ses.GetTxnHandler() == nil { 2488 panic("need txn handler 3") 2489 } 2490 2491 //!!!NOTE!!!: it does not work 2492 //_, txnOp = ses.GetTxnHandler().GetTxn() 2493 //if txnOp != nil { 2494 // err = rollbackLastStmt(execCtx, txnOp, err) 2495 //} 2496 }() 2497 2498 err = dispatchStmt(ses, execCtx) 2499 return 2500 } 2501 2502 func dispatchStmt(ses FeSession, 2503 execCtx *ExecCtx) (err error) { 2504 //5. check plan within txn 2505 if execCtx.cw.Plan() != nil { 2506 if checkModify(execCtx.cw.Plan(), ses) { 2507 2508 //plan changed 2509 //clear all cached plan and parse sql again 2510 var stmts []tree.Statement 2511 stmts, err = parseSql(execCtx) 2512 if err != nil { 2513 return err 2514 } 2515 if len(stmts) != len(execCtx.cws) { 2516 return moerr.NewInternalError(execCtx.reqCtx, "the count of stmts parsed from cached sql is not equal to cws length") 2517 } 2518 for i, cw := range execCtx.cws { 2519 cw.ResetPlanAndStmt(stmts[i]) 2520 } 2521 } 2522 } 2523 2524 //6. execute stmt within txn 2525 switch sesImpl := ses.(type) { 2526 case *Session: 2527 return executeStmt(sesImpl, execCtx) 2528 case *backSession: 2529 return executeStmtInBack(sesImpl, execCtx) 2530 default: 2531 return moerr.NewInternalError(execCtx.reqCtx, "no such session implementation") 2532 } 2533 } 2534 2535 func executeStmt(ses *Session, 2536 execCtx *ExecCtx, 2537 ) (err error) { 2538 if txw, ok := execCtx.cw.(*TxnComputationWrapper); ok { 2539 ses.GetTxnCompileCtx().tcw = txw 2540 } 2541 2542 // record goroutine info when ddl stmt run timeout 2543 switch execCtx.stmt.(type) { 2544 case *tree.CreateTable, *tree.DropTable, *tree.CreateDatabase, *tree.DropDatabase: 2545 _, span := trace.Start(execCtx.reqCtx, "executeStmtHung", 2546 trace.WithHungThreshold(time.Minute), // be careful with this options 2547 trace.WithProfileGoroutine(), 2548 trace.WithProfileTraceSecs(10*time.Second), 2549 ) 2550 defer span.End() 2551 default: 2552 } 2553 2554 var cmpBegin time.Time 2555 var ret interface{} 2556 2557 switch execCtx.stmt.StmtKind().ExecLocation() { 2558 case tree.EXEC_IN_FRONTEND: 2559 return execInFrontend(ses, execCtx) 2560 case tree.EXEC_IN_ENGINE: 2561 //in the computation engine 2562 } 2563 2564 switch st := execCtx.stmt.(type) { 2565 case *tree.Select: 2566 if st.Ep != nil { 2567 if getGlobalPu().SV.DisableSelectInto { 2568 err = moerr.NewSyntaxError(execCtx.reqCtx, "Unsupport select statement") 2569 return 2570 } 2571 ses.InitExportConfig(st.Ep) 2572 defer func() { 2573 ses.ClearExportParam() 2574 }() 2575 err = doCheckFilePath(execCtx.reqCtx, ses, st.Ep) 2576 if err != nil { 2577 return 2578 } 2579 } 2580 case *tree.CreateDatabase: 2581 err = inputNameIsInvalid(execCtx.reqCtx, string(st.Name)) 2582 if err != nil { 2583 return 2584 } 2585 if st.SubscriptionOption != nil && ses.GetTenantInfo() != nil && !ses.GetTenantInfo().IsAdminRole() { 2586 err = moerr.NewInternalError(execCtx.reqCtx, "only admin can create subscription") 2587 return 2588 } 2589 st.Sql = execCtx.sqlOfStmt 2590 case *tree.DropDatabase: 2591 err = inputNameIsInvalid(execCtx.reqCtx, string(st.Name)) 2592 if err != nil { 2593 return 2594 } 2595 ses.InvalidatePrivilegeCache() 2596 // if the droped database is the same as the one in use, database must be reseted to empty. 2597 if string(st.Name) == ses.GetDatabaseName() { 2598 ses.SetDatabaseName("") 2599 } 2600 case *tree.ExplainAnalyze: 2601 ses.SetData(nil) 2602 case *tree.ShowTableStatus: 2603 ses.SetShowStmtType(ShowTableStatus) 2604 ses.SetData(nil) 2605 case *tree.Load: 2606 if st.Local { 2607 execCtx.proc.LoadLocalReader, execCtx.loadLocalWriter = io.Pipe() 2608 } 2609 case *tree.ShowGrants: 2610 if len(st.Username) == 0 { 2611 st.Username = execCtx.userName 2612 } 2613 if len(st.Hostname) == 0 || st.Hostname == "%" { 2614 st.Hostname = rootHost 2615 } 2616 } 2617 2618 defer func() { 2619 // Serialize the execution plan as json 2620 if cwft, ok := execCtx.cw.(*TxnComputationWrapper); ok { 2621 _ = cwft.RecordExecPlan(execCtx.reqCtx) 2622 } 2623 }() 2624 2625 cmpBegin = time.Now() 2626 2627 if ret, err = execCtx.cw.Compile(execCtx, ses.GetOutputCallback(execCtx)); err != nil { 2628 return 2629 } 2630 2631 defer func() { 2632 if c, ok := ret.(*compile.Compile); ok { 2633 c.Release() 2634 } 2635 }() 2636 2637 // cw.Compile may rewrite the stmt in the EXECUTE statement, we fetch the latest version 2638 //need to check again. 2639 execCtx.stmt = execCtx.cw.GetAst() 2640 switch execCtx.stmt.StmtKind().ExecLocation() { 2641 case tree.EXEC_IN_FRONTEND: 2642 return execInFrontend(ses, execCtx) 2643 case tree.EXEC_IN_ENGINE: 2644 2645 } 2646 2647 execCtx.runner = ret.(ComputationRunner) 2648 2649 // only log if build time is longer than 1s 2650 if time.Since(cmpBegin) > time.Second { 2651 logInfo(ses, ses.GetDebugString(), fmt.Sprintf("time of Exec.Build : %s", time.Since(cmpBegin).String())) 2652 } 2653 2654 //output result & status 2655 StmtKind := execCtx.stmt.StmtKind().OutputType() 2656 switch StmtKind { 2657 case tree.OUTPUT_RESULT_ROW: 2658 err = executeResultRowStmt(ses, execCtx) 2659 if err != nil { 2660 return err 2661 } 2662 case tree.OUTPUT_STATUS: 2663 err = executeStatusStmt(ses, execCtx) 2664 if err != nil { 2665 return err 2666 } 2667 case tree.OUTPUT_UNDEFINED: 2668 if _, ok := execCtx.stmt.(*tree.Execute); !ok { 2669 return moerr.NewInternalError(execCtx.reqCtx, "need set result type for %s", execCtx.sqlOfStmt) 2670 } 2671 } 2672 2673 return 2674 } 2675 2676 // execute query 2677 func doComQuery(ses *Session, execCtx *ExecCtx, input *UserInput) (retErr error) { 2678 ses.GetTxnCompileCtx().SetExecCtx(execCtx) 2679 // set the batch buf for stream scan 2680 var inMemStreamScan []*kafka.Message 2681 2682 if batchValue, ok := execCtx.reqCtx.Value(defines.SourceScanResKey{}).([]*kafka.Message); ok { 2683 inMemStreamScan = batchValue 2684 } 2685 2686 beginInstant := time.Now() 2687 execCtx.reqCtx = appendStatementAt(execCtx.reqCtx, beginInstant) 2688 input.genSqlSourceType(ses) 2689 ses.SetShowStmtType(NotShowStatement) 2690 proto := ses.GetMysqlProtocol() 2691 ses.SetSql(input.getSql()) 2692 2693 //the ses.GetUserName returns the user_name with the account_name. 2694 //here,we only need the user_name. 2695 userNameOnly := rootName 2696 2697 proc := ses.proc 2698 proc.Ctx = execCtx.reqCtx 2699 2700 proc.CopyVectorPool(ses.proc) 2701 proc.CopyValueScanBatch(ses.proc) 2702 proc.Id = ses.getNextProcessId() 2703 proc.Lim.Size = getGlobalPu().SV.ProcessLimitationSize 2704 proc.Lim.BatchRows = getGlobalPu().SV.ProcessLimitationBatchRows 2705 proc.Lim.MaxMsgSize = getGlobalPu().SV.MaxMessageSize 2706 proc.Lim.PartitionRows = getGlobalPu().SV.ProcessLimitationPartitionRows 2707 proc.SessionInfo = process.SessionInfo{ 2708 User: ses.GetUserName(), 2709 Host: getGlobalPu().SV.Host, 2710 ConnectionID: uint64(proto.ConnectionID()), 2711 Database: ses.GetDatabaseName(), 2712 Version: makeServerVersion(getGlobalPu(), serverVersion.Load().(string)), 2713 TimeZone: ses.GetTimeZone(), 2714 StorageEngine: getGlobalPu().StorageEngine, 2715 LastInsertID: ses.GetLastInsertID(), 2716 SqlHelper: ses.GetSqlHelper(), 2717 Buf: ses.GetBuffer(), 2718 SourceInMemScanBatch: inMemStreamScan, 2719 } 2720 proc.SetResolveVariableFunc(ses.txnCompileCtx.ResolveVariable) 2721 proc.InitSeq() 2722 // Copy curvalues stored in session to this proc. 2723 // Deep copy the map, takes some memory. 2724 ses.CopySeqToProc(proc) 2725 if ses.GetTenantInfo() != nil { 2726 proc.SessionInfo.Account = ses.GetTenantInfo().GetTenant() 2727 proc.SessionInfo.AccountId = ses.GetTenantInfo().GetTenantID() 2728 proc.SessionInfo.Role = ses.GetTenantInfo().GetDefaultRole() 2729 proc.SessionInfo.RoleId = ses.GetTenantInfo().GetDefaultRoleID() 2730 proc.SessionInfo.UserId = ses.GetTenantInfo().GetUserID() 2731 2732 if len(ses.GetTenantInfo().GetVersion()) != 0 { 2733 proc.SessionInfo.Version = ses.GetTenantInfo().GetVersion() 2734 } 2735 userNameOnly = ses.GetTenantInfo().GetUser() 2736 } else { 2737 var accountId uint32 2738 accountId, retErr = defines.GetAccountId(execCtx.reqCtx) 2739 if retErr != nil { 2740 return retErr 2741 } 2742 proc.SessionInfo.AccountId = accountId 2743 proc.SessionInfo.UserId = defines.GetUserId(execCtx.reqCtx) 2744 proc.SessionInfo.RoleId = defines.GetRoleId(execCtx.reqCtx) 2745 } 2746 var span trace.Span 2747 execCtx.reqCtx, span = trace.Start(execCtx.reqCtx, "doComQuery", 2748 trace.WithKind(trace.SpanKindStatement)) 2749 defer span.End() 2750 2751 proc.SessionInfo.User = userNameOnly 2752 proc.SessionInfo.QueryId = ses.getQueryId(input.isInternal()) 2753 2754 statsInfo := statistic.StatsInfo{ParseStartTime: beginInstant} 2755 execCtx.reqCtx = statistic.ContextWithStatsInfo(execCtx.reqCtx, &statsInfo) 2756 execCtx.input = input 2757 2758 cws, err := GetComputationWrapper(execCtx, ses.GetDatabaseName(), 2759 ses.GetUserName(), 2760 getGlobalPu().StorageEngine, 2761 proc, ses) 2762 2763 ParseDuration := time.Since(beginInstant) 2764 2765 if err != nil { 2766 statsInfo.ParseDuration = ParseDuration 2767 var err2 error 2768 execCtx.reqCtx, err2 = RecordParseErrorStatement(execCtx.reqCtx, ses, proc, beginInstant, parsers.HandleSqlForRecord(input.getSql()), input.getSqlSourceTypes(), err) 2769 if err2 != nil { 2770 return err2 2771 } 2772 retErr = err 2773 if _, ok := err.(*moerr.Error); !ok { 2774 retErr = moerr.NewParseError(execCtx.reqCtx, err.Error()) 2775 } 2776 logStatementStringStatus(execCtx.reqCtx, ses, input.getSql(), fail, retErr) 2777 return retErr 2778 } 2779 2780 singleStatement := len(cws) == 1 2781 if ses.GetCmd() == COM_STMT_PREPARE && !singleStatement { 2782 return moerr.NewNotSupported(execCtx.reqCtx, "prepare multi statements") 2783 } 2784 2785 defer func() { 2786 ses.SetMysqlResultSet(nil) 2787 }() 2788 2789 canCache := true 2790 Cached := false 2791 defer func() { 2792 execCtx.stmt = nil 2793 execCtx.cw = nil 2794 execCtx.cws = nil 2795 if !Cached { 2796 for i := 0; i < len(cws); i++ { 2797 cws[i].Free() 2798 } 2799 } 2800 }() 2801 sqlRecord := parsers.HandleSqlForRecord(input.getSql()) 2802 2803 for i, cw := range cws { 2804 if cwft, ok := cw.(*TxnComputationWrapper); ok { 2805 if cwft.stmt.GetQueryType() == tree.QueryTypeDDL || cwft.stmt.GetQueryType() == tree.QueryTypeDCL || 2806 cwft.stmt.GetQueryType() == tree.QueryTypeOth || 2807 cwft.stmt.GetQueryType() == tree.QueryTypeTCL { 2808 if _, ok := cwft.stmt.(*tree.SetVar); !ok { 2809 ses.cleanCache() 2810 } 2811 canCache = false 2812 } 2813 } 2814 2815 ses.SetMysqlResultSet(&MysqlResultSet{}) 2816 ses.sentRows.Store(int64(0)) 2817 ses.writeCsvBytes.Store(int64(0)) 2818 proto.ResetStatistics() // move from getDataFromPipeline, for record column fields' data 2819 stmt := cw.GetAst() 2820 sqlType := input.getSqlSourceType(i) 2821 var err2 error 2822 execCtx.reqCtx, err2 = RecordStatement(execCtx.reqCtx, ses, proc, cw, beginInstant, sqlRecord[i], sqlType, singleStatement) 2823 if err2 != nil { 2824 return err2 2825 } 2826 2827 statsInfo.Reset() 2828 //average parse duration 2829 statsInfo.ParseDuration = time.Duration(ParseDuration.Nanoseconds() / int64(len(cws))) 2830 2831 tenant := ses.GetTenantNameWithStmt(stmt) 2832 //skip PREPARE statement here 2833 if ses.GetTenantInfo() != nil && !IsPrepareStatement(stmt) { 2834 err = authenticateUserCanExecuteStatement(execCtx.reqCtx, ses, stmt) 2835 if err != nil { 2836 logStatementStatus(execCtx.reqCtx, ses, stmt, fail, err) 2837 return err 2838 } 2839 } 2840 2841 /* 2842 if it is in an active or multi-statement transaction, we check the type of the statement. 2843 Then we decide that if we can execute the statement. 2844 2845 If we check the active transaction, it will generate the case below. 2846 case: 2847 set autocommit = 0; <- no active transaction 2848 <- no active transaction 2849 drop table test1; <- no active transaction, no error 2850 <- has active transaction 2851 drop table test1; <- has active transaction, error 2852 <- has active transaction 2853 */ 2854 if ses.GetTxnHandler().InActiveTxn() { 2855 err = canExecuteStatementInUncommittedTransaction(execCtx.reqCtx, ses, stmt) 2856 if err != nil { 2857 logStatementStatus(execCtx.reqCtx, ses, stmt, fail, err) 2858 return err 2859 } 2860 } 2861 2862 // update UnixTime for new query, which is used for now() / CURRENT_TIMESTAMP 2863 proc.UnixTime = time.Now().UnixNano() 2864 if ses.proc != nil { 2865 ses.proc.UnixTime = proc.UnixTime 2866 } 2867 execCtx.stmt = stmt 2868 execCtx.isLastStmt = i >= len(cws)-1 2869 execCtx.tenant = tenant 2870 execCtx.userName = userNameOnly 2871 execCtx.sqlOfStmt = sqlRecord[i] 2872 execCtx.cw = cw 2873 execCtx.proc = proc 2874 execCtx.proto = proto 2875 execCtx.ses = ses 2876 execCtx.cws = cws 2877 execCtx.input = input 2878 2879 err = executeStmtWithResponse(ses, execCtx) 2880 if err != nil { 2881 return err 2882 } 2883 2884 } // end of for 2885 2886 if canCache && !ses.isCached(input.getSql()) { 2887 plans := make([]*plan.Plan, len(cws)) 2888 stmts := make([]tree.Statement, len(cws)) 2889 for i, cw := range cws { 2890 if cwft, ok := cw.(*TxnComputationWrapper); ok { 2891 if checkNodeCanCache(cwft.plan) { 2892 plans[i] = cwft.plan 2893 stmts[i] = cwft.stmt 2894 } else { 2895 return nil 2896 } 2897 } 2898 cw.Clear() 2899 } 2900 Cached = true 2901 ses.cachePlan(input.getSql(), stmts, plans) 2902 } 2903 2904 return nil 2905 } 2906 2907 func checkNodeCanCache(p *plan2.Plan) bool { 2908 if p == nil { 2909 return true 2910 } 2911 if q, ok := p.Plan.(*plan2.Plan_Query); ok { 2912 for _, node := range q.Query.Nodes { 2913 if node.NotCacheable { 2914 return false 2915 } 2916 if node.ObjRef != nil && len(node.ObjRef.SubscriptionName) > 0 { 2917 return false 2918 } 2919 } 2920 } 2921 return true 2922 } 2923 2924 // ExecRequest the server execute the commands from the client following the mysql's routine 2925 func ExecRequest(ses *Session, execCtx *ExecCtx, req *Request) (resp *Response, err error) { 2926 defer func() { 2927 if e := recover(); e != nil { 2928 moe, ok := e.(*moerr.Error) 2929 if !ok { 2930 err = moerr.ConvertPanicError(execCtx.reqCtx, e) 2931 resp = NewGeneralErrorResponse(COM_QUERY, ses.txnHandler.GetServerStatus(), err) 2932 } else { 2933 resp = NewGeneralErrorResponse(COM_QUERY, ses.txnHandler.GetServerStatus(), moe) 2934 } 2935 } 2936 }() 2937 2938 var span trace.Span 2939 execCtx.reqCtx, span = trace.Start(execCtx.reqCtx, "ExecRequest", 2940 trace.WithKind(trace.SpanKindStatement)) 2941 defer span.End() 2942 2943 var sql string 2944 logDebugf(ses.GetDebugString(), "cmd %v", req.GetCmd()) 2945 ses.SetCmd(req.GetCmd()) 2946 switch req.GetCmd() { 2947 case COM_QUIT: 2948 return resp, moerr.GetMysqlClientQuit() 2949 case COM_QUERY: 2950 var query = string(req.GetData().([]byte)) 2951 ses.addSqlCount(1) 2952 logDebug(ses, ses.GetDebugString(), "query trace", logutil.ConnectionIdField(ses.GetConnectionID()), logutil.QueryField(SubStringFromBegin(query, int(getGlobalPu().SV.LengthOfQueryPrinted)))) 2953 err = doComQuery(ses, execCtx, &UserInput{sql: query}) 2954 if err != nil { 2955 resp = NewGeneralErrorResponse(COM_QUERY, ses.GetTxnHandler().GetServerStatus(), err) 2956 } 2957 return resp, nil 2958 case COM_INIT_DB: 2959 var dbname = string(req.GetData().([]byte)) 2960 ses.addSqlCount(1) 2961 query := "use `" + dbname + "`" 2962 err = doComQuery(ses, execCtx, &UserInput{sql: query}) 2963 if err != nil { 2964 resp = NewGeneralErrorResponse(COM_INIT_DB, ses.GetTxnHandler().GetServerStatus(), err) 2965 } 2966 2967 return resp, nil 2968 case COM_FIELD_LIST: 2969 var payload = string(req.GetData().([]byte)) 2970 ses.addSqlCount(1) 2971 query := makeCmdFieldListSql(payload) 2972 err = doComQuery(ses, execCtx, &UserInput{sql: query}) 2973 if err != nil { 2974 resp = NewGeneralErrorResponse(COM_FIELD_LIST, ses.GetTxnHandler().GetServerStatus(), err) 2975 } 2976 2977 return resp, nil 2978 case COM_PING: 2979 resp = NewGeneralOkResponse(COM_PING, ses.GetTxnHandler().GetServerStatus()) 2980 2981 return resp, nil 2982 2983 case COM_STMT_PREPARE: 2984 ses.SetCmd(COM_STMT_PREPARE) 2985 sql = string(req.GetData().([]byte)) 2986 ses.addSqlCount(1) 2987 2988 // rewrite to "Prepare stmt_name from 'xxx'" 2989 newLastStmtID := ses.GenNewStmtId() 2990 newStmtName := getPrepareStmtName(newLastStmtID) 2991 sql = fmt.Sprintf("prepare %s from %s", newStmtName, sql) 2992 logDebug(ses, ses.GetDebugString(), "query trace", logutil.ConnectionIdField(ses.GetConnectionID()), logutil.QueryField(sql)) 2993 2994 err = doComQuery(ses, execCtx, &UserInput{sql: sql}) 2995 if err != nil { 2996 resp = NewGeneralErrorResponse(COM_STMT_PREPARE, ses.GetTxnHandler().GetServerStatus(), err) 2997 } 2998 return resp, nil 2999 3000 case COM_STMT_EXECUTE: 3001 ses.SetCmd(COM_STMT_EXECUTE) 3002 data := req.GetData().([]byte) 3003 var prepareStmt *PrepareStmt 3004 sql, prepareStmt, err = parseStmtExecute(execCtx.reqCtx, ses, data) 3005 if err != nil { 3006 return NewGeneralErrorResponse(COM_STMT_EXECUTE, ses.GetTxnHandler().GetServerStatus(), err), nil 3007 } 3008 err = doComQuery(ses, execCtx, &UserInput{sql: sql}) 3009 if err != nil { 3010 resp = NewGeneralErrorResponse(COM_STMT_EXECUTE, ses.GetTxnHandler().GetServerStatus(), err) 3011 } 3012 if prepareStmt.params != nil { 3013 prepareStmt.params.GetNulls().Reset() 3014 for k := range prepareStmt.getFromSendLongData { 3015 delete(prepareStmt.getFromSendLongData, k) 3016 } 3017 } 3018 return resp, nil 3019 3020 case COM_STMT_SEND_LONG_DATA: 3021 ses.SetCmd(COM_STMT_SEND_LONG_DATA) 3022 data := req.GetData().([]byte) 3023 err = parseStmtSendLongData(execCtx.reqCtx, ses, data) 3024 if err != nil { 3025 resp = NewGeneralErrorResponse(COM_STMT_SEND_LONG_DATA, ses.GetTxnHandler().GetServerStatus(), err) 3026 return resp, nil 3027 } 3028 return nil, nil 3029 3030 case COM_STMT_CLOSE: 3031 data := req.GetData().([]byte) 3032 3033 // rewrite to "deallocate Prepare stmt_name" 3034 stmtID := binary.LittleEndian.Uint32(data[0:4]) 3035 stmtName := getPrepareStmtName(stmtID) 3036 sql = fmt.Sprintf("deallocate prepare %s", stmtName) 3037 logDebug(ses, ses.GetDebugString(), "query trace", logutil.ConnectionIdField(ses.GetConnectionID()), logutil.QueryField(sql)) 3038 3039 err = doComQuery(ses, execCtx, &UserInput{sql: sql}) 3040 if err != nil { 3041 resp = NewGeneralErrorResponse(COM_STMT_CLOSE, ses.GetTxnHandler().GetServerStatus(), err) 3042 } 3043 return resp, nil 3044 3045 case COM_STMT_RESET: 3046 data := req.GetData().([]byte) 3047 3048 //Payload of COM_STMT_RESET 3049 stmtID := binary.LittleEndian.Uint32(data[0:4]) 3050 stmtName := getPrepareStmtName(stmtID) 3051 sql = fmt.Sprintf("reset prepare %s", stmtName) 3052 logDebug(ses, ses.GetDebugString(), "query trace", logutil.ConnectionIdField(ses.GetConnectionID()), logutil.QueryField(sql)) 3053 err = doComQuery(ses, execCtx, &UserInput{sql: sql}) 3054 if err != nil { 3055 resp = NewGeneralErrorResponse(COM_STMT_RESET, ses.GetTxnHandler().GetServerStatus(), err) 3056 } 3057 return resp, nil 3058 3059 case COM_SET_OPTION: 3060 data := req.GetData().([]byte) 3061 err := handleSetOption(ses, execCtx, data) 3062 if err != nil { 3063 resp = NewGeneralErrorResponse(COM_SET_OPTION, ses.GetTxnHandler().GetServerStatus(), err) 3064 } 3065 return NewGeneralOkResponse(COM_SET_OPTION, ses.GetTxnHandler().GetServerStatus()), nil 3066 3067 default: 3068 resp = NewGeneralErrorResponse(req.GetCmd(), ses.GetTxnHandler().GetServerStatus(), moerr.NewInternalError(execCtx.reqCtx, "unsupported command. 0x%x", req.GetCmd())) 3069 } 3070 return resp, nil 3071 } 3072 3073 func parseStmtExecute(reqCtx context.Context, ses *Session, data []byte) (string, *PrepareStmt, error) { 3074 // see https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_stmt_execute.html 3075 pos := 0 3076 if len(data) < 4 { 3077 return "", nil, moerr.NewInvalidInput(reqCtx, "sql command contains malformed packet") 3078 } 3079 stmtID := binary.LittleEndian.Uint32(data[0:4]) 3080 pos += 4 3081 3082 stmtName := fmt.Sprintf("%s_%d", prefixPrepareStmtName, stmtID) 3083 preStmt, err := ses.GetPrepareStmt(reqCtx, stmtName) 3084 if err != nil { 3085 return "", nil, err 3086 } 3087 3088 sql := fmt.Sprintf("execute %s", stmtName) 3089 logDebug(ses, ses.GetDebugString(), "query trace", logutil.ConnectionIdField(ses.GetConnectionID()), logutil.QueryField(sql)) 3090 err = ses.GetMysqlProtocol().ParseExecuteData(reqCtx, ses.GetTxnCompileCtx().GetProcess(), preStmt, data, pos) 3091 if err != nil { 3092 return "", nil, err 3093 } 3094 return sql, preStmt, nil 3095 } 3096 3097 func parseStmtSendLongData(reqCtx context.Context, ses *Session, data []byte) error { 3098 // see https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_stmt_send_long_data.html 3099 pos := 0 3100 if len(data) < 4 { 3101 return moerr.NewInvalidInput(reqCtx, "sql command contains malformed packet") 3102 } 3103 stmtID := binary.LittleEndian.Uint32(data[0:4]) 3104 pos += 4 3105 3106 stmtName := fmt.Sprintf("%s_%d", prefixPrepareStmtName, stmtID) 3107 preStmt, err := ses.GetPrepareStmt(reqCtx, stmtName) 3108 if err != nil { 3109 return err 3110 } 3111 3112 sql := fmt.Sprintf("send long data for stmt %s", stmtName) 3113 logDebug(ses, ses.GetDebugString(), "query trace", logutil.ConnectionIdField(ses.GetConnectionID()), logutil.QueryField(sql)) 3114 3115 err = ses.GetMysqlProtocol().ParseSendLongData(reqCtx, ses.GetTxnCompileCtx().GetProcess(), preStmt, data, pos) 3116 if err != nil { 3117 return err 3118 } 3119 return nil 3120 } 3121 3122 /* 3123 convert the type in computation engine to the type in mysql. 3124 */ 3125 func convertEngineTypeToMysqlType(ctx context.Context, engineType types.T, col *MysqlColumn) error { 3126 switch engineType { 3127 case types.T_any: 3128 col.SetColumnType(defines.MYSQL_TYPE_NULL) 3129 case types.T_json: 3130 col.SetColumnType(defines.MYSQL_TYPE_JSON) 3131 case types.T_bool: 3132 col.SetColumnType(defines.MYSQL_TYPE_BOOL) 3133 case types.T_bit: 3134 col.SetColumnType(defines.MYSQL_TYPE_BIT) 3135 col.SetSigned(false) 3136 case types.T_int8: 3137 col.SetColumnType(defines.MYSQL_TYPE_TINY) 3138 case types.T_uint8: 3139 col.SetColumnType(defines.MYSQL_TYPE_TINY) 3140 col.SetSigned(false) 3141 case types.T_int16: 3142 col.SetColumnType(defines.MYSQL_TYPE_SHORT) 3143 case types.T_uint16: 3144 col.SetColumnType(defines.MYSQL_TYPE_SHORT) 3145 col.SetSigned(false) 3146 case types.T_int32: 3147 col.SetColumnType(defines.MYSQL_TYPE_LONG) 3148 case types.T_uint32: 3149 col.SetColumnType(defines.MYSQL_TYPE_LONG) 3150 col.SetSigned(false) 3151 case types.T_int64: 3152 col.SetColumnType(defines.MYSQL_TYPE_LONGLONG) 3153 case types.T_uint64: 3154 col.SetColumnType(defines.MYSQL_TYPE_LONGLONG) 3155 col.SetSigned(false) 3156 case types.T_float32: 3157 col.SetColumnType(defines.MYSQL_TYPE_FLOAT) 3158 case types.T_float64: 3159 col.SetColumnType(defines.MYSQL_TYPE_DOUBLE) 3160 case types.T_char: 3161 col.SetColumnType(defines.MYSQL_TYPE_STRING) 3162 case types.T_varchar: 3163 col.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) 3164 case types.T_array_float32, types.T_array_float64: 3165 col.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 3166 case types.T_binary: 3167 col.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 3168 case types.T_varbinary: 3169 col.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 3170 case types.T_date: 3171 col.SetColumnType(defines.MYSQL_TYPE_DATE) 3172 case types.T_datetime: 3173 col.SetColumnType(defines.MYSQL_TYPE_DATETIME) 3174 case types.T_time: 3175 col.SetColumnType(defines.MYSQL_TYPE_TIME) 3176 case types.T_timestamp: 3177 col.SetColumnType(defines.MYSQL_TYPE_TIMESTAMP) 3178 case types.T_decimal64: 3179 col.SetColumnType(defines.MYSQL_TYPE_DECIMAL) 3180 case types.T_decimal128: 3181 col.SetColumnType(defines.MYSQL_TYPE_DECIMAL) 3182 case types.T_blob: 3183 col.SetColumnType(defines.MYSQL_TYPE_BLOB) 3184 case types.T_text: 3185 col.SetColumnType(defines.MYSQL_TYPE_TEXT) 3186 case types.T_uuid: 3187 col.SetColumnType(defines.MYSQL_TYPE_UUID) 3188 case types.T_TS: 3189 col.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 3190 case types.T_Blockid: 3191 col.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 3192 case types.T_enum: 3193 col.SetColumnType(defines.MYSQL_TYPE_VARCHAR) 3194 default: 3195 return moerr.NewInternalError(ctx, "RunWhileSend : unsupported type %d", engineType) 3196 } 3197 return nil 3198 } 3199 3200 func convertMysqlTextTypeToBlobType(col *MysqlColumn) { 3201 if col.ColumnType() == defines.MYSQL_TYPE_TEXT { 3202 col.SetColumnType(defines.MYSQL_TYPE_BLOB) 3203 } 3204 } 3205 3206 // build plan json when marhal plan error 3207 func buildErrorJsonPlan(buffer *bytes.Buffer, uuid uuid.UUID, errcode uint16, msg string) []byte { 3208 var bytes [36]byte 3209 util.EncodeUUIDHex(bytes[:], uuid[:]) 3210 explainData := explain.ExplainData{ 3211 Code: errcode, 3212 Message: msg, 3213 Uuid: util.UnsafeBytesToString(bytes[:]), 3214 } 3215 encoder := json.NewEncoder(buffer) 3216 encoder.SetEscapeHTML(false) 3217 encoder.Encode(explainData) 3218 return buffer.Bytes() 3219 } 3220 3221 type jsonPlanHandler struct { 3222 jsonBytes []byte 3223 statsBytes statistic.StatsArray 3224 stats motrace.Statistic 3225 buffer *bytes.Buffer 3226 } 3227 3228 func NewJsonPlanHandler(ctx context.Context, stmt *motrace.StatementInfo, plan *plan2.Plan, opts ...marshalPlanOptions) *jsonPlanHandler { 3229 h := NewMarshalPlanHandler(ctx, stmt, plan, opts...) 3230 jsonBytes := h.Marshal(ctx) 3231 statsBytes, stats := h.Stats(ctx) 3232 return &jsonPlanHandler{ 3233 jsonBytes: jsonBytes, 3234 statsBytes: statsBytes, 3235 stats: stats, 3236 buffer: h.handoverBuffer(), 3237 } 3238 } 3239 3240 func (h *jsonPlanHandler) Stats(ctx context.Context) (statistic.StatsArray, motrace.Statistic) { 3241 return h.statsBytes, h.stats 3242 } 3243 3244 func (h *jsonPlanHandler) Marshal(ctx context.Context) []byte { 3245 return h.jsonBytes 3246 } 3247 3248 func (h *jsonPlanHandler) Free() { 3249 if h.buffer != nil { 3250 releaseMarshalPlanBufferPool(h.buffer) 3251 h.buffer = nil 3252 h.jsonBytes = nil 3253 } 3254 } 3255 3256 type marshalPlanConfig struct { 3257 waitActiveCost time.Duration 3258 } 3259 3260 type marshalPlanOptions func(*marshalPlanConfig) 3261 3262 func WithWaitActiveCost(cost time.Duration) marshalPlanOptions { 3263 return func(h *marshalPlanConfig) { 3264 h.waitActiveCost = cost 3265 } 3266 } 3267 3268 type marshalPlanHandler struct { 3269 query *plan.Query 3270 marshalPlan *explain.ExplainData 3271 stmt *motrace.StatementInfo 3272 uuid uuid.UUID 3273 buffer *bytes.Buffer 3274 3275 marshalPlanConfig 3276 } 3277 3278 func NewMarshalPlanHandler(ctx context.Context, stmt *motrace.StatementInfo, plan *plan2.Plan, opts ...marshalPlanOptions) *marshalPlanHandler { 3279 // TODO: need mem improvement 3280 uuid := uuid.UUID(stmt.StatementID) 3281 stmt.MarkResponseAt() 3282 if plan == nil || plan.GetQuery() == nil { 3283 return &marshalPlanHandler{ 3284 query: nil, 3285 marshalPlan: nil, 3286 stmt: stmt, 3287 uuid: uuid, 3288 buffer: nil, 3289 } 3290 } 3291 query := plan.GetQuery() 3292 h := &marshalPlanHandler{ 3293 query: query, 3294 stmt: stmt, 3295 uuid: uuid, 3296 buffer: nil, 3297 } 3298 // END> new marshalPlanHandler 3299 3300 // SET options 3301 for _, opt := range opts { 3302 opt(&h.marshalPlanConfig) 3303 } 3304 3305 if h.needMarshalPlan() { 3306 h.marshalPlan = explain.BuildJsonPlan(ctx, h.uuid, &explain.MarshalPlanOptions, h.query) 3307 h.marshalPlan.NewPlanStats.SetWaitActiveCost(h.waitActiveCost) 3308 } 3309 return h 3310 } 3311 3312 // needMarshalPlan return true if statement.duration - waitActive > longQueryTime && NOT mo_logger query 3313 // check longQueryTime, need after StatementInfo.MarkResponseAt 3314 // MoLogger NOT record ExecPlan 3315 func (h *marshalPlanHandler) needMarshalPlan() bool { 3316 return (h.stmt.Duration-h.waitActiveCost) > motrace.GetLongQueryTime() && 3317 !h.stmt.IsMoLogger() 3318 } 3319 3320 func (h *marshalPlanHandler) Free() { 3321 h.stmt = nil 3322 if h.buffer != nil { 3323 releaseMarshalPlanBufferPool(h.buffer) 3324 h.buffer = nil 3325 } 3326 } 3327 3328 func (h *marshalPlanHandler) handoverBuffer() *bytes.Buffer { 3329 b := h.buffer 3330 h.buffer = nil 3331 return b 3332 } 3333 3334 var marshalPlanBufferPool = sync.Pool{New: func() any { 3335 return bytes.NewBuffer(make([]byte, 0, 8192)) 3336 }} 3337 3338 // get buffer from marshalPlanBufferPool 3339 func getMarshalPlanBufferPool() *bytes.Buffer { 3340 return marshalPlanBufferPool.Get().(*bytes.Buffer) 3341 } 3342 3343 func releaseMarshalPlanBufferPool(b *bytes.Buffer) { 3344 marshalPlanBufferPool.Put(b) 3345 } 3346 3347 // allocBufferIfNeeded should call just right before needed. 3348 // It will reuse buffer from pool if possible. 3349 func (h *marshalPlanHandler) allocBufferIfNeeded() { 3350 if h.buffer == nil { 3351 h.buffer = getMarshalPlanBufferPool() 3352 } 3353 } 3354 3355 func (h *marshalPlanHandler) Marshal(ctx context.Context) (jsonBytes []byte) { 3356 var err error 3357 if h.marshalPlan != nil { 3358 h.allocBufferIfNeeded() 3359 h.buffer.Reset() 3360 var jsonBytesLen = 0 3361 // XXX, `buffer` can be used repeatedly as a global variable in the future 3362 // Provide a relatively balanced initial capacity [8192] for byte slice to prevent multiple memory requests 3363 encoder := json.NewEncoder(h.buffer) 3364 encoder.SetEscapeHTML(false) 3365 err = encoder.Encode(h.marshalPlan) 3366 if err != nil { 3367 moError := moerr.NewInternalError(ctx, "serialize plan to json error: %s", err.Error()) 3368 h.buffer.Reset() 3369 jsonBytes = buildErrorJsonPlan(h.buffer, h.uuid, moError.ErrorCode(), moError.Error()) 3370 } else { 3371 jsonBytesLen = h.buffer.Len() 3372 } 3373 // BG: bytes.Buffer maintain buf []byte. 3374 // if buf[off:] not enough but len(buf) is enough place, then it will reset off = 0. 3375 // So, in here, we need call Next(...) after all data has been written 3376 if jsonBytesLen > 0 { 3377 jsonBytes = h.buffer.Next(jsonBytesLen) 3378 } 3379 } else if h.query != nil { 3380 // DO NOT use h.buffer 3381 return sqlQueryIgnoreExecPlan 3382 } else { 3383 // DO NOT use h.buffer 3384 return sqlQueryNoRecordExecPlan 3385 } 3386 return 3387 } 3388 3389 var sqlQueryIgnoreExecPlan = []byte(`{}`) 3390 var sqlQueryNoRecordExecPlan = []byte(`{"code":200,"message":"sql query no record execution plan"}`) 3391 3392 func (h *marshalPlanHandler) Stats(ctx context.Context) (statsByte statistic.StatsArray, stats motrace.Statistic) { 3393 if h.query != nil { 3394 options := &explain.MarshalPlanOptions 3395 statsByte.Reset() 3396 for _, node := range h.query.Nodes { 3397 // part 1: for statistic.StatsArray 3398 s := explain.GetStatistic4Trace(ctx, node, options) 3399 statsByte.Add(&s) 3400 // part 2: for motrace.Statistic 3401 if node.NodeType == plan.Node_TABLE_SCAN || node.NodeType == plan.Node_EXTERNAL_SCAN { 3402 rows, bytes := explain.GetInputRowsAndInputSize(ctx, node, options) 3403 stats.RowsRead += rows 3404 stats.BytesScan += bytes 3405 } 3406 } 3407 } else { 3408 statsByte = statistic.DefaultStatsArray 3409 } 3410 statsInfo := statistic.StatsInfoFromContext(ctx) 3411 if statsInfo != nil { 3412 val := int64(statsByte.GetTimeConsumed()) + 3413 int64(statsInfo.ParseDuration+ 3414 statsInfo.CompileDuration+ 3415 statsInfo.PlanDuration) - (statsInfo.IOAccessTimeConsumption + statsInfo.IOMergerTimeConsumption()) 3416 if val < 0 { 3417 logutil.Warnf(" negative cpu (%s) + statsInfo(%d + %d + %d - %d - %d) = %d", 3418 uuid.UUID(h.stmt.StatementID).String(), 3419 statsInfo.ParseDuration, 3420 statsInfo.CompileDuration, 3421 statsInfo.PlanDuration, 3422 statsInfo.IOAccessTimeConsumption, 3423 statsInfo.IOMergerTimeConsumption(), 3424 val) 3425 v2.GetTraceNegativeCUCounter("cpu").Inc() 3426 } else { 3427 statsByte.WithTimeConsumed(float64(val)) 3428 } 3429 } 3430 3431 return 3432 } 3433 3434 func handleSetOption(ses *Session, execCtx *ExecCtx, data []byte) (err error) { 3435 if len(data) < 2 { 3436 return moerr.NewInternalError(execCtx.reqCtx, "invalid cmd_set_option data length") 3437 } 3438 cap := ses.GetMysqlProtocol().GetCapability() 3439 switch binary.LittleEndian.Uint16(data[:2]) { 3440 case 0: 3441 // MO do not support CLIENT_MULTI_STATEMENTS in prepare, so do nothing here(Like MySQL) 3442 // cap |= CLIENT_MULTI_STATEMENTS 3443 // GetSession().GetMysqlProtocol().SetCapability(cap) 3444 3445 case 1: 3446 cap &^= CLIENT_MULTI_STATEMENTS 3447 ses.GetMysqlProtocol().SetCapability(cap) 3448 3449 default: 3450 return moerr.NewInternalError(execCtx.reqCtx, "invalid cmd_set_option data") 3451 } 3452 3453 return nil 3454 } 3455 3456 func handleExecUpgrade(ses *Session, execCtx *ExecCtx, st *tree.UpgradeStatement) error { 3457 retryCount := st.Retry 3458 if st.Retry <= 0 { 3459 retryCount = 1 3460 } 3461 err := ses.UpgradeTenant(execCtx.reqCtx, st.Target.AccountName, uint32(retryCount), st.Target.IsALLAccount) 3462 if err != nil { 3463 return err 3464 } 3465 3466 return nil 3467 }