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

import com.chenyang.druid.DbType;
import com.chenyang.druid.sql.ast.SQLArrayDataType;
import com.chenyang.druid.sql.ast.SQLDataType;
import com.chenyang.druid.sql.ast.SQLExpr;
import com.chenyang.druid.sql.ast.SQLLimit;
import com.chenyang.druid.sql.ast.SQLName;
import com.chenyang.druid.sql.ast.SQLStatement;
import com.chenyang.druid.sql.ast.SQLWindow;
import com.chenyang.druid.sql.ast.expr.SQLBinaryExpr;
import com.chenyang.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.chenyang.druid.sql.ast.expr.SQLIdentifierExpr;
import com.chenyang.druid.sql.ast.expr.SQLListExpr;
import com.chenyang.druid.sql.ast.expr.SQLPropertyExpr;
import com.chenyang.druid.sql.ast.expr.SQLVariantRefExpr;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableItem;
import com.chenyang.druid.sql.ast.statement.SQLAssignItem;
import com.chenyang.druid.sql.ast.statement.SQLColumnConstraint;
import com.chenyang.druid.sql.ast.statement.SQLCommitStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateUserStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLExprTableSource;
import com.chenyang.druid.sql.ast.statement.SQLGrantStatement;
import com.chenyang.druid.sql.ast.statement.SQLIfStatement;
import com.chenyang.druid.sql.ast.statement.SQLPrivilegeItem;
import com.chenyang.druid.sql.ast.statement.SQLRollbackStatement;
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.SQLTableElement;
import com.chenyang.druid.sql.ast.statement.SQLTableSource;
import com.chenyang.druid.sql.ast.statement.SQLTruncateStatement;
import com.chenyang.druid.sql.ast.statement.SQLUpdateSetItem;
import com.chenyang.druid.sql.ast.statement.SQLWithSubqueryClause;
import com.chenyang.druid.sql.dialect.oracle.ast.clause.PartitionExtensionClause;
import com.chenyang.druid.sql.dialect.postgresql.ast.PGSQLIndexSpec;
import com.chenyang.druid.sql.dialect.postgresql.ast.PGSQLPartition;
import com.chenyang.druid.sql.dialect.postgresql.ast.PGSQLPartitionBy;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.PGBoxExpr;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.PGCidrExpr;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.PGCircleExpr;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.PGColumnSimpleDefinitionExpr;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.PGExtractExpr;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.PGInetExpr;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.PGLineSegmentsExpr;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.PGMacAddrExpr;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.PGOptionValue;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.PGPointExpr;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.PGPolygonExpr;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.PGSQLObjectCollection;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.PGSchemaTables;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.PGTypeCastExpr;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.constraint.PGConstraint;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.constraint.PGStorageParameter;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.tablesource.PGExprTableSource;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.tablesource.PGMethodInvokeTableSource;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.tablesource.PGRowsFromTableSource;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.tablesource.PGSubqueryTableSource;
import com.chenyang.druid.sql.dialect.postgresql.ast.expr.tablesource.PGValuesTableSource;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGAlterDatabaseStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGAlterIndexStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGAlterSchemaStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGAlterSequenceStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGAlterTableStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGAlterViewStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGConnectToStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGCreateDatabaseStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGCreateIndexStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGCreateSchemaStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGCreateSeqenceStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGCreateTableSpaceStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGCreateTableStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGCreateViewStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGDeleteStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGDropSchemaStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGDropSequenceStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGFunctionTableSource;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGGrantStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGInsertStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGSelectStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGShowStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGStartTransactionStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGUpdateStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableAddColumn;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableAddConstraint;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableAlterColumn;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableAlterColumnOptions;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableCluster;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableDisableEnabelTrigger;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableDropColumn;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableDropConstraint;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableInheriteOrNotParentTable;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableOf;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableRenameColumn;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableRenameConstraint;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableRenameTo;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableSetNewTableSpace;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableSetReset;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableSetSchema;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableSetTableSpace;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableSetWith;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGAlterTableValidateConstraint;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.alterTable.PGColumnDefinition;
import com.chenyang.druid.sql.visitor.SQLASTOutputVisitor;
import com.chenyang.druid.util.FnvHash;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import util.StringJoin;

public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor {
   public PGOutputVisitor(Appendable appender) {
      super(appender);
      this.dbType = DbType.postgresql;
   }

   public PGOutputVisitor(Appendable appender, boolean parameterized) {
      super(appender, parameterized);
      this.dbType = DbType.postgresql;
   }

   public boolean visit(PGSelectQueryBlock.FetchClause x) {
      this.print0(this.ucase ? "FETCH " : "fetch ");
      if (PGSelectQueryBlock.FetchClause.Option.FIRST.equals(x.getOption())) {
         this.print0(this.ucase ? "FIRST " : "first ");
      } else if (PGSelectQueryBlock.FetchClause.Option.NEXT.equals(x.getOption())) {
         this.print0(this.ucase ? "NEXT " : "next ");
      }

      x.getCount().accept(this);
      this.print0(this.ucase ? " ROWS ONLY" : " rows only");
      return false;
   }

   public boolean visit(SQLIfStatement.Else x) {
      this.print0(this.ucase ? "ELSE" : "else");
      ++this.indentCount;
      this.println();
      int i = 0;

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

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

      --this.indentCount;
      return false;
   }

   public boolean visit(SQLIfStatement.ElseIf x) {
      this.print0(this.ucase ? "ELSE IF " : "else if ");
      x.getCondition().accept(this);
      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;
      return false;
   }

   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(SQLArrayDataType x) {
      x.getComponentType().accept(this);
      this.print('[');
      this.printAndAccept(x.getArguments(), ", ");
      this.print(']');
      return false;
   }

   public boolean visit(PGExprTableSource ts) {
      if (ts.isOnly()) {
         this.print0(" ONLY ");
      }

      if (ts.getExpr() != null) {
         ts.getExpr().accept(this);
      }

      if (ts.getAlias() != null) {
         this.print0(" AS ");
         this.print0(ts.getAlias());
         this.print0(" ");
      }

      if (ts.getColumns() != null && ts.getColumns().size() > 0) {
         this.print0("(");

         for(int i = 0; i < ts.getColumns().size(); ++i) {
            ((SQLName)ts.getColumns().get(i)).accept(this);
            if (i != ts.getColumns().size() - 1) {
               this.print0(",");
            }
         }

         this.print0(")");
      }

      if (ts.getSampling() != null) {
         ts.getSampling().accept(this);
      }

      return false;
   }

   public void endVisit(PGRowsFromTableSource x) {
   }

   public boolean visit(PGRowsFromTableSource ts) {
      this.print0(this.ucase ? "ROWS FROM (" : "rows from (");

      for(int i = 0; i < ts.getInvokers().size(); ++i) {
         ((PGMethodInvokeTableSource)ts.getInvokers().get(i)).accept(this);
         if (i != ts.getInvokers().size() - 1) {
            this.print0(",");
         }
      }

      this.print0(")");
      if (ts.isWithOrdinality()) {
         this.print0(this.ucase ? " WITH ORDINALITY " : " with ordinality ");
      }

      if (ts.getAlias() != null) {
         this.print0(this.ucase ? " AS " : " as ");
         this.print0(ts.getAlias());
      }

      if (ts.getColumns() != null && ts.getColumns().size() > 0) {
         this.print0("(");

         for(int i = 0; i < ts.getColumns().size(); ++i) {
            ((SQLName)ts.getColumns().get(i)).accept(this);
            if (i != ts.getColumns().size() - 1) {
               this.print0(",");
            }
         }

         this.print0(")");
      }

      if (ts.isRowsFrom()) {
         this.print0(") ");
      }

      return false;
   }

   public void endVisit(PGAlterDatabaseStatement x) {
   }

   public boolean visit(PGAlterDatabaseStatement stmt) {
      this.print0(this.ucase ? "ALTER DATABASE " : "alter database ");
      stmt.getName().accept(this);
      this.print0(" ");
      if (stmt.getConnLimit() != null) {
         this.print0(this.ucase ? "WITH CONNECTION LIMIT " : "with connection limit ");
         stmt.getConnLimit().accept(this);
      } else if (stmt.getNewName() != null) {
         this.print0(this.ucase ? "RENAME TO " : "rename to ");
         stmt.getNewName().accept(this);
      } else if (stmt.getNewOwner() != null) {
         this.print0(this.ucase ? "OWNER TO " : "owner to ");
         stmt.getNewOwner().accept(this);
      } else if (stmt.getType() == PGAlterDatabaseStatement.SetType.Set) {
         this.print0(this.ucase ? "SET " : "set ");
         if (stmt.getNewTableSpace() != null) {
            this.print0(this.ucase ? "TABLESPACE " : "tablespace ");
            stmt.getNewTableSpace().accept(this);
         } else {
            stmt.getParamter().accept(this);
            this.print0(" ");
            if (stmt.getValues() != null && stmt.getValues().size() > 0) {
               if (stmt.isSetTo()) {
                  this.print0(this.ucase ? "TO " : "to ");
               } else {
                  this.print0("= ");
               }

               for(int i = 0; i < stmt.getValues().size(); ++i) {
                  ((SQLExpr)stmt.getValues().get(i)).accept(this);
                  if (i != stmt.getValues().size() - 1) {
                     this.print0(",");
                  }
               }
            } else if (stmt.isSetFromCurrent()) {
               this.print0(this.ucase ? "FROM CURRENT" : "from current");
            }
         }
      } else if (stmt.getType() == PGAlterDatabaseStatement.SetType.Reset) {
         this.print0(this.ucase ? "RESET " : "reset ");
         if (stmt.getParamter() != null) {
            stmt.getParamter().accept(this);
         } else {
            this.print0(this.ucase ? "ALL" : "all");
         }
      }

      return false;
   }

   public void endVisit(PGValuesTableSource x) {
   }

   public boolean visit(PGValuesTableSource ts) {
      this.println();
      this.print0("(");
      this.print0(this.ucase ? "VALUES " : "values ");

      for(int i = 0; i < ts.getRows().size(); ++i) {
         PGValuesTableSource.ValueRow row = (PGValuesTableSource.ValueRow)ts.getRows().get(i);
         this.print0("(");

         for(int j = 0; j < row.getVals().size(); ++j) {
            ((SQLExpr)row.getVals().get(j)).accept(this);
            if (j != row.getVals().size() - 1) {
               this.print0(",");
            }
         }

         this.print0(")");
         if (i != ts.getRows().size() - 1) {
            this.print0(",");
         }
      }

      this.print0(") ");
      this.print0(ts.getAlias());
      if (ts.getColumns().size() > 0) {
         List<SQLName> columns = ts.getColumns();
         this.print0(" (");

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

         this.print0(")");
      }

      return false;
   }

   public void endVisit(PGAlterIndexStatement x) {
   }

   public boolean visit(PGAlterIndexStatement x) {
      this.print0(this.ucase ? "ALTER INDEX " : "alter index ");
      if (x.isSetIfExists()) {
         this.printUcase("IF EXISTS ");
      }

      if (x.isSetAllIn()) {
         this.printUcase("ALL IN TABLESPACE ");
      }

      x.getName().accept(this);
      if (x.isSetOwnedBy()) {
         this.printUcase(" OWNED BY ");
      }

      List<SQLExpr> roleList = x.getRoleList();
      if (roleList != null && roleList.size() > 0) {
         this.printAndAccept(roleList, ", ");
      }

      if ("Set".equals(x.getType().name())) {
         this.print0(this.ucase ? " SET " : " set ");
         if (x.getNewTableSpace() != null) {
            this.print0(this.ucase ? "TABLESPACE " + x.getNewTableSpace() : " tablespace " + x.getNewTableSpace());
         }

         List<SQLUpdateSetItem> parameterList = x.getParameterList();
         if (parameterList != null && parameterList.size() > 0) {
            this.print0("(");
            this.printAndAccept(parameterList, ", ");
            this.print0(")");
         }

         if (x.isSetNowait()) {
            this.print0(" NOWAIT");
         }
      }

      if ("Reset".equals(x.getType().name())) {
         this.print0(this.ucase ? " RESET " : " reset ");
         List<SQLExpr> itemList = x.getItemList();
         if (itemList != null && itemList.size() > 0) {
            this.print0("(");
            this.printAndAccept(itemList, ", ");
            this.print0(")");
         }
      }

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

      return false;
   }

   public void endVisit(PGAlterSequenceStatement x) {
   }

   public boolean visit(PGAlterSequenceStatement x) {
      this.print0(this.ucase ? "ALTER SEQUENCE " : "alter sequence ");
      if (x.isIfExists()) {
         this.printUcase("IF EXISTS ");
      }

      x.getName().accept(this);
      if (x.getIncrementBy() != null) {
         this.print0(this.ucase ? " INCREMENT " : " increment ");
         if (x.isBy()) {
            this.print0(this.ucase ? "BY " : "by ");
         }

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

      if (x.getMinValue() != null) {
         this.print0(this.ucase ? " MINVALUE " : " minvalue ");
         x.getMinValue().accept(this);
      }

      if (x.getMaxValue() != null) {
         this.print0(this.ucase ? " MAXVALUE " : " maxvalue ");
         x.getMaxValue().accept(this);
      }

      if (x.isNoMaxValue()) {
         this.print0(this.ucase ? " NO MAXVALUE" : " no maxvalue");
      }

      if (x.isNoMinValue()) {
         this.print0(this.ucase ? " NO MINVALUE" : " no minvalue");
      }

      if (x.getStartWith() != null) {
         this.print0(this.ucase ? " START " : " start ");
         if (x.isStart()) {
            this.print0(this.ucase ? "WITH " : "with ");
         }

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

      SQLExpr restartWith = x.getRestartWith();
      if (restartWith != null) {
         this.print0(this.ucase ? " RESTART" : " restart");
         if (x.isRestart()) {
            this.print0(this.ucase ? " WITH " : " with ");
         }

         restartWith.accept(this);
      }

      Boolean cache = x.getCache();
      if (cache != null && cache) {
         this.print0(this.ucase ? " CACHE " : " cache ");
         SQLExpr cacheValue = x.getCacheValue();
         if (cacheValue != null) {
            cacheValue.accept(this);
         }
      }

      if (x.getCycle() != null) {
         if (x.isCycleNo()) {
            this.print0(this.ucase ? " NO" : " no");
         }

         if (x.getCycle()) {
            this.print0(this.ucase ? " CYCLE" : " cycle");
         }
      }

      if (x.isOwnedBy()) {
         this.print0(this.ucase ? " OWNED BY " : " owned by ");
         x.getOwnedByName().accept(this);
      }

      if (x.isNone()) {
         this.print0(this.ucase ? " NONE " : " none ");
      }

      if (x.isOwnerTo()) {
         this.print0(this.ucase ? " OWNER TO " : " owner to ");
         x.getNewOwner().accept(this);
      }

      if (x.isRenameTo()) {
         this.print0(this.ucase ? " RENAME TO " : " rename to ");
         x.getNewName().accept(this);
      }

      if (x.isSetSchema()) {
         this.print0(this.ucase ? " SET SCHEMA " : " set schema ");
         x.getNewSchema().accept(this);
      }

      return false;
   }

   public void endVisit(PGAlterTableStatement x) {
   }

   public boolean visit(PGAlterTableStatement stmt) {
      this.print0(this.ucase ? "ALTER TABLE " : "alter table ");
      if (stmt.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

      if (stmt.isOnly()) {
         this.print0(this.ucase ? "ONLY " : "only ");
      }

      if (stmt.getTableName() != null) {
         stmt.getName().accept(this);
      }

      this.print0(" ");

      for(int i = 0; i < stmt.getItems().size(); ++i) {
         this.println();
         this.print("\t");
         ((SQLAlterTableItem)stmt.getItems().get(i)).accept(this);
         if (i != stmt.getItems().size() - 1) {
            this.print0(",");
         }
      }

      return false;
   }

   public void endVisit(PGAlterTableAddColumn x) {
   }

   public boolean visit(PGAlterTableAddColumn item) {
      this.print0(this.ucase ? "ADD COLUMN " : "add column ");
      PGColumnDefinition column = (PGColumnDefinition)item.getColumns().get(0);
      column.getName().accept(this);
      this.print0(" ");
      column.getType().accept(this);
      this.print0(" ");
      SQLExpr defaultExpr = column.getDefaultExpr();
      if (defaultExpr != null) {
         this.print0(this.ucase ? "DEFAULT " : "default ");
         defaultExpr.accept(this);
         this.print0(" ");
      }

      List<SQLColumnConstraint> constraints = column.getConstraints();
      if (constraints != null && constraints.size() > 0) {
         for(SQLColumnConstraint constraint : constraints) {
            constraint.accept(this);
            this.print0(" ");
         }
      }

      SQLExpr collateExpr = column.getCollateExpr();
      if (collateExpr != null) {
         this.print0(this.ucase ? "COLLATE " : "collate ");
         collateExpr.accept(this);
         this.print0(" ");
      }

      List<SQLExpr> encodings = column.getEncodings();
      if (encodings != null && encodings.size() > 0) {
         this.print0(this.ucase ? "ENCODING (" : "encoding (");

         for(int i = 0; i < encodings.size(); ++i) {
            ((SQLExpr)encodings.get(i)).accept(this);
            if (i != encodings.size() - 1) {
               this.print0(",");
            }
         }

         this.print0(")");
      }

      return false;
   }

   public void endVisit(PGCreateDatabaseStatement x) {
   }

   public boolean visit(PGCreateDatabaseStatement stmt) {
      this.print0(this.ucase ? "CREATE DATABSE " : "create database ");
      stmt.getName().accept(this);
      this.print0(" ");
      if (stmt.getOwner() != null) {
         this.print0(this.ucase ? "OWNER=" : "owner=");
         stmt.getOwner().accept(this);
         this.print(" ");
      }

      if (stmt.getTemplate() != null) {
         this.print0(this.ucase ? "TEMPLATE=" : "template=");
         stmt.getTemplate().accept(this);
         this.print(" ");
      }

      if (stmt.getEncoding() != null) {
         this.print0(this.ucase ? "ENCODING=" : "encoding=");
         stmt.getEncoding().accept(this);
         this.print(" ");
      }

      if (stmt.getLcCollate() != null) {
         this.print0(this.ucase ? "LC_COLLATE=" : "lc_collate=");
         stmt.getLcCollate().accept(this);
         this.print(" ");
      }

      if (stmt.getCtype() != null) {
         this.print0(this.ucase ? "LC_CTYPE=" : "lc_ctype=");
         stmt.getCtype().accept(this);
         this.print(" ");
      }

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

      if (stmt.getLimit() != null) {
         this.print0(this.ucase ? "CONNECTION LIMIT=" : "connection limit=");
         stmt.getLimit().accept(this);
         this.print(" ");
      }

      return false;
   }

   public void endVisit(PGSubqueryTableSource x) {
   }

   public boolean visit(PGSubqueryTableSource ts) {
      if (ts.isOnly()) {
         this.print0(" ONLY ");
      }

      if (ts.getSelect() != null) {
         this.print0("(");
         ts.getSelect().accept(this);
         this.print0(")");
      }

      if (ts.getAlias() != null) {
         this.print0(" AS ");
         this.print0(ts.getAlias());
         this.print0(" ");
      }

      if (ts.getColumns() != null && ts.getColumns().size() > 0) {
         this.print0("(");

         for(int i = 0; i < ts.getColumns().size(); ++i) {
            ((SQLName)ts.getColumns().get(i)).accept(this);
            if (i != ts.getColumns().size() - 1) {
               this.print0(",");
            }
         }

         this.print0(")");
      }

      return false;
   }

   public void endVisit(PGMethodInvokeTableSource x) {
   }

   public boolean visit(PGMethodInvokeTableSource ts) {
      if (ts.isOnly()) {
         this.print0(" ONLY ");
      }

      ts.getExpr().accept(this);
      this.print0("(");

      for(int i = 0; i < ts.getParameters().size(); ++i) {
         ((SQLExpr)ts.getParameters().get(i)).accept(this);
         if (i != ts.getParameters().size() - 1) {
            this.print0(",");
         }
      }

      this.print0(")");
      if (ts.isWithOrdinality()) {
         this.print0(this.ucase ? " WITH ORDINALITY " : " with ordinality ");
      }

      if (ts.getAlias() != null) {
         this.print0(this.ucase ? " AS " : " as ");
         this.print0(ts.getAlias());
      }

      List<PGColumnSimpleDefinitionExpr> defines = ts.getDefines();
      boolean flag = false;
      if (defines != null && defines.size() > 0) {
         flag = true;
         this.print0(this.ucase ? " AS (" : " as (");

         for(int i = 0; i < defines.size(); ++i) {
            PGColumnSimpleDefinitionExpr def = (PGColumnSimpleDefinitionExpr)defines.get(i);
            def.getName().accept(this);
            if (def.getType() != null) {
               this.print0(" ");
               def.getType().accept(this);
            }

            if (i != defines.size() - 1) {
               this.print0(",");
            }
         }

         this.print0(")");
      }

      if (!flag && ts.getColumns() != null && ts.getColumns().size() > 0) {
         this.print0("(");

         for(int i = 0; i < ts.getColumns().size(); ++i) {
            ((SQLName)ts.getColumns().get(i)).accept(this);
            if (i != ts.getColumns().size() - 1) {
               this.print0(",");
            }
         }

         this.print0(")");
      }

      return false;
   }

   public void endVisit(PGExprTableSource x) {
   }

   public void endVisit(PGSelectQueryBlock.ForClause x) {
   }

   public boolean visit(PGSelectQueryBlock.ForClause x) {
      this.print0(this.ucase ? "FOR " : "for ");
      if (PGSelectQueryBlock.ForClause.Option.UPDATE.equals(x.getOption())) {
         this.print0(this.ucase ? "UPDATE" : "update");
      } else if (PGSelectQueryBlock.ForClause.Option.SHARE.equals(x.getOption())) {
         this.print0(this.ucase ? "SHARE" : "share");
      } else if (PGSelectQueryBlock.ForClause.Option.NO_KEY_UPDATE.equals(x.getOption())) {
         this.print0(this.ucase ? "NO KEY UPDATE" : "no key update");
      } else if (PGSelectQueryBlock.ForClause.Option.KEY_SHARE.equals(x.getOption())) {
         this.print0(this.ucase ? "KEY SHARE" : "key share");
      }

      if (x.getOf().size() > 0) {
         this.print(' ');
         this.print0(this.ucase ? "OF" : "of");
         this.print(' ');

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

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

      if (x.isNoWait()) {
         this.print0(this.ucase ? " NOWAIT" : " nowait");
      } else if (x.isSkipLocked()) {
         this.print0(this.ucase ? " SKIP LOCKED" : " skip locked");
      }

      return false;
   }

   public void endVisit(PGDeleteStatement x) {
   }

   public void endVisit(PGSelectQueryBlock x) {
      this.endVisit((SQLSelectQueryBlock)x);
   }

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

      boolean bracket = x.isBracket();
      if (bracket) {
         this.print('(');
      }

      this.print0(this.ucase ? "SELECT " : "select ");
      if (1 == x.getDistionOption()) {
         this.print0(this.ucase ? "ALL " : "all ");
      } else if (2 == x.getDistionOption()) {
         this.print0(this.ucase ? "DISTINCT " : "distinct ");
         List<SQLExpr> distinctOn = x.getDistinctOn();
         if (distinctOn != null && distinctOn.size() > 0) {
            this.print0(this.ucase ? "ON " : "on ");
            if (distinctOn.size() == 1 && distinctOn.get(0) instanceof SQLListExpr) {
               this.printExpr((SQLExpr)distinctOn.get(0));
               this.print(' ');
            } else {
               this.print0("(");
               this.printAndAccept(distinctOn, ", ");
               this.print0(") ");
            }
         }
      }

      this.printSelectList(x.getSelectList());
      if (x.getInto() != null) {
         this.println();
         if (x.getIntoOption() != null) {
            this.print0(x.getIntoOption().name());
            this.print(' ');
         }

         this.print0(this.ucase ? "INTO " : "into ");
         x.getInto().accept(this);
      }

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

      SQLExpr where = x.getWhere();
      if (where != null) {
         this.println();
         this.print0(this.ucase ? "WHERE " : "where ");
         where.accept(this);
         if (where.hasAfterComment() && this.isPrettyFormat()) {
            this.print(' ');
            this.printlnComment(x.getWhere().getAfterCommentsDirect());
         }
      }

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

      List<SQLWindow> windows = x.getWindows();
      if (windows != null && windows.size() > 0) {
         this.println();
         this.print0(this.ucase ? "WINDOW " : "window ");
         this.printAndAccept(windows, ", ");
      }

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

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

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

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

      if (bracket) {
         this.print(')');
      }

      return false;
   }

   public void endVisit(PGSelectQueryBlock.FetchClause x) {
   }

   public boolean visit(SQLTruncateStatement x) {
      this.print0(this.ucase ? "TRUNCATE TABLE " : "truncate table ");
      if (x.isOnly()) {
         this.print0(this.ucase ? "ONLY " : "only ");
      }

      this.printlnAndAccept(x.getTableSources(), ", ");
      if (x.getRestartIdentity() != null) {
         if (x.getRestartIdentity()) {
            this.print0(this.ucase ? " RESTART IDENTITY" : " restart identity");
         } else {
            this.print0(this.ucase ? " CONTINUE IDENTITY" : " continue identity");
         }
      }

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

      return false;
   }

   public boolean visit(PGDeleteStatement x) {
      if (x.getWith() != null) {
         x.getWith().accept(this);
         this.println();
      }

      this.print0(this.ucase ? "DELETE FROM " : "delete from ");
      if (x.isOnly()) {
         this.print0(this.ucase ? "ONLY " : "only ");
      }

      this.printTableSourceExpr(x.getTableName());
      if (x.getAlias() != null) {
         this.print0(this.ucase ? " AS " : " as ");
         this.print0(x.getAlias());
      }

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

      List<SQLTableSource> usingList = x.getUsingList();
      if (usingList != null) {
         this.println();
         this.print0(this.ucase ? "USING " : "using ");

         for(int i = 0; i < usingList.size(); ++i) {
            SQLExprTableSource sqlExprTableSource = (SQLExprTableSource)usingList.get(i);
            if (i == usingList.size() - 1) {
               this.print0(sqlExprTableSource.getExpr().toString() + " ");
            } else {
               this.print0(sqlExprTableSource.getExpr().toString() + ", ");
            }
         }
      }

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

      if (x.isReturning()) {
         this.println();
         this.print0(this.ucase ? "RETURNING *" : "returning *");
      }

      return false;
   }

   public void endVisit(PGInsertStatement x) {
   }

   public boolean visit(PGInsertStatement x) {
      if (x.getWith() != null) {
         x.getWith().accept(this);
         this.println();
      }

      this.print0(this.ucase ? "INSERT INTO " : "insert into ");
      x.getTableSource().accept(this);
      this.printInsertColumns(x.getColumns());
      if (x.getValues() != null) {
         this.println();
         this.print0(this.ucase ? "VALUES " : "values ");
         this.printlnAndAccept(x.getValuesList(), ", ");
      } else if (x.getQuery() != null) {
         this.println();
         x.getQuery().accept(this);
      }

      List<SQLExpr> onConflictTarget = x.getOnConflictTarget();
      List<SQLUpdateSetItem> onConflictUpdateSetItems = x.getOnConflictUpdateSetItems();
      boolean onConflictDoNothing = x.isOnConflictDoNothing();
      if (onConflictDoNothing || onConflictTarget != null && onConflictTarget.size() > 0 || onConflictUpdateSetItems != null && onConflictUpdateSetItems.size() > 0) {
         this.println();
         this.print0(this.ucase ? "ON CONFLICT" : "on conflict");
         if (onConflictTarget != null && onConflictTarget.size() > 0) {
            this.print0(" (");
            this.printAndAccept(onConflictTarget, ", ");
            this.print(')');
         }

         SQLName onConflictConstraint = x.getOnConflictConstraint();
         if (onConflictConstraint != null) {
            this.print0(this.ucase ? " ON CONSTRAINT " : " on constraint ");
            this.printExpr(onConflictConstraint);
         }

         SQLExpr onConflictWhere = x.getOnConflictWhere();
         if (onConflictWhere != null) {
            this.print0(this.ucase ? " WHERE " : " where ");
            this.printExpr(onConflictWhere);
         }

         if (onConflictDoNothing) {
            this.print0(this.ucase ? " DO NOTHING" : " do nothing");
         } else if (onConflictUpdateSetItems != null && onConflictUpdateSetItems.size() > 0) {
            this.print0(this.ucase ? " DO UPDATE SET " : " do update set ");
            this.printAndAccept(onConflictUpdateSetItems, ", ");
            SQLExpr onConflictUpdateWhere = x.getOnConflictUpdateWhere();
            if (onConflictUpdateWhere != null) {
               this.print0(this.ucase ? " WHERE " : " where ");
               this.printExpr(onConflictUpdateWhere);
            }
         }
      }

      if (x.getReturning() != null) {
         this.println();
         this.print0(this.ucase ? "RETURNING " : "returning ");
         x.getReturning().accept(this);
      }

      return false;
   }

   public void endVisit(PGSelectStatement x) {
      this.endVisit((SQLSelectStatement)x);
   }

   public boolean visit(PGSelectStatement x) {
      return this.visit((SQLSelectStatement)x);
   }

   public void endVisit(PGUpdateStatement x) {
   }

   public boolean visit(PGUpdateStatement x) {
      SQLWithSubqueryClause with = x.getWith();
      if (with != null) {
         this.visit((SQLWithSubqueryClause)with);
         this.println();
      }

      this.print0(this.ucase ? "UPDATE " : "update ");
      if (x.isOnly()) {
         this.print0(this.ucase ? "ONLY " : "only ");
      }

      this.printTableSource(x.getTableSource());
      this.println();
      this.print0(this.ucase ? "SET " : "set ");
      int i = 0;

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

         SQLUpdateSetItem item = (SQLUpdateSetItem)x.getItems().get(i);
         this.visit((SQLUpdateSetItem)item);
      }

      SQLTableSource from = x.getFrom();
      if (from != null) {
         this.println();
         this.print0(this.ucase ? "FROM " : "from ");
         this.printTableSource(from);
      }

      SQLExpr where = x.getWhere();
      if (where != null) {
         this.println();
         ++this.indentCount;
         this.print0(this.ucase ? "WHERE " : "where ");
         this.printExpr(where);
         --this.indentCount;
      }

      List<SQLExpr> returning = x.getReturning();
      if (returning.size() > 0) {
         this.println();
         this.print0(this.ucase ? "RETURNING " : "returning ");
         this.printAndAccept(returning, ", ");
      }

      return false;
   }

   public void endVisit(PGFunctionTableSource x) {
   }

   public boolean visit(PGFunctionTableSource x) {
      x.getExpr().accept(this);
      if (x.getAlias() != null) {
         this.print0(this.ucase ? " AS " : " as ");
         this.print0(x.getAlias());
      }

      if (x.getParameters().size() > 0) {
         this.print('(');
         this.printAndAccept(x.getParameters(), ", ");
         this.print(')');
      }

      return false;
   }

   public void endVisit(PGTypeCastExpr x) {
   }

   public boolean visit(PGTypeCastExpr x) {
      SQLExpr expr = x.getExpr();
      SQLDataType dataType = x.getDataType();
      if (dataType.nameHashCode64() == FnvHash.Constants.VARBIT) {
         dataType.accept(this);
         this.print(' ');
         this.printExpr(expr);
         return false;
      } else {
         if (expr != null) {
            if (expr instanceof SQLBinaryOpExpr) {
               this.print('(');
               expr.accept(this);
               this.print(')');
            } else {
               if (expr instanceof PGTypeCastExpr && dataType.getArguments().size() == 0) {
                  dataType.accept(this);
                  this.print('(');
                  this.visit((PGTypeCastExpr)expr);
                  this.print(')');
                  return false;
               }

               expr.accept(this);
            }
         }

         this.print0("::");
         dataType.accept(this);
         return false;
      }
   }

   public void endVisit(PGExtractExpr x) {
   }

   public boolean visit(PGExtractExpr x) {
      this.print0(this.ucase ? "EXTRACT (" : "extract (");
      this.print0(x.getField().name());
      this.print0(this.ucase ? " FROM " : " from ");
      x.getSource().accept(this);
      this.print(')');
      return false;
   }

   public void endVisit(PGBoxExpr x) {
   }

   public boolean visit(PGBoxExpr x) {
      this.print0(this.ucase ? "BOX " : "box ");
      x.getValue().accept(this);
      return false;
   }

   public void endVisit(PGPointExpr x) {
   }

   public boolean visit(PGPointExpr x) {
      this.print0(this.ucase ? "POINT " : "point ");
      x.getValue().accept(this);
      return false;
   }

   public void endVisit(PGMacAddrExpr x) {
   }

   public boolean visit(PGMacAddrExpr x) {
      this.print0("macaddr ");
      x.getValue().accept(this);
      return false;
   }

   public void endVisit(PGInetExpr x) {
   }

   public boolean visit(PGInetExpr x) {
      this.print0("inet ");
      x.getValue().accept(this);
      return false;
   }

   public void endVisit(PGCidrExpr x) {
   }

   public boolean visit(PGCidrExpr x) {
      this.print0("cidr ");
      x.getValue().accept(this);
      return false;
   }

   public void endVisit(PGPolygonExpr x) {
   }

   public boolean visit(PGPolygonExpr x) {
      this.print0("polygon ");
      x.getValue().accept(this);
      return false;
   }

   public void endVisit(PGCircleExpr x) {
   }

   public boolean visit(PGCircleExpr x) {
      this.print0("circle ");
      x.getValue().accept(this);
      return false;
   }

   public void endVisit(PGLineSegmentsExpr x) {
   }

   public boolean visit(PGLineSegmentsExpr x) {
      this.print0("lseg ");
      x.getValue().accept(this);
      return false;
   }

   public void endVisit(PGShowStatement x) {
   }

   public boolean visit(SQLBinaryExpr x) {
      this.print0(this.ucase ? "B'" : "b'");
      this.print0(x.getText());
      this.print('\'');
      return false;
   }

   public boolean visit(PGShowStatement x) {
      this.print0(this.ucase ? "SHOW " : "show ");
      x.getExpr().accept(this);
      return false;
   }

   public void endVisit(PGStartTransactionStatement x) {
   }

   public boolean visit(SQLLimit x) {
      this.print0(this.ucase ? "LIMIT " : "limit ");
      if (x.getRowCount() != null) {
         x.getRowCount().accept(this);
      }

      if (x.getOffset() != null) {
         this.print0(this.ucase ? " OFFSET " : " offset ");
         x.getOffset().accept(this);
      }

      return false;
   }

   public boolean visit(PGStartTransactionStatement x) {
      this.print0(this.ucase ? "START TRANSACTION" : "start transaction");
      return false;
   }

   public void endVisit(PGConnectToStatement x) {
   }

   public boolean visit(PGConnectToStatement x) {
      this.print0(this.ucase ? "CONNECT TO " : "connect to ");
      x.getTarget().accept(this);
      return false;
   }

   public void endVisit(PGCreateSchemaStatement x) {
   }

   public boolean visit(PGCreateSchemaStatement x) {
      this.printUcase("CREATE SCHEMA ");
      if (x.isIfNotExists()) {
         this.printUcase("IF NOT EXISTS ");
      }

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

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

      if (x.getElements() != null && x.getElements().size() > 0) {
         this.incrementIndent();

         for(SQLStatement element : x.getElements()) {
            this.println();
            this.printIndent();
            element.accept(this);
         }
      }

      return false;
   }

   public void endVisit(PGDropSchemaStatement x) {
   }

   public boolean visit(PGDropSchemaStatement x) {
      this.printUcase("DROP SCHEMA ");
      if (x.isIfExists()) {
         this.printUcase("IF EXISTS ");
      }

      ArrayList<SQLIdentifierExpr> schemaList = x.getSchemaList();
      if (schemaList != null && schemaList.size() > 0) {
         this.printAndAccept(schemaList, ", ");
      }

      if (x.isCascade()) {
         this.printUcase(" CASCADE ");
      } else if (x.isRestrict()) {
         this.printUcase(" RESTRICT ");
      }

      return false;
   }

   public void endVisit(PGAlterSchemaStatement x) {
   }

   public boolean visit(PGAlterSchemaStatement x) {
      this.printUcase("ALTER SCHEMA ");
      x.getSchemaName().accept(this);
      if (x.getNewName() != null) {
         this.print0(" RENAME TO ");
         x.getNewName().accept(this);
      } else if (x.getNewOwner() != null) {
         this.print0(" OWNER TO ");
         x.getNewOwner().accept(this);
      }

      return false;
   }

   public void endVisit(PGOptionValue x) {
   }

   public boolean visit(PGOptionValue value) {
      value.getOption().accept(this);
      if (value.isEq()) {
         if (value.getValue() != null) {
            this.print0("=");
            value.getValue().accept(this);
         }
      } else {
         this.print0(" ");
         if (value.getValue() != null) {
            value.getValue().accept(this);
            this.print0(" ");
         }
      }

      return false;
   }

   public void endVisit(PGCreateTableStatement.PGTableDistributedBy x) {
   }

   public boolean visit(PGCreateTableStatement.PGTableDistributedBy by) {
      this.print0(this.ucase ? "DISTRIBUTED " : "distributed ");
      List<PGOptionValue> columns = by.getColumns();
      if (columns != null && columns.size() > 0) {
         this.print0(this.ucase ? "BY (" : "by (");

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

         this.print0(") ");
      }

      PGCreateTableStatement.PGTableDistributedBy.Option option = by.getOption();
      if (option != null) {
         switch (option) {
            case randomly:
               this.print0(this.ucase ? "RANDOMLY " : "randomly ");
               break;
            case replicated:
               this.print0(this.ucase ? "REPLICATED " : "replicated ");
         }
      }

      return false;
   }

   public void endVisit(PGAlterTableAddConstraint x) {
   }

   public boolean visit(PGAlterTableAddConstraint item) {
      this.print0(this.ucase ? "ADD " : "add ");
      if (item.getConstraint() != null) {
         item.getConstraint().accept(this);
      } else if (item.getUsingIndex() != null) {
         PGAlterTableAddConstraint.PGAlterTableAddConstraintUsingIndex index = item.getUsingIndex();
         if (index.getConstraint() != null) {
            this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
            index.getConstraint().accept(this);
            this.print0(" ");
         }

         if (index.getType() == PGAlterTableAddConstraint.PGAlterTableAddConstraintUsingIndex.ConstraintType.unique) {
            this.print0(this.ucase ? "UNIQUE " : "unique ");
         } else {
            this.print0(this.ucase ? "PRIMARY KEY " : "primary key ");
         }

         this.print0(this.ucase ? "USING INDEX " : "using index ");
         index.getIndexName().accept(this);
         this.print0(" ");
         if (index.getStrategy() != null) {
            switch (index.getStrategy()) {
               case deferable:
                  this.print0(this.ucase ? "DEFERRABLE " : "deferrable");
                  break;
               case notDeferable:
                  this.print0(this.ucase ? "NOT DEFERRABLE " : "not deferrable");
                  break;
               case initiallyDefered:
                  this.print0(this.ucase ? "INITIALLY DEFERRED " : "initially deferred ");
                  break;
               case initiallyImmediate:
                  this.print0(this.ucase ? "INITIALLY IMMEDIATE " : "initially immediate ");
            }
         }
      }

      return false;
   }

   public void endVisit(PGAlterTableAddConstraint.PGAlterTableAddConstraintUsingIndex x) {
   }

   public boolean visit(PGAlterTableAddConstraint.PGAlterTableAddConstraintUsingIndex x) {
      return true;
   }

   public void endVisit(PGAlterTableAlterColumn x) {
   }

   public boolean visit(PGAlterTableAlterColumn item) {
      this.print0(this.ucase ? "ALTER COLUMN " : "alter column ");
      item.getColumn().accept(this);
      this.print0(" ");
      switch (item.getType()) {
         case setType:
            this.print0(this.ucase ? "SET DATA TYPE " : "set data type ");
            item.getDataType().accept(this);
            this.print0(" ");
            SQLExpr collation = item.getCollation();
            if (collation != null) {
               this.print0(this.ucase ? "COLLATE " : "collate ");
               collation.accept(this);
               this.print0(" ");
            }

            SQLExpr usingExpression = item.getUsingExpression();
            if (usingExpression != null) {
               this.print0(this.ucase ? "USING " : "using ");
               usingExpression.accept(this);
               this.print0(" ");
            }
            break;
         case setDefault:
            this.print0(this.ucase ? "SET DEFAULT " : "set default ");
            item.getDefaultExpression().accept(this);
            break;
         case dropDefault:
            this.print0(this.ucase ? "DROP DEFAULT " : "drop default ");
            break;
         case setNotNull:
            this.print0(this.ucase ? "SET NOT NULL " : "set not null ");
            break;
         case dropNotNull:
            this.print0(this.ucase ? "DROP NOT NULL " : "drop not null ");
            break;
         case setStatistics:
            this.print0(this.ucase ? "SET STATISTICS " : "set statistics ");
            item.getStatics().accept(this);
            this.print0(" ");
      }

      return false;
   }

   public void endVisit(PGAlterTableAlterColumnOptions x) {
   }

   public boolean visit(PGAlterTableAlterColumnOptions item) {
      this.print0(this.ucase ? "ALTER COLUMN COLUMN " : "alter column column ");
      if (item.isSet()) {
         this.print0(this.ucase ? "SET (" : "set (");
      } else {
         this.print0(this.ucase ? "RESET (" : "reset (");
      }

      List<PGAlterTableAlterColumnOptions.PGAlterTableAlterColumnOptionValue> options = item.getOptions();

      for(int i = 0; i < options.size(); ++i) {
         PGAlterTableAlterColumnOptions.PGAlterTableAlterColumnOptionValue option = (PGAlterTableAlterColumnOptions.PGAlterTableAlterColumnOptionValue)options.get(i);
         option.getAttribute().accept(this);
         SQLExpr value = option.getValue();
         if (value != null) {
            this.print0("=");
            value.accept(this);
         }

         if (i != options.size() - 1) {
            this.print0(",");
         }
      }

      this.print0(") ");
      return false;
   }

   public void endVisit(PGAlterTableAlterColumnOptions.PGAlterTableAlterColumnOptionValue x) {
   }

   public boolean visit(PGAlterTableAlterColumnOptions.PGAlterTableAlterColumnOptionValue x) {
      return true;
   }

   public void endVisit(PGAlterTableCluster x) {
   }

   public boolean visit(PGAlterTableCluster x) {
      this.print0(this.ucase ? "CLUSTER ON " : "cluster on ");
      x.getIndex().accept(this);
      this.print0(" ");
      return false;
   }

   public void endVisit(PGAlterTableDisableEnabelTrigger x) {
   }

   public boolean visit(PGAlterTableDisableEnabelTrigger item) {
      if (!item.isEnable()) {
         this.print0(this.ucase ? "DISABLE TRIGGER " : "disable trigger ");
      } else {
         this.print0(this.ucase ? "ENABLE TRIGGER " : "enable trigger ");
      }

      if (item.getTrigger() != null) {
         item.getTrigger().accept(this);
      } else if (item.getType() != null) {
         if (item.getType() == PGAlterTableDisableEnabelTrigger.Type.all) {
            this.print0(this.ucase ? "ALL " : "all ");
         } else {
            this.print0(this.ucase ? "USER " : "user ");
         }
      }

      return false;
   }

   public void endVisit(PGAlterTableDropColumn x) {
   }

   public boolean visit(PGAlterTableDropColumn item) {
      this.print0(this.ucase ? "DROP COLUMN " : "drop column ");
      if (item.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

      item.getColumnName().accept(this);
      this.print0(" ");
      PGAlterTableDropColumn.DropColumType type = item.getType();
      if (type != null) {
         if (type == PGAlterTableDropColumn.DropColumType.restrict) {
            this.print0(this.ucase ? "RESTRICT " : "restrict ");
         } else {
            this.print0(this.ucase ? "CASCADE " : "cascade ");
         }
      }

      return false;
   }

   public void endVisit(PGAlterTableDropConstraint x) {
   }

   public boolean visit(PGAlterTableDropConstraint item) {
      this.print0(this.ucase ? "DROP CONSTRAINT " : "drop constraint ");
      if (item.isIfExists()) {
         this.print0(this.ucase ? "IF EXISTS " : "if exists ");
      }

      item.getConstraint().accept(this);
      this.print0(" ");
      PGAlterTableDropConstraint.DorpType type = item.getType();
      if (type != null) {
         if (type == PGAlterTableDropConstraint.DorpType.cascade) {
            this.print0(this.ucase ? "RESTRICT " : "restrict ");
         } else {
            this.print0(this.ucase ? "CASCADE " : "cascade ");
         }
      }

      return false;
   }

   public void endVisit(PGConstraint x) {
   }

   public boolean visit(PGConstraint constraint) {
      if (constraint.getName() != null) {
         this.println();
         this.print0(this.ucase ? "CONSTRAINT " : "constraint ");
         constraint.getName().accept(this);
      }

      if (constraint.getiNull() != null && constraint.getiNull()) {
         this.println();
         this.print0(this.ucase ? "NULL " : "null ");
      }

      if (constraint.getNotNull() != null && constraint.getNotNull()) {
         this.println();
         this.print0(this.ucase ? "NOT NULL " : "not null ");
      }

      if (constraint.getCheck() != null) {
         this.println();
         this.print0(this.ucase ? "CHECK " : "check ");
         this.print0("(");
         constraint.getCheck().getExpr().accept(this);
         this.print0(")");
         this.space();
         if (constraint.getCheck().isNoInherit()) {
            this.print0(this.ucase ? "NO INHERIT " : "no inherit ");
         }
      }

      if (constraint.getDefValue() != null) {
         this.println();
         this.print0(this.ucase ? "DEFAULT " : "default ");
         constraint.getDefValue().accept(this);
      }

      if (constraint.getUnique() != null) {
         this.println();
         this.print0(this.ucase ? "UNIQUE " : "unique ");
         List<SQLName> columns = constraint.getUnique().getColumns();
         if (columns != null && columns.size() > 0) {
            this.print0("(");

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

            this.print0(") ");
         }

         PGConstraint.PGIndexParamaters indexParamaters = constraint.getUnique().getIndexParamaters();
         if (indexParamaters != null) {
            indexParamaters.accept(this);
         }
      }

      if (constraint.getPrimaryKey() != null) {
         this.println();
         this.print0(this.ucase ? "PRIMARY KEY " : "primary key ");
         PGConstraint.PGIndexParamaters indexParamaters = constraint.getPrimaryKey().getIndexParamaters();
         if (indexParamaters != null) {
            indexParamaters.accept(this);
         }
      }

      if (constraint.getReference() != null) {
         this.println();
         constraint.getReference().accept(this);
      }

      if (constraint.getType() != null) {
         switch (constraint.getType()) {
            case deferrable:
               this.print0(this.ucase ? "DEFERRABLE " : "deferrable ");
               break;
            case notDeferrable:
               this.print0(this.ucase ? "NOT DEFERRABLE " : "not deferrable ");
               break;
            case initiallyDeferred:
               this.print0(this.ucase ? "INITIALLY DEFERRED " : "initially deferred ");
               break;
            case initiallyImmediate:
               this.print0(this.ucase ? "INITIALLY IMMEDIATE " : "initially immediate ");
         }
      }

      return false;
   }

   public void endVisit(PGConstraint.PGConstraintCheck x) {
   }

   public boolean visit(PGConstraint.PGConstraintCheck x) {
      return true;
   }

   public void endVisit(PGConstraint.PGIndexParamaters x) {
   }

   public boolean visit(PGConstraint.PGIndexParamaters r) {
      List<PGStorageParameter> parameters = r.getParameters();
      if (parameters != null && parameters.size() > 0) {
         this.print0(this.ucase ? "WITH (" : "with (");

         for(int i = 0; i < parameters.size(); ++i) {
            ((PGStorageParameter)parameters.get(i)).accept(this);
            if (i != parameters.size() - 1) {
               this.print0(",");
            }
         }

         this.print0(") ");
      }

      if (r.getTablespace() != null) {
         this.print0(this.ucase ? "USING INDEX TABLESPACE " : "using index tablespace ");
         r.getTablespace().accept(this);
         this.space();
      }

      return false;
   }

   public void endVisit(PGConstraint.PGUnique x) {
   }

   public boolean visit(PGConstraint.PGUnique x) {
      return true;
   }

   public void endVisit(PGConstraint.PGForeignKey x) {
   }

   public boolean visit(PGConstraint.PGForeignKey x) {
      return true;
   }

   public void endVisit(PGConstraint.PGPrimaryKey x) {
   }

   public boolean visit(PGConstraint.PGPrimaryKey x) {
      return true;
   }

   public void endVisit(PGCreateTableStatement x) {
   }

   public boolean visit(PGCreateTableStatement stmt) {
      this.print0(this.ucase ? "CREATE " : "create ");
      if (stmt.getTableType() != null) {
         switch (stmt.getTableType()) {
            case GLOBAL_TEMPORARY:
               this.print0(this.ucase ? "GLOBAL TEMPORARY " : "golbal temporary ");
               break;
            case LOCAL_TEMPORARY:
               this.print0(this.ucase ? "LOCAL TEMPORARY " : "local temporary ");
               break;
            case GLOBAL_TEMP:
               this.print0(this.ucase ? "GLOBAL TEMP " : "golbal temp ");
               break;
            case LOCAL_TEMP:
               this.print0(this.ucase ? "LOCAL TEMP " : "local temp ");
               break;
            case GLOBAL_UNLOGGED:
               this.print0(this.ucase ? "GLOBAL UNLOGGED " : "golbal unlogged ");
               break;
            case LOCAL_UNLOGGED:
               this.print0(this.ucase ? "LOCAL UNLOGGED " : "local unlogged ");
               break;
            case TEMPORARY:
               this.print0(this.ucase ? "TEMPORARY " : "temporary ");
               break;
            case TEMP:
               this.print0(this.ucase ? "TEMP " : "temp ");
               break;
            case UNLOGGED:
               this.print0(this.ucase ? "UNLOGGED " : "unlogged ");
         }
      }

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

      stmt.getTableSource().accept(this);
      this.print0(" ");
      if (stmt.getOfType() != null) {
         this.print0(this.ucase ? "OF " : "of ");
         stmt.getOfType().accept(this);
         this.print0(" ");
      }

      if (stmt.getTableElementList() != null && stmt.getTableElementList().size() > 0) {
         this.print0("(");

         for(int i = 0; i < stmt.getTableElementList().size(); ++i) {
            this.println();
            SQLTableElement element = (SQLTableElement)stmt.getTableElementList().get(i);
            element.accept(this);
            if (i != stmt.getTableElementList().size() - 1) {
               this.print0(",");
            }
         }

         this.println();
         this.print0(")");
      }

      List<SQLExpr> parentTables = stmt.getParentTables();
      if (parentTables != null && parentTables.size() > 0) {
         this.println();
         this.print0(this.ucase ? "INHERITS " : "inherits ");
         this.print0("(");

         for(int i = 0; i < parentTables.size(); ++i) {
            ((SQLExpr)parentTables.get(i)).accept(this);
            if (i != parentTables.size() - 1) {
               this.print0(",");
            }
         }

         this.print0(")");
      }

      if (stmt.getParameters() != null && stmt.getParameters().size() > 0) {
         this.println();
         this.print0(this.ucase ? "WITH " : "with ");
         this.print0("(");

         for(int i = 0; i < stmt.getParameters().size(); ++i) {
            PGStorageParameter paramter = (PGStorageParameter)stmt.getParameters().get(i);
            paramter.accept(this);
            this.println();
            if (i != stmt.getParameters().size() - 1) {
               this.print0(",");
            }
         }

         this.print0(")");
      }

      if (stmt.getTableOptions() != null && stmt.getTableOptions().size() > 0) {
         this.println();
         this.print0(this.ucase ? "WITH " : "with ");
         this.print0("(");

         for(int i = 0; i < stmt.getTableOptions().size(); ++i) {
            SQLAssignItem paramter = (SQLAssignItem)stmt.getTableOptions().get(i);
            paramter.accept(this);
            this.println();
            if (i != stmt.getTableOptions().size() - 1) {
               this.print0(",");
            }
         }

         this.print0(")");
      }

      if (stmt.getOnCommit() != null) {
         this.println();
         this.print0(this.ucase ? "ON COMMIT " : "on commit ");
         switch (stmt.getOnCommit()) {
            case preserveRows:
               this.print0(this.ucase ? "PRESERVE ROWS" : "preserve rows");
               break;
            case deleteRows:
               this.print0(this.ucase ? "DELETE ROWS" : "delete rows");
               break;
            case drop:
               this.print0(this.ucase ? "DROP" : "drop");
         }
      }

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

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

      if (stmt.getDistributedBy() != null) {
         this.println();
         stmt.getDistributedBy().accept(this);
      }

      if (stmt.getPartitioning() != null) {
         this.println();
         stmt.getPartitioning().accept(this);
      }

      return false;
   }

   public void endVisit(PGColumnDefinition x) {
   }

   public boolean visit(PGColumnDefinition d) {
      this.incrementIndent();
      this.printIndent();
      d.getName().accept(this);
      this.space();
      if (d.isWith()) {
         this.print0(this.ucase ? "WITH OPTIONS " : "with options ");
      } else {
         if (d.getType() != null) {
            d.getType().accept(this);
         } else if (d.getDataType() != null) {
            d.getDataType().accept(this);
         }

         this.space();
         if (d.getCollateExpr() != null) {
            this.print0(this.ucase ? "COLLATE " : "collate ");
            d.getCollateExpr().accept(this);
         }
      }

      List<SQLColumnConstraint> constraints = d.getConstraints();
      if (constraints != null && constraints.size() > 0) {
         for(int i = 0; i < constraints.size(); ++i) {
            ((SQLColumnConstraint)constraints.get(i)).accept(this);
         }
      }

      List<SQLExpr> encodings = d.getEncodings();
      if (encodings != null && encodings.size() > 0) {
         this.println();
         this.print0(this.ucase ? "ENCODING " : "encoding ");
         this.print0("(");

         for(int i = 0; i < encodings.size(); ++i) {
            SQLExpr sqlExpr = (SQLExpr)encodings.get(i);
            sqlExpr.accept(this);
            if (i != encodings.size() - 1) {
               this.print0(",");
            }
         }

         this.print0(")");
      }

      if (d.getTableConstraint() != null) {
         d.getTableConstraint().accept(this);
      }

      if (d.getLike() != null) {
         this.print0(this.ucase ? "LIKE " : "like ");
         d.getLike().accept(this);
         this.space();
         List<PGColumnDefinition.ColumnLikeOption> likeOptions = d.getLikeOptions();
         if (likeOptions != null && likeOptions.size() > 0) {
            for(int i = 0; i < likeOptions.size(); ++i) {
               PGColumnDefinition.ColumnLikeOption option = (PGColumnDefinition.ColumnLikeOption)likeOptions.get(i);
               switch (option.getIncludeType()) {
                  case including:
                     this.print0(this.ucase ? "INCLUDING " : "including ");
                     break;
                  case excluding:
                     this.print0(this.ucase ? "EXCLUDING " : "excluding ");
               }

               switch (option.getOption()) {
                  case defaults:
                     this.print0(this.ucase ? "DEFAULTS " : "defaults ");
                     break;
                  case constraints:
                     this.print0(this.ucase ? "CONSTRAINTS " : "constraints ");
                     break;
                  case indexes:
                     this.print0(this.ucase ? "INDEXES " : "indexes ");
                     break;
                  case storage:
                     this.print0(this.ucase ? "STORAGE " : "storage ");
                     break;
                  case comments:
                     this.print0(this.ucase ? "COMMENTS " : "comments ");
                     break;
                  case all:
                     this.print0(this.ucase ? "ALL " : "all ");
               }
            }
         }
      }

      List<PGConstraint.PGReference> columnReferenceStorageDirectives = d.getColumnReferenceStorageDirectives();
      if (columnReferenceStorageDirectives != null && columnReferenceStorageDirectives.size() > 0) {
         for(int i = 0; i < columnReferenceStorageDirectives.size(); ++i) {
            PGConstraint.PGReference gpReference = (PGConstraint.PGReference)columnReferenceStorageDirectives.get(i);
            gpReference.accept(this);
            if (i != columnReferenceStorageDirectives.size() - 1) {
               this.print0(",");
            }
         }
      }

      this.decrementIndent();
      return false;
   }

   public void endVisit(PGStorageParameter x) {
   }

   public boolean visit(PGStorageParameter x) {
      return true;
   }

   public void endVisit(PGSchemaTables x) {
   }

   public boolean visit(PGSchemaTables datas) {
      if (datas != null && datas.size() > 0) {
         this.print0(this.ucase ? "ALL TABLES IN SCHEMA " : "all tables in schema ");

         for(int i = 0; i < datas.size(); ++i) {
            datas.get(i).accept(this);
            if (i != datas.size() - 1) {
               this.print0(",");
            }
         }
      }

      return false;
   }

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

      if (x.isTemp()) {
         this.print0(this.ucase ? " TEMP " : " temp ");
      }

      if (x.isTemporary()) {
         this.print0(this.ucase ? " TEMPORARY " : " temporary ");
      }

      if (x.isRecursiveView()) {
         this.print0(this.ucase ? " RECURSIVE " : " recursive ");
      }

      this.print0(this.ucase ? " VIEW " : " view ");
      x.getViewName().accept(this);
      List<SQLExpr> columnList = x.getColumnList();
      if (columnList != null && columnList.size() > 0) {
         this.print0("(");
         this.printAndAccept(columnList, ", ");
         this.print0(")");
      }

      if (x.isWithOption()) {
         this.print0(this.ucase ? " WITH" : " with");
         List<SQLUpdateSetItem> withList = x.getWithList();
         this.print0("(");
         this.printAndAccept(withList, ", ");
         this.print0(")");
      }

      this.print0(this.ucase ? " AS " : " as ");
      if (x.isAsWithRecursive()) {
         x.getWithSubqueryClause().accept(this);
      } else {
         x.getSubQuery().accept(this);
         if (x.isWithCascaded()) {
            this.print0(this.ucase ? " WITH CASCADED CHECK OPTION " : " with cascaded check option ");
         }

         if (x.isWithLocal()) {
            this.print0(this.ucase ? " WITH LOCAL CHECK OPTION " : " with local check option ");
         }
      }

      return false;
   }

   public boolean visit(PGDropSequenceStatement x) {
      this.print0(this.ucase ? "DROP SEQUENCE " : " drop sequence ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? " IF EXISTS " : " if exists ");
      }

      ArrayList<SQLIdentifierExpr> seqList = x.getSeqList();
      if (seqList != null && seqList.size() > 0) {
         this.printAndAccept(seqList, ", ");
      }

      if (x.isCascade()) {
         this.print0(this.ucase ? " CASCADE " : " cascade ");
      } else if (x.isRestrict()) {
         this.print0(this.ucase ? " RESTRICT " : " restrict ");
      }

      return false;
   }

   public boolean visit(PGSQLPartition x) {
      SQLName name = x.getName();
      if (name != null) {
         boolean subPartition = x.isSubPartition();
         if (x.isIfDefault()) {
            this.print0(this.ucase ? " DEFAULT PARTITION " : " default partition ");
            x.getName().accept(this);
            return false;
         }

         if (subPartition) {
            this.print0(this.ucase ? " SUBPARTITION " : " subpartition ");
         } else {
            this.print0(this.ucase ? " PARTITION " : " partition ");
         }

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

      ArrayList<SQLExpr> valueList = x.getValueList();
      if (valueList != null && valueList.size() > 0) {
         this.print0(this.ucase ? " VALUES " : " values ");
         this.print0(" (");
         this.printAndAccept(valueList, ", ");
         this.print0(") ");
      } else {
         if (x.isStart()) {
            this.print0(this.ucase ? " START" : " star ");
            this.print0("(");
            SQLExpr startDataType = x.getStartDataType();
            if (startDataType != null) {
               startDataType.accept(this);
               this.print0(" ");
            }

            x.getStartValue().accept(this);
            this.print0(")");
            if (x.isStartInclusive()) {
               this.print0(this.ucase ? " INCLUSIVE " : " inclusive ");
            }

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

         if (x.isEnd()) {
            this.print0(this.ucase ? " END" : " end");
            this.print0("(");
            SQLExpr endDataType = x.getEndDataType();
            if (endDataType != null) {
               endDataType.accept(this);
               this.print0(" ");
            }

            x.getEndValue().accept(this);
            this.print0(")");
            if (x.isEndInclusive()) {
               this.print0(this.ucase ? " INCLUSIVE " : " inclusive ");
            }

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

         if (x.isEvery()) {
            this.print0(this.ucase ? " EVERY " : " every ");
            this.print0("(");
            SQLExpr everyDataType = x.getEveryDataType();
            if (everyDataType != null) {
               everyDataType.accept(this);
               this.print0(" ");
            }

            x.getEveryValue().accept(this);
            this.print0(")");
         }
      }

      if (x.isWith()) {
         this.print0(this.ucase ? " WITH " : " with ");
         List<SQLUpdateSetItem> withList = x.getWithList();
         if (withList != null && withList.size() > 0) {
            this.printAndAccept(withList, ",");
         }
      }

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

      return false;
   }

   public boolean visit(PGCreateIndexStatement x) {
      this.print0(this.ucase ? "CREATE " : "create ");
      if (x.getType() != null) {
         this.print0(x.getType());
         this.print(' ');
      }

      this.print0(this.ucase ? "INDEX" : "index");
      SQLName name = x.getName();
      if (name != null) {
         this.print(' ');
         name.accept(this);
      }

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

      this.print0(" (");
      this.printAndAccept(x.getSpecList(), ", ");
      this.print(')');
      List<SQLUpdateSetItem> withList = x.getWithList();
      if (withList != null && withList.size() > 0) {
         this.print0(this.ucase ? " WITH " : " with ");
         this.print0(" (");
         this.printAndAccept(withList, ",");
         this.print(')');
      }

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

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

      return false;
   }

   public void endVisit(PGConstraint.PGReference x) {
   }

   public boolean visit(SQLDropTableStatement x) {
      this.print0(this.ucase ? "DROP TABLE " : " drop table ");
      if (x.isIfExists()) {
         this.print0(this.ucase ? " IF EXISTS " : " if exists ");
      }

      this.printAndAccept(x.getTableSources(), ",");
      if (x.isCascade()) {
         this.print0(this.ucase ? " CASCADE " : " cascade ");
      } else if (x.isRestrict()) {
         this.print0(this.ucase ? " RESTRICT " : " restrict ");
      }

      return false;
   }

   public boolean visit(SQLRollbackStatement x) {
      this.print0(this.ucase ? "ROLLBACK" : "rollback");
      if (x.isWork()) {
         this.print0(this.ucase ? " WORK" : " work");
      } else if (x.isTransaction()) {
         this.print0(this.ucase ? " TRANSACTION" : " transaction");
      }

      if (x.getTo() != null) {
         this.print0(this.ucase ? " TO " : " to ");
         if (x.isHasSavepoint()) {
            this.print0(this.ucase ? " SAVEPOINT " : " savepoint ");
         }

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

      return false;
   }

   public boolean visit(SQLCommitStatement x) {
      this.print0(this.ucase ? "COMMIT" : "commit");
      if (x.isWork()) {
         this.print0(this.ucase ? " WORK" : " work");
      } else if (x.isTransaction()) {
         this.print0(this.ucase ? " TRANSACTION" : " transaction");
      }

      return false;
   }

   public boolean visit(PGConstraint.PGReference r) {
      this.print0(this.ucase ? "REFERENCES " : "references ");
      r.getRefTable().accept(this);
      this.space();
      List<SQLExpr> columns = r.getColumns();
      if (columns != null && columns.size() > 0) {
         this.print0("(");

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

         this.print0(") ");
      }

      PGConstraint.PGReference.MatchType matchType = r.getMatchType();
      if (matchType != null) {
         switch (matchType) {
            case full:
               this.print0(this.ucase ? "MATCH FULL " : "match full ");
               break;
            case partial:
               this.print0(this.ucase ? "MATCH PARTIAL " : "match partial ");
               break;
            case simple:
               this.print0(this.ucase ? "MATCH SIMPLE " : "match simple ");
         }
      }

      if (r.getDeleteAction() != null) {
         this.print0(this.ucase ? "ON DELETE " : "on delete ");
         switch (r.getDeleteAction()) {
            case onDelete:
               this.print0(this.ucase ? "ON DELETE " : "on delete ");
               break;
            case onUpdate:
               this.print0(this.ucase ? "ON UPDATE " : "on update ");
               break;
            case noAction:
               this.print0(this.ucase ? "NO ACTION " : "no action ");
               break;
            case restrict:
               this.print0(this.ucase ? "RESTRICT " : "restrict ");
               break;
            case cascade:
               this.print0(this.ucase ? "CASCADE " : "cascade ");
               break;
            case setNull:
               this.print0(this.ucase ? "SET NULL " : "set null ");
               break;
            case setDefault:
               this.print0(this.ucase ? "SET DEFAULT " : "set default ");
         }
      }

      if (r.getUpdateAction() != null) {
         this.print0(this.ucase ? "ON UPDATE " : "on update ");
         switch (r.getUpdateAction()) {
            case onDelete:
               this.print0(this.ucase ? "ON DELETE " : "on delete ");
               break;
            case onUpdate:
               this.print0(this.ucase ? "ON UPDATE " : "on update ");
               break;
            case noAction:
               this.print0(this.ucase ? "NO ACTION " : "no action ");
               break;
            case restrict:
               this.print0(this.ucase ? "RESTRICT " : "restrict ");
               break;
            case cascade:
               this.print0(this.ucase ? "CASCADE " : "cascade ");
               break;
            case setNull:
               this.print0(this.ucase ? "SET NULL " : "set null ");
               break;
            case setDefault:
               this.print0(this.ucase ? "SET DEFAULT " : "set default ");
         }
      }

      return false;
   }

   public void endVisit(PGColumnSimpleDefinitionExpr x) {
   }

   public boolean visit(PGColumnSimpleDefinitionExpr x) {
      return true;
   }

   public void endVisit(PGValuesTableSource.ValueRow x) {
   }

   public boolean visit(PGValuesTableSource.ValueRow x) {
      return true;
   }

   public void endVisit(PGAlterTableInheriteOrNotParentTable x) {
   }

   public boolean visit(PGAlterTableInheriteOrNotParentTable item) {
      if (item.isInherite()) {
         this.print0(this.ucase ? "INHERIT " : "inherit ");
      } else {
         this.print0(this.ucase ? "NO INHERIT " : "no inherit ");
      }

      item.getParentTable().accept(this);
      this.print0(" ");
      return false;
   }

   public void endVisit(PGAlterTableOf x) {
   }

   public boolean visit(PGAlterTableOf item) {
      if (item.isOf()) {
         this.print0(this.ucase ? "OF " : "of ");
         item.getTypeName().accept(this);
      }

      if (item.isNotOf()) {
         this.print0(this.ucase ? "NOT OF " : "not of ");
      }

      if (item.isOwn()) {
         this.print0(this.ucase ? "OWNER TO  " : "owner to  ");
         item.getNewOwner().accept(this);
      }

      this.print0(" ");
      return false;
   }

   public void endVisit(PGAlterTableRenameColumn x) {
   }

   public boolean visit(PGAlterTableRenameColumn item) {
      this.print0(this.ucase ? "RENAME COLUMN " : "rename column ");
      item.getCol().accept(this);
      this.print0(this.ucase ? " TO " : " to ");
      item.getTo().accept(this);
      return false;
   }

   public void endVisit(PGAlterTableRenameConstraint x) {
   }

   public boolean visit(PGAlterTableRenameConstraint item) {
      this.print0(this.ucase ? "RENAME CONSTRAINT " : "rename constraint ");
      item.getCol().accept(this);
      this.print0(this.ucase ? " TO " : " to ");
      item.getTo().accept(this);
      return false;
   }

   public void endVisit(PGAlterTableRenameTo x) {
   }

   public boolean visit(PGAlterTableRenameTo x) {
      this.print0(this.ucase ? "RENAME TO " : "rename to ");
      x.getTo().accept(this);
      return false;
   }

   public void endVisit(PGAlterTableSetNewTableSpace x) {
   }

   public boolean visit(PGAlterTableSetNewTableSpace item) {
      this.print0(this.ucase ? "ALL IN TABLESPACE " : "all in tablespace ");
      item.getName().accept(this);
      this.print0(" ");
      if (item.getOwners() != null && item.getOwners().size() > 0) {
         this.print0(this.ucase ? "OWNED BY " : "owned by ");

         for(int i = 0; i < item.getOwners().size(); ++i) {
            ((SQLExpr)item.getOwners().get(i)).accept(this);
            if (i != item.getOwners().size() - 1) {
               this.print(",");
            }
         }

         this.print0(" ");
      }

      this.print0(this.ucase ? "SET TABLESPACE " : "set tablespace ");
      item.getNewTablespace().accept(this);
      if (item.isNowait()) {
         this.print0(this.ucase ? " NOWAIT " : " nowait ");
      }

      return false;
   }

   public void endVisit(PGAlterTableSetReset x) {
   }

   public boolean visit(PGAlterTableSetReset item) {
      if (item.isSet()) {
         this.print0(this.ucase ? "SET " : "set ");
      } else {
         this.print0(this.ucase ? "RESET " : "reset ");
      }

      if (item.isCluster()) {
         this.print0(this.ucase ? "WITHOUT CLUSTER " : "without cluster ");
         return false;
      } else if (item.isOids()) {
         this.print0(this.ucase ? "WITHOUT OIDS" : "without oids ");
         return false;
      } else if (item.getTablespace() != null) {
         this.print0(this.ucase ? "TABLESPACE  " : "tablespace ");
         item.getTablespace().accept(this);
         this.print0(" ");
         return false;
      } else {
         List<PGAlterTableSetReset.StorageParameter> parameters = item.getParameters();
         if (parameters != null && parameters.size() > 0) {
            this.print0("(");

            for(int i = 0; i < parameters.size(); ++i) {
               PGAlterTableSetReset.StorageParameter parameter = (PGAlterTableSetReset.StorageParameter)parameters.get(i);
               parameter.getParameter().accept(this);
               SQLExpr value = parameter.getValue();
               if (value != null) {
                  this.print0("=");
                  value.accept(this);
               }

               if (i != parameters.size() - 1) {
                  this.print0(",");
               }
            }

            this.print0(")");
         }

         return false;
      }
   }

   public void endVisit(PGAlterTableSetReset.StorageParameter x) {
   }

   public boolean visit(PGAlterTableSetReset.StorageParameter x) {
      return true;
   }

   public void endVisit(PGAlterTableSetSchema x) {
   }

   public boolean visit(PGAlterTableSetSchema x) {
      this.print0(this.ucase ? "SET SCHEMA " : "set schema ");
      x.getSchema().accept(this);
      return false;
   }

   public void endVisit(PGAlterTableSetTableSpace x) {
   }

   public boolean visit(PGAlterTableSetTableSpace item) {
      this.print0(this.ucase ? "SET TABLESPACE " : "set tablespace ");
      item.getName().accept(this);
      return false;
   }

   public void endVisit(PGAlterTableSetWith x) {
   }

   public boolean visit(PGAlterTableSetWith item) {
      this.print0(this.ucase ? "SET " : "set ");
      switch (item.getDistributeType()) {
         case with:
            this.print0(this.ucase ? "WITH (REORGANIZE=" : "with (reorganize=");
            this.print0(item.isWithReorgnize() ? "true" : "false");
            this.print0(")");
            break;
         case by:
            this.print0(this.ucase ? "DISTRIBUTED BY (" : "distributed by (");

            for(int i = 0; i < item.getOptions().size(); ++i) {
               PGAlterTableSetWith.PGAlterTableDistributeByOption option = (PGAlterTableSetWith.PGAlterTableDistributeByOption)item.getOptions().get(i);
               option.getColumnName().accept(this);
               if (option.getOpClass() != null) {
                  this.print0(" ");
                  option.getOpClass().accept(this);
               }

               if (i != item.getOptions().size() - 1) {
                  this.print0(",");
               }
            }

            this.print0(")");
            break;
         case randomly:
            this.print0(this.ucase ? "DISTRIBUTED RANDOMLY" : "distributed randomly");
            break;
         case replicated:
            this.print0(this.ucase ? "DISTRIBUTED REPLICATED" : "distributed replicated");
      }

      return false;
   }

   public void endVisit(PGAlterTableSetWith.PGAlterTableDistributeByOption x) {
   }

   public boolean visit(PGAlterTableSetWith.PGAlterTableDistributeByOption x) {
      return true;
   }

   public void endVisit(PGAlterTableValidateConstraint x) {
   }

   public boolean visit(PGAlterTableValidateConstraint x) {
      this.print0(this.ucase ? "VALIDATE CONSTRAINT " : "validate constraint ");
      x.getConstraint().accept(this);
      this.print0(" ");
      return false;
   }

   public boolean visit(PGSQLPartitionBy x) {
      this.print0(this.ucase ? "PARTITION BY " : " partition by ");
      SQLName partitionType = x.getPartitionType();
      partitionType.accept(this);
      this.print0(" (");
      x.getColumn().accept(this);
      this.print0(")\n");
      ArrayList<PGSQLPartitionBy> subPartitionByList = x.getSubPartitionByList();
      if (subPartitionByList != null && subPartitionByList.size() > 0) {
         boolean ifUseTemplate = ((PGSQLPartitionBy)subPartitionByList.get(0)).isIfUseTemplate();
         if (!ifUseTemplate) {
            for(PGSQLPartitionBy subPartitionBy : subPartitionByList) {
               this.print0(this.ucase ? " SUBPARTITION BY " : " subpartition by ");
               this.print0("(");
               subPartitionBy.getPartitionType().accept(this);
               this.print0(")");
               this.print0("\n ");
            }

            this.print0(this.visitPartitionRecursive(x, 0));
            return false;
         }

         for(PGSQLPartitionBy subPartitionBy : subPartitionByList) {
            this.print0(this.ucase ? " SUBPARTITION BY " : " subpartition by ");
            subPartitionBy.getPartitionType().accept(this);
            this.print0(" (");
            subPartitionBy.getColumn().accept(this);
            this.print0(")\n");
            this.print0(this.ucase ? "  SUBPARTITION TEMPLATE" : "  subpartition template");
            this.print0(" (\n ");
            ArrayList<PGSQLPartition> subPartitionList = subPartitionBy.getPartitionList();
            if (subPartitionList != null && subPartitionList.size() > 0) {
               this.printAndAccept(subPartitionList, ",\n ");
            }

            this.print0(")\n");
         }
      }

      this.print0("(");
      List<PGSQLPartition> specList = x.getPartitionList();
      if (specList != null && specList.size() > 0) {
         this.printAndAccept(specList, ",\n");
      }

      this.print0("\n) ");
      return false;
   }

   private String visitPartitionRecursive(PGSQLPartitionBy partitionBy, int level) {
      ArrayList<PGSQLPartitionBy> subPartitionByList = partitionBy.getSubPartitionByList();
      ArrayList<PGSQLPartition> crtPartitions;
      if (level == 0) {
         crtPartitions = partitionBy.getPartitionList();
      } else {
         crtPartitions = ((PGSQLPartitionBy)subPartitionByList.get(level - 1)).getPartitionList();
      }

      if (level == subPartitionByList.size()) {
         return "(" + StringJoin.join(crtPartitions, ",") + ")";
      } else {
         String result = "(";

         for(PGSQLPartition crtPartition : crtPartitions) {
            if (!"(".equals(result)) {
               result = result + ",\n";
            }

            result = result + crtPartition + "\n" + this.visitPartitionRecursive(partitionBy, level + 1);
         }

         result = result + ")";
         return result;
      }
   }

   public boolean visit(PGSQLIndexSpec x) {
      x.getName().accept(this);
      SQLExpr collateParam = x.getCollateParam();
      if (collateParam != null) {
         this.print0(this.ucase ? " COLLATE " : " collate ");
         collateParam.accept(this);
      }

      SQLName opclass = x.getOpclass();
      if (opclass != null) {
         this.print0(" ");
         opclass.accept(this);
      }

      if (x.isAsc()) {
         this.print0(this.ucase ? " ASC " : " asc ");
      } else if (x.isDesc()) {
         this.print0(this.ucase ? " DESC " : " desc ");
      }

      if (x.isNullsFirst()) {
         this.print0(this.ucase ? " NULLS FIRST " : " nulls first ");
      } else if (x.isNullsLast()) {
         this.print0(this.ucase ? " NULLS LAST " : " nulls last ");
      }

      return false;
   }

   public boolean visit(PGSelectQueryBlock.ForClauses x) {
      if (x != null && x.getClauses() != null && x.getClauses().size() > 0) {
         for(int i = 0; i < x.getClauses().size(); ++i) {
            PGSelectQueryBlock.ForClause forClause = (PGSelectQueryBlock.ForClause)x.getClauses().get(i);
            forClause.accept(this);
            if (i != x.getClauses().size() - 1) {
               this.println();
            }
         }
      }

      return false;
   }

   public void endVisit(PGSelectQueryBlock.ForClauses x) {
   }

   public boolean visit(PGCreateSeqenceStatement x) {
      this.print0(this.ucase ? " CREATE " : " create ");
      if (x.isTemp()) {
         this.print0(this.ucase ? " TEMP " : " temp ");
      }

      if (x.isTemporary()) {
         this.print0(this.ucase ? " TEMPORARY " : " temporary ");
      }

      this.print0(this.ucase ? " SEQUENCE " : " sequence ");
      x.getSqeunceName().accept(this);
      if (x.isIncrement()) {
         this.print0(this.ucase ? " INCREMENT " : " increment ");
         x.getIncrementValue().accept(this);
      }

      if (x.isIncrementBy()) {
         this.print0(this.ucase ? " INCREMENT BY " : " increment by ");
         x.getIncrementValue().accept(this);
      }

      if (x.isMin()) {
         this.print0(this.ucase ? " MINVALUE " : " minvalue ");
         x.getMinValue().accept(this);
      }

      if (x.isMax()) {
         this.print0(this.ucase ? " MAXVALUE " : " maxvalue ");
         x.getMaxValue().accept(this);
      }

      if (x.isNoMax()) {
         this.print0(this.ucase ? " NO MAXVALUE " : " no maxvalue ");
      }

      if (x.isNoMin()) {
         this.print0(this.ucase ? " NO MINVALUE " : " no minvalue ");
      }

      if (x.isStart()) {
         this.print0(this.ucase ? " START " : " start ");
         x.getStartValue().accept(this);
      }

      if (x.isStartWith()) {
         this.print0(this.ucase ? " START WITH " : " start with ");
         x.getStartValue().accept(this);
      }

      if (x.isCache()) {
         this.print0(this.ucase ? " CACHE " : " cache ");
         x.getCacheName().accept(this);
      }

      if (x.isCycle()) {
         this.print0(this.ucase ? " CYCLE " : " cycle ");
      }

      if (x.isNoCycle()) {
         this.print0(this.ucase ? " NO CYCLE " : " no cycle ");
      }

      if (x.isOwnedBy()) {
         this.print0(this.ucase ? " OWNED BY " : " owned by ");
         x.getOwnedByName().accept(this);
      }

      return false;
   }

   public boolean visit(PGCreateTableSpaceStatement x) {
      this.print0(this.ucase ? " CREATE TABLESPACE " : " create tablespace ");
      x.getTableSpaceName().accept(this);
      if (x.isOwner()) {
         this.print0(this.ucase ? " OWNER " : " owner ");
         x.getOwnerName().accept(this);
      }

      this.print0(this.ucase ? " LOCATION " : " location ");
      x.getLocationDir().accept(this);
      if (x.isWith()) {
         this.print0(this.ucase ? " WITH " : " with ");
         List<SQLUpdateSetItem> parameterList = x.getParameterList();
         if (parameterList != null && parameterList.size() > 0) {
            this.print0("(");
            this.printAndAccept(parameterList, ", ");
            this.print0(")");
         }
      }

      return false;
   }

   public boolean visit(PGAlterViewStatement x) {
      this.print0(this.ucase ? " ALTER VIEW " : " alter view ");
      if (x.isIfExists()) {
         this.printUcase(" IF EXISTS ");
      }

      x.getViewName().accept(this);
      if (x.isRenameTo()) {
         this.print0(this.ucase ? " RENAME TO " : " rename to ");
         x.getNewViewName().accept(this);
      } else if (x.isAlter()) {
         this.print0(this.ucase ? " ALTER COLUMN  " : " alter column ");
         x.getColumnName().accept(this);
         if (x.isSetDefault()) {
            this.print0(this.ucase ? " SET DEFAULT  " : " set default ");
            x.getDefaultValue().accept(this);
            this.print0(";");
         } else if (x.isDropDefault()) {
            this.print0(this.ucase ? " DROP DEFAULT  " : " drop default ");
         }
      } else if (x.isOwnerTo()) {
         this.print0(this.ucase ? " OWNER TO " : " owner to ");
         x.getNewOwner().accept(this);
      } else if (x.isSetSchema()) {
         this.print0(this.ucase ? " SET SCHEMA " : " set schema ");
         x.getNewSchema().accept(this);
      } else if (x.isSet()) {
         this.print0(this.ucase ? " SET " : " set ");
         List<SQLUpdateSetItem> parameterList = x.getParameterList();
         if (parameterList != null && parameterList.size() > 0) {
            this.print0("(");
            this.printAndAccept(parameterList, ", ");
            this.print0(")");
         } else {
            List<SQLExpr> itemList = x.getItemList();
            if (itemList != null && itemList.size() > 0) {
               this.print0("(");
               this.printAndAccept(itemList, ", ");
               this.print0(")");
            }
         }
      } else if (x.isReset()) {
         this.print0(this.ucase ? " RESET " : " reset ");
         List<SQLExpr> itemList = x.getItemList();
         if (itemList != null && itemList.size() > 0) {
            this.print0("(");
            this.printAndAccept(itemList, ", ");
            this.print0(")");
         }
      }

      return false;
   }

   public boolean visit(PGSQLObjectCollection datas) {
      if (datas != null && datas.size() > 0) {
         for(int i = 0; i < datas.size(); ++i) {
            datas.get(i).accept(this);
            if (i != datas.size() - 1) {
               this.print0(",");
            }
         }
      }

      return false;
   }

   public void endVisit(PGSQLObjectCollection x) {
   }

   public void endVisit(PGGrantStatement x) {
   }

   public boolean visit(PGGrantStatement x) {
      this.print0(this.ucase ? "GRANT " : "grant ");
      this.printAndAccept(x.getPrivileges(), ", ");
      this.printGrantOn(x);
      if (x.getUsers() != null && x.getUsers().size() > 0) {
         this.print0(this.ucase ? " TO " : " to ");
         this.printAndAccept(x.getUsers(), ",");
      }

      if (x.getGroups() != null && x.getGroups().size() > 0) {
         this.print0(this.ucase ? " TO Group " : " to group ");
         this.printAndAccept(x.getGroups(), ",");
      }

      if (x.getWithGrantOption()) {
         this.print0(this.ucase ? " WITH GRANT OPTION" : " with grant option");
      }

      boolean with = false;
      SQLExpr maxQueriesPerHour = x.getMaxQueriesPerHour();
      if (maxQueriesPerHour != null) {
         if (!with) {
            this.print0(this.ucase ? " WITH" : " with");
            with = true;
         }

         this.print0(this.ucase ? " MAX_QUERIES_PER_HOUR " : " max_queries_per_hour ");
         maxQueriesPerHour.accept(this);
      }

      SQLExpr maxUpdatesPerHour = x.getMaxUpdatesPerHour();
      if (maxUpdatesPerHour != null) {
         if (!with) {
            this.print0(this.ucase ? " WITH" : " with");
            with = true;
         }

         this.print0(this.ucase ? " MAX_UPDATES_PER_HOUR " : " max_updates_per_hour ");
         maxUpdatesPerHour.accept(this);
      }

      SQLExpr maxConnectionsPerHour = x.getMaxConnectionsPerHour();
      if (maxConnectionsPerHour != null) {
         if (!with) {
            this.print0(this.ucase ? " WITH" : " with");
            with = true;
         }

         this.print0(this.ucase ? " MAX_CONNECTIONS_PER_HOUR " : " max_connections_per_hour ");
         maxConnectionsPerHour.accept(this);
      }

      SQLExpr maxUserConnections = x.getMaxUserConnections();
      if (maxUserConnections != null) {
         if (!with) {
            this.print0(this.ucase ? " WITH" : " with");
            with = true;
         }

         this.print0(this.ucase ? " MAX_USER_CONNECTIONS " : " max_user_connections ");
         maxUserConnections.accept(this);
      }

      if (x.isAdminOption()) {
         if (!with) {
            this.print0(this.ucase ? " WITH" : " with");
            with = true;
         }

         this.print0(this.ucase ? " ADMIN OPTION" : " admin option");
      }

      if (x.getIdentifiedBy() != null) {
         this.print0(this.ucase ? " IDENTIFIED BY " : " identified by ");
         x.getIdentifiedBy().accept(this);
      }

      return false;
   }

   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);
         SQLExpr target = item.getTarget();
         target.accept(this);
         SQLExpr value = item.getValue();
         if (target instanceof SQLIdentifierExpr && ((SQLIdentifierExpr)target).getName().equalsIgnoreCase("TIME ZONE")) {
            this.print(' ');
         } else if (value instanceof SQLPropertyExpr && ((SQLPropertyExpr)value).getOwner() instanceof SQLVariantRefExpr) {
            this.print0(" := ");
         } else {
            this.print0(" TO ");
         }

         if (value instanceof SQLListExpr) {
            SQLListExpr listExpr = (SQLListExpr)value;
            this.printAndAccept(listExpr.getItems(), ", ");
         } else {
            value.accept(this);
         }
      }

      return false;
   }

   public boolean visit(SQLCreateUserStatement x) {
      this.print0(this.ucase ? "CREATE USER " : "create user ");
      x.getUser().accept(this);
      this.print0(this.ucase ? " PASSWORD " : " password ");
      SQLExpr passoword = x.getPassword();
      if (passoword instanceof SQLIdentifierExpr) {
         this.print('\'');
         passoword.accept(this);
         this.print('\'');
      } else {
         passoword.accept(this);
      }

      return false;
   }

   protected void printGrantPrivileges(SQLGrantStatement x) {
      List<SQLPrivilegeItem> privileges = x.getPrivileges();
      int i = 0;

      for(SQLPrivilegeItem privilege : privileges) {
         if (i != 0) {
            this.print(", ");
         }

         SQLExpr action = privilege.getAction();
         if (action instanceof SQLIdentifierExpr) {
            String name = ((SQLIdentifierExpr)action).getName();
            if ("RESOURCE".equalsIgnoreCase(name)) {
               continue;
            }
         }

         privilege.accept(this);
         ++i;
      }

   }

   public boolean visit(SQLGrantStatement x) {
      if (x.getResource() == null) {
         this.print("ALTER ROLE ");
         this.printAndAccept(x.getUsers(), ",");
         this.print(' ');
         Set<SQLIdentifierExpr> pgPrivilegs = new LinkedHashSet();

         for(SQLPrivilegeItem privilege : x.getPrivileges()) {
            SQLExpr action = privilege.getAction();
            if (action instanceof SQLIdentifierExpr) {
               String name = ((SQLIdentifierExpr)action).getName();
               if (name.equalsIgnoreCase("CONNECT")) {
                  pgPrivilegs.add(new SQLIdentifierExpr("LOGIN"));
               }

               if (name.toLowerCase().startsWith("create ")) {
                  pgPrivilegs.add(new SQLIdentifierExpr("CREATEDB"));
               }
            }
         }

         int i = 0;

         for(SQLExpr privilege : pgPrivilegs) {
            if (i != 0) {
               this.print(' ');
            }

            privilege.accept(this);
            ++i;
         }

         return false;
      } else {
         return super.visit(x);
      }
   }

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

   private void space() {
      this.print0(" ");
   }
}
