// 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 ( "fmt" "io" "reflect" "regexp" "strings" "github.com/pingcap/errors" "github.com/pingcap/parser/format" "github.com/pingcap/parser/model" "github.com/pingcap/parser/opcode" ) var ( _ ExprNode = &BetweenExpr{} _ ExprNode = &BinaryOperationExpr{} _ ExprNode = &CaseExpr{} _ ExprNode = &ColumnNameExpr{} _ ExprNode = &TableNameExpr{} _ ExprNode = &CompareSubqueryExpr{} _ ExprNode = &DefaultExpr{} _ ExprNode = &ExistsSubqueryExpr{} _ ExprNode = &IsNullExpr{} _ ExprNode = &IsTruthExpr{} _ ExprNode = &ParenthesesExpr{} _ ExprNode = &PatternInExpr{} _ ExprNode = &PatternLikeExpr{} _ ExprNode = &PatternRegexpExpr{} _ ExprNode = &PositionExpr{} _ ExprNode = &RowExpr{} _ ExprNode = &SubqueryExpr{} _ ExprNode = &UnaryOperationExpr{} _ ExprNode = &ValuesExpr{} _ ExprNode = &VariableExpr{} _ ExprNode = &MatchAgainst{} _ ExprNode = &SetCollationExpr{} _ Node = &ColumnName{} _ Node = &WhenClause{} ) // ValueExpr define a interface for ValueExpr. type ValueExpr interface { ExprNode SetValue(val interface{}) GetValue() interface{} GetDatumString() string GetString() string GetProjectionOffset() int SetProjectionOffset(offset int) } // NewValueExpr creates a ValueExpr with value, and sets default field type. var NewValueExpr func(value interface{}, charset string, collate string) ValueExpr // NewParamMarkerExpr creates a ParamMarkerExpr. var NewParamMarkerExpr func(offset int) ParamMarkerExpr // BetweenExpr is for "between and" or "not between and" expression. type BetweenExpr struct { exprNode // Expr is the expression to be checked. Expr ExprNode // Left is the expression for minimal value in the range. Left ExprNode // Right is the expression for maximum value in the range. Right ExprNode // Not is true, the expression is "not between and". Not bool } // Restore implements Node interface. func (n *BetweenExpr) Restore(ctx *format.RestoreCtx) error { if err := n.Expr.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore BetweenExpr.Expr") } if n.Not { ctx.WriteKeyWord(" NOT BETWEEN ") } else { ctx.WriteKeyWord(" BETWEEN ") } if err := n.Left.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore BetweenExpr.Left") } ctx.WriteKeyWord(" AND ") if err := n.Right.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore BetweenExpr.Right ") } return nil } // Format the ExprNode into a Writer. func (n *BetweenExpr) Format(w io.Writer) { n.Expr.Format(w) if n.Not { fmt.Fprint(w, " NOT BETWEEN ") } else { fmt.Fprint(w, " BETWEEN ") } n.Left.Format(w) fmt.Fprint(w, " AND ") n.Right.Format(w) } // Accept implements Node interface. func (n *BetweenExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*BetweenExpr) node, ok := n.Expr.Accept(v) if !ok { return n, false } n.Expr = node.(ExprNode) node, ok = n.Left.Accept(v) if !ok { return n, false } n.Left = node.(ExprNode) node, ok = n.Right.Accept(v) if !ok { return n, false } n.Right = node.(ExprNode) return v.Leave(n) } // BinaryOperationExpr is for binary operation like `1 + 1`, `1 - 1`, etc. type BinaryOperationExpr struct { exprNode // Op is the operator code for BinaryOperation. Op opcode.Op // L is the left expression in BinaryOperation. L ExprNode // R is the right expression in BinaryOperation. R ExprNode } func restoreBinaryOpWithSpacesAround(ctx *format.RestoreCtx, op opcode.Op) error { shouldInsertSpace := ctx.Flags.HasSpacesAroundBinaryOperationFlag() || op.IsKeyword() if shouldInsertSpace { ctx.WritePlain(" ") } if err := op.Restore(ctx); err != nil { return err // no need to annotate, the caller will annotate. } if shouldInsertSpace { ctx.WritePlain(" ") } return nil } // Restore implements Node interface. func (n *BinaryOperationExpr) Restore(ctx *format.RestoreCtx) error { if err := n.L.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred when restore BinaryOperationExpr.L") } if err := restoreBinaryOpWithSpacesAround(ctx, n.Op); err != nil { return errors.Annotate(err, "An error occurred when restore BinaryOperationExpr.Op") } if err := n.R.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred when restore BinaryOperationExpr.R") } return nil } // Format the ExprNode into a Writer. func (n *BinaryOperationExpr) Format(w io.Writer) { n.L.Format(w) fmt.Fprint(w, " ") n.Op.Format(w) fmt.Fprint(w, " ") n.R.Format(w) } // Accept implements Node interface. func (n *BinaryOperationExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*BinaryOperationExpr) node, ok := n.L.Accept(v) if !ok { return n, false } n.L = node.(ExprNode) node, ok = n.R.Accept(v) if !ok { return n, false } n.R = node.(ExprNode) return v.Leave(n) } // WhenClause is the when clause in Case expression for "when condition then result". type WhenClause struct { node // Expr is the condition expression in WhenClause. Expr ExprNode // Result is the result expression in WhenClause. Result ExprNode } // Restore implements Node interface. func (n *WhenClause) Restore(ctx *format.RestoreCtx) error { ctx.WriteKeyWord("WHEN ") if err := n.Expr.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore WhenClauses.Expr") } ctx.WriteKeyWord(" THEN ") if err := n.Result.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore WhenClauses.Result") } return nil } // Accept implements Node Accept interface. func (n *WhenClause) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*WhenClause) node, ok := n.Expr.Accept(v) if !ok { return n, false } n.Expr = node.(ExprNode) node, ok = n.Result.Accept(v) if !ok { return n, false } n.Result = node.(ExprNode) return v.Leave(n) } // CaseExpr is the case expression. type CaseExpr struct { exprNode // Value is the compare value expression. Value ExprNode // WhenClauses is the condition check expression. WhenClauses []*WhenClause // ElseClause is the else result expression. ElseClause ExprNode } // Restore implements Node interface. func (n *CaseExpr) Restore(ctx *format.RestoreCtx) error { ctx.WriteKeyWord("CASE") if n.Value != nil { ctx.WritePlain(" ") if err := n.Value.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore CaseExpr.Value") } } for _, clause := range n.WhenClauses { ctx.WritePlain(" ") if err := clause.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore CaseExpr.WhenClauses") } } if n.ElseClause != nil { ctx.WriteKeyWord(" ELSE ") if err := n.ElseClause.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore CaseExpr.ElseClause") } } ctx.WriteKeyWord(" END") return nil } // Format the ExprNode into a Writer. func (n *CaseExpr) Format(w io.Writer) { fmt.Fprint(w, "CASE") // Because the presence of `case when` syntax, `Value` could be nil and we need check this. if n.Value != nil { fmt.Fprint(w, " ") n.Value.Format(w) } for _, clause := range n.WhenClauses { fmt.Fprint(w, " ") fmt.Fprint(w, "WHEN ") clause.Expr.Format(w) fmt.Fprint(w, " THEN ") clause.Result.Format(w) } if n.ElseClause != nil { fmt.Fprint(w, " ELSE ") n.ElseClause.Format(w) } fmt.Fprint(w, " END") } // Accept implements Node Accept interface. func (n *CaseExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*CaseExpr) if n.Value != nil { node, ok := n.Value.Accept(v) if !ok { return n, false } n.Value = node.(ExprNode) } for i, val := range n.WhenClauses { node, ok := val.Accept(v) if !ok { return n, false } n.WhenClauses[i] = node.(*WhenClause) } if n.ElseClause != nil { node, ok := n.ElseClause.Accept(v) if !ok { return n, false } n.ElseClause = node.(ExprNode) } return v.Leave(n) } // SubqueryExpr represents a subquery. type SubqueryExpr struct { exprNode // Query is the query SelectNode. Query ResultSetNode Evaluated bool Correlated bool MultiRows bool Exists bool } // Restore implements Node interface. func (n *SubqueryExpr) Restore(ctx *format.RestoreCtx) error { ctx.WritePlain("(") if err := n.Query.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore SubqueryExpr.Query") } ctx.WritePlain(")") return nil } // Format the ExprNode into a Writer. func (n *SubqueryExpr) Format(w io.Writer) { panic("Not implemented") } // Accept implements Node Accept interface. func (n *SubqueryExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*SubqueryExpr) node, ok := n.Query.Accept(v) if !ok { return n, false } n.Query = node.(ResultSetNode) return v.Leave(n) } // CompareSubqueryExpr is the expression for "expr cmp (select ...)". // See https://dev.mysql.com/doc/refman/5.7/en/comparisons-using-subqueries.html // See https://dev.mysql.com/doc/refman/5.7/en/any-in-some-subqueries.html // See https://dev.mysql.com/doc/refman/5.7/en/all-subqueries.html type CompareSubqueryExpr struct { exprNode // L is the left expression L ExprNode // Op is the comparison opcode. Op opcode.Op // R is the subquery for right expression, may be rewritten to other type of expression. R ExprNode // All is true, we should compare all records in subquery. All bool } // Restore implements Node interface. func (n *CompareSubqueryExpr) Restore(ctx *format.RestoreCtx) error { if err := n.L.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore CompareSubqueryExpr.L") } if err := restoreBinaryOpWithSpacesAround(ctx, n.Op); err != nil { return errors.Annotate(err, "An error occurred while restore CompareSubqueryExpr.Op") } if n.All { ctx.WriteKeyWord("ALL ") } else { ctx.WriteKeyWord("ANY ") } if err := n.R.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore CompareSubqueryExpr.R") } return nil } // Format the ExprNode into a Writer. func (n *CompareSubqueryExpr) Format(w io.Writer) { panic("Not implemented") } // Accept implements Node Accept interface. func (n *CompareSubqueryExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*CompareSubqueryExpr) node, ok := n.L.Accept(v) if !ok { return n, false } n.L = node.(ExprNode) node, ok = n.R.Accept(v) if !ok { return n, false } n.R = node.(ExprNode) return v.Leave(n) } // TableNameExpr represents a table-level object name expression, such as sequence/table/view etc. type TableNameExpr struct { exprNode // Name is the referenced object name expression. Name *TableName } // Restore implements Node interface. func (n *TableNameExpr) Restore(ctx *format.RestoreCtx) error { if err := n.Name.Restore(ctx); err != nil { return errors.Trace(err) } return nil } // Format the ExprNode into a Writer. func (n *TableNameExpr) Format(w io.Writer) { dbName, tbName := n.Name.Schema.L, n.Name.Name.L if dbName == "" { fmt.Fprintf(w, "`%s`", tbName) } else { fmt.Fprintf(w, "`%s`.`%s`", dbName, tbName) } } // Accept implements Node Accept interface. func (n *TableNameExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*TableNameExpr) node, ok := n.Name.Accept(v) if !ok { return n, false } n.Name = node.(*TableName) return v.Leave(n) } // ColumnName represents column name. type ColumnName struct { node Schema model.CIStr Table model.CIStr Name model.CIStr } // Restore implements Node interface. func (n *ColumnName) Restore(ctx *format.RestoreCtx) error { if n.Schema.O != "" { ctx.WriteName(n.Schema.O) ctx.WritePlain(".") } if n.Table.O != "" { ctx.WriteName(n.Table.O) ctx.WritePlain(".") } ctx.WriteName(n.Name.O) return nil } // Accept implements Node Accept interface. func (n *ColumnName) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*ColumnName) return v.Leave(n) } // String implements Stringer interface. func (n *ColumnName) String() string { result := n.Name.L if n.Table.L != "" { result = n.Table.L + "." + result } if n.Schema.L != "" { result = n.Schema.L + "." + result } return result } // OrigColName returns the full original column name. func (n *ColumnName) OrigColName() (ret string) { ret = n.Name.O if n.Table.O == "" { return } ret = n.Table.O + "." + ret if n.Schema.O == "" { return } ret = n.Schema.O + "." + ret return } // ColumnNameExpr represents a column name expression. type ColumnNameExpr struct { exprNode // Name is the referenced column name. Name *ColumnName // Refer is the result field the column name refers to. // The value of Refer.Expr is used as the value of the expression. Refer *ResultField } // Restore implements Node interface. func (n *ColumnNameExpr) Restore(ctx *format.RestoreCtx) error { if err := n.Name.Restore(ctx); err != nil { return errors.Trace(err) } return nil } // Format the ExprNode into a Writer. func (n *ColumnNameExpr) Format(w io.Writer) { name := strings.Replace(n.Name.String(), ".", "`.`", -1) fmt.Fprintf(w, "`%s`", name) } // Accept implements Node Accept interface. func (n *ColumnNameExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*ColumnNameExpr) node, ok := n.Name.Accept(v) if !ok { return n, false } n.Name = node.(*ColumnName) return v.Leave(n) } // DefaultExpr is the default expression using default value for a column. type DefaultExpr struct { exprNode // Name is the column name. Name *ColumnName } // Restore implements Node interface. func (n *DefaultExpr) Restore(ctx *format.RestoreCtx) error { ctx.WriteKeyWord("DEFAULT") if n.Name != nil { ctx.WritePlain("(") if err := n.Name.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore DefaultExpr.Name") } ctx.WritePlain(")") } return nil } // Format the ExprNode into a Writer. func (n *DefaultExpr) Format(w io.Writer) { panic("Not implemented") } // Accept implements Node Accept interface. func (n *DefaultExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*DefaultExpr) return v.Leave(n) } // ExistsSubqueryExpr is the expression for "exists (select ...)". // See https://dev.mysql.com/doc/refman/5.7/en/exists-and-not-exists-subqueries.html type ExistsSubqueryExpr struct { exprNode // Sel is the subquery, may be rewritten to other type of expression. Sel ExprNode // Not is true, the expression is "not exists". Not bool } // Restore implements Node interface. func (n *ExistsSubqueryExpr) Restore(ctx *format.RestoreCtx) error { if n.Not { ctx.WriteKeyWord("NOT EXISTS ") } else { ctx.WriteKeyWord("EXISTS ") } if err := n.Sel.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore ExistsSubqueryExpr.Sel") } return nil } // Format the ExprNode into a Writer. func (n *ExistsSubqueryExpr) Format(w io.Writer) { panic("Not implemented") } // Accept implements Node Accept interface. func (n *ExistsSubqueryExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*ExistsSubqueryExpr) node, ok := n.Sel.Accept(v) if !ok { return n, false } n.Sel = node.(ExprNode) return v.Leave(n) } // PatternInExpr is the expression for in operator, like "expr in (1, 2, 3)" or "expr in (select c from t)". type PatternInExpr struct { exprNode // Expr is the value expression to be compared. Expr ExprNode // List is the list expression in compare list. List []ExprNode // Not is true, the expression is "not in". Not bool // Sel is the subquery, may be rewritten to other type of expression. Sel ExprNode } // Restore implements Node interface. func (n *PatternInExpr) Restore(ctx *format.RestoreCtx) error { if err := n.Expr.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore PatternInExpr.Expr") } if n.Not { ctx.WriteKeyWord(" NOT IN ") } else { ctx.WriteKeyWord(" IN ") } if n.Sel != nil { if err := n.Sel.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore PatternInExpr.Sel") } } else { ctx.WritePlain("(") for i, expr := range n.List { if i != 0 { ctx.WritePlain(",") } if err := expr.Restore(ctx); err != nil { return errors.Annotatef(err, "An error occurred while restore PatternInExpr.List[%d]", i) } } ctx.WritePlain(")") } return nil } // Format the ExprNode into a Writer. func (n *PatternInExpr) Format(w io.Writer) { n.Expr.Format(w) if n.Not { fmt.Fprint(w, " NOT IN (") } else { fmt.Fprint(w, " IN (") } for i, expr := range n.List { if i != 0 { fmt.Fprint(w, ",") } expr.Format(w) } fmt.Fprint(w, ")") } // Accept implements Node Accept interface. func (n *PatternInExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*PatternInExpr) node, ok := n.Expr.Accept(v) if !ok { return n, false } n.Expr = node.(ExprNode) for i, val := range n.List { node, ok = val.Accept(v) if !ok { return n, false } n.List[i] = node.(ExprNode) } if n.Sel != nil { node, ok = n.Sel.Accept(v) if !ok { return n, false } n.Sel = node.(ExprNode) } return v.Leave(n) } // IsNullExpr is the expression for null check. type IsNullExpr struct { exprNode // Expr is the expression to be checked. Expr ExprNode // Not is true, the expression is "is not null". Not bool } // Restore implements Node interface. func (n *IsNullExpr) Restore(ctx *format.RestoreCtx) error { if err := n.Expr.Restore(ctx); err != nil { return errors.Trace(err) } if n.Not { ctx.WriteKeyWord(" IS NOT NULL") } else { ctx.WriteKeyWord(" IS NULL") } return nil } // Format the ExprNode into a Writer. func (n *IsNullExpr) Format(w io.Writer) { n.Expr.Format(w) if n.Not { fmt.Fprint(w, " IS NOT NULL") return } fmt.Fprint(w, " IS NULL") } // Accept implements Node Accept interface. func (n *IsNullExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*IsNullExpr) node, ok := n.Expr.Accept(v) if !ok { return n, false } n.Expr = node.(ExprNode) return v.Leave(n) } // IsTruthExpr is the expression for true/false check. type IsTruthExpr struct { exprNode // Expr is the expression to be checked. Expr ExprNode // Not is true, the expression is "is not true/false". Not bool // True indicates checking true or false. True int64 } // Restore implements Node interface. func (n *IsTruthExpr) Restore(ctx *format.RestoreCtx) error { if err := n.Expr.Restore(ctx); err != nil { return errors.Trace(err) } if n.Not { ctx.WriteKeyWord(" IS NOT") } else { ctx.WriteKeyWord(" IS") } if n.True > 0 { ctx.WriteKeyWord(" TRUE") } else { ctx.WriteKeyWord(" FALSE") } return nil } // Format the ExprNode into a Writer. func (n *IsTruthExpr) Format(w io.Writer) { n.Expr.Format(w) if n.Not { fmt.Fprint(w, " IS NOT") } else { fmt.Fprint(w, " IS") } if n.True > 0 { fmt.Fprint(w, " TRUE") } else { fmt.Fprint(w, " FALSE") } } // Accept implements Node Accept interface. func (n *IsTruthExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*IsTruthExpr) node, ok := n.Expr.Accept(v) if !ok { return n, false } n.Expr = node.(ExprNode) return v.Leave(n) } // PatternLikeExpr is the expression for like operator, e.g, expr like "%123%" type PatternLikeExpr struct { exprNode // Expr is the expression to be checked. Expr ExprNode // Pattern is the like expression. Pattern ExprNode // Not is true, the expression is "not like". Not bool Escape byte PatChars []byte PatTypes []byte } // Restore implements Node interface. func (n *PatternLikeExpr) Restore(ctx *format.RestoreCtx) error { if err := n.Expr.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore PatternLikeExpr.Expr") } if n.Not { ctx.WriteKeyWord(" NOT LIKE ") } else { ctx.WriteKeyWord(" LIKE ") } if err := n.Pattern.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore PatternLikeExpr.Pattern") } escape := string(n.Escape) if escape != "\\" { ctx.WriteKeyWord(" ESCAPE ") ctx.WriteString(escape) } return nil } // Format the ExprNode into a Writer. func (n *PatternLikeExpr) Format(w io.Writer) { n.Expr.Format(w) if n.Not { fmt.Fprint(w, " NOT LIKE ") } else { fmt.Fprint(w, " LIKE ") } n.Pattern.Format(w) if n.Escape != '\\' { fmt.Fprint(w, " ESCAPE ") fmt.Fprintf(w, "'%c'", n.Escape) } } // Accept implements Node Accept interface. func (n *PatternLikeExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*PatternLikeExpr) if n.Expr != nil { node, ok := n.Expr.Accept(v) if !ok { return n, false } n.Expr = node.(ExprNode) } if n.Pattern != nil { node, ok := n.Pattern.Accept(v) if !ok { return n, false } n.Pattern = node.(ExprNode) } return v.Leave(n) } // ParamMarkerExpr expression holds a place for another expression. // Used in parsing prepare statement. type ParamMarkerExpr interface { ValueExpr SetOrder(int) } // ParenthesesExpr is the parentheses expression. type ParenthesesExpr struct { exprNode // Expr is the expression in parentheses. Expr ExprNode } // Restore implements Node interface. func (n *ParenthesesExpr) Restore(ctx *format.RestoreCtx) error { ctx.WritePlain("(") if err := n.Expr.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred when restore ParenthesesExpr.Expr") } ctx.WritePlain(")") return nil } // Format the ExprNode into a Writer. func (n *ParenthesesExpr) Format(w io.Writer) { fmt.Fprint(w, "(") n.Expr.Format(w) fmt.Fprint(w, ")") } // Accept implements Node Accept interface. func (n *ParenthesesExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*ParenthesesExpr) if n.Expr != nil { node, ok := n.Expr.Accept(v) if !ok { return n, false } n.Expr = node.(ExprNode) } return v.Leave(n) } // PositionExpr is the expression for order by and group by position. // MySQL use position expression started from 1, it looks a little confused inner. // maybe later we will use 0 at first. type PositionExpr struct { exprNode // N is the position, started from 1 now. N int // P is the parameterized position. P ExprNode // Refer is the result field the position refers to. Refer *ResultField } // Restore implements Node interface. func (n *PositionExpr) Restore(ctx *format.RestoreCtx) error { ctx.WritePlainf("%d", n.N) return nil } // Format the ExprNode into a Writer. func (n *PositionExpr) Format(w io.Writer) { panic("Not implemented") } // Accept implements Node Accept interface. func (n *PositionExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*PositionExpr) if n.P != nil { node, ok := n.P.Accept(v) if !ok { return n, false } n.P = node.(ExprNode) } return v.Leave(n) } // PatternRegexpExpr is the pattern expression for pattern match. type PatternRegexpExpr struct { exprNode // Expr is the expression to be checked. Expr ExprNode // Pattern is the expression for pattern. Pattern ExprNode // Not is true, the expression is "not rlike", Not bool // Re is the compiled regexp. Re *regexp.Regexp // Sexpr is the string for Expr expression. Sexpr *string } // Restore implements Node interface. func (n *PatternRegexpExpr) Restore(ctx *format.RestoreCtx) error { if err := n.Expr.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore PatternRegexpExpr.Expr") } if n.Not { ctx.WriteKeyWord(" NOT REGEXP ") } else { ctx.WriteKeyWord(" REGEXP ") } if err := n.Pattern.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore PatternRegexpExpr.Pattern") } return nil } // Format the ExprNode into a Writer. func (n *PatternRegexpExpr) Format(w io.Writer) { n.Expr.Format(w) if n.Not { fmt.Fprint(w, " NOT REGEXP ") } else { fmt.Fprint(w, " REGEXP ") } n.Pattern.Format(w) } // Accept implements Node Accept interface. func (n *PatternRegexpExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*PatternRegexpExpr) node, ok := n.Expr.Accept(v) if !ok { return n, false } n.Expr = node.(ExprNode) node, ok = n.Pattern.Accept(v) if !ok { return n, false } n.Pattern = node.(ExprNode) return v.Leave(n) } // RowExpr is the expression for row constructor. // See https://dev.mysql.com/doc/refman/5.7/en/row-subqueries.html type RowExpr struct { exprNode Values []ExprNode } // Restore implements Node interface. func (n *RowExpr) Restore(ctx *format.RestoreCtx) error { ctx.WriteKeyWord("ROW") ctx.WritePlain("(") for i, v := range n.Values { if i != 0 { ctx.WritePlain(",") } if err := v.Restore(ctx); err != nil { return errors.Annotatef(err, "An error occurred when restore RowExpr.Values[%v]", i) } } ctx.WritePlain(")") return nil } // Format the ExprNode into a Writer. func (n *RowExpr) Format(w io.Writer) { panic("Not implemented") } // Accept implements Node Accept interface. func (n *RowExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*RowExpr) for i, val := range n.Values { node, ok := val.Accept(v) if !ok { return n, false } n.Values[i] = node.(ExprNode) } return v.Leave(n) } // UnaryOperationExpr is the expression for unary operator. type UnaryOperationExpr struct { exprNode // Op is the operator opcode. Op opcode.Op // V is the unary expression. V ExprNode } // Restore implements Node interface. func (n *UnaryOperationExpr) Restore(ctx *format.RestoreCtx) error { if err := n.Op.Restore(ctx); err != nil { return errors.Trace(err) } if err := n.V.Restore(ctx); err != nil { return errors.Trace(err) } return nil } // Format the ExprNode into a Writer. func (n *UnaryOperationExpr) Format(w io.Writer) { n.Op.Format(w) n.V.Format(w) } // Accept implements Node Accept interface. func (n *UnaryOperationExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*UnaryOperationExpr) node, ok := n.V.Accept(v) if !ok { return n, false } n.V = node.(ExprNode) return v.Leave(n) } // ValuesExpr is the expression used in INSERT VALUES. type ValuesExpr struct { exprNode // Column is column name. Column *ColumnNameExpr } // Restore implements Node interface. func (n *ValuesExpr) Restore(ctx *format.RestoreCtx) error { ctx.WriteKeyWord("VALUES") ctx.WritePlain("(") if err := n.Column.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore ValuesExpr.Column") } ctx.WritePlain(")") return nil } // Format the ExprNode into a Writer. func (n *ValuesExpr) Format(w io.Writer) { panic("Not implemented") } // Accept implements Node Accept interface. func (n *ValuesExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*ValuesExpr) node, ok := n.Column.Accept(v) if !ok { return n, false } if col, ok := node.(*ColumnNameExpr); ok { // `node` may be *ast.ValueExpr n.Column = col } return v.Leave(n) } // VariableExpr is the expression for variable. type VariableExpr struct { exprNode // Name is the variable name. Name string // IsGlobal indicates whether this variable is global. IsGlobal bool // IsSystem indicates whether this variable is a system variable in current session. IsSystem bool // ExplicitScope indicates whether this variable scope is set explicitly. ExplicitScope bool // Value is the variable value. Value ExprNode } // Restore implements Node interface. func (n *VariableExpr) Restore(ctx *format.RestoreCtx) error { if n.IsSystem { ctx.WritePlain("@@") if n.ExplicitScope { if n.IsGlobal { ctx.WriteKeyWord("GLOBAL") } else { ctx.WriteKeyWord("SESSION") } ctx.WritePlain(".") } } else { ctx.WritePlain("@") } ctx.WriteName(n.Name) if n.Value != nil { ctx.WritePlain(":=") if err := n.Value.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore VariableExpr.Value") } } return nil } // Format the ExprNode into a Writer. func (n *VariableExpr) Format(w io.Writer) { panic("Not implemented") } // Accept implements Node Accept interface. func (n *VariableExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*VariableExpr) if n.Value == nil { return v.Leave(n) } node, ok := n.Value.Accept(v) if !ok { return n, false } n.Value = node.(ExprNode) return v.Leave(n) } // MaxValueExpr is the expression for "maxvalue" used in partition. type MaxValueExpr struct { exprNode } // Restore implements Node interface. func (n *MaxValueExpr) Restore(ctx *format.RestoreCtx) error { ctx.WriteKeyWord("MAXVALUE") return nil } // Format the ExprNode into a Writer. func (n *MaxValueExpr) Format(w io.Writer) { fmt.Fprint(w, "MAXVALUE") } // Accept implements Node Accept interface. func (n *MaxValueExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } return v.Leave(n) } // MatchAgainst is the expression for matching against fulltext index. type MatchAgainst struct { exprNode // ColumnNames are the columns to match. ColumnNames []*ColumnName // Against Against ExprNode // Modifier Modifier FulltextSearchModifier } func (n *MatchAgainst) Restore(ctx *format.RestoreCtx) error { ctx.WriteKeyWord("MATCH") ctx.WritePlain(" (") for i, v := range n.ColumnNames { if i != 0 { ctx.WritePlain(",") } if err := v.Restore(ctx); err != nil { return errors.Annotatef(err, "An error occurred while restore MatchAgainst.ColumnNames[%d]", i) } } ctx.WritePlain(") ") ctx.WriteKeyWord("AGAINST") ctx.WritePlain(" (") if err := n.Against.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore MatchAgainst.Against") } if n.Modifier.IsBooleanMode() { ctx.WritePlain(" IN BOOLEAN MODE") if n.Modifier.WithQueryExpansion() { return errors.New("BOOLEAN MODE doesn't support QUERY EXPANSION") } } else if n.Modifier.WithQueryExpansion() { ctx.WritePlain(" WITH QUERY EXPANSION") } ctx.WritePlain(")") return nil } func (n *MatchAgainst) Format(w io.Writer) { fmt.Fprint(w, "MATCH(") for i, v := range n.ColumnNames { if i != 0 { fmt.Fprintf(w, ",%s", v.String()) } else { fmt.Fprint(w, v.String()) } } fmt.Fprint(w, ") AGAINST(") n.Against.Format(w) if n.Modifier.IsBooleanMode() { fmt.Fprint(w, " IN BOOLEAN MODE") } else if n.Modifier.WithQueryExpansion() { fmt.Fprint(w, " WITH QUERY EXPANSION") } fmt.Fprint(w, ")") } func (n *MatchAgainst) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*MatchAgainst) for i, colName := range n.ColumnNames { newColName, ok := colName.Accept(v) if !ok { return n, false } n.ColumnNames[i] = newColName.(*ColumnName) } newAgainst, ok := n.Against.Accept(v) if !ok { return n, false } n.Against = newAgainst.(ExprNode) return v.Leave(n) } // SetCollationExpr is the expression for the `COLLATE collation_name` clause. type SetCollationExpr struct { exprNode // Expr is the expression to be set. Expr ExprNode // Collate is the name of collation to set. Collate string } // Restore implements Node interface. func (n *SetCollationExpr) Restore(ctx *format.RestoreCtx) error { if err := n.Expr.Restore(ctx); err != nil { return errors.Trace(err) } ctx.WriteKeyWord(" COLLATE ") ctx.WritePlain(n.Collate) return nil } // Format the ExprNode into a Writer. func (n *SetCollationExpr) Format(w io.Writer) { n.Expr.Format(w) fmt.Fprintf(w, " COLLATE %s", n.Collate) } // Accept implements Node Accept interface. func (n *SetCollationExpr) Accept(v Visitor) (Node, bool) { newNode, skipChildren := v.Enter(n) if skipChildren { return v.Leave(newNode) } n = newNode.(*SetCollationExpr) node, ok := n.Expr.Accept(v) if !ok { return n, false } n.Expr = node.(ExprNode) return v.Leave(n) } type exprTextPositionCleaner struct { oldTextPos []int restore bool } func (e *exprTextPositionCleaner) BeginRestore() { e.restore = true } func (e *exprTextPositionCleaner) Enter(n Node) (node Node, skipChildren bool) { if e.restore { n.SetOriginTextPosition(e.oldTextPos[0]) e.oldTextPos = e.oldTextPos[1:] return n, false } e.oldTextPos = append(e.oldTextPos, n.OriginTextPosition()) n.SetOriginTextPosition(0) return n, false } func (e *exprTextPositionCleaner) Leave(n Node) (node Node, ok bool) { return n, true } // ExpressionDeepEqual compares the equivalence of two expressions. func ExpressionDeepEqual(a ExprNode, b ExprNode) bool { cleanerA := &exprTextPositionCleaner{} cleanerB := &exprTextPositionCleaner{} a.Accept(cleanerA) b.Accept(cleanerB) result := reflect.DeepEqual(a, b) cleanerA.BeginRestore() cleanerB.BeginRestore() a.Accept(cleanerA) b.Accept(cleanerB) return result }