Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Planning and Parsing Support for Create Index of MySQL 5.7 #7024

Merged
merged 14 commits into from
Nov 18, 2020
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions go/test/endtoend/vtgate/misc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,16 @@ func TestInsertStmtInOLAP(t *testing.T) {
assertMatches(t, conn, `select id1 from t1 order by id1`, `[]`)
}

func TestCreateIndex(t *testing.T) {
defer cluster.PanicHandler(t)
ctx := context.Background()
conn, err := mysql.Connect(ctx, &vtParams)
require.NoError(t, err)
defer conn.Close()
_, err = conn.ExecuteFetch(`create index i1 on t1 (id1)`, 1000, true)
require.NoError(t, err)
}

func assertMatches(t *testing.T, conn *mysql.Conn, query, expected string) {
t.Helper()
qr := exec(t, conn, query)
Expand Down
22 changes: 11 additions & 11 deletions go/vt/sqlparser/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func ASTToStatementType(stmt Statement) StatementType {
return StmtSet
case *Show:
return StmtShow
case *DDL, *DBDDL:
case DDLStatement, *DBDDL:
return StmtDDL
case *Use:
return StmtUse
Expand Down Expand Up @@ -256,21 +256,21 @@ func IsDMLStatement(stmt Statement) bool {
}

//IsVschemaDDL returns true if the query is an Vschema alter ddl.
func IsVschemaDDL(ddl *DDL) bool {
switch ddl.Action {
case CreateVindexDDLAction, DropVindexDDLAction, AddVschemaTableDDLAction, DropVschemaTableDDLAction, AddColVindexDDLAction, DropColVindexDDLAction, AddSequenceDDLAction, AddAutoIncDDLAction:
return true
func IsVschemaDDL(ddl DDLStatement) bool {
switch ddlStatement := ddl.(type) {
case *DDL:
switch ddlStatement.Action {
case CreateVindexDDLAction, DropVindexDDLAction, AddVschemaTableDDLAction, DropVschemaTableDDLAction, AddColVindexDDLAction, DropColVindexDDLAction, AddSequenceDDLAction, AddAutoIncDDLAction:
return true
}
}
return false
}

// IsOnlineSchemaDDL returns true if the query is an online schema change DDL
func IsOnlineSchemaDDL(ddl *DDL, sql string) bool {
switch ddl.Action {
case AlterDDLAction:
if ddl.OnlineHint != nil {
return ddl.OnlineHint.Strategy != ""
}
func IsOnlineSchemaDDL(ddl DDLStatement) bool {
if ddl.GetOnlineHint() != nil {
return ddl.GetOnlineHint().Strategy != ""
}
return false
}
Expand Down
116 changes: 113 additions & 3 deletions go/vt/sqlparser/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ type (
SQLNode
}

// DDLStatement represents any DDL Statement
DDLStatement interface {
iDDLStatement()
GetOnlineHint() *OnlineDDLHint
IsFullyParsed() bool
GetTable() TableName
AffectedTables() TableNames
Statement
}

// Select represents a SELECT statement.
Select struct {
Cache *bool // a reference here so it can be nil
Expand Down Expand Up @@ -249,6 +259,18 @@ type (
AutoIncSpec *AutoIncSpec
}

// CreateIndex represents a CREATE INDEX query
CreateIndex struct {
Constraint string
Name ColIdent
OnlineHint *OnlineDDLHint
IndexType string
Table TableName
Columns []*IndexColumn
Options []*IndexOption
FullyParsed bool
}

// DDLAction is an enum for DDL.Action
DDLAction int8

Expand Down Expand Up @@ -342,6 +364,56 @@ func (*Select) iSelectStatement() {}
func (*Union) iSelectStatement() {}
func (*ParenSelect) iSelectStatement() {}
func (*Load) iStatement() {}
func (*CreateIndex) iStatement() {}

func (*DDL) iDDLStatement() {}
func (*CreateIndex) iDDLStatement() {}

// IsFullyParsed implements the DDLStatement interface
func (*DDL) IsFullyParsed() bool {
return false
}

// IsFullyParsed implements the DDLStatement interface
func (node *CreateIndex) IsFullyParsed() bool {
return node.FullyParsed
}

// GetOnlineHint implements the DDLStatement interface
func (node *DDL) GetOnlineHint() *OnlineDDLHint {
return node.OnlineHint
}

// GetOnlineHint implements the DDLStatement interface
func (node *CreateIndex) GetOnlineHint() *OnlineDDLHint {
return node.OnlineHint
}

// GetTable implements the DDLStatement interface
func (node *CreateIndex) GetTable() TableName {
return node.Table
}

// GetTable implements the DDLStatement interface
func (node *DDL) GetTable() TableName {
return node.Table
}

// AffectedTables returns the list table names affected by the DDLStatement.
func (node *DDL) AffectedTables() TableNames {
if node.Action == RenameDDLAction || node.Action == DropDDLAction {
list := make(TableNames, 0, len(node.FromTables)+len(node.ToTables))
list = append(list, node.FromTables...)
list = append(list, node.ToTables...)
return list
}
return TableNames{node.Table}
}

// AffectedTables implements DDLStatement.
func (node *CreateIndex) AffectedTables() TableNames {
return TableNames{node.Table}
}

// ParenSelect can actually not be a top level statement,
// but we have to allow it because it's a requirement
Expand Down Expand Up @@ -953,7 +1025,7 @@ type Order struct {
Direction OrderDirection
}

// OrderDirection is an enum for Order.Direction
// OrderDirection is an enum for the direction in which to order - asc or desc.
type OrderDirection int8

// Limit represents a LIMIT clause.
Expand Down Expand Up @@ -1344,13 +1416,16 @@ func (idx *IndexDefinition) Format(buf *TrackedBuffer) {
if col.Length != nil {
buf.astPrintf(idx, "(%v)", col.Length)
}
if col.Direction == DescOrder {
buf.astPrintf(idx, " desc")
}
}
buf.astPrintf(idx, ")")

for _, opt := range idx.Options {
buf.astPrintf(idx, " %s", opt.Name)
if opt.Using != "" {
buf.astPrintf(idx, " %s", opt.Using)
if opt.String != "" {
buf.astPrintf(idx, " %s", opt.String)
} else {
buf.astPrintf(idx, " %v", opt.Value)
}
Expand Down Expand Up @@ -2155,3 +2230,38 @@ func (node *SelectInto) Format(buf *TrackedBuffer) {
}
buf.astPrintf(node, "%s%s%s%s", node.FormatOption, node.ExportOption, node.Manifest, node.Overwrite)
}

// Format formats the node.
func (node *CreateIndex) Format(buf *TrackedBuffer) {
buf.WriteString("create")
if node.Constraint != "" {
buf.WriteString(" " + node.Constraint)
}
buf.astPrintf(node, " index %v", node.Name)
if node.IndexType != "" {
buf.WriteString(" using " + node.IndexType)
}
buf.astPrintf(node, " on %v (", node.Table)
for i, col := range node.Columns {
if i != 0 {
buf.astPrintf(node, ", %v", col.Column)
} else {
buf.astPrintf(node, "%v", col.Column)
}
if col.Length != nil {
buf.astPrintf(node, "(%v)", col.Length)
}
if col.Direction == DescOrder {
buf.WriteString(" desc")
}
}
buf.astPrintf(node, ")")
for _, opt := range node.Options {
buf.WriteString(" " + strings.ToLower(opt.Name))
if opt.String != "" {
buf.WriteString(" " + opt.String)
} else {
buf.astPrintf(node, " %v", opt.Value)
}
}
}
25 changes: 8 additions & 17 deletions go/vt/sqlparser/ast_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ func Append(buf *strings.Builder, node SQLNode) {

// IndexColumn describes a column in an index definition with optional length
type IndexColumn struct {
Column ColIdent
Length *Literal
Column ColIdent
Length *Literal
Direction OrderDirection
}

// LengthScaleOption is used for types that have an optional length
Expand All @@ -86,11 +87,11 @@ type LengthScaleOption struct {
Scale *Literal
}

// IndexOption is used for trailing options for indexes: COMMENT, KEY_BLOCK_SIZE, USING
// IndexOption is used for trailing options for indexes: COMMENT, KEY_BLOCK_SIZE, USING, WITH PARSER
type IndexOption struct {
Name string
Value *Literal
Using string
Name string
Value *Literal
String string
}

// ColumnKeyOption indicates whether or not the given column is defined as an
Expand Down Expand Up @@ -147,17 +148,6 @@ const (
BitVal
)

// AffectedTables returns the list table names affected by the DDL.
func (node *DDL) AffectedTables() TableNames {
if node.Action == RenameDDLAction || node.Action == DropDDLAction {
list := make(TableNames, 0, len(node.FromTables)+len(node.ToTables))
list = append(list, node.FromTables...)
list = append(list, node.ToTables...)
return list
}
return TableNames{node.Table}
}

// AddColumn appends the given column to the list in the spec
func (ts *TableSpec) AddColumn(cd *ColumnDefinition) {
ts.Columns = append(ts.Columns, cd)
Expand Down Expand Up @@ -1123,6 +1113,7 @@ func (ty ExplainType) ToString() string {
}
}

// ToString returns the type as a string
func (sel SelectIntoType) ToString() string {
switch sel {
case IntoOutfile:
Expand Down
41 changes: 25 additions & 16 deletions go/vt/sqlparser/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ import (

var (
validSQL = []struct {
input string
output string
input string
output string
partialDDL bool
}{{
input: "select 1",
output: "select 1 from dual",
Expand Down Expand Up @@ -1151,23 +1152,24 @@ var (
input: "alter vschema on a drop vindex `add`",
output: "alter vschema on a drop vindex `add`",
}, {
input: "create index a on b",
output: "alter table b",
input: "create index a on b (col1)",
}, {
input: "create unique index a on b (col1)",
}, {
input: "create unique index a using foo on b (col1 desc)",
}, {
input: "create unique index a on b",
output: "alter table b",
input: "create with 'gh-ost' unique index a using foo on b (col1 desc)",
output: "create unique index a using foo on b (col1 desc)",
}, {
input: "create unique index a using foo on b",
output: "alter table b",
input: "create fulltext index a using foo on b (col1)",
}, {
input: "create fulltext index a using foo on b",
output: "alter table b",
input: "create spatial index a using foo on b (col1)",
}, {
input: "create spatial index a using foo on b",
output: "alter table b",
input: "create index a on b (col1) using btree key_block_size 12 with parser 'a' comment 'string' algorithm inplace lock none",
}, {
input: "create fulltext index a using foo on b",
output: "alter table b",
input: "create index a on b ((col1 + col2), (col1*col2))",
output: "create index a on b ()",
partialDDL: true,
}, {
input: "create view a",
output: "create table a",
Expand Down Expand Up @@ -1769,6 +1771,14 @@ func TestValid(t *testing.T) {
if tcase.output != out {
t.Errorf("Parsing failed. \nExpected/Got:\n%s\n%s", tcase.output, out)
}

// CREATE INDEX currently only has 5.7 specifications.
// For mysql 8.0 syntax, the query is not entirely parsed.
// Add more structs as we go on adding full parsing support for DDL constructs for 5.7 syntax.
switch x := tree.(type) {
case *CreateIndex:
assert.Equal(t, !tcase.partialDDL, x.IsFullyParsed())
}
// This test just exercises the tree walking functionality.
// There's no way automated way to verify that a node calls
// all its children. But we can examine code coverage and
Expand Down Expand Up @@ -1841,8 +1851,7 @@ func TestCaseSensitivity(t *testing.T) {
input: "create table A (\n\t`B` int\n)",
output: "create table A (\n\tB int\n)",
}, {
input: "create index b on A",
output: "alter table A",
input: "create index b on A (col1 desc)",
}, {
input: "alter table A foo",
output: "alter table A",
Expand Down
12 changes: 12 additions & 0 deletions go/vt/sqlparser/rewriter.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.