github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/interlock/show.go (about) 1 // Copyright 2020 WHTCORPS INC, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package interlock 15 16 import ( 17 "bytes" 18 "context" 19 gjson "encoding/json" 20 "fmt" 21 "sort" 22 "strconv" 23 "strings" 24 "time" 25 26 "github.com/cznic/mathutil" 27 "github.com/whtcorpsinc/BerolinaSQL" 28 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 29 "github.com/whtcorpsinc/BerolinaSQL/ast" 30 "github.com/whtcorpsinc/BerolinaSQL/auth" 31 "github.com/whtcorpsinc/BerolinaSQL/charset" 32 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 33 "github.com/whtcorpsinc/BerolinaSQL/terror" 34 "github.com/whtcorpsinc/errors" 35 "github.com/whtcorpsinc/milevadb-tools/milevadb-binlog/node" 36 "github.com/whtcorpsinc/milevadb-tools/pkg/etcd" 37 "github.com/whtcorpsinc/milevadb-tools/pkg/utils" 38 "github.com/whtcorpsinc/milevadb/bindinfo" 39 "github.com/whtcorpsinc/milevadb/causet" 40 "github.com/whtcorpsinc/milevadb/causet/blocks" 41 causetembedded "github.com/whtcorpsinc/milevadb/causet/embedded" 42 "github.com/whtcorpsinc/milevadb/causetstore/einsteindb" 43 "github.com/whtcorpsinc/milevadb/config" 44 "github.com/whtcorpsinc/milevadb/dbs" 45 "github.com/whtcorpsinc/milevadb/ekv" 46 "github.com/whtcorpsinc/milevadb/memex" 47 "github.com/whtcorpsinc/milevadb/petri" 48 "github.com/whtcorpsinc/milevadb/plugin" 49 "github.com/whtcorpsinc/milevadb/privilege" 50 "github.com/whtcorpsinc/milevadb/privilege/privileges" 51 "github.com/whtcorpsinc/milevadb/schemareplicant" 52 "github.com/whtcorpsinc/milevadb/soliton" 53 "github.com/whtcorpsinc/milevadb/soliton/chunk" 54 "github.com/whtcorpsinc/milevadb/soliton/defCauslate" 55 "github.com/whtcorpsinc/milevadb/soliton/format" 56 "github.com/whtcorpsinc/milevadb/soliton/hint" 57 "github.com/whtcorpsinc/milevadb/soliton/replog" 58 "github.com/whtcorpsinc/milevadb/soliton/set" 59 "github.com/whtcorpsinc/milevadb/soliton/sqlexec" 60 "github.com/whtcorpsinc/milevadb/soliton/stringutil" 61 "github.com/whtcorpsinc/milevadb/spacetime/autoid" 62 "github.com/whtcorpsinc/milevadb/stochastikctx" 63 "github.com/whtcorpsinc/milevadb/stochastikctx/stmtctx" 64 "github.com/whtcorpsinc/milevadb/stochastikctx/variable" 65 "github.com/whtcorpsinc/milevadb/types" 66 "github.com/whtcorpsinc/milevadb/types/json" 67 ) 68 69 var etcdDialTimeout = 5 * time.Second 70 71 // ShowInterDirc represents a show interlock. 72 type ShowInterDirc struct { 73 baseInterlockingDirectorate 74 75 Tp ast.ShowStmtType // Databases/Blocks/DeferredCausets/.... 76 DBName perceptron.CIStr 77 Block *ast.BlockName // Used for showing defCausumns. 78 DeferredCauset *ast.DeferredCausetName // Used for `desc causet defCausumn`. 79 IndexName perceptron.CIStr // Used for show causet regions. 80 Flag int // Some flag parsed from allegrosql, such as FULL. 81 Roles []*auth.RoleIdentity // Used for show grants. 82 User *auth.UserIdentity // Used by show grants, show create user. 83 84 is schemareplicant.SchemaReplicant 85 86 result *chunk.Chunk 87 cursor int 88 89 Full bool 90 IfNotExists bool // Used for `show create database if not exists` 91 GlobalScope bool // GlobalScope is used by show variables 92 Extended bool // Used for `show extended defCausumns from ...` 93 } 94 95 // Next implements the InterlockingDirectorate Next interface. 96 func (e *ShowInterDirc) Next(ctx context.Context, req *chunk.Chunk) error { 97 req.GrowAndReset(e.maxChunkSize) 98 if e.result == nil { 99 e.result = newFirstChunk(e) 100 err := e.fetchAll(ctx) 101 if err != nil { 102 return errors.Trace(err) 103 } 104 iter := chunk.NewIterator4Chunk(e.result) 105 for defCausIdx := 0; defCausIdx < e.Schema().Len(); defCausIdx++ { 106 retType := e.Schema().DeferredCausets[defCausIdx].RetType 107 if !types.IsTypeVarchar(retType.Tp) { 108 continue 109 } 110 for event := iter.Begin(); event != iter.End(); event = iter.Next() { 111 if valLen := len(event.GetString(defCausIdx)); retType.Flen < valLen { 112 retType.Flen = valLen 113 } 114 } 115 } 116 } 117 if e.cursor >= e.result.NumEvents() { 118 return nil 119 } 120 numCurBatch := mathutil.Min(req.Capacity(), e.result.NumEvents()-e.cursor) 121 req.Append(e.result, e.cursor, e.cursor+numCurBatch) 122 e.cursor += numCurBatch 123 return nil 124 } 125 126 func (e *ShowInterDirc) fetchAll(ctx context.Context) error { 127 switch e.Tp { 128 case ast.ShowCharset: 129 return e.fetchShowCharset() 130 case ast.ShowDefCauslation: 131 return e.fetchShowDefCauslation() 132 case ast.ShowDeferredCausets: 133 return e.fetchShowDeferredCausets(ctx) 134 case ast.ShowConfig: 135 return e.fetchShowClusterConfigs(ctx) 136 case ast.ShowCreateBlock: 137 return e.fetchShowCreateBlock() 138 case ast.ShowCreateSequence: 139 return e.fetchShowCreateSequence() 140 case ast.ShowCreateUser: 141 return e.fetchShowCreateUser() 142 case ast.ShowCreateView: 143 return e.fetchShowCreateView() 144 case ast.ShowCreateDatabase: 145 return e.fetchShowCreateDatabase() 146 case ast.ShowDatabases: 147 return e.fetchShowDatabases() 148 case ast.ShowDrainerStatus: 149 return e.fetchShowPumpOrDrainerStatus(node.DrainerNode) 150 case ast.ShowEngines: 151 return e.fetchShowEngines() 152 case ast.ShowGrants: 153 return e.fetchShowGrants() 154 case ast.ShowIndex: 155 return e.fetchShowIndex() 156 case ast.ShowProcedureStatus: 157 return e.fetchShowProcedureStatus() 158 case ast.ShowPumpStatus: 159 return e.fetchShowPumpOrDrainerStatus(node.PumpNode) 160 case ast.ShowStatus: 161 return e.fetchShowStatus() 162 case ast.ShowBlocks: 163 return e.fetchShowBlocks() 164 case ast.ShowOpenBlocks: 165 return e.fetchShowOpenBlocks() 166 case ast.ShowBlockStatus: 167 return e.fetchShowBlockStatus() 168 case ast.ShowTriggers: 169 return e.fetchShowTriggers() 170 case ast.ShowVariables: 171 return e.fetchShowVariables() 172 case ast.ShowWarnings: 173 return e.fetchShowWarnings(false) 174 case ast.ShowErrors: 175 return e.fetchShowWarnings(true) 176 case ast.ShowProcessList: 177 return e.fetchShowProcessList() 178 case ast.ShowEvents: 179 // empty result 180 case ast.ShowStatsMeta: 181 return e.fetchShowStatsMeta() 182 case ast.ShowStatsHistograms: 183 return e.fetchShowStatsHistogram() 184 case ast.ShowStatsBuckets: 185 return e.fetchShowStatsBuckets() 186 case ast.ShowStatsHealthy: 187 e.fetchShowStatsHealthy() 188 return nil 189 case ast.ShowPlugins: 190 return e.fetchShowPlugins() 191 case ast.ShowProfiles: 192 // empty result 193 case ast.ShowMasterStatus: 194 return e.fetchShowMasterStatus() 195 case ast.ShowPrivileges: 196 return e.fetchShowPrivileges() 197 case ast.ShowBindings: 198 return e.fetchShowBind() 199 case ast.ShowAnalyzeStatus: 200 e.fetchShowAnalyzeStatus() 201 return nil 202 case ast.ShowRegions: 203 return e.fetchShowBlockRegions() 204 case ast.ShowBuiltins: 205 return e.fetchShowBuiltins() 206 case ast.ShowBackups: 207 return e.fetchShowBRIE(ast.BRIEHoTTBackup) 208 case ast.ShowRestores: 209 return e.fetchShowBRIE(ast.BRIEHoTTRestore) 210 } 211 return nil 212 } 213 214 // visibleChecker checks if a stmt is visible for a certain user. 215 type visibleChecker struct { 216 defaultDB string 217 ctx stochastikctx.Context 218 is schemareplicant.SchemaReplicant 219 manager privilege.Manager 220 ok bool 221 } 222 223 func (v *visibleChecker) Enter(in ast.Node) (out ast.Node, skipChildren bool) { 224 switch x := in.(type) { 225 case *ast.BlockName: 226 schemaReplicant := x.Schema.L 227 if schemaReplicant == "" { 228 schemaReplicant = v.defaultDB 229 } 230 if !v.is.BlockExists(perceptron.NewCIStr(schemaReplicant), x.Name) { 231 return in, true 232 } 233 activeRoles := v.ctx.GetStochastikVars().ActiveRoles 234 if v.manager != nil && !v.manager.RequestVerification(activeRoles, schemaReplicant, x.Name.L, "", allegrosql.SelectPriv) { 235 v.ok = false 236 } 237 return in, true 238 } 239 return in, false 240 } 241 242 func (v *visibleChecker) Leave(in ast.Node) (out ast.Node, ok bool) { 243 return in, true 244 } 245 246 func (e *ShowInterDirc) fetchShowBind() error { 247 var bindRecords []*bindinfo.BindRecord 248 if !e.GlobalScope { 249 handle := e.ctx.Value(bindinfo.StochastikBindInfoKeyType).(*bindinfo.StochastikHandle) 250 bindRecords = handle.GetAllBindRecord() 251 } else { 252 bindRecords = petri.GetPetri(e.ctx).BindHandle().GetAllBindRecord() 253 } 254 BerolinaSQL := BerolinaSQL.New() 255 for _, bindData := range bindRecords { 256 for _, hint := range bindData.Bindings { 257 stmt, err := BerolinaSQL.ParseOneStmt(hint.BindALLEGROSQL, hint.Charset, hint.DefCauslation) 258 if err != nil { 259 return err 260 } 261 checker := visibleChecker{ 262 defaultDB: bindData.EDB, 263 ctx: e.ctx, 264 is: e.is, 265 manager: privilege.GetPrivilegeManager(e.ctx), 266 ok: true, 267 } 268 stmt.Accept(&checker) 269 if !checker.ok { 270 continue 271 } 272 e.appendEvent([]interface{}{ 273 bindData.OriginalALLEGROSQL, 274 hint.BindALLEGROSQL, 275 bindData.EDB, 276 hint.Status, 277 hint.CreateTime, 278 hint.UFIDelateTime, 279 hint.Charset, 280 hint.DefCauslation, 281 hint.Source, 282 }) 283 } 284 } 285 return nil 286 } 287 288 func (e *ShowInterDirc) fetchShowEngines() error { 289 allegrosql := `SELECT * FROM information_schema.engines` 290 rows, _, err := e.ctx.(sqlexec.RestrictedALLEGROSQLInterlockingDirectorate).InterDircRestrictedALLEGROSQL(allegrosql) 291 292 if err != nil { 293 return errors.Trace(err) 294 } 295 for _, event := range rows { 296 e.result.AppendEvent(event) 297 } 298 return nil 299 } 300 301 // moveSchemaReplicantToFront moves information_schema to the first, and the others are sorted in the origin ascending order. 302 func moveSchemaReplicantToFront(dbs []string) { 303 if len(dbs) > 0 && strings.EqualFold(dbs[0], "INFORMATION_SCHEMA") { 304 return 305 } 306 307 i := sort.SearchStrings(dbs, "INFORMATION_SCHEMA") 308 if i < len(dbs) && strings.EqualFold(dbs[i], "INFORMATION_SCHEMA") { 309 copy(dbs[1:i+1], dbs[0:i]) 310 dbs[0] = "INFORMATION_SCHEMA" 311 } 312 } 313 314 func (e *ShowInterDirc) fetchShowDatabases() error { 315 dbs := e.is.AllSchemaNames() 316 checker := privilege.GetPrivilegeManager(e.ctx) 317 sort.Strings(dbs) 318 // let information_schema be the first database 319 moveSchemaReplicantToFront(dbs) 320 for _, d := range dbs { 321 if checker != nil && !checker.DBIsVisible(e.ctx.GetStochastikVars().ActiveRoles, d) { 322 continue 323 } 324 e.appendEvent([]interface{}{ 325 d, 326 }) 327 } 328 return nil 329 } 330 331 func (e *ShowInterDirc) fetchShowProcessList() error { 332 sm := e.ctx.GetStochastikManager() 333 if sm == nil { 334 return nil 335 } 336 337 loginUser, activeRoles := e.ctx.GetStochastikVars().User, e.ctx.GetStochastikVars().ActiveRoles 338 var hasProcessPriv bool 339 if pm := privilege.GetPrivilegeManager(e.ctx); pm != nil { 340 if pm.RequestVerification(activeRoles, "", "", "", allegrosql.ProcessPriv) { 341 hasProcessPriv = true 342 } 343 } 344 345 pl := sm.ShowProcessList() 346 for _, pi := range pl { 347 // If you have the PROCESS privilege, you can see all threads. 348 // Otherwise, you can see only your own threads. 349 if !hasProcessPriv && pi.User != loginUser.Username { 350 continue 351 } 352 event := pi.ToEventForShow(e.Full) 353 e.appendEvent(event) 354 } 355 return nil 356 } 357 358 func (e *ShowInterDirc) fetchShowOpenBlocks() error { 359 // MilevaDB has no concept like allegrosql's "causet cache" and "open causet" 360 // For simplicity, we just return an empty result with the same structure as MyALLEGROSQL's SHOW OPEN TABLES 361 return nil 362 } 363 364 func (e *ShowInterDirc) fetchShowBlocks() error { 365 checker := privilege.GetPrivilegeManager(e.ctx) 366 if checker != nil && e.ctx.GetStochastikVars().User != nil { 367 if !checker.DBIsVisible(e.ctx.GetStochastikVars().ActiveRoles, e.DBName.O) { 368 return e.dbAccessDenied() 369 } 370 } 371 if !e.is.SchemaExists(e.DBName) { 372 return ErrBadDB.GenWithStackByArgs(e.DBName) 373 } 374 // sort for blocks 375 blockNames := make([]string, 0, len(e.is.SchemaBlocks(e.DBName))) 376 activeRoles := e.ctx.GetStochastikVars().ActiveRoles 377 var blockTypes = make(map[string]string) 378 for _, v := range e.is.SchemaBlocks(e.DBName) { 379 // Test with allegrosql.AllPrivMask means any privilege would be OK. 380 // TODO: Should consider defCausumn privileges, which also make a causet visible. 381 if checker != nil && !checker.RequestVerification(activeRoles, e.DBName.O, v.Meta().Name.O, "", allegrosql.AllPrivMask) { 382 continue 383 } 384 blockNames = append(blockNames, v.Meta().Name.O) 385 if v.Meta().IsView() { 386 blockTypes[v.Meta().Name.O] = "VIEW" 387 } else if v.Meta().IsSequence() { 388 blockTypes[v.Meta().Name.O] = "SEQUENCE" 389 } else if soliton.IsSystemView(e.DBName.L) { 390 blockTypes[v.Meta().Name.O] = "SYSTEM VIEW" 391 } else { 392 blockTypes[v.Meta().Name.O] = "BASE TABLE" 393 } 394 } 395 sort.Strings(blockNames) 396 for _, v := range blockNames { 397 if e.Full { 398 e.appendEvent([]interface{}{v, blockTypes[v]}) 399 } else { 400 e.appendEvent([]interface{}{v}) 401 } 402 } 403 return nil 404 } 405 406 func (e *ShowInterDirc) fetchShowBlockStatus() error { 407 checker := privilege.GetPrivilegeManager(e.ctx) 408 if checker != nil && e.ctx.GetStochastikVars().User != nil { 409 if !checker.DBIsVisible(e.ctx.GetStochastikVars().ActiveRoles, e.DBName.O) { 410 return e.dbAccessDenied() 411 } 412 } 413 if !e.is.SchemaExists(e.DBName) { 414 return ErrBadDB.GenWithStackByArgs(e.DBName) 415 } 416 417 allegrosql := fmt.Sprintf(`SELECT 418 block_name, engine, version, row_format, block_rows, 419 avg_row_length, data_length, max_data_length, index_length, 420 data_free, auto_increment, create_time, uFIDelate_time, check_time, 421 block_defCauslation, IFNULL(checksum,''), create_options, block_comment 422 FROM information_schema.blocks 423 WHERE block_schema='%s' ORDER BY block_name`, e.DBName) 424 425 rows, _, err := e.ctx.(sqlexec.RestrictedALLEGROSQLInterlockingDirectorate).InterDircRestrictedALLEGROSQLWithSnapshot(allegrosql) 426 427 if err != nil { 428 return errors.Trace(err) 429 } 430 431 activeRoles := e.ctx.GetStochastikVars().ActiveRoles 432 for _, event := range rows { 433 if checker != nil && !checker.RequestVerification(activeRoles, e.DBName.O, event.GetString(0), "", allegrosql.AllPrivMask) { 434 continue 435 } 436 e.result.AppendEvent(event) 437 438 } 439 return nil 440 } 441 442 func (e *ShowInterDirc) fetchShowDeferredCausets(ctx context.Context) error { 443 tb, err := e.getBlock() 444 445 if err != nil { 446 return errors.Trace(err) 447 } 448 checker := privilege.GetPrivilegeManager(e.ctx) 449 activeRoles := e.ctx.GetStochastikVars().ActiveRoles 450 if checker != nil && e.ctx.GetStochastikVars().User != nil && !checker.RequestVerification(activeRoles, e.DBName.O, tb.Meta().Name.O, "", allegrosql.AllPrivMask) { 451 return e.blockAccessDenied("SELECT", tb.Meta().Name.O) 452 } 453 454 var defcaus []*causet.DeferredCauset 455 // The optional EXTENDED keyword causes the output to include information about hidden defCausumns that MyALLEGROSQL uses internally and are not accessible by users. 456 // See https://dev.allegrosql.com/doc/refman/8.0/en/show-defCausumns.html 457 if e.Extended { 458 defcaus = tb.DefCauss() 459 } else { 460 defcaus = tb.VisibleDefCauss() 461 } 462 if tb.Meta().IsView() { 463 // Because view's underblock's defCausumn could change or recreate, so view's defCausumn type may change overtime. 464 // To avoid this situation we need to generate a logical plan and extract current defCausumn types from Schema. 465 planBuilder := causetembedded.NewCausetBuilder(e.ctx, e.is, &hint.BlockHintProcessor{}) 466 viewLogicalCauset, err := planBuilder.BuildDataSourceFromView(ctx, e.DBName, tb.Meta()) 467 if err != nil { 468 return err 469 } 470 viewSchema := viewLogicalCauset.Schema() 471 viewOutputNames := viewLogicalCauset.OutputNames() 472 for _, defCaus := range defcaus { 473 idx := memex.FindFieldNameIdxByDefCausName(viewOutputNames, defCaus.Name.L) 474 if idx >= 0 { 475 defCaus.FieldType = *viewSchema.DeferredCausets[idx].GetType() 476 } 477 } 478 } 479 for _, defCaus := range defcaus { 480 if e.DeferredCauset != nil && e.DeferredCauset.Name.L != defCaus.Name.L { 481 continue 482 } 483 484 desc := causet.NewDefCausDesc(defCaus) 485 var defCausumnDefault interface{} 486 if desc.DefaultValue != nil { 487 // SHOW COLUMNS result expects string value 488 defaultValStr := fmt.Sprintf("%v", desc.DefaultValue) 489 // If defCausumn is timestamp, and default value is not current_timestamp, should convert the default value to the current stochastik time zone. 490 if defCaus.Tp == allegrosql.TypeTimestamp && defaultValStr != types.ZeroDatetimeStr && !strings.HasPrefix(strings.ToUpper(defaultValStr), strings.ToUpper(ast.CurrentTimestamp)) { 491 timeValue, err := causet.GetDefCausDefaultValue(e.ctx, defCaus.ToInfo()) 492 if err != nil { 493 return errors.Trace(err) 494 } 495 defaultValStr = timeValue.GetMysqlTime().String() 496 } 497 if defCaus.Tp == allegrosql.TypeBit { 498 defaultValBinaryLiteral := types.BinaryLiteral(defaultValStr) 499 defCausumnDefault = defaultValBinaryLiteral.ToBitLiteralString(true) 500 } else { 501 defCausumnDefault = defaultValStr 502 } 503 } 504 505 // The FULL keyword causes the output to include the defCausumn defCauslation and comments, 506 // as well as the privileges you have for each defCausumn. 507 if e.Full { 508 e.appendEvent([]interface{}{ 509 desc.Field, 510 desc.Type, 511 desc.DefCauslation, 512 desc.Null, 513 desc.Key, 514 defCausumnDefault, 515 desc.Extra, 516 desc.Privileges, 517 desc.Comment, 518 }) 519 } else { 520 e.appendEvent([]interface{}{ 521 desc.Field, 522 desc.Type, 523 desc.Null, 524 desc.Key, 525 defCausumnDefault, 526 desc.Extra, 527 }) 528 } 529 } 530 return nil 531 } 532 533 func (e *ShowInterDirc) fetchShowIndex() error { 534 tb, err := e.getBlock() 535 if err != nil { 536 return errors.Trace(err) 537 } 538 539 checker := privilege.GetPrivilegeManager(e.ctx) 540 activeRoles := e.ctx.GetStochastikVars().ActiveRoles 541 if checker != nil && e.ctx.GetStochastikVars().User != nil && !checker.RequestVerification(activeRoles, e.DBName.O, tb.Meta().Name.O, "", allegrosql.AllPrivMask) { 542 return e.blockAccessDenied("SELECT", tb.Meta().Name.O) 543 } 544 545 if tb.Meta().PKIsHandle { 546 var pkDefCaus *causet.DeferredCauset 547 for _, defCaus := range tb.DefCauss() { 548 if allegrosql.HasPriKeyFlag(defCaus.Flag) { 549 pkDefCaus = defCaus 550 break 551 } 552 } 553 e.appendEvent([]interface{}{ 554 tb.Meta().Name.O, // Block 555 0, // Non_unique 556 "PRIMARY", // Key_name 557 1, // Seq_in_index 558 pkDefCaus.Name.O, // DeferredCauset_name 559 "A", // DefCauslation 560 0, // Cardinality 561 nil, // Sub_part 562 nil, // Packed 563 "", // Null 564 "BTREE", // Index_type 565 "", // Comment 566 "", // Index_comment 567 "YES", // Index_visible 568 "NULL", // Expression 569 }) 570 } 571 for _, idx := range tb.Indices() { 572 idxInfo := idx.Meta() 573 if idxInfo.State != perceptron.StatePublic { 574 continue 575 } 576 for i, defCaus := range idxInfo.DeferredCausets { 577 nonUniq := 1 578 if idx.Meta().Unique { 579 nonUniq = 0 580 } 581 582 var subPart interface{} 583 if defCaus.Length != types.UnspecifiedLength { 584 subPart = defCaus.Length 585 } 586 587 nullVal := "YES" 588 if idx.Meta().Name.O == allegrosql.PrimaryKeyName { 589 nullVal = "" 590 } 591 592 visible := "YES" 593 if idx.Meta().Invisible { 594 visible = "NO" 595 } 596 597 defCausName := defCaus.Name.O 598 memex := "NULL" 599 tblDefCaus := tb.Meta().DeferredCausets[defCaus.Offset] 600 if tblDefCaus.Hidden { 601 defCausName = "NULL" 602 memex = fmt.Sprintf("(%s)", tblDefCaus.GeneratedExprString) 603 } 604 605 e.appendEvent([]interface{}{ 606 tb.Meta().Name.O, // Block 607 nonUniq, // Non_unique 608 idx.Meta().Name.O, // Key_name 609 i + 1, // Seq_in_index 610 defCausName, // DeferredCauset_name 611 "A", // DefCauslation 612 0, // Cardinality 613 subPart, // Sub_part 614 nil, // Packed 615 nullVal, // Null 616 idx.Meta().Tp.String(), // Index_type 617 "", // Comment 618 idx.Meta().Comment, // Index_comment 619 visible, // Index_visible 620 memex, // Expression 621 }) 622 } 623 } 624 return nil 625 } 626 627 // fetchShowCharset gets all charset information and fill them into e.rows. 628 // See http://dev.allegrosql.com/doc/refman/5.7/en/show-character-set.html 629 func (e *ShowInterDirc) fetchShowCharset() error { 630 descs := charset.GetSupportedCharsets() 631 for _, desc := range descs { 632 e.appendEvent([]interface{}{ 633 desc.Name, 634 desc.Desc, 635 desc.DefaultDefCauslation, 636 desc.Maxlen, 637 }) 638 } 639 return nil 640 } 641 642 func (e *ShowInterDirc) fetchShowMasterStatus() error { 643 tso := e.ctx.GetStochastikVars().TxnCtx.StartTS 644 e.appendEvent([]interface{}{"milevadb-binlog", tso, "", "", ""}) 645 return nil 646 } 647 648 func (e *ShowInterDirc) fetchShowVariables() (err error) { 649 var ( 650 value string 651 ok bool 652 stochastikVars = e.ctx.GetStochastikVars() 653 unreachedVars = make([]string, 0, len(variable.SysVars)) 654 ) 655 for _, v := range variable.SysVars { 656 if !e.GlobalScope { 657 // For a stochastik scope variable, 658 // 1. try to fetch value from StochastikVars.Systems; 659 // 2. if this variable is stochastik-only, fetch value from SysVars 660 // otherwise, fetch the value from causet `allegrosql.Global_Variables`. 661 value, ok, err = variable.GetStochastikOnlySysVars(stochastikVars, v.Name) 662 } else { 663 // If the scope of a system variable is ScopeNone, 664 // it's a read-only variable, so we return the default value of it. 665 // Otherwise, we have to fetch the values from causet `allegrosql.Global_Variables` for global variable names. 666 value, ok, err = variable.GetScopeNoneSystemVar(v.Name) 667 } 668 if err != nil { 669 return errors.Trace(err) 670 } 671 if !ok { 672 unreachedVars = append(unreachedVars, v.Name) 673 continue 674 } 675 e.appendEvent([]interface{}{v.Name, value}) 676 } 677 if len(unreachedVars) != 0 { 678 systemVars, err := stochastikVars.GlobalVarsAccessor.GetAllSysVars() 679 if err != nil { 680 return errors.Trace(err) 681 } 682 for _, varName := range unreachedVars { 683 varValue, ok := systemVars[varName] 684 if !ok { 685 varValue = variable.SysVars[varName].Value 686 } 687 e.appendEvent([]interface{}{varName, varValue}) 688 } 689 } 690 return nil 691 } 692 693 func (e *ShowInterDirc) fetchShowStatus() error { 694 stochastikVars := e.ctx.GetStochastikVars() 695 statusVars, err := variable.GetStatusVars(stochastikVars) 696 if err != nil { 697 return errors.Trace(err) 698 } 699 for status, v := range statusVars { 700 if e.GlobalScope && v.Scope == variable.ScopeStochastik { 701 continue 702 } 703 switch v.Value.(type) { 704 case []interface{}, nil: 705 v.Value = fmt.Sprintf("%v", v.Value) 706 } 707 value, err := types.ToString(v.Value) 708 if err != nil { 709 return errors.Trace(err) 710 } 711 e.appendEvent([]interface{}{status, value}) 712 } 713 return nil 714 } 715 716 func getDefaultDefCauslate(charsetName string) string { 717 for _, c := range charset.GetSupportedCharsets() { 718 if strings.EqualFold(c.Name, charsetName) { 719 return c.DefaultDefCauslation 720 } 721 } 722 return "" 723 } 724 725 // ConstructResultOfShowCreateBlock constructs the result for show create causet. 726 func ConstructResultOfShowCreateBlock(ctx stochastikctx.Context, blockInfo *perceptron.BlockInfo, allocators autoid.SlabPredictors, buf *bytes.Buffer) (err error) { 727 if blockInfo.IsView() { 728 fetchShowCreateBlock4View(ctx, blockInfo, buf) 729 return nil 730 } 731 if blockInfo.IsSequence() { 732 ConstructResultOfShowCreateSequence(ctx, blockInfo, buf) 733 return nil 734 } 735 736 tblCharset := blockInfo.Charset 737 if len(tblCharset) == 0 { 738 tblCharset = allegrosql.DefaultCharset 739 } 740 tblDefCauslate := blockInfo.DefCauslate 741 // Set default defCauslate if defCauslate is not specified. 742 if len(tblDefCauslate) == 0 { 743 tblDefCauslate = getDefaultDefCauslate(tblCharset) 744 } 745 746 sqlMode := ctx.GetStochastikVars().ALLEGROSQLMode 747 fmt.Fprintf(buf, "CREATE TABLE %s (\n", stringutil.Escape(blockInfo.Name.O, sqlMode)) 748 var pkDefCaus *perceptron.DeferredCausetInfo 749 var hasAutoIncID bool 750 needAddComma := false 751 for i, defCaus := range blockInfo.DefCauss() { 752 if defCaus.Hidden { 753 continue 754 } 755 if needAddComma { 756 buf.WriteString(",\n") 757 } 758 fmt.Fprintf(buf, " %s %s", stringutil.Escape(defCaus.Name.O, sqlMode), defCaus.GetTypeDesc()) 759 if defCaus.Charset != "binary" { 760 if defCaus.Charset != tblCharset { 761 fmt.Fprintf(buf, " CHARACTER SET %s", defCaus.Charset) 762 } 763 if defCaus.DefCauslate != tblDefCauslate { 764 fmt.Fprintf(buf, " COLLATE %s", defCaus.DefCauslate) 765 } else { 766 defdefCaus, err := charset.GetDefaultDefCauslation(defCaus.Charset) 767 if err == nil && defdefCaus != defCaus.DefCauslate { 768 fmt.Fprintf(buf, " COLLATE %s", defCaus.DefCauslate) 769 } 770 } 771 } 772 if defCaus.IsGenerated() { 773 // It's a generated defCausumn. 774 fmt.Fprintf(buf, " GENERATED ALWAYS AS (%s)", defCaus.GeneratedExprString) 775 if defCaus.GeneratedStored { 776 buf.WriteString(" STORED") 777 } else { 778 buf.WriteString(" VIRTUAL") 779 } 780 } 781 if allegrosql.HasAutoIncrementFlag(defCaus.Flag) { 782 hasAutoIncID = true 783 buf.WriteString(" NOT NULL AUTO_INCREMENT") 784 } else { 785 if allegrosql.HasNotNullFlag(defCaus.Flag) { 786 buf.WriteString(" NOT NULL") 787 } 788 // default values are not shown for generated defCausumns in MyALLEGROSQL 789 if !allegrosql.HasNoDefaultValueFlag(defCaus.Flag) && !defCaus.IsGenerated() { 790 defaultValue := defCaus.GetDefaultValue() 791 switch defaultValue { 792 case nil: 793 if !allegrosql.HasNotNullFlag(defCaus.Flag) { 794 if defCaus.Tp == allegrosql.TypeTimestamp { 795 buf.WriteString(" NULL") 796 } 797 buf.WriteString(" DEFAULT NULL") 798 } 799 case "CURRENT_TIMESTAMP": 800 buf.WriteString(" DEFAULT CURRENT_TIMESTAMP") 801 if defCaus.Decimal > 0 { 802 buf.WriteString(fmt.Sprintf("(%d)", defCaus.Decimal)) 803 } 804 default: 805 defaultValStr := fmt.Sprintf("%v", defaultValue) 806 // If defCausumn is timestamp, and default value is not current_timestamp, should convert the default value to the current stochastik time zone. 807 if defCaus.Tp == allegrosql.TypeTimestamp && defaultValStr != types.ZeroDatetimeStr { 808 timeValue, err := causet.GetDefCausDefaultValue(ctx, defCaus) 809 if err != nil { 810 return errors.Trace(err) 811 } 812 defaultValStr = timeValue.GetMysqlTime().String() 813 } 814 815 if defCaus.Tp == allegrosql.TypeBit { 816 defaultValBinaryLiteral := types.BinaryLiteral(defaultValStr) 817 fmt.Fprintf(buf, " DEFAULT %s", defaultValBinaryLiteral.ToBitLiteralString(true)) 818 } else if types.IsTypeNumeric(defCaus.Tp) || defCaus.DefaultIsExpr { 819 fmt.Fprintf(buf, " DEFAULT %s", format.OutputFormat(defaultValStr)) 820 } else { 821 fmt.Fprintf(buf, " DEFAULT '%s'", format.OutputFormat(defaultValStr)) 822 } 823 } 824 } 825 if allegrosql.HasOnUFIDelateNowFlag(defCaus.Flag) { 826 buf.WriteString(" ON UFIDelATE CURRENT_TIMESTAMP") 827 buf.WriteString(causet.OptionalFsp(&defCaus.FieldType)) 828 } 829 } 830 if dbs.IsAutoRandomDeferredCausetID(blockInfo, defCaus.ID) { 831 buf.WriteString(fmt.Sprintf(" /*T![auto_rand] AUTO_RANDOM(%d) */", blockInfo.AutoRandomBits)) 832 } 833 if len(defCaus.Comment) > 0 { 834 buf.WriteString(fmt.Sprintf(" COMMENT '%s'", format.OutputFormat(defCaus.Comment))) 835 } 836 if i != len(blockInfo.DefCauss())-1 { 837 needAddComma = true 838 } 839 if blockInfo.PKIsHandle && allegrosql.HasPriKeyFlag(defCaus.Flag) { 840 pkDefCaus = defCaus 841 } 842 } 843 844 if pkDefCaus != nil { 845 // If PKIsHanle, pk info is not in tb.Indices(). We should handle it here. 846 buf.WriteString(",\n") 847 fmt.Fprintf(buf, " PRIMARY KEY (%s)", stringutil.Escape(pkDefCaus.Name.O, sqlMode)) 848 } 849 850 publicIndices := make([]*perceptron.IndexInfo, 0, len(blockInfo.Indices)) 851 for _, idx := range blockInfo.Indices { 852 if idx.State == perceptron.StatePublic { 853 publicIndices = append(publicIndices, idx) 854 } 855 } 856 if len(publicIndices) > 0 { 857 buf.WriteString(",\n") 858 } 859 860 for i, idxInfo := range publicIndices { 861 if idxInfo.Primary { 862 buf.WriteString(" PRIMARY KEY ") 863 } else if idxInfo.Unique { 864 fmt.Fprintf(buf, " UNIQUE KEY %s ", stringutil.Escape(idxInfo.Name.O, sqlMode)) 865 } else { 866 fmt.Fprintf(buf, " KEY %s ", stringutil.Escape(idxInfo.Name.O, sqlMode)) 867 } 868 869 defcaus := make([]string, 0, len(idxInfo.DeferredCausets)) 870 var defCausInfo string 871 for _, c := range idxInfo.DeferredCausets { 872 if blockInfo.DeferredCausets[c.Offset].Hidden { 873 defCausInfo = fmt.Sprintf("(%s)", blockInfo.DeferredCausets[c.Offset].GeneratedExprString) 874 } else { 875 defCausInfo = stringutil.Escape(c.Name.O, sqlMode) 876 if c.Length != types.UnspecifiedLength { 877 defCausInfo = fmt.Sprintf("%s(%s)", defCausInfo, strconv.Itoa(c.Length)) 878 } 879 } 880 defcaus = append(defcaus, defCausInfo) 881 } 882 fmt.Fprintf(buf, "(%s)", strings.Join(defcaus, ",")) 883 if idxInfo.Invisible { 884 fmt.Fprintf(buf, ` /*!80000 INVISIBLE */`) 885 } 886 if i != len(publicIndices)-1 { 887 buf.WriteString(",\n") 888 } 889 } 890 891 // Foreign Keys are supported by data dictionary even though 892 // they are not enforced by DBS. This is still helpful to applications. 893 for _, fk := range blockInfo.ForeignKeys { 894 buf.WriteString(fmt.Sprintf(",\n CONSTRAINT %s FOREIGN KEY ", stringutil.Escape(fk.Name.O, sqlMode))) 895 defCausNames := make([]string, 0, len(fk.DefCauss)) 896 for _, defCaus := range fk.DefCauss { 897 defCausNames = append(defCausNames, stringutil.Escape(defCaus.O, sqlMode)) 898 } 899 buf.WriteString(fmt.Sprintf("(%s)", strings.Join(defCausNames, ","))) 900 buf.WriteString(fmt.Sprintf(" REFERENCES %s ", stringutil.Escape(fk.RefBlock.O, sqlMode))) 901 refDefCausNames := make([]string, 0, len(fk.DefCauss)) 902 for _, refDefCaus := range fk.RefDefCauss { 903 refDefCausNames = append(refDefCausNames, stringutil.Escape(refDefCaus.O, sqlMode)) 904 } 905 buf.WriteString(fmt.Sprintf("(%s)", strings.Join(refDefCausNames, ","))) 906 if ast.ReferOptionType(fk.OnDelete) != 0 { 907 buf.WriteString(fmt.Sprintf(" ON DELETE %s", ast.ReferOptionType(fk.OnDelete).String())) 908 } 909 if ast.ReferOptionType(fk.OnUFIDelate) != 0 { 910 buf.WriteString(fmt.Sprintf(" ON UFIDelATE %s", ast.ReferOptionType(fk.OnUFIDelate).String())) 911 } 912 } 913 914 buf.WriteString("\n") 915 916 buf.WriteString(") ENGINE=InnoDB") 917 // We need to explicitly set the default charset and defCauslation 918 // to make it work on MyALLEGROSQL server which has default defCauslate utf8_general_ci. 919 if len(tblDefCauslate) == 0 || tblDefCauslate == "binary" { 920 // If we can not find default defCauslate for the given charset, 921 // or the defCauslate is 'binary'(MyALLEGROSQL-5.7 compatibility, see #15633 for details), 922 // do not show the defCauslate part. 923 fmt.Fprintf(buf, " DEFAULT CHARSET=%s", tblCharset) 924 } else { 925 fmt.Fprintf(buf, " DEFAULT CHARSET=%s COLLATE=%s", tblCharset, tblDefCauslate) 926 } 927 928 // Displayed if the compression typed is set. 929 if len(blockInfo.Compression) != 0 { 930 fmt.Fprintf(buf, " COMPRESSION='%s'", blockInfo.Compression) 931 } 932 933 incrementSlabPredictor := allocators.Get(autoid.EventIDAllocType) 934 if hasAutoIncID && incrementSlabPredictor != nil { 935 autoIncID, err := incrementSlabPredictor.NextGlobalAutoID(blockInfo.ID) 936 if err != nil { 937 return errors.Trace(err) 938 } 939 940 // It's compatible with MyALLEGROSQL. 941 if autoIncID > 1 { 942 fmt.Fprintf(buf, " AUTO_INCREMENT=%d", autoIncID) 943 } 944 } 945 946 if blockInfo.AutoIdCache != 0 { 947 fmt.Fprintf(buf, " /*T![auto_id_cache] AUTO_ID_CACHE=%d */", blockInfo.AutoIdCache) 948 } 949 950 randomSlabPredictor := allocators.Get(autoid.AutoRandomType) 951 if randomSlabPredictor != nil { 952 autoRandID, err := randomSlabPredictor.NextGlobalAutoID(blockInfo.ID) 953 if err != nil { 954 return errors.Trace(err) 955 } 956 957 if autoRandID > 1 { 958 fmt.Fprintf(buf, " /*T![auto_rand_base] AUTO_RANDOM_BASE=%d */", autoRandID) 959 } 960 } 961 962 if blockInfo.ShardEventIDBits > 0 { 963 fmt.Fprintf(buf, "/*!90000 SHARD_ROW_ID_BITS=%d ", blockInfo.ShardEventIDBits) 964 if blockInfo.PreSplitRegions > 0 { 965 fmt.Fprintf(buf, "PRE_SPLIT_REGIONS=%d ", blockInfo.PreSplitRegions) 966 } 967 buf.WriteString("*/") 968 } 969 970 if len(blockInfo.Comment) > 0 { 971 fmt.Fprintf(buf, " COMMENT='%s'", format.OutputFormat(blockInfo.Comment)) 972 } 973 // add partition info here. 974 appendPartitionInfo(blockInfo.Partition, buf) 975 return nil 976 } 977 978 // ConstructResultOfShowCreateSequence constructs the result for show create sequence. 979 func ConstructResultOfShowCreateSequence(ctx stochastikctx.Context, blockInfo *perceptron.BlockInfo, buf *bytes.Buffer) { 980 sqlMode := ctx.GetStochastikVars().ALLEGROSQLMode 981 fmt.Fprintf(buf, "CREATE SEQUENCE %s ", stringutil.Escape(blockInfo.Name.O, sqlMode)) 982 sequenceInfo := blockInfo.Sequence 983 fmt.Fprintf(buf, "start with %d ", sequenceInfo.Start) 984 fmt.Fprintf(buf, "minvalue %d ", sequenceInfo.MinValue) 985 fmt.Fprintf(buf, "maxvalue %d ", sequenceInfo.MaxValue) 986 fmt.Fprintf(buf, "increment by %d ", sequenceInfo.Increment) 987 if sequenceInfo.Cache { 988 fmt.Fprintf(buf, "cache %d ", sequenceInfo.CacheValue) 989 } else { 990 buf.WriteString("nocache ") 991 } 992 if sequenceInfo.Cycle { 993 buf.WriteString("cycle ") 994 } else { 995 buf.WriteString("nocycle ") 996 } 997 buf.WriteString("ENGINE=InnoDB") 998 if len(sequenceInfo.Comment) > 0 { 999 fmt.Fprintf(buf, " COMMENT='%s'", format.OutputFormat(sequenceInfo.Comment)) 1000 } 1001 } 1002 1003 func (e *ShowInterDirc) fetchShowCreateSequence() error { 1004 tbl, err := e.getBlock() 1005 if err != nil { 1006 return errors.Trace(err) 1007 } 1008 blockInfo := tbl.Meta() 1009 if !blockInfo.IsSequence() { 1010 return ErrWrongObject.GenWithStackByArgs(e.DBName.O, blockInfo.Name.O, "SEQUENCE") 1011 } 1012 var buf bytes.Buffer 1013 ConstructResultOfShowCreateSequence(e.ctx, blockInfo, &buf) 1014 e.appendEvent([]interface{}{blockInfo.Name.O, buf.String()}) 1015 return nil 1016 } 1017 1018 // TestShowClusterConfigKey is the key used to causetstore TestShowClusterConfigFunc. 1019 var TestShowClusterConfigKey stringutil.StringerStr = "TestShowClusterConfigKey" 1020 1021 // TestShowClusterConfigFunc is used to test 'show config ...'. 1022 type TestShowClusterConfigFunc func() ([][]types.Causet, error) 1023 1024 func (e *ShowInterDirc) fetchShowClusterConfigs(ctx context.Context) error { 1025 emptySet := set.NewStringSet() 1026 var confItems [][]types.Causet 1027 var err error 1028 if f := e.ctx.Value(TestShowClusterConfigKey); f != nil { 1029 confItems, err = f.(TestShowClusterConfigFunc)() 1030 } else { 1031 confItems, err = fetchClusterConfig(e.ctx, emptySet, emptySet) 1032 } 1033 if err != nil { 1034 return err 1035 } 1036 for _, items := range confItems { 1037 event := make([]interface{}, 0, 4) 1038 for _, item := range items { 1039 event = append(event, item.GetString()) 1040 } 1041 e.appendEvent(event) 1042 } 1043 return nil 1044 } 1045 1046 func (e *ShowInterDirc) fetchShowCreateBlock() error { 1047 tb, err := e.getBlock() 1048 if err != nil { 1049 return errors.Trace(err) 1050 } 1051 1052 blockInfo := tb.Meta() 1053 var buf bytes.Buffer 1054 // TODO: let the result more like MyALLEGROSQL. 1055 if err = ConstructResultOfShowCreateBlock(e.ctx, blockInfo, tb.SlabPredictors(e.ctx), &buf); err != nil { 1056 return err 1057 } 1058 if blockInfo.IsView() { 1059 e.appendEvent([]interface{}{blockInfo.Name.O, buf.String(), blockInfo.Charset, blockInfo.DefCauslate}) 1060 return nil 1061 } 1062 1063 e.appendEvent([]interface{}{blockInfo.Name.O, buf.String()}) 1064 return nil 1065 } 1066 1067 func (e *ShowInterDirc) fetchShowCreateView() error { 1068 EDB, ok := e.is.SchemaByName(e.DBName) 1069 if !ok { 1070 return schemareplicant.ErrDatabaseNotExists.GenWithStackByArgs(e.DBName.O) 1071 } 1072 1073 tb, err := e.getBlock() 1074 if err != nil { 1075 return errors.Trace(err) 1076 } 1077 1078 if !tb.Meta().IsView() { 1079 return ErrWrongObject.GenWithStackByArgs(EDB.Name.O, tb.Meta().Name.O, "VIEW") 1080 } 1081 1082 var buf bytes.Buffer 1083 fetchShowCreateBlock4View(e.ctx, tb.Meta(), &buf) 1084 e.appendEvent([]interface{}{tb.Meta().Name.O, buf.String(), tb.Meta().Charset, tb.Meta().DefCauslate}) 1085 return nil 1086 } 1087 1088 func fetchShowCreateBlock4View(ctx stochastikctx.Context, tb *perceptron.BlockInfo, buf *bytes.Buffer) { 1089 sqlMode := ctx.GetStochastikVars().ALLEGROSQLMode 1090 1091 fmt.Fprintf(buf, "CREATE ALGORITHM=%s ", tb.View.Algorithm.String()) 1092 fmt.Fprintf(buf, "DEFINER=%s@%s ", stringutil.Escape(tb.View.Definer.Username, sqlMode), stringutil.Escape(tb.View.Definer.Hostname, sqlMode)) 1093 fmt.Fprintf(buf, "ALLEGROALLEGROSQL SECURITY %s ", tb.View.Security.String()) 1094 fmt.Fprintf(buf, "VIEW %s (", stringutil.Escape(tb.Name.O, sqlMode)) 1095 for i, defCaus := range tb.DeferredCausets { 1096 fmt.Fprintf(buf, "%s", stringutil.Escape(defCaus.Name.O, sqlMode)) 1097 if i < len(tb.DeferredCausets)-1 { 1098 fmt.Fprintf(buf, ", ") 1099 } 1100 } 1101 fmt.Fprintf(buf, ") AS %s", tb.View.SelectStmt) 1102 } 1103 1104 func appendPartitionInfo(partitionInfo *perceptron.PartitionInfo, buf *bytes.Buffer) { 1105 if partitionInfo == nil { 1106 return 1107 } 1108 if partitionInfo.Type == perceptron.PartitionTypeHash { 1109 fmt.Fprintf(buf, "\nPARTITION BY HASH( %s )", partitionInfo.Expr) 1110 fmt.Fprintf(buf, "\nPARTITIONS %d", partitionInfo.Num) 1111 return 1112 } 1113 // this if memex takes care of range defCausumns case 1114 if partitionInfo.DeferredCausets != nil && partitionInfo.Type == perceptron.PartitionTypeRange { 1115 buf.WriteString("\nPARTITION BY RANGE COLUMNS(") 1116 for i, defCaus := range partitionInfo.DeferredCausets { 1117 buf.WriteString(defCaus.L) 1118 if i < len(partitionInfo.DeferredCausets)-1 { 1119 buf.WriteString(",") 1120 } 1121 } 1122 buf.WriteString(") (\n") 1123 } else { 1124 fmt.Fprintf(buf, "\nPARTITION BY %s ( %s ) (\n", partitionInfo.Type.String(), partitionInfo.Expr) 1125 } 1126 for i, def := range partitionInfo.Definitions { 1127 lessThans := strings.Join(def.LessThan, ",") 1128 fmt.Fprintf(buf, " PARTITION `%s` VALUES LESS THAN (%s)", def.Name, lessThans) 1129 if i < len(partitionInfo.Definitions)-1 { 1130 buf.WriteString(",\n") 1131 } else { 1132 buf.WriteString("\n") 1133 } 1134 } 1135 buf.WriteString(")") 1136 } 1137 1138 // ConstructResultOfShowCreateDatabase constructs the result for show create database. 1139 func ConstructResultOfShowCreateDatabase(ctx stochastikctx.Context, dbInfo *perceptron.DBInfo, ifNotExists bool, buf *bytes.Buffer) (err error) { 1140 sqlMode := ctx.GetStochastikVars().ALLEGROSQLMode 1141 var ifNotExistsStr string 1142 if ifNotExists { 1143 ifNotExistsStr = "/*!32312 IF NOT EXISTS*/ " 1144 } 1145 fmt.Fprintf(buf, "CREATE DATABASE %s%s", ifNotExistsStr, stringutil.Escape(dbInfo.Name.O, sqlMode)) 1146 if dbInfo.Charset != "" { 1147 fmt.Fprintf(buf, " /*!40100 DEFAULT CHARACTER SET %s ", dbInfo.Charset) 1148 defaultDefCauslate, err := charset.GetDefaultDefCauslation(dbInfo.Charset) 1149 if err != nil { 1150 return errors.Trace(err) 1151 } 1152 if dbInfo.DefCauslate != "" && dbInfo.DefCauslate != defaultDefCauslate { 1153 fmt.Fprintf(buf, "COLLATE %s ", dbInfo.DefCauslate) 1154 } 1155 fmt.Fprint(buf, "*/") 1156 return nil 1157 } 1158 if dbInfo.DefCauslate != "" { 1159 defCauslInfo, err := defCauslate.GetDefCauslationByName(dbInfo.DefCauslate) 1160 if err != nil { 1161 return errors.Trace(err) 1162 } 1163 fmt.Fprintf(buf, " /*!40100 DEFAULT CHARACTER SET %s ", defCauslInfo.CharsetName) 1164 if !defCauslInfo.IsDefault { 1165 fmt.Fprintf(buf, "COLLATE %s ", dbInfo.DefCauslate) 1166 } 1167 fmt.Fprint(buf, "*/") 1168 return nil 1169 } 1170 // MyALLEGROSQL 5.7 always show the charset info but MilevaDB may ignore it, which makes a slight difference. We keep this 1171 // behavior unchanged because it is trivial enough. 1172 return nil 1173 } 1174 1175 // fetchShowCreateDatabase composes show create database result. 1176 func (e *ShowInterDirc) fetchShowCreateDatabase() error { 1177 checker := privilege.GetPrivilegeManager(e.ctx) 1178 if checker != nil && e.ctx.GetStochastikVars().User != nil { 1179 if !checker.DBIsVisible(e.ctx.GetStochastikVars().ActiveRoles, e.DBName.String()) { 1180 return e.dbAccessDenied() 1181 } 1182 } 1183 dbInfo, ok := e.is.SchemaByName(e.DBName) 1184 if !ok { 1185 return schemareplicant.ErrDatabaseNotExists.GenWithStackByArgs(e.DBName.O) 1186 } 1187 1188 var buf bytes.Buffer 1189 err := ConstructResultOfShowCreateDatabase(e.ctx, dbInfo, e.IfNotExists, &buf) 1190 if err != nil { 1191 return err 1192 } 1193 e.appendEvent([]interface{}{dbInfo.Name.O, buf.String()}) 1194 return nil 1195 } 1196 1197 func (e *ShowInterDirc) fetchShowDefCauslation() error { 1198 defCauslations := defCauslate.GetSupportedDefCauslations() 1199 for _, v := range defCauslations { 1200 isDefault := "" 1201 if v.IsDefault { 1202 isDefault = "Yes" 1203 } 1204 e.appendEvent([]interface{}{ 1205 v.Name, 1206 v.CharsetName, 1207 v.ID, 1208 isDefault, 1209 "Yes", 1210 1, 1211 }) 1212 } 1213 return nil 1214 } 1215 1216 // fetchShowCreateUser composes show create create user result. 1217 func (e *ShowInterDirc) fetchShowCreateUser() error { 1218 checker := privilege.GetPrivilegeManager(e.ctx) 1219 if checker == nil { 1220 return errors.New("miss privilege checker") 1221 } 1222 1223 userName, hostName := e.User.Username, e.User.Hostname 1224 sessVars := e.ctx.GetStochastikVars() 1225 if e.User.CurrentUser { 1226 userName = sessVars.User.AuthUsername 1227 hostName = sessVars.User.AuthHostname 1228 } else { 1229 // Show create user requires the SELECT privilege on allegrosql.user. 1230 // Ref https://dev.allegrosql.com/doc/refman/5.7/en/show-create-user.html 1231 activeRoles := sessVars.ActiveRoles 1232 if !checker.RequestVerification(activeRoles, allegrosql.SystemDB, allegrosql.UserBlock, "", allegrosql.SelectPriv) { 1233 return e.blockAccessDenied("SELECT", allegrosql.UserBlock) 1234 } 1235 } 1236 1237 allegrosql := fmt.Sprintf(`SELECT * FROM %s.%s WHERE User='%s' AND Host='%s';`, 1238 allegrosql.SystemDB, allegrosql.UserBlock, userName, hostName) 1239 rows, _, err := e.ctx.(sqlexec.RestrictedALLEGROSQLInterlockingDirectorate).InterDircRestrictedALLEGROSQL(allegrosql) 1240 if err != nil { 1241 return errors.Trace(err) 1242 } 1243 if len(rows) == 0 { 1244 return ErrCannotUser.GenWithStackByArgs("SHOW CREATE USER", 1245 fmt.Sprintf("'%s'@'%s'", e.User.Username, e.User.Hostname)) 1246 } 1247 allegrosql = fmt.Sprintf(`SELECT PRIV FROM %s.%s WHERE User='%s' AND Host='%s'`, 1248 allegrosql.SystemDB, allegrosql.GlobalPrivBlock, userName, hostName) 1249 rows, _, err = e.ctx.(sqlexec.RestrictedALLEGROSQLInterlockingDirectorate).InterDircRestrictedALLEGROSQL(allegrosql) 1250 if err != nil { 1251 return errors.Trace(err) 1252 } 1253 require := "NONE" 1254 if len(rows) == 1 { 1255 privData := rows[0].GetString(0) 1256 var privValue privileges.GlobalPrivValue 1257 err = gjson.Unmarshal(replog.Slice(privData), &privValue) 1258 if err != nil { 1259 return errors.Trace(err) 1260 } 1261 require = privValue.RequireStr() 1262 } 1263 showStr := fmt.Sprintf("CREATE USER '%s'@'%s' IDENTIFIED WITH 'mysql_native_password' AS '%s' REQUIRE %s PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK", 1264 e.User.Username, e.User.Hostname, checker.GetEncodedPassword(e.User.Username, e.User.Hostname), require) 1265 e.appendEvent([]interface{}{showStr}) 1266 return nil 1267 } 1268 1269 func (e *ShowInterDirc) fetchShowGrants() error { 1270 // Get checker 1271 checker := privilege.GetPrivilegeManager(e.ctx) 1272 if checker == nil { 1273 return errors.New("miss privilege checker") 1274 } 1275 sessVars := e.ctx.GetStochastikVars() 1276 if !e.User.CurrentUser { 1277 userName := sessVars.User.AuthUsername 1278 hostName := sessVars.User.AuthHostname 1279 // Show grant user requires the SELECT privilege on allegrosql schemaReplicant. 1280 // Ref https://dev.allegrosql.com/doc/refman/8.0/en/show-grants.html 1281 if userName != e.User.Username || hostName != e.User.Hostname { 1282 activeRoles := sessVars.ActiveRoles 1283 if !checker.RequestVerification(activeRoles, allegrosql.SystemDB, "", "", allegrosql.SelectPriv) { 1284 return ErrDBaccessDenied.GenWithStackByArgs(userName, hostName, allegrosql.SystemDB) 1285 } 1286 } 1287 } 1288 for _, r := range e.Roles { 1289 if r.Hostname == "" { 1290 r.Hostname = "%" 1291 } 1292 if !checker.FindEdge(e.ctx, r, e.User) { 1293 return ErrRoleNotGranted.GenWithStackByArgs(r.String(), e.User.String()) 1294 } 1295 } 1296 gs, err := checker.ShowGrants(e.ctx, e.User, e.Roles) 1297 if err != nil { 1298 return errors.Trace(err) 1299 } 1300 for _, g := range gs { 1301 e.appendEvent([]interface{}{g}) 1302 } 1303 return nil 1304 } 1305 1306 func (e *ShowInterDirc) fetchShowPrivileges() error { 1307 e.appendEvent([]interface{}{"Alter", "Blocks", "To alter the causet"}) 1308 e.appendEvent([]interface{}{"Alter", "Blocks", "To alter the causet"}) 1309 e.appendEvent([]interface{}{"Alter routine", "Functions,Procedures", "To alter or drop stored functions/procedures"}) 1310 e.appendEvent([]interface{}{"Create", "Databases,Blocks,Indexes", "To create new databases and blocks"}) 1311 e.appendEvent([]interface{}{"Create routine", "Databases", "To use CREATE FUNCTION/PROCEDURE"}) 1312 e.appendEvent([]interface{}{"Create temporary blocks", "Databases", "To use CREATE TEMPORARY TABLE"}) 1313 e.appendEvent([]interface{}{"Create view", "Blocks", "To create new views"}) 1314 e.appendEvent([]interface{}{"Create user", "Server Admin", "To create new users"}) 1315 e.appendEvent([]interface{}{"Delete", "Blocks", "To delete existing rows"}) 1316 e.appendEvent([]interface{}{"Drop", "Databases,Blocks", "To drop databases, blocks, and views"}) 1317 e.appendEvent([]interface{}{"Event", "Server Admin", "To create, alter, drop and execute events"}) 1318 e.appendEvent([]interface{}{"InterDircute", "Functions,Procedures", "To execute stored routines"}) 1319 e.appendEvent([]interface{}{"File", "File access on server", "To read and write files on the server"}) 1320 e.appendEvent([]interface{}{"Grant option", "Databases,Blocks,Functions,Procedures", "To give to other users those privileges you possess"}) 1321 e.appendEvent([]interface{}{"Index", "Blocks", "To create or drop indexes"}) 1322 e.appendEvent([]interface{}{"Insert", "Blocks", "To insert data into blocks"}) 1323 e.appendEvent([]interface{}{"Lock blocks", "Databases", "To use LOCK TABLES (together with SELECT privilege)"}) 1324 e.appendEvent([]interface{}{"Process", "Server Admin", "To view the plain text of currently executing queries"}) 1325 e.appendEvent([]interface{}{"Proxy", "Server Admin", "To make proxy user possible"}) 1326 e.appendEvent([]interface{}{"References", "Databases,Blocks", "To have references on blocks"}) 1327 e.appendEvent([]interface{}{"Reload", "Server Admin", "To reload or refresh blocks, logs and privileges"}) 1328 e.appendEvent([]interface{}{"Replication client", "Server Admin", "To ask where the slave or master servers are"}) 1329 e.appendEvent([]interface{}{"Replication slave", "Server Admin", "To read binary log events from the master"}) 1330 e.appendEvent([]interface{}{"Select", "Blocks", "To retrieve rows from causet"}) 1331 e.appendEvent([]interface{}{"Show databases", "Server Admin", "To see all databases with SHOW DATABASES"}) 1332 e.appendEvent([]interface{}{"Show view", "Blocks", "To see views with SHOW CREATE VIEW"}) 1333 e.appendEvent([]interface{}{"Shutdown", "Server Admin", "To shut down the server"}) 1334 e.appendEvent([]interface{}{"Super", "Server Admin", "To use KILL thread, SET GLOBAL, CHANGE MASTER, etc."}) 1335 e.appendEvent([]interface{}{"Trigger", "Blocks", "To use triggers"}) 1336 e.appendEvent([]interface{}{"Create blockspace", "Server Admin", "To create/alter/drop blockspaces"}) 1337 e.appendEvent([]interface{}{"UFIDelate", "Blocks", "To uFIDelate existing rows"}) 1338 e.appendEvent([]interface{}{"Usage", "Server Admin", "No privileges - allow connect only"}) 1339 return nil 1340 } 1341 1342 func (e *ShowInterDirc) fetchShowTriggers() error { 1343 return nil 1344 } 1345 1346 func (e *ShowInterDirc) fetchShowProcedureStatus() error { 1347 return nil 1348 } 1349 1350 func (e *ShowInterDirc) fetchShowPlugins() error { 1351 tiPlugins := plugin.GetAll() 1352 for _, ps := range tiPlugins { 1353 for _, p := range ps { 1354 e.appendEvent([]interface{}{p.Name, p.StateValue(), p.HoTT.String(), p.Path, p.License, strconv.Itoa(int(p.Version))}) 1355 } 1356 } 1357 return nil 1358 } 1359 1360 func (e *ShowInterDirc) fetchShowWarnings(errOnly bool) error { 1361 warns := e.ctx.GetStochastikVars().StmtCtx.GetWarnings() 1362 for _, w := range warns { 1363 if errOnly && w.Level != stmtctx.WarnLevelError { 1364 continue 1365 } 1366 warn := errors.Cause(w.Err) 1367 switch x := warn.(type) { 1368 case *terror.Error: 1369 sqlErr := terror.ToALLEGROSQLError(x) 1370 e.appendEvent([]interface{}{w.Level, int64(sqlErr.Code), sqlErr.Message}) 1371 default: 1372 e.appendEvent([]interface{}{w.Level, int64(allegrosql.ErrUnknown), warn.Error()}) 1373 } 1374 } 1375 return nil 1376 } 1377 1378 // fetchShowPumpOrDrainerStatus gets status of all pumps or drainers and fill them into e.rows. 1379 func (e *ShowInterDirc) fetchShowPumpOrDrainerStatus(HoTT string) error { 1380 registry, err := createRegistry(config.GetGlobalConfig().Path) 1381 if err != nil { 1382 return errors.Trace(err) 1383 } 1384 1385 nodes, _, err := registry.Nodes(context.Background(), node.NodePrefix[HoTT]) 1386 if err != nil { 1387 return errors.Trace(err) 1388 } 1389 err = registry.Close() 1390 if err != nil { 1391 return errors.Trace(err) 1392 } 1393 1394 for _, n := range nodes { 1395 if n.State == node.Offline { 1396 continue 1397 } 1398 e.appendEvent([]interface{}{n.NodeID, n.Addr, n.State, n.MaxCommitTS, utils.TSOToRoughTime(n.UFIDelateTS).Format(types.TimeFormat)}) 1399 } 1400 1401 return nil 1402 } 1403 1404 // createRegistry returns an ectd registry 1405 func createRegistry(urls string) (*node.EtcdRegistry, error) { 1406 ectdEndpoints, err := utils.ParseHostPortAddr(urls) 1407 if err != nil { 1408 return nil, errors.Trace(err) 1409 } 1410 cli, err := etcd.NewClientFromCfg(ectdEndpoints, etcdDialTimeout, node.DefaultRootPath, nil) 1411 if err != nil { 1412 return nil, errors.Trace(err) 1413 } 1414 1415 return node.NewEtcdRegistry(cli, etcdDialTimeout), nil 1416 } 1417 1418 func (e *ShowInterDirc) getBlock() (causet.Block, error) { 1419 if e.Block == nil { 1420 return nil, errors.New("causet not found") 1421 } 1422 tb, ok := e.is.BlockByID(e.Block.BlockInfo.ID) 1423 if !ok { 1424 return nil, errors.Errorf("causet %s not found", e.Block.Name) 1425 } 1426 return tb, nil 1427 } 1428 1429 func (e *ShowInterDirc) dbAccessDenied() error { 1430 user := e.ctx.GetStochastikVars().User 1431 u := user.Username 1432 h := user.Hostname 1433 if len(user.AuthUsername) > 0 && len(user.AuthHostname) > 0 { 1434 u = user.AuthUsername 1435 h = user.AuthHostname 1436 } 1437 return ErrDBaccessDenied.GenWithStackByArgs(u, h, e.DBName) 1438 } 1439 1440 func (e *ShowInterDirc) blockAccessDenied(access string, causet string) error { 1441 user := e.ctx.GetStochastikVars().User 1442 u := user.Username 1443 h := user.Hostname 1444 if len(user.AuthUsername) > 0 && len(user.AuthHostname) > 0 { 1445 u = user.AuthUsername 1446 h = user.AuthHostname 1447 } 1448 return ErrBlockaccessDenied.GenWithStackByArgs(access, u, h, causet) 1449 } 1450 1451 func (e *ShowInterDirc) appendEvent(event []interface{}) { 1452 for i, defCaus := range event { 1453 if defCaus == nil { 1454 e.result.AppendNull(i) 1455 continue 1456 } 1457 switch x := defCaus.(type) { 1458 case nil: 1459 e.result.AppendNull(i) 1460 case int: 1461 e.result.AppendInt64(i, int64(x)) 1462 case int64: 1463 e.result.AppendInt64(i, x) 1464 case uint64: 1465 e.result.AppendUint64(i, x) 1466 case float64: 1467 e.result.AppendFloat64(i, x) 1468 case float32: 1469 e.result.AppendFloat32(i, x) 1470 case string: 1471 e.result.AppendString(i, x) 1472 case []byte: 1473 e.result.AppendBytes(i, x) 1474 case types.BinaryLiteral: 1475 e.result.AppendBytes(i, x) 1476 case *types.MyDecimal: 1477 e.result.AppendMyDecimal(i, x) 1478 case types.Time: 1479 e.result.AppendTime(i, x) 1480 case json.BinaryJSON: 1481 e.result.AppendJSON(i, x) 1482 case types.Duration: 1483 e.result.AppendDuration(i, x) 1484 case types.Enum: 1485 e.result.AppendEnum(i, x) 1486 case types.Set: 1487 e.result.AppendSet(i, x) 1488 default: 1489 e.result.AppendNull(i) 1490 } 1491 } 1492 } 1493 1494 func (e *ShowInterDirc) fetchShowBlockRegions() error { 1495 causetstore := e.ctx.GetStore() 1496 einsteindbStore, ok := causetstore.(einsteindb.CausetStorage) 1497 if !ok { 1498 return nil 1499 } 1500 splitStore, ok := causetstore.(ekv.SplitblockStore) 1501 if !ok { 1502 return nil 1503 } 1504 1505 tb, err := e.getBlock() 1506 if err != nil { 1507 return errors.Trace(err) 1508 } 1509 1510 physicalIDs := []int64{} 1511 if pi := tb.Meta().GetPartitionInfo(); pi != nil { 1512 for _, name := range e.Block.PartitionNames { 1513 pid, err := blocks.FindPartitionByName(tb.Meta(), name.L) 1514 if err != nil { 1515 return err 1516 } 1517 physicalIDs = append(physicalIDs, pid) 1518 } 1519 if len(physicalIDs) == 0 { 1520 for _, p := range pi.Definitions { 1521 physicalIDs = append(physicalIDs, p.ID) 1522 } 1523 } 1524 } else { 1525 if len(e.Block.PartitionNames) != 0 { 1526 return causetembedded.ErrPartitionClauseOnNonpartitioned 1527 } 1528 physicalIDs = append(physicalIDs, tb.Meta().ID) 1529 } 1530 1531 // Get causet regions from from fidel, not from regionCache, because the region cache maybe outdated. 1532 var regions []regionMeta 1533 if len(e.IndexName.L) != 0 { 1534 indexInfo := tb.Meta().FindIndexByName(e.IndexName.L) 1535 if indexInfo == nil { 1536 return causetembedded.ErrKeyDoesNotExist.GenWithStackByArgs(e.IndexName, tb.Meta().Name) 1537 } 1538 regions, err = getBlockIndexRegions(indexInfo, physicalIDs, einsteindbStore, splitStore) 1539 } else { 1540 regions, err = getBlockRegions(tb, physicalIDs, einsteindbStore, splitStore) 1541 } 1542 1543 if err != nil { 1544 return err 1545 } 1546 e.fillRegionsToChunk(regions) 1547 return nil 1548 } 1549 1550 func getBlockRegions(tb causet.Block, physicalIDs []int64, einsteindbStore einsteindb.CausetStorage, splitStore ekv.SplitblockStore) ([]regionMeta, error) { 1551 regions := make([]regionMeta, 0, len(physicalIDs)) 1552 uniqueRegionMap := make(map[uint64]struct{}) 1553 for _, id := range physicalIDs { 1554 rs, err := getPhysicalBlockRegions(id, tb.Meta(), einsteindbStore, splitStore, uniqueRegionMap) 1555 if err != nil { 1556 return nil, err 1557 } 1558 regions = append(regions, rs...) 1559 } 1560 return regions, nil 1561 } 1562 1563 func getBlockIndexRegions(indexInfo *perceptron.IndexInfo, physicalIDs []int64, einsteindbStore einsteindb.CausetStorage, splitStore ekv.SplitblockStore) ([]regionMeta, error) { 1564 regions := make([]regionMeta, 0, len(physicalIDs)) 1565 uniqueRegionMap := make(map[uint64]struct{}) 1566 for _, id := range physicalIDs { 1567 rs, err := getPhysicalIndexRegions(id, indexInfo, einsteindbStore, splitStore, uniqueRegionMap) 1568 if err != nil { 1569 return nil, err 1570 } 1571 regions = append(regions, rs...) 1572 } 1573 return regions, nil 1574 } 1575 1576 func (e *ShowInterDirc) fillRegionsToChunk(regions []regionMeta) { 1577 for i := range regions { 1578 e.result.AppendUint64(0, regions[i].region.Id) 1579 e.result.AppendString(1, regions[i].start) 1580 e.result.AppendString(2, regions[i].end) 1581 e.result.AppendUint64(3, regions[i].leaderID) 1582 e.result.AppendUint64(4, regions[i].storeID) 1583 1584 peers := "" 1585 for i, peer := range regions[i].region.Peers { 1586 if i > 0 { 1587 peers += ", " 1588 } 1589 peers += strconv.FormatUint(peer.Id, 10) 1590 } 1591 e.result.AppendString(5, peers) 1592 if regions[i].scattering { 1593 e.result.AppendInt64(6, 1) 1594 } else { 1595 e.result.AppendInt64(6, 0) 1596 } 1597 1598 e.result.AppendInt64(7, regions[i].writtenBytes) 1599 e.result.AppendInt64(8, regions[i].readBytes) 1600 e.result.AppendInt64(9, regions[i].approximateSize) 1601 e.result.AppendInt64(10, regions[i].approximateKeys) 1602 } 1603 } 1604 1605 func (e *ShowInterDirc) fetchShowBuiltins() error { 1606 for _, f := range memex.GetBuiltinList() { 1607 e.appendEvent([]interface{}{f}) 1608 } 1609 return nil 1610 }