package com.chenyang.druid.sql.dialect.dm.visitor;

import com.chenyang.druid.DbType;
import com.chenyang.druid.sql.ast.AutoIncrementType;
import com.chenyang.druid.sql.ast.SQLArgument;
import com.chenyang.druid.sql.ast.SQLCommentHint;
import com.chenyang.druid.sql.ast.SQLDataType;
import com.chenyang.druid.sql.ast.SQLExpr;
import com.chenyang.druid.sql.ast.SQLHint;
import com.chenyang.druid.sql.ast.SQLKeep;
import com.chenyang.druid.sql.ast.SQLLimit;
import com.chenyang.druid.sql.ast.SQLName;
import com.chenyang.druid.sql.ast.SQLObject;
import com.chenyang.druid.sql.ast.SQLOrderBy;
import com.chenyang.druid.sql.ast.SQLOver;
import com.chenyang.druid.sql.ast.SQLParameter;
import com.chenyang.druid.sql.ast.SQLPartitionBy;
import com.chenyang.druid.sql.ast.SQLStatement;
import com.chenyang.druid.sql.ast.expr.SQLAggregateExpr;
import com.chenyang.druid.sql.ast.expr.SQLAggregateOption;
import com.chenyang.druid.sql.ast.expr.SQLBetweenExpr;
import com.chenyang.druid.sql.ast.expr.SQLBooleanExpr;
import com.chenyang.druid.sql.ast.expr.SQLCharExpr;
import com.chenyang.druid.sql.ast.expr.SQLDateExpr;
import com.chenyang.druid.sql.ast.expr.SQLIdentifierExpr;
import com.chenyang.druid.sql.ast.expr.SQLIntegerExpr;
import com.chenyang.druid.sql.ast.expr.SQLListExpr;
import com.chenyang.druid.sql.ast.expr.SQLLiteralExpr;
import com.chenyang.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.chenyang.druid.sql.ast.expr.SQLNCharExpr;
import com.chenyang.druid.sql.ast.expr.SQLNullExpr;
import com.chenyang.druid.sql.ast.expr.SQLNumberExpr;
import com.chenyang.druid.sql.ast.expr.SQLQueryExpr;
import com.chenyang.druid.sql.ast.expr.SQLTimeExpr;
import com.chenyang.druid.sql.ast.expr.SQLTimestampExpr;
import com.chenyang.druid.sql.ast.expr.SQLVariantRefExpr;
import com.chenyang.druid.sql.ast.statement.SQLAlterDatabaseStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableDisableTriggers;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableEnableTriggers;
import com.chenyang.druid.sql.ast.statement.SQLAssignItem;
import com.chenyang.druid.sql.ast.statement.SQLBlockStatement;
import com.chenyang.druid.sql.ast.statement.SQLColumnCheck;
import com.chenyang.druid.sql.ast.statement.SQLColumnConstraint;
import com.chenyang.druid.sql.ast.statement.SQLColumnDefinition;
import com.chenyang.druid.sql.ast.statement.SQLCreateFunctionStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateProcedureStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateTriggerStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropIndexStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropPackageStatement;
import com.chenyang.druid.sql.ast.statement.SQLExprTableSource;
import com.chenyang.druid.sql.ast.statement.SQLForeignKeyConstraint;
import com.chenyang.druid.sql.ast.statement.SQLForeignKeyImpl;
import com.chenyang.druid.sql.ast.statement.SQLIfStatement;
import com.chenyang.druid.sql.ast.statement.SQLInsertStatement;
import com.chenyang.druid.sql.ast.statement.SQLPrimaryKey;
import com.chenyang.druid.sql.ast.statement.SQLSelect;
import com.chenyang.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.chenyang.druid.sql.ast.statement.SQLSelectQuery;
import com.chenyang.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.chenyang.druid.sql.ast.statement.SQLSelectStatement;
import com.chenyang.druid.sql.ast.statement.SQLSetStatement;
import com.chenyang.druid.sql.ast.statement.SQLSubqueryTableSource;
import com.chenyang.druid.sql.ast.statement.SQLUnionQuery;
import com.chenyang.druid.sql.ast.statement.SQLUpdateStatement;
import com.chenyang.druid.sql.ast.statement.SQLWhileStatement;
import com.chenyang.druid.sql.ast.statement.SQLWithSubqueryClause;
import com.chenyang.druid.sql.dialect.dm.ast.clause.DmPartitionExtensionClause;
import com.chenyang.druid.sql.dialect.dm.ast.clause.DmReturningClause;
import com.chenyang.druid.sql.dialect.dm.ast.clause.DmSampleClause;
import com.chenyang.druid.sql.dialect.dm.ast.clause.DmStorageClause;
import com.chenyang.druid.sql.dialect.dm.ast.expr.DMIntervalExpr;
import com.chenyang.druid.sql.dialect.dm.ast.expr.DmAnalytic;
import com.chenyang.druid.sql.dialect.dm.ast.expr.DmAnalyticWindowing;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DMIndexTablespacleConstraint;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DMSQLAlterTableRebuildColumns;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterDatabaseAddLogfile;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterDatabaseArchivelog;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterDatabaseMoveDatafile;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterDatabaseRenameLogfile;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterDatabaseResizeLogfile;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterDatabaseStatus;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterIndexStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterPackageCompile;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableAddConstraint;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableAddIdentity;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableAddPartition;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableAlterColumn;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableCounter;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableDefaultDirectory;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableDropIdentity;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableDropPartition;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableEnableUsingLongRow;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableExchangePartition;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableLocation;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableMergePartition;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableModify;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableModifyConstraint;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableModifyDiskspace;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableModifyPartition;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableMovePartition;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableRenamePartition;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableRowMovement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableSetPartitionTemplate;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableSplitPartition;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTableTruncateSubpartition;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterTriggerStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmAlterViewStatment;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmConstraint;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmContinueStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmCreateIndexStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmCreatePackageStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmCreateSchemaStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmCreateSynonymStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmCreateTableStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmCreateTriggerStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmDataTypeIntervalYear;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmDropUserStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmExceptionStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmExecuteImmediateStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmExitStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmForeignKeyImpl;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmGotoStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmInsertStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmLabelStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmLockTableStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmLogfile;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmMultiInsertStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmPrintStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmRaiseStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmSQLColumnPrimaryKey;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmSQLColumnReference;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmSQLPrimaryKey;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmSQLTruncateStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmSQLUniqueKey;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmSelectPivot;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmSelectQueryBlock;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmSelectSubqueryTableSource;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmSelectTableReference;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmSelectUnPivot;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmSetTransactionStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.DmUpdateStatement;
import com.chenyang.druid.sql.dialect.dm.ast.stmt.SQLNotVisibleConstraint;
import com.chenyang.druid.sql.dialect.oracle.ast.clause.PartitionExtensionClause;
import com.chenyang.druid.sql.dialect.oracle.parser.OracleFunctionDataType;
import com.chenyang.druid.sql.dialect.oracle.parser.OracleProcedureDataType;
import com.chenyang.druid.sql.visitor.ExportParameterVisitorUtils;
import com.chenyang.druid.sql.visitor.SQLASTOutputVisitor;
import com.chenyang.druid.util.FnvHash;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public class DmOutputVisitor extends SQLASTOutputVisitor implements DmASTVisitor {
   private final boolean printPostSemi;

   public DmOutputVisitor(Appendable appender) {
      this(appender, true);
   }

   public DmOutputVisitor(Appendable appender, boolean printPostSemi) {
      super(appender);
      this.dbType = DbType.dm;
      this.printPostSemi = printPostSemi;
   }

   public boolean isPrintPostSemi() {
      return this.printPostSemi;
   }

   public boolean visit(DMIntervalExpr x) {
      SQLExpr value = x.getValue();
      if (!(value instanceof SQLLiteralExpr) && !(value instanceof SQLVariantRefExpr)) {
         this.print('(');
         value.accept(this);
         this.print0(") ");
      } else {
         this.print0(this.ucase ? "INTERVAL " : "interval ");
         value.accept(this);
         this.print(' ');
      }

      this.print0(x.getType().name());
      if (x.getPrecision() != null) {
         this.print('(');
         this.printExpr(x.getPrecision(), this.parameterized);
         if (x.getFactionalSecondsPrecision() != null) {
            this.print0(", ");
            this.print(x.getFactionalSecondsPrecision());
         }

         this.print(')');
      }

      if (x.getToType() != null) {
         this.print0(this.ucase ? " TO " : " to ");
         this.print0(x.getToType().name());
         if (x.getToFactionalSecondsPrecision() != null) {
            this.print('(');
            this.printExpr(x.getToFactionalSecondsPrecision(), this.parameterized);
            this.print(')');
         }
      }

      return false;
   }

   public boolean visit(DmReturningClause x) {
      this.println();
      if (x.getReturnType() == DmReturningClause.ReturnType.RETURN) {
         this.print0(this.ucase ? "RETURN " : "return ");
      } else {
         this.print0(this.ucase ? "RETURNING " : "returning ");
      }

      this.printAndAccept(x.getItems(), ", ");
      if (x.getIntoType() == DmReturningClause.IntoType.INTO) {
         this.print0(this.ucase ? " INTO " : " into ");
      } else {
         this.print0(this.ucase ? " BULK COLLECT INTO " : " bulk collect into ");
      }

      this.printAndAccept(x.getValues(), ", ");
      return false;
   }

   public boolean visit(DmInsertStatement x) {
      this.print0(this.ucase ? "INSERT " : "insert ");
      if (x.getHints().size() > 0) {
         this.printAndAccept(x.getHints(), ", ");
         this.print(' ');
      }

      this.print0(this.ucase ? "INTO " : "into ");
      if (x.getSelect() != null) {
         this.print("(");
         x.getSelect().accept(this);
         this.print(") ");
         if (x.isSelectAsToken()) {
            this.print(this.ucase ? "AS " : "as ");
         }

         if (x.getSelectAlias() != null) {
            this.print(x.getSelectAlias());
         }
      }

      if (x.getTableSource() != null) {
         x.getTableSource().accept(this);
      }

      this.printInsertColumns(x.getColumns());
      if (x.getValues() != null) {
         List<SQLInsertStatement.ValuesClause> valuesList = x.getValuesList();
         if (!valuesList.isEmpty()) {
            this.println();
            this.printValuesList(valuesList);
         }
      } else if (x.getQuery() != null) {
         this.println();
         x.getQuery().accept(this);
      }

      if (x.getReturning() != null) {
         this.println();
         x.getReturning().accept(this);
      }

      if (x.getErrorLogging() != null) {
         this.println();
         x.getErrorLogging().accept(this);
      }

      return false;
   }

   protected void printValuesList(List<SQLInsertStatement.ValuesClause> valuesList) {
      if (this.parameterized && valuesList.size() > 1 && !this.parameterizedQuesUnMergeValuesList) {
         this.print0(this.ucase ? "VALUES " : "values ");
         ++this.indentCount;
         boolean allConst = true;
         if (valuesList.size() > 1) {
            for(int index = 0; index < valuesList.size(); ++index) {
               List<SQLExpr> values = ((SQLInsertStatement.ValuesClause)valuesList.get(index)).getValues();

               for(int i = 0; i < values.size(); ++i) {
                  SQLExpr value = (SQLExpr)values.get(i);
                  if (!(value instanceof SQLLiteralExpr) && !(value instanceof SQLVariantRefExpr) && (!(value instanceof SQLMethodInvokeExpr) || ((SQLMethodInvokeExpr)value).getArguments().size() != 0)) {
                     allConst = false;
                     break;
                  }
               }

               if (!allConst) {
                  break;
               }
            }
         }

         if (!allConst) {
            for(int index = 0; index < valuesList.size(); ++index) {
               if (index != 0) {
                  this.print(',');
                  this.println();
               }

               this.visit((SQLInsertStatement.ValuesClause)valuesList.get(index), this.parameters);
            }
         } else if (valuesList.size() > 1 && this.parameters != null) {
            SQLInsertStatement.ValuesClause first = (SQLInsertStatement.ValuesClause)valuesList.get(0);
            List<Object> valuesParameters = new ArrayList(first.getValues().size());
            this.visit(first, valuesParameters);
            this.parameters.add(valuesParameters);

            for(int index = 1; index < valuesList.size(); ++index) {
               List<SQLExpr> values = ((SQLInsertStatement.ValuesClause)valuesList.get(index)).getValues();
               List<Object> var16 = new ArrayList(values.size());
               int i = 0;

               for(int size = values.size(); i < size; ++i) {
                  SQLExpr expr = (SQLExpr)values.get(i);
                  if (!(expr instanceof SQLIntegerExpr) && !(expr instanceof SQLBooleanExpr) && !(expr instanceof SQLNumberExpr) && !(expr instanceof SQLCharExpr) && !(expr instanceof SQLNCharExpr) && !(expr instanceof SQLTimestampExpr) && !(expr instanceof SQLDateExpr) && !(expr instanceof SQLTimeExpr)) {
                     if (expr instanceof SQLNullExpr) {
                        this.incrementReplaceCunt();
                        var16.add(null);
                     }
                  } else {
                     this.incrementReplaceCunt();
                     ExportParameterVisitorUtils.exportParameter(var16, (SQLExpr)expr);
                  }
               }

               this.parameters.add(var16);
            }

            this.incrementReplaceCunt();
         } else {
            if (valuesList.size() > 1) {
               this.incrementReplaceCunt();
            }

            this.visit((SQLInsertStatement.ValuesClause)valuesList.get(0), this.parameters);
         }

         --this.indentCount;
      } else {
         this.print0(this.ucase ? "VALUES " : "values ");
         if (valuesList.size() > 1) {
            ++this.indentCount;
         }

         int i = 0;

         for(int size = valuesList.size(); i < size; ++i) {
            if (i != 0) {
               this.print(',');
               this.println();
            }

            SQLInsertStatement.ValuesClause item = (SQLInsertStatement.ValuesClause)valuesList.get(i);
            this.visit(item, this.parameters);
         }

         if (valuesList.size() > 1) {
            --this.indentCount;
         }

      }
   }

   public boolean visit(DmMultiInsertStatement.InsertIntoClause x) {
      this.print0(this.ucase ? "INTO " : "into ");
      x.getTableSource().accept(this);
      if (x.getColumns().size() > 0) {
         ++this.indentCount;
         this.println();
         this.print('(');
         int i = 0;

         for(int size = x.getColumns().size(); i < size; ++i) {
            if (i != 0) {
               if (i % 5 == 0) {
                  this.println();
               }

               this.print0(", ");
            }

            ((SQLExpr)x.getColumns().get(i)).accept(this);
         }

         this.print(')');
         --this.indentCount;
      }

      if (x.getValues() != null) {
         this.println();
         this.print0(this.ucase ? "VALUES " : "values ");
         x.getValues().accept(this);
      } else if (x.getQuery() != null) {
         this.println();
         x.getQuery().accept(this);
      }

      return false;
   }

   public boolean visit(DmMultiInsertStatement x) {
      this.print0(this.ucase ? "INSERT " : "insert ");
      if (x.getHints().size() > 0) {
         this.printHints(x.getHints());
      }

      if (x.getOption() != null) {
         this.print0(x.getOption().name());
         this.print(' ');
      }

      int i = 0;

      for(int size = x.getEntries().size(); i < size; ++i) {
         ++this.indentCount;
         this.println();
         ((DmMultiInsertStatement.Entry)x.getEntries().get(i)).accept(this);
         --this.indentCount;
      }

      this.println();
      x.getSubQuery().accept(this);
      return false;
   }

   private void printHints(List<SQLHint> hints) {
      if (hints.size() > 0) {
         this.print0("/*+ ");
         this.printAndAccept(hints, ", ");
         this.print0(" */");
      }

   }

   public boolean visit(DmMultiInsertStatement.ConditionalInsertClause x) {
      int i = 0;

      for(int size = x.getItems().size(); i < size; ++i) {
         if (i != 0) {
            this.println();
         }

         DmMultiInsertStatement.ConditionalInsertClauseItem item = (DmMultiInsertStatement.ConditionalInsertClauseItem)x.getItems().get(i);
         item.accept(this);
      }

      if (x.getElseItem() != null) {
         this.println();
         this.print0(this.ucase ? "ELSE" : "else");
         ++this.indentCount;
         this.println();
         x.getElseItem().accept(this);
         --this.indentCount;
      }

      return false;
   }

   public boolean visit(DmMultiInsertStatement.ConditionalInsertClauseItem x) {
      this.print0(this.ucase ? "WHEN " : "when ");
      x.getWhen().accept(this);
      this.print0(this.ucase ? " THEN" : " then");
      ++this.indentCount;
      this.println();
      x.getThen().accept(this);
      --this.indentCount;
      return false;
   }

   public boolean visit(SQLSelectQueryBlock select) {
      return select instanceof DmSelectQueryBlock ? this.visit((DmSelectQueryBlock)select) : super.visit(select);
   }

   public boolean visit(DmSelectQueryBlock x) {
      if (this.isPrettyFormat() && x.hasBeforeComment()) {
         this.printlnComments(x.getBeforeCommentsDirect());
      }

      this.print0(this.ucase ? "SELECT " : "select ");
      if (x.getHintsSize() > 0) {
         this.printAndAccept(x.getHints(), ", ");
         this.print(' ');
      }

      if (1 == x.getDistionOption()) {
         this.print0(this.ucase ? "ALL " : "all ");
      } else if (2 == x.getDistionOption()) {
         this.print0(this.ucase ? "DISTINCT " : "distinct ");
      } else if (3 == x.getDistionOption()) {
         this.print0(this.ucase ? "UNIQUE " : "unique ");
      }

      if (x.getTop() != null) {
         SQLLimit top = x.getTop();
         SQLExpr rowCount = top.getRowCount();
         SQLExpr offset = top.getOffset();
         if (offset != null) {
            this.print0(this.ucase ? "TOP " + offset.toString() + "," + rowCount.toString() + " " : "top " + offset.toString() + "," + rowCount.toString() + " ");
         } else {
            this.print0(this.ucase ? "TOP " + rowCount.toString() + " " : "TOP " + rowCount.toString() + " ");
         }
      }

      if (x.isPercent()) {
         this.print0(this.ucase ? "PERCENT " : "percent ");
      }

      if (x.isWithties()) {
         this.print0(this.ucase ? "WITH TIES " : "with ties ");
      }

      this.printSelectList(x.getSelectList());
      if (x.getInto() != null) {
         this.println();
         this.print0(this.ucase ? "INTO " : "into ");
         x.getInto().accept(this);
      }

      if (x.getIntoVariable() != null) {
         this.println();
         this.print0(this.ucase ? "INTO " : "into ");
         if (x.getIntoVariable() instanceof SQLListExpr) {
            this.printAndAccept(((SQLListExpr)x.getIntoVariable()).getItems(), ",");
         } else {
            x.getIntoVariable().accept(this);
         }
      }

      this.println();
      this.print0(this.ucase ? "FROM " : "from ");
      if (x.getFrom() == null) {
         this.print0(this.ucase ? "DUAL" : "dual");
      } else {
         x.getFrom().accept(this);
      }

      if (x.getWhere() != null) {
         this.println();
         this.print0(this.ucase ? "WHERE " : "where ");
         x.getWhere().accept(this);
      }

      this.printHierarchical(x);
      if (x.getGroupBy() != null) {
         this.println();
         x.getGroupBy().accept(this);
      }

      SQLOrderBy orderBy = x.getOrderBy();
      if (orderBy != null) {
         this.println();
         orderBy.accept(this);
      }

      this.printFetchFirst(x);
      if (x.isForUpdate()) {
         this.println();
         this.print0(this.ucase ? "FOR UPDATE" : "for update");
         if (x.getForUpdateOfSize() > 0) {
            this.print('(');
            this.printAndAccept(x.getForUpdateOf(), ", ");
            this.print(')');
         }

         if (x.isNoWait()) {
            this.print0(this.ucase ? " NOWAIT" : " nowait");
         } else if (x.isSkipLocked()) {
            this.print0(this.ucase ? " SKIP LOCKED" : " skip locked");
         } else if (x.getWaitTime() != null) {
            this.print0(this.ucase ? " WAIT " : " wait ");
            x.getWaitTime().accept(this);
         }
      }

      return false;
   }

   public void endVisit(DmSelectQueryBlock x) {
   }

   public boolean visit(SQLSelectStatement stmt) {
      List<SQLCommentHint> headHints = stmt.getHeadHintsDirect();
      if (headHints != null) {
         for(SQLCommentHint hint : headHints) {
            this.visit((SQLCommentHint)hint);
            this.println();
         }
      }

      SQLSelect select = stmt.getSelect();
      if (select != null) {
         this.visit(select);
      }

      return false;
   }

   public boolean visit(SQLSelect x) {
      SQLHint headHint = x.getHeadHint();
      if (headHint != null) {
         headHint.accept(this);
         this.println();
      }

      SQLWithSubqueryClause withSubQuery = x.getWithSubQuery();
      if (withSubQuery != null) {
         withSubQuery.accept(this);
         this.println();
      }

      this.printQuery(x.getQuery());
      SQLOrderBy orderBy = x.getOrderBy();
      if (orderBy != null) {
         this.println();
         orderBy.accept(this);
      }

      SQLLimit limit = x.getLimit();
      if (limit != null) {
         this.println();
         limit.accept(this);
      }

      if (x.isForUpdate()) {
         this.println();
         this.print0(this.ucase ? "FOR UPDATE" : "for update");
         if (x.getForUpdateOfSize() > 0) {
            this.print('(');
            this.printAndAccept(x.getForUpdateOf(), ", ");
            this.print(')');
         }

         if (x.isNoWait()) {
            this.print0(this.ucase ? " NOWAIT" : " nowait");
         } else if (x.isSkipLocked()) {
            this.print0(this.ucase ? " SKIP LOCKED" : " skip locked");
         } else if (x.getWaitTime() != null) {
            this.print0(this.ucase ? " WAIT " : " wait ");
            x.getWaitTime().accept(this);
         }
      }

      if (x.getHintsSize() > 0) {
         this.printAndAccept(x.getHints(), "");
      }

      return false;
   }

   protected void printQuery(SQLSelectQuery x) {
      Class<?> clazz = x.getClass();
      if (clazz == DmSelectQueryBlock.class) {
         this.visit((DmSelectQueryBlock)x);
      } else if (clazz == SQLUnionQuery.class) {
         this.visit((SQLUnionQuery)((SQLUnionQuery)x));
      } else {
         x.accept(this);
      }

   }

   protected void printFetchFirst(DmSelectQueryBlock x) {
      SQLLimit limit = x.getLimit();
      if (limit != null) {
         if (limit.getType() != null && limit.getType() != SQLLimit.Type.FETCH) {
            this.println();
            limit.accept(this);
         } else {
            SQLExpr offset = limit.getOffset();
            SQLExpr first = limit.getRowCount();
            SQLObject parent = x.getParent();
            if (parent instanceof SQLSelect) {
               SQLOrderBy orderBy = ((SQLSelect)parent).getOrderBy();
               if (orderBy != null && orderBy.getItems().size() > 0) {
                  this.println();
                  this.print0(this.ucase ? "ORDER BY " : "order by ");
                  this.printAndAccept(orderBy.getItems(), ", ");
               }
            }

            this.println();
            if (offset != null && x.getTop() == null) {
               this.print0(this.ucase ? "OFFSET " : "offset ");
               offset.accept(this);
               this.print0(this.ucase ? " ROWS" : " rows");
            }

            if (first != null && x.getTop() == null) {
               if (offset != null) {
                  this.print(' ');
               }

               if (DbType.sqlserver == this.dbType && offset != null) {
                  this.print0(this.ucase ? "FETCH NEXT " : "fetch next ");
               } else {
                  this.print0(this.ucase ? "FETCH FIRST " : "fetch first ");
               }

               first.accept(this);
               if (limit.isPercent()) {
                  this.print0(this.ucase ? " PERCENT ROWS ONLY" : " percent rows only");
               } else {
                  this.print0(this.ucase ? " ROWS ONLY" : " rows only");
               }
            }

         }
      }
   }

   public boolean visit(SQLLimit x) {
      this.print0(this.ucase ? "LIMIT " : "limit ");
      SQLExpr offset = x.getOffset();
      if (!x.isLimitOffsetType() && offset != null) {
         this.printExpr(offset, this.parameterized);
         this.print0(", ");
      }

      SQLExpr rowCount = x.getRowCount();
      if (rowCount != null) {
         this.printExpr(rowCount, this.parameterized);
      }

      if (x.isLimitOffsetType() && offset != null) {
         this.print0(this.ucase ? " OFFSET " : " offset ");
         this.printExpr(offset, this.parameterized);
      }

      List<SQLExpr> by = x.getBy();
      if (by != null) {
         this.print0(this.ucase ? " BY " : " by ");

         for(int i = 0; i < by.size(); ++i) {
            if (i != 0) {
               this.print0(", ");
            }

            ((SQLExpr)by.get(i)).accept(this);
         }
      }

      return false;
   }

   public boolean visit(DmSelectTableReference x) {
      this.printTableSourceExpr(x.getExpr());
      if (x.getPartition() != null) {
         this.print(' ');
         x.getPartition().accept(this);
      }

      if (x.getHints().size() > 0) {
         this.printHints(x.getHints());
      }

      if (x.getSampleClause() != null) {
         this.print(' ');
         x.getSampleClause().accept(this);
      }

      if (x.getPivot() != null) {
         this.println();
         x.getPivot().accept(this);
      }

      this.printFlashback(x.getFlashback());
      this.printAlias(x.getAlias());
      return false;
   }

   public boolean visit(PartitionExtensionClause x) {
      return false;
   }

   private void printFlashback(SQLExpr flashback) {
      if (flashback != null) {
         this.println();
         if (flashback instanceof SQLBetweenExpr) {
            flashback.accept(this);
         } else {
            this.print0(this.ucase ? "AS OF " : "as of ");
            flashback.accept(this);
         }

      }
   }

   public boolean visit(DmSelectPivot x) {
      this.print0(this.ucase ? "PIVOT" : "pivot");
      if (x.isXml()) {
         this.print0(this.ucase ? " XML" : " xml");
      }

      this.print0(" (");
      this.printAndAccept(x.getItems(), ", ");
      if (x.getPivotFor().size() > 0) {
         this.print0(this.ucase ? " FOR " : " for ");
         if (x.getPivotFor().size() == 1) {
            ((SQLExpr)x.getPivotFor().get(0)).accept(this);
         } else {
            this.print('(');
            this.printAndAccept(x.getPivotFor(), ", ");
            this.print(')');
         }
      }

      if (x.getPivotIn().size() > 0) {
         this.print0(this.ucase ? " IN (" : " in (");
         this.printAndAccept(x.getPivotIn(), ", ");
         this.print(')');
      }

      this.print(')');
      return false;
   }

   public void endVisit(DmSelectPivot x) {
   }

   public boolean visit(DmSelectPivot.Item x) {
      x.getExpr().accept(this);
      if (x.getAlias() != null && x.getAlias().length() > 0) {
         this.print0(this.ucase ? " AS " : " as ");
         this.print0(x.getAlias());
      }

      return false;
   }

   public boolean visit(DmSelectUnPivot x) {
      this.print0(this.ucase ? "UNPIVOT" : "unpivot");
      if (x.getNullsIncludeType() != null) {
         this.print(' ');
      }

      this.print0(" (");
      if (x.getItems().size() == 1) {
         ((SQLExpr)x.getItems().get(0)).accept(this);
      } else {
         this.print0(" (");
         this.printAndAccept(x.getItems(), ", ");
         this.print(')');
      }

      if (x.getPivotFor().size() > 0) {
         this.print0(this.ucase ? " FOR " : " for ");
         if (x.getPivotFor().size() == 1) {
            ((SQLExpr)x.getPivotFor().get(0)).accept(this);
         } else {
            this.print('(');
            this.printAndAccept(x.getPivotFor(), ", ");
            this.print(')');
         }
      }

      if (x.getPivotIn().size() > 0) {
         this.print0(this.ucase ? " IN (" : " in (");
         this.printAndAccept(x.getPivotIn(), ", ");
         this.print(')');
      }

      this.print(')');
      return false;
   }

   public void endVisit(DmSelectUnPivot x) {
   }

   public boolean visit(DmUpdateStatement x) {
      super.visit((SQLUpdateStatement)x);
      if (x.getDmReturning() != null) {
         this.visit(x.getDmReturning());
      }

      return false;
   }

   public boolean visit(SQLSubqueryTableSource x) {
      this.print('(');
      if (x.getSelect() != null) {
         x.getSelect().accept(this);
      }

      this.print(") ");
      this.print(x.getAlias());
      return false;
   }

   public boolean visit(DmSelectSubqueryTableSource x) {
      this.print(" ( ");
      if (x.getPivot() != null) {
         x.getPivot().accept(this);
      }

      if (x.getSelect() != null) {
         x.getSelect().accept(this);
      }

      this.print(" ) ");
      this.print(x.getAlias());
      return false;
   }

   public boolean visit(SQLAggregateExpr x) {
      boolean parameterized = this.parameterized;
      if (x.methodNameHashCode64() == FnvHash.Constants.GROUP_CONCAT) {
         this.parameterized = false;
      }

      if (x.methodNameHashCode64() == FnvHash.Constants.COUNT) {
         List<SQLExpr> arguments = x.getArguments();
         if (arguments.size() == 1) {
            SQLExpr arg0 = (SQLExpr)arguments.get(0);
            if (arg0 instanceof SQLLiteralExpr) {
               this.parameterized = false;
            }
         }
      }

      if (x.getOwner() != null) {
         this.printExpr(x.getOwner());
         this.print(".");
      }

      String methodName = x.getMethodName();
      this.print0(this.ucase ? methodName : methodName.toLowerCase());
      this.print('(');
      SQLAggregateOption option = x.getOption();
      if (option != null) {
         this.print0(option.toString());
         this.print(' ');
      }

      List<SQLExpr> arguments = x.getArguments();
      int i = 0;

      for(int size = arguments.size(); i < size; ++i) {
         if (i != 0) {
            this.print0(", ");
         }

         this.printExpr((SQLExpr)arguments.get(i), false);
      }

     boolean i2 = x.isWithinGroup();
      if (i2) {
         this.print0(this.ucase ? ") WITHIN GROUP (" : " within group (");
      }

      this.visitAggreateRest(x);
      this.print(')');
      if (x.isIgnoreNulls()) {
         this.print0(this.ucase ? " IGNORE NULLS" : " ignore nulls");
      }

      SQLKeep keep = x.getKeep();
      if (keep != null) {
         this.print(' ');
         this.visit((SQLKeep)keep);
      }

      SQLOver over = x.getOver();
      if (over != null) {
         this.print0(this.ucase ? " OVER " : " over ");
         over.accept(this);
      }

      SQLName overRef = x.getOverRef();
      if (overRef != null) {
         this.print0(this.ucase ? " OVER " : " over ");
         overRef.accept(this);
      }

      SQLExpr filter = x.getFilter();
      if (filter != null) {
         this.print0(this.ucase ? " FILTER (WHERE " : " filter (where ");
         this.printExpr(filter);
         this.print(')');
      }

      this.parameterized = parameterized;
      return false;
   }

   protected void visitAggreateRest(SQLAggregateExpr x) {
      SQLOrderBy orderBy = x.getOrderBy();
      if (orderBy != null) {
         if (!x.isWithinGroup()) {
            this.print(' ');
         }

         orderBy.accept(this);
      }

   }

   public boolean visit(DmAnalytic x) {
      this.print0(this.ucase ? "(" : "(");
      boolean space = false;
      if (x.getPartitionBy().size() > 0) {
         this.print0(this.ucase ? "PARTITION BY " : "partition by ");
         this.printAndAccept(x.getPartitionBy(), ", ");
         space = true;
      }

      SQLOrderBy orderBy = x.getOrderBy();
      if (orderBy != null) {
         if (space) {
            this.print(' ');
         }

         this.visit((SQLOrderBy)orderBy);
         space = true;
      }

      DmAnalyticWindowing windowing = x.getWindowing();
      if (windowing != null) {
         if (space) {
            this.print(' ');
         }

         this.visit(windowing);
      }

      if (x.isWindowingPreceding()) {
         this.print0(this.ucase ? " PRECEDING" : " preceding");
      }

      this.print(')');
      return false;
   }

   public boolean visit(DmAnalyticWindowing x) {
      this.print0(x.getType().name().toUpperCase());
      this.print(' ');
      SQLExpr expr = x.getExpr();
      if (expr instanceof SQLBetweenExpr && x.getParent() instanceof SQLOver) {
         SQLOver over = (SQLOver)x.getParent();
         SQLBetweenExpr betweenExpr = (SQLBetweenExpr)expr;
         SQLOver.WindowingBound beginBound = over.getWindowingBetweenBeginBound();
         if (beginBound != null) {
            this.print0(this.ucase ? " BETWEEN " : " between ");
            betweenExpr.getBeginExpr().accept(this);
            this.print(' ');
            this.print0(this.ucase ? beginBound.name : beginBound.name_lower);
            this.print0(this.ucase ? " AND " : " and ");
            betweenExpr.getEndExpr().accept(this);
            return false;
         }
      }

      expr.accept(this);
      return false;
   }

   public boolean visit(DmSampleClause x) {
      this.print0(this.ucase ? "SAMPLE " : "sample ");
      if (x.isBlock()) {
         this.print0(this.ucase ? "BLOCK " : "block ");
      }

      this.print('(');
      this.printAndAccept(x.getPercent(), ", ");
      this.print(')');
      if (x.getSeedValue() != null) {
         this.print0(this.ucase ? " SEED (" : " seed (");
         x.getSeedValue().accept(this);
         this.print(')');
      }

      return false;
   }

   public void endVisit(DmSelectPivot.Item x) {
   }

   public boolean visit(DmPartitionExtensionClause x) {
      if (x.isSubPartition()) {
         this.print0(this.ucase ? "SUBPARTITION " : "subpartition ");
      } else {
         this.print0(this.ucase ? "PARTITION " : "partition ");
      }

      if (x.getPartition() != null) {
         this.print('(');
         x.getPartition().accept(this);
         this.print(')');
      } else {
         this.print0(this.ucase ? "FOR (" : "for (");
         this.printAndAccept(x.getFor(), ",");
         this.print(')');
      }

      return false;
   }

   protected void printCreateTable(SQLCreateTableStatement x, boolean printSelect) {
      this.print0(this.ucase ? "CREATE " : "create ");
      if (x.isExternal()) {
         this.print0(this.ucase ? "EXTERNAL " : "external ");
      }

      SQLCreateTableStatement.Type tableType = x.getType();
      if (SQLCreateTableStatement.Type.GLOBAL_TEMPORARY.equals(tableType)) {
         this.print0(this.ucase ? "GLOBAL TEMPORARY " : "global temporary ");
      } else if (SQLCreateTableStatement.Type.LOCAL_TEMPORARY.equals(tableType)) {
         this.print0(this.ucase ? "LOCAL TEMPORARY " : "local temporary ");
      } else if (SQLCreateTableStatement.Type.SHADOW.equals(tableType)) {
         this.print0(this.ucase ? "SHADOW " : "shadow ");
      } else if (SQLCreateTableStatement.Type.TEMPORARY.equals(tableType)) {
         this.print0(this.ucase ? "TEMPORARY " : "temporary ");
      }

      if (x.isDimension()) {
         this.print0(this.ucase ? "DIMENSION " : "dimension ");
      }

      this.print0(this.ucase ? "TABLE " : "table ");
      if (x.isIfNotExists()) {
         this.print0(this.ucase ? "IF NOT EXISTS " : "if not exists ");
      }

      this.printTableSourceExpr(x.getName());
      this.printTableElements(x.getTableElementList());
      SQLExprTableSource inherits = x.getInherits();
      if (inherits != null) {
         this.print0(this.ucase ? " INHERITS (" : " inherits (");
         inherits.accept(this);
         this.print(')');
      }

      SQLExpr storedAs = x.getStoredAs();
      if (storedAs != null) {
         this.print0(this.ucase ? " STORE AS " : " store as ");
         this.printExpr(storedAs, this.parameterized);
      }

   }

   public boolean visit(DmCreateTableStatement x) {
      this.printCreateTable(x, true);
      if (x.isExternal()) {
         this.print0(this.ucase ? " FROM" : " from");
         if (x.isDatafile()) {
            this.print0(this.ucase ? " DATAFILE" : " datafile");
            if (x.getDirectory() != null) {
               this.print0(this.ucase ? " DEFAULT DIRECTORY " : " default directory ");
               x.getDirectory().accept(this);
               this.print0(this.ucase ? " LOCATION (" : " location (");
               x.getLocation().accept(this);
               this.print0(")");
               if (x.getParmsList().size() > 0) {
                  this.print0(this.ucase ? " PARMS" : " parms");
                  this.print0("(");
                  this.printAndAccept(x.getParmsList(), ",");
                  this.print0(")");
               }
            } else {
               this.print0(" ");
               x.getFilepath().accept(this);
               if (x.getParmsList().size() > 0) {
                  this.print0(this.ucase ? " PARMS" : " parms");
                  this.print0("(");
                  this.printAndAccept(x.getParmsList(), ",");
                  this.print0(")");
               }
            }
         } else if (x.getDirectory() != null) {
            this.print0(this.ucase ? " DEFAULT DIRECTORY " : " default directory ");
            x.getDirectory().accept(this);
            this.print0(this.ucase ? " LOCATION (" : " location (");
            x.getLocation().accept(this);
            this.print0(")");
         } else if (x.getFilepath() != null) {
            this.print0(" ");
            x.getFilepath().accept(this);
         }

         return false;
      } else {
         if (x.isOnCommitPreserveRows()) {
            this.println();
            this.print0(this.ucase ? "ON COMMIT PRESERVE ROWS" : "on commit preserve rows");
         } else if (x.isOnCommitDeleteRows()) {
            this.println();
            this.print0(this.ucase ? "ON COMMIT DELETE ROWS" : "on commit delete rows");
         }

         SQLPartitionBy partitionBy = x.getPartitioning();
         if (partitionBy != null) {
            this.println();
            this.print0(this.ucase ? "PARTITION BY " : "partition by ");
            partitionBy.accept(this);
         }

         List<SQLAssignItem> options = x.getTableOptions();
         if (options.size() > 0) {
            this.println();
            this.print0(this.ucase ? "WITH (" : "with (");
            this.printAndAccept(options, ", ");
            this.print(')');
         }

         SQLName tablespace = x.getTablespace();
         if (tablespace != null) {
            this.println();
            this.print0(this.ucase ? "TABLESPACE " : "tablespace ");
            tablespace.accept(this);
         }

         if (x.getSpacelimit() != null) {
            this.println();
            this.print0(this.ucase ? "DISKSPACE LIMIT  " : "diskspace limit  ");
            this.print(x.getSpacelimit());
            this.print(' ');
         } else if (x.getUnlimited() != null) {
            this.println();
            this.print0(this.ucase ? "DISKSPACE UNLIMITED " : "diskspace UNLIMITED ");
         }

         if (x.getStorage() != null) {
            this.println();
            x.getStorage().accept(this);
         }

         if (x.getEnableRowMovement() != null) {
            this.println();
            if (x.getEnableRowMovement()) {
               this.print0(this.ucase ? "ENABLE ROW MOVEMENT " : " enable row movement ");
            } else {
               this.print0(this.ucase ? "DISABLE ROW MOVEMENT " : " disable row movement ");
            }
         }

         SQLExpr engine = x.getEngine();
         if (engine != null) {
            this.print0(this.ucase ? " ENGINE = " : " engine = ");
            engine.accept(this);
         }

         SQLSelect select = x.getSelect();
         if (select != null) {
            this.println();
            this.print0(this.ucase ? "AS" : "as");
            this.println();
            this.visit(select);
         }

         return false;
      }
   }

   public void endVisit(DmCreateTableStatement x) {
   }

   public boolean visit(DmSQLColumnPrimaryKey x) {
      SQLName name = x.getName();
      if (name != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         name.accept(this);
         this.print(' ');
      }

      if (x.isNot()) {
         this.print0(this.ucase ? "NOT " : "not ");
      }

      if (x.isCluster()) {
         this.print0(this.ucase ? "CLUSTER " : "cluster ");
         if (x.isPrimary()) {
            this.print0(this.ucase ? "PRIMARY KEY " : "primary key ");
         }

         if (x.isUnique()) {
            this.print0(this.ucase ? "UNIQUE KEY " : "unique key ");
         }

         if (x.isKey()) {
            this.print0(this.ucase ? "KEY" : "key ");
         }
      }

      return false;
   }

   public void endVisit(DmSQLColumnPrimaryKey x) {
   }

   public boolean visit(DmStorageClause x) {
      this.print0(this.ucase ? "STORAGE (" : "storage (");
      ++this.indentCount;
      SQLExpr initial = x.getInitial();
      boolean comma = false;
      if (initial != null) {
         this.println();
         this.print0(this.ucase ? "INITIAL " : "initial ");
         this.printExpr(initial, false);
         comma = true;
      }

      SQLExpr next = x.getNext();
      if (next != null) {
         if (comma) {
            this.print0(", ");
         }

         this.println();
         this.print0(this.ucase ? "NEXT " : "next ");
         this.printExpr(next, false);
         comma = true;
      }

      SQLExpr minExtents = x.getMinExtents();
      if (minExtents != null) {
         if (comma) {
            this.print0(", ");
         }

         this.println();
         this.print0(this.ucase ? "MINEXTENTS " : "minextents ");
         this.printExpr(minExtents, false);
         comma = true;
      }

      SQLExpr on = x.getOn();
      if (on != null) {
         if (comma) {
            this.print0(", ");
         }

         this.println();
         this.print0(this.ucase ? "ON " : "on ");
         this.printExpr(on, false);
         comma = true;
      }

      SQLExpr fillfactor = x.getFillfactor();
      if (fillfactor != null) {
         if (comma) {
            this.print0(", ");
         }

         this.println();
         this.print0(this.ucase ? "FILLFACTOR " : "fillfactor ");
         this.printExpr(fillfactor, false);
         comma = true;
      }

      SQLExpr nobranchcount = x.getNobranchcount();
      SQLExpr branchcount = x.getBranchcount();
      if (nobranchcount != null) {
         if (comma) {
            this.print0(", ");
         }

         this.println();
         this.print0(this.ucase ? "BRANCH( " : "branch( ");
         this.printExpr(branchcount, false);
         this.print0(", ");
         this.printExpr(nobranchcount, false);
         this.print0(" ) ");
         comma = true;
      } else if (branchcount != null) {
         if (comma) {
            this.print0(", ");
         }

         this.println();
         this.print0(this.ucase ? "BRANCH " : "branch ");
         this.printExpr(branchcount, false);
         comma = true;
      }

      boolean nobranch = x.isNobranch();
      if (nobranch) {
         if (comma) {
            this.print0(", ");
         }

         this.println();
         this.print0(this.ucase ? "NOBRANCH " : "nobranch ");
         comma = true;
      }

      boolean clusterbtr = x.isClusterbtr();
      if (clusterbtr) {
         if (comma) {
            this.print0(", ");
         }

         this.println();
         this.print0(this.ucase ? "CLUSTERBTR " : "clusterbtr ");
         comma = true;
      }

      boolean withCounter = x.isWithCounter();
      if (withCounter) {
         if (comma) {
            this.print0(", ");
         }

         this.println();
         this.print0(this.ucase ? "WITH COUNTER " : "with counter ");
         comma = true;
      }

      boolean withoutCounter = x.isWithoutCounter();
      if (withoutCounter) {
         if (comma) {
            this.print0(", ");
         }

         this.println();
         this.print0(this.ucase ? "WITHOUT COUNTER " : "without counter  ");
         comma = true;
      }

      boolean usingLongRow = x.isUsingLongRow();
      if (usingLongRow) {
         if (comma) {
            this.print0(", ");
         }

         this.println();
         this.print0(this.ucase ? "USING LONG ROW " : "using long row ");
         comma = true;
      }

      if (x.isStatNone()) {
         if (comma) {
            this.print0(", ");
         }

         this.println();
         this.print0(this.ucase ? "STAT NONE " : "stat none ");
         comma = true;
      }

      if (x.getSectioncount() != null) {
         if (comma) {
            this.print0(", ");
         }

         this.println();
         this.print0(this.ucase ? "SECTION (" : "section (");
         x.getSectioncount().accept(this);
         this.print0(this.ucase ? ")" : ")");
         comma = true;
      }

      --this.indentCount;
      this.println();
      this.print(')');
      return false;
   }

   public void endVisit(DmStorageClause x) {
   }

   public boolean visit(DMIndexTablespacleConstraint x) {
      SQLName name = x.getName();
      if (name != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         name.accept(this);
         this.print(' ');
      }

      this.print0(this.ucase ? "USING INDEX TABLESPACE " : "using index tablespace ");
      x.getTablespacename().accept(this);
      this.print(' ');
      if (x.getEnable() != null && x.getEnable()) {
         this.print0(this.ucase ? " ENABLE" : " enable");
      }

      if (x.getEnable() != null && !x.getEnable()) {
         this.print0(this.ucase ? " DISABLE" : " disable");
      }

      return false;
   }

   public void endVisit(DMIndexTablespacleConstraint x) {
   }

   public boolean visit(SQLNotVisibleConstraint x) {
      SQLName name = x.getName();
      if (name != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         name.accept(this);
         this.print(' ');
      }

      this.print0(this.ucase ? "NOT VISIBLE " : "not visible ");
      if (x.getEnable() != null && x.getEnable()) {
         this.print0(this.ucase ? "ENABLE " : "enable ");
      }

      if (x.getEnable() != null && !x.getEnable()) {
         this.print0(this.ucase ? "DISABLE " : "disable ");
      }

      return false;
   }

   public void endVisit(SQLNotVisibleConstraint x) {
   }

   public boolean visit(DmSQLColumnReference x) {
      SQLName name = x.getName();
      if (name != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         name.accept(this);
         this.print(' ');
      }

      this.print0(this.ucase ? "REFERENCES " : "references ");
      if (x.getPendant() != null && x.getPendant()) {
         this.print0(this.ucase ? "PENDANT " : "pendant ");
      }

      x.getTable().accept(this);
      this.print0(" (");
      this.printAndAccept(x.getColumns(), ", ");
      this.print(')');
      SQLForeignKeyImpl.Match match = x.getReferenceMatch();
      if (match != null) {
         this.print0(this.ucase ? " MATCH " : " match ");
         this.print0(this.ucase ? match.name : match.name_lcase);
      }

      if (x.getOnDelete() != null) {
         this.print0(this.ucase ? " ON DELETE " : " on delete ");
         this.print0(this.ucase ? x.getOnDelete().name : x.getOnDelete().name_lcase);
      }

      if (x.getOnUpdate() != null) {
         this.print0(this.ucase ? " ON UPDATE " : " on update ");
         this.print0(this.ucase ? x.getOnUpdate().name : x.getOnUpdate().name_lcase);
      }

      if (x.getWithIndex() != null && x.getWithIndex()) {
         this.print0(this.ucase ? " WITH INDEX " : " with index ");
      }

      return false;
   }

   public void endVisit(DmSQLColumnReference x) {
   }

   public boolean visit(SQLColumnDefinition x) {
      boolean parameterized = this.parameterized;
      this.parameterized = false;
      x.getName().accept(this);
      SQLDataType dataType = x.getDataType();
      if (dataType != null) {
         this.print(' ');
         dataType.accept(this);
      }

      if (x.getDefaultExpr() != null) {
         this.visitColumnDefault(x);
      }

      if (x.isAutoIncrement()) {
         this.print0(this.ucase ? " AUTO_INCREMENT" : " auto_increment");
      }

      AutoIncrementType sequenceType = x.getSequenceType();
      if (sequenceType != null) {
         this.print0(" ");
         this.print0(this.ucase ? sequenceType.getKeyword() : sequenceType.getKeyword().toLowerCase());
      }

      for(SQLColumnConstraint item : x.getConstraints()) {
         boolean newLine = item instanceof SQLForeignKeyConstraint || item instanceof SQLPrimaryKey || item instanceof SQLColumnCheck || item instanceof SQLColumnCheck || item.getName() != null;
         if (newLine) {
            ++this.indentCount;
            this.println();
         } else {
            this.print(' ');
         }

         item.accept(this);
         if (newLine) {
            --this.indentCount;
         }
      }

      SQLExpr generatedAlawsAs = x.getGeneratedAlawsAs();
      if (generatedAlawsAs != null) {
         this.print0(this.ucase ? " GENERATED ALWAYS AS " : " generated always as ");
         this.print0(" (");
         this.printExpr(generatedAlawsAs, parameterized);
         this.print0(") ");
      }

      SQLColumnDefinition.Identity identity = x.getIdentity();
      if (identity != null) {
         if (this.dbType == DbType.h2) {
            this.print0(this.ucase ? " AS " : " as ");
         } else {
            this.print(' ');
         }

         identity.accept(this);
      }

      if (x.isVirtual()) {
         this.print0(this.ucase ? " VIRTUAL" : " virtual");
      }

      if (x.isVisible()) {
         this.print0(this.ucase ? " VISIBLE" : " visible");
      }

      Boolean enable = x.getEnable();
      if (enable != null && enable) {
         this.print0(this.ucase ? " ENABLE" : " enable");
      }

      if (x.getComment() != null) {
         this.print0(this.ucase ? " COMMENT " : " comment ");
         x.getComment().accept(this);
      }

      List<SQLAssignItem> mappedBy = x.getMappedByDirect();
      if (mappedBy != null && mappedBy.size() > 0) {
         this.print0(this.ucase ? " MAPPED BY (" : " mapped by (");
         this.printAndAccept(mappedBy, ", ");
         this.print0(this.ucase ? ")" : ")");
      }

      List<SQLAssignItem> colProperties = x.getColPropertiesDirect();
      if (colProperties != null && colProperties.size() > 0) {
         this.print0(this.ucase ? " COLPROPERTIES (" : " colproperties (");
         this.printAndAccept(colProperties, ", ");
         this.print0(this.ucase ? ")" : ")");
      }

      if (x.getEncode() != null) {
         this.print0(this.ucase ? " ENCODE=" : " encode=");
         x.getEncode().accept(this);
      }

      if (x.getCompression() != null) {
         this.print0(this.ucase ? " COMPRESSION=" : " compression=");
         x.getCompression().accept(this);
      }

      if (x.getStorage() != null) {
         this.print(' ');
         x.getStorage().accept(this);
      }

      this.parameterized = parameterized;
      return false;
   }

   public boolean visit(DmSQLPrimaryKey x) {
      SQLName name = x.getName();
      if (name != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         name.accept(this);
         this.print(' ');
         if (x.getParent() instanceof DmAlterTableModifyConstraint) {
            this.print0(this.ucase ? "TO " : "to ");
         }
      }

      if (x.getNot() != null && x.getNot()) {
         this.print0(this.ucase ? "NOT " : "not ");
      }

      if (x.isClustered()) {
         this.print0(this.ucase ? "CLUSTER " : "cluster ");
      }

      this.print0(this.ucase ? "PRIMARY KEY " : "primary key ");
      this.print('(');
      this.printAndAccept(x.getColumns(), ", ");
      this.print(')');
      if (x.getTablespacename() != null) {
         this.print0(this.ucase ? " USING INDEX TABLESPACE " : " using index tablespace ");
         x.getTablespacename().accept(this);
         this.print(' ');
      } else if (x.getNull() != null && x.getNull()) {
         this.print0(this.ucase ? " NULL " : " null ");
      }

      if (x.getEnable() != null && x.getEnable()) {
         this.print0(this.ucase ? "ENABLE " : "enable ");
      }

      if (x.getEnable() != null && !x.getEnable()) {
         this.print0(this.ucase ? "DISABLE " : "disable ");
      }

      return false;
   }

   public void endVisit(DmSQLPrimaryKey x) {
   }

   public boolean visit(DmSQLUniqueKey x) {
      if (x.getName() != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         x.getName().accept(this);
         this.print(' ');
         if (x.getParent() instanceof DmAlterTableModifyConstraint) {
            this.print0(this.ucase ? "TO " : "to ");
         }
      }

      if (x.getClustered() != null && x.getClustered()) {
         this.print0(this.ucase ? "CLUSTER " : "cluster ");
      }

      if (x.getUnique() != null && x.getUnique()) {
         this.print0(this.ucase ? "UNIQUE " : "unique ");
      }

      if (x.getKey() != null && x.getKey()) {
         this.print0(this.ucase ? "KEY " : "key ");
      }

      this.print('(');
      List<SQLSelectOrderByItem> columns = x.getColumns();
      int i = 0;

      for(int size = columns.size(); i < size; ++i) {
         if (i != 0) {
            this.print0(", ");
         }

         this.visit((SQLSelectOrderByItem)((SQLSelectOrderByItem)columns.get(i)));
      }

      this.print(')');
      if (x.getTablespacename() != null) {
         this.print0(this.ucase ? " USING INDEX TABLESPACE " : " using index tablespace ");
         x.getTablespacename().accept(this);
         this.print(' ');
      }

      if (x.getEnable() != null && x.getEnable()) {
         this.print0(this.ucase ? " ENABLE " : " enable ");
      }

      if (x.getEnable() != null && !x.getEnable()) {
         this.print0(this.ucase ? " DISABLE " : " disable ");
      }

      return false;
   }

   public void endVisit(DmSQLUniqueKey x) {
   }

   public boolean visit(DmForeignKeyImpl x) {
      SQLName name = x.getName();
      if (name != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         name.accept(this);
         this.print(' ');
         if (x.getParent() instanceof DmAlterTableModifyConstraint) {
            this.print0(this.ucase ? "TO " : "to ");
         }
      }

      this.print0(this.ucase ? "FOREIGN KEY (" : "foreign key (");
      this.printAndAccept(x.getReferencingColumns(), ", ");
      this.print(')');
      this.print0(this.ucase ? " REFERENCES " : " references ");
      if (x.getPendant() != null && x.getPendant()) {
         this.print0(this.ucase ? "PENDANT " : "pendant ");
      }

      x.getReferencedTableName().accept(this);
      if (x.getReferencedColumns().size() > 0) {
         this.print0(" (");
         this.printAndAccept(x.getReferencedColumns(), ", ");
         this.print(')');
      }

      SQLForeignKeyImpl.Match match = x.getReferenceMatch();
      if (match != null) {
         this.print0(this.ucase ? " MATCH " : " match ");
         this.print0(this.ucase ? match.name : match.name_lcase);
      }

      if (x.getOnDelete() != null) {
         this.print0(this.ucase ? " ON DELETE " : " on delete ");
         this.print0(this.ucase ? x.getOnDelete().name : x.getOnDelete().name_lcase);
      }

      if (x.getOnUpdate() != null) {
         this.print0(this.ucase ? " ON UPDATE " : " on update ");
         this.print0(this.ucase ? x.getOnUpdate().name : x.getOnUpdate().name_lcase);
      }

      if (x.getWithIndex() != null && x.getWithIndex()) {
         this.print0(this.ucase ? " WITH INDEX " : " with index ");
      }

      return false;
   }

   public void endVisit(DmForeignKeyImpl x) {
   }

   public boolean visit(DmAlterTableAlterColumn x) {
      this.print0(this.ucase ? "ALTER COLUMN " : "alter column ");
      SQLName originColumn = x.getOriginColumn();
      if (originColumn != null) {
         originColumn.accept(this);
         this.print(' ');
      }

      x.getColumn().accept(this);
      if (x.isSetNotNull()) {
         this.print0(this.ucase ? " SET NOT NULL" : " set not null");
      }

      if (x.isSetNull()) {
         this.print0(this.ucase ? " SET NULL" : " set null");
      }

      if (x.isSetNotVisible()) {
         this.print0(this.ucase ? " SET NOT VISIBLE" : " set not visible");
      }

      if (x.isSetVisible()) {
         this.print0(this.ucase ? " SET VISIBLE" : " set visible");
      }

      if (x.getNewColumnname() != null) {
         this.print0(this.ucase ? " RENAME TO" : " rename to");
         x.getNewColumnname().accept(this);
      }

      if (x.isDropNotNull()) {
         this.print0(this.ucase ? " DROP NOT NULL" : " drop not null");
      }

      if (x.getSetDefault() != null) {
         this.print0(this.ucase ? " SET DEFAULT " : " set default ");
         x.getSetDefault().accept(this);
      }

      if (x.isDropDefault()) {
         this.print0(this.ucase ? " DROP DEFAULT" : " drop default");
      }

      SQLDataType dataType = x.getDataType();
      if (dataType != null) {
         this.print0(this.ucase ? " SET DATA TYPE " : " set data type ");
         dataType.accept(this);
      }

      SQLName after = x.getAfter();
      if (after != null) {
         this.print0(this.ucase ? " AFTER " : " after ");
         after.accept(this);
      }

      return false;
   }

   public void endVisit(DmAlterTableAlterColumn x) {
   }

   public boolean visit(DMSQLAlterTableRebuildColumns x) {
      this.print0(this.ucase ? " REBUILD COLUMNS " : " rebuild columns ");
      return false;
   }

   public void endVisit(DMSQLAlterTableRebuildColumns x) {
   }

   public boolean visit(SQLAlterTableDisableTriggers x) {
      this.print0(this.ucase ? " DISABLE ALL TRIGGERS " : " disable all triggers ");
      return false;
   }

   public boolean visit(SQLAlterTableEnableTriggers x) {
      this.print0(this.ucase ? " ENABLE ALL TRIGGERS " : " enable all triggers ");
      return false;
   }

   public boolean visit(DmAlterTableModifyDiskspace x) {
      if (x.getSpacelimit() != null) {
         this.print0(this.ucase ? " MODIFY DISKSPACE LIMIT  " : "diskspace limit  ");
         this.print(x.getSpacelimit());
         this.print(' ');
      } else if (x.getUnlimited() != null) {
         this.print0(this.ucase ? " MODIFY DISKSPACE UNLIMITED " : "diskspace UNLIMITED ");
      }

      return false;
   }

   public void endVisit(DmAlterTableModifyDiskspace x) {
   }

   public boolean visit(DmAlterTableModifyConstraint x) {
      this.print0(this.ucase ? "MODIFY" : "modify");
      if (x.getExternalTableFilePath() != null) {
         this.print0(this.ucase ? " PATH " : " path ");
         x.getExternalTableFilePath().accept(this);
         return false;
      } else {
         x.getConstraint().accept(this);
         if (x.getCheck() != null && x.getCheck()) {
            this.print0(this.ucase ? " CHECK " : " check ");
         }

         if (x.getCheck() != null && !x.getCheck()) {
            this.print0(this.ucase ? " NOT CHECK " : " not check ");
         }

         if (x.getCascade() != null) {
            this.print0(this.ucase ? " CASCADE " : " cascade ");
         }

         if (x.getRestrict() != null) {
            this.print0(this.ucase ? " RESTRICT " : " restrict ");
         }

         return false;
      }
   }

   public void endVisit(DmAlterTableModifyConstraint x) {
   }

   public boolean visit(DmConstraint x) {
      if (x.getName() != null) {
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         x.getName().accept(this);
         this.print(' ');
      }

      if (x.getEnable() != null && x.getEnable()) {
         this.print0(this.ucase ? " ENABLE " : " enable ");
      }

      if (x.getEnable() != null && !x.getEnable()) {
         this.print0(this.ucase ? " DISABLE " : " disable ");
      }

      return false;
   }

   public void endVisit(DmConstraint x) {
   }

   public boolean visit(DmAlterTableCounter x) {
      if (x.isWith()) {
         this.print0(this.ucase ? " WITH " : " with ");
      } else {
         this.print0(this.ucase ? " WITHOUT " : " without ");
      }

      this.print0(this.ucase ? "COUNTER " : "counter ");
      return false;
   }

   public void endVisit(DmAlterTableCounter x) {
   }

   public boolean visit(DmAlterTableAddIdentity x) {
      this.print0(this.ucase ? " ADD COLUMN " : " add column ");
      x.getName().accept(this);
      this.print0(this.ucase ? " " : " ");
      x.getIdentity().accept(this);
      return false;
   }

   public void endVisit(DmAlterTableAddIdentity x) {
   }

   public boolean visit(DmAlterTableDropIdentity x) {
      this.print0(this.ucase ? " DROP IDENTITY" : " drop identity");
      return false;
   }

   public void endVisit(DmAlterTableDropIdentity x) {
   }

   public boolean visit(DmAlterTableTruncateSubpartition x) {
      this.print0(this.ucase ? "TRUNCATE SUBPARTITION " : "truncate subpartition ");
      x.getName().accept(this);
      return false;
   }

   public void endVisit(DmAlterTableTruncateSubpartition x) {
   }

   public boolean visit(DmAlterTableRowMovement x) {
      if (x.isEnable()) {
         this.print0(this.ucase ? " ENABLE " : " enable ");
      } else {
         this.print0(this.ucase ? " DISABLE " : " disable ");
      }

      this.print0(this.ucase ? "ROW MOVEMENT" : "row movement");
      return false;
   }

   public void endVisit(DmAlterTableRowMovement x) {
   }

   public boolean visit(DmAlterTableEnableUsingLongRow x) {
      this.print0(this.ucase ? "ENABLE USING LONG ROW" : "enable using long row");
      return false;
   }

   public void endVisit(DmAlterTableEnableUsingLongRow x) {
   }

   public boolean visit(DmAlterTableModifyPartition x) {
      this.print0(this.ucase ? "MODIFY " : "MODIFY ");
      this.print0(x.getType().toString());
      this.print(" ");
      x.getName().accept(this);
      if (x.getSubPartition() != null) {
         this.print0(this.ucase ? " ADD " : " add ");
         x.getSubPartition().accept(this);
      } else if (x.getValues() != null) {
         this.print(" ");
         this.print(x.getAction().toString());
         this.print(" ");
         x.getValues().accept(this);
      }

      return false;
   }

   public void endVisit(DmAlterTableModifyPartition x) {
   }

   public boolean visit(DmAlterTableDropPartition x) {
      this.print0(this.ucase ? "DROP " : "drop ");
      this.print0(x.getType().toString());
      this.print(" ");
      if (x.getName() != null) {
         x.getName().accept(this);
      } else {
         this.print0(this.ucase ? "FOR( " : "for( ");
         this.printAndAccept(x.getItems(), ", ", false);
         this.print0(this.ucase ? ") " : ") ");
      }

      return false;
   }

   public void endVisit(DmAlterTableDropPartition x) {
   }

   public boolean visit(DmAlterTableAddPartition x) {
      this.print0(this.ucase ? "ADD " : "add ");
      x.getPartition().accept(this);
      return false;
   }

   public void endVisit(DmAlterTableAddPartition x) {
   }

   public boolean visit(DmAlterTableExchangePartition x) {
      this.print0(this.ucase ? "EXCHANGE " : "exchange ");
      this.print0(x.getType().toString());
      this.print0(" ");
      this.print0(this.ucase ? "WITH TABLE " : "with table ");
      x.getTableSource().accept(this);
      return false;
   }

   public void endVisit(DmAlterTableExchangePartition x) {
   }

   public boolean visit(DmAlterTableSplitPartition x) {
      this.print0(this.ucase ? "SPLIT PARTITION " : "split partition ");
      x.getName().accept(this);
      this.print0(" ");
      if (x.getAt().size() > 0) {
         this.print0(this.ucase ? "AT( " : "at( ");
         this.printAndAccept(x.getAt(), ", ", false);
         this.print0(this.ucase ? ") " : ") ");
      } else if (x.getValues().size() > 0) {
         this.print0(this.ucase ? "VALUES( " : "values( ");
         this.printAndAccept(x.getValues(), ", ", false);
         this.print0(this.ucase ? ") " : ") ");
      }

      this.print0(this.ucase ? "INTO" : "into");
      this.printSQLPartitions(x.getInto());
      return false;
   }

   public void endVisit(DmAlterTableSplitPartition x) {
   }

   public boolean visit(DmAlterTableMergePartition x) {
      this.print0(this.ucase ? "MERGE PARTITIONS " : "merge partitions ");
      this.printAndAccept(x.getNameList(), ", ", false);
      this.print0(this.ucase ? " INTO PARTITION " : " into partition ");
      x.getInto().accept(this);
      return false;
   }

   public void endVisit(DmAlterTableMergePartition x) {
   }

   public boolean visit(DmAlterTableDefaultDirectory x) {
      this.print0(this.ucase ? "DEFAULT DIRECTORY " : "default directory ");
      x.getDirectory().accept(this);
      return false;
   }

   public void endVisit(DmAlterTableDefaultDirectory x) {
   }

   public boolean visit(DmAlterTableLocation x) {
      this.print0(this.ucase ? "LOCATION( " : "location( ");
      x.getLocation().accept(this);
      this.print0(" )");
      return false;
   }

   public void endVisit(DmAlterTableLocation x) {
   }

   public boolean visit(DmAlterTableSetPartitionTemplate x) {
      this.print0(this.ucase ? "SET SUBPARTITION TEMPLATE" : "SET SUBPARTITION TEMPLATE");
      if (x.getSubPartitionTemplate().size() > 0) {
         this.print0(" ( ");
         ++this.indentCount;
         this.println();
         this.printlnAndAccept(x.getSubPartitionTemplate(), ",");
         --this.indentCount;
         this.println();
         this.print0(" ) ");
      } else {
         if (x.getSubPartitionsCount() != null) {
            this.print0(this.ucase ? " SUBPARTITIONS " : " subpartitions ");
            x.getSubPartitionsCount().accept(this);
         }

         if (x.getStoreIn().size() > 0) {
            this.println();
            this.print0(this.ucase ? "STORE IN (" : "store in (");
            this.printAndAccept(x.getStoreIn(), ", ");
            this.print(')');
         }
      }

      return false;
   }

   public void endVisit(DmAlterTableSetPartitionTemplate x) {
   }

   public boolean visit(DmAlterTableRenamePartition x) {
      this.print0(this.ucase ? "RENAME " : "rename ");
      this.print(x.getType().name().toUpperCase(Locale.ROOT));
      this.print0(" ");
      x.getName().accept(this);
      this.print0(this.ucase ? " TO " : " to ");
      x.getTo().accept(this);
      return false;
   }

   public void endVisit(DmAlterTableRenamePartition x) {
   }

   public boolean visit(DmAlterTableMovePartition x) {
      this.print0(this.ucase ? "MOVE " : "move ");
      this.print(x.getType().name().toUpperCase(Locale.ROOT));
      this.print0(" ");
      x.getName().accept(this);
      this.print0(this.ucase ? " TABLESPACE " : " tablespace ");
      x.getTablespace().accept(this);
      return false;
   }

   public void endVisit(DmAlterTableMovePartition x) {
   }

   public boolean visit(DmAlterTableModify x) {
      this.print0(this.ucase ? "MODIFY (" : "modify (");
      ++this.indentCount;
      int i = 0;

      for(int size = x.getColumns().size(); i < size; ++i) {
         this.println();
         SQLColumnDefinition column = (SQLColumnDefinition)x.getColumns().get(i);
         column.accept(this);
         if (i != size - 1) {
            this.print0(", ");
         }
      }

      --this.indentCount;
      this.println();
      this.print(')');
      return false;
   }

   public void endVisit(DmAlterTableModify x) {
   }

   public boolean visit(DmAlterTableAddConstraint x) {
      this.print0(this.ucase ? "ADD " : "add ");
      x.getConstraint().accept(this);
      if (x.getCheck() != null && x.getCheck()) {
         this.print0(this.ucase ? " CHECK" : " check");
      }

      if (x.getCheck() != null && !x.getCheck()) {
         this.print0(this.ucase ? " NOT CHECK" : " not check");
      }

      if (x.getEnable() != null && x.getEnable()) {
         this.print0(this.ucase ? " ENABLE " : " enable");
      }

      if (x.getEnable() != null && !x.getEnable()) {
         this.print0(this.ucase ? " DISABLE " : " disable");
      }

      return false;
   }

   public void endVisit(DmAlterTableAddConstraint x) {
   }

   public boolean visit(SQLAlterDatabaseStatement x) {
      this.print0(this.ucase ? "ALTER DATABASE " : "alter database ");
      if (x.getItem() != null) {
         x.getItem().accept(this);
      }

      return false;
   }

   public boolean visit(DmAlterDatabaseStatus x) {
      this.print0(this.ucase ? x.getStatus().name().toUpperCase(Locale.ROOT) : x.getStatus().name().toLowerCase(Locale.ROOT));
      if (x.getForce() != null && x.getForce()) {
         this.print0(this.ucase ? " FORCE" : " force");
      }

      if (x.getCurrent() != null && x.getCurrent()) {
         this.print0(this.ucase ? " CURRENT" : " current");
      }

      return false;
   }

   public void endVisit(DmAlterDatabaseStatus x) {
   }

   public boolean visit(DmAlterDatabaseResizeLogfile x) {
      this.print0(this.ucase ? " RESIZE LOGFILE " : " resize logfile ");
      x.getFilepath().accept(this);
      this.print0(this.ucase ? " TO " : " to ");
      x.getFilesize().accept(this);
      return false;
   }

   public void endVisit(DmAlterDatabaseResizeLogfile x) {
   }

   public boolean visit(DmLogfile x) {
      x.getFilepath().accept(this);
      this.print0(this.ucase ? " SIZE " : " size ");
      x.getFilesize().accept(this);
      return false;
   }

   public void endVisit(DmLogfile x) {
   }

   public boolean visit(DmAlterDatabaseAddLogfile x) {
      if (x.getNode() != null && x.getNode()) {
         this.print0(this.ucase ? "ADD NODE LOGFILE " : "add node logfile ");
      } else {
         this.print0(this.ucase ? "ADD LOGFILE " : "add logfile ");
      }

      this.printAndAccept(x.getFileItems(), ",");
      return false;
   }

   public void endVisit(DmAlterDatabaseAddLogfile x) {
   }

   public boolean visit(DmAlterDatabaseRenameLogfile x) {
      this.print0(this.ucase ? "RENAME LOGFILE " : "rename logfile ");
      this.printAndAccept(x.getFilepathItems(), ",");
      this.print0(this.ucase ? " TO " : " to ");
      this.printAndAccept(x.getNewFilepathItems(), ",");
      return false;
   }

   public void endVisit(DmAlterDatabaseRenameLogfile x) {
   }

   public boolean visit(DmAlterDatabaseMoveDatafile x) {
      this.print0(this.ucase ? "MOVE DATAFILE " : "move datafile ");
      x.getFilepath().accept(this);
      this.print0(this.ucase ? " TO " : " to ");
      x.getNewFilepath().accept(this);
      if (x.getKeep() != null && x.getKeep()) {
         this.print0(this.ucase ? " KEEP" : " keep");
      }

      if (x.getReuse() != null && x.getReuse()) {
         this.print0(this.ucase ? " REUSE" : " reuse");
      }

      return false;
   }

   public void endVisit(DmAlterDatabaseMoveDatafile x) {
   }

   public boolean visit(DmAlterDatabaseArchivelog x) {
      this.print0(this.ucase ? x.getAction().name().toUpperCase(Locale.ROOT) : x.getAction().name().toLowerCase(Locale.ROOT));
      this.print0(this.ucase ? " ARCHIVELOG " : " archivelog ");
      x.getConfigure_clause().accept(this);
      return false;
   }

   public void endVisit(DmAlterDatabaseArchivelog x) {
   }

   public boolean visit(DmDropUserStatement x) {
      this.print0(this.ucase ? "DROP USER " : "drop user ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

      this.printAndAccept(x.getUsers(), ", ");
      if (x.getCascade() != null) {
         this.print0(this.ucase ? " CASCADE" : " cascade");
      }

      if (x.getRestrict() != null) {
         this.print0(this.ucase ? " RESTRICT" : " restrict");
      }

      return false;
   }

   public void endVisit(DmDropUserStatement x) {
   }

   public boolean visit(SQLDropPackageStatement x) {
      this.print0(this.ucase ? "DROP PACKAGE " : "drop package ");
      if (x.isBody()) {
         this.print0(this.ucase ? "BODY " : "body ");
      }

      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

      x.getName().accept(this);
      return false;
   }

   public boolean visit(DmCreateSchemaStatement x) {
      this.printUcase("CREATE SCHEMA ");
      if (x.getSchemaName() != null) {
         x.getSchemaName().accept(this);
      }

      if (x.isAuthorization()) {
         this.printUcase("AUTHORIZATION ");
         x.getUserName().accept(this);
      }

      if (x.getStmtList().size() > 0) {
         this.println();
         this.printlnAndAccept(x.getStmtList(), " ");
      }

      return false;
   }

   public void endVisit(DmCreateSchemaStatement x) {
   }

   public boolean visit(DmSQLTruncateStatement x) {
      this.print0(this.ucase ? "TRUNCATE TABLE " : "truncate table ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

      this.printAndAccept(x.getTableSources(), ", ");
      this.print0(this.ucase ? " PARTITION (" : " partition (");
      x.getPartitionName().accept(this);
      this.print(')');
      return false;
   }

   public void endVisit(DmSQLTruncateStatement x) {
   }

   public boolean visit(DmCreateIndexStatement x) {
      this.print0(this.ucase ? "CREATE " : "create ");
      if (x.isOrReplace()) {
         this.print0(this.ucase ? "OR REPLACE " : "or replace ");
      }

      if (x.isContext()) {
         this.print0(this.ucase ? "CONTEXT " : "context ");
      }

      if (x.isCluster()) {
         this.print0(this.ucase ? "CLUSTER " : "cluster ");
      }

      if (x.isNotPartial()) {
         this.print0(this.ucase ? "NOT PARTIAL " : "not partial ");
      }

      if (x.getType() != null) {
         this.print0(x.getType());
         this.print(' ');
      }

      this.print0(this.ucase ? "INDEX " : "index ");
      x.getName().accept(this);
      this.print0(this.ucase ? " ON " : " on ");
      x.getTable().accept(this);
      List<SQLSelectOrderByItem> items = x.getItems();
      if (items.size() > 0) {
         this.print('(');
         this.printAndAccept(items, ", ");
         this.print(')');
      }

      if (x.isGlobal()) {
         this.print(' ');
         this.print0(this.ucase ? "GLOBAL" : "global");
      }

      if (x.getSort() != null && !x.getSort()) {
         this.print(' ');
         this.print0(this.ucase ? "NOSORT" : "nosort");
      }

      if (x.isReverse()) {
         this.print(' ');
         this.print0(this.ucase ? "REVERSE" : "reverse");
      }

      this.printOracleSegmentAttributes(x);
      if (x.isOnline()) {
         this.print0(this.ucase ? " ONLINE" : " online");
      }

      if (x.getLexer() != null) {
         this.print0(this.ucase ? " LEXER " : " lexer ");
         x.getLexer().accept(this);
      }

      if (x.isSync()) {
         this.print0(this.ucase ? " SYNC" : " sync");
         if (x.isTransaction()) {
            this.print0(this.ucase ? " TRANSACTION" : " transaction");
         }
      }

      return false;
   }

   public void endVisit(DmCreateIndexStatement x) {
   }

   public boolean visit(DmAlterIndexStatement x) {
      this.print0(this.ucase ? "ALTER" : "alter");
      if (x.getContext() != null && x.getContext()) {
         this.print0(this.ucase ? " CONTEXT" : " context");
      }

      this.print0(this.ucase ? " INDEX " : " index ");
      x.getName().accept(this);
      if (x.getRenameTo() != null) {
         this.print0(this.ucase ? " RENAME TO " : " rename to ");
         x.getRenameTo().accept(this);
      }

      SQLExprTableSource table = x.getTable();
      if (table != null) {
         this.print0(this.ucase ? " ON " : " on ");
         table.accept(this);
      }

      if (x.getPartitions().size() > 0) {
         this.print0(this.ucase ? " PARTITION (" : " partition (");
         this.printAndAccept(x.getPartitions(), ", ");
         this.print(')');
      }

      if (x.getVisible() != null && x.getVisible()) {
         this.print0(this.ucase ? " VISIBLE" : " visible");
      }

      if (x.getVisible() != null && !x.getVisible()) {
         this.print0(this.ucase ? " INVISIBLE" : " invisible");
      }

      if (x.isCompile()) {
         this.print0(this.ucase ? " COMPILE" : " compile");
      }

      if (x.getEnable() != null && x.getEnable().equals(Boolean.TRUE)) {
         this.print0(this.ucase ? " ENABLE" : " enable");
      }

      if (x.getEnable() != null && x.getEnable().equals(Boolean.FALSE)) {
         this.print0(this.ucase ? " DISABLE" : " disable");
      }

      if (x.isUnusable()) {
         this.print0(this.ucase ? " UNUSABLE" : " unusable");
      }

      if (x.getMonitoringUsage() != null) {
         this.print0(this.ucase ? " MONITORING USAGE" : " monitoring usage");
      }

      if (x.getMonitoringUsage() != null) {
         this.print0(this.ucase ? " NOMONITORING USAGE" : " nomonitoring usage");
      }

      if (x.getIncrement() != null) {
         this.print0(this.ucase ? " INCREMENT" : " increment");
      }

      if (x.getOptimize() != null) {
         this.print0(this.ucase ? " OPTIMIZE" : " optimize");
      }

      if (x.getRebuild() != null) {
         this.print(' ');
         x.getRebuild().accept(this);
      }

      if (x.getParallel() != null) {
         this.print0(this.ucase ? " PARALLEL" : " parallel");
         x.getParallel().accept(this);
      }

      if (x.getOnline() != null && x.getOnline()) {
         this.print0(this.ucase ? " ONLINE" : " online");
      }

      if (x.getLexer() != null) {
         this.print0(this.ucase ? " LEXER " : " lexer ");
         x.getLexer().accept(this);
      }

      return false;
   }

   public void endVisit(DmAlterIndexStatement x) {
   }

   public boolean visit(SQLDropIndexStatement x) {
      this.print0(this.ucase ? "DROP" : "drop");
      if (x.isContext()) {
         this.print0(this.ucase ? " CONTEXT" : " context");
      }

      this.print0(this.ucase ? " INDEX " : " index ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? " IF EXISTS " : " if exists ");
      }

      x.getIndexName().accept(this);
      SQLExprTableSource table = x.getTableName();
      if (table != null) {
         this.print0(this.ucase ? " ON " : " on ");
         table.accept(this);
      }

      return false;
   }

   public boolean visit(DmAlterViewStatment x) {
      this.print0(this.ucase ? "ALTER VIEW " : "alter view ");
      x.getName().accept(this);
      this.print0(this.ucase ? " COMPILE" : " compile");
      return false;
   }

   public void endVisit(DmAlterViewStatment x) {
   }

   public boolean visit(DmSetTransactionStatement x) {
      this.print0(this.ucase ? "SET TRANSACTION" : "set transaction");
      if (x.getLevel() != null) {
         this.print0(this.ucase ? " ISOLATION LEVEL " : " isolation level ");
         this.print0(x.getLevel().name);
      }

      if (x.isReadOnly()) {
         this.print0(this.ucase ? " READ ONLY" : " read only");
      }

      if (x.isReadWrite()) {
         this.print0(this.ucase ? " READ WRITE" : " read write");
      }

      return false;
   }

   public void endVisit(DmSetTransactionStatement x) {
   }

   public boolean visit(DmLockTableStatement x) {
      this.print0(this.ucase ? "LOCK TABLE " : "lock table ");
      x.getName().accept(this);
      this.print0(this.ucase ? " IN" : " in");
      if (x.isIntent()) {
         this.print0(this.ucase ? " INTENT" : " intent");
      }

      if (x.isExclusive()) {
         this.print0(this.ucase ? " EXCLUSIVE" : " exclusive");
      }

      if (x.isShare()) {
         this.print0(this.ucase ? " SHARE" : " share");
      }

      this.print0(this.ucase ? " MODE" : " mode");
      if (x.isNowait()) {
         this.print0(this.ucase ? " NOWAIT" : " nowait");
      }

      return false;
   }

   public void endVisit(DmLockTableStatement x) {
   }

   public boolean visit(DmCreateTriggerStatement x) {
      this.print0(this.ucase ? "CREATE " : "create ");
      if (x.isOrReplace()) {
         this.print0(this.ucase ? "OR REPLACE " : "or replace ");
      }

      this.print0(this.ucase ? "TRIGGER " : "trigger ");
      x.getName().accept(this);
      if (x.isWithEncryption()) {
         this.print0(this.ucase ? " WITH ENCRYPTION" : " with encryption");
      }

      ++this.indentCount;
      this.println();
      if (SQLCreateTriggerStatement.TriggerType.INSTEAD_OF.equals(x.getTriggerType())) {
         this.print0(this.ucase ? "INSTEAD OF" : "instead of");
      } else {
         String triggerTypeName = x.getTriggerType().name();
         this.print0(this.ucase ? triggerTypeName : triggerTypeName.toLowerCase());
      }

      if (x.getEvents().size() > 0) {
         this.print0(" ");
         this.printAndAccept(x.getEvents(), " or ");
      }

      if (x.isInsert()) {
         this.print0(this.ucase ? " INSERT" : " insert");
      }

      if (x.isDelete()) {
         if (x.isInsert()) {
            this.print0(this.ucase ? " OR" : " or");
         }

         this.print0(this.ucase ? " DELETE" : " delete");
      }

      if (x.isUpdate()) {
         if (x.isInsert() || x.isDelete()) {
            this.print0(this.ucase ? " OR" : " or");
         }

         this.print0(this.ucase ? " UPDATE" : " update");

         for(SQLName colum : x.getUpdateOfColumns()) {
            this.print(' ');
            colum.accept(this);
         }
      }

      this.println();
      if (x.isLocal()) {
         this.print0(this.ucase ? "LOCAL " : "local ");
      }

      this.print0(this.ucase ? "ON " : "on ");
      if (x.getOn() != null) {
         x.getOn().accept(this);
      }

      if (x.isDatabase()) {
         this.print0(this.ucase ? "DATABASE " : "database ");
      }

      if (x.isSchema()) {
         if (x.getSchemaName() != null) {
            x.getSchemaName().accept(this);
            this.print0(".");
         }

         this.print0(this.ucase ? "SCHEMA " : "schema ");
      }

      if (x.getOldRow() != null || x.getNewRow() != null) {
         this.println();
         this.print0(this.ucase ? "REFERENCING" : "referencing");
         if (x.getNewRow() != null) {
            this.print0(this.ucase ? " NEW ROW AS " : " new row as ");
            x.getNewRow().accept(this);
         }

         if (x.getOldRow() != null) {
            this.print0(this.ucase ? " OLD ROW AS " : " old row as ");
            x.getOldRow().accept(this);
         }
      }

      if (x.getTimer() != null) {
         x.getTimer().accept(this);
      }

      if (x.isForEachRow()) {
         this.println();
         this.print0(this.ucase ? "FOR EACH ROW" : "for each row");
      }

      if (x.isForEachStatement()) {
         this.println();
         this.print0(this.ucase ? "FOR EACH STATEMENT" : "for each statement");
      }

      SQLExpr when = x.getWhen();
      if (when != null) {
         this.println();
         this.print0(this.ucase ? "WHEN( " : "when( ");
         when.accept(this);
         this.print0(")");
      }

      ++this.indentCount;
      this.println();
      x.getBody().accept(this);
      return false;
   }

   public void endVisit(DmCreateTriggerStatement x) {
   }

   public boolean visit(DmCreateSynonymStatement x) {
      if (x.isOrReplace()) {
         this.print0(this.ucase ? "CREATE OR REPLACE " : "create or replace ");
      } else {
         this.print0(this.ucase ? "CREATE " : "create ");
      }

      if (x.isPublic()) {
         this.print0(this.ucase ? "PUBLIC " : "public ");
      }

      this.print0(this.ucase ? "SYNONYM " : "synonym ");
      x.getName().accept(this);
      this.print0(this.ucase ? " FOR " : " for ");
      x.getObject().accept(this);
      return false;
   }

   public void endVisit(DmCreateSynonymStatement x) {
   }

   public boolean visit(SQLIfStatement x) {
      this.print0(this.ucase ? "IF " : "if ");
      int lines = this.lines;
      ++this.indentCount;
      x.getCondition().accept(this);
      --this.indentCount;
      if (lines != this.lines) {
         this.println();
      } else {
         this.print(' ');
      }

      this.print0(this.ucase ? "THEN" : "then");
      ++this.indentCount;
      int i = 0;

      for(int size = x.getStatements().size(); i < size; ++i) {
         this.println();
         SQLStatement item = (SQLStatement)x.getStatements().get(i);
         item.accept(this);
      }

      --this.indentCount;

      for(SQLIfStatement.ElseIf elseIf : x.getElseIfList()) {
         this.println();
         elseIf.accept(this);
      }

      if (x.getElseItem() != null) {
         this.println();
         x.getElseItem().accept(this);
      }

      this.println();
      this.print0(this.ucase ? "END IF" : "end if");
      return false;
   }

   public boolean visit(DmAlterTriggerStatement x) {
      this.print0(this.ucase ? "ALTER TRIGGER " : "alter trigger ");
      x.getName().accept(this);
      if (x.isCompile()) {
         this.print0(this.ucase ? " COMPILE" : " compile");
         if (x.isDebug()) {
            this.print0(this.ucase ? " DEBUG" : " debug");
         }
      }

      if (x.getEnable() != null) {
         if (x.getEnable()) {
            this.print0(this.ucase ? " ENABLE" : " enable");
         } else {
            this.print0(this.ucase ? " DISABLE" : " disable");
         }
      }

      return false;
   }

   public void endVisit(DmAlterTriggerStatement x) {
   }

   public boolean visit(SQLAssignItem x) {
      x.getTarget().accept(this);
      this.print0(" := ");
      x.getValue().accept(this);
      return false;
   }

   public boolean visit(DmPrintStatement x) {
      this.print0("PRINT ");
      x.getString().accept(this);
      return false;
   }

   public void endVisit(DmPrintStatement x) {
   }

   public boolean visit(DmExecuteImmediateStatement x) {
      this.print0(this.ucase ? "EXECUTE IMMEDIATE " : "execute immediate ");
      x.getDynamicSql().accept(this);
      List<SQLExpr> into = x.getInto();
      if (into.size() > 0) {
         this.print0(this.ucase ? " INTO " : " into ");
         this.printAndAccept(into, ", ");
      }

      List<SQLArgument> using = x.getArguments();
      if (using.size() > 0) {
         this.print0(this.ucase ? " USING " : " using ");
         this.printAndAccept(using, ", ");
      }

      List<SQLExpr> returnInto = x.getReturnInto();
      if (returnInto.size() > 0) {
         this.print0(this.ucase ? " RETURNNING INTO " : " returnning into ");
         this.printAndAccept(returnInto, ", ");
      }

      return false;
   }

   public void endVisit(DmExecuteImmediateStatement x) {
   }

   protected void printParamDefaultValue(SQLParameter x) {
      if (x.getDefaultValue() != null) {
         if (x.getDataType() != null && x.getDataType().toString().equals("EXCEPTION")) {
            this.print0(" FOR ");
         } else {
            this.print0(" := ");
         }

         x.getDefaultValue().accept(this);
      }

   }

   public boolean visit(SQLWhileStatement x) {
      String label = x.getLabelName();
      if (label != null && label.length() != 0) {
         this.print0(x.getLabelName());
         this.print0(": ");
      }

      this.print0(this.ucase ? "WHILE " : "while ");
      x.getCondition().accept(this);
      this.print0(this.ucase ? " LOOP" : " loop");
      this.println();
      int i = 0;

      for(int size = x.getStatements().size(); i < size; ++i) {
         SQLStatement item = (SQLStatement)x.getStatements().get(i);
         item.accept(this);
         if (i != size - 1) {
            this.println();
         }
      }

      this.println();
      this.print0(this.ucase ? "END LOOP;" : "end loop;");
      if (label != null && label.length() != 0) {
         this.print(' ');
         this.print0(label);
      }

      return false;
   }

   public boolean visit(DmRaiseStatement x) {
      this.print0(this.ucase ? "RAISE" : "raise");
      if (x.getException() != null) {
         this.print(' ');
         x.getException().accept(this);
      }

      this.print(';');
      return false;
   }

   public void endVisit(DmRaiseStatement x) {
   }

   public boolean visit(DmExitStatement x) {
      this.print0(this.ucase ? "EXIT" : "exit");
      if (x.getLabel() != null) {
         this.print(' ');
         this.print0(x.getLabel());
      }

      if (x.getWhen() != null) {
         this.print0(this.ucase ? " WHEN " : " when ");
         x.getWhen().accept(this);
      }

      return false;
   }

   public void endVisit(DmExitStatement x) {
   }

   public boolean visit(DmExceptionStatement x) {
      return false;
   }

   public void endVisit(DmExceptionStatement x) {
   }

   public boolean visit(SQLBlockStatement x) {
      if (x.getParameters().size() != 0) {
         this.print0(this.ucase ? "DECLARE" : "declare");
         this.println();
         ++this.indentCount;
         if (x.getParent() instanceof SQLCreateProcedureStatement) {
            SQLCreateProcedureStatement procedureStatement = (SQLCreateProcedureStatement)x.getParent();
            if (procedureStatement.isCreate()) {
               this.printIndent();
            }
         }

         int i = 0;

         for(int size = x.getParameters().size(); i < size; ++i) {
            if (i != 0) {
               this.println();
            }

            SQLParameter param = (SQLParameter)x.getParameters().get(i);
            param.accept(this);
            this.print(';');
         }

         --this.indentCount;
         this.println();
      }

      this.print0(this.ucase ? "BEGIN" : "begin");
      ++this.indentCount;
      int i = 0;

      for(int size = x.getStatementList().size(); i < size; ++i) {
         this.println();
         SQLStatement stmt = (SQLStatement)x.getStatementList().get(i);
         stmt.accept(this);
      }

      --this.indentCount;
      SQLStatement exception = x.getException();
      if (exception != null) {
         this.println();
         exception.accept(this);
      }

      this.println();
      this.print0(this.ucase ? "END;" : "end;");
      return false;
   }

   public boolean visit(DmExceptionStatement.Item x) {
      this.print0(this.ucase ? "WHEN " : "when ");
      x.getWhen().accept(this);
      this.print0(this.ucase ? " THEN" : " then");
      ++this.indentCount;
      if (x.getStatements().size() > 1) {
         this.println();
      } else if (x.getStatements().size() == 1 && x.getStatements().get(0) instanceof SQLIfStatement) {
         this.println();
      } else {
         this.print(' ');
      }

      int i = 0;

      for(int size = x.getStatements().size(); i < size; ++i) {
         if (i != 0 && size > 1) {
            this.println();
         }

         SQLStatement stmt = (SQLStatement)x.getStatements().get(i);
         stmt.accept(this);
      }

      --this.indentCount;
      return false;
   }

   public void endVisit(DmExceptionStatement.Item x) {
   }

   public boolean visit(SQLCreateFunctionStatement x) {
      boolean create = x.isCreate();
      if (!create) {
         this.print0(this.ucase ? "FUNCTION " : "function ");
      } else if (x.isOrReplace()) {
         this.print0(this.ucase ? "CREATE OR REPLACE FUNCTION " : "create or replace function ");
      } else {
         this.print0(this.ucase ? "CREATE FUNCTION " : "create function ");
      }

      x.getName().accept(this);
      int paramSize = x.getParameters().size();
      if (paramSize > 0) {
         this.print0(" (");
         ++this.indentCount;
         this.println();

         for(int i = 0; i < paramSize; ++i) {
            if (i != 0) {
               this.print0(", ");
               this.println();
            }

            SQLParameter param = (SQLParameter)x.getParameters().get(i);
            param.accept(this);
         }

         --this.indentCount;
         this.println();
         this.print(')');
      }

      String wrappedSource = x.getWrappedSource();
      if (wrappedSource != null) {
         this.print0(this.ucase ? " WRAPPED " : " wrapped ");
         this.print0(wrappedSource);
         if (x.isAfterSemi()) {
            this.print(';');
         }

         return false;
      } else {
         this.println();
         this.print(this.ucase ? "RETURN " : "return ");
         x.getReturnDataType().accept(this);
         if (x.isResultCache()) {
            this.print(this.ucase ? " RESULT_CACHE " : " result_cache ");
         }

         if (x.isDeterministic()) {
            this.print(this.ucase ? " DETERMINISTIC " : " deterministic ");
         }

         if (x.isPipelined()) {
            this.print(this.ucase ? " PIPELINED " : " pipelined ");
         }

         SQLName authid = x.getAuthid();
         if (authid != null) {
            this.print(this.ucase ? " AUTHID " : " authid ");
            authid.accept(this);
         }

         SQLStatement block = x.getBlock();
         if (block != null && !create) {
            this.println();
            this.println("IS");
         } else {
            this.println();
            if (block instanceof SQLBlockStatement) {
               SQLBlockStatement blockStatement = (SQLBlockStatement)block;
               if (blockStatement.getParameters().size() > 0 || authid != null) {
                  this.println(this.ucase ? "AS" : "as");
               }
            }
         }

         String javaCallSpec = x.getJavaCallSpec();
         if (javaCallSpec != null) {
            this.print0(this.ucase ? "LANGUAGE JAVA NAME '" : "language java name '");
            this.print0(javaCallSpec);
            this.print('\'');
            return false;
         } else {
            if (x.isParallelEnable()) {
               this.print0(this.ucase ? "PARALLEL_ENABLE" : "parallel_enable");
               this.println();
            }

            if (x.isAggregate()) {
               this.print0(this.ucase ? "AGGREGATE" : "aggregate");
               this.println();
            }

            SQLName using = x.getUsing();
            if (using != null) {
               this.print0(this.ucase ? "USING " : "using ");
               using.accept(this);
            }

            boolean afterSemi = false;
            if (block != null) {
               block.accept(this);
               if (block instanceof SQLBlockStatement && ((SQLBlockStatement)block).getStatementList().size() > 0) {
                  afterSemi = ((SQLStatement)((SQLBlockStatement)block).getStatementList().get(0)).isAfterSemi();
               }
            }

            if (!afterSemi && x.getParent() instanceof DmCreatePackageStatement) {
               this.print(';');
            }

            return false;
         }
      }
   }

   public boolean visit(SQLParameter x) {
      SQLName name = x.getName();
      if (x.getDataType().getName().equalsIgnoreCase("CURSOR")) {
         this.print0(this.ucase ? "CURSOR " : "cursor ");
         x.getName().accept(this);
         this.print0(this.ucase ? " IS" : " is");
         ++this.indentCount;
         this.println();
         SQLSelect select = ((SQLQueryExpr)x.getDefaultValue()).getSubQuery();
         select.accept(this);
         --this.indentCount;
      } else {
         if (x.isMap()) {
            this.print0(this.ucase ? "MAP MEMBER " : "map member ");
         } else if (x.isOrder()) {
            this.print0(this.ucase ? "ORDER MEMBER " : "order member ");
         } else if (x.isMember()) {
            this.print0(this.ucase ? "MEMBER " : "member ");
         }

         SQLDataType dataType = x.getDataType();
         if (DbType.oracle != this.dbType && !(dataType instanceof OracleFunctionDataType) && !(dataType instanceof OracleProcedureDataType)) {
            x.getName().accept(this);
            this.print(' ');
            if (x.getParamType() == SQLParameter.ParameterType.IN) {
               boolean skip = DbType.mysql == this.dbType && x.getParent() instanceof SQLCreateFunctionStatement;
               if (!skip) {
                  this.print0(this.ucase ? "IN " : "in ");
               }
            } else if (x.getParamType() == SQLParameter.ParameterType.OUT) {
               this.print0(this.ucase ? "OUT " : "out ");
            } else if (x.getParamType() == SQLParameter.ParameterType.INOUT) {
               this.print0(this.ucase ? "INOUT " : "inout ");
            }
         } else {
            if (dataType instanceof OracleFunctionDataType) {
               OracleFunctionDataType functionDataType = (OracleFunctionDataType)dataType;
               this.visit((OracleFunctionDataType)functionDataType);
               return false;
            }

            if (dataType instanceof OracleProcedureDataType) {
               OracleProcedureDataType procedureDataType = (OracleProcedureDataType)dataType;
               this.visit((OracleProcedureDataType)procedureDataType);
               return false;
            }

            String dataTypeName = dataType.getName();
            boolean printType = dataTypeName.startsWith("TABLE OF") && x.getDefaultValue() == null || dataTypeName.equalsIgnoreCase("REF CURSOR") || dataTypeName.startsWith("VARRAY(");
            if (printType) {
               this.print0(this.ucase ? "TYPE " : "type ");
            }

            name.accept(this);
            if (x.getParamType() == SQLParameter.ParameterType.IN) {
               this.print0(this.ucase ? " IN " : " in ");
            } else if (x.getParamType() == SQLParameter.ParameterType.OUT) {
               this.print0(this.ucase ? " OUT " : " out ");
            } else if (x.getParamType() == SQLParameter.ParameterType.INOUT) {
               this.print0(this.ucase ? " IN OUT " : " in out ");
            } else {
               this.print(' ');
            }

            if (x.isNoCopy()) {
               this.print0(this.ucase ? "NOCOPY " : "nocopy ");
            }

            if (x.isConstant()) {
               this.print0(this.ucase ? "CONSTANT " : "constant ");
            }

            if (printType) {
               this.print0(this.ucase ? "IS " : "is ");
            }
         }

         dataType.accept(this);
         this.printParamDefaultValue(x);
      }

      return false;
   }

   public boolean visit(DmContinueStatement x) {
      this.print0(this.ucase ? "CONTINUE" : "continue");
      String label = x.getLabel();
      if (label != null) {
         this.print(' ');
         this.print0(label);
      }

      if (x.getWhen() != null) {
         this.print0(this.ucase ? " WHEN " : " when ");
         x.getWhen().accept(this);
      }

      return false;
   }

   public void endVisit(DmContinueStatement x) {
   }

   public void endVisit(DMIntervalExpr x) {
   }

   public void endVisit(DmReturningClause x) {
   }

   public void endVisit(DmMultiInsertStatement x) {
   }

   public void endVisit(DmInsertStatement x) {
   }

   public void endVisit(DmMultiInsertStatement.ConditionalInsertClause x) {
   }

   public void endVisit(DmMultiInsertStatement.ConditionalInsertClauseItem x) {
   }

   public void endVisit(DmMultiInsertStatement.InsertIntoClause x) {
   }

   public void endVisit(DmSelectSubqueryTableSource x) {
   }

   public void endVisit(DmSelectTableReference x) {
   }

   public void endVisit(DmPartitionExtensionClause x) {
   }

   public void endVisit(DmUpdateStatement x) {
   }

   public void endVisit(DmAnalytic x) {
   }

   public void endVisit(DmAnalyticWindowing x) {
   }

   public void endVisit(DmSampleClause x) {
   }

   public boolean visit(DmCreateTableStatement.OIDIndex x) {
      return false;
   }

   public void endVisit(DmCreateTableStatement.OIDIndex x) {
   }

   public boolean visit(DmCreateTableStatement.Organization x) {
      return false;
   }

   public void endVisit(DmCreateTableStatement.Organization x) {
   }

   public boolean visit(DmGotoStatement x) {
      this.print0(this.ucase ? "GOTO " : "GOTO ");
      x.getLabel().accept(this);
      return false;
   }

   public void endVisit(DmGotoStatement x) {
   }

   public boolean visit(DmLabelStatement x) {
      this.print0("<<");
      x.getLabel().accept(this);
      this.print0(">>");
      return false;
   }

   public void endVisit(DmLabelStatement x) {
   }

   public boolean visit(SQLSetStatement x) {
      this.print0(this.ucase ? "SET " : "set ");
      SQLSetStatement.Option option = x.getOption();
      if (option != null) {
         this.print(option.name());
         this.print(' ');
      }

      List<SQLAssignItem> items = x.getItems();

      for(int i = 0; i < items.size(); ++i) {
         if (i != 0) {
            this.print0(", ");
         }

         SQLAssignItem item = (SQLAssignItem)x.getItems().get(i);
         item.getTarget().accept(this);
         SQLExpr value = item.getValue();
         if (!(value instanceof SQLIdentifierExpr) || ((SQLIdentifierExpr)value).nameHashCode64() != FnvHash.Constants.ON && ((SQLIdentifierExpr)value).nameHashCode64() != FnvHash.Constants.OFF) {
            this.print0(" = ");
         } else {
            this.print(' ');
         }

         value.accept(this);
      }

      return false;
   }

   public boolean visit(DmDataTypeIntervalYear x) {
      this.print0(x.getName());
      if (x.getArguments().size() > 0) {
         this.print('(');
         ((SQLExpr)x.getArguments().get(0)).accept(this);
         this.print(')');
      }

      if (x.isToMonth()) {
         this.print0(this.ucase ? " TO MONTH" : " to month");
      }

      return false;
   }

   public void endVisit(DmDataTypeIntervalYear x) {
   }

   public boolean visit(DmCreateTableStatement.PARMS x) {
      this.println();
      this.print0(x.getType().name);
      this.print0(" ");
      x.getExpr().accept(this);
      return false;
   }

   public void endVisit(DmCreateTableStatement.PARMS x) {
   }

   public boolean visit(DmAlterPackageCompile x) {
      this.print0(this.ucase ? "ALTER PACKAGE " : "alter package ");
      x.getName().accept(this);
      this.print0(this.ucase ? " COMPILE" : " compile");
      if (x.isDebug()) {
         this.print0(this.ucase ? " DEBUG" : " debug");
      }

      return false;
   }

   public void endVisit(DmAlterPackageCompile x) {
   }

   public boolean visit(DmCreateTriggerStatement.Timer x) {
      this.println();
      if (x.getType() == DmCreateTriggerStatement.Timer.Type.ONCE) {
         this.print0(this.ucase ? "FOR ONCE AT DATETIME " : "for once at datetime ");
         x.getDatetime().accept(this);
      } else {
         if (x.getMonth_rate() != null) {
            this.print0(this.ucase ? "FOR EACH " : "for each ");
            x.getMonth_rate().accept(this);
            this.print0(this.ucase ? " MONTH " : " month ");
            if (x.getDay_in_month_week() != null) {
               x.getDay_in_month_week().accept(this);
            } else {
               this.print0(this.ucase ? "DAY " : "day ");
               x.getDay_in_month().accept(this);
            }
         } else if (x.getWeek_rate() != null) {
            this.print0(this.ucase ? "FOR EACH " : "for each ");
            x.getWeek_rate().accept(this);
            this.print0(this.ucase ? " WEEK" : " week");
            this.printAndAccept(x.getDay_of_week_list(), ",");
         } else if (x.getDay_rate() != null) {
            this.print0(this.ucase ? "FOR EACH " : "for each ");
            x.getDay_rate().accept(this);
            this.print0(this.ucase ? " DAY" : " day");
         }

         if (x.getOnce_in_day() != null) {
            this.print0(this.ucase ? " AT TIME " : " at time ");
            x.getOnce_in_day().accept(this);
         } else if (x.getDuaringTime() != null) {
            this.print0(" ");
            x.getDuaringTime().accept(this);
            this.print0(this.ucase ? " FOR EACH " : " for each ");
            x.getTimes_in_day().accept(this);
            this.print0(this.ucase ? " MINUTE" : " minute");
         } else if (x.getTimes_in_day() != null) {
            this.print0(this.ucase ? " FOR EACH " : " for each ");
            x.getTimes_in_day().accept(this);
            this.print0(this.ucase ? " MINUTE" : " minute");
         }

         if (x.getDuaringDate() != null) {
            this.println();
            x.getDuaringDate().accept(this);
         }
      }

      if (x.getExec_ep_seqno() != null) {
         this.println();
         this.print0(this.ucase ? "EXECUTE AT " : "execute at");
         x.getExec_ep_seqno().accept(this);
      }

      return false;
   }

   public void endVisit(DmCreateTriggerStatement.Timer x) {
   }

   public boolean visit(DmCreateTriggerStatement.Timer.DayInMonthWeek x) {
      this.print0(this.ucase ? "DAY " : "day ");
      x.getDay().accept(this);
      this.print0(this.ucase ? " OF WEEK " : " of week ");
      if (x.getWeek() != null) {
         x.getWeek().accept(this);
      } else {
         this.print0(this.ucase ? " LAST" : " last");
      }

      return false;
   }

   public void endVisit(DmCreateTriggerStatement.Timer.DayInMonthWeek x) {
   }

   public boolean visit(DmCreateTriggerStatement.Timer.DuaringTime x) {
      this.print0(this.ucase ? "FROM TIME " : "from time ");
      x.getFrom().accept(this);
      if (x.getTo() != null) {
         this.print0(this.ucase ? " TO TIME " : " to time ");
         x.getTo().accept(this);
      }

      return false;
   }

   public void endVisit(DmCreateTriggerStatement.Timer.DuaringTime x) {
   }

   public boolean visit(DmCreateTriggerStatement.Timer.DuaringDate x) {
      this.print0(this.ucase ? "FROM DATETIME " : "from datetime ");
      x.getFrom().accept(this);
      if (x.getTo() != null) {
         this.print0(this.ucase ? " TO DATETIME " : " to datetime ");
         x.getTo().accept(this);
      }

      return false;
   }

   public void endVisit(DmCreateTriggerStatement.Timer.DuaringDate x) {
   }

   public boolean visit(DmCreatePackageStatement x) {
      if (x.isOrReplace()) {
         this.print0(this.ucase ? "CREATE OR REPLACE PACKAGE " : "create or replace procedure ");
      } else {
         this.print0(this.ucase ? "CREATE PACKAGE " : "create package ");
      }

      if (x.isBody()) {
         this.print0(this.ucase ? "BODY " : "body ");
      }

      x.getName().accept(this);
      if (x.isWithEncryption()) {
         this.print(this.ucase ? " WITH ENCRYPTION " : " with encryption ");
      }

      SQLName authid = x.getAuthid();
      if (authid != null) {
         this.print(this.ucase ? " AUTHID " : " authid ");
         authid.accept(this);
      }

      this.print0(this.ucase ? " AS" : " as ");
      ++this.indentCount;
      List<SQLStatement> statements = x.getStatements();
      int i = 0;

      for(int size = statements.size(); i < size; ++i) {
         this.println();
         SQLStatement stmt = (SQLStatement)statements.get(i);
         stmt.accept(this);
      }

      --this.indentCount;
      return false;
   }

   public void endVisit(DmCreatePackageStatement x) {
   }
}
