/* Copyright 2019 The Vitess Authors. 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, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package sqlparser import ( "fmt" "strings" "vitess.io/vitess/go/sqltypes" ) /* This is the Vitess AST. This file should only contain pure struct declarations, or methods used to mark a struct as implementing an interface. All other methods related to these structs live in ast_funcs.go */ // SQLNode defines the interface for all nodes // generated by the parser. type SQLNode interface { Format(buf *TrackedBuffer) } // Statements type ( // Statement represents a statement. Statement interface { iStatement() SQLNode } // SelectStatement any SELECT statement. SelectStatement interface { iSelectStatement() iStatement() iInsertRows() AddOrder(*Order) SetLimit(*Limit) SQLNode } // Select represents a SELECT statement. Select struct { Cache string Comments Comments Distinct string Hints string SelectExprs SelectExprs From TableExprs Where *Where GroupBy GroupBy Having *Where OrderBy OrderBy Limit *Limit Lock string } // Union represents a UNION statement. Union struct { Type string Left, Right SelectStatement OrderBy OrderBy Limit *Limit Lock string } // Stream represents a SELECT statement. Stream struct { Comments Comments SelectExpr SelectExpr Table TableName } // Insert represents an INSERT or REPLACE statement. // Per the MySQL docs, http://dev.mysql.com/doc/refman/5.7/en/replace.html // Replace is the counterpart to `INSERT IGNORE`, and works exactly like a // normal INSERT except if the row exists. In that case it first deletes // the row and re-inserts with new values. For that reason we keep it as an Insert struct. // Replaces are currently disallowed in sharded schemas because // of the implications the deletion part may have on vindexes. // If you add fields here, consider adding them to calls to validateUnshardedRoute. Insert struct { Action string Comments Comments Ignore string Table TableName Partitions Partitions Columns Columns Rows InsertRows OnDup OnDup } // Update represents an UPDATE statement. // If you add fields here, consider adding them to calls to validateUnshardedRoute. Update struct { Comments Comments Ignore string TableExprs TableExprs Exprs UpdateExprs Where *Where OrderBy OrderBy Limit *Limit } // Delete represents a DELETE statement. // If you add fields here, consider adding them to calls to validateUnshardedRoute. Delete struct { Comments Comments Targets TableNames TableExprs TableExprs Partitions Partitions Where *Where OrderBy OrderBy Limit *Limit } // Set represents a SET statement. Set struct { Comments Comments Exprs SetExprs Scope string } // DBDDL represents a CREATE, DROP, or ALTER database statement. DBDDL struct { Action string DBName string IfExists bool Collate string Charset string } // DDL represents a CREATE, ALTER, DROP, RENAME, TRUNCATE or ANALYZE statement. DDL struct { Action string // FromTables is set if Action is RenameStr or DropStr. FromTables TableNames // ToTables is set if Action is RenameStr. ToTables TableNames // Table is set if Action is other than RenameStr or DropStr. Table TableName // The following fields are set if a DDL was fully analyzed. IfExists bool TableSpec *TableSpec OptLike *OptLike PartitionSpec *PartitionSpec // VindexSpec is set for CreateVindexStr, DropVindexStr, AddColVindexStr, DropColVindexStr. VindexSpec *VindexSpec // VindexCols is set for AddColVindexStr. VindexCols []ColIdent // AutoIncSpec is set for AddAutoIncStr. AutoIncSpec *AutoIncSpec } // ParenSelect is a parenthesized SELECT statement. ParenSelect struct { Select SelectStatement } // Show represents a show statement. Show struct { Type string OnTable TableName Table TableName ShowTablesOpt *ShowTablesOpt Scope string ShowCollationFilterOpt *Expr // TODO: this should not be a pointer } // Use represents a use statement. Use struct { DBName TableIdent } // Begin represents a Begin statement. Begin struct{} // Commit represents a Commit statement. Commit struct{} // Rollback represents a Rollback statement. Rollback struct{} // OtherRead represents a DESCRIBE, or EXPLAIN statement. // It should be used only as an indicator. It does not contain // the full AST for the statement. OtherRead struct{} // OtherAdmin represents a misc statement that relies on ADMIN privileges, // such as REPAIR, OPTIMIZE, or TRUNCATE statement. // It should be used only as an indicator. It does not contain // the full AST for the statement. OtherAdmin struct{} ) func (*Union) iStatement() {} func (*Select) iStatement() {} func (*Stream) iStatement() {} func (*Insert) iStatement() {} func (*Update) iStatement() {} func (*Delete) iStatement() {} func (*Set) iStatement() {} func (*DBDDL) iStatement() {} func (*DDL) iStatement() {} func (*Show) iStatement() {} func (*Use) iStatement() {} func (*Begin) iStatement() {} func (*Commit) iStatement() {} func (*Rollback) iStatement() {} func (*OtherRead) iStatement() {} func (*OtherAdmin) iStatement() {} func (*Select) iSelectStatement() {} func (*Union) iSelectStatement() {} func (*ParenSelect) iSelectStatement() {} // ParenSelect can actually not be a top level statement, // but we have to allow it because it's a requirement // of SelectStatement. func (*ParenSelect) iStatement() {} // InsertRows represents the rows for an INSERT statement. type InsertRows interface { iInsertRows() SQLNode } func (*Select) iInsertRows() {} func (*Union) iInsertRows() {} func (Values) iInsertRows() {} func (*ParenSelect) iInsertRows() {} // OptLike works for create table xxx like xxx type OptLike struct { LikeTable TableName } // PartitionSpec describe partition actions (for alter and create) type PartitionSpec struct { Action string Name ColIdent Definitions []*PartitionDefinition } // PartitionDefinition describes a very minimal partition definition type PartitionDefinition struct { Name ColIdent Limit Expr Maxvalue bool } // TableSpec describes the structure of a table from a CREATE TABLE statement type TableSpec struct { Columns []*ColumnDefinition Indexes []*IndexDefinition Constraints []*ConstraintDefinition Options string } // ColumnDefinition describes a column in a CREATE TABLE statement type ColumnDefinition struct { Name ColIdent // TODO: Should this not be a reference? Type ColumnType } // ColumnType represents a sql type in a CREATE TABLE statement // All optional fields are nil if not specified type ColumnType struct { // The base type string Type string // Generic field options. NotNull BoolVal Autoincrement BoolVal Default Expr OnUpdate Expr Comment *SQLVal // Numeric field options Length *SQLVal Unsigned BoolVal Zerofill BoolVal Scale *SQLVal // Text field options Charset string Collate string // Enum values EnumValues []string // Key specification KeyOpt ColumnKeyOption } // IndexDefinition describes an index in a CREATE TABLE statement type IndexDefinition struct { Info *IndexInfo Columns []*IndexColumn Options []*IndexOption } // IndexInfo describes the name and type of an index in a CREATE TABLE statement type IndexInfo struct { Type string Name ColIdent Primary bool Spatial bool Unique bool } // VindexSpec defines a vindex for a CREATE VINDEX or DROP VINDEX statement type VindexSpec struct { Name ColIdent Type ColIdent Params []VindexParam } // AutoIncSpec defines and autoincrement value for a ADD AUTO_INCREMENT statement type AutoIncSpec struct { Column ColIdent Sequence TableName } // VindexParam defines a key/value parameter for a CREATE VINDEX statement type VindexParam struct { Key ColIdent Val string } // ConstraintDefinition describes a constraint in a CREATE TABLE statement type ConstraintDefinition struct { Name string Details ConstraintInfo } type ( // ConstraintInfo details a constraint in a CREATE TABLE statement ConstraintInfo interface { SQLNode iConstraintInfo() } // ForeignKeyDefinition describes a foreign key in a CREATE TABLE statement ForeignKeyDefinition struct { Source Columns ReferencedTable TableName ReferencedColumns Columns OnDelete ReferenceAction OnUpdate ReferenceAction } ) // ShowFilter is show tables filter type ShowFilter struct { Like string Filter Expr } // Comments represents a list of comments. type Comments [][]byte // SelectExprs represents SELECT expressions. type SelectExprs []SelectExpr type ( // SelectExpr represents a SELECT expression. SelectExpr interface { iSelectExpr() SQLNode } // StarExpr defines a '*' or 'table.*' expression. StarExpr struct { TableName TableName } // AliasedExpr defines an aliased SELECT expression. AliasedExpr struct { Expr Expr As ColIdent } // Nextval defines the NEXT VALUE expression. Nextval struct { Expr Expr } ) func (*StarExpr) iSelectExpr() {} func (*AliasedExpr) iSelectExpr() {} func (Nextval) iSelectExpr() {} // Columns represents an insert column list. type Columns []ColIdent // Partitions is a type alias for Columns so we can handle printing efficiently type Partitions Columns // TableExprs represents a list of table expressions. type TableExprs []TableExpr type ( // TableExpr represents a table expression. TableExpr interface { iTableExpr() SQLNode } // AliasedTableExpr represents a table expression // coupled with an optional alias or index hint. // If As is empty, no alias was used. AliasedTableExpr struct { Expr SimpleTableExpr Partitions Partitions As TableIdent Hints *IndexHints } // JoinTableExpr represents a TableExpr that's a JOIN operation. JoinTableExpr struct { LeftExpr TableExpr Join string RightExpr TableExpr Condition JoinCondition } // ParenTableExpr represents a parenthesized list of TableExpr. ParenTableExpr struct { Exprs TableExprs } ) func (*AliasedTableExpr) iTableExpr() {} func (*ParenTableExpr) iTableExpr() {} func (*JoinTableExpr) iTableExpr() {} type ( // SimpleTableExpr represents a simple table expression. SimpleTableExpr interface { iSimpleTableExpr() SQLNode } // TableName represents a table name. // Qualifier, if specified, represents a database or keyspace. // TableName is a value struct whose fields are case sensitive. // This means two TableName vars can be compared for equality // and a TableName can also be used as key in a map. TableName struct { Name, Qualifier TableIdent } // Subquery represents a subquery. Subquery struct { Select SelectStatement } ) func (TableName) iSimpleTableExpr() {} func (*Subquery) iSimpleTableExpr() {} // TableNames is a list of TableName. type TableNames []TableName // JoinCondition represents the join conditions (either a ON or USING clause) // of a JoinTableExpr. type JoinCondition struct { On Expr Using Columns } // IndexHints represents a list of index hints. type IndexHints struct { Type string Indexes []ColIdent } // Where represents a WHERE or HAVING clause. type Where struct { Type string Expr Expr } // *********** Expressions type ( // Expr represents an expression. Expr interface { iExpr() SQLNode } // AndExpr represents an AND expression. AndExpr struct { Left, Right Expr } // OrExpr represents an OR expression. OrExpr struct { Left, Right Expr } // NotExpr represents a NOT expression. NotExpr struct { Expr Expr } // ParenExpr represents a parenthesized boolean expression. ParenExpr struct { Expr Expr } // ComparisonExpr represents a two-value comparison expression. ComparisonExpr struct { Operator string Left, Right Expr Escape Expr } // RangeCond represents a BETWEEN or a NOT BETWEEN expression. RangeCond struct { Operator string Left Expr From, To Expr } // IsExpr represents an IS ... or an IS NOT ... expression. IsExpr struct { Operator string Expr Expr } // ExistsExpr represents an EXISTS expression. ExistsExpr struct { Subquery *Subquery } // SQLVal represents a single value. SQLVal struct { Type ValType Val []byte } // NullVal represents a NULL value. NullVal struct{} // BoolVal is true or false. BoolVal bool // ColName represents a column name. ColName struct { // Metadata is not populated by the parser. // It's a placeholder for analyzers to store // additional data, typically info about which // table or column this node references. Metadata interface{} Name ColIdent Qualifier TableName } // ColTuple represents a list of column values. // It can be ValTuple, Subquery, ListArg. ColTuple interface { iColTuple() Expr } // ListArg represents a named list argument. ListArg []byte // ValTuple represents a tuple of actual values. ValTuple Exprs // BinaryExpr represents a binary value expression. BinaryExpr struct { Operator string Left, Right Expr } // UnaryExpr represents a unary value expression. UnaryExpr struct { Operator string Expr Expr } // IntervalExpr represents a date-time INTERVAL expression. IntervalExpr struct { Expr Expr Unit string } // TimestampFuncExpr represents the function and arguments for TIMESTAMP{ADD,DIFF} functions. TimestampFuncExpr struct { Name string Expr1 Expr Expr2 Expr Unit string } // CollateExpr represents dynamic collate operator. CollateExpr struct { Expr Expr Charset string } // FuncExpr represents a function call. FuncExpr struct { Qualifier TableIdent Name ColIdent Distinct bool Exprs SelectExprs } // GroupConcatExpr represents a call to GROUP_CONCAT GroupConcatExpr struct { Distinct string Exprs SelectExprs OrderBy OrderBy Separator string Limit *Limit } // ValuesFuncExpr represents a function call. ValuesFuncExpr struct { Name *ColName } // SubstrExpr represents a call to SubstrExpr(column, value_expression) or SubstrExpr(column, value_expression,value_expression) // also supported syntax SubstrExpr(column from value_expression for value_expression). // Additionally to column names, SubstrExpr is also supported for string values, e.g.: // SubstrExpr('static string value', value_expression, value_expression) // In this case StrVal will be set instead of Name. SubstrExpr struct { Name *ColName StrVal *SQLVal From Expr To Expr } // ConvertExpr represents a call to CONVERT(expr, type) // or it's equivalent CAST(expr AS type). Both are rewritten to the former. ConvertExpr struct { Expr Expr Type *ConvertType } // ConvertUsingExpr represents a call to CONVERT(expr USING charset). ConvertUsingExpr struct { Expr Expr Type string } // MatchExpr represents a call to the MATCH function MatchExpr struct { Columns SelectExprs Expr Expr Option string } // CaseExpr represents a CASE expression. CaseExpr struct { Expr Expr Whens []*When Else Expr } // Default represents a DEFAULT expression. Default struct { ColName string } // When represents a WHEN sub-expression. When struct { Cond Expr Val Expr } // CurTimeFuncExpr represents the function and arguments for CURRENT DATE/TIME functions // supported functions are documented in the grammar CurTimeFuncExpr struct { Name ColIdent Fsp Expr // fractional seconds precision, integer from 0 to 6 } ) // iExpr ensures that only expressions nodes can be assigned to a Expr func (*AndExpr) iExpr() {} func (*OrExpr) iExpr() {} func (*NotExpr) iExpr() {} func (*ParenExpr) iExpr() {} func (*ComparisonExpr) iExpr() {} func (*RangeCond) iExpr() {} func (*IsExpr) iExpr() {} func (*ExistsExpr) iExpr() {} func (*SQLVal) iExpr() {} func (*NullVal) iExpr() {} func (BoolVal) iExpr() {} func (*ColName) iExpr() {} func (ValTuple) iExpr() {} func (*Subquery) iExpr() {} func (ListArg) iExpr() {} func (*BinaryExpr) iExpr() {} func (*UnaryExpr) iExpr() {} func (*IntervalExpr) iExpr() {} func (*CollateExpr) iExpr() {} func (*FuncExpr) iExpr() {} func (*TimestampFuncExpr) iExpr() {} func (*CurTimeFuncExpr) iExpr() {} func (*CaseExpr) iExpr() {} func (*ValuesFuncExpr) iExpr() {} func (*ConvertExpr) iExpr() {} func (*SubstrExpr) iExpr() {} func (*ConvertUsingExpr) iExpr() {} func (*MatchExpr) iExpr() {} func (*GroupConcatExpr) iExpr() {} func (*Default) iExpr() {} // Exprs represents a list of value expressions. // It's not a valid expression because it's not parenthesized. type Exprs []Expr func (ValTuple) iColTuple() {} func (*Subquery) iColTuple() {} func (ListArg) iColTuple() {} // ConvertType represents the type in call to CONVERT(expr, type) type ConvertType struct { Type string Length *SQLVal Scale *SQLVal Operator string Charset string } // GroupBy represents a GROUP BY clause. type GroupBy []Expr // OrderBy represents an ORDER By clause. type OrderBy []*Order // Order represents an ordering expression. type Order struct { Expr Expr Direction string } // Limit represents a LIMIT clause. type Limit struct { Offset, Rowcount Expr } // Values represents a VALUES clause. type Values []ValTuple // UpdateExprs represents a list of update expressions. type UpdateExprs []*UpdateExpr // UpdateExpr represents an update expression. type UpdateExpr struct { Name *ColName Expr Expr } // SetExprs represents a list of set expressions. type SetExprs []*SetExpr // SetExpr represents a set expression. type SetExpr struct { Name ColIdent Expr Expr } // OnDup represents an ON DUPLICATE KEY clause. type OnDup UpdateExprs // ColIdent is a case insensitive SQL identifier. It will be escaped with // backquotes if necessary. type ColIdent struct { // This artifact prevents this struct from being compared // with itself. It consumes no space as long as it's not the // last field in the struct. _ [0]struct{ _ []byte } val, lowered string at atCount } // TableIdent is a case sensitive SQL identifier. It will be escaped with // backquotes if necessary. type TableIdent struct { v string } // Here follow all the Format implementations for AST nodes // Format formats the node. func (node *Select) Format(buf *TrackedBuffer) { buf.Myprintf("select %v%s%s%s%v from %v%v%v%v%v%v%s", node.Comments, node.Cache, node.Distinct, node.Hints, node.SelectExprs, node.From, node.Where, node.GroupBy, node.Having, node.OrderBy, node.Limit, node.Lock) } // Format formats the node. func (node *ParenSelect) Format(buf *TrackedBuffer) { buf.Myprintf("(%v)", node.Select) } // Format formats the node. func (node *Union) Format(buf *TrackedBuffer) { buf.Myprintf("%v %s %v%v%v%s", node.Left, node.Type, node.Right, node.OrderBy, node.Limit, node.Lock) } // Format formats the node. func (node *Stream) Format(buf *TrackedBuffer) { buf.Myprintf("stream %v%v from %v", node.Comments, node.SelectExpr, node.Table) } // Format formats the node. func (node *Insert) Format(buf *TrackedBuffer) { buf.Myprintf("%s %v%sinto %v%v%v %v%v", node.Action, node.Comments, node.Ignore, node.Table, node.Partitions, node.Columns, node.Rows, node.OnDup) } // Format formats the node. func (node *Update) Format(buf *TrackedBuffer) { buf.Myprintf("update %v%s%v set %v%v%v%v", node.Comments, node.Ignore, node.TableExprs, node.Exprs, node.Where, node.OrderBy, node.Limit) } // Format formats the node. func (node *Delete) Format(buf *TrackedBuffer) { buf.Myprintf("delete %v", node.Comments) if node.Targets != nil { buf.Myprintf("%v ", node.Targets) } buf.Myprintf("from %v%v%v%v%v", node.TableExprs, node.Partitions, node.Where, node.OrderBy, node.Limit) } // Format formats the node. func (node *Set) Format(buf *TrackedBuffer) { if node.Scope == "" { buf.Myprintf("set %v%v", node.Comments, node.Exprs) } else { buf.Myprintf("set %v%s %v", node.Comments, node.Scope, node.Exprs) } } // Format formats the node. func (node *DBDDL) Format(buf *TrackedBuffer) { switch node.Action { case CreateStr, AlterStr: buf.WriteString(fmt.Sprintf("%s database %s", node.Action, node.DBName)) case DropStr: exists := "" if node.IfExists { exists = " if exists" } buf.WriteString(fmt.Sprintf("%s database%s %v", node.Action, exists, node.DBName)) } } // Format formats the node. func (node *DDL) Format(buf *TrackedBuffer) { switch node.Action { case CreateStr: if node.OptLike != nil { buf.Myprintf("%s table %v %v", node.Action, node.Table, node.OptLike) } else if node.TableSpec != nil { buf.Myprintf("%s table %v %v", node.Action, node.Table, node.TableSpec) } else { buf.Myprintf("%s table %v", node.Action, node.Table) } case DropStr: exists := "" if node.IfExists { exists = " if exists" } buf.Myprintf("%s table%s %v", node.Action, exists, node.FromTables) case RenameStr: buf.Myprintf("%s table %v to %v", node.Action, node.FromTables[0], node.ToTables[0]) for i := 1; i < len(node.FromTables); i++ { buf.Myprintf(", %v to %v", node.FromTables[i], node.ToTables[i]) } case AlterStr: if node.PartitionSpec != nil { buf.Myprintf("%s table %v %v", node.Action, node.Table, node.PartitionSpec) } else { buf.Myprintf("%s table %v", node.Action, node.Table) } case FlushStr: buf.Myprintf("%s", node.Action) case CreateVindexStr: buf.Myprintf("alter vschema create vindex %v %v", node.Table, node.VindexSpec) case DropVindexStr: buf.Myprintf("alter vschema drop vindex %v", node.Table) case AddVschemaTableStr: buf.Myprintf("alter vschema add table %v", node.Table) case DropVschemaTableStr: buf.Myprintf("alter vschema drop table %v", node.Table) case AddColVindexStr: buf.Myprintf("alter vschema on %v add vindex %v (", node.Table, node.VindexSpec.Name) for i, col := range node.VindexCols { if i != 0 { buf.Myprintf(", %v", col) } else { buf.Myprintf("%v", col) } } buf.Myprintf(")") if node.VindexSpec.Type.String() != "" { buf.Myprintf(" %v", node.VindexSpec) } case DropColVindexStr: buf.Myprintf("alter vschema on %v drop vindex %v", node.Table, node.VindexSpec.Name) case AddSequenceStr: buf.Myprintf("alter vschema add sequence %v", node.Table) case AddAutoIncStr: buf.Myprintf("alter vschema on %v add auto_increment %v", node.Table, node.AutoIncSpec) default: buf.Myprintf("%s table %v", node.Action, node.Table) } } // Format formats the node. func (node *OptLike) Format(buf *TrackedBuffer) { buf.Myprintf("like %v", node.LikeTable) } // Format formats the node. func (node *PartitionSpec) Format(buf *TrackedBuffer) { switch node.Action { case ReorganizeStr: buf.Myprintf("%s %v into (", node.Action, node.Name) var prefix string for _, pd := range node.Definitions { buf.Myprintf("%s%v", prefix, pd) prefix = ", " } buf.Myprintf(")") default: panic("unimplemented") } } // Format formats the node func (node *PartitionDefinition) Format(buf *TrackedBuffer) { if !node.Maxvalue { buf.Myprintf("partition %v values less than (%v)", node.Name, node.Limit) } else { buf.Myprintf("partition %v values less than (maxvalue)", node.Name) } } // Format formats the node. func (ts *TableSpec) Format(buf *TrackedBuffer) { buf.Myprintf("(\n") for i, col := range ts.Columns { if i == 0 { buf.Myprintf("\t%v", col) } else { buf.Myprintf(",\n\t%v", col) } } for _, idx := range ts.Indexes { buf.Myprintf(",\n\t%v", idx) } for _, c := range ts.Constraints { buf.Myprintf(",\n\t%v", c) } buf.Myprintf("\n)%s", strings.Replace(ts.Options, ", ", ",\n ", -1)) } // Format formats the node. func (col *ColumnDefinition) Format(buf *TrackedBuffer) { buf.Myprintf("%v %v", col.Name, &col.Type) } // Format returns a canonical string representation of the type and all relevant options func (ct *ColumnType) Format(buf *TrackedBuffer) { buf.Myprintf("%s", ct.Type) if ct.Length != nil && ct.Scale != nil { buf.Myprintf("(%v,%v)", ct.Length, ct.Scale) } else if ct.Length != nil { buf.Myprintf("(%v)", ct.Length) } if ct.EnumValues != nil { buf.Myprintf("(%s)", strings.Join(ct.EnumValues, ", ")) } opts := make([]string, 0, 16) if ct.Unsigned { opts = append(opts, keywordStrings[UNSIGNED]) } if ct.Zerofill { opts = append(opts, keywordStrings[ZEROFILL]) } if ct.Charset != "" { opts = append(opts, keywordStrings[CHARACTER], keywordStrings[SET], ct.Charset) } if ct.Collate != "" { opts = append(opts, keywordStrings[COLLATE], ct.Collate) } if ct.NotNull { opts = append(opts, keywordStrings[NOT], keywordStrings[NULL]) } if ct.Default != nil { opts = append(opts, keywordStrings[DEFAULT], String(ct.Default)) } if ct.OnUpdate != nil { opts = append(opts, keywordStrings[ON], keywordStrings[UPDATE], String(ct.OnUpdate)) } if ct.Autoincrement { opts = append(opts, keywordStrings[AUTO_INCREMENT]) } if ct.Comment != nil { opts = append(opts, keywordStrings[COMMENT_KEYWORD], String(ct.Comment)) } if ct.KeyOpt == colKeyPrimary { opts = append(opts, keywordStrings[PRIMARY], keywordStrings[KEY]) } if ct.KeyOpt == colKeyUnique { opts = append(opts, keywordStrings[UNIQUE]) } if ct.KeyOpt == colKeyUniqueKey { opts = append(opts, keywordStrings[UNIQUE], keywordStrings[KEY]) } if ct.KeyOpt == colKeySpatialKey { opts = append(opts, keywordStrings[SPATIAL], keywordStrings[KEY]) } if ct.KeyOpt == colKey { opts = append(opts, keywordStrings[KEY]) } if len(opts) != 0 { buf.Myprintf(" %s", strings.Join(opts, " ")) } } // Format formats the node. func (idx *IndexDefinition) Format(buf *TrackedBuffer) { buf.Myprintf("%v (", idx.Info) for i, col := range idx.Columns { if i != 0 { buf.Myprintf(", %v", col.Column) } else { buf.Myprintf("%v", col.Column) } if col.Length != nil { buf.Myprintf("(%v)", col.Length) } } buf.Myprintf(")") for _, opt := range idx.Options { buf.Myprintf(" %s", opt.Name) if opt.Using != "" { buf.Myprintf(" %s", opt.Using) } else { buf.Myprintf(" %v", opt.Value) } } } // Format formats the node. func (ii *IndexInfo) Format(buf *TrackedBuffer) { if ii.Primary { buf.Myprintf("%s", ii.Type) } else { buf.Myprintf("%s", ii.Type) if !ii.Name.IsEmpty() { buf.Myprintf(" %v", ii.Name) } } } // Format formats the node. func (node *AutoIncSpec) Format(buf *TrackedBuffer) { buf.Myprintf("%v ", node.Column) buf.Myprintf("using %v", node.Sequence) } // Format formats the node. The "CREATE VINDEX" preamble was formatted in // the containing DDL node Format, so this just prints the type, any // parameters, and optionally the owner func (node *VindexSpec) Format(buf *TrackedBuffer) { buf.Myprintf("using %v", node.Type) numParams := len(node.Params) if numParams != 0 { buf.Myprintf(" with ") for i, p := range node.Params { if i != 0 { buf.Myprintf(", ") } buf.Myprintf("%v", p) } } } // Format formats the node. func (node VindexParam) Format(buf *TrackedBuffer) { buf.Myprintf("%s=%s", node.Key.String(), node.Val) } // Format formats the node. func (c *ConstraintDefinition) Format(buf *TrackedBuffer) { if c.Name != "" { buf.Myprintf("constraint %s ", c.Name) } c.Details.Format(buf) } // Format formats the node. func (a ReferenceAction) Format(buf *TrackedBuffer) { switch a { case Restrict: buf.WriteString("restrict") case Cascade: buf.WriteString("cascade") case NoAction: buf.WriteString("no action") case SetNull: buf.WriteString("set null") case SetDefault: buf.WriteString("set default") } } // Format formats the node. func (f *ForeignKeyDefinition) Format(buf *TrackedBuffer) { buf.Myprintf("foreign key %v references %v %v", f.Source, f.ReferencedTable, f.ReferencedColumns) if f.OnDelete != DefaultAction { buf.Myprintf(" on delete %v", f.OnDelete) } if f.OnUpdate != DefaultAction { buf.Myprintf(" on update %v", f.OnUpdate) } } // Format formats the node. func (node *Show) Format(buf *TrackedBuffer) { nodeType := strings.ToLower(node.Type) if (nodeType == "tables" || nodeType == "columns" || nodeType == "fields" || nodeType == "index" || nodeType == "keys") && node.ShowTablesOpt != nil { opt := node.ShowTablesOpt buf.Myprintf("show %s%s", opt.Full, nodeType) if (nodeType == "columns" || nodeType == "fields" || nodeType == "index" || nodeType == "keys") && node.HasOnTable() { buf.Myprintf(" from %v", node.OnTable) } if opt.DbName != "" { buf.Myprintf(" from %s", opt.DbName) } buf.Myprintf("%v", opt.Filter) return } if node.Scope == "" { buf.Myprintf("show %s", nodeType) } else { buf.Myprintf("show %s %s", node.Scope, nodeType) } if node.HasOnTable() { buf.Myprintf(" on %v", node.OnTable) } if nodeType == "collation" && node.ShowCollationFilterOpt != nil { buf.Myprintf(" where %v", *node.ShowCollationFilterOpt) } if nodeType == "charset" && node.ShowTablesOpt != nil { buf.Myprintf("%v", node.ShowTablesOpt.Filter) } if node.HasTable() { buf.Myprintf(" %v", node.Table) } } // Format formats the node. func (node *ShowFilter) Format(buf *TrackedBuffer) { if node == nil { return } if node.Like != "" { buf.Myprintf(" like '%s'", node.Like) } else { buf.Myprintf(" where %v", node.Filter) } } // Format formats the node. func (node *Use) Format(buf *TrackedBuffer) { if node.DBName.v != "" { buf.Myprintf("use %v", node.DBName) } else { buf.Myprintf("use") } } // Format formats the node. func (node *Commit) Format(buf *TrackedBuffer) { buf.WriteString("commit") } // Format formats the node. func (node *Begin) Format(buf *TrackedBuffer) { buf.WriteString("begin") } // Format formats the node. func (node *Rollback) Format(buf *TrackedBuffer) { buf.WriteString("rollback") } // Format formats the node. func (node *OtherRead) Format(buf *TrackedBuffer) { buf.WriteString("otherread") } // Format formats the node. func (node *OtherAdmin) Format(buf *TrackedBuffer) { buf.WriteString("otheradmin") } // Format formats the node. func (node Comments) Format(buf *TrackedBuffer) { for _, c := range node { buf.Myprintf("%s ", c) } } // Format formats the node. func (node SelectExprs) Format(buf *TrackedBuffer) { var prefix string for _, n := range node { buf.Myprintf("%s%v", prefix, n) prefix = ", " } } // Format formats the node. func (node *StarExpr) Format(buf *TrackedBuffer) { if !node.TableName.IsEmpty() { buf.Myprintf("%v.", node.TableName) } buf.Myprintf("*") } // Format formats the node. func (node *AliasedExpr) Format(buf *TrackedBuffer) { buf.Myprintf("%v", node.Expr) if !node.As.IsEmpty() { buf.Myprintf(" as %v", node.As) } } // Format formats the node. func (node Nextval) Format(buf *TrackedBuffer) { buf.Myprintf("next %v values", node.Expr) } // Format formats the node. func (node Columns) Format(buf *TrackedBuffer) { if node == nil { return } prefix := "(" for _, n := range node { buf.Myprintf("%s%v", prefix, n) prefix = ", " } buf.WriteString(")") } // Format formats the node func (node Partitions) Format(buf *TrackedBuffer) { if node == nil { return } prefix := " partition (" for _, n := range node { buf.Myprintf("%s%v", prefix, n) prefix = ", " } buf.WriteString(")") } // Format formats the node. func (node TableExprs) Format(buf *TrackedBuffer) { var prefix string for _, n := range node { buf.Myprintf("%s%v", prefix, n) prefix = ", " } } // Format formats the node. func (node *AliasedTableExpr) Format(buf *TrackedBuffer) { buf.Myprintf("%v%v", node.Expr, node.Partitions) if !node.As.IsEmpty() { buf.Myprintf(" as %v", node.As) } if node.Hints != nil { // Hint node provides the space padding. buf.Myprintf("%v", node.Hints) } } // Format formats the node. func (node TableNames) Format(buf *TrackedBuffer) { var prefix string for _, n := range node { buf.Myprintf("%s%v", prefix, n) prefix = ", " } } // Format formats the node. func (node TableName) Format(buf *TrackedBuffer) { if node.IsEmpty() { return } if !node.Qualifier.IsEmpty() { buf.Myprintf("%v.", node.Qualifier) } buf.Myprintf("%v", node.Name) } // Format formats the node. func (node *ParenTableExpr) Format(buf *TrackedBuffer) { buf.Myprintf("(%v)", node.Exprs) } // Format formats the node. func (node JoinCondition) Format(buf *TrackedBuffer) { if node.On != nil { buf.Myprintf(" on %v", node.On) } if node.Using != nil { buf.Myprintf(" using %v", node.Using) } } // Format formats the node. func (node *JoinTableExpr) Format(buf *TrackedBuffer) { buf.Myprintf("%v %s %v%v", node.LeftExpr, node.Join, node.RightExpr, node.Condition) } // Format formats the node. func (node *IndexHints) Format(buf *TrackedBuffer) { buf.Myprintf(" %sindex ", node.Type) if len(node.Indexes) == 0 { buf.Myprintf("()") } else { prefix := "(" for _, n := range node.Indexes { buf.Myprintf("%s%v", prefix, n) prefix = ", " } buf.Myprintf(")") } } // Format formats the node. func (node *Where) Format(buf *TrackedBuffer) { if node == nil || node.Expr == nil { return } buf.Myprintf(" %s %v", node.Type, node.Expr) } // Format formats the node. func (node Exprs) Format(buf *TrackedBuffer) { var prefix string for _, n := range node { buf.Myprintf("%s%v", prefix, n) prefix = ", " } } // Format formats the node. func (node *AndExpr) Format(buf *TrackedBuffer) { buf.Myprintf("%v and %v", node.Left, node.Right) } // Format formats the node. func (node *OrExpr) Format(buf *TrackedBuffer) { buf.Myprintf("%v or %v", node.Left, node.Right) } // Format formats the node. func (node *NotExpr) Format(buf *TrackedBuffer) { buf.Myprintf("not %v", node.Expr) } // Format formats the node. func (node *ParenExpr) Format(buf *TrackedBuffer) { buf.Myprintf("(%v)", node.Expr) } // Format formats the node. func (node *ComparisonExpr) Format(buf *TrackedBuffer) { buf.Myprintf("%v %s %v", node.Left, node.Operator, node.Right) if node.Escape != nil { buf.Myprintf(" escape %v", node.Escape) } } // Format formats the node. func (node *RangeCond) Format(buf *TrackedBuffer) { buf.Myprintf("%v %s %v and %v", node.Left, node.Operator, node.From, node.To) } // Format formats the node. func (node *IsExpr) Format(buf *TrackedBuffer) { buf.Myprintf("%v %s", node.Expr, node.Operator) } // Format formats the node. func (node *ExistsExpr) Format(buf *TrackedBuffer) { buf.Myprintf("exists %v", node.Subquery) } // Format formats the node. func (node *SQLVal) Format(buf *TrackedBuffer) { switch node.Type { case StrVal: sqltypes.MakeTrusted(sqltypes.VarBinary, node.Val).EncodeSQL(buf) case IntVal, FloatVal, HexNum: buf.Myprintf("%s", []byte(node.Val)) case HexVal: buf.Myprintf("X'%s'", []byte(node.Val)) case BitVal: buf.Myprintf("B'%s'", []byte(node.Val)) case ValArg: buf.WriteArg(string(node.Val)) default: panic("unexpected") } } // Format formats the node. func (node *NullVal) Format(buf *TrackedBuffer) { buf.Myprintf("null") } // Format formats the node. func (node BoolVal) Format(buf *TrackedBuffer) { if node { buf.Myprintf("true") } else { buf.Myprintf("false") } } // Format formats the node. func (node *ColName) Format(buf *TrackedBuffer) { if !node.Qualifier.IsEmpty() { buf.Myprintf("%v.", node.Qualifier) } buf.Myprintf("%v", node.Name) } // Format formats the node. func (node ValTuple) Format(buf *TrackedBuffer) { buf.Myprintf("(%v)", Exprs(node)) } // Format formats the node. func (node *Subquery) Format(buf *TrackedBuffer) { buf.Myprintf("(%v)", node.Select) } // Format formats the node. func (node ListArg) Format(buf *TrackedBuffer) { buf.WriteArg(string(node)) } // Format formats the node. func (node *BinaryExpr) Format(buf *TrackedBuffer) { buf.Myprintf("%v %s %v", node.Left, node.Operator, node.Right) } // Format formats the node. func (node *UnaryExpr) Format(buf *TrackedBuffer) { if _, unary := node.Expr.(*UnaryExpr); unary { buf.Myprintf("%s %v", node.Operator, node.Expr) return } buf.Myprintf("%s%v", node.Operator, node.Expr) } // Format formats the node. func (node *IntervalExpr) Format(buf *TrackedBuffer) { buf.Myprintf("interval %v %s", node.Expr, node.Unit) } // Format formats the node. func (node *TimestampFuncExpr) Format(buf *TrackedBuffer) { buf.Myprintf("%s(%s, %v, %v)", node.Name, node.Unit, node.Expr1, node.Expr2) } // Format formats the node. func (node *CurTimeFuncExpr) Format(buf *TrackedBuffer) { buf.Myprintf("%s(%v)", node.Name.String(), node.Fsp) } // Format formats the node. func (node *CollateExpr) Format(buf *TrackedBuffer) { buf.Myprintf("%v collate %s", node.Expr, node.Charset) } // Format formats the node. func (node *FuncExpr) Format(buf *TrackedBuffer) { var distinct string if node.Distinct { distinct = "distinct " } if !node.Qualifier.IsEmpty() { buf.Myprintf("%v.", node.Qualifier) } // Function names should not be back-quoted even // if they match a reserved word, only if they contain illegal characters funcName := node.Name.String() if containEscapableChars(funcName, NoAt) { writeEscapedString(buf, funcName) } else { buf.WriteString(funcName) } buf.Myprintf("(%s%v)", distinct, node.Exprs) } // Format formats the node func (node *GroupConcatExpr) Format(buf *TrackedBuffer) { buf.Myprintf("group_concat(%s%v%v%s%v)", node.Distinct, node.Exprs, node.OrderBy, node.Separator, node.Limit) } // Format formats the node. func (node *ValuesFuncExpr) Format(buf *TrackedBuffer) { buf.Myprintf("values(%v)", node.Name) } // Format formats the node. func (node *SubstrExpr) Format(buf *TrackedBuffer) { var val interface{} if node.Name != nil { val = node.Name } else { val = node.StrVal } if node.To == nil { buf.Myprintf("substr(%v, %v)", val, node.From) } else { buf.Myprintf("substr(%v, %v, %v)", val, node.From, node.To) } } // Format formats the node. func (node *ConvertExpr) Format(buf *TrackedBuffer) { buf.Myprintf("convert(%v, %v)", node.Expr, node.Type) } // Format formats the node. func (node *ConvertUsingExpr) Format(buf *TrackedBuffer) { buf.Myprintf("convert(%v using %s)", node.Expr, node.Type) } // Format formats the node. func (node *ConvertType) Format(buf *TrackedBuffer) { buf.Myprintf("%s", node.Type) if node.Length != nil { buf.Myprintf("(%v", node.Length) if node.Scale != nil { buf.Myprintf(", %v", node.Scale) } buf.Myprintf(")") } if node.Charset != "" { buf.Myprintf("%s %s", node.Operator, node.Charset) } } // Format formats the node func (node *MatchExpr) Format(buf *TrackedBuffer) { buf.Myprintf("match(%v) against (%v%s)", node.Columns, node.Expr, node.Option) } // Format formats the node. func (node *CaseExpr) Format(buf *TrackedBuffer) { buf.Myprintf("case ") if node.Expr != nil { buf.Myprintf("%v ", node.Expr) } for _, when := range node.Whens { buf.Myprintf("%v ", when) } if node.Else != nil { buf.Myprintf("else %v ", node.Else) } buf.Myprintf("end") } // Format formats the node. func (node *Default) Format(buf *TrackedBuffer) { buf.Myprintf("default") if node.ColName != "" { buf.Myprintf("(%s)", node.ColName) } } // Format formats the node. func (node *When) Format(buf *TrackedBuffer) { buf.Myprintf("when %v then %v", node.Cond, node.Val) } // Format formats the node. func (node GroupBy) Format(buf *TrackedBuffer) { prefix := " group by " for _, n := range node { buf.Myprintf("%s%v", prefix, n) prefix = ", " } } // Format formats the node. func (node OrderBy) Format(buf *TrackedBuffer) { prefix := " order by " for _, n := range node { buf.Myprintf("%s%v", prefix, n) prefix = ", " } } // Format formats the node. func (node *Order) Format(buf *TrackedBuffer) { if node, ok := node.Expr.(*NullVal); ok { buf.Myprintf("%v", node) return } if node, ok := node.Expr.(*FuncExpr); ok { if node.Name.Lowered() == "rand" { buf.Myprintf("%v", node) return } } buf.Myprintf("%v %s", node.Expr, node.Direction) } // Format formats the node. func (node *Limit) Format(buf *TrackedBuffer) { if node == nil { return } buf.Myprintf(" limit ") if node.Offset != nil { buf.Myprintf("%v, ", node.Offset) } buf.Myprintf("%v", node.Rowcount) } // Format formats the node. func (node Values) Format(buf *TrackedBuffer) { prefix := "values " for _, n := range node { buf.Myprintf("%s%v", prefix, n) prefix = ", " } } // Format formats the node. func (node UpdateExprs) Format(buf *TrackedBuffer) { var prefix string for _, n := range node { buf.Myprintf("%s%v", prefix, n) prefix = ", " } } // Format formats the node. func (node *UpdateExpr) Format(buf *TrackedBuffer) { buf.Myprintf("%v = %v", node.Name, node.Expr) } // Format formats the node. func (node SetExprs) Format(buf *TrackedBuffer) { var prefix string for _, n := range node { buf.Myprintf("%s%v", prefix, n) prefix = ", " } } // Format formats the node. func (node *SetExpr) Format(buf *TrackedBuffer) { // We don't have to backtick set variable names. if node.Name.EqualString("charset") || node.Name.EqualString("names") { buf.Myprintf("%s %v", node.Name.String(), node.Expr) } else if node.Name.EqualString(TransactionStr) { sqlVal := node.Expr.(*SQLVal) buf.Myprintf("%s %s", node.Name.String(), strings.ToLower(string(sqlVal.Val))) } else { buf.Myprintf("%v = %v", node.Name, node.Expr) } } // Format formats the node. func (node OnDup) Format(buf *TrackedBuffer) { if node == nil { return } buf.Myprintf(" on duplicate key update %v", UpdateExprs(node)) } // Format formats the node. func (node ColIdent) Format(buf *TrackedBuffer) { for i := NoAt; i < node.at; i++ { buf.WriteByte('@') } formatID(buf, node.val, node.Lowered(), node.at) } // Format formats the node. func (node TableIdent) Format(buf *TrackedBuffer) { formatID(buf, node.v, strings.ToLower(node.v), NoAt) }