/**
* Copyright 2011-2013 Akiban Technologies, 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,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.akiban.sql.unparser;
import com.akiban.sql.parser.*;
import com.akiban.sql.StandardException;
public class NodeToString
{
public NodeToString() {
}
public String toString(QueryTreeNode node) throws StandardException {
switch (node.getNodeType()) {
case NodeTypes.CREATE_TABLE_NODE:
return createTableNode((CreateTableNode)node);
case NodeTypes.CREATE_VIEW_NODE:
return createViewNode((CreateViewNode)node);
case NodeTypes.DROP_TABLE_NODE:
case NodeTypes.DROP_VIEW_NODE:
case NodeTypes.DROP_TRIGGER_NODE:
return qualifiedDDLNode((DDLStatementNode)node);
case NodeTypes.DROP_INDEX_NODE:
return dropIndexNode((DropIndexNode)node);
case NodeTypes.EXPLAIN_STATEMENT_NODE:
return explainStatementNode((ExplainStatementNode)node);
case NodeTypes.TRANSACTION_CONTROL_NODE:
return transactionControlNode((TransactionControlNode)node);
case NodeTypes.SET_TRANSACTION_ISOLATION_NODE:
return setTransactionIsolationNode((SetTransactionIsolationNode)node);
case NodeTypes.SET_TRANSACTION_ACCESS_NODE:
return setTransactionAccessNode((SetTransactionAccessNode)node);
case NodeTypes.SET_CONFIGURATION_NODE:
return setConfigurationNode((SetConfigurationNode)node);
case NodeTypes.TABLE_ELEMENT_LIST:
return tableElementList((TableElementList)node);
case NodeTypes.COLUMN_DEFINITION_NODE:
return columnDefinitionNode((ColumnDefinitionNode)node);
case NodeTypes.CONSTRAINT_DEFINITION_NODE:
return constraintDefinitionNode((ConstraintDefinitionNode)node);
case NodeTypes.FK_CONSTRAINT_DEFINITION_NODE:
return fkConstraintDefinitionNode((FKConstraintDefinitionNode)node);
case NodeTypes.CREATE_INDEX_NODE:
return createIndexNode((CreateIndexNode)node);
case NodeTypes.INDEX_COLUMN_LIST:
return indexColumnList((IndexColumnList)node);
case NodeTypes.INDEX_COLUMN:
return indexColumn((IndexColumn)node);
case NodeTypes.CREATE_ALIAS_NODE:
return createAliasNode((CreateAliasNode)node);
case NodeTypes.RENAME_NODE:
return renameNode((RenameNode)node);
case NodeTypes.CURSOR_NODE:
return cursorNode((CursorNode)node);
case NodeTypes.SELECT_NODE:
return selectNode((SelectNode)node);
case NodeTypes.INSERT_NODE:
return insertNode((InsertNode)node);
case NodeTypes.UPDATE_NODE:
return updateNode((UpdateNode)node);
case NodeTypes.DELETE_NODE:
return deleteNode((DeleteNode)node);
case NodeTypes.SUBQUERY_NODE:
return subqueryNode((SubqueryNode)node);
case NodeTypes.RESULT_COLUMN_LIST:
return resultColumnList((ResultColumnList)node);
case NodeTypes.RESULT_COLUMN:
return resultColumn((ResultColumn)node);
case NodeTypes.ALL_RESULT_COLUMN:
return allResultColumn((AllResultColumn)node);
case NodeTypes.FROM_LIST:
return fromList((FromList)node);
case NodeTypes.JOIN_NODE:
case NodeTypes.HALF_OUTER_JOIN_NODE:
case NodeTypes.FULL_OUTER_JOIN_NODE:
return joinNode((JoinNode)node);
case NodeTypes.UNION_NODE:
return unionNode((UnionNode)node);
case NodeTypes.GROUP_BY_LIST:
return groupByList((GroupByList)node);
case NodeTypes.GROUP_CONCAT_NODE:
return groupConcat((GroupConcatNode)node);
case NodeTypes.ORDER_BY_LIST:
return orderByList((OrderByList)node);
case NodeTypes.VALUE_NODE_LIST:
return valueNodeList((ValueNodeList)node);
case NodeTypes.FROM_BASE_TABLE:
return fromBaseTable((FromBaseTable)node);
case NodeTypes.FROM_SUBQUERY:
return fromSubquery((FromSubquery)node);
case NodeTypes.TABLE_NAME:
return tableName((TableName)node);
case NodeTypes.COLUMN_REFERENCE:
return columnReference((ColumnReference)node);
case NodeTypes.VIRTUAL_COLUMN_NODE:
return virtualColumnNode((VirtualColumnNode)node);
case NodeTypes.ROW_RESULT_SET_NODE:
return rowResultSetNode((RowResultSetNode)node);
case NodeTypes.ROWS_RESULT_SET_NODE:
return rowsResultSetNode((RowsResultSetNode)node);
case NodeTypes.GROUP_BY_COLUMN:
return groupByColumn((GroupByColumn)node);
case NodeTypes.ORDER_BY_COLUMN:
return orderByColumn((OrderByColumn)node);
case NodeTypes.PARTITION_BY_LIST:
return partitionByList((PartitionByList)node);
case NodeTypes.PARTITION_BY_COLUMN:
return partitionByColumn((PartitionByColumn)node);
case NodeTypes.WINDOW_DEFINITION_NODE:
return windowDefinitionNode((WindowDefinitionNode)node);
case NodeTypes.WINDOW_REFERENCE_NODE:
return windowReferenceNode((WindowReferenceNode)node);
case NodeTypes.AGGREGATE_WINDOW_FUNCTION_NODE:
return aggregateWindowFunctionNode((AggregateWindowFunctionNode)node);
case NodeTypes.ROW_NUMBER_FUNCTION_NODE:
return rowNumberFunctionNode((RowNumberFunctionNode)node);
case NodeTypes.AND_NODE:
case NodeTypes.OR_NODE:
return binaryLogicalOperatorNode((BinaryLogicalOperatorNode)node);
case NodeTypes.BINARY_EQUALS_OPERATOR_NODE:
case NodeTypes.BINARY_NOT_EQUALS_OPERATOR_NODE:
case NodeTypes.BINARY_GREATER_THAN_OPERATOR_NODE:
case NodeTypes.BINARY_GREATER_EQUALS_OPERATOR_NODE:
case NodeTypes.BINARY_LESS_THAN_OPERATOR_NODE:
case NodeTypes.BINARY_LESS_EQUALS_OPERATOR_NODE:
return binaryComparisonOperatorNode((BinaryComparisonOperatorNode)node);
case NodeTypes.BINARY_PLUS_OPERATOR_NODE:
case NodeTypes.BINARY_TIMES_OPERATOR_NODE:
case NodeTypes.BINARY_DIVIDE_OPERATOR_NODE:
case NodeTypes.BINARY_DIV_OPERATOR_NODE:
case NodeTypes.BINARY_MINUS_OPERATOR_NODE:
case NodeTypes.MOD_OPERATOR_NODE:
return binaryArithmeticOperatorNode((BinaryArithmeticOperatorNode)node);
case NodeTypes.BINARY_BIT_OPERATOR_NODE:
return binaryBitOperatorNode((BinaryBitOperatorNode)node);
case NodeTypes.CONCATENATION_OPERATOR_NODE:
return concatenationOperatorNode((ConcatenationOperatorNode)node);
case NodeTypes.NOT_NODE:
return notNode((NotNode)node);
case NodeTypes.IS_NULL_NODE:
case NodeTypes.IS_NOT_NULL_NODE:
return isNullNode((IsNullNode)node);
case NodeTypes.IS_NODE:
return isNode((IsNode)node);
case NodeTypes.ABSOLUTE_OPERATOR_NODE:
case NodeTypes.SQRT_OPERATOR_NODE:
return unaryArithmeticOperatorNode((UnaryArithmeticOperatorNode)node);
case NodeTypes.UNARY_PLUS_OPERATOR_NODE:
case NodeTypes.UNARY_MINUS_OPERATOR_NODE:
return unaryPrefixOperatorNode((UnaryArithmeticOperatorNode)node);
case NodeTypes.UNARY_BITNOT_OPERATOR_NODE:
return unaryBitOperatorNode((UnaryBitOperatorNode)node);
case NodeTypes.UNARY_DATE_TIMESTAMP_OPERATOR_NODE:
return unaryDateTimestampOperatorNode((UnaryDateTimestampOperatorNode)node);
case NodeTypes.TIMESTAMP_OPERATOR_NODE:
return timestampOperatorNode((TimestampOperatorNode)node);
case NodeTypes.EXTRACT_OPERATOR_NODE:
return extractOperatorNode((ExtractOperatorNode)node);
case NodeTypes.CHAR_LENGTH_OPERATOR_NODE:
return lengthOperatorNode((LengthOperatorNode)node);
case NodeTypes.OCTET_LENGTH_OPERATOR_NODE:
return octetLengthOperatorNode((OctetLengthOperatorNode)node);
case NodeTypes.RIGHT_FN_NODE:
case NodeTypes.LEFT_FN_NODE:
return leftRightFuncOperatorNode((LeftRightFuncOperatorNode)node);
case NodeTypes.SIMPLE_STRING_OPERATOR_NODE:
return simpleStringOperatorNode((SimpleStringOperatorNode)node);
case NodeTypes.LIKE_OPERATOR_NODE:
return likeEscapeOperatorNode((LikeEscapeOperatorNode)node);
case NodeTypes.LOCATE_FUNCTION_NODE:
case NodeTypes.SUBSTRING_OPERATOR_NODE:
return ternaryOperatorNode((TernaryOperatorNode)node);
case NodeTypes.TIMESTAMP_ADD_FN_NODE:
case NodeTypes.TIMESTAMP_DIFF_FN_NODE:
return timestampFunctionNode((TernaryOperatorNode)node);
case NodeTypes.TRIM_OPERATOR_NODE:
return trimOperatorNode((TrimOperatorNode)node);
case NodeTypes.IN_LIST_OPERATOR_NODE:
return inListOperatorNode((InListOperatorNode)node);
case NodeTypes.ROW_CTOR_NODE:
return rowCtorNode((RowConstructorNode)node);
case NodeTypes.BETWEEN_OPERATOR_NODE:
return betweenOperatorNode((BetweenOperatorNode)node);
case NodeTypes.CONDITIONAL_NODE:
return conditionalNode((ConditionalNode)node);
case NodeTypes.SIMPLE_CASE_NODE:
return simpleCaseNode((SimpleCaseNode)node);
case NodeTypes.COALESCE_FUNCTION_NODE:
return coalesceFunctionNode((CoalesceFunctionNode)node);
case NodeTypes.AGGREGATE_NODE:
return aggregateNode((AggregateNode)node);
case NodeTypes.UNTYPED_NULL_CONSTANT_NODE:
case NodeTypes.SQL_BOOLEAN_CONSTANT_NODE:
case NodeTypes.BOOLEAN_CONSTANT_NODE:
case NodeTypes.BIT_CONSTANT_NODE:
case NodeTypes.VARBIT_CONSTANT_NODE:
case NodeTypes.CHAR_CONSTANT_NODE:
case NodeTypes.DECIMAL_CONSTANT_NODE:
case NodeTypes.DOUBLE_CONSTANT_NODE:
case NodeTypes.FLOAT_CONSTANT_NODE:
case NodeTypes.INT_CONSTANT_NODE:
case NodeTypes.LONGINT_CONSTANT_NODE:
case NodeTypes.LONGVARBIT_CONSTANT_NODE:
case NodeTypes.LONGVARCHAR_CONSTANT_NODE:
case NodeTypes.SMALLINT_CONSTANT_NODE:
case NodeTypes.TINYINT_CONSTANT_NODE:
case NodeTypes.USERTYPE_CONSTANT_NODE:
case NodeTypes.VARCHAR_CONSTANT_NODE:
case NodeTypes.BLOB_CONSTANT_NODE:
case NodeTypes.CLOB_CONSTANT_NODE:
case NodeTypes.XML_CONSTANT_NODE:
return constantNode((ConstantNode)node);
case NodeTypes.PARAMETER_NODE:
return parameterNode((ParameterNode)node);
case NodeTypes.DEFAULT_NODE:
return "DEFAULT";
case NodeTypes.USER_NODE:
return "USER";
case NodeTypes.CURRENT_USER_NODE:
return "CURRENT_USER";
case NodeTypes.SESSION_USER_NODE:
return "SESSION_USER";
case NodeTypes.SYSTEM_USER_NODE:
return "SYSTEM_USER";
case NodeTypes.CURRENT_ISOLATION_NODE:
return "CURRENT ISOLATION";
case NodeTypes.IDENTITY_VAL_NODE:
return "IDENTITY_VAL_LOCAL()";
case NodeTypes.CURRENT_SCHEMA_NODE:
return "CURRENT SCHEMA";
case NodeTypes.CURRENT_ROLE_NODE:
return "CURRENT_ROLE";
case NodeTypes.CURRENT_DATETIME_OPERATOR_NODE:
return currentDatetimeOperatorNode((CurrentDatetimeOperatorNode)node);
case NodeTypes.CAST_NODE:
return castNode((CastNode)node);
case NodeTypes.EXPLICIT_COLLATE_NODE:
return explicitCollateNode((ExplicitCollateNode)node);
case NodeTypes.NEXT_SEQUENCE_NODE:
return nextSequenceNode((NextSequenceNode)node);
case NodeTypes.CURRENT_SEQUENCE_NODE:
return currentSequenceNode((CurrentSequenceNode)node);
case NodeTypes.JAVA_TO_SQL_VALUE_NODE:
return javaToSQLValueNode((JavaToSQLValueNode)node);
case NodeTypes.SQL_TO_JAVA_VALUE_NODE:
return sqlToJavaValueNode((SQLToJavaValueNode)node);
case NodeTypes.STATIC_METHOD_CALL_NODE:
return staticMethodCallNode((StaticMethodCallNode)node);
case NodeTypes.CALL_STATEMENT_NODE:
return callStatementNode((CallStatementNode)node);
case NodeTypes.INDEX_CONSTRAINT_NODE:
return indexConstraint((IndexConstraintDefinitionNode)node);
case NodeTypes.DECLARE_STATEMENT_NODE:
return declareStatementNode((DeclareStatementNode)node);
case NodeTypes.FETCH_STATEMENT_NODE:
return fetchStatementNode((FetchStatementNode)node);
case NodeTypes.CLOSE_STATEMENT_NODE:
return closeStatementNode((CloseStatementNode)node);
case NodeTypes.PREPARE_STATEMENT_NODE:
return prepareStatementNode((PrepareStatementNode)node);
case NodeTypes.EXECUTE_STATEMENT_NODE:
return executeStatementNode((ExecuteStatementNode)node);
case NodeTypes.DEALLOCATE_STATEMENT_NODE:
return deallocateStatementNode((DeallocateStatementNode)node);
case NodeTypes.COPY_STATEMENT_NODE:
return copyStatementNode((CopyStatementNode)node);
default:
return "**UNKNOWN(" + node.getNodeType() +")**";
}
}
protected String indexConstraint(IndexConstraintDefinitionNode node) throws StandardException
{
StringBuilder builder = new StringBuilder("INDEX ");
String indexName = node.getIndexName();
if (indexName != null)
builder.append(indexName).append(' ');
builder.append('(')
.append(indexColumnList(node.getIndexColumnList()))
.append(')');
StorageLocation loc = node.getLocation();
if (loc != null)
builder.append(" AS ").append(loc);
return builder.toString();
}
protected String createTableNode(CreateTableNode node) throws StandardException {
StringBuilder str = new StringBuilder("CREATE TABLE ");
str.append(toString(node.getObjectName()));
if (node.getTableElementList() != null) {
str.append("(");
str.append(toString(node.getTableElementList()));
str.append(")");
}
if (node.getQueryExpression() != null) {
str.append(" AS (");
str.append(toString(node.getQueryExpression()));
str.append(") WITH ");
if (!node.isWithData()) str.append("NO ");
str.append("DATA");
}
return str.toString();
}
protected String createViewNode(CreateViewNode node) throws StandardException {
StringBuilder str = new StringBuilder("CREATE VIEW ");
str.append(toString(node.getObjectName()));
if (node.getResultColumns() != null) {
str.append("(");
str.append(toString(node.getResultColumns()));
str.append(")");
}
str.append(" AS (");
str.append(toString(node.getParsedQueryExpression()));
str.append(")");
return str.toString();
}
protected String tableElementList(TableElementList node) throws StandardException {
return nodeList(node);
}
protected String columnDefinitionNode(ColumnDefinitionNode node)
throws StandardException {
return node.getColumnName() + " " + node.getType();
}
protected String constraintDefinitionNode(ConstraintDefinitionNode node)
throws StandardException {
switch (node.getConstraintType()) {
case PRIMARY_KEY:
return "PRIMARY KEY(" + toString(node.getColumnList()) + ")";
case UNIQUE:
return "UNIQUE(" + toString(node.getColumnList()) + ")";
default:
return "**UNKNOWN(" + node.getConstraintType() + ")";
}
}
protected String fkConstraintDefinitionNode(FKConstraintDefinitionNode node)
throws StandardException {
StringBuilder str = new StringBuilder();
if (node.isGrouping())
str.append("GROUPING ");
str.append("FOREIGN KEY(");
str.append(toString(node.getColumnList()));
str.append(") REFERENCES ");
str.append(toString(node.getRefTableName()));
str.append("(");
str.append(toString(node.getColumnList()));
str.append(")");
return str.toString();
}
protected String createIndexNode(CreateIndexNode node) throws StandardException {
StringBuilder str = new StringBuilder("CREATE ");
if (node.getUniqueness())
str.append("UNIQUE ");
str.append("INDEX");
str.append(" ");
switch (node.getExistenceCheck())
{
case IF_EXISTS:
str.append("IF EXISTS ");
break;
case IF_NOT_EXISTS:
str.append("IF NOT EXISTS ");
break;
}
str.append(toString(node.getIndexName()));
str.append(" ON ");
str.append(node.getIndexTableName());
str.append("(");
str.append(toString(node.getColumnList()));
str.append(")");
if (node.getJoinType() != null) {
str.append(String.format(" USING %s JOIN",
node.getJoinType() == JoinNode.JoinType.LEFT_OUTER ? "LEFT" : "RIGHT"));
}
return str.toString();
}
protected String indexColumnList(IndexColumnList node) throws StandardException {
StringBuilder buffer = new StringBuilder();
int firstFunctionArg = node.firstFunctionArg();
int lastFunctionArg = node.lastFunctionArg();
int arg = 0;
while (arg < node.size()) {
if (arg > 0) {
buffer.append(", ");
}
if (arg == firstFunctionArg) {
buffer.append(node.functionType());
buffer.append('(');
}
buffer.append(toString(node.get(arg)));
if (arg == lastFunctionArg) {
buffer.append(')');
}
arg++;
}
return buffer.toString();
}
protected String indexColumn(IndexColumn node) throws StandardException {
StringBuilder str = new StringBuilder();
if (node.getTableName() != null) {
str.append(toString(node.getTableName()));
str.append(".");
}
str.append(node.getColumnName());
if (!node.isAscending())
str.append(" DESC");
return str.toString();
}
protected String createAliasNode(CreateAliasNode node) throws StandardException {
StringBuilder str = new StringBuilder(node.statementToString());
if (node.isCreateOrReplace())
str.insert(6, " OR REPLACE");
str.append(' ');
str.append(toString(node.getObjectName()));
switch (node.getAliasType()) {
case PROCEDURE:
case FUNCTION:
str.append(node.getAliasInfo());
if (node.getDefinition() != null) {
str.append(" AS '");
if (node.getDefinition().indexOf('\n') >= 0) {
str.append("$$");
str.append(node.getDefinition());
str.append("$$");
}
else {
str.append(node.getDefinition().replace("'", "''"));
}
str.append('\'');
}
else {
str.append(" EXTERNAL NAME '");
str.append(node.getJavaClassName());
if (node.getMethodName() != null) {
str.append('.');
str.append(node.getMethodName());
}
str.append('\'');
}
break;
}
return str.toString();
}
protected String renameNode(RenameNode node) throws StandardException {
if (node.isAlterTable()) {
return "ALTER TABLE " + toString(node.getObjectName()) +
"RENAME COLUMN " + node.getOldObjectName() +
" TO " + node.getNewObjectName();
}
else if (node.getRenameType() == RenameNode.RenameType.INDEX
|| node.getRenameType() == RenameNode.RenameType.COLUMN) {
if (node.getObjectName() == null) {
return node.statementToString() + " " + node.getOldObjectName() +
" TO " + node.getNewObjectName();
}
else {
return node.statementToString() + " " + toString(node.getObjectName()) +
"." + node.getOldObjectName() +
" TO " + node.getNewObjectName();
}
}
else {
return node.statementToString() + " " + toString(node.getObjectName()) +
" TO " + toString(node.getNewTableName());
}
}
protected String dropIndexNode(DropIndexNode node) throws StandardException {
StringBuilder str = new StringBuilder(node.statementToString());
str.append(" ");
if (node.getObjectName() != null) {
str.append(toString(node.getObjectName()));
str.append(".");
}
str.append(node.getIndexName());
return str.toString();
}
protected String cursorNode(CursorNode node) throws StandardException {
String result = toString(node.getResultSetNode());
if (node.getOrderByList() != null) {
result += " " + toString(node.getOrderByList());
}
if (node.getFetchFirstClause() != null) {
result += " LIMIT " + toString(node.getFetchFirstClause());
}
if (node.getOffsetClause() != null) {
result += " OFFSET " + toString(node.getOffsetClause());
}
return result;
}
protected String selectNode(SelectNode node) throws StandardException {
StringBuilder str = new StringBuilder("SELECT ");
if (node.isDistinct())
str.append("DISTINCT ");
str.append(toString(node.getResultColumns()));
if (!node.getFromList().isEmpty()) {
str.append(" FROM ");
str.append(toString(node.getFromList()));
}
if (node.getWhereClause() != null) {
str.append(" WHERE ");
str.append(toString(node.getWhereClause()));
}
if (node.getGroupByList() != null) {
str.append(" ");
str.append(toString(node.getGroupByList()));
}
if (node.getHavingClause() != null) {
str.append(" HAVING ");
str.append(toString(node.getHavingClause()));
}
if (node.getWindows() != null) {
str.append(" ");
str.append(windowList(node.getWindows())); // Does not have NodeType.
}
return str.toString();
}
protected String insertNode(InsertNode node) throws StandardException {
StringBuilder str = new StringBuilder("INSERT INTO ");
str.append(toString(node.getTargetTableName()));
if (node.getTargetColumnList() != null) {
str.append("(");
str.append(toString(node.getTargetColumnList()));
str.append(")");
}
str.append(" ");
str.append(toString(node.getResultSetNode()));
if (node.getOrderByList() != null) {
str.append(" ");
str.append(toString(node.getOrderByList()));
}
if (node.getReturningList() != null) {
str.append(" RETURNING ");
str.append(toString(node.getReturningList()));
}
return str.toString();
}
protected String updateNode(UpdateNode unode) throws StandardException {
// Cf. Parser's getUpdateNode().
SelectNode snode = (SelectNode)unode.getResultSetNode();
StringBuilder str = new StringBuilder("UPDATE ");
str.append(toString(snode.getFromList().get(0)));
str.append(" SET ");
boolean first = true;
for (ResultColumn col : snode.getResultColumns()) {
if (first)
first = false;
else
str.append(", ");
str.append(toString(col.getReference()));
str.append(" = ");
str.append(maybeParens(col.getExpression()));
}
if (snode.getWhereClause() != null) {
str.append(" WHERE ");
str.append(toString(snode.getWhereClause()));
}
if (unode.getReturningList() != null) {
str.append(" RETURNING ");
str.append(toString(unode.getReturningList()));
}
return str.toString();
}
protected String deleteNode(DeleteNode dnode) throws StandardException {
// Cf. Parser's getDeleteNode().
SelectNode snode = (SelectNode)dnode.getResultSetNode();
StringBuilder str = new StringBuilder("DELETE FROM ");
str.append(toString(snode.getFromList().get(0)));
if (snode.getWhereClause() != null) {
str.append(" WHERE ");
str.append(toString(snode.getWhereClause()));
}
if (dnode.getReturningList() != null) {
str.append(" RETURNING ");
str.append(toString(dnode.getReturningList()));
}
return str.toString();
}
protected String subqueryNode(SubqueryNode node) throws StandardException {
String str = toString(node.getResultSet());
if (node.getOrderByList() != null) {
str = str + " " + toString(node.getOrderByList());
}
str = "(" + str + ")";
switch (node.getSubqueryType()) {
case FROM:
case EXPRESSION:
default:
return str;
case EXISTS:
return "EXISTS " + str;
case NOT_EXISTS:
return "NOT EXISTS " + str;
case IN:
return maybeParens(node.getLeftOperand()) + " IN " + str;
case NOT_IN:
return maybeParens(node.getLeftOperand()) + " NOT IN " + str;
case EQ_ANY:
return maybeParens(node.getLeftOperand()) + " = ANY " + str;
case EQ_ALL:
return maybeParens(node.getLeftOperand()) + " = ALL " + str;
case NE_ANY:
return maybeParens(node.getLeftOperand()) + " <> ANY " + str;
case NE_ALL:
return maybeParens(node.getLeftOperand()) + " <> ALL " + str;
case GT_ANY:
return maybeParens(node.getLeftOperand()) + " > ANY " + str;
case GT_ALL:
return maybeParens(node.getLeftOperand()) + " > ALL " + str;
case GE_ANY:
return maybeParens(node.getLeftOperand()) + " >= ANY " + str;
case GE_ALL:
return maybeParens(node.getLeftOperand()) + " > ANY " + str;
case LT_ANY:
return maybeParens(node.getLeftOperand()) + " < ANY " + str;
case LT_ALL:
return maybeParens(node.getLeftOperand()) + " < ALL " + str;
case LE_ANY:
return maybeParens(node.getLeftOperand()) + " <= ANY " + str;
case LE_ALL:
return maybeParens(node.getLeftOperand()) + " <= ALL " + str;
}
}
protected String rowResultSetNode(RowResultSetNode node) throws StandardException {
return "VALUES(" + toString(node.getResultColumns()) + ")";
}
protected String rowsResultSetNode(RowsResultSetNode node) throws StandardException {
StringBuilder str = new StringBuilder("VALUES");
boolean first = true;
for (RowResultSetNode row : node.getRows()) {
if (first)
first = false;
else
str.append(", ");
str.append("(");
str.append(toString(row.getResultColumns()));
str.append(")");
}
return str.toString();
}
protected String resultColumnList(ResultColumnList node) throws StandardException {
return nodeList(node);
}
protected String resultColumn(ResultColumn node) throws StandardException {
if (node.getReference() != null)
return toString(node.getReference());
String n = node.getName();
if (node.getExpression() == null)
return n;
String x = maybeParens(node.getExpression());
if ((n == null) || n.equals(x))
return x;
else
return x + " AS " + n;
}
protected String allResultColumn(AllResultColumn node) throws StandardException {
if (node.getFullTableName() == null) {
return "*";
} else {
return node.getFullTableName() + ".*";
}
}
protected String fromList(FromList node) throws StandardException {
return nodeList(node);
}
protected String fromBaseTable(FromBaseTable node) throws StandardException {
String tn = toString(node.getOrigTableName());
String n = node.getCorrelationName();
if (n == null)
return tn;
else
return tn + " AS " + n;
}
protected String fromSubquery(FromSubquery node) throws StandardException {
StringBuilder str = new StringBuilder(toString(node.getSubquery()));
if (node.getOrderByList() != null) {
str.append(' ');
str.append(toString(node.getOrderByList()));
}
str.insert(0, '(');
str.append(')');
str.append(" AS ");
str.append(node.getCorrelationName());
if (node.getResultColumns() != null) {
str.append('(');
str.append(toString(node.getResultColumns()));
str.append(')');
}
return str.toString();
}
protected String joinNode(JoinNode node) throws StandardException {
StringBuilder str = new StringBuilder(toString(node.getLeftResultSet()));
JoinNode.JoinType joinType = JoinNode.JoinType.INNER;
if (node instanceof HalfOuterJoinNode)
joinType = ((HalfOuterJoinNode)node).isRightOuterJoin() ?
JoinNode.JoinType.RIGHT_OUTER : JoinNode.JoinType.LEFT_OUTER;
else if (node instanceof FullOuterJoinNode)
joinType = JoinNode.JoinType.FULL_OUTER;
str.append(' ');
if (node.isNaturalJoin())
str.append("NATURAL ");
str.append(JoinNode.joinTypeToString(joinType));
str.append(' ');
str.append(toString(node.getRightResultSet()));
if (node.getJoinClause() != null) {
str.append(" ON ");
str.append(maybeParens(node.getJoinClause()));
}
if (node.getUsingClause() != null) {
str.append(" USING (");
str.append(toString(node.getUsingClause()));
str.append(')');
}
return str.toString();
}
protected String unionNode(UnionNode node) throws StandardException {
return toString(node.getLeftResultSet()) + " UNION " +
toString(node.getRightResultSet());
}
protected String tableName(TableName node) throws StandardException {
return node.getFullTableName();
}
protected String columnReference(ColumnReference node) throws StandardException {
return node.getSQLColumnName();
}
protected String virtualColumnNode(VirtualColumnNode node) throws StandardException {
return node.getSourceColumn().getName();
}
protected String groupByList(GroupByList node) throws StandardException {
return "GROUP BY " + nodeList(node);
}
protected String groupByColumn(GroupByColumn node) throws StandardException {
return maybeParens(node.getColumnExpression());
}
protected String orderByList(OrderByList node) throws StandardException {
return "ORDER BY " + nodeList(node);
}
protected String orderByColumn(OrderByColumn node) throws StandardException {
String result = maybeParens(node.getExpression());
if (!node.isAscending()) {
result += " DESC";
}
if (node.isNullsOrderedLow()) {
result += " NULLS FIRST";
}
return result;
}
protected String partitionByList(PartitionByList node) throws StandardException {
return "PARTITION BY " + nodeList(node);
}
protected String partitionByColumn(PartitionByColumn node) throws StandardException {
return toString(node.getColumnExpression());
}
protected String windowList(WindowList node) throws StandardException {
return "WINDOW " + nodeList(node);
}
protected String windowDefinitionNode(WindowDefinitionNode node)
throws StandardException {
StringBuffer str = new StringBuffer("");
if (!node.isInline()) {
str.append(node.getName());
str.append(" AS ");
}
str.append("(");
if (node.getPartitionByList() != null)
str.append(toString(node.getPartitionByList()));
if (node.getOrderByList() != null) {
if (node.getPartitionByList() != null)
str.append(" ");
str.append(toString(node.getOrderByList()));
}
str.append(")");
return str.toString();
}
protected String windowReferenceNode(WindowReferenceNode node)
throws StandardException {
return node.getName();
}
protected String aggregateWindowFunctionNode(AggregateWindowFunctionNode node)
throws StandardException {
return toString(node.getAggregateFunction()) +
" OVER " + toString(node.getWindow());
}
protected String rowNumberFunctionNode(RowNumberFunctionNode node)
throws StandardException {
return node.getOperator().toUpperCase() + "()" +
" OVER " + toString(node.getWindow());
}
protected String binaryLogicalOperatorNode(BinaryLogicalOperatorNode node)
throws StandardException {
return infixBinary(node);
}
protected String binaryComparisonOperatorNode(BinaryComparisonOperatorNode node)
throws StandardException {
return infixBinary(node);
}
protected String binaryArithmeticOperatorNode(BinaryArithmeticOperatorNode node)
throws StandardException {
return infixBinary(node);
}
protected String binaryBitOperatorNode(BinaryBitOperatorNode node)
throws StandardException {
return infixBinary(node);
}
protected String concatenationOperatorNode(ConcatenationOperatorNode node)
throws StandardException {
return infixBinary(node);
}
protected String leftRightFuncOperatorNode(LeftRightFuncOperatorNode node)
throws StandardException {
return functionBinary(node);
}
protected String simpleStringOperatorNode(SimpleStringOperatorNode node)
throws StandardException {
return functionUnary(node);
}
protected String notNode(NotNode node) throws StandardException {
return prefixUnary(node);
}
protected String isNullNode(IsNullNode node) throws StandardException {
return suffixUnary(node);
}
protected String unaryArithmeticOperatorNode(UnaryArithmeticOperatorNode node)
throws StandardException {
return functionUnary(node);
}
protected String unaryPrefixOperatorNode(UnaryArithmeticOperatorNode node)
throws StandardException {
return prefixUnary(node);
}
protected String unaryBitOperatorNode(UnaryBitOperatorNode node)
throws StandardException {
return prefixUnary(node);
}
protected String extractOperatorNode(ExtractOperatorNode node)
throws StandardException {
return node.getOperator().substring("EXTRACT ".length()).toUpperCase() + "(" +
toString(node.getOperand()) + ")";
}
protected String unaryDateTimestampOperatorNode(UnaryDateTimestampOperatorNode node)
throws StandardException {
return functionUnary(node);
}
protected String timestampOperatorNode(TimestampOperatorNode node)
throws StandardException {
return functionBinary(node);
}
protected String lengthOperatorNode(LengthOperatorNode node)
throws StandardException {
return functionUnary(node);
}
protected String octetLengthOperatorNode(OctetLengthOperatorNode node)
throws StandardException {
return functionUnary(node);
}
protected String isNode(IsNode node) throws StandardException {
StringBuilder str = new StringBuilder(maybeParens(node.getLeftOperand()));
str.append(" IS ");
if (node.isNegated())
str.append("NOT ");
ValueNode rightOperand = node.getRightOperand();
if (rightOperand instanceof BooleanConstantNode) {
Boolean value = (Boolean)((BooleanConstantNode)rightOperand).getValue();
if (value == null)
str.append("UNKNOWN");
else
str.append(value.toString().toUpperCase());
}
else
str.append(maybeParens(rightOperand));
return str.toString();
}
protected String aggregateNode(AggregateNode node) throws StandardException {
if (node.getOperand() == null)
return node.getAggregateName();
else
return node.getAggregateName() + "(" + toString(node.getOperand()) + ")";
}
protected String likeEscapeOperatorNode(LikeEscapeOperatorNode node)
throws StandardException {
String like = maybeParens(node.getReceiver()) +
" " + node.getOperator().toUpperCase() + " " +
maybeParens(node.getLeftOperand());
if (node.getRightOperand() != null)
like += " ESCAPE " + maybeParens(node.getRightOperand());
return like;
}
protected String ternaryOperatorNode(TernaryOperatorNode node)
throws StandardException {
StringBuilder str = new StringBuilder(node.getOperator().toUpperCase());
str.append("(");
str.append(toString(node.getReceiver()));
str.append(", ");
str.append(toString(node.getLeftOperand()));
if (node.getRightOperand() != null) {
str.append(", ");
str.append(toString(node.getRightOperand()));
}
return str.toString();
}
protected String timestampFunctionNode(TernaryOperatorNode node)
throws StandardException {
String interval = toString(node.getReceiver());
switch ((Integer)((ConstantNode)node.getReceiver()).getValue()) {
case TernaryOperatorNode.YEAR_INTERVAL:
interval = "YEAR";
break;
case TernaryOperatorNode.QUARTER_INTERVAL:
interval = "QUARTER";
break;
case TernaryOperatorNode.MONTH_INTERVAL:
interval = "MONTH";
break;
case TernaryOperatorNode.WEEK_INTERVAL:
interval = "WEEK";
break;
case TernaryOperatorNode.DAY_INTERVAL:
interval = "DAY";
break;
case TernaryOperatorNode.HOUR_INTERVAL:
interval = "HOUR";
break;
case TernaryOperatorNode.MINUTE_INTERVAL:
interval = "MINUTE";
break;
case TernaryOperatorNode.SECOND_INTERVAL:
interval = "SECOND";
break;
case TernaryOperatorNode.FRAC_SECOND_INTERVAL:
interval = "MICROSECOND>";
break;
}
return node.getOperator().toUpperCase() + "(" +
interval + ", " +
toString(node.getLeftOperand()) + ", " +
toString(node.getRightOperand()) + ")";
}
protected String trimOperatorNode(TrimOperatorNode node)
throws StandardException {
if ((node.getRightOperand() instanceof ConstantNode) &&
" ".equals(((ConstantNode)node.getRightOperand()).getValue())) {
return node.getOperator().toUpperCase() + "(" +
toString(node.getLeftOperand()) + ")";
}
else {
StringBuilder str = new StringBuilder("TRIM(");
if ("LTRIM".equals(node.getOperator()))
str.append("LEADING");
else if ("RTRIM".equals(node.getOperator()))
str.append("TRAILING");
else
str.append("BOTH");
str.append(" ");
str.append(toString(node.getRightOperand()));
str.append(" FROM ");
str.append(toString(node.getLeftOperand()));
return str.toString();
}
}
protected String inListOperatorNode(InListOperatorNode node) throws StandardException {
return maybeParens(node.getLeftOperand()) +
" " + (node.isNegated() ? "NOT IN" : "IN") +
" (" + toString(node.getRightOperandList()) + ")";
}
protected String valueNodeList(ValueNodeList node) throws StandardException {
return nodeList(node, true);
}
protected String betweenOperatorNode(BetweenOperatorNode node)
throws StandardException {
return maybeParens(node.getLeftOperand()) +
" BETWEEN " + maybeParens(node.getRightOperandList().get(0)) +
" AND " + maybeParens(node.getRightOperandList().get(1));
}
protected String conditionalNode(ConditionalNode node) throws StandardException {
StringBuilder str = new StringBuilder("CASE");
while (true) {
str.append(" WHEN ");
str.append(maybeParens(node.getTestCondition()));
str.append(" THEN ");
str.append(maybeParens(node.getThenNode()));
ValueNode elseNode = node.getElseNode();
if (elseNode instanceof ConditionalNode)
node = (ConditionalNode)elseNode;
else {
str.append(" ELSE ");
str.append(maybeParens(elseNode));
break;
}
}
str.append(" END");
return str.toString();
}
protected String simpleCaseNode(SimpleCaseNode node) throws StandardException {
StringBuilder str = new StringBuilder("CASE ");
str.append(maybeParens(node.getOperand()));
for (int i = 0; i < node.getNumberOfCases(); i++) {
str.append(" WHEN ");
str.append(maybeParens(node.getCaseOperand(i)));
str.append(" THEN ");
str.append(maybeParens(node.getResultValue(i)));
}
if (node.getElseValue() != null) {
str.append(" ELSE ");
str.append(maybeParens(node.getElseValue()));
}
str.append(" END");
return str.toString();
}
protected String coalesceFunctionNode(CoalesceFunctionNode node)
throws StandardException {
return functionCall(node.getFunctionName(),
node.getArgumentsList());
}
protected String constantNode(ConstantNode node) throws StandardException {
Object value = node.getValue();
if (value == null)
return "NULL";
else if (value instanceof String)
return "'" + ((String)value).replace("'", "''") + "'";
else if (value instanceof byte[])
return hexConstant((byte[])value);
else if (value instanceof Double)
return String.format("%e", value);
else if (value instanceof Boolean)
return value.toString().toUpperCase();
else
return value.toString();
}
protected String prefixUnary(UnaryOperatorNode node) throws StandardException {
return node.getOperator().toUpperCase() + " " +
maybeParens(node.getOperand());
}
protected String suffixUnary(UnaryOperatorNode node) throws StandardException {
return maybeParens(node.getOperand()) + " " +
node.getOperator().toUpperCase();
}
protected String functionUnary(UnaryOperatorNode node) throws StandardException {
return node.getOperator().toUpperCase() + "(" +
toString(node.getOperand()) + ")";
}
protected String infixBinary(BinaryOperatorNode node) throws StandardException {
return maybeParens(node.getLeftOperand()) +
" " + node.getOperator().toUpperCase() + " " +
maybeParens(node.getRightOperand());
}
protected String functionBinary(BinaryOperatorNode node) throws StandardException {
return node.getOperator().toUpperCase() + "(" +
toString(node.getLeftOperand()) + ", " +
toString(node.getRightOperand()) + ")";
}
protected String functionCall(String functionName, ValueNodeList args)
throws StandardException {
return functionName + "(" + nodeList(args, true) + ")";
}
protected String nodeList(QueryTreeNodeList<? extends QueryTreeNode> nl)
throws StandardException {
return nodeList(nl, false);
}
protected String nodeList(QueryTreeNodeList<? extends QueryTreeNode> nl, boolean expr)
throws StandardException {
StringBuilder str = new StringBuilder();
boolean first = true;
for (QueryTreeNode node : nl) {
if (first)
first = false;
else
str.append(", ");
str.append(expr ? maybeParens(node) : toString(node));
}
return str.toString();
}
protected String maybeParens(QueryTreeNode node) throws StandardException {
String str = toString(node);
if (node instanceof ConstantNode)
return str;
else if (str.indexOf(' ') < 0)
return str;
else
return "(" + str + ")";
}
protected String hexConstant(byte[] value) {
StringBuilder str = new StringBuilder("X'");
for (byte b : value) {
str.append(Integer.toString((int)b & 0xFF, 16).toUpperCase());
}
str.append("'");
return str.toString();
}
protected String parameterNode(ParameterNode node) throws StandardException {
return "$" + (node.getParameterNumber() + 1);
}
protected String currentDatetimeOperatorNode(CurrentDatetimeOperatorNode node)
throws StandardException {
switch (node.getField()) {
case DATE:
return "CURRENT_DATE";
case TIME:
return "CURRENT_TIME";
case TIMESTAMP:
return "CURRENT_TIMESTAMP";
default:
return "**UNKNOWN(" + node.getField() +")**";
}
}
protected String castNode(CastNode node) throws StandardException {
return "CAST(" + toString(node.getCastOperand()) +
" AS " + node.getType().toString() + ")";
}
protected String explicitCollateNode(ExplicitCollateNode node)
throws StandardException {
return maybeParens(node.getOperand()) +
" COLLATE " + node.getCollation();
}
protected String nextSequenceNode(NextSequenceNode node)
throws StandardException {
return "NEXT VALUE FOR " + toString(node.getSequenceName ());
}
protected String currentSequenceNode(CurrentSequenceNode node)
throws StandardException {
return "CURRENT VALUE FOR " + toString(node.getSequenceName ());
}
protected String javaToSQLValueNode(JavaToSQLValueNode node)
throws StandardException {
return toString(node.getJavaValueNode());
}
protected String sqlToJavaValueNode(SQLToJavaValueNode node)
throws StandardException {
return toString(node.getSQLValueNode());
}
protected String staticMethodCallNode(StaticMethodCallNode node)
throws StandardException {
StringBuilder str = new StringBuilder();
if (node.getProcedureName() != null)
str.append(toString(node.getProcedureName()));
else
str.append(node.getMethodName());
str.append("(");
JavaValueNode[] params = node.getMethodParameters();
for (int i = 0; i < params.length; i++) {
if (i > 0) str.append(", ");
str.append(maybeParens(params[i]));
}
str.append(")");
return str.toString();
}
protected String callStatementNode(CallStatementNode node) throws StandardException {
return "CALL " + javaToSQLValueNode(node.methodCall());
}
protected String qualifiedDDLNode(DDLStatementNode node) throws StandardException {
return node.statementToString() + " " + node.getObjectName();
}
protected String explainStatementNode(ExplainStatementNode node)
throws StandardException {
String detail;
switch (node.getDetail()) {
case BRIEF:
detail = "BRIEF ";
break;
case VERBOSE:
detail = "VERBOSE ";
break;
case NORMAL:
default:
detail = "";
break;
}
return "EXPLAIN " + detail + toString(node.getStatement());
}
protected String transactionControlNode(TransactionControlNode node)
throws StandardException {
return node.statementToString();
}
protected String setTransactionIsolationNode(SetTransactionIsolationNode node)
throws StandardException {
return node.statementToString() + " " + node.getIsolationLevel().getSyntax();
}
protected String setTransactionAccessNode(SetTransactionAccessNode node)
throws StandardException {
return node.statementToString() + " " + node.getAccessMode().getSyntax();
}
protected String setConfigurationNode(SetConfigurationNode node)
throws StandardException {
return node.statementToString() + " = '" + node.getValue() + "'";
}
protected String rowCtorNode(RowConstructorNode row) throws StandardException
{
ValueNodeList list = row.getNodeList();
switch(list.size())
{
case 0:
return "EMPTY";
case 1:
QueryTreeNode node = list.get(0);
if (!(node instanceof RowConstructorNode))
return toString(node);
}
StringBuilder bd = new StringBuilder();
for (QueryTreeNode node : list )
{
doPrint(node, bd);
bd.append(", ");
}
return bd.substring(0, bd.length() -2); // delete the last (<COMMA> <SPACE>)
}
protected String declareStatementNode(DeclareStatementNode node)
throws StandardException {
return "DECLARE " + node.getName() + " CURSOR FOR " +
toString(node.getStatement());
}
protected String fetchStatementNode(FetchStatementNode node)
throws StandardException {
return "FETCH " +
((node.getCount() < 0) ? "ALL" : Integer.toString(node.getCount())) +
" FROM " + node.getName();
}
protected String closeStatementNode(CloseStatementNode node)
throws StandardException {
return "CLOSE " + node.getName();
}
protected String prepareStatementNode(PrepareStatementNode node)
throws StandardException {
return "PREPARE " + node.getName() + " AS " +
toString(node.getStatement());
}
protected String executeStatementNode(ExecuteStatementNode node)
throws StandardException {
return "EXECUTE " + node.getName() +
"(" + nodeList(node.getParameterList(), true) + ")";
}
protected String deallocateStatementNode(DeallocateStatementNode node)
throws StandardException {
return "DEALLOCATE " + node.getName();
}
protected String copyStatementNode(CopyStatementNode node)
throws StandardException {
StringBuilder str = new StringBuilder("COPY ");
if (node.getSubquery() != null) {
str.append("(");
str.append(toString(node.getSubquery()));
str.append(")");
}
else {
str.append(node.getTableName());
if (node.getColumnList() != null) {
str.append("(");
str.append(toString(node.getColumnList()));
str.append(")");
}
}
switch (node.getMode()) {
case FROM_TABLE:
case FROM_SUBQUERY:
str.append(" TO ");
break;
case TO_TABLE:
str.append(" FROM ");
break;
}
if (node.getFilename() != null) {
str.append("'");
str.append(node.getFilename());
str.append("'");
}
else if (node.getMode() == CopyStatementNode.Mode.TO_TABLE) {
str.append("STDIN");
}
else {
str.append("STDOUT");
}
boolean options = false;
if (node.getFormat() != null) {
options = copyOption(str, "FORMAT", node.getFormat().name(), options);
}
if (node.getDelimiter() != null) {
options = copyOptionString(str, "DELIMITER", node.getDelimiter(), options);
}
if (node.getNullString() != null) {
options = copyOptionString(str, "NULL", node.getNullString(), options);
}
if (node.isHeader()) {
options = copyOption(str, "HEADER", "TRUE", options);
}
if (node.getQuote() != null) {
options = copyOptionString(str, "QUOTE", node.getQuote(), options);
}
if (node.getEscape() != null) {
options = copyOptionString(str, "ESCAPE", node.getEscape(), options);
}
if (node.getEncoding() != null) {
options = copyOptionString(str, "ENCODING", node.getEncoding(), options);
}
if (node.getCommitFrequency() != 0) {
options = copyOption(str, "COMMIT", node.getCommitFrequency() + " ROWS", options);
}
if (options) {
str.append(")");
}
return str.toString();
}
protected boolean copyOptionString(StringBuilder str, String keyword, String value, boolean options) {
return copyOption(str, keyword, "'" + value + "'", options);
}
protected boolean copyOption(StringBuilder str, String keyword, String value, boolean options) {
if (!options) {
str.append(" WITH (");
}
else {
str.append(", ");
}
str.append(keyword);
str.append(" " );
str.append(value);
return true;
}
protected void doPrint(QueryTreeNode node, StringBuilder bd) throws StandardException
{
if (node instanceof RowConstructorNode)
bd.append(rowCtorNode((RowConstructorNode)node));
else
bd.append(toString(node));
}
protected String groupConcat(GroupConcatNode node) throws StandardException
{
StringBuilder ret = new StringBuilder("GROUP_CONCAT(");
ret.append(node.getOperand());
OrderByList orderBy = node.getOrderBy();
if (orderBy != null)
ret.append(this.toString(orderBy));
// i
ret.append("SEPARATOR \'").append(node.getSeparator()).append("\')");
return ret.toString();
}
}