Skip to content

Commit

Permalink
planner: misuse like2regexp and regexp when to query information.sche…
Browse files Browse the repository at this point in the history
…ma (#32490)

close #32451
  • Loading branch information
hawkingrei authored Mar 10, 2022
1 parent b9416e1 commit 284b90d
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 68 deletions.
24 changes: 13 additions & 11 deletions executor/infoschema_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"fmt"
"io"
"net/http"
"regexp"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -682,29 +681,32 @@ func (e *hugeMemTableRetriever) dataForColumnsInTable(ctx context.Context, sctx
sctx.GetSessionVars().StmtCtx.AppendWarning(err)
return
}
var tableSchemaRegexp, tableNameRegexp, columnsRegexp []*regexp.Regexp
var tableSchemaRegexp, tableNameRegexp, columnsRegexp []collate.WildcardPattern
var tableSchemaFilterEnable,
tableNameFilterEnable, columnsFilterEnable bool
if !extractor.SkipRequest {
tableSchemaFilterEnable = extractor.TableSchema.Count() > 0
tableNameFilterEnable = extractor.TableName.Count() > 0
columnsFilterEnable = extractor.ColumnName.Count() > 0
if len(extractor.TableSchemaPatterns) > 0 {
tableSchemaRegexp = make([]*regexp.Regexp, len(extractor.TableSchemaPatterns))
tableSchemaRegexp = make([]collate.WildcardPattern, len(extractor.TableSchemaPatterns))
for i, pattern := range extractor.TableSchemaPatterns {
tableSchemaRegexp[i] = regexp.MustCompile(pattern)
tableSchemaRegexp[i] = collate.GetCollatorByID(collate.CollationName2ID(mysql.UTF8MB4DefaultCollation)).Pattern()
tableSchemaRegexp[i].Compile(pattern, byte('\\'))
}
}
if len(extractor.TableNamePatterns) > 0 {
tableNameRegexp = make([]*regexp.Regexp, len(extractor.TableNamePatterns))
tableNameRegexp = make([]collate.WildcardPattern, len(extractor.TableNamePatterns))
for i, pattern := range extractor.TableNamePatterns {
tableNameRegexp[i] = regexp.MustCompile(pattern)
tableNameRegexp[i] = collate.GetCollatorByID(collate.CollationName2ID(mysql.UTF8MB4DefaultCollation)).Pattern()
tableNameRegexp[i].Compile(pattern, byte('\\'))
}
}
if len(extractor.ColumnNamePatterns) > 0 {
columnsRegexp = make([]*regexp.Regexp, len(extractor.ColumnNamePatterns))
columnsRegexp = make([]collate.WildcardPattern, len(extractor.ColumnNamePatterns))
for i, pattern := range extractor.ColumnNamePatterns {
columnsRegexp[i] = regexp.MustCompile(pattern)
columnsRegexp[i] = collate.GetCollatorByID(collate.CollationName2ID(mysql.UTF8MB4DefaultCollation)).Pattern()
columnsRegexp[i].Compile(pattern, byte('\\'))
}
}
}
Expand All @@ -724,17 +726,17 @@ ForColumnsTag:
continue
}
for _, re := range tableSchemaRegexp {
if !re.MatchString(schema.Name.L) {
if !re.DoMatch(schema.Name.L) {
continue ForColumnsTag
}
}
for _, re := range tableNameRegexp {
if !re.MatchString(tbl.Name.L) {
if !re.DoMatch(tbl.Name.L) {
continue ForColumnsTag
}
}
for _, re := range columnsRegexp {
if !re.MatchString(col.Name.L) {
if !re.DoMatch(col.Name.L) {
continue ForColumnsTag
}
}
Expand Down
25 changes: 13 additions & 12 deletions executor/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"context"
gjson "encoding/json"
"fmt"
"regexp"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -430,15 +429,16 @@ func (e *ShowExec) fetchShowTables() error {
tableNames := make([]string, 0, len(schemaTables))
activeRoles := e.ctx.GetSessionVars().ActiveRoles
var (
tableTypes = make(map[string]string)
fieldPatternsRegexp *regexp.Regexp
FieldFilterEnable bool
fieldFilter string
tableTypes = make(map[string]string)
fieldPatternsLike collate.WildcardPattern
FieldFilterEnable bool
fieldFilter string
)
if e.Extractor != nil {
extractor := (e.Extractor).(*plannercore.ShowTablesTableExtractor)
if extractor.FieldPatterns != "" {
fieldPatternsRegexp = regexp.MustCompile(extractor.FieldPatterns)
fieldPatternsLike = collate.GetCollatorByID(collate.CollationName2ID(mysql.UTF8MB4DefaultCollation)).Pattern()
fieldPatternsLike.Compile(extractor.FieldPatterns, byte('\\'))
}
FieldFilterEnable = extractor.Field != ""
fieldFilter = extractor.Field
Expand All @@ -450,7 +450,7 @@ func (e *ShowExec) fetchShowTables() error {
continue
} else if FieldFilterEnable && v.Meta().Name.L != fieldFilter {
continue
} else if fieldPatternsRegexp != nil && !fieldPatternsRegexp.MatchString(v.Meta().Name.L) {
} else if fieldPatternsLike != nil && !fieldPatternsLike.DoMatch(v.Meta().Name.L) {
continue
}
tableNames = append(tableNames, v.Meta().Name.O)
Expand Down Expand Up @@ -528,14 +528,15 @@ func (e *ShowExec) fetchShowColumns(ctx context.Context) error {
return errors.Trace(err)
}
var (
fieldPatternsRegexp *regexp.Regexp
FieldFilterEnable bool
fieldFilter string
fieldPatternsLike collate.WildcardPattern
FieldFilterEnable bool
fieldFilter string
)
if e.Extractor != nil {
extractor := (e.Extractor).(*plannercore.ShowColumnsTableExtractor)
if extractor.FieldPatterns != "" {
fieldPatternsRegexp = regexp.MustCompile(extractor.FieldPatterns)
fieldPatternsLike = collate.GetCollatorByID(collate.CollationName2ID(mysql.UTF8MB4DefaultCollation)).Pattern()
fieldPatternsLike.Compile(extractor.FieldPatterns, byte('\\'))
}
FieldFilterEnable = extractor.Field != ""
fieldFilter = extractor.Field
Expand All @@ -561,7 +562,7 @@ func (e *ShowExec) fetchShowColumns(ctx context.Context) error {
for _, col := range cols {
if FieldFilterEnable && col.Name.L != fieldFilter {
continue
} else if fieldPatternsRegexp != nil && !fieldPatternsRegexp.MatchString(col.Name.L) {
} else if fieldPatternsLike != nil && !fieldPatternsLike.DoMatch(col.Name.L) {
continue
}
desc := table.NewColDesc(col)
Expand Down
26 changes: 16 additions & 10 deletions planner/core/memtable_predicate_extractor.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ func (helper extractHelper) extractLikePatternCol(
predicates []expression.Expression,
extractColName string,
toLower bool,
needLike2Regexp bool,
) (
remained []expression.Expression,
patterns []string,
Expand All @@ -263,13 +264,13 @@ func (helper extractHelper) extractLikePatternCol(
// We use '|' to combine DNF regular expression: .*a.*|.*b.*
// e.g:
// SELECT * FROM t WHERE c LIKE '%a%' OR c LIKE '%b%'
if fn.FuncName.L == ast.LogicOr {
canBuildPattern, pattern = helper.extractOrLikePattern(fn, extractColName, extractCols)
if fn.FuncName.L == ast.LogicOr && !toLower {
canBuildPattern, pattern = helper.extractOrLikePattern(fn, extractColName, extractCols, needLike2Regexp)
} else {
canBuildPattern, pattern = helper.extractLikePattern(fn, extractColName, extractCols)
canBuildPattern, pattern = helper.extractLikePattern(fn, extractColName, extractCols, needLike2Regexp)
}
if canBuildPattern && toLower {
pattern = "(?i)" + pattern
pattern = strings.ToLower(pattern)
}
if canBuildPattern {
patterns = append(patterns, pattern)
Expand All @@ -284,6 +285,7 @@ func (helper extractHelper) extractOrLikePattern(
orFunc *expression.ScalarFunction,
extractColName string,
extractCols map[int64]*types.FieldName,
needLike2Regexp bool,
) (
ok bool,
pattern string,
Expand All @@ -300,7 +302,7 @@ func (helper extractHelper) extractOrLikePattern(
return false, ""
}

ok, partPattern := helper.extractLikePattern(fn, extractColName, extractCols)
ok, partPattern := helper.extractLikePattern(fn, extractColName, extractCols, needLike2Regexp)
if !ok {
return false, ""
}
Expand All @@ -313,6 +315,7 @@ func (helper extractHelper) extractLikePattern(
fn *expression.ScalarFunction,
extractColName string,
extractCols map[int64]*types.FieldName,
needLike2Regexp bool,
) (
ok bool,
pattern string,
Expand All @@ -328,7 +331,10 @@ func (helper extractHelper) extractLikePattern(
case ast.EQ:
return true, "^" + regexp.QuoteMeta(datums[0].GetString()) + "$"
case ast.Like:
return true, stringutil.CompileLike2Regexp(datums[0].GetString())
if needLike2Regexp {
return true, stringutil.CompileLike2Regexp(datums[0].GetString())
}
return true, datums[0].GetString()
case ast.Regexp:
return true, datums[0].GetString()
default:
Expand Down Expand Up @@ -682,7 +688,7 @@ func (e *ClusterLogTableExtractor) Extract(
return nil
}

remained, patterns := e.extractLikePatternCol(schema, names, remained, "message", false)
remained, patterns := e.extractLikePatternCol(schema, names, remained, "message", false, true)
e.Patterns = patterns
return remained
}
Expand Down Expand Up @@ -1506,9 +1512,9 @@ func (e *ColumnsTableExtractor) Extract(_ sessionctx.Context,
if e.SkipRequest {
return
}
remained, tableSchemaPatterns := e.extractLikePatternCol(schema, names, remained, "table_schema", true)
remained, tableNamePatterns := e.extractLikePatternCol(schema, names, remained, "table_name", true)
remained, columnNamePatterns := e.extractLikePatternCol(schema, names, remained, "column_name", true)
remained, tableSchemaPatterns := e.extractLikePatternCol(schema, names, remained, "table_schema", true, false)
remained, tableNamePatterns := e.extractLikePatternCol(schema, names, remained, "table_name", true, false)
remained, columnNamePatterns := e.extractLikePatternCol(schema, names, remained, "column_name", true, false)

e.ColumnName = columnName
e.TableName = tableName
Expand Down
52 changes: 27 additions & 25 deletions planner/core/memtable_predicate_extractor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1598,23 +1598,23 @@ func TestColumns(t *testing.T) {
},
{
sql: `select * from information_schema.COLUMNS where table_name like 'T%';`,
tableNamePattern: []string{"(?i)T.*"},
tableNamePattern: []string{"t%"},
},
{
sql: `select * from information_schema.COLUMNS where column_name like 'T%';`,
columnNamePattern: []string{"(?i)T.*"},
columnNamePattern: []string{"t%"},
},
{
sql: `select * from information_schema.COLUMNS where column_name like 'i%';`,
columnNamePattern: []string{"(?i)i.*"},
columnNamePattern: []string{"i%"},
},
{
sql: `select * from information_schema.COLUMNS where column_name like 'abc%' or column_name like "def%";`,
columnNamePattern: []string{"(?i)abc.*|def.*"},
columnNamePattern: []string{},
},
{
sql: `select * from information_schema.COLUMNS where column_name like 'abc%' and column_name like "%def";`,
columnNamePattern: []string{"(?i)abc.*", "(?i).*def"},
columnNamePattern: []string{"abc%", "%def"},
},
}
parser := parser.New()
Expand Down Expand Up @@ -1659,37 +1659,39 @@ 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 t(id int, abctime int,DATETIME_PRECISION 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"))
tk.MustQuery("select TABLE_NAME from information_schema.columns where table_schema = 'TEST' and column_name like 'id'").Check(testkit.Rows("t"))
tk.MustQuery("select column_name from information_schema.columns where table_schema = 'TEST' and (column_name like 'I%' or column_name like '%D')").Check(testkit.Rows("id"))
tk.MustQuery("select column_name from information_schema.columns where table_schema = 'TEST' and (column_name like 'abc%' and column_name like '%lmn')").Check(testkit.Rows("abclmn"))
tk.MustQuery("describe t").Check(testkit.Rows("id int(11) YES <nil> ", "abclmn int(11) YES <nil> "))
tk.MustQuery("select column_name from information_schema.columns where table_schema = 'TEST' and (column_name like 'i%' or column_name like '%d')").Check(testkit.Rows("id"))
tk.MustQuery("select column_name from information_schema.columns where table_schema = 'TEST' and (column_name like 'abc%' and column_name like '%time')").Check(testkit.Rows("abctime"))
result := tk.MustQuery("select TABLE_NAME, column_name from information_schema.columns where table_schema = 'TEST' and column_name like '%time';")
require.Len(t, result.Rows(), 1)
tk.MustQuery("describe t").Check(testkit.Rows("id int(11) YES <nil> ", "abctime int(11) YES <nil> ", "DATETIME_PRECISION int(11) YES <nil> "))
tk.MustQuery("describe t id").Check(testkit.Rows("id int(11) YES <nil> "))
tk.MustQuery("describe t ID").Check(testkit.Rows("id int(11) YES <nil> "))
tk.MustGetErrCode("describe t 'I%'", errno.ErrParse)
tk.MustGetErrCode("describe t I%", errno.ErrParse)

tk.MustQuery("show columns from t like 'abclmn'").Check(testkit.RowsWithSep(",", "abclmn,int(11),YES,,<nil>,"))
tk.MustQuery("show columns from t like 'ABCLMN'").Check(testkit.RowsWithSep(",", "abclmn,int(11),YES,,<nil>,"))
tk.MustQuery("show columns from t like 'abc%'").Check(testkit.RowsWithSep(",", "abclmn,int(11),YES,,<nil>,"))
tk.MustQuery("show columns from t like 'ABC%'").Check(testkit.RowsWithSep(",", "abclmn,int(11),YES,,<nil>,"))
tk.MustQuery("show columns from t like '%lmn'").Check(testkit.RowsWithSep(",", "abclmn,int(11),YES,,<nil>,"))
tk.MustQuery("show columns from t like '%LMN'").Check(testkit.RowsWithSep(",", "abclmn,int(11),YES,,<nil>,"))
tk.MustQuery("show columns in t like '%lmn'").Check(testkit.RowsWithSep(",", "abclmn,int(11),YES,,<nil>,"))
tk.MustQuery("show columns in t like '%LMN'").Check(testkit.RowsWithSep(",", "abclmn,int(11),YES,,<nil>,"))
tk.MustQuery("show fields in t like '%lmn'").Check(testkit.RowsWithSep(",", "abclmn,int(11),YES,,<nil>,"))
tk.MustQuery("show fields in t like '%LMN'").Check(testkit.RowsWithSep(",", "abclmn,int(11),YES,,<nil>,"))
tk.MustQuery("show columns from t like 'abctime'").Check(testkit.RowsWithSep(",", "abctime,int(11),YES,,<nil>,"))
tk.MustQuery("show columns from t like 'ABCTIME'").Check(testkit.RowsWithSep(",", "abctime,int(11),YES,,<nil>,"))
tk.MustQuery("show columns from t like 'abc%'").Check(testkit.RowsWithSep(",", "abctime,int(11),YES,,<nil>,"))
tk.MustQuery("show columns from t like 'ABC%'").Check(testkit.RowsWithSep(",", "abctime,int(11),YES,,<nil>,"))
tk.MustQuery("show columns from t like '%ime'").Check(testkit.RowsWithSep(",", "abctime,int(11),YES,,<nil>,"))
tk.MustQuery("show columns from t like '%IME'").Check(testkit.RowsWithSep(",", "abctime,int(11),YES,,<nil>,"))
tk.MustQuery("show columns in t like '%ime'").Check(testkit.RowsWithSep(",", "abctime,int(11),YES,,<nil>,"))
tk.MustQuery("show columns in t like '%IME'").Check(testkit.RowsWithSep(",", "abctime,int(11),YES,,<nil>,"))
tk.MustQuery("show fields in t like '%ime'").Check(testkit.RowsWithSep(",", "abctime,int(11),YES,,<nil>,"))
tk.MustQuery("show fields in t like '%IME'").Check(testkit.RowsWithSep(",", "abctime,int(11),YES,,<nil>,"))

tk.MustQuery("show columns from t where field like '%lmn'").Check(testkit.RowsWithSep(",", "abclmn,int(11),YES,,<nil>,"))
tk.MustQuery("show columns from t where field = 'abclmn'").Check(testkit.RowsWithSep(",", "abclmn,int(11),YES,,<nil>,"))
tk.MustQuery("show columns in t where field = 'abclmn'").Check(testkit.RowsWithSep(",", "abclmn,int(11),YES,,<nil>,"))
tk.MustQuery("show fields from t where field = 'abclmn'").Check(testkit.RowsWithSep(",", "abclmn,int(11),YES,,<nil>,"))
tk.MustQuery("show fields in t where field = 'abclmn'").Check(testkit.RowsWithSep(",", "abclmn,int(11),YES,,<nil>,"))
tk.MustQuery("explain t").Check(testkit.Rows("id int(11) YES <nil> ", "abclmn int(11) YES <nil> "))
tk.MustQuery("show columns from t where field like '%time'").Check(testkit.RowsWithSep(",", "abctime,int(11),YES,,<nil>,"))
tk.MustQuery("show columns from t where field = 'abctime'").Check(testkit.RowsWithSep(",", "abctime,int(11),YES,,<nil>,"))
tk.MustQuery("show columns in t where field = 'abctime'").Check(testkit.RowsWithSep(",", "abctime,int(11),YES,,<nil>,"))
tk.MustQuery("show fields from t where field = 'abctime'").Check(testkit.RowsWithSep(",", "abctime,int(11),YES,,<nil>,"))
tk.MustQuery("show fields in t where field = 'abctime'").Check(testkit.RowsWithSep(",", "abctime,int(11),YES,,<nil>,"))
tk.MustQuery("explain t").Check(testkit.Rows("id int(11) YES <nil> ", "abctime int(11) YES <nil> ", "DATETIME_PRECISION int(11) YES <nil> "))

tk.MustGetErrCode("show columns from t like id", errno.ErrBadField)
tk.MustGetErrCode("show columns from t like `id`", errno.ErrBadField)
Expand Down
9 changes: 3 additions & 6 deletions planner/core/show_predicate_extractor.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (

"github.com/pingcap/tidb/parser/ast"
driver "github.com/pingcap/tidb/types/parser_driver"
"github.com/pingcap/tidb/util/collate"
"github.com/pingcap/tidb/util/stringutil"
)

Expand Down Expand Up @@ -60,12 +59,11 @@ func (e *ShowColumnsTableExtractor) Extract(show *ast.ShowStmt) bool {
// It is used in `SHOW COLUMNS FROM 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
}
// (?i) mean to be case-insensitive.
e.FieldPatterns = "(?i)" + stringutil.CompileLike2Regexp(string(patValue))
e.FieldPatterns = strings.ToLower(string(patValue))
return true
case *ast.ColumnNameExpr:
// It is used in `SHOW COLUMNS FROM t LIKE abc`.
Expand Down Expand Up @@ -116,8 +114,7 @@ func (e *ShowTablesTableExtractor) Extract(show *ast.ShowStmt) bool {
e.Field = strings.ToLower(string(patValue))
return true
}
// (?i) mean to be case-insensitive.
e.FieldPatterns = "(?i)" + stringutil.CompileLike2Regexp(string(patValue))
e.FieldPatterns = strings.ToLower(string(patValue))
return true
}
}
Expand Down
8 changes: 4 additions & 4 deletions planner/core/stringer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ func TestPlanStringer(t *testing.T) {
}{
{
sql: "show columns from t like 'a'",
plan: "Show(field_pattern:[(?i)a])",
plan: "Show(field:[a])",
},
{
sql: "show columns from t like 'a%'",
plan: "Show(field_pattern:[(?i)a.*])",
plan: "Show(field_pattern:[a%])",
},
{
sql: "show columns from t where field = 'a'",
Expand All @@ -66,11 +66,11 @@ func TestPlanStringer(t *testing.T) {
},
{
sql: "show tables in test like 't%'",
plan: "Show(table_pattern:[(?i)t.*])",
plan: "Show(table_pattern:[t%])",
},
{
sql: "show tables in test like '%T%'",
plan: "Show(table_pattern:[(?i).*T.*])",
plan: "Show(table_pattern:[%t%])",
},
}
parser := parser.New()
Expand Down

0 comments on commit 284b90d

Please sign in to comment.