github.com/dolthub/go-mysql-server@v0.18.0/sql/planbuilder/show.go (about) 1 // Copyright 2023 Dolthub, 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 // 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 planbuilder 16 17 import ( 18 "fmt" 19 "strings" 20 "time" 21 22 "github.com/dolthub/vitess/go/sqltypes" 23 ast "github.com/dolthub/vitess/go/vt/sqlparser" 24 25 "github.com/dolthub/go-mysql-server/sql" 26 "github.com/dolthub/go-mysql-server/sql/binlogreplication" 27 "github.com/dolthub/go-mysql-server/sql/expression" 28 "github.com/dolthub/go-mysql-server/sql/plan" 29 "github.com/dolthub/go-mysql-server/sql/transform" 30 "github.com/dolthub/go-mysql-server/sql/types" 31 ) 32 33 func (b *Builder) buildShow(inScope *scope, s *ast.Show) (outScope *scope) { 34 showType := strings.ToLower(s.Type) 35 switch showType { 36 case "processlist": 37 outScope = inScope.push() 38 outScope.node = plan.NewShowProcessList() 39 case ast.CreateTableStr, "create view": 40 return b.buildShowTable(inScope, s, showType) 41 case "create database", "create schema": 42 return b.buildShowDatabase(inScope, s) 43 case ast.CreateTriggerStr: 44 return b.buildShowTrigger(inScope, s) 45 case ast.CreateProcedureStr: 46 return b.buildShowProcedure(inScope, s) 47 case ast.CreateEventStr: 48 return b.buildShowEvent(inScope, s) 49 case "triggers": 50 return b.buildShowAllTriggers(inScope, s) 51 case "events": 52 return b.buildShowAllEvents(inScope, s) 53 case ast.ProcedureStatusStr: 54 return b.buildShowProcedureStatus(inScope, s) 55 case ast.FunctionStatusStr: 56 return b.buildShowFunctionStatus(inScope, s) 57 case ast.TableStatusStr: 58 return b.buildShowTableStatus(inScope, s) 59 case "index": 60 return b.buildShowIndex(inScope, s) 61 case ast.KeywordString(ast.VARIABLES): 62 return b.buildShowVariables(inScope, s) 63 case ast.KeywordString(ast.TABLES): 64 return b.buildShowAllTables(inScope, s) 65 case ast.KeywordString(ast.DATABASES), ast.KeywordString(ast.SCHEMAS): 66 return b.buildShowAllDatabases(inScope, s) 67 case ast.KeywordString(ast.FIELDS), ast.KeywordString(ast.COLUMNS): 68 return b.buildShowAllColumns(inScope, s) 69 case ast.KeywordString(ast.WARNINGS): 70 return b.buildShowWarnings(inScope, s) 71 case ast.KeywordString(ast.COLLATION): 72 return b.buildShowCollation(inScope, s) 73 case ast.KeywordString(ast.CHARSET): 74 return b.buildShowCharset(inScope, s) 75 case ast.KeywordString(ast.ENGINES): 76 return b.buildShowEngines(inScope, s) 77 case ast.KeywordString(ast.STATUS): 78 return b.buildShowStatus(inScope, s) 79 case ast.KeywordString(ast.PLUGINS): 80 return b.buildShowPlugins(inScope, s) 81 case "replica status": 82 outScope = inScope.push() 83 showRep := plan.NewShowReplicaStatus() 84 if binCat, ok := b.cat.(binlogreplication.BinlogReplicaCatalog); ok && binCat.IsBinlogReplicaCatalog() { 85 showRep.ReplicaController = binCat.GetBinlogReplicaController() 86 } 87 outScope.node = showRep 88 default: 89 unsupportedShow := fmt.Sprintf("SHOW %s", s.Type) 90 b.handleErr(sql.ErrUnsupportedFeature.New(unsupportedShow)) 91 } 92 return 93 } 94 95 func (b *Builder) buildShowTable(inScope *scope, s *ast.Show, showType string) (outScope *scope) { 96 outScope = inScope.push() 97 var asOf *ast.AsOf 98 var asOfExpr sql.Expression 99 if s.ShowTablesOpt != nil && s.ShowTablesOpt.AsOf != nil { 100 asOfExpr = b.buildAsOfExpr(inScope, s.ShowTablesOpt.AsOf) 101 asOf = &ast.AsOf{Time: s.ShowTablesOpt.AsOf} 102 } 103 104 db := s.Database 105 if db == "" { 106 db = s.Table.Qualifier.String() 107 } 108 if db == "" { 109 db = b.currentDb().Name() 110 } 111 112 tableName := strings.ToLower(s.Table.Name.String()) 113 tableScope, ok := b.buildResolvedTable(inScope, db, tableName, asOf) 114 if !ok { 115 err := sql.ErrTableNotFound.New(tableName) 116 b.handleErr(err) 117 } 118 rt, _ := tableScope.node.(*plan.ResolvedTable) 119 for _, c := range tableScope.node.Schema() { 120 outScope.newColumn(scopeColumn{ 121 db: c.DatabaseSource, 122 table: c.Source, 123 col: strings.ToLower(c.Name), 124 typ: c.Type, 125 nullable: c.Nullable, 126 }) 127 } 128 129 showCreate := plan.NewShowCreateTableWithAsOf(tableScope.node, showType == "create view", asOfExpr) 130 outScope.node = showCreate 131 132 if rt != nil { 133 checks := b.loadChecksFromTable(outScope, rt.Table) 134 // To match MySQL output format, transform the column names and wrap with backticks 135 for i, check := range checks { 136 checks[i].Expr, _, _ = transform.Expr(check.Expr, func(e sql.Expression) (sql.Expression, transform.TreeIdentity, error) { 137 if t, ok := e.(*expression.GetField); ok { 138 return expression.NewUnresolvedColumn(fmt.Sprintf("`%s`", t.Name())), transform.NewTree, nil 139 } 140 return e, transform.SameTree, nil 141 }) 142 } 143 showCreate = showCreate.WithChecks(checks).(*plan.ShowCreateTable) 144 145 showCreate.Indexes = b.getInfoSchemaIndexes(rt) 146 147 pks, _ := rt.Table.(sql.PrimaryKeyTable) 148 if pks != nil { 149 showCreate.PrimaryKeySchema = pks.PrimaryKeySchema() 150 } 151 outScope.node = b.modifySchemaTarget(outScope, showCreate, rt) 152 153 } 154 return 155 } 156 157 func (b *Builder) buildShowDatabase(inScope *scope, s *ast.Show) (outScope *scope) { 158 outScope = inScope.push() 159 dbName := s.Database 160 if dbName == "" { 161 dbName = b.ctx.GetCurrentDatabase() 162 } 163 db := b.resolveDb(dbName) 164 outScope.node = plan.NewShowCreateDatabase( 165 db, 166 s.IfNotExists, 167 ) 168 return 169 } 170 171 func (b *Builder) buildShowTrigger(inScope *scope, s *ast.Show) (outScope *scope) { 172 outScope = inScope.push() 173 dbName := s.Table.Qualifier.String() 174 if dbName == "" { 175 dbName = b.ctx.GetCurrentDatabase() 176 } 177 db, err := b.cat.Database(b.ctx, dbName) 178 if err != nil { 179 b.handleErr(err) 180 } 181 outScope.node = plan.NewShowCreateTrigger(db, s.Table.Name.String()) 182 return 183 } 184 185 func (b *Builder) buildShowAllTriggers(inScope *scope, s *ast.Show) (outScope *scope) { 186 dbName := s.Table.Qualifier.String() 187 if dbName == "" { 188 dbName = b.ctx.GetCurrentDatabase() 189 } 190 if dbName == "" && &s.ShowTablesOpt != nil { 191 dbName = s.ShowTablesOpt.DbName 192 } 193 db := b.resolveDb(dbName) 194 195 var node sql.Node = plan.NewShowTriggers(db) 196 197 outScope = inScope.push() 198 for _, c := range node.Schema() { 199 outScope.newColumn(scopeColumn{ 200 db: c.DatabaseSource, 201 table: c.Source, 202 col: strings.ToLower(c.Name), 203 typ: c.Type, 204 nullable: c.Nullable, 205 }) 206 } 207 var filter sql.Expression 208 if s.ShowTablesOpt != nil { 209 dbName = s.ShowTablesOpt.DbName 210 if s.ShowTablesOpt.Filter != nil { 211 if s.ShowTablesOpt.Filter.Filter != nil { 212 filter = b.buildScalar(outScope, s.ShowTablesOpt.Filter.Filter) 213 } else if s.ShowTablesOpt.Filter.Like != "" { 214 filter = expression.NewLike( 215 expression.NewGetField(2, types.LongText, "Table", false), 216 expression.NewLiteral(s.ShowTablesOpt.Filter.Like, types.LongText), 217 nil, 218 ) 219 } 220 } 221 } 222 223 if filter != nil { 224 node = plan.NewFilter(filter, node) 225 } 226 227 outScope.node = node 228 return 229 } 230 231 func (b *Builder) buildShowEvent(inScope *scope, s *ast.Show) (outScope *scope) { 232 outScope = inScope.push() 233 dbName := strings.ToLower(s.Table.Qualifier.String()) 234 if dbName == "" { 235 dbName = b.ctx.GetCurrentDatabase() 236 } 237 238 db := b.resolveDb(dbName) 239 240 eventName := strings.ToLower(s.Table.Name.String()) 241 eventDb, ok := db.(sql.EventDatabase) 242 if !ok { 243 err := sql.ErrEventsNotSupported.New(db.Name()) 244 b.handleErr(err) 245 } 246 247 event, exists, err := eventDb.GetEvent(b.ctx, eventName) 248 if err != nil { 249 b.handleErr(err) 250 } 251 if !exists { 252 err := sql.ErrUnknownEvent.New(eventName) 253 b.handleErr(err) 254 } 255 256 outScope.node = plan.NewShowCreateEvent(db, event) 257 return 258 } 259 260 func (b *Builder) buildShowAllEvents(inScope *scope, s *ast.Show) (outScope *scope) { 261 outScope = inScope.push() 262 var dbName string 263 264 if dbName == "" { 265 dbName = b.ctx.GetCurrentDatabase() 266 } 267 db := b.resolveDb(dbName) 268 showEvents := plan.NewShowEvents(db) 269 showEvents.Events = b.loadAllEventDefinitions(db) 270 271 var node sql.Node = showEvents 272 for _, c := range node.Schema() { 273 outScope.newColumn(scopeColumn{ 274 db: c.DatabaseSource, 275 table: c.Source, 276 col: c.Name, typ: c.Type, nullable: c.Nullable}) 277 } 278 var filter sql.Expression 279 if s.ShowTablesOpt != nil { 280 dbName = s.ShowTablesOpt.DbName 281 if s.ShowTablesOpt.Filter != nil { 282 if s.ShowTablesOpt.Filter.Filter != nil { 283 filter = b.buildScalar(outScope, s.ShowTablesOpt.Filter.Filter) 284 } else if s.ShowTablesOpt.Filter.Like != "" { 285 filter = expression.NewLike( 286 expression.NewGetField(1, types.LongText, "name", false), 287 expression.NewLiteral(s.ShowTablesOpt.Filter.Like, types.LongText), 288 nil, 289 ) 290 } 291 } 292 } 293 if filter != nil { 294 node = plan.NewFilter(filter, node) 295 } 296 297 outScope.node = node 298 return 299 } 300 301 func (b *Builder) loadAllEventDefinitions(db sql.Database) []sql.EventDefinition { 302 if eventDb, ok := db.(sql.EventDatabase); ok { 303 events, _, err := eventDb.GetEvents(b.ctx) 304 if err != nil { 305 b.handleErr(err) 306 } 307 return events 308 } 309 return nil 310 } 311 312 func (b *Builder) buildShowProcedure(inScope *scope, s *ast.Show) (outScope *scope) { 313 outScope = inScope.push() 314 var db sql.Database 315 dbName := s.Table.Qualifier.String() 316 if dbName != "" { 317 db = b.resolveDb(dbName) 318 } else { 319 db = b.currentDb() 320 } 321 outScope.node = plan.NewShowCreateProcedure(db, s.Table.Name.String()) 322 return 323 } 324 325 func (b *Builder) buildShowProcedureStatus(inScope *scope, s *ast.Show) (outScope *scope) { 326 var filter sql.Expression 327 328 node, _, _, err := b.Parse("select routine_schema as `Db`, routine_name as `Name`, routine_type as `Type`,"+ 329 "definer as `Definer`, last_altered as `Modified`, created as `Created`, security_type as `Security_type`,"+ 330 "routine_comment as `Comment`, CHARACTER_SET_CLIENT as `character_set_client`, COLLATION_CONNECTION as `collation_connection`,"+ 331 "database_collation as `Database Collation` from information_schema.routines where routine_type = 'PROCEDURE'", false) 332 if err != nil { 333 b.handleErr(err) 334 } 335 336 outScope = inScope.push() 337 for _, c := range node.Schema() { 338 outScope.newColumn(scopeColumn{ 339 db: c.DatabaseSource, 340 table: c.Source, 341 col: c.Name, typ: c.Type, nullable: c.Nullable}) 342 } 343 if s.Filter != nil { 344 if s.Filter.Filter != nil { 345 filter = b.buildScalar(outScope, s.Filter.Filter) 346 } else if s.Filter.Like != "" { 347 filter = expression.NewLike( 348 expression.NewGetField(1, types.MustCreateString(sqltypes.VarChar, 64, sql.Collation_Information_Schema_Default), "Name", false), 349 expression.NewLiteral(s.Filter.Like, types.LongText), 350 nil, 351 ) 352 } 353 } 354 355 if filter != nil { 356 node = plan.NewHaving(filter, node) 357 } 358 outScope.node = node 359 return 360 } 361 362 func (b *Builder) buildShowFunctionStatus(inScope *scope, s *ast.Show) (outScope *scope) { 363 var filter sql.Expression 364 node, _, _, err := b.Parse("select routine_schema as `Db`, routine_name as `Name`, routine_type as `Type`,"+ 365 "definer as `Definer`, last_altered as `Modified`, created as `Created`, security_type as `Security_type`,"+ 366 "routine_comment as `Comment`, character_set_client, collation_connection,"+ 367 "database_collation as `Database Collation` from information_schema.routines where routine_type = 'FUNCTION'", false) 368 if err != nil { 369 b.handleErr(err) 370 } 371 372 outScope = inScope.push() 373 for _, c := range node.Schema() { 374 outScope.newColumn(scopeColumn{ 375 db: c.DatabaseSource, 376 table: c.Source, 377 col: c.Name, typ: c.Type, nullable: c.Nullable}) 378 } 379 380 if s.Filter != nil { 381 if s.Filter.Filter != nil { 382 filter = b.buildScalar(outScope, s.Filter.Filter) 383 } else if s.Filter.Like != "" { 384 filter = expression.NewLike( 385 expression.NewGetField(1, types.MustCreateString(sqltypes.VarChar, 64, sql.Collation_Information_Schema_Default), "Name", false), 386 expression.NewLiteral(s.Filter.Like, types.LongText), 387 nil, 388 ) 389 } 390 } 391 392 if filter != nil { 393 node = plan.NewHaving(filter, node) 394 } 395 outScope.node = node 396 return 397 } 398 399 func (b *Builder) buildShowTableStatus(inScope *scope, s *ast.Show) (outScope *scope) { 400 dbName := b.ctx.GetCurrentDatabase() 401 if s.Database != "" { 402 dbName = s.Database 403 } 404 405 if dbName == "" { 406 dbName = b.ctx.GetCurrentDatabase() 407 } 408 db := b.resolveDb(dbName) 409 410 showStatus := plan.NewShowTableStatus(db) 411 showStatus.Catalog = b.cat 412 var node sql.Node = showStatus 413 414 outScope = inScope.push() 415 for _, c := range node.Schema() { 416 outScope.newColumn(scopeColumn{ 417 db: c.DatabaseSource, 418 table: c.Source, 419 col: strings.ToLower(c.Name), 420 typ: c.Type, 421 nullable: c.Nullable, 422 }) 423 } 424 425 var filter sql.Expression 426 if s.Filter != nil { 427 if s.Filter.Filter != nil { 428 filter = b.buildScalar(outScope, s.Filter.Filter) 429 } else if s.Filter.Like != "" { 430 filter = expression.NewLike( 431 expression.NewGetField(0, types.LongText, "Name", false), 432 expression.NewLiteral(s.Filter.Like, types.LongText), 433 nil, 434 ) 435 } 436 } 437 438 if filter != nil { 439 node = plan.NewFilter(filter, node) 440 } 441 442 outScope.node = node 443 return 444 } 445 446 func (b *Builder) buildShowIndex(inScope *scope, s *ast.Show) (outScope *scope) { 447 outScope = inScope.push() 448 dbName := strings.ToLower(s.Database) 449 if dbName == "" { 450 dbName = s.Table.Qualifier.String() 451 } 452 if dbName == "" { 453 dbName = b.ctx.GetCurrentDatabase() 454 } 455 tableName := strings.ToLower(s.Table.Name.String()) 456 tableScope, ok := b.buildResolvedTable(inScope, strings.ToLower(dbName), tableName, nil) 457 if !ok { 458 err := sql.ErrTableNotFound.New(tableName) 459 b.handleErr(err) 460 } 461 showIdx := plan.NewShowIndexes(tableScope.node) 462 switch n := tableScope.node.(type) { 463 case *plan.ResolvedTable: 464 showIdx.IndexesToShow = b.getInfoSchemaIndexes(n) 465 case *plan.SubqueryAlias: 466 // views don't have keys 467 showIdx.Child = plan.NewResolvedDualTable() 468 default: 469 err := sql.ErrTableNotFound.New(tableName) 470 b.handleErr(err) 471 } 472 outScope.node = showIdx 473 return 474 } 475 476 func (b *Builder) getInfoSchemaIndexes(rt *plan.ResolvedTable) []sql.Index { 477 it, ok := rt.Table.(sql.IndexAddressableTable) 478 if !ok { 479 return nil 480 } 481 482 indexes, err := it.GetIndexes(b.ctx) 483 if err != nil { 484 b.handleErr(err) 485 } 486 487 for i := 0; i < len(indexes); i++ { 488 // remove generated indexes 489 idx := indexes[i] 490 if idx.IsGenerated() { 491 indexes[i], indexes[len(indexes)-1] = indexes[len(indexes)-1], indexes[i] 492 indexes = indexes[:len(indexes)-1] 493 i-- 494 } 495 } 496 497 if b.ctx.GetIndexRegistry().HasIndexes() { 498 idxRegistry := b.ctx.GetIndexRegistry() 499 for _, idx := range idxRegistry.IndexesByTable(rt.Database().Name(), rt.Table.Name()) { 500 if !idx.IsGenerated() { 501 indexes = append(indexes, idx) 502 } 503 } 504 } 505 506 return indexes 507 } 508 509 func (b *Builder) buildShowVariables(inScope *scope, s *ast.Show) (outScope *scope) { 510 outScope = inScope.push() 511 dummy := &plan.ShowVariables{} 512 for _, c := range dummy.Schema() { 513 outScope.newColumn(scopeColumn{ 514 db: strings.ToLower(c.DatabaseSource), 515 table: strings.ToLower(c.Source), 516 col: strings.ToLower(c.Name), 517 typ: c.Type, 518 nullable: c.Nullable, 519 }) 520 } 521 522 var filter sql.Expression 523 var like sql.Expression 524 if s.Filter != nil { 525 if s.Filter.Filter != nil { 526 filter = b.buildScalar(outScope, s.Filter.Filter) 527 } 528 if s.Filter.Like != "" { 529 like = expression.NewLike( 530 expression.NewGetField(0, types.LongText, "variable_name", false), 531 expression.NewLiteral(s.Filter.Like, types.LongText), 532 nil, 533 ) 534 if filter != nil { 535 filter = expression.NewAnd(like, filter) 536 } else { 537 filter = like 538 } 539 } 540 } 541 if filter == nil { 542 filter = expression.NewLiteral(true, types.Boolean) 543 } 544 outScope.node = plan.NewShowVariables(filter, strings.ToLower(s.Scope) == "global") 545 546 return 547 } 548 549 func (b *Builder) buildAsOfLit(inScope *scope, t ast.Expr) interface{} { 550 expr := b.buildAsOfExpr(inScope, t) 551 res, err := expr.Eval(b.ctx, nil) 552 if err != nil { 553 b.handleErr(err) 554 } 555 switch res.(type) { 556 case string, time.Time: 557 return res 558 } 559 560 if res != nil { 561 err = sql.ErrInvalidAsOfExpression.New(res) 562 } else { 563 err = sql.ErrInvalidAsOfExpression.New(t) 564 } 565 b.handleErr(err) 566 return nil 567 } 568 569 func (b *Builder) buildAsOfExpr(inScope *scope, time ast.Expr) sql.Expression { 570 switch v := time.(type) { 571 case *ast.SQLVal: 572 if v.Type == ast.ValArg && (b.bindCtx == nil || b.bindCtx.resolveOnly) { 573 return nil 574 } 575 repl := b.normalizeValArg(v) 576 val, ok := repl.(*ast.SQLVal) 577 if !ok { 578 // *ast.NullVal 579 return nil 580 } 581 ret, _, err := types.Text.Convert(val.Val) 582 if err != nil { 583 b.handleErr(err) 584 } 585 return expression.NewLiteral(ret.(string), types.LongText) 586 case *ast.ColName: 587 sysVar, _, ok := b.buildSysVar(v, ast.SetScope_None) 588 if ok { 589 return sysVar 590 } 591 return expression.NewLiteral(v.String(), types.LongText) 592 case *ast.FuncExpr: 593 // todo(max): more specific validation for nested ASOF functions 594 if isWindowFunc(v.Name.Lowered()) || isAggregateFunc(v.Name.Lowered()) { 595 err := sql.ErrInvalidAsOfExpression.New(v) 596 b.handleErr(err) 597 } 598 default: 599 } 600 return b.buildScalar(b.newScope(), time) 601 } 602 603 func (b *Builder) buildShowAllTables(inScope *scope, s *ast.Show) (outScope *scope) { 604 outScope = inScope.push() 605 606 var dbName string 607 var filter sql.Expression 608 var asOf sql.Expression 609 if s.ShowTablesOpt != nil { 610 dbName = s.ShowTablesOpt.DbName 611 if s.ShowTablesOpt.AsOf != nil { 612 asOf = b.buildAsOfExpr(inScope, s.ShowTablesOpt.AsOf) 613 } 614 } 615 616 if dbName == "" { 617 dbName = b.ctx.GetCurrentDatabase() 618 } 619 db := b.resolveDb(dbName) 620 621 showTabs := plan.NewShowTables(db, s.Full, asOf) 622 for _, c := range showTabs.Schema() { 623 outScope.newColumn(scopeColumn{ 624 db: strings.ToLower(c.DatabaseSource), 625 table: strings.ToLower(c.Source), 626 col: c.Name, typ: c.Type, nullable: c.Nullable}) 627 } 628 629 if s.ShowTablesOpt.Filter != nil { 630 if s.ShowTablesOpt.Filter.Filter != nil { 631 filter = b.buildScalar(outScope, s.ShowTablesOpt.Filter.Filter) 632 } else if s.ShowTablesOpt.Filter.Like != "" { 633 filter = expression.NewLike( 634 expression.NewGetField(0, types.LongText, fmt.Sprintf("Tables_in_%s", dbName), false), 635 expression.NewLiteral(s.ShowTablesOpt.Filter.Like, types.LongText), 636 nil, 637 ) 638 } 639 } 640 641 outScope.node = showTabs 642 643 if filter != nil { 644 outScope.node = plan.NewFilter(filter, outScope.node) 645 } 646 647 return 648 } 649 650 func (b *Builder) buildShowAllDatabases(inScope *scope, s *ast.Show) (outScope *scope) { 651 showDbs := plan.NewShowDatabases() 652 showDbs.Catalog = b.cat 653 outScope = inScope.push() 654 for _, c := range showDbs.Schema() { 655 outScope.newColumn(scopeColumn{ 656 db: strings.ToLower(c.DatabaseSource), 657 table: strings.ToLower(c.Source), 658 col: c.Name, typ: c.Type, nullable: c.Nullable}) 659 } 660 var filter sql.Expression 661 if s.Filter != nil { 662 if s.Filter.Filter != nil { 663 filter = b.buildScalar(outScope, s.Filter.Filter) 664 } else if s.Filter.Like != "" { 665 filter = expression.NewLike( 666 expression.NewGetField(0, types.LongText, "Database", false), 667 expression.NewLiteral(s.Filter.Like, types.LongText), 668 nil, 669 ) 670 } 671 } 672 outScope.node = showDbs 673 if filter != nil { 674 outScope.node = plan.NewFilter(filter, outScope.node) 675 } 676 return 677 } 678 679 func (b *Builder) buildShowAllColumns(inScope *scope, s *ast.Show) (outScope *scope) { 680 outScope = inScope.push() 681 full := s.Full 682 var table sql.Node 683 684 var asOf *ast.AsOf 685 if s.ShowTablesOpt != nil && s.ShowTablesOpt.AsOf != nil { 686 asOf = &ast.AsOf{Time: s.ShowTablesOpt.AsOf} 687 } 688 689 db := s.Database 690 if db == "" { 691 db = s.Table.Qualifier.String() 692 } 693 if db == "" { 694 db = b.currentDb().Name() 695 } 696 697 tableName := strings.ToLower(s.Table.Name.String()) 698 tableScope, ok := b.buildResolvedTable(inScope, db, tableName, asOf) 699 if !ok { 700 err := sql.ErrTableNotFound.New(tableName) 701 b.handleErr(err) 702 } 703 table = tableScope.node 704 705 show := plan.NewShowColumns(full, table) 706 707 for _, c := range show.Schema() { 708 outScope.newColumn(scopeColumn{ 709 db: strings.ToLower(c.DatabaseSource), 710 table: strings.ToLower(c.Source), 711 col: strings.ToLower(c.Name), 712 typ: c.Type, 713 nullable: c.Nullable, 714 }) 715 } 716 717 var node sql.Node = show 718 switch t := table.(type) { 719 case *plan.ResolvedTable: 720 show.Indexes = b.getInfoSchemaIndexes(t) 721 node = b.modifySchemaTarget(tableScope, show, t) 722 case *plan.SubqueryAlias: 723 var err error 724 node, err = show.WithTargetSchema(t.Schema()) 725 if err != nil { 726 b.handleErr(err) 727 } 728 default: 729 } 730 731 if s.ShowTablesOpt != nil && s.ShowTablesOpt.Filter != nil { 732 if s.ShowTablesOpt.Filter.Like != "" { 733 pattern := expression.NewLiteral(s.ShowTablesOpt.Filter.Like, types.LongText) 734 735 node = plan.NewFilter( 736 expression.NewLike( 737 expression.NewGetField(0, plan.VarChar25000, "Field", false), 738 pattern, 739 nil, 740 ), 741 node, 742 ) 743 } 744 745 if s.ShowTablesOpt.Filter.Filter != nil { 746 filter := b.buildScalar(outScope, s.ShowTablesOpt.Filter.Filter) 747 node = plan.NewFilter(filter, node) 748 } 749 } 750 751 outScope.node = node 752 return 753 } 754 755 func (b *Builder) buildShowWarnings(inScope *scope, s *ast.Show) (outScope *scope) { 756 outScope = inScope.push() 757 if s.CountStar { 758 unsupportedShow := "SHOW COUNT(*) WARNINGS" 759 b.handleErr(sql.ErrUnsupportedFeature.New(unsupportedShow)) 760 } 761 var node sql.Node 762 node = plan.ShowWarnings(b.ctx.Session.Warnings()) 763 if s.Limit != nil { 764 if s.Limit.Offset != nil { 765 offset := b.buildScalar(inScope, s.Limit.Offset) 766 node = plan.NewOffset(offset, node) 767 } 768 limit := b.buildScalar(inScope, s.Limit.Rowcount) 769 node = plan.NewLimit(limit, node) 770 } 771 772 outScope.node = node 773 return 774 } 775 776 func (b *Builder) buildShowCollation(inScope *scope, s *ast.Show) (outScope *scope) { 777 outScope = inScope.push() 778 // show collation statements are functionally identical to selecting from the collations table in 779 // information_schema, with slightly different syntax and with some columns aliased. 780 // TODO: install information_schema automatically for all catalogs 781 node, _, _, err := b.Parse("select collation_name as `collation`, character_set_name as charset, id,"+ 782 "is_default as `default`, is_compiled as compiled, sortlen, pad_attribute from information_schema.collations order by collation_name", false) 783 if err != nil { 784 b.handleErr(err) 785 } 786 787 for _, c := range node.Schema() { 788 outScope.newColumn(scopeColumn{ 789 db: strings.ToLower(c.DatabaseSource), 790 table: strings.ToLower(c.Source), 791 col: strings.ToLower(c.Name), 792 typ: c.Type, 793 nullable: c.Nullable, 794 }) 795 } 796 797 if s.ShowCollationFilterOpt != nil { 798 filterExpr := b.buildScalar(outScope, s.ShowCollationFilterOpt) 799 // TODO: once collations are properly implemented, we should better be able to handle utf8 -> utf8mb3 comparisons as they're aliases 800 filterExpr, _, _ = transform.Expr(filterExpr, func(expr sql.Expression) (sql.Expression, transform.TreeIdentity, error) { 801 if exprLiteral, ok := expr.(*expression.Literal); ok { 802 const utf8Prefix = "utf8_" 803 if strLiteral, ok := exprLiteral.Value().(string); ok && strings.HasPrefix(strLiteral, utf8Prefix) { 804 return expression.NewLiteral("utf8mb3_"+strLiteral[len(utf8Prefix):], exprLiteral.Type()), transform.NewTree, nil 805 } 806 } 807 return expr, transform.SameTree, nil 808 }) 809 node = plan.NewHaving(filterExpr, node) 810 } 811 812 outScope.node = node 813 return 814 } 815 816 func (b *Builder) buildShowEngines(inScope *scope, s *ast.Show) (outScope *scope) { 817 outScope = inScope.push() 818 infoSchemaSelect, _, _, err := b.Parse("select * from information_schema.engines", false) 819 if err != nil { 820 b.handleErr(err) 821 } 822 823 outScope.node = infoSchemaSelect 824 return 825 } 826 827 func (b *Builder) buildShowPlugins(inScope *scope, s *ast.Show) (outScope *scope) { 828 outScope = inScope.push() 829 infoSchemaSelect, _, _, err := b.Parse("select * from information_schema.plugins", false) 830 if err != nil { 831 b.handleErr(err) 832 } 833 834 outScope.node = infoSchemaSelect 835 return 836 } 837 838 func (b *Builder) buildShowStatus(inScope *scope, s *ast.Show) (outScope *scope) { 839 outScope = inScope.push() 840 var node sql.Node 841 if s.Scope == ast.GlobalStr { 842 node = plan.NewShowStatus(plan.ShowStatusModifier_Global) 843 } else { 844 node = plan.NewShowStatus(plan.ShowStatusModifier_Session) 845 } 846 847 for _, c := range node.Schema() { 848 outScope.newColumn(scopeColumn{ 849 db: strings.ToLower(c.DatabaseSource), 850 table: strings.ToLower(c.Source), 851 col: strings.ToLower(c.Name), 852 typ: c.Type, 853 nullable: c.Nullable, 854 }) 855 } 856 857 var filter sql.Expression 858 if s.Filter != nil { 859 if s.Filter.Like != "" { 860 filter = expression.NewLike( 861 expression.NewGetField(0, node.Schema()[0].Type, plan.ShowStatusVariableCol, false), 862 expression.NewLiteral(s.Filter.Like, types.LongText), 863 nil, 864 ) 865 } else if s.Filter.Filter != nil { 866 filter = b.buildScalar(outScope, s.Filter.Filter) 867 } 868 } 869 870 if filter != nil { 871 node = plan.NewFilter(filter, node) 872 } 873 874 outScope.node = node 875 876 return 877 } 878 879 func (b *Builder) buildShowCharset(inScope *scope, s *ast.Show) (outScope *scope) { 880 outScope = inScope.push() 881 882 showCharset := plan.NewShowCharset() 883 showCharset.CharacterSetTable = b.resolveTable("character_sets", "information_schema", nil) 884 885 var node sql.Node = showCharset 886 for _, c := range node.Schema() { 887 outScope.newColumn(scopeColumn{ 888 db: strings.ToLower(c.DatabaseSource), 889 table: strings.ToLower(c.Source), 890 col: c.Name, typ: c.Type, nullable: c.Nullable}) 891 } 892 893 var filter sql.Expression 894 if s.Filter != nil { 895 if s.Filter.Filter != nil { 896 filter = b.buildScalar(outScope, s.Filter.Filter) 897 } else if s.Filter.Like != "" { 898 filter = expression.NewLike( 899 expression.NewGetField(0, types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), "Charset", false), 900 expression.NewLiteral(s.Filter.Like, types.LongText), 901 nil, 902 ) 903 } 904 } 905 906 if filter != nil { 907 node = plan.NewFilter(filter, node) 908 } 909 outScope.node = node 910 return 911 }