/* * Copyright 1999-2012 Alibaba Group. * * 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. */ /** * (created at 2011-6-1) */ package com.alibaba.cobar.parser.visitor; import static com.alibaba.cobar.parser.ast.expression.comparison.ComparisionIsExpression.IS_FALSE; import static com.alibaba.cobar.parser.ast.expression.comparison.ComparisionIsExpression.IS_NOT_FALSE; import static com.alibaba.cobar.parser.ast.expression.comparison.ComparisionIsExpression.IS_NOT_NULL; import static com.alibaba.cobar.parser.ast.expression.comparison.ComparisionIsExpression.IS_NOT_TRUE; import static com.alibaba.cobar.parser.ast.expression.comparison.ComparisionIsExpression.IS_NOT_UNKNOWN; import static com.alibaba.cobar.parser.ast.expression.comparison.ComparisionIsExpression.IS_NULL; import static com.alibaba.cobar.parser.ast.expression.comparison.ComparisionIsExpression.IS_TRUE; import static com.alibaba.cobar.parser.ast.expression.comparison.ComparisionIsExpression.IS_UNKNOWN; import java.util.List; import java.util.Map; import com.alibaba.cobar.parser.ast.ASTNode; import com.alibaba.cobar.parser.ast.expression.BinaryOperatorExpression; import com.alibaba.cobar.parser.ast.expression.Expression; import com.alibaba.cobar.parser.ast.expression.PolyadicOperatorExpression; import com.alibaba.cobar.parser.ast.expression.TernaryOperatorExpression; import com.alibaba.cobar.parser.ast.expression.UnaryOperatorExpression; import com.alibaba.cobar.parser.ast.expression.comparison.BetweenAndExpression; import com.alibaba.cobar.parser.ast.expression.comparison.ComparisionEqualsExpression; import com.alibaba.cobar.parser.ast.expression.comparison.ComparisionIsExpression; import com.alibaba.cobar.parser.ast.expression.comparison.ComparisionNullSafeEqualsExpression; import com.alibaba.cobar.parser.ast.expression.comparison.InExpression; import com.alibaba.cobar.parser.ast.expression.logical.LogicalAndExpression; import com.alibaba.cobar.parser.ast.expression.logical.LogicalOrExpression; import com.alibaba.cobar.parser.ast.expression.misc.InExpressionList; import com.alibaba.cobar.parser.ast.expression.misc.QueryExpression; import com.alibaba.cobar.parser.ast.expression.misc.UserExpression; import com.alibaba.cobar.parser.ast.expression.primary.CaseWhenOperatorExpression; import com.alibaba.cobar.parser.ast.expression.primary.DefaultValue; import com.alibaba.cobar.parser.ast.expression.primary.ExistsPrimary; import com.alibaba.cobar.parser.ast.expression.primary.Identifier; import com.alibaba.cobar.parser.ast.expression.primary.MatchExpression; import com.alibaba.cobar.parser.ast.expression.primary.ParamMarker; import com.alibaba.cobar.parser.ast.expression.primary.PlaceHolder; import com.alibaba.cobar.parser.ast.expression.primary.RowExpression; import com.alibaba.cobar.parser.ast.expression.primary.SysVarPrimary; import com.alibaba.cobar.parser.ast.expression.primary.UsrDefVarPrimary; import com.alibaba.cobar.parser.ast.expression.primary.VariableExpression; import com.alibaba.cobar.parser.ast.expression.primary.function.FunctionExpression; import com.alibaba.cobar.parser.ast.expression.primary.function.cast.Cast; import com.alibaba.cobar.parser.ast.expression.primary.function.cast.Convert; import com.alibaba.cobar.parser.ast.expression.primary.function.datetime.Extract; import com.alibaba.cobar.parser.ast.expression.primary.function.datetime.GetFormat; import com.alibaba.cobar.parser.ast.expression.primary.function.datetime.Timestampadd; import com.alibaba.cobar.parser.ast.expression.primary.function.datetime.Timestampdiff; import com.alibaba.cobar.parser.ast.expression.primary.function.groupby.Avg; import com.alibaba.cobar.parser.ast.expression.primary.function.groupby.Count; import com.alibaba.cobar.parser.ast.expression.primary.function.groupby.GroupConcat; import com.alibaba.cobar.parser.ast.expression.primary.function.groupby.Max; import com.alibaba.cobar.parser.ast.expression.primary.function.groupby.Min; import com.alibaba.cobar.parser.ast.expression.primary.function.groupby.Sum; import com.alibaba.cobar.parser.ast.expression.primary.function.string.Char; import com.alibaba.cobar.parser.ast.expression.primary.function.string.Trim; import com.alibaba.cobar.parser.ast.expression.primary.literal.IntervalPrimary; import com.alibaba.cobar.parser.ast.expression.primary.literal.LiteralBitField; import com.alibaba.cobar.parser.ast.expression.primary.literal.LiteralBoolean; import com.alibaba.cobar.parser.ast.expression.primary.literal.LiteralHexadecimal; import com.alibaba.cobar.parser.ast.expression.primary.literal.LiteralNull; import com.alibaba.cobar.parser.ast.expression.primary.literal.LiteralNumber; import com.alibaba.cobar.parser.ast.expression.primary.literal.LiteralString; import com.alibaba.cobar.parser.ast.expression.string.LikeExpression; import com.alibaba.cobar.parser.ast.expression.type.CollateExpression; import com.alibaba.cobar.parser.ast.fragment.GroupBy; import com.alibaba.cobar.parser.ast.fragment.Limit; import com.alibaba.cobar.parser.ast.fragment.OrderBy; import com.alibaba.cobar.parser.ast.fragment.SortOrder; import com.alibaba.cobar.parser.ast.fragment.VariableScope; import com.alibaba.cobar.parser.ast.fragment.ddl.ColumnDefinition; import com.alibaba.cobar.parser.ast.fragment.ddl.TableOptions; import com.alibaba.cobar.parser.ast.fragment.ddl.datatype.DataType; import com.alibaba.cobar.parser.ast.fragment.ddl.index.IndexColumnName; import com.alibaba.cobar.parser.ast.fragment.ddl.index.IndexOption; import com.alibaba.cobar.parser.ast.fragment.tableref.Dual; import com.alibaba.cobar.parser.ast.fragment.tableref.IndexHint; import com.alibaba.cobar.parser.ast.fragment.tableref.InnerJoin; import com.alibaba.cobar.parser.ast.fragment.tableref.NaturalJoin; import com.alibaba.cobar.parser.ast.fragment.tableref.OuterJoin; import com.alibaba.cobar.parser.ast.fragment.tableref.StraightJoin; import com.alibaba.cobar.parser.ast.fragment.tableref.SubqueryFactor; import com.alibaba.cobar.parser.ast.fragment.tableref.TableRefFactor; import com.alibaba.cobar.parser.ast.fragment.tableref.TableReference; import com.alibaba.cobar.parser.ast.fragment.tableref.TableReferences; import com.alibaba.cobar.parser.ast.stmt.dal.DALSetCharacterSetStatement; import com.alibaba.cobar.parser.ast.stmt.dal.DALSetNamesStatement; import com.alibaba.cobar.parser.ast.stmt.dal.DALSetStatement; import com.alibaba.cobar.parser.ast.stmt.dal.ShowAuthors; import com.alibaba.cobar.parser.ast.stmt.dal.ShowBinLogEvent; import com.alibaba.cobar.parser.ast.stmt.dal.ShowBinaryLog; import com.alibaba.cobar.parser.ast.stmt.dal.ShowCharaterSet; import com.alibaba.cobar.parser.ast.stmt.dal.ShowCollation; import com.alibaba.cobar.parser.ast.stmt.dal.ShowColumns; import com.alibaba.cobar.parser.ast.stmt.dal.ShowContributors; import com.alibaba.cobar.parser.ast.stmt.dal.ShowCreate; import com.alibaba.cobar.parser.ast.stmt.dal.ShowDatabases; import com.alibaba.cobar.parser.ast.stmt.dal.ShowEngine; import com.alibaba.cobar.parser.ast.stmt.dal.ShowEngines; import com.alibaba.cobar.parser.ast.stmt.dal.ShowErrors; import com.alibaba.cobar.parser.ast.stmt.dal.ShowEvents; import com.alibaba.cobar.parser.ast.stmt.dal.ShowFunctionCode; import com.alibaba.cobar.parser.ast.stmt.dal.ShowFunctionStatus; import com.alibaba.cobar.parser.ast.stmt.dal.ShowGrants; import com.alibaba.cobar.parser.ast.stmt.dal.ShowIndex; import com.alibaba.cobar.parser.ast.stmt.dal.ShowMasterStatus; import com.alibaba.cobar.parser.ast.stmt.dal.ShowOpenTables; import com.alibaba.cobar.parser.ast.stmt.dal.ShowPlugins; import com.alibaba.cobar.parser.ast.stmt.dal.ShowPrivileges; import com.alibaba.cobar.parser.ast.stmt.dal.ShowProcedureCode; import com.alibaba.cobar.parser.ast.stmt.dal.ShowProcedureStatus; import com.alibaba.cobar.parser.ast.stmt.dal.ShowProcesslist; import com.alibaba.cobar.parser.ast.stmt.dal.ShowProfile; import com.alibaba.cobar.parser.ast.stmt.dal.ShowProfiles; import com.alibaba.cobar.parser.ast.stmt.dal.ShowSlaveHosts; import com.alibaba.cobar.parser.ast.stmt.dal.ShowSlaveStatus; import com.alibaba.cobar.parser.ast.stmt.dal.ShowStatus; import com.alibaba.cobar.parser.ast.stmt.dal.ShowTableStatus; import com.alibaba.cobar.parser.ast.stmt.dal.ShowTables; import com.alibaba.cobar.parser.ast.stmt.dal.ShowTriggers; import com.alibaba.cobar.parser.ast.stmt.dal.ShowVariables; import com.alibaba.cobar.parser.ast.stmt.dal.ShowWarnings; import com.alibaba.cobar.parser.ast.stmt.ddl.DDLAlterTableStatement; import com.alibaba.cobar.parser.ast.stmt.ddl.DDLAlterTableStatement.AlterSpecification; import com.alibaba.cobar.parser.ast.stmt.ddl.DDLCreateIndexStatement; import com.alibaba.cobar.parser.ast.stmt.ddl.DDLCreateTableStatement; import com.alibaba.cobar.parser.ast.stmt.ddl.DDLDropIndexStatement; import com.alibaba.cobar.parser.ast.stmt.ddl.DDLDropTableStatement; import com.alibaba.cobar.parser.ast.stmt.ddl.DDLRenameTableStatement; import com.alibaba.cobar.parser.ast.stmt.ddl.DDLTruncateStatement; import com.alibaba.cobar.parser.ast.stmt.ddl.DescTableStatement; import com.alibaba.cobar.parser.ast.stmt.dml.DMLCallStatement; import com.alibaba.cobar.parser.ast.stmt.dml.DMLDeleteStatement; import com.alibaba.cobar.parser.ast.stmt.dml.DMLInsertStatement; import com.alibaba.cobar.parser.ast.stmt.dml.DMLReplaceStatement; import com.alibaba.cobar.parser.ast.stmt.dml.DMLSelectStatement; import com.alibaba.cobar.parser.ast.stmt.dml.DMLSelectUnionStatement; import com.alibaba.cobar.parser.ast.stmt.dml.DMLUpdateStatement; import com.alibaba.cobar.parser.ast.stmt.extension.ExtDDLCreatePolicy; import com.alibaba.cobar.parser.ast.stmt.extension.ExtDDLDropPolicy; import com.alibaba.cobar.parser.ast.stmt.mts.MTSReleaseStatement; import com.alibaba.cobar.parser.ast.stmt.mts.MTSRollbackStatement; import com.alibaba.cobar.parser.ast.stmt.mts.MTSSavepointStatement; import com.alibaba.cobar.parser.ast.stmt.mts.MTSSetTransactionStatement; import com.alibaba.cobar.parser.util.Pair; /** * @author <a href="mailto:shuo.qius@alibaba-inc.com">QIU Shuo</a> */ public final class MySQLOutputASTVisitor implements SQLASTVisitor { private static final Object[] EMPTY_OBJ_ARRAY = new Object[0]; private static final int[] EMPTY_INT_ARRAY = new int[0]; private final StringBuilder appendable; private final Object[] args; private int[] argsIndex; private Map<PlaceHolder, Object> placeHolderToString; public MySQLOutputASTVisitor(StringBuilder appendable) { this(appendable, null); } /** * @param args parameters for {@link java.sql.PreparedStatement * preparedStmt} */ public MySQLOutputASTVisitor(StringBuilder appendable, Object[] args) { this.appendable = appendable; this.args = args == null ? EMPTY_OBJ_ARRAY : args; this.argsIndex = args == null ? EMPTY_INT_ARRAY : new int[args.length]; } public void setPlaceHolderToString(Map<PlaceHolder, Object> map) { this.placeHolderToString = map; } public String getSql() { return appendable.toString(); } /** * @return never null. rst[i] ≡ {@link #args}[{@link #argsIndex}[i]] */ public Object[] getArguments() { final int argsIndexSize = argsIndex.length; if (argsIndexSize <= 0) return EMPTY_OBJ_ARRAY; boolean noChange = true; for (int i = 0; i < argsIndexSize; ++i) { if (i != argsIndex[i]) { noChange = false; break; } } if (noChange) return args; Object[] rst = new Object[argsIndexSize]; for (int i = 0; i < argsIndexSize; ++i) { rst[i] = args[argsIndex[i]]; } return rst; } /** * @param list never null */ private void printList(List<? extends ASTNode> list) { printList(list, ", "); } /** * @param list never null */ private void printList(List<? extends ASTNode> list, String sep) { boolean isFst = true; for (ASTNode arg : list) { if (isFst) isFst = false; else appendable.append(sep); arg.accept(this); } } @Override public void visit(BetweenAndExpression node) { Expression comparee = node.getFirst(); boolean paren = comparee.getPrecedence() <= node.getPrecedence(); if (paren) appendable.append('('); comparee.accept(this); if (paren) appendable.append(')'); if (node.isNot()) appendable.append(" NOT BETWEEN "); else appendable.append(" BETWEEN "); Expression start = node.getSecond(); paren = start.getPrecedence() < node.getPrecedence(); if (paren) appendable.append('('); start.accept(this); if (paren) appendable.append(')'); appendable.append(" AND "); Expression end = node.getThird(); paren = end.getPrecedence() < node.getPrecedence(); if (paren) appendable.append('('); end.accept(this); if (paren) appendable.append(')'); } @Override public void visit(ComparisionIsExpression node) { Expression comparee = node.getOperand(); boolean paren = comparee.getPrecedence() < node.getPrecedence(); if (paren) appendable.append('('); comparee.accept(this); if (paren) appendable.append(')'); switch (node.getMode()) { case IS_NULL: appendable.append(" IS NULL"); break; case IS_TRUE: appendable.append(" IS TRUE"); break; case IS_FALSE: appendable.append(" IS FALSE"); break; case IS_UNKNOWN: appendable.append(" IS UNKNOWN"); break; case IS_NOT_NULL: appendable.append(" IS NOT NULL"); break; case IS_NOT_TRUE: appendable.append(" IS NOT TRUE"); break; case IS_NOT_FALSE: appendable.append(" IS NOT FALSE"); break; case IS_NOT_UNKNOWN: appendable.append(" IS NOT UNKNOWN"); break; default: throw new IllegalArgumentException("unknown mode for IS expression: " + node.getMode()); } } @Override public void visit(InExpressionList node) { appendable.append('('); printList(node.getList()); appendable.append(')'); } @Override public void visit(LikeExpression node) { Expression comparee = node.getFirst(); boolean paren = comparee.getPrecedence() < node.getPrecedence(); if (paren) appendable.append('('); comparee.accept(this); if (paren) appendable.append(')'); if (node.isNot()) appendable.append(" NOT LIKE "); else appendable.append(" LIKE "); Expression pattern = node.getSecond(); paren = pattern.getPrecedence() <= node.getPrecedence(); if (paren) appendable.append('('); pattern.accept(this); if (paren) appendable.append(')'); Expression escape = node.getThird(); if (escape != null) { appendable.append(" ESCAPE "); paren = escape.getPrecedence() <= node.getPrecedence(); if (paren) appendable.append('('); escape.accept(this); if (paren) appendable.append(')'); } } @Override public void visit(CollateExpression node) { Expression string = node.getString(); boolean paren = string.getPrecedence() < node.getPrecedence(); if (paren) appendable.append('('); string.accept(this); if (paren) appendable.append(')'); appendable.append(" COLLATE ").append(node.getCollateName()); } @Override public void visit(UserExpression node) { appendable.append(node.getUserAtHost()); } @Override public void visit(UnaryOperatorExpression node) { appendable.append(node.getOperator()).append(' '); boolean paren = node.getOperand().getPrecedence() < node.getPrecedence(); if (paren) appendable.append('('); node.getOperand().accept(this); if (paren) appendable.append(')'); } @Override public void visit(BinaryOperatorExpression node) { Expression left = node.getLeftOprand(); boolean paren = node.isLeftCombine() ? left.getPrecedence() < node.getPrecedence() : left.getPrecedence() <= node.getPrecedence(); if (paren) appendable.append('('); left.accept(this); if (paren) appendable.append(')'); appendable.append(' ').append(node.getOperator()).append(' '); Expression right = node.getRightOprand(); paren = node.isLeftCombine() ? right.getPrecedence() <= node.getPrecedence() : right.getPrecedence() < node.getPrecedence(); if (paren) appendable.append('('); right.accept(this); if (paren) appendable.append(')'); } @Override public void visit(PolyadicOperatorExpression node) { for (int i = 0, len = node.getArity(); i < len; ++i) { if (i > 0) appendable.append(' ').append(node.getOperator()).append(' '); Expression operand = node.getOperand(i); boolean paren = operand.getPrecedence() < node.getPrecedence(); if (paren) appendable.append('('); operand.accept(this); if (paren) appendable.append(')'); } } @Override public void visit(LogicalAndExpression node) { visit((PolyadicOperatorExpression) node); } @Override public void visit(LogicalOrExpression node) { visit((PolyadicOperatorExpression) node); } @Override public void visit(ComparisionEqualsExpression node) { visit((BinaryOperatorExpression) node); } @Override public void visit(ComparisionNullSafeEqualsExpression node) { visit((BinaryOperatorExpression) node); } @Override public void visit(InExpression node) { visit((BinaryOperatorExpression) node); } @Override public void visit(FunctionExpression node) { String functionName = node.getFunctionName(); appendable.append(functionName).append('('); printList(node.getArguments()); appendable.append(')'); } @Override public void visit(Char node) { String functionName = node.getFunctionName(); appendable.append(functionName).append('('); printList(node.getArguments()); String charset = node.getCharset(); if (charset != null) { appendable.append(" USING ").append(charset); } appendable.append(')'); } @Override public void visit(Convert node) { String functionName = node.getFunctionName(); appendable.append(functionName).append('('); printList(node.getArguments()); String transcodeName = node.getTranscodeName(); appendable.append(" USING ").append(transcodeName); appendable.append(')'); } @Override public void visit(Trim node) { String functionName = node.getFunctionName(); appendable.append(functionName).append('('); Expression remStr = node.getRemainString(); switch (node.getDirection()) { case DEFAULT: if (remStr != null) { remStr.accept(this); appendable.append(" FROM "); } break; case BOTH: appendable.append("BOTH "); if (remStr != null) remStr.accept(this); appendable.append(" FROM "); break; case LEADING: appendable.append("LEADING "); if (remStr != null) remStr.accept(this); appendable.append(" FROM "); break; case TRAILING: appendable.append("TRAILING "); if (remStr != null) remStr.accept(this); appendable.append(" FROM "); break; default: throw new IllegalArgumentException("unknown trim direction: " + node.getDirection()); } Expression str = node.getString(); str.accept(this); appendable.append(')'); } @Override public void visit(Cast node) { String functionName = node.getFunctionName(); appendable.append(functionName).append('('); node.getExpr().accept(this); appendable.append(" AS "); String typeName = node.getTypeName(); appendable.append(typeName); Expression info1 = node.getTypeInfo1(); if (info1 != null) { appendable.append('('); info1.accept(this); Expression info2 = node.getTypeInfo2(); if (info2 != null) { appendable.append(", "); info2.accept(this); } appendable.append(')'); } appendable.append(')'); } @Override public void visit(Avg node) { String functionName = node.getFunctionName(); appendable.append(functionName).append('('); if (node.isDistinct()) { appendable.append("DISTINCT "); } printList(node.getArguments()); appendable.append(')'); } @Override public void visit(Max node) { String functionName = node.getFunctionName(); appendable.append(functionName).append('('); if (node.isDistinct()) { appendable.append("DISTINCT "); } printList(node.getArguments()); appendable.append(')'); } @Override public void visit(Min node) { String functionName = node.getFunctionName(); appendable.append(functionName).append('('); if (node.isDistinct()) { appendable.append("DISTINCT "); } printList(node.getArguments()); appendable.append(')'); } @Override public void visit(Sum node) { String functionName = node.getFunctionName(); appendable.append(functionName).append('('); if (node.isDistinct()) { appendable.append("DISTINCT "); } printList(node.getArguments()); appendable.append(')'); } @Override public void visit(Count node) { String functionName = node.getFunctionName(); appendable.append(functionName).append('('); if (node.isDistinct()) { appendable.append("DISTINCT "); } printList(node.getArguments()); appendable.append(')'); } @Override public void visit(GroupConcat node) { String functionName = node.getFunctionName(); appendable.append(functionName).append('('); if (node.isDistinct()) { appendable.append("DISTINCT "); } printList(node.getArguments()); Expression orderBy = node.getOrderBy(); if (orderBy != null) { appendable.append(" ORDER BY "); orderBy.accept(this); if (node.isDesc()) appendable.append(" DESC"); else appendable.append(" ASC"); List<Expression> list = node.getAppendedColumnNames(); if (list != null && !list.isEmpty()) { appendable.append(", "); printList(list); } } String sep = node.getSeparator(); if (sep != null) { appendable.append(" SEPARATOR ").append(sep); } appendable.append(')'); } @Override public void visit(Extract node) { appendable.append("EXTRACT(").append(node.getUnit().name()).append(" FROM "); printList(node.getArguments()); appendable.append(')'); } @Override public void visit(Timestampdiff node) { appendable.append("TIMESTAMPDIFF(").append(node.getUnit().name()).append(", "); printList(node.getArguments()); appendable.append(')'); } @Override public void visit(Timestampadd node) { appendable.append("TIMESTAMPADD(").append(node.getUnit().name()).append(", "); printList(node.getArguments()); appendable.append(')'); } @Override public void visit(GetFormat node) { appendable.append("GET_FORMAT("); GetFormat.FormatType type = node.getFormatType(); appendable.append(type.name()).append(", "); printList(node.getArguments()); appendable.append(')'); } @Override public void visit(PlaceHolder node) { if (placeHolderToString == null) { appendable.append("${").append(node.getName()).append('}'); return; } Object toStringer = placeHolderToString.get(node); if (toStringer == null) { appendable.append("${").append(node.getName()).append('}'); } else { appendable.append(toStringer.toString()); } } @Override public void visit(IntervalPrimary node) { appendable.append("INTERVAL "); Expression quantity = node.getQuantity(); boolean paren = quantity.getPrecedence() < node.getPrecedence(); if (paren) appendable.append('('); quantity.accept(this); if (paren) appendable.append(')'); IntervalPrimary.Unit unit = node.getUnit(); appendable.append(' ').append(unit.name()); } @Override public void visit(LiteralBitField node) { String introducer = node.getIntroducer(); if (introducer != null) appendable.append(introducer).append(' '); appendable.append("b'").append(node.getText()).append('\''); } @Override public void visit(LiteralBoolean node) { if (node.isTrue()) { appendable.append("TRUE"); } else { appendable.append("FALSE"); } } @Override public void visit(LiteralHexadecimal node) { String introducer = node.getIntroducer(); if (introducer != null) appendable.append(introducer).append(' '); appendable.append("x'"); node.appendTo(appendable); appendable.append('\''); } @Override public void visit(LiteralNull node) { appendable.append("NULL"); } @Override public void visit(LiteralNumber node) { appendable.append(String.valueOf(node.getNumber())); } @Override public void visit(LiteralString node) { String introducer = node.getIntroducer(); if (introducer != null) { appendable.append(introducer); } else if (node.isNchars()) { appendable.append('N'); } appendable.append('\'').append(node.getString()).append('\''); } @Override public void visit(CaseWhenOperatorExpression node) { appendable.append("CASE"); Expression comparee = node.getComparee(); if (comparee != null) { appendable.append(' '); comparee.accept(this); } List<Pair<Expression, Expression>> whenList = node.getWhenList(); for (Pair<Expression, Expression> whenthen : whenList) { appendable.append(" WHEN "); Expression when = whenthen.getKey(); when.accept(this); appendable.append(" THEN "); Expression then = whenthen.getValue(); then.accept(this); } Expression elseRst = node.getElseResult(); if (elseRst != null) { appendable.append(" ELSE "); elseRst.accept(this); } appendable.append(" END"); } @Override public void visit(DefaultValue node) { appendable.append("DEFAULT"); } @Override public void visit(ExistsPrimary node) { appendable.append("EXISTS ("); node.getSubquery().accept(this); appendable.append(')'); } @Override public void visit(Identifier node) { Expression parent = node.getParent(); if (parent != null) { parent.accept(this); appendable.append('.'); } appendable.append(node.getIdText()); } private static boolean containsCompIn(Expression pat) { if (pat.getPrecedence() > Expression.PRECEDENCE_COMPARISION) return false; if (pat instanceof BinaryOperatorExpression) { if (pat instanceof InExpression) { return true; } BinaryOperatorExpression bp = (BinaryOperatorExpression) pat; if (bp.isLeftCombine()) { return containsCompIn(bp.getLeftOprand()); } else { return containsCompIn(bp.getLeftOprand()); } } else if (pat instanceof ComparisionIsExpression) { ComparisionIsExpression is = (ComparisionIsExpression) pat; return containsCompIn(is.getOperand()); } else if (pat instanceof TernaryOperatorExpression) { TernaryOperatorExpression tp = (TernaryOperatorExpression) pat; return containsCompIn(tp.getFirst()) || containsCompIn(tp.getSecond()) || containsCompIn(tp.getThird()); } else if (pat instanceof UnaryOperatorExpression) { UnaryOperatorExpression up = (UnaryOperatorExpression) pat; return containsCompIn(up.getOperand()); } else { return false; } } @Override public void visit(MatchExpression node) { appendable.append("MATCH ("); printList(node.getColumns()); appendable.append(") AGAINST ("); Expression pattern = node.getPattern(); boolean inparen = containsCompIn(pattern); if (inparen) appendable.append('('); pattern.accept(this); if (inparen) appendable.append(')'); switch (node.getModifier()) { case IN_BOOLEAN_MODE: appendable.append(" IN BOOLEAN MODE"); break; case IN_NATURAL_LANGUAGE_MODE: appendable.append(" IN NATURAL LANGUAGE MODE"); break; case IN_NATURAL_LANGUAGE_MODE_WITH_QUERY_EXPANSION: appendable.append(" IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION"); break; case WITH_QUERY_EXPANSION: appendable.append(" WITH QUERY EXPANSION"); break; case _DEFAULT: break; default: throw new IllegalArgumentException("unkown modifier for match expression: " + node.getModifier()); } appendable.append(')'); } private int index = -1; private void appendArgsIndex(int value) { int i = ++index; if (argsIndex.length <= i) { int[] a = new int[i + 1]; if (i > 0) System.arraycopy(argsIndex, 0, a, 0, i); argsIndex = a; } argsIndex[i] = value; } @Override public void visit(ParamMarker node) { appendable.append('?'); appendArgsIndex(node.getParamIndex() - 1); } @Override public void visit(RowExpression node) { appendable.append("ROW("); printList(node.getRowExprList()); appendable.append(')'); } @Override public void visit(SysVarPrimary node) { VariableScope scope = node.getScope(); switch (scope) { case GLOBAL: appendable.append("@@global."); break; case SESSION: appendable.append("@@"); break; default: throw new IllegalArgumentException("unkown scope for sysVar primary: " + scope); } appendable.append(node.getVarText()); } @Override public void visit(UsrDefVarPrimary node) { appendable.append(node.getVarText()); } @Override public void visit(IndexHint node) { IndexHint.IndexAction action = node.getAction(); switch (action) { case FORCE: appendable.append("FORCE "); break; case IGNORE: appendable.append("IGNORE "); break; case USE: appendable.append("USE "); break; default: throw new IllegalArgumentException("unkown index action for index hint: " + action); } IndexHint.IndexType type = node.getType(); switch (type) { case INDEX: appendable.append("INDEX "); break; case KEY: appendable.append("KEY "); break; default: throw new IllegalArgumentException("unkown index type for index hint: " + type); } IndexHint.IndexScope scope = node.getScope(); switch (scope) { case GROUP_BY: appendable.append("FOR GROUP BY "); break; case ORDER_BY: appendable.append("FOR ORDER BY "); break; case JOIN: appendable.append("FOR JOIN "); break; case ALL: break; default: throw new IllegalArgumentException("unkown index scope for index hint: " + scope); } appendable.append('('); List<String> indexList = node.getIndexList(); boolean isFst = true; for (String indexName : indexList) { if (isFst) isFst = false; else appendable.append(", "); appendable.append(indexName); } appendable.append(')'); } @Override public void visit(TableReferences node) { printList(node.getTableReferenceList()); } @Override public void visit(InnerJoin node) { TableReference left = node.getLeftTableRef(); boolean paren = left.getPrecedence() < node.getPrecedence(); if (paren) appendable.append('('); left.accept(this); if (paren) appendable.append(')'); appendable.append(" INNER JOIN "); TableReference right = node.getRightTableRef(); paren = right.getPrecedence() <= node.getPrecedence(); if (paren) appendable.append('('); right.accept(this); if (paren) appendable.append(')'); Expression on = node.getOnCond(); List<String> using = node.getUsing(); if (on != null) { appendable.append(" ON "); on.accept(this); } else if (using != null) { appendable.append(" USING ("); boolean isFst = true; for (String col : using) { if (isFst) isFst = false; else appendable.append(", "); appendable.append(col); } appendable.append(")"); } } @Override public void visit(NaturalJoin node) { TableReference left = node.getLeftTableRef(); boolean paren = left.getPrecedence() < node.getPrecedence(); if (paren) appendable.append('('); left.accept(this); if (paren) appendable.append(')'); appendable.append(" NATURAL "); if (node.isOuter()) { if (node.isLeft()) appendable.append("LEFT "); else appendable.append("RIGHT "); } appendable.append("JOIN "); TableReference right = node.getRightTableRef(); paren = right.getPrecedence() <= node.getPrecedence(); if (paren) appendable.append('('); right.accept(this); if (paren) appendable.append(')'); } @Override public void visit(StraightJoin node) { TableReference left = node.getLeftTableRef(); boolean paren = left.getPrecedence() < node.getPrecedence(); if (paren) appendable.append('('); left.accept(this); if (paren) appendable.append(')'); appendable.append(" STRAIGHT_JOIN "); TableReference right = node.getRightTableRef(); paren = right.getPrecedence() <= node.getPrecedence(); if (paren) appendable.append('('); right.accept(this); if (paren) appendable.append(')'); Expression on = node.getOnCond(); if (on != null) { appendable.append(" ON "); on.accept(this); } } @Override public void visit(OuterJoin node) { TableReference left = node.getLeftTableRef(); boolean paren = left.getPrecedence() < node.getPrecedence(); if (paren) appendable.append('('); left.accept(this); if (paren) appendable.append(')'); if (node.isLeftJoin()) appendable.append(" LEFT JOIN "); else appendable.append(" RIGHT JOIN "); TableReference right = node.getRightTableRef(); paren = right.getPrecedence() <= node.getPrecedence(); if (paren) appendable.append('('); right.accept(this); if (paren) appendable.append(')'); Expression on = node.getOnCond(); List<String> using = node.getUsing(); if (on != null) { appendable.append(" ON "); on.accept(this); } else if (using != null) { appendable.append(" USING ("); boolean isFst = true; for (String col : using) { if (isFst) isFst = false; else appendable.append(", "); appendable.append(col); } appendable.append(")"); } else { throw new IllegalArgumentException("either ON or USING must be included for OUTER JOIN"); } } @Override public void visit(SubqueryFactor node) { appendable.append('('); QueryExpression query = node.getSubquery(); query.accept(this); appendable.append(") AS ").append(node.getAlias()); } @Override public void visit(TableRefFactor node) { Identifier table = node.getTable(); table.accept(this); String alias = node.getAlias(); if (alias != null) { appendable.append(" AS ").append(alias); } List<IndexHint> list = node.getHintList(); if (list != null && !list.isEmpty()) { appendable.append(' '); printList(list, " "); } } @Override public void visit(Dual dual) { appendable.append("DUAL"); } @Override public void visit(GroupBy node) { appendable.append("GROUP BY "); boolean isFst = true; for (Pair<Expression, SortOrder> p : node.getOrderByList()) { if (isFst) isFst = false; else appendable.append(", "); Expression col = p.getKey(); col.accept(this); switch (p.getValue()) { case DESC: appendable.append(" DESC"); break; } } if (node.isWithRollup()) { appendable.append(" WITH ROLLUP"); } } @Override public void visit(OrderBy node) { appendable.append("ORDER BY "); boolean isFst = true; for (Pair<Expression, SortOrder> p : node.getOrderByList()) { if (isFst) isFst = false; else appendable.append(", "); Expression col = p.getKey(); col.accept(this); switch (p.getValue()) { case DESC: appendable.append(" DESC"); break; } } } @Override public void visit(Limit node) { appendable.append("LIMIT "); Object offset = node.getOffset(); if (offset instanceof ParamMarker) { ((ParamMarker) offset).accept(this); } else { appendable.append(String.valueOf(offset)); } appendable.append(", "); Object size = node.getSize(); if (size instanceof ParamMarker) { ((ParamMarker) size).accept(this); } else { appendable.append(String.valueOf(size)); } } @Override public void visit(ColumnDefinition node) { throw new UnsupportedOperationException("col_def in CREATE TABLE is partially parsed"); } @Override public void visit(IndexOption node) { if (node.getKeyBlockSize() != null) { appendable.append("KEY_BLOCK_SIZE = "); node.getKeyBlockSize().accept(this); } else if (node.getIndexType() != null) { appendable.append("USING "); switch (node.getIndexType()) {// USING {BTREE | HASH} case BTREE: appendable.append("BTREE"); break; case HASH: appendable.append("HASH"); break; } } else if (node.getParserName() != null) { appendable.append("WITH PARSER "); node.getParserName().accept(this); } else if (node.getComment() != null) { appendable.append("COMMENT "); node.getComment().accept(this); } } @Override public void visit(IndexColumnName node) { // QS_TODO } @Override public void visit(TableOptions node) { // QS_TODO } @Override public void visit(AlterSpecification node) { throw new UnsupportedOperationException("subclass have not implement visit"); } @Override public void visit(DataType node) { throw new UnsupportedOperationException("subclass have not implement visit"); } private void printSimpleShowStmt(String attName) { appendable.append("SHOW ").append(attName); } @Override public void visit(ShowAuthors node) { printSimpleShowStmt("AUTHORS"); } @Override public void visit(ShowBinaryLog node) { printSimpleShowStmt("BINARY LOGS"); } @Override public void visit(ShowBinLogEvent node) { appendable.append("SHOW BINLOG EVENTS"); String logName = node.getLogName(); if (logName != null) appendable.append(" IN ").append(logName); Expression pos = node.getPos(); if (pos != null) { appendable.append(" FROM "); pos.accept(this); } Limit limit = node.getLimit(); if (limit != null) { appendable.append(' '); limit.accept(this); } } /** * ' ' will be prepended */ private void printLikeOrWhere(String like, Expression where) { if (like != null) { appendable.append(" LIKE ").append(like); } else if (where != null) { appendable.append(" WHERE "); where.accept(this); } } @Override public void visit(ShowCharaterSet node) { appendable.append("SHOW CHARACTER SET"); printLikeOrWhere(node.getPattern(), node.getWhere()); } @Override public void visit(ShowCollation node) { appendable.append("SHOW COLLATION"); printLikeOrWhere(node.getPattern(), node.getWhere()); } @Override public void visit(ShowColumns node) { appendable.append("SHOW "); if (node.isFull()) appendable.append("FULL "); appendable.append("COLUMNS FROM "); node.getTable().accept(this); printLikeOrWhere(node.getPattern(), node.getWhere()); } @Override public void visit(ShowContributors node) { printSimpleShowStmt("CONTRIBUTORS"); } @Override public void visit(ShowCreate node) { appendable.append("SHOW CREATE ").append(node.getType().name()).append(' '); node.getId().accept(this); } @Override public void visit(ShowDatabases node) { appendable.append("SHOW DATABASES"); printLikeOrWhere(node.getPattern(), node.getWhere()); } @Override public void visit(ShowEngine node) { appendable.append("SHOW ENGINE "); switch (node.getType()) { case INNODB_MUTEX: appendable.append("INNODB MUTEX"); break; case INNODB_STATUS: appendable.append("INNODB STATUS"); break; case PERFORMANCE_SCHEMA_STATUS: appendable.append("PERFORMANCE SCHEMA STATUS"); break; default: throw new IllegalArgumentException("unrecognized type for SHOW ENGINE: " + node.getType()); } } @Override public void visit(ShowEngines node) { printSimpleShowStmt("ENGINES"); } @Override public void visit(ShowErrors node) { appendable.append("SHOW "); if (node.isCount()) { appendable.append("COUNT(*) ERRORS"); } else { appendable.append("ERRORS"); Limit limit = node.getLimit(); if (node.getLimit() != null) { appendable.append(' '); limit.accept(this); } } } @Override public void visit(ShowEvents node) { appendable.append("SHOW EVENTS"); Identifier schema = node.getSchema(); if (schema != null) { appendable.append(" FROM "); schema.accept(this); } printLikeOrWhere(node.getPattern(), node.getWhere()); } @Override public void visit(ShowFunctionCode node) { appendable.append("SHOW FUNCTION CODE "); node.getFunctionName().accept(this); } @Override public void visit(ShowFunctionStatus node) { appendable.append("SHOW FUNCTION STATUS"); printLikeOrWhere(node.getPattern(), node.getWhere()); } @Override public void visit(ShowGrants node) { appendable.append("SHOW GRANTS"); Expression user = node.getUser(); if (user != null) { appendable.append(" FOR "); user.accept(this); } } @Override public void visit(ShowIndex node) { appendable.append("SHOW "); switch (node.getType()) { case INDEX: appendable.append("INDEX "); break; case INDEXES: appendable.append("INDEXES "); break; case KEYS: appendable.append("KEYS "); break; default: throw new IllegalArgumentException("unrecognized type for SHOW INDEX: " + node.getType()); } appendable.append("IN "); node.getTable().accept(this); } @Override public void visit(ShowMasterStatus node) { printSimpleShowStmt("MASTER STATUS"); } @Override public void visit(ShowOpenTables node) { appendable.append("SHOW OPEN TABLES"); Identifier db = node.getSchema(); if (db != null) { appendable.append(" FROM "); db.accept(this); } printLikeOrWhere(node.getPattern(), node.getWhere()); } @Override public void visit(ShowPlugins node) { printSimpleShowStmt("PLUGINS"); } @Override public void visit(ShowPrivileges node) { printSimpleShowStmt("PRIVILEGES"); } @Override public void visit(ShowProcedureCode node) { appendable.append("SHOW PROCEDURE CODE "); node.getProcedureName().accept(this); } @Override public void visit(ShowProcedureStatus node) { appendable.append("SHOW PROCEDURE STATUS"); printLikeOrWhere(node.getPattern(), node.getWhere()); } @Override public void visit(ShowProcesslist node) { appendable.append("SHOW "); if (node.isFull()) appendable.append("FULL "); appendable.append("PROCESSLIST"); } @Override public void visit(ShowProfile node) { appendable.append("SHOW PROFILE"); List<ShowProfile.Type> types = node.getTypes(); boolean isFst = true; for (ShowProfile.Type type : types) { if (isFst) { isFst = false; appendable.append(' '); } else { appendable.append(", "); } appendable.append(type.name().replace('_', ' ')); } Expression query = node.getForQuery(); if (query != null) { appendable.append(" FOR QUERY "); query.accept(this); } Limit limit = node.getLimit(); if (limit != null) { appendable.append(' '); limit.accept(this); } } @Override public void visit(ShowProfiles node) { printSimpleShowStmt("PROFILES"); } @Override public void visit(ShowSlaveHosts node) { printSimpleShowStmt("SLAVE HOSTS"); } @Override public void visit(ShowSlaveStatus node) { printSimpleShowStmt("SLAVE STATUS"); } @Override public void visit(ShowStatus node) { appendable.append("SHOW ").append(node.getScope().name().replace('_', ' ')).append(" STATUS"); printLikeOrWhere(node.getPattern(), node.getWhere()); } @Override public void visit(ShowTables node) { appendable.append("SHOW"); if (node.isFull()) appendable.append(" FULL"); appendable.append(" TABLES"); Identifier schema = node.getSchema(); if (schema != null) { appendable.append(" FROM "); schema.accept(this); } printLikeOrWhere(node.getPattern(), node.getWhere()); } @Override public void visit(ShowTableStatus node) { appendable.append("SHOW TABLE STATUS"); Identifier schema = node.getDatabase(); if (schema != null) { appendable.append(" FROM "); schema.accept(this); } printLikeOrWhere(node.getPattern(), node.getWhere()); } @Override public void visit(ShowTriggers node) { appendable.append("SHOW TRIGGERS"); Identifier schema = node.getSchema(); if (schema != null) { appendable.append(" FROM "); schema.accept(this); } printLikeOrWhere(node.getPattern(), node.getWhere()); } @Override public void visit(ShowVariables node) { appendable.append("SHOW ").append(node.getScope().name().replace('_', ' ')).append(" VARIABLES"); printLikeOrWhere(node.getPattern(), node.getWhere()); } @Override public void visit(ShowWarnings node) { appendable.append("SHOW "); if (node.isCount()) { appendable.append("COUNT(*) WARNINGS"); } else { appendable.append("WARNINGS"); Limit limit = node.getLimit(); if (limit != null) { appendable.append(' '); limit.accept(this); } } } @Override public void visit(DescTableStatement node) { appendable.append("DESC "); node.getTable().accept(this); } @Override public void visit(DALSetStatement node) { appendable.append("SET "); boolean isFst = true; for (Pair<VariableExpression, Expression> p : node.getAssignmentList()) { if (isFst) isFst = false; else appendable.append(", "); p.getKey().accept(this); appendable.append(" = "); p.getValue().accept(this); } } @Override public void visit(DALSetNamesStatement node) { appendable.append("SET NAMES "); if (node.isDefault()) { appendable.append("DEFAULT"); } else { appendable.append(node.getCharsetName()); String collate = node.getCollationName(); if (collate != null) { appendable.append(" COLLATE "); appendable.append(collate); } } } @Override public void visit(DALSetCharacterSetStatement node) { appendable.append("SET CHARACTER SET "); if (node.isDefault()) { appendable.append("DEFAULT"); } else { appendable.append(node.getCharset()); } } @Override public void visit(MTSSetTransactionStatement node) { appendable.append("SET "); VariableScope scope = node.getScope(); if (scope != null) { switch (scope) { case SESSION: appendable.append("SESSION "); break; case GLOBAL: appendable.append("GLOBAL "); break; default: throw new IllegalArgumentException("unknown scope for SET TRANSACTION ISOLATION LEVEL: " + scope); } } appendable.append("TRANSACTION ISOLATION LEVEL "); switch (node.getLevel()) { case READ_COMMITTED: appendable.append("READ COMMITTED"); break; case READ_UNCOMMITTED: appendable.append("READ UNCOMMITTED"); break; case REPEATABLE_READ: appendable.append("REPEATABLE READ"); break; case SERIALIZABLE: appendable.append("SERIALIZABLE"); break; default: throw new IllegalArgumentException("unknown level for SET TRANSACTION ISOLATION LEVEL: " + node.getLevel()); } } @Override public void visit(MTSSavepointStatement node) { appendable.append("SAVEPOINT "); node.getSavepoint().accept(this); } @Override public void visit(MTSReleaseStatement node) { appendable.append("RELEASE SAVEPOINT "); node.getSavepoint().accept(this); } @Override public void visit(MTSRollbackStatement node) { appendable.append("ROLLBACK"); Identifier savepoint = node.getSavepoint(); if (savepoint == null) { MTSRollbackStatement.CompleteType type = node.getCompleteType(); switch (type) { case CHAIN: appendable.append(" AND CHAIN"); break; case NO_CHAIN: appendable.append(" AND NO CHAIN"); break; case NO_RELEASE: appendable.append(" NO RELEASE"); break; case RELEASE: appendable.append(" RELEASE"); break; case UN_DEF: break; default: throw new IllegalArgumentException("unrecgnized complete type: " + type); } } else { appendable.append(" TO SAVEPOINT "); savepoint.accept(this); } } @Override public void visit(DMLCallStatement node) { appendable.append("CALL "); node.getProcedure().accept(this); appendable.append('('); printList(node.getArguments()); appendable.append(')'); } @Override public void visit(DMLDeleteStatement node) { appendable.append("DELETE "); if (node.isLowPriority()) appendable.append("LOW_PRIORITY "); if (node.isQuick()) appendable.append("QUICK "); if (node.isIgnore()) appendable.append("IGNORE "); TableReferences tableRefs = node.getTableRefs(); if (tableRefs == null) { appendable.append("FROM "); node.getTableNames().get(0).accept(this); } else { printList(node.getTableNames()); appendable.append(" FROM "); node.getTableRefs().accept(this); } Expression where = node.getWhereCondition(); if (where != null) { appendable.append(" WHERE "); where.accept(this); } OrderBy orderBy = node.getOrderBy(); if (orderBy != null) { appendable.append(' '); orderBy.accept(this); } Limit limit = node.getLimit(); if (limit != null) { appendable.append(' '); limit.accept(this); } } @Override public void visit(DMLInsertStatement node) { appendable.append("INSERT "); switch (node.getMode()) { case DELAY: appendable.append("DELAYED "); break; case HIGH: appendable.append("HIGH_PRIORITY "); break; case LOW: appendable.append("LOW_PRIORITY "); break; case UNDEF: break; default: throw new IllegalArgumentException("unknown mode for INSERT: " + node.getMode()); } if (node.isIgnore()) appendable.append("IGNORE "); appendable.append("INTO "); node.getTable().accept(this); appendable.append(' '); List<Identifier> cols = node.getColumnNameList(); if (cols != null && !cols.isEmpty()) { appendable.append('('); printList(cols); appendable.append(") "); } QueryExpression select = node.getSelect(); if (select == null) { appendable.append("VALUES "); List<RowExpression> rows = node.getRowList(); if (rows != null && !rows.isEmpty()) { boolean isFst = true; for (RowExpression row : rows) { if (row == null || row.getRowExprList().isEmpty()) continue; if (isFst) isFst = false; else appendable.append(", "); appendable.append('('); printList(row.getRowExprList()); appendable.append(')'); } } else { throw new IllegalArgumentException("at least one row for INSERT"); } } else { select.accept(this); } List<Pair<Identifier, Expression>> dup = node.getDuplicateUpdate(); if (dup != null && !dup.isEmpty()) { appendable.append(" ON DUPLICATE KEY UPDATE "); boolean isFst = true; for (Pair<Identifier, Expression> p : dup) { if (isFst) isFst = false; else appendable.append(", "); p.getKey().accept(this); appendable.append(" = "); p.getValue().accept(this); } } } @Override public void visit(DMLReplaceStatement node) { appendable.append("REPLACE "); switch (node.getMode()) { case DELAY: appendable.append("DELAYED "); break; case LOW: appendable.append("LOW_PRIORITY "); break; case UNDEF: break; default: throw new IllegalArgumentException("unknown mode for INSERT: " + node.getMode()); } appendable.append("INTO "); node.getTable().accept(this); appendable.append(' '); List<Identifier> cols = node.getColumnNameList(); if (cols != null && !cols.isEmpty()) { appendable.append('('); printList(cols); appendable.append(") "); } QueryExpression select = node.getSelect(); if (select == null) { appendable.append("VALUES "); List<RowExpression> rows = node.getRowList(); if (rows != null && !rows.isEmpty()) { boolean isFst = true; for (RowExpression row : rows) { if (row == null || row.getRowExprList().isEmpty()) continue; if (isFst) isFst = false; else appendable.append(", "); appendable.append('('); printList(row.getRowExprList()); appendable.append(')'); } } else { throw new IllegalArgumentException("at least one row for REPLACE"); } } else { select.accept(this); } } @Override public void visit(DMLSelectStatement node) { appendable.append("SELECT "); final DMLSelectStatement.SelectOption option = node.getOption(); switch (option.resultDup) { case ALL: break; case DISTINCT: appendable.append("DISTINCT "); break; case DISTINCTROW: appendable.append("DISTINCTROW "); break; default: throw new IllegalArgumentException("unknown option for SELECT: " + option); } if (option.highPriority) { appendable.append("HIGH_PRIORITY "); } if (option.straightJoin) { appendable.append("STRAIGHT_JOIN "); } switch (option.resultSize) { case SQL_BIG_RESULT: appendable.append("SQL_BIG_RESULT "); break; case SQL_SMALL_RESULT: appendable.append("SQL_SMALL_RESULT "); break; case UNDEF: break; default: throw new IllegalArgumentException("unknown option for SELECT: " + option); } if (option.sqlBufferResult) { appendable.append("SQL_BUFFER_RESULT "); } switch (option.queryCache) { case SQL_CACHE: appendable.append("SQL_CACHE "); break; case SQL_NO_CACHE: appendable.append("SQL_NO_CACHE "); break; case UNDEF: break; default: throw new IllegalArgumentException("unknown option for SELECT: " + option); } if (option.sqlCalcFoundRows) { appendable.append("SQL_CALC_FOUND_ROWS "); } boolean isFst = true; List<Pair<Expression, String>> exprList = node.getSelectExprList(); for (Pair<Expression, String> p : exprList) { if (isFst) isFst = false; else appendable.append(", "); p.getKey().accept(this); String alias = p.getValue(); if (alias != null) { appendable.append(" AS ").append(alias); } } TableReferences from = node.getTables(); if (from != null) { appendable.append(" FROM "); from.accept(this); } Expression where = node.getWhere(); if (where != null) { appendable.append(" WHERE "); where.accept(this); } GroupBy group = node.getGroup(); if (group != null) { appendable.append(' '); group.accept(this); } Expression having = node.getHaving(); if (having != null) { appendable.append(" HAVING "); having.accept(this); } OrderBy order = node.getOrder(); if (order != null) { appendable.append(' '); order.accept(this); } Limit limit = node.getLimit(); if (limit != null) { appendable.append(' '); limit.accept(this); } switch (option.lockMode) { case FOR_UPDATE: appendable.append(" FOR UPDATE"); break; case LOCK_IN_SHARE_MODE: appendable.append(" LOCK IN SHARE MODE"); break; case UNDEF: break; default: throw new IllegalArgumentException("unknown option for SELECT: " + option); } } @Override public void visit(DMLSelectUnionStatement node) { List<DMLSelectStatement> list = node.getSelectStmtList(); if (list == null || list.isEmpty()) { throw new IllegalArgumentException("SELECT UNION must have at least one SELECT"); } final int fstDist = node.getFirstDistinctIndex(); int i = 0; for (DMLSelectStatement select : list) { if (i > 0) { appendable.append(" UNION "); if (i > fstDist) { appendable.append("ALL "); } } appendable.append('('); select.accept(this); appendable.append(')'); ++i; } OrderBy order = node.getOrderBy(); if (order != null) { appendable.append(' '); order.accept(this); } Limit limit = node.getLimit(); if (limit != null) { appendable.append(' '); limit.accept(this); } } @Override public void visit(DMLUpdateStatement node) { appendable.append("UPDATE "); if (node.isLowPriority()) { appendable.append("LOW_PRIORITY "); } if (node.isIgnore()) { appendable.append("IGNORE "); } node.getTableRefs().accept(this); appendable.append(" SET "); boolean isFst = true; for (Pair<Identifier, Expression> p : node.getValues()) { if (isFst) isFst = false; else appendable.append(", "); p.getKey().accept(this); appendable.append(" = "); p.getValue().accept(this); } Expression where = node.getWhere(); if (where != null) { appendable.append(" WHERE "); where.accept(this); } OrderBy order = node.getOrderBy(); if (order != null) { appendable.append(' '); order.accept(this); } Limit limit = node.getLimit(); if (limit != null) { appendable.append(' '); limit.accept(this); } } @Override public void visit(DDLTruncateStatement node) { appendable.append("TRUNCATE TABLE "); node.getTable().accept(this); } @Override public void visit(DDLAlterTableStatement node) { throw new UnsupportedOperationException("ALTER TABLE is partially parsed"); } @Override public void visit(DDLCreateIndexStatement node) { throw new UnsupportedOperationException("CREATE INDEX is partially parsed"); } @Override public void visit(DDLCreateTableStatement node) { throw new UnsupportedOperationException("CREATE TABLE is partially parsed"); } @Override public void visit(DDLRenameTableStatement node) { appendable.append("RENAME TABLE "); boolean isFst = true; for (Pair<Identifier, Identifier> p : node.getList()) { if (isFst) isFst = false; else appendable.append(", "); p.getKey().accept(this); appendable.append(" TO "); p.getValue().accept(this); } } @Override public void visit(DDLDropIndexStatement node) { appendable.append("DROP INDEX "); node.getIndexName().accept(this); appendable.append(" ON "); node.getTable().accept(this); } @Override public void visit(DDLDropTableStatement node) { appendable.append("DROP "); if (node.isTemp()) { appendable.append("TEMPORARY "); } appendable.append("TABLE "); if (node.isIfExists()) { appendable.append("IF EXISTS "); } printList(node.getTableNames()); switch (node.getMode()) { case CASCADE: appendable.append(" CASCADE"); break; case RESTRICT: appendable.append(" RESTRICT"); break; case UNDEF: break; default: throw new IllegalArgumentException("unsupported mode for DROP TABLE: " + node.getMode()); } } @Override public void visit(ExtDDLCreatePolicy node) { appendable.append("CREATE POLICY "); node.getName().accept(this); appendable.append(" ("); boolean first = true; for (Pair<Integer, Expression> p : node.getProportion()) { if (first) first = false; else appendable.append(", "); appendable.append(p.getKey()).append(' '); p.getValue().accept(this); } appendable.append(')'); } @Override public void visit(ExtDDLDropPolicy node) { appendable.append("DROP POLICY "); node.getPolicyName().accept(this); } }