[parser] parser: support index advisor (#667)

This commit is contained in:
Jian Yang
2019-12-10 13:19:50 +08:00
committed by Ti Chi Robot
parent de4291013c
commit 07751a60e2
6 changed files with 9166 additions and 8808 deletions

80
parser/ast/advisor.go Normal file
View File

@ -0,0 +1,80 @@
// Copyright 2019 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
package ast
import (
. "github.com/pingcap/parser/format"
)
var _ StmtNode = &IndexAdviseStmt{}
// IndexAdviseStmt is used to advise indexes
type IndexAdviseStmt struct {
stmtNode
IsLocal bool
Path string
MaxMinutes uint64
MaxIndexNum *MaxIndexNumClause
LinesInfo *LinesClause
}
// Restore implements Node Accept interface.
func (n *IndexAdviseStmt) Restore(ctx *RestoreCtx) error {
ctx.WriteKeyWord("INDEX ADVISE ")
if n.IsLocal {
ctx.WriteKeyWord("LOCAL ")
}
ctx.WriteKeyWord("INFILE ")
ctx.WriteString(n.Path)
if n.MaxMinutes != UnspecifiedSize {
ctx.WriteKeyWord(" MAX_MINUTES ")
ctx.WritePlainf("%d", n.MaxMinutes)
}
if n.MaxIndexNum != nil {
n.MaxIndexNum.Restore(ctx)
}
n.LinesInfo.Restore(ctx)
return nil
}
// Accept implements Node Accept interface.
func (n *IndexAdviseStmt) Accept(v Visitor) (Node, bool) {
newNode, skipChildren := v.Enter(n)
if skipChildren {
return v.Leave(newNode)
}
n = newNode.(*IndexAdviseStmt)
return v.Leave(n)
}
// MaxIndexNumClause represents 'maximum number of indexes' clause in index advise statement.
type MaxIndexNumClause struct {
PerTable uint64
PerDB uint64
}
// Restore for max index num clause
func (n *MaxIndexNumClause) Restore(ctx *RestoreCtx) error {
ctx.WriteKeyWord(" MAX_IDXNUM")
if n.PerTable != UnspecifiedSize {
ctx.WriteKeyWord(" PER_TABLE ")
ctx.WritePlainf("%d", n.PerTable)
}
if n.PerDB != UnspecifiedSize {
ctx.WriteKeyWord(" PER_DB ")
ctx.WritePlainf("%d", n.PerDB)
}
return nil
}

View File

@ -13,6 +13,13 @@
package ast
import "math"
// UnspecifiedSize is unspecified size.
const (
UnspecifiedSize = math.MaxUint64
)
// IsReadOnly checks whether the input ast is readOnly.
func IsReadOnly(node Node) bool {
switch st := node.(type) {

View File

@ -138,6 +138,7 @@ var tokenMap = map[string]int{
"ACTION": action,
"ADD": add,
"ADDDATE": addDate,
"ADVISE": advise,
"ADMIN": admin,
"AFTER": after,
"AGAINST": against,
@ -393,6 +394,8 @@ var tokenMap = map[string]int{
"MAX": max,
"MAX_CONNECTIONS_PER_HOUR": maxConnectionsPerHour,
"MAX_EXECUTION_TIME": maxExecutionTime,
"MAX_IDXNUM": max_idxnum,
"MAX_MINUTES": max_minutes,
"MAX_QUERIES_PER_HOUR": maxQueriesPerHour,
"MAX_ROWS": maxRows,
"MAX_UPDATES_PER_HOUR": maxUpdatesPerHour,
@ -461,6 +464,8 @@ var tokenMap = map[string]int{
"PARTITIONS": partitions,
"PASSWORD": password,
"PESSIMISTIC": pessimistic,
"PER_TABLE": per_table,
"PER_DB": per_db,
"PLUGINS": plugins,
"POSITION": position,
"PRECEDING": preceding,

File diff suppressed because it is too large Load Diff

View File

@ -282,6 +282,7 @@ import (
/* The following tokens belong to UnReservedKeyword. Notice: make sure these tokens are contained in UnReservedKeyword. */
account "ACCOUNT"
action "ACTION"
advise "ADVISE"
after "AFTER"
against "AGAINST"
always "ALWAYS"
@ -404,6 +405,8 @@ import (
merge "MERGE"
minRows "MIN_ROWS"
minValue "MINVALUE"
max_minutes "MAX_MINUTES"
max_idxnum "MAX_IDXNUM"
names "NAMES"
national "NATIONAL"
ncharType "NCHAR"
@ -433,6 +436,8 @@ import (
processlist "PROCESSLIST"
profile "PROFILE"
profiles "PROFILES"
per_table "PER_TABLE"
per_db "PER_DB"
quarter "QUARTER"
query "QUERY"
queries "QUERIES"
@ -760,6 +765,7 @@ import (
GrantStmt "Grant statement"
GrantRoleStmt "Grant role statement"
InsertIntoStmt "INSERT INTO statement"
IndexAdviseStmt "INDEX ADVISE stetement"
KillStmt "Kill statement"
LoadDataStmt "Load data statement"
LoadStatsStmt "Load statistic statement"
@ -1146,6 +1152,10 @@ import (
EnforcedOrNotOrNotNullOpt "{[ENFORCED|NOT ENFORCED|NOT NULL]}"
Match "[MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]"
MatchOpt "optional MATCH clause"
MaxMinutesOpt "MAX_MINUTES num(int)"
MaxIndexNumOpt "MAX_IDXNUM clause"
PerTable "Max index number PER_TABLE"
PerDB "Max index number PER_DB"
%type <ident>
AsOpt "AS or EmptyString"
@ -4603,7 +4613,7 @@ Identifier:
identifier | UnReservedKeyword | NotKeywordToken | TiDBKeyword
UnReservedKeyword:
"ACTION" | "ASCII" | "AUTO_INCREMENT" | "AFTER" | "ALWAYS" | "AVG" | "BEGIN" | "BIT" | "BOOL" | "BOOLEAN" | "BTREE" | "BYTE" | "CAPTURE" |"CLEANUP" | "CHARSET"
"ACTION" | "ADVISE" |"ASCII" | "AUTO_INCREMENT" | "AFTER" | "ALWAYS" | "AVG" | "BEGIN" | "BIT" | "BOOL" | "BOOLEAN" | "BTREE" | "BYTE" | "CAPTURE" |"CLEANUP" | "CHARSET"
| "COLUMNS" | "COMMIT" | "COMPACT" | "COMPRESSED" | "CONSISTENT" | "CURRENT" | "DATA" | "DATE" %prec lowerThanStringLitToken| "DATETIME" | "DAY" | "DEALLOCATE" | "DO" | "DUPLICATE"
| "DYNAMIC" | "ENCRYPTION" | "END" | "ENFORCED" | "ENGINE" | "ENGINES" | "ENUM" | "ERRORS" | "ESCAPE" | "EVOLVE" | "EXECUTE" | "EXTENDED" | "FIELDS" | "FIRST" | "FIXED" | "FLUSH" | "FOLLOWING" | "FORMAT" | "FULL" |"GLOBAL"
| "HASH" | "HOUR" | "INSERT_METHOD" | "LESS" | "LOCAL" | "LAST" | "NAMES" | "OFFSET" | "PASSWORD" %prec lowerThanEq | "PREPARE" | "QUICK" | "REBUILD" | "REDUNDANT" | "REORGANIZE"
@ -4621,7 +4631,7 @@ UnReservedKeyword:
| "WITHOUT" | "RTREE" | "EXCHANGE" | "COLUMN_FORMAT" | "REPAIR" | "IMPORT" | "DISCARD" | "TABLE_CHECKSUM" | "UNICODE"
| "SQL_TSI_DAY" | "SQL_TSI_HOUR" | "SQL_TSI_MINUTE" | "SQL_TSI_MONTH" | "SQL_TSI_QUARTER" | "SQL_TSI_SECOND" |
"SQL_TSI_WEEK" | "SQL_TSI_YEAR" | "INVISIBLE" | "VISIBLE" | "TYPE" | "NOWAIT" | "REPLICA" | "LOCATION" | "LABELS"
| "LOGS" | "HOSTS" | "AGAINST" | "EXPANSION" | "INCREMENT" | "MINVALUE" | "NOMAXVALUE" | "NOMINVALUE" | "NOCACHE" | "CACHE" | "CYCLE" | "NOCYCLE" | "NOORDER"
| "LOGS" | "HOSTS" | "AGAINST" | "EXPANSION" | "INCREMENT" | "MINVALUE" | "NOMAXVALUE" | "NOMINVALUE" | "NOCACHE" | "CACHE" | "CYCLE" | "NOCYCLE" | "NOORDER" | "MAX_MINUTES" | "MAX_IDXNUM" | "PER_TABLE" | "PER_DB"
TiDBKeyword:
"ADMIN" | "AGG_TO_COP" |"BUCKETS" | "BUILTINS" | "CANCEL" | "CMSKETCH" | "DDL" | "DEPTH" | "DRAINER" | "JOBS" | "JOB" | "NODE_ID" | "NODE_STATE" | "PUMP" | "SAMPLES" | "STATS" | "STATS_META" | "STATS_HISTOGRAMS" | "STATS_BUCKETS" | "STATS_HEALTHY" | "TIDB"
@ -8673,6 +8683,7 @@ Statement:
| GrantStmt
| GrantRoleStmt
| InsertIntoStmt
| IndexAdviseStmt
| KillStmt
| LoadDataStmt
| LoadStatsStmt
@ -10927,4 +10938,79 @@ SignedNum:
$$ = -$2.(int64)
}
/********************************************************************
* Index Advisor Statement
*
* INDEX ADVISE
* [LOCAL]
* INFILE 'file_name'
* [MAX_MINUTES number]
* [MAX_IDXNUM
* [PER_TABLE number]
* [PER_DB number]
* ]
* [LINES
* [STARTING BY 'string']
* [TERMINATED BY 'string']
* ]
*******************************************************************/
IndexAdviseStmt:
"INDEX" "ADVISE" LocalOpt "INFILE" stringLit MaxMinutesOpt MaxIndexNumOpt Lines
{
x := &ast.IndexAdviseStmt{
Path: $5,
MaxMinutes: $6.(uint64),
}
if $3 != nil {
x.IsLocal = true
}
if $7 != nil {
x.MaxIndexNum = $7.(*ast.MaxIndexNumClause)
}
if $8 != nil {
x.LinesInfo = $8.(*ast.LinesClause)
}
$$ = x
}
MaxMinutesOpt:
{
$$ = uint64(ast.UnspecifiedSize)
}
| "MAX_MINUTES" NUM
{
$$ = getUint64FromNUM($2)
}
MaxIndexNumOpt:
{
$$ = nil
}
| "MAX_IDXNUM" PerTable PerDB
{
$$ = &ast.MaxIndexNumClause{
PerTable: $2.(uint64),
PerDB: $3.(uint64),
}
}
PerTable:
{
$$ = uint64(ast.UnspecifiedSize)
}
| "PER_TABLE" NUM
{
$$ = getUint64FromNUM($2)
}
PerDB:
{
$$ = uint64(ast.UnspecifiedSize)
}
| "PER_DB" NUM
{
$$ = getUint64FromNUM($2)
}
%%

View File

@ -4837,3 +4837,63 @@ func (checker *nodeTextCleaner) Enter(in ast.Node) (out ast.Node, skipChildren b
func (checker *nodeTextCleaner) Leave(in ast.Node) (out ast.Node, ok bool) {
return in, true
}
// For index advisor
func (s *testParserSuite) TestIndexAdviseStmt(c *C) {
table := []testCase{
{"INDEX ADVISE INFILE '/tmp/t.sql'", true, "INDEX ADVISE INFILE '/tmp/t.sql'"},
{"INDEX ADVISE LOCAL INFILE '/tmp/t.sql'", true, "INDEX ADVISE LOCAL INFILE '/tmp/t.sql'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES -1", false, ""},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_IDXNUM PER_TABLE 4", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_IDXNUM PER_TABLE 4"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_IDXNUM PER_DB 4", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_IDXNUM PER_DB 4"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_IDXNUM PER_TABLE 8 PER_DB 4", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_IDXNUM PER_TABLE 8 PER_DB 4"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_IDXNUM PER_DB 4 PER_TABLE 8", false, ""},
{"INDEX ADVISE INFILE '/tmp/t.sql' LINES STARTING BY 'ab'", true, "INDEX ADVISE INFILE '/tmp/t.sql' LINES STARTING BY 'ab'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' LINES TERMINATED BY '\n'", true, "INDEX ADVISE INFILE '/tmp/t.sql'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' LINES TERMINATED BY 'cd'", true, "INDEX ADVISE INFILE '/tmp/t.sql' LINES TERMINATED BY 'cd'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' LINES STARTING BY 'ab' TERMINATED BY '\n'", true, "INDEX ADVISE INFILE '/tmp/t.sql' LINES STARTING BY 'ab'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' LINES STARTING BY 'ab' TERMINATED BY 'cd'", true, "INDEX ADVISE INFILE '/tmp/t.sql' LINES STARTING BY 'ab' TERMINATED BY 'cd'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 4", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 4"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_DB 4", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_DB 4"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_TABLE 4", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_TABLE 4"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_DB 4", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_DB 4"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_TABLE 8 PER_DB 4", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_TABLE 8 PER_DB 4"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES -1 MAX_IDXNUM PER_TABLE 4", false, ""},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES -1 MAX_IDXNUM PER_DB 4", false, ""},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES -1 MAX_IDXNUM PER_TABLE 8 PER_DB 4", false, ""},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4 LINES STARTING BY 'ab'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4 LINES STARTING BY 'ab'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4 LINES TERMINATED BY '\n'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4 LINES TERMINATED BY 'cd'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4 LINES TERMINATED BY 'cd'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4 LINES STARTING BY 'ab' TERMINATED BY '\n'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4 LINES STARTING BY 'ab'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4 LINES STARTING BY 'ab' TERMINATED BY 'cd'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4 LINES STARTING BY 'ab' TERMINATED BY 'cd'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 LINES STARTING BY 'ab'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 LINES STARTING BY 'ab'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 LINES TERMINATED BY '\n'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 LINES TERMINATED BY 'cd'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 LINES TERMINATED BY 'cd'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 LINES STARTING BY 'ab' TERMINATED BY '\n'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 LINES STARTING BY 'ab'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 LINES STARTING BY 'ab' TERMINATED BY 'cd'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 LINES STARTING BY 'ab' TERMINATED BY 'cd'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES -1 LINES STARTING BY 'ab' TERMINATED BY '\n'", false, ""},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES -1 LINES STARTING BY 'ab' TERMINATED BY 'cd'", false, ""},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 4 LINES STARTING BY 'ab'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 4 LINES STARTING BY 'ab'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_DB 4 LINES STARTING BY 'ab'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_DB 4 LINES STARTING BY 'ab'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES TERMINATED BY '\n'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES TERMINATED BY 'cd'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES TERMINATED BY 'cd'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab' TERMINATED BY '\n'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab' TERMINATED BY 'cd'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab' TERMINATED BY 'cd'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab' TERMINATED BY '\n'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab' TERMINATED BY 'cd'", true, "INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab' TERMINATED BY 'cd'"},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES -1 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab' TERMINATED BY '\n'", false, ""},
{"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES -1 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab' TERMINATED BY 'cd'", false, ""},
}
s.RunTest(c, table)
}