From 949e4d1cfc9c43c30eddd445201aa56ceadabd2a Mon Sep 17 00:00:00 2001 From: Weizhen Wang Date: Mon, 24 Jan 2022 14:55:49 +0800 Subject: [PATCH 1/7] *: add show push down for ShowTables Signed-off-by: Weizhen Wang --- executor/show.go | 19 ++++++- .../core/memtable_predicate_extractor_test.go | 9 ++++ planner/core/planbuilder.go | 12 ++++- planner/core/show_predicate_extractor.go | 50 ++++++++++++++++++- planner/core/stringer_test.go | 8 +++ 5 files changed, 94 insertions(+), 4 deletions(-) diff --git a/executor/show.go b/executor/show.go index 498825084093d..d564718ef990d 100644 --- a/executor/show.go +++ b/executor/show.go @@ -428,12 +428,29 @@ func (e *ShowExec) fetchShowTables() error { // sort for tables tableNames := make([]string, 0, len(e.is.SchemaTables(e.DBName))) activeRoles := e.ctx.GetSessionVars().ActiveRoles - var tableTypes = make(map[string]string) + 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 e.is.SchemaTables(e.DBName) { // 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() { diff --git a/planner/core/memtable_predicate_extractor_test.go b/planner/core/memtable_predicate_extractor_test.go index 663da2cfb92d2..5414d0ed3f9a6 100644 --- a/planner/core/memtable_predicate_extractor_test.go +++ b/planner/core/memtable_predicate_extractor_test.go @@ -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")) @@ -1693,4 +1694,12 @@ 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.MustGetErrCode("show tables like T", errno.ErrBadField) + tk.MustGetErrCode("show tables like `T`", errno.ErrBadField) } diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index fdfdf8057ce16..e2474ea46a9a4 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -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 to build Selection. + show.Pattern = nil + } + case ast.ShowTableStatus: if p.DBName == "" { return nil, ErrNoDB } diff --git a/planner/core/show_predicate_extractor.go b/planner/core/show_predicate_extractor.go index 0be76a053fd6d..813a9fdf012c1 100644 --- a/planner/core/show_predicate_extractor.go +++ b/planner/core/show_predicate_extractor.go @@ -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. @@ -75,7 +78,6 @@ func (e *ShowColumnsTableExtractor) Extract(show *ast.ShowStmt) bool { return true } return false - } func (e *ShowColumnsTableExtractor) explainInfo() string { @@ -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 FROM t LIKE `abc``. + ptn := pattern.Pattern.(*driver.ValueExpr).GetString() + patValue, patTypes := stringutil.CompilePattern(ptn, pattern.Escape) + if !collate.NewCollationEnabled() && 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 +} diff --git a/planner/core/stringer_test.go b/planner/core/stringer_test.go index 3ca5cbfc66568..5c8b2a4c5d2d6 100644 --- a/planner/core/stringer_test.go +++ b/planner/core/stringer_test.go @@ -56,6 +56,14 @@ 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_pattern:[(?i)t.*])", + }, } parser := parser.New() for _, tt := range tests { From 8ba5e06f3e75a883a54ffd9c2332a47658c5d00c Mon Sep 17 00:00:00 2001 From: Weizhen Wang Date: Mon, 24 Jan 2022 15:47:47 +0800 Subject: [PATCH 2/7] test full tables Signed-off-by: Weizhen Wang --- planner/core/memtable_predicate_extractor_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/planner/core/memtable_predicate_extractor_test.go b/planner/core/memtable_predicate_extractor_test.go index 5414d0ed3f9a6..2e11ed2d2263d 100644 --- a/planner/core/memtable_predicate_extractor_test.go +++ b/planner/core/memtable_predicate_extractor_test.go @@ -1700,6 +1700,7 @@ func TestPredicateQuery(t *testing.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) } From f5c76c18b1e8c4277b6dd8876f81bda94c7fc74d Mon Sep 17 00:00:00 2001 From: Weizhen Wang Date: Mon, 24 Jan 2022 16:28:44 +0800 Subject: [PATCH 3/7] *: delete duplicate operations Signed-off-by: Weizhen Wang --- executor/show.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/executor/show.go b/executor/show.go index d564718ef990d..349a5ad307de5 100644 --- a/executor/show.go +++ b/executor/show.go @@ -426,7 +426,8 @@ 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) @@ -442,7 +443,7 @@ func (e *ShowExec) fetchShowTables() error { FieldFilterEnable = extractor.Field != "" fieldFilter = extractor.Field } - for _, v := range e.is.SchemaTables(e.DBName) { + 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) { From 9b492c514c24d9268b4a45866e1592f89da516f0 Mon Sep 17 00:00:00 2001 From: Weizhen Wang Date: Mon, 24 Jan 2022 16:46:29 +0800 Subject: [PATCH 4/7] *: fix comment Signed-off-by: Weizhen Wang --- planner/core/show_predicate_extractor.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/planner/core/show_predicate_extractor.go b/planner/core/show_predicate_extractor.go index 813a9fdf012c1..28de5ce7c71ff 100644 --- a/planner/core/show_predicate_extractor.go +++ b/planner/core/show_predicate_extractor.go @@ -109,7 +109,7 @@ func (e *ShowTablesTableExtractor) Extract(show *ast.ShowStmt) bool { pattern := show.Pattern switch pattern.Pattern.(type) { case *driver.ValueExpr: - // It is used in `SHOW TABLE FROM t LIKE `abc``. + // It is used in `SHOW TABLE in t LIKE `abc``. ptn := pattern.Pattern.(*driver.ValueExpr).GetString() patValue, patTypes := stringutil.CompilePattern(ptn, pattern.Escape) if !collate.NewCollationEnabled() && stringutil.IsExactMatch(patTypes) { From eb77e6b2cda7c4cc5922175f9606d02ded160bc9 Mon Sep 17 00:00:00 2001 From: Weizhen Wang Date: Mon, 24 Jan 2022 21:44:22 +0800 Subject: [PATCH 5/7] *: add test for plan stringer Signed-off-by: Weizhen Wang --- planner/core/stringer_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/planner/core/stringer_test.go b/planner/core/stringer_test.go index 5c8b2a4c5d2d6..e4163c7c29c8e 100644 --- a/planner/core/stringer_test.go +++ b/planner/core/stringer_test.go @@ -60,10 +60,18 @@ func TestPlanStringer(t *testing.T) { 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 { From b33342416c00c3eb46688ca0bd43a849500639e5 Mon Sep 17 00:00:00 2001 From: Weizhen Wang Date: Tue, 25 Jan 2022 11:37:54 +0800 Subject: [PATCH 6/7] Update planner/core/planbuilder.go Co-authored-by: Lynn --- planner/core/planbuilder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index e2474ea46a9a4..61246210f7c65 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -2883,7 +2883,7 @@ func (b *PlanBuilder) buildShow(ctx context.Context, show *ast.ShowStmt) (Plan, var extractor ShowTablesTableExtractor if extractor.Extract(show) { p.Extractor = &extractor - // avoid to build Selection. + // Avoid building Selection. show.Pattern = nil } case ast.ShowTableStatus: From 8245dc20d744a7e5b48a385d6b442afbf4e9d032 Mon Sep 17 00:00:00 2001 From: Weizhen Wang Date: Wed, 26 Jan 2022 16:48:44 +0800 Subject: [PATCH 7/7] remove new collation conditional Signed-off-by: Weizhen Wang --- planner/core/show_predicate_extractor.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/planner/core/show_predicate_extractor.go b/planner/core/show_predicate_extractor.go index 28de5ce7c71ff..103c4107c7f5e 100644 --- a/planner/core/show_predicate_extractor.go +++ b/planner/core/show_predicate_extractor.go @@ -112,7 +112,7 @@ func (e *ShowTablesTableExtractor) Extract(show *ast.ShowStmt) bool { // It is used in `SHOW TABLE in t LIKE `abc``. ptn := pattern.Pattern.(*driver.ValueExpr).GetString() patValue, patTypes := stringutil.CompilePattern(ptn, pattern.Escape) - if !collate.NewCollationEnabled() && stringutil.IsExactMatch(patTypes) { + if stringutil.IsExactMatch(patTypes) { e.Field = strings.ToLower(string(patValue)) return true }