// Copyright 2015 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 ( "strings" "github.com/pingcap/errors" "github.com/pingcap/parser/auth" "github.com/pingcap/parser/model" "github.com/pingcap/parser/mysql" ) var ( _ DMLNode = &DeleteStmt{} _ DMLNode = &InsertStmt{} _ DMLNode = &UnionStmt{} _ DMLNode = &UpdateStmt{} _ DMLNode = &SelectStmt{} _ DMLNode = &ShowStmt{} _ DMLNode = &LoadDataStmt{} _ Node = &Assignment{} _ Node = &ByItem{} _ Node = &FieldList{} _ Node = &GroupByClause{} _ Node = &HavingClause{} _ Node = &Join{} _ Node = &Limit{} _ Node = &OnCondition{} _ Node = &OrderByClause{} _ Node = &SelectField{} _ Node = &TableName{} _ Node = &TableRefsClause{} _ Node = &TableSource{} _ Node = &UnionSelectList{} _ Node = &WildCardField{} _ Node = &WindowSpec{} _ Node = &PartitionByClause{} _ Node = &FrameClause{} _ Node = &FrameBound{} ) // JoinType is join type, including cross/left/right/full. type JoinType int const ( // CrossJoin is cross join type. CrossJoin JoinType = iota + 1 // LeftJoin is left Join type. LeftJoin // RightJoin is right Join type. RightJoin ) // Join represents table join. type Join struct { node resultSetNode // Left table can be TableSource or JoinNode. Left ResultSetNode // Right table can be TableSource or JoinNode or nil. Right ResultSetNode // Tp represents join type. Tp JoinType // On represents join on condition. On *OnCondition // Using represents join using clause. Using []*ColumnName // NaturalJoin represents join is natural join. NaturalJoin bool // StraightJoin represents a straight join. StraightJoin bool } // Restore implements Node interface. func (n *Join) Restore(ctx *RestoreCtx) error { if ctx.JoinLevel != 0 { ctx.WritePlain("(") defer ctx.WritePlain(")") } ctx.JoinLevel++ if err := n.Left.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore Join.Left") } ctx.JoinLevel-- if n.Right == nil { return nil } if n.NaturalJoin { ctx.WriteKeyWord(" NATURAL") } switch n.Tp { case LeftJoin: ctx.WriteKeyWord(" LEFT") case RightJoin: ctx.WriteKeyWord(" RIGHT") } if n.StraightJoin { ctx.WriteKeyWord(" STRAIGHT_JOIN ") } else { ctx.WriteKeyWord(" JOIN ") } ctx.JoinLevel++ if err := n.Right.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore Join.Right") } ctx.JoinLevel-- if n.On != nil { ctx.WritePlain(" ") if err := n.On.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore Join.On") } } if len(n.Using) != 0 { ctx.WriteKeyWord(" USING ") ctx.WritePlain("(") for i, v := range n.Using { if i != 0 { ctx.WritePlain(",") } if err := v.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore Join.Using") } } ctx.WritePlain(")") } return nil } // Accept implements Node Accept interface. func (n *Join) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*Join) node, ok := n.Left.Accept(v) if !ok { return n, false } n.Left = node.(ResultSetNode) if n.Right != nil { node, ok = n.Right.Accept(v) if !ok { return n, false } n.Right = node.(ResultSetNode) } if n.On != nil { node, ok = n.On.Accept(v) if !ok { return n, false } n.On = node.(*OnCondition) } return v.Leave(n) } // TableName represents a table name. type TableName struct { node resultSetNode Schema model.CIStr Name model.CIStr DBInfo *model.DBInfo TableInfo *model.TableInfo IndexHints []*IndexHint } // Restore implements Node interface. func (n *TableName) Restore(ctx *RestoreCtx) error { if n.Schema.String() != "" { ctx.WriteName(n.Schema.String()) ctx.WritePlain(".") } ctx.WriteName(n.Name.String()) for _, value := range n.IndexHints { ctx.WritePlain(" ") if err := value.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while splicing IndexHints") } } return nil } // IndexHintType is the type for index hint use, ignore or force. type IndexHintType int // IndexHintUseType values. const ( HintUse IndexHintType = 1 HintIgnore IndexHintType = 2 HintForce IndexHintType = 3 ) // IndexHintScope is the type for index hint for join, order by or group by. type IndexHintScope int // Index hint scopes. const ( HintForScan IndexHintScope = 1 HintForJoin IndexHintScope = 2 HintForOrderBy IndexHintScope = 3 HintForGroupBy IndexHintScope = 4 ) // IndexHint represents a hint for optimizer to use/ignore/force for join/order by/group by. type IndexHint struct { IndexNames []model.CIStr HintType IndexHintType HintScope IndexHintScope } // IndexHint Restore (The const field uses switch to facilitate understanding) func (n *IndexHint) Restore(ctx *RestoreCtx) error { indexHintType := "" switch n.HintType { case 1: indexHintType = "USE INDEX" case 2: indexHintType = "IGNORE INDEX" case 3: indexHintType = "FORCE INDEX" default: // Prevent accidents return errors.New("IndexHintType has an error while matching") } indexHintScope := "" switch n.HintScope { case 1: indexHintScope = "" case 2: indexHintScope = " FOR JOIN" case 3: indexHintScope = " FOR ORDER BY" case 4: indexHintScope = " FOR GROUP BY" default: // Prevent accidents return errors.New("IndexHintScope has an error while matching") } ctx.WriteKeyWord(indexHintType) ctx.WriteKeyWord(indexHintScope) ctx.WritePlain(" (") for i, value := range n.IndexNames { if i > 0 { ctx.WritePlain(", ") } ctx.WriteName(value.O) } ctx.WritePlain(")") return nil } // Accept implements Node Accept interface. func (n *TableName) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*TableName) return v.Leave(n) } // DeleteTableList is the tablelist used in delete statement multi-table mode. type DeleteTableList struct { node Tables []*TableName } // Restore implements Node interface. func (n *DeleteTableList) Restore(ctx *RestoreCtx) error { for i, t := range n.Tables { if i != 0 { ctx.WritePlain(",") } if err := t.Restore(ctx); err != nil { return errors.Annotatef(err, "An error occurred while restore DeleteTableList.Tables[%v]", i) } } return nil } // Accept implements Node Accept interface. func (n *DeleteTableList) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*DeleteTableList) if n != nil { for i, t := range n.Tables { node, ok := t.Accept(v) if !ok { return n, false } n.Tables[i] = node.(*TableName) } } return v.Leave(n) } // OnCondition represents JOIN on condition. type OnCondition struct { node Expr ExprNode } // Restore implements Node interface. func (n *OnCondition) Restore(ctx *RestoreCtx) error { ctx.WriteKeyWord("ON ") if err := n.Expr.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore OnCondition.Expr") } return nil } // Accept implements Node Accept interface. func (n *OnCondition) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*OnCondition) node, ok := n.Expr.Accept(v) if !ok { return n, false } n.Expr = node.(ExprNode) return v.Leave(n) } // TableSource represents table source with a name. type TableSource struct { node // Source is the source of the data, can be a TableName, // a SelectStmt, a UnionStmt, or a JoinNode. Source ResultSetNode // AsName is the alias name of the table source. AsName model.CIStr } // Restore implements Node interface. func (n *TableSource) Restore(ctx *RestoreCtx) error { needParen := false switch n.Source.(type) { case *SelectStmt, *UnionStmt: needParen = true } if needParen { ctx.WritePlain("(") } if err := n.Source.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore TableSource.Source") } if needParen { ctx.WritePlain(")") } if asName := n.AsName.String(); asName != "" { ctx.WriteKeyWord(" AS ") ctx.WriteName(asName) } return nil } // Accept implements Node Accept interface. func (n *TableSource) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*TableSource) node, ok := n.Source.Accept(v) if !ok { return n, false } n.Source = node.(ResultSetNode) return v.Leave(n) } // SelectLockType is the lock type for SelectStmt. type SelectLockType int // Select lock types. const ( SelectLockNone SelectLockType = iota SelectLockForUpdate SelectLockInShareMode ) // String implements fmt.Stringer. func (slt SelectLockType) String() string { switch slt { case SelectLockNone: return "none" case SelectLockForUpdate: return "for update" case SelectLockInShareMode: return "in share mode" } return "unsupported select lock type" } // WildCardField is a special type of select field content. type WildCardField struct { node Table model.CIStr Schema model.CIStr } // Restore implements Node interface. func (n *WildCardField) Restore(ctx *RestoreCtx) error { if schema := n.Schema.String(); schema != "" { ctx.WriteName(schema) ctx.WritePlain(".") } if table := n.Table.String(); table != "" { ctx.WriteName(table) ctx.WritePlain(".") } ctx.WritePlain("*") return nil } // Accept implements Node Accept interface. func (n *WildCardField) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*WildCardField) return v.Leave(n) } // SelectField represents fields in select statement. // There are two type of select field: wildcard // and expression with optional alias name. type SelectField struct { node // Offset is used to get original text. Offset int // WildCard is not nil, Expr will be nil. WildCard *WildCardField // Expr is not nil, WildCard will be nil. Expr ExprNode // AsName is alias name for Expr. AsName model.CIStr // Auxiliary stands for if this field is auxiliary. // When we add a Field into SelectField list which is used for having/orderby clause but the field is not in select clause, // we should set its Auxiliary to true. Then the TrimExec will trim the field. Auxiliary bool } // Restore implements Node interface. func (n *SelectField) Restore(ctx *RestoreCtx) error { if n.WildCard != nil { if err := n.WildCard.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore SelectField.WildCard") } } if n.Expr != nil { if err := n.Expr.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore SelectField.Expr") } } if asName := n.AsName.String(); asName != "" { ctx.WriteKeyWord(" AS ") ctx.WriteName(asName) } return nil } // Accept implements Node Accept interface. func (n *SelectField) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*SelectField) if n.Expr != nil { node, ok := n.Expr.Accept(v) if !ok { return n, false } n.Expr = node.(ExprNode) } return v.Leave(n) } // FieldList represents field list in select statement. type FieldList struct { node Fields []*SelectField } // Restore implements Node interface. func (n *FieldList) Restore(ctx *RestoreCtx) error { for i, v := range n.Fields { if i != 0 { ctx.WritePlain(", ") } if err := v.Restore(ctx); err != nil { return errors.Annotatef(err, "An error occurred while restore FieldList.Fields[%d]", i) } } return nil } // Accept implements Node Accept interface. func (n *FieldList) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*FieldList) for i, val := range n.Fields { node, ok := val.Accept(v) if !ok { return n, false } n.Fields[i] = node.(*SelectField) } return v.Leave(n) } // TableRefsClause represents table references clause in dml statement. type TableRefsClause struct { node TableRefs *Join } // Restore implements Node interface. func (n *TableRefsClause) Restore(ctx *RestoreCtx) error { if err := n.TableRefs.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore TableRefsClause.TableRefs") } return nil } // Accept implements Node Accept interface. func (n *TableRefsClause) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*TableRefsClause) node, ok := n.TableRefs.Accept(v) if !ok { return n, false } n.TableRefs = node.(*Join) return v.Leave(n) } // ByItem represents an item in order by or group by. type ByItem struct { node Expr ExprNode Desc bool } // Restore implements Node interface. func (n *ByItem) Restore(ctx *RestoreCtx) error { if err := n.Expr.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore ByItem.Expr") } if n.Desc { ctx.WriteKeyWord(" DESC") } return nil } // Accept implements Node Accept interface. func (n *ByItem) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*ByItem) node, ok := n.Expr.Accept(v) if !ok { return n, false } n.Expr = node.(ExprNode) return v.Leave(n) } // GroupByClause represents group by clause. type GroupByClause struct { node Items []*ByItem } // Restore implements Node interface. func (n *GroupByClause) Restore(ctx *RestoreCtx) error { ctx.WriteKeyWord("GROUP BY ") for i, v := range n.Items { if i != 0 { ctx.WritePlain(",") } if err := v.Restore(ctx); err != nil { return errors.Annotatef(err, "An error occurred while restore GroupByClause.Items[%d]", i) } } return nil } // Accept implements Node Accept interface. func (n *GroupByClause) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*GroupByClause) for i, val := range n.Items { node, ok := val.Accept(v) if !ok { return n, false } n.Items[i] = node.(*ByItem) } return v.Leave(n) } // HavingClause represents having clause. type HavingClause struct { node Expr ExprNode } // Restore implements Node interface. func (n *HavingClause) Restore(ctx *RestoreCtx) error { ctx.WriteKeyWord("HAVING ") if err := n.Expr.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore HavingClause.Expr") } return nil } // Accept implements Node Accept interface. func (n *HavingClause) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*HavingClause) node, ok := n.Expr.Accept(v) if !ok { return n, false } n.Expr = node.(ExprNode) return v.Leave(n) } // OrderByClause represents order by clause. type OrderByClause struct { node Items []*ByItem ForUnion bool } // Restore implements Node interface. func (n *OrderByClause) Restore(ctx *RestoreCtx) error { ctx.WriteKeyWord("ORDER BY ") for i, item := range n.Items { if i != 0 { ctx.WritePlain(",") } if err := item.Restore(ctx); err != nil { return errors.Annotatef(err, "An error occurred while restore OrderByClause.Items[%d]", i) } } return nil } // Accept implements Node Accept interface. func (n *OrderByClause) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*OrderByClause) for i, val := range n.Items { node, ok := val.Accept(v) if !ok { return n, false } n.Items[i] = node.(*ByItem) } return v.Leave(n) } // SelectStmt represents the select query node. // See https://dev.mysql.com/doc/refman/5.7/en/select.html type SelectStmt struct { dmlNode resultSetNode // SelectStmtOpts wraps around select hints and switches. *SelectStmtOpts // Distinct represents whether the select has distinct option. Distinct bool // From is the from clause of the query. From *TableRefsClause // Where is the where clause in select statement. Where ExprNode // Fields is the select expression list. Fields *FieldList // GroupBy is the group by expression list. GroupBy *GroupByClause // Having is the having condition. Having *HavingClause // WindowSpecs is the window specification list. WindowSpecs []WindowSpec // OrderBy is the ordering expression list. OrderBy *OrderByClause // Limit is the limit clause. Limit *Limit // LockTp is the lock type LockTp SelectLockType // TableHints represents the table level Optimizer Hint for join type TableHints []*TableOptimizerHint // IsAfterUnionDistinct indicates whether it's a stmt after "union distinct". IsAfterUnionDistinct bool // IsInBraces indicates whether it's a stmt in brace. IsInBraces bool } // Restore implements Node interface. func (n *SelectStmt) Restore(ctx *RestoreCtx) error { return errors.New("Not implemented") } // Accept implements Node Accept interface. func (n *SelectStmt) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*SelectStmt) if n.TableHints != nil && len(n.TableHints) != 0 { newHints := make([]*TableOptimizerHint, len(n.TableHints)) for i, hint := range n.TableHints { node, ok := hint.Accept(v) if !ok { return n, false } newHints[i] = node.(*TableOptimizerHint) } n.TableHints = newHints } if n.From != nil { node, ok := n.From.Accept(v) if !ok { return n, false } n.From = node.(*TableRefsClause) } if n.Where != nil { node, ok := n.Where.Accept(v) if !ok { return n, false } n.Where = node.(ExprNode) } if n.Fields != nil { node, ok := n.Fields.Accept(v) if !ok { return n, false } n.Fields = node.(*FieldList) } if n.GroupBy != nil { node, ok := n.GroupBy.Accept(v) if !ok { return n, false } n.GroupBy = node.(*GroupByClause) } if n.Having != nil { node, ok := n.Having.Accept(v) if !ok { return n, false } n.Having = node.(*HavingClause) } for i, spec := range n.WindowSpecs { node, ok := spec.Accept(v) if !ok { return n, false } n.WindowSpecs[i] = *node.(*WindowSpec) } if n.OrderBy != nil { node, ok := n.OrderBy.Accept(v) if !ok { return n, false } n.OrderBy = node.(*OrderByClause) } if n.Limit != nil { node, ok := n.Limit.Accept(v) if !ok { return n, false } n.Limit = node.(*Limit) } return v.Leave(n) } // UnionSelectList represents the select list in a union statement. type UnionSelectList struct { node Selects []*SelectStmt } // Restore implements Node interface. func (n *UnionSelectList) Restore(ctx *RestoreCtx) error { return errors.New("Not implemented") } // Accept implements Node Accept interface. func (n *UnionSelectList) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*UnionSelectList) for i, sel := range n.Selects { node, ok := sel.Accept(v) if !ok { return n, false } n.Selects[i] = node.(*SelectStmt) } return v.Leave(n) } // UnionStmt represents "union statement" // See https://dev.mysql.com/doc/refman/5.7/en/union.html type UnionStmt struct { dmlNode resultSetNode SelectList *UnionSelectList OrderBy *OrderByClause Limit *Limit } // Restore implements Node interface. func (n *UnionStmt) Restore(ctx *RestoreCtx) error { return errors.New("Not implemented") } // Accept implements Node Accept interface. func (n *UnionStmt) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*UnionStmt) if n.SelectList != nil { node, ok := n.SelectList.Accept(v) if !ok { return n, false } n.SelectList = node.(*UnionSelectList) } if n.OrderBy != nil { node, ok := n.OrderBy.Accept(v) if !ok { return n, false } n.OrderBy = node.(*OrderByClause) } if n.Limit != nil { node, ok := n.Limit.Accept(v) if !ok { return n, false } n.Limit = node.(*Limit) } return v.Leave(n) } // Assignment is the expression for assignment, like a = 1. type Assignment struct { node // Column is the column name to be assigned. Column *ColumnName // Expr is the expression assigning to ColName. Expr ExprNode } // Restore implements Node interface. func (n *Assignment) Restore(ctx *RestoreCtx) error { if err := n.Column.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore Assignment.Column") } ctx.WritePlain("=") if err := n.Expr.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore Assignment.Expr") } return nil } // Accept implements Node Accept interface. func (n *Assignment) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*Assignment) node, ok := n.Column.Accept(v) if !ok { return n, false } n.Column = node.(*ColumnName) node, ok = n.Expr.Accept(v) if !ok { return n, false } n.Expr = node.(ExprNode) return v.Leave(n) } // LoadDataStmt is a statement to load data from a specified file, then insert this rows into an existing table. // See https://dev.mysql.com/doc/refman/5.7/en/load-data.html type LoadDataStmt struct { dmlNode IsLocal bool Path string Table *TableName Columns []*ColumnName FieldsInfo *FieldsClause LinesInfo *LinesClause IgnoreLines uint64 } // Restore implements Node interface. func (n *LoadDataStmt) Restore(ctx *RestoreCtx) error { return errors.New("Not implemented") } // Accept implements Node Accept interface. func (n *LoadDataStmt) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*LoadDataStmt) if n.Table != nil { node, ok := n.Table.Accept(v) if !ok { return n, false } n.Table = node.(*TableName) } for i, val := range n.Columns { node, ok := val.Accept(v) if !ok { return n, false } n.Columns[i] = node.(*ColumnName) } return v.Leave(n) } // FieldsClause represents fields references clause in load data statement. type FieldsClause struct { Terminated string Enclosed byte Escaped byte } // LinesClause represents lines references clause in load data statement. type LinesClause struct { Starting string Terminated string } // InsertStmt is a statement to insert new rows into an existing table. // See https://dev.mysql.com/doc/refman/5.7/en/insert.html type InsertStmt struct { dmlNode IsReplace bool IgnoreErr bool Table *TableRefsClause Columns []*ColumnName Lists [][]ExprNode Setlist []*Assignment Priority mysql.PriorityEnum OnDuplicate []*Assignment Select ResultSetNode } // Restore implements Node interface. func (n *InsertStmt) Restore(ctx *RestoreCtx) error { return errors.New("Not implemented") } // Accept implements Node Accept interface. func (n *InsertStmt) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*InsertStmt) if n.Select != nil { node, ok := n.Select.Accept(v) if !ok { return n, false } n.Select = node.(ResultSetNode) } node, ok := n.Table.Accept(v) if !ok { return n, false } n.Table = node.(*TableRefsClause) for i, val := range n.Columns { node, ok := val.Accept(v) if !ok { return n, false } n.Columns[i] = node.(*ColumnName) } for i, list := range n.Lists { for j, val := range list { node, ok := val.Accept(v) if !ok { return n, false } n.Lists[i][j] = node.(ExprNode) } } for i, val := range n.Setlist { node, ok := val.Accept(v) if !ok { return n, false } n.Setlist[i] = node.(*Assignment) } for i, val := range n.OnDuplicate { node, ok := val.Accept(v) if !ok { return n, false } n.OnDuplicate[i] = node.(*Assignment) } return v.Leave(n) } // DeleteStmt is a statement to delete rows from table. // See https://dev.mysql.com/doc/refman/5.7/en/delete.html type DeleteStmt struct { dmlNode // TableRefs is used in both single table and multiple table delete statement. TableRefs *TableRefsClause // Tables is only used in multiple table delete statement. Tables *DeleteTableList Where ExprNode Order *OrderByClause Limit *Limit Priority mysql.PriorityEnum IgnoreErr bool Quick bool IsMultiTable bool BeforeFrom bool // TableHints represents the table level Optimizer Hint for join type. TableHints []*TableOptimizerHint } // Restore implements Node interface. func (n *DeleteStmt) Restore(ctx *RestoreCtx) error { return errors.New("Not implemented") } // Accept implements Node Accept interface. func (n *DeleteStmt) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*DeleteStmt) node, ok := n.TableRefs.Accept(v) if !ok { return n, false } n.TableRefs = node.(*TableRefsClause) node, ok = n.Tables.Accept(v) if !ok { return n, false } n.Tables = node.(*DeleteTableList) if n.Where != nil { node, ok = n.Where.Accept(v) if !ok { return n, false } n.Where = node.(ExprNode) } if n.Order != nil { node, ok = n.Order.Accept(v) if !ok { return n, false } n.Order = node.(*OrderByClause) } if n.Limit != nil { node, ok = n.Limit.Accept(v) if !ok { return n, false } n.Limit = node.(*Limit) } return v.Leave(n) } // UpdateStmt is a statement to update columns of existing rows in tables with new values. // See https://dev.mysql.com/doc/refman/5.7/en/update.html type UpdateStmt struct { dmlNode TableRefs *TableRefsClause List []*Assignment Where ExprNode Order *OrderByClause Limit *Limit Priority mysql.PriorityEnum IgnoreErr bool MultipleTable bool TableHints []*TableOptimizerHint } // Restore implements Node interface. func (n *UpdateStmt) Restore(ctx *RestoreCtx) error { return errors.New("Not implemented") } // Accept implements Node Accept interface. func (n *UpdateStmt) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*UpdateStmt) node, ok := n.TableRefs.Accept(v) if !ok { return n, false } n.TableRefs = node.(*TableRefsClause) for i, val := range n.List { node, ok = val.Accept(v) if !ok { return n, false } n.List[i] = node.(*Assignment) } if n.Where != nil { node, ok = n.Where.Accept(v) if !ok { return n, false } n.Where = node.(ExprNode) } if n.Order != nil { node, ok = n.Order.Accept(v) if !ok { return n, false } n.Order = node.(*OrderByClause) } if n.Limit != nil { node, ok = n.Limit.Accept(v) if !ok { return n, false } n.Limit = node.(*Limit) } return v.Leave(n) } // Limit is the limit clause. type Limit struct { node Count ExprNode Offset ExprNode } // Restore implements Node interface. func (n *Limit) Restore(ctx *RestoreCtx) error { ctx.WriteKeyWord("LIMIT ") if n.Offset != nil { if err := n.Offset.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore Limit.Offset") } ctx.WritePlain(",") } if err := n.Count.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore Limit.Count") } return nil } // Accept implements Node Accept interface. func (n *Limit) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } if n.Count != nil { node, ok := n.Count.Accept(v) if !ok { return n, false } n.Count = node.(ExprNode) } if n.Offset != nil { node, ok := n.Offset.Accept(v) if !ok { return n, false } n.Offset = node.(ExprNode) } n = newNode.(*Limit) return v.Leave(n) } // ShowStmtType is the type for SHOW statement. type ShowStmtType int // Show statement types. const ( ShowNone = iota ShowEngines ShowDatabases ShowTables ShowTableStatus ShowColumns ShowWarnings ShowCharset ShowVariables ShowStatus ShowCollation ShowCreateTable ShowGrants ShowTriggers ShowProcedureStatus ShowIndex ShowProcessList ShowCreateDatabase ShowEvents ShowStatsMeta ShowStatsHistograms ShowStatsBuckets ShowStatsHealthy ShowPlugins ShowProfiles ShowMasterStatus ShowPrivileges ShowErrors ) // ShowStmt is a statement to provide information about databases, tables, columns and so on. // See https://dev.mysql.com/doc/refman/5.7/en/show.html type ShowStmt struct { dmlNode resultSetNode Tp ShowStmtType // Databases/Tables/Columns/.... DBName string Table *TableName // Used for showing columns. Column *ColumnName // Used for `desc table column`. Flag int // Some flag parsed from sql, such as FULL. Full bool User *auth.UserIdentity // Used for show grants. IfNotExists bool // Used for `show create database if not exists` // GlobalScope is used by show variables GlobalScope bool Pattern *PatternLikeExpr Where ExprNode } // Restore implements Node interface. func (n *ShowStmt) Restore(ctx *RestoreCtx) error { return errors.New("Not implemented") } // Accept implements Node Accept interface. func (n *ShowStmt) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*ShowStmt) if n.Table != nil { node, ok := n.Table.Accept(v) if !ok { return n, false } n.Table = node.(*TableName) } if n.Column != nil { node, ok := n.Column.Accept(v) if !ok { return n, false } n.Column = node.(*ColumnName) } if n.Pattern != nil { node, ok := n.Pattern.Accept(v) if !ok { return n, false } n.Pattern = node.(*PatternLikeExpr) } switch n.Tp { case ShowTriggers, ShowProcedureStatus, ShowProcessList, ShowEvents: // We don't have any data to return for those types, // but visiting Where may cause resolving error, so return here to avoid error. return v.Leave(n) } if n.Where != nil { node, ok := n.Where.Accept(v) if !ok { return n, false } n.Where = node.(ExprNode) } return v.Leave(n) } // WindowSpec is the specification of a window. type WindowSpec struct { node Name model.CIStr // Ref is the reference window of this specification. For example, in `w2 as (w1 order by a)`, // the definition of `w2` references `w1`. Ref model.CIStr PartitionBy *PartitionByClause OrderBy *OrderByClause Frame *FrameClause } // Restore implements Node interface. func (n *WindowSpec) Restore(ctx *RestoreCtx) error { return errors.New("Not implemented") } // Accept implements Node Accept interface. func (n *WindowSpec) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*WindowSpec) if n.PartitionBy != nil { node, ok := n.PartitionBy.Accept(v) if !ok { return n, false } n.PartitionBy = node.(*PartitionByClause) } if n.OrderBy != nil { node, ok := n.OrderBy.Accept(v) if !ok { return n, false } n.OrderBy = node.(*OrderByClause) } if n.Frame != nil { node, ok := n.Frame.Accept(v) if !ok { return n, false } n.Frame = node.(*FrameClause) } return v.Leave(n) } // PartitionByClause represents partition by clause. type PartitionByClause struct { node Items []*ByItem } // Restore implements Node interface. func (n *PartitionByClause) Restore(ctx *RestoreCtx) error { return errors.New("Not implemented") } // Accept implements Node Accept interface. func (n *PartitionByClause) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*PartitionByClause) for i, val := range n.Items { node, ok := val.Accept(v) if !ok { return n, false } n.Items[i] = node.(*ByItem) } return v.Leave(n) } // FrameType is the type of window function frame. type FrameType int // Window function frame types. // MySQL only supports `ROWS` and `RANGES`. const ( Rows = iota Ranges Groups ) // FrameClause represents frame clause. type FrameClause struct { node Type FrameType Extent FrameExtent } // Restore implements Node interface. func (n *FrameClause) Restore(ctx *RestoreCtx) error { return errors.New("Not implemented") } // Accept implements Node Accept interface. func (n *FrameClause) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*FrameClause) node, ok := n.Extent.Start.Accept(v) if !ok { return n, false } n.Extent.Start = *node.(*FrameBound) node, ok = n.Extent.End.Accept(v) if !ok { return n, false } n.Extent.End = *node.(*FrameBound) return v.Leave(n) } // FrameExtent represents frame extent. type FrameExtent struct { Start FrameBound End FrameBound } // FrameType is the type of window function frame bound. type BoundType int // Frame bound types. const ( Following = iota Preceding CurrentRow ) // FrameBound represents frame bound. type FrameBound struct { node Type BoundType UnBounded bool Expr ExprNode // `Unit` is used to indicate the units in which the `Expr` should be interpreted. // For example: '2:30' MINUTE_SECOND. Unit ExprNode } // Restore implements Node interface. func (n *FrameBound) Restore(ctx *RestoreCtx) error { if n.UnBounded { ctx.WriteKeyWord("UNBOUNDED") } switch n.Type { case CurrentRow: ctx.WriteKeyWord("CURRENT ROW") case Preceding, Following: if n.Unit != nil { ctx.WriteKeyWord("INTERVAL ") } if n.Expr != nil { if err := n.Expr.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore FrameBound.Expr") } } if n.Unit != nil { // Here the Unit string should not be quoted. // TODO: This is a temporary workaround that should be changed once something like "Keyword Expression" is implemented. var sb strings.Builder n.Unit.Restore(NewRestoreCtx(0, &sb)) ctx.WritePlain(" ") ctx.WriteKeyWord(sb.String()) } if n.Type == Preceding { ctx.WriteKeyWord(" PRECEDING") } else { ctx.WriteKeyWord(" FOLLOWING") } } return nil } // Accept implements Node Accept interface. func (n *FrameBound) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*FrameBound) if n.Expr != nil { node, ok := n.Expr.Accept(v) if !ok { return n, false } n.Expr = node.(ExprNode) } if n.Unit != nil { node, ok := n.Unit.Accept(v) if !ok { return n, false } n.Unit = node.(ExprNode) } return v.Leave(n) }