Skip to content

Commit

Permalink
*: add show push down for ShowTables (#31919)
Browse files Browse the repository at this point in the history
close #30803
  • Loading branch information
hawkingrei authored Jan 26, 2022
1 parent 6a53a03 commit 93454da
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 6 deletions.
24 changes: 21 additions & 3 deletions executor/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,14 +426,32 @@ func (e *ShowExec) fetchShowTables() error {
return ErrBadDB.GenWithStackByArgs(e.DBName)
}
// sort for tables
tableNames := make([]string, 0, len(e.is.SchemaTables(e.DBName)))
schemaTables := e.is.SchemaTables(e.DBName)
tableNames := make([]string, 0, len(schemaTables))
activeRoles := e.ctx.GetSessionVars().ActiveRoles
var tableTypes = make(map[string]string)
for _, v := range e.is.SchemaTables(e.DBName) {
var (
tableTypes = make(map[string]string)
fieldPatternsRegexp *regexp.Regexp
FieldFilterEnable bool
fieldFilter string
)
if e.Extractor != nil {
extractor := (e.Extractor).(*plannercore.ShowTablesTableExtractor)
if extractor.FieldPatterns != "" {
fieldPatternsRegexp = regexp.MustCompile(extractor.FieldPatterns)
}
FieldFilterEnable = extractor.Field != ""
fieldFilter = extractor.Field
}
for _, v := range schemaTables {
// Test with mysql.AllPrivMask means any privilege would be OK.
// TODO: Should consider column privileges, which also make a table visible.
if checker != nil && !checker.RequestVerification(activeRoles, e.DBName.O, v.Meta().Name.O, "", mysql.AllPrivMask) {
continue
} else if FieldFilterEnable && v.Meta().Name.L != fieldFilter {
continue
} else if fieldPatternsRegexp != nil && !fieldPatternsRegexp.MatchString(v.Meta().Name.L) {
continue
}
tableNames = append(tableNames, v.Meta().Name.O)
if v.Meta().IsView() {
Expand Down
10 changes: 10 additions & 0 deletions planner/core/memtable_predicate_extractor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1661,6 +1661,7 @@ func TestPredicateQuery(t *testing.T) {
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create table t(id int, abclmn int);")
tk.MustExec("create table abclmn(a int);")
tk.MustQuery("select TABLE_NAME from information_schema.columns where table_schema = 'test' and column_name like 'i%'").Check(testkit.Rows("t"))
tk.MustQuery("select TABLE_NAME from information_schema.columns where table_schema = 'TEST' and column_name like 'I%'").Check(testkit.Rows("t"))
tk.MustQuery("select TABLE_NAME from information_schema.columns where table_schema = 'TEST' and column_name like 'ID'").Check(testkit.Rows("t"))
Expand Down Expand Up @@ -1693,4 +1694,13 @@ func TestPredicateQuery(t *testing.T) {

tk.MustGetErrCode("show columns from t like id", errno.ErrBadField)
tk.MustGetErrCode("show columns from t like `id`", errno.ErrBadField)

tk.MustQuery("show tables like 't'").Check(testkit.Rows("t"))
tk.MustQuery("show tables like 'T'").Check(testkit.Rows("t"))
tk.MustQuery("show tables like 'ABCLMN'").Check(testkit.Rows("abclmn"))
tk.MustQuery("show tables like 'ABC%'").Check(testkit.Rows("abclmn"))
tk.MustQuery("show tables like '%lmn'").Check(testkit.Rows("abclmn"))
tk.MustQuery("show full tables like '%lmn'").Check(testkit.Rows("abclmn BASE TABLE"))
tk.MustGetErrCode("show tables like T", errno.ErrBadField)
tk.MustGetErrCode("show tables like `T`", errno.ErrBadField)
}
12 changes: 11 additions & 1 deletion planner/core/planbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2876,7 +2876,17 @@ func (b *PlanBuilder) buildShow(ctx context.Context, show *ast.ShowStmt) (Plan,
// avoid to build Selection.
show.Pattern = nil
}
case ast.ShowTables, ast.ShowTableStatus:
case ast.ShowTables:
if p.DBName == "" {
return nil, ErrNoDB
}
var extractor ShowTablesTableExtractor
if extractor.Extract(show) {
p.Extractor = &extractor
// Avoid building Selection.
show.Pattern = nil
}
case ast.ShowTableStatus:
if p.DBName == "" {
return nil, ErrNoDB
}
Expand Down
50 changes: 48 additions & 2 deletions planner/core/show_predicate_extractor.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ import (
"github.com/pingcap/tidb/util/stringutil"
)

var _ ShowPredicateExtractor = &ShowColumnsTableExtractor{}
var (
_ ShowPredicateExtractor = &ShowColumnsTableExtractor{}
_ ShowPredicateExtractor = &ShowTablesTableExtractor{}
)

// ShowPredicateExtractor is used to extract some predicates from `PatternLikeExpr` clause
// and push the predicates down to the data retrieving on reading memory table stage when use ShowStmt.
Expand Down Expand Up @@ -75,7 +78,6 @@ func (e *ShowColumnsTableExtractor) Extract(show *ast.ShowStmt) bool {
return true
}
return false

}

func (e *ShowColumnsTableExtractor) explainInfo() string {
Expand All @@ -95,3 +97,47 @@ func (e *ShowColumnsTableExtractor) explainInfo() string {
}
return s
}

// ShowTablesTableExtractor is used to extract some predicates of tables.
type ShowTablesTableExtractor struct {
ShowColumnsTableExtractor
}

// Extract implements the ShowTablesTableExtractor Extract interface
func (e *ShowTablesTableExtractor) Extract(show *ast.ShowStmt) bool {
if show.Pattern != nil && show.Pattern.Pattern != nil {
pattern := show.Pattern
switch pattern.Pattern.(type) {
case *driver.ValueExpr:
// It is used in `SHOW TABLE in t LIKE `abc``.
ptn := pattern.Pattern.(*driver.ValueExpr).GetString()
patValue, patTypes := stringutil.CompilePattern(ptn, pattern.Escape)
if stringutil.IsExactMatch(patTypes) {
e.Field = strings.ToLower(string(patValue))
return true
}
// (?i) mean to be case-insensitive.
e.FieldPatterns = "(?i)" + stringutil.CompileLike2Regexp(string(patValue))
return true
}
}
return false
}

func (e *ShowTablesTableExtractor) explainInfo() string {
r := new(bytes.Buffer)
if len(e.Field) > 0 {
r.WriteString(fmt.Sprintf("table:[%s], ", e.Field))
}

if len(e.FieldPatterns) > 0 {
r.WriteString(fmt.Sprintf("table_pattern:[%s], ", e.FieldPatterns))
}

// remove the last ", " in the message info
s := r.String()
if len(s) > 2 {
return s[:len(s)-2]
}
return s
}
16 changes: 16 additions & 0 deletions planner/core/stringer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,22 @@ func TestPlanStringer(t *testing.T) {
sql: "desc t a",
plan: "Show(field:[a])",
},
{
sql: "show tables in test like 't'",
plan: "Show(table:[t])",
},
{
sql: "show tables in test like 'T'",
plan: "Show(table:[t])",
},
{
sql: "show tables in test like 't%'",
plan: "Show(table_pattern:[(?i)t.*])",
},
{
sql: "show tables in test like '%T%'",
plan: "Show(table_pattern:[(?i).*T.*])",
},
}
parser := parser.New()
for _, tt := range tests {
Expand Down

0 comments on commit 93454da

Please sign in to comment.