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

import com.chenyang.druid.DbType;
import com.chenyang.druid.sql.ast.SQLCommentHint;
import com.chenyang.druid.sql.ast.SQLExpr;
import com.chenyang.druid.sql.ast.SQLName;
import com.chenyang.druid.sql.ast.SQLObject;
import com.chenyang.druid.sql.ast.SQLStatement;
import com.chenyang.druid.sql.ast.expr.SQLAllColumnExpr;
import com.chenyang.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.chenyang.druid.sql.ast.expr.SQLBinaryOperator;
import com.chenyang.druid.sql.ast.expr.SQLCharExpr;
import com.chenyang.druid.sql.ast.expr.SQLCurrentOfCursorExpr;
import com.chenyang.druid.sql.ast.expr.SQLDateExpr;
import com.chenyang.druid.sql.ast.expr.SQLIdentifierExpr;
import com.chenyang.druid.sql.ast.expr.SQLListExpr;
import com.chenyang.druid.sql.ast.expr.SQLQueryExpr;
import com.chenyang.druid.sql.ast.expr.SQLRealExpr;
import com.chenyang.druid.sql.ast.expr.SQLTimestampExpr;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableAlterColumn;
import com.chenyang.druid.sql.ast.statement.SQLColumnDefinition;
import com.chenyang.druid.sql.ast.statement.SQLCommitStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateContextStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateDirectoryStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateDomainStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateFunctionStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateIndexStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateProcedureStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropDatabaseStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropSequenceStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLExprTableSource;
import com.chenyang.druid.sql.ast.statement.SQLGrantStatement;
import com.chenyang.druid.sql.ast.statement.SQLInsertStatement;
import com.chenyang.druid.sql.ast.statement.SQLObjectType;
import com.chenyang.druid.sql.ast.statement.SQLPrivilegeItem;
import com.chenyang.druid.sql.ast.statement.SQLRollbackStatement;
import com.chenyang.druid.sql.ast.statement.SQLSelect;
import com.chenyang.druid.sql.ast.statement.SQLSetStatement;
import com.chenyang.druid.sql.ast.statement.SQLTableSource;
import com.chenyang.druid.sql.ast.statement.SQLUpdateSetItem;
import com.chenyang.druid.sql.ast.statement.SQLUpdateStatement;
import com.chenyang.druid.sql.ast.statement.SQLWithSubqueryClause;
import com.chenyang.druid.sql.dialect.postgresql.ast.PGSQLIndexSpec;
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.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.PGGrantStatement;
import com.chenyang.druid.sql.dialect.postgresql.ast.stmt.PGInsertStatement;
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.parser.EOFParserException;
import com.chenyang.druid.sql.parser.Lexer;
import com.chenyang.druid.sql.parser.ParserException;
import com.chenyang.druid.sql.parser.SQLCreateTableParser;
import com.chenyang.druid.sql.parser.SQLExprParser;
import com.chenyang.druid.sql.parser.SQLParserFeature;
import com.chenyang.druid.sql.parser.SQLSelectParser;
import com.chenyang.druid.sql.parser.SQLStatementParser;
import com.chenyang.druid.sql.parser.Token;
import com.chenyang.druid.util.FnvHash;
import com.chenyang.druid.util.JdbcUtils;
import java.util.ArrayList;
import java.util.List;

public class PGSQLStatementParser extends SQLStatementParser {
   public static final String TIME_ZONE = "TIME ZONE";
   public static final String TIME = "TIME";
   public static final String LOCAL = "LOCAL";

   public PGSQLStatementParser(PGExprParser parser) {
      super((SQLExprParser)parser);
   }

   public PGSQLStatementParser(String sql) {
      super((SQLExprParser)(new PGExprParser(sql)));
   }

   public PGSQLStatementParser(String sql, SQLParserFeature... features) {
      super((SQLExprParser)(new PGExprParser(sql, features)));
   }

   public PGSQLStatementParser(Lexer lexer) {
      super((SQLExprParser)(new PGExprParser(lexer)));
   }

   public PGSelectParser createSQLSelectParser() {
      return new PGSelectParser(this.exprParser, this.selectListCache);
   }

   public SQLUpdateStatement parseUpdateStatement() {
      this.accept(Token.UPDATE);
      PGUpdateStatement udpateStatement = new PGUpdateStatement();
      SQLSelectParser selectParser = this.exprParser.createSelectParser();
      SQLTableSource tableSource = selectParser.parseTableSource();
      udpateStatement.setTableSource(tableSource);
      this.parseUpdateSet(udpateStatement);
      if (this.lexer.token() == Token.FROM) {
         this.lexer.nextToken();
         SQLTableSource from = selectParser.parseTableSource();
         udpateStatement.setFrom(from);
      }

      if (this.lexer.token() == Token.WHERE) {
         this.lexer.nextToken();
         udpateStatement.setWhere(this.exprParser.expr());
      }

      if (this.lexer.token() == Token.RETURNING) {
         this.lexer.nextToken();

         while(true) {
            udpateStatement.getReturning().add(this.exprParser.expr());
            if (this.lexer.token() != Token.COMMA) {
               break;
            }

            this.lexer.nextToken();
         }
      }

      return udpateStatement;
   }

   public PGInsertStatement parseInsert() {
      PGInsertStatement stmt = new PGInsertStatement();
      if (this.lexer.token() == Token.INSERT) {
         this.lexer.nextToken();
         this.accept(Token.INTO);
         SQLName tableName = this.exprParser.name();
         stmt.setTableName(tableName);
         if (this.lexer.token() == Token.AS) {
            this.lexer.nextToken();
            stmt.setAlias(this.lexer.stringVal());
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.IDENTIFIER) {
            stmt.setAlias(this.lexer.stringVal());
            this.lexer.nextToken();
         }
      }

      if (this.lexer.token() == Token.DEFAULT) {
         this.lexer.nextToken();
         this.accept(Token.VALUES);
         stmt.setDefaultValues(true);
      }

      if (this.lexer.token() == Token.LPAREN) {
         this.lexer.nextToken();
         this.exprParser.exprList(stmt.getColumns(), stmt);
         this.accept(Token.RPAREN);
      }

      if (this.lexer.token() == Token.VALUES) {
         this.lexer.nextToken();

         while(true) {
            this.accept(Token.LPAREN);
            SQLInsertStatement.ValuesClause valuesCaluse = new SQLInsertStatement.ValuesClause();
            this.exprParser.exprList(valuesCaluse.getValues(), valuesCaluse);
            stmt.addValueCause(valuesCaluse);
            this.accept(Token.RPAREN);
            if (this.lexer.token() != Token.COMMA) {
               break;
            }

            this.lexer.nextToken();
         }
      } else if (this.lexer.token() == Token.SELECT) {
         SQLQueryExpr queryExpr = (SQLQueryExpr)this.exprParser.expr();
         stmt.setQuery(queryExpr.getSubQuery());
      }

      if (this.lexer.token() == Token.ON) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals(FnvHash.Constants.CONFLICT)) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.LPAREN) {
               this.lexer.nextToken();
               List<SQLExpr> onConflictTarget = new ArrayList();
               this.exprParser.exprList(onConflictTarget, stmt);
               stmt.setOnConflictTarget(onConflictTarget);
               this.accept(Token.RPAREN);
            }

            if (this.lexer.token() == Token.ON) {
               this.lexer.nextToken();
               this.accept(Token.CONSTRAINT);
               SQLName constraintName = this.exprParser.name();
               stmt.setOnConflictConstraint(constraintName);
            }

            if (this.lexer.token() == Token.WHERE) {
               this.lexer.nextToken();
               SQLExpr where = this.exprParser.expr();
               stmt.setOnConflictWhere(where);
            }

            if (this.lexer.token() == Token.DO) {
               this.lexer.nextToken();
               if (this.lexer.identifierEquals(FnvHash.Constants.NOTHING)) {
                  this.lexer.nextToken();
                  stmt.setOnConflictDoNothing(true);
               } else {
                  this.accept(Token.UPDATE);
                  this.accept(Token.SET);

                  while(true) {
                     SQLUpdateSetItem item = this.exprParser.parseUpdateSetItem();
                     stmt.addConflicUpdateItem(item);
                     if (this.lexer.token() != Token.COMMA) {
                        if (this.lexer.token() == Token.WHERE) {
                           this.lexer.nextToken();
                           SQLExpr where = this.exprParser.expr();
                           stmt.setOnConflictUpdateWhere(where);
                        }
                        break;
                     }

                     this.lexer.nextToken();
                  }
               }
            }
         }
      }

      if (this.lexer.token() == Token.RETURNING) {
         this.lexer.nextToken();
         SQLExpr returning = this.exprParser.expr();
         if (this.lexer.token() == Token.COMMA) {
            this.lexer.nextToken();
            SQLListExpr list = new SQLListExpr();
            list.addItem(returning);
            this.exprParser.exprList(list.getItems(), list);
            returning = list;
         }

         stmt.setReturning(returning);
      }

      return stmt;
   }

   public PGCreateSchemaStatement parseCreateSchema() {
      this.accept(Token.CREATE);
      this.accept(Token.SCHEMA);
      PGCreateSchemaStatement stmt = new PGCreateSchemaStatement();
      if (this.lexer.token() == Token.IF) {
         this.lexer.nextToken();
         this.accept(Token.NOT);
         this.accept(Token.EXISTS);
         stmt.setIfNotExists(true);
      }

      while(this.lexer.token() != Token.COMMA && this.lexer.token() != Token.EOF) {
         if (this.lexer.token() == Token.CREATE) {
            SQLStatement statement = this.parseStatement();
            stmt.addElement(statement);
         } else if (this.lexer.token() == Token.IDENTIFIER) {
            if (this.lexer.identifierEquals("AUTHORIZATION")) {
               this.lexer.nextToken();
               stmt.setAuthorization(true);
               SQLIdentifierExpr userName = (SQLIdentifierExpr)this.exprParser.expr();
               stmt.setUserName(userName);
            } else {
               SQLIdentifierExpr schemaName = (SQLIdentifierExpr)this.exprParser.expr();
               stmt.setSchemaName(schemaName);
               if (this.lexer.identifierEquals("AUTHORIZATION")) {
                  this.lexer.nextToken();
                  stmt.setAuthorization(true);
                  SQLIdentifierExpr userName = (SQLIdentifierExpr)this.exprParser.expr();
                  stmt.setUserName(userName);
               }
            }
         }
      }

      return stmt;
   }

   protected SQLStatement parseAlterSchema() {
      this.accept(Token.ALTER);
      this.accept(Token.SCHEMA);
      PGAlterSchemaStatement stmt = new PGAlterSchemaStatement();
      stmt.setSchemaName(this.exprParser.identifier());
      if (this.lexer.identifierEquals(FnvHash.Constants.RENAME)) {
         this.lexer.nextToken();
         this.accept(Token.TO);
         stmt.setNewName(this.exprParser.identifier());
      } else if (this.lexer.identifierEquals(FnvHash.Constants.OWNER)) {
         this.lexer.nextToken();
         this.accept(Token.TO);
         stmt.setNewOwner(this.exprParser.identifier());
      }

      return stmt;
   }

   protected PGAlterDatabaseStatement parseAlterDatabase() {
      PGAlterDatabaseStatement stmt = new PGAlterDatabaseStatement();
      this.accept(Token.ALTER);
      this.accept(Token.DATABASE);
      stmt.setName(this.exprParser.name());
      if (this.lexer.token() == Token.WITH) {
         this.lexer.nextToken();
         this.acceptIdentifier("CONNECTION");
         this.accept(Token.LIMIT);
         stmt.setConnLimit(this.exprParser.expr());
      } else if (this.lexer.identifierEquals("RENAME")) {
         this.lexer.nextToken();
         this.accept(Token.TO);
         stmt.setNewName(this.exprParser.name());
      } else if (this.lexer.identifierEquals("OWNER")) {
         this.lexer.nextToken();
         this.accept(Token.TO);
         stmt.setNewOwner(this.exprParser.expr());
      } else if (this.lexer.token() == Token.SET) {
         this.lexer.nextToken();
         stmt.setType(PGAlterDatabaseStatement.SetType.Set);
         if (this.lexer.token() == Token.TABLESPACE) {
            this.lexer.nextToken();
            stmt.setNewTableSpace(this.exprParser.expr());
         } else {
            stmt.setParamter(this.exprParser.expr());
            if (this.lexer.token() != Token.TO && this.lexer.token() != Token.EQ) {
               if (this.lexer.token() == Token.FROM) {
                  this.lexer.nextToken();
                  this.accept(Token.CURRENT);
                  stmt.setSetFromCurrent(true);
               }
            } else {
               if (this.lexer.token() == Token.TO) {
                  stmt.setSetTo(true);
               } else if (this.lexer.token() == Token.EQ) {
                  stmt.setSetTo(false);
               }

               do {
                  this.lexer.nextToken();
                  SQLExpr e = this.exprParser.expr();
                  stmt.addValue(e);
               } while(this.lexer.token() == Token.COMMA);
            }
         }
      } else if (this.lexer.identifierEquals("RESET")) {
         this.lexer.nextToken();
         stmt.setType(PGAlterDatabaseStatement.SetType.Reset);
         if (this.lexer.token() != Token.ALL) {
            stmt.setParamter(this.exprParser.expr());
         } else {
            this.accept(Token.ALL);
         }
      }

      return stmt;
   }

   public PGDropSchemaStatement parseDropSchema() {
      PGDropSchemaStatement stmt = new PGDropSchemaStatement();
      stmt.setDbType(this.dbType);
      this.accept(Token.SCHEMA);
      if (this.lexer.token() == Token.IF) {
         this.lexer.nextToken();
         this.accept(Token.EXISTS);
         stmt.setIfExists(true);
      }

      while(true) {
         stmt.getSchemaList().add(new SQLIdentifierExpr(this.lexer.stringVal()));
         this.lexer.nextToken();
         if (this.lexer.token() != Token.COMMA) {
            if (this.lexer.token() != Token.RESTRICT && !this.lexer.identifierEquals(FnvHash.Constants.RESTRICT)) {
               if (this.lexer.token() != Token.CASCADE && !this.lexer.identifierEquals(FnvHash.Constants.CASCADE)) {
                  stmt.setCascade(false);
               } else {
                  this.lexer.nextToken();
                  stmt.setCascade(true);
               }
            } else {
               this.lexer.nextToken();
               stmt.setRestrict(true);
            }

            return stmt;
         }

         this.lexer.nextToken();
      }
   }

   public PGDeleteStatement parseDeleteStatement() {
      this.lexer.nextToken();
      PGDeleteStatement deleteStatement = new PGDeleteStatement();
      if (this.lexer.token() == Token.FROM) {
         this.lexer.nextToken();
      }

      if (this.lexer.token() == Token.ONLY) {
         this.lexer.nextToken();
         deleteStatement.setOnly(true);
      }

      SQLName tableName = this.exprParser.name();
      deleteStatement.setTableName(tableName);
      if (this.lexer.token() == Token.AS) {
         this.accept(Token.AS);
      }

      if (this.lexer.token() == Token.IDENTIFIER) {
         deleteStatement.setAlias(this.lexer.stringVal());
         this.lexer.nextToken();
      }

      if (this.lexer.token() == Token.USING) {
         this.lexer.nextToken();
         ArrayList<SQLTableSource> using = new ArrayList();

         while(this.lexer.token() != Token.WHERE) {
            SQLExprTableSource tableSource = new SQLExprTableSource();
            tableSource.setExpr((SQLExpr)this.exprParser.name());
            using.add(tableSource);
            if (this.lexer.token() == Token.COMMA) {
               this.lexer.nextToken();
            }
         }

         deleteStatement.setUsingList(using);
      }

      if (this.lexer.token() == Token.WHERE) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.CURRENT) {
            this.lexer.nextToken();
            this.accept(Token.OF);
            SQLName cursorName = this.exprParser.name();
            SQLExpr where = new SQLCurrentOfCursorExpr(cursorName);
            deleteStatement.setWhere(where);
         } else {
            SQLExpr where = this.exprParser.expr();
            deleteStatement.setWhere(where);
         }
      }

      if (this.lexer.token() == Token.RETURNING) {
         this.lexer.nextToken();
         this.accept(Token.STAR);
         deleteStatement.setReturning(true);
      }

      return deleteStatement;
   }

   public boolean parseStatementListDialect(List<SQLStatement> statementList) {
      switch (this.lexer.token()) {
         case BEGIN:
         case START:
            PGStartTransactionStatement stmt = this.parseBegin();
            statementList.add(stmt);
            return true;
         case WITH:
            statementList.add(this.parseWith());
            return true;
         default:
            if (this.lexer.identifierEquals(FnvHash.Constants.CONNECT)) {
               SQLStatement stmt2 = this.parseConnectTo();
               statementList.add(stmt2);
               return true;
            } else {
               return false;
            }
      }
   }

   protected PGStartTransactionStatement parseBegin() {
      PGStartTransactionStatement stmt = new PGStartTransactionStatement();
      if (this.lexer.token() == Token.START) {
         this.lexer.nextToken();
         this.acceptIdentifier("TRANSACTION");
      } else {
         this.accept(Token.BEGIN);
      }

      return stmt;
   }

   public SQLStatement parseConnectTo() {
      this.acceptIdentifier("CONNECT");
      this.accept(Token.TO);
      PGConnectToStatement stmt = new PGConnectToStatement();
      SQLName target = this.exprParser.name();
      stmt.setTarget(target);
      return stmt;
   }

   public PGSelectStatement parseSelect() {
      PGSelectParser selectParser = this.createSQLSelectParser();
      SQLSelect select = selectParser.select();
      return new PGSelectStatement(select);
   }

   public SQLStatement parseWith() {
      SQLWithSubqueryClause with = this.parseWithQuery();
      if (this.lexer.token() == Token.INSERT) {
         PGInsertStatement stmt = this.parseInsert();
         stmt.setWith(with);
         return stmt;
      } else if (this.lexer.token() != Token.SELECT && this.lexer.token() != Token.TABLE) {
         if (this.lexer.token() == Token.DELETE) {
            PGDeleteStatement stmt = this.parseDeleteStatement();
            stmt.setWith(with);
            return stmt;
         } else if (this.lexer.token() == Token.UPDATE) {
            PGUpdateStatement stmt = (PGUpdateStatement)this.parseUpdateStatement();
            stmt.setWith(with);
            return stmt;
         } else {
            throw new ParserException("TODO. " + this.lexer.info());
         }
      } else {
         PGSelectStatement stmt = this.parseSelect();
         stmt.getSelect().setWithSubQuery(with);
         return stmt;
      }
   }

   protected SQLAlterTableAlterColumn parseAlterColumn() {
      if (this.lexer.token() == Token.COLUMN) {
         this.lexer.nextToken();
      }

      SQLColumnDefinition column = this.exprParser.parseColumn();
      SQLAlterTableAlterColumn alterColumn = new SQLAlterTableAlterColumn();
      alterColumn.setColumn(column);
      if (column.getDataType() == null && column.getConstraints().size() == 0) {
         if (this.lexer.token() == Token.SET) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.NOT) {
               this.lexer.nextToken();
               this.accept(Token.NULL);
               alterColumn.setSetNotNull(true);
            } else {
               this.accept(Token.DEFAULT);
               SQLExpr defaultValue = this.exprParser.expr();
               alterColumn.setSetDefault(defaultValue);
            }
         } else if (this.lexer.token() == Token.DROP) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.NOT) {
               this.lexer.nextToken();
               this.accept(Token.NULL);
               alterColumn.setDropNotNull(true);
            } else {
               this.accept(Token.DEFAULT);
               alterColumn.setDropDefault(true);
            }
         }
      }

      return alterColumn;
   }

   public SQLStatement parseShow() {
      this.accept(Token.SHOW);
      PGShowStatement stmt = new PGShowStatement();
      switch (this.lexer.token()) {
         case ALL:
            stmt.setExpr(new SQLIdentifierExpr(Token.ALL.name()));
            this.lexer.nextToken();
            break;
         default:
            stmt.setExpr(this.exprParser.expr());
      }

      return stmt;
   }

   public SQLStatement parseCommit() {
      SQLCommitStatement stmt = new SQLCommitStatement();
      stmt.setDbType(this.dbType);
      this.lexer.nextToken();
      if (this.lexer.identifierEquals("WORK")) {
         stmt.setWork(true);
         this.lexer.nextToken();
      } else if (this.lexer.identifierEquals("TRANSACTION")) {
         stmt.setTransaction(true);
         this.lexer.nextToken();
      }

      return stmt;
   }

   public SQLStatement parseSet() {
      this.accept(Token.SET);
      Token token = this.lexer.token();
      String range = "";
      SQLSetStatement.Option option = null;
      if (token == Token.SESSION) {
         this.lexer.nextToken();
         range = Token.SESSION.name();
         option = SQLSetStatement.Option.SESSION;
      } else if (token == Token.IDENTIFIER && "LOCAL".equalsIgnoreCase(this.lexer.stringVal())) {
         range = "LOCAL";
         option = SQLSetStatement.Option.LOCAL;
         this.lexer.nextToken();
      }

      long hash = this.lexer.hash_lower();
      String parameter = this.lexer.stringVal();
      List<SQLExpr> values = new ArrayList();
      SQLExpr paramExpr;
      if (hash == FnvHash.Constants.TIME) {
         this.lexer.nextToken();
         this.acceptIdentifier("ZONE");
         paramExpr = new SQLIdentifierExpr("TIME ZONE");
         String value = this.lexer.stringVal();
         if (this.lexer.token() == Token.IDENTIFIER) {
            values.add(new SQLIdentifierExpr(value.toUpperCase()));
         } else {
            values.add(new SQLCharExpr(value));
         }

         this.lexer.nextToken();
      } else if (hash == FnvHash.Constants.ROLE) {
         paramExpr = new SQLIdentifierExpr(parameter);
         this.lexer.nextToken();
         values.add(this.exprParser.primary());
         this.lexer.nextToken();
      } else {
         paramExpr = new SQLIdentifierExpr(parameter);
         this.lexer.nextToken();

         for(; !this.lexer.isEOF(); this.lexer.nextToken()) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.LITERAL_CHARS) {
               values.add(new SQLCharExpr(this.lexer.stringVal()));
            } else if (this.lexer.token() == Token.LITERAL_INT) {
               values.add(new SQLIdentifierExpr(this.lexer.numberString()));
            } else if (!this.lexer.identifierEquals(FnvHash.Constants.JSON_SET) && !this.lexer.identifierEquals(FnvHash.Constants.JSONB_SET)) {
               values.add(new SQLIdentifierExpr(this.lexer.stringVal()));
            } else {
               SQLExpr json_set = this.exprParser.expr();
               values.add(json_set);
            }
         }
      }

      SQLExpr valueExpr;
      if (values.size() == 1) {
         valueExpr = (SQLExpr)values.get(0);
      } else {
         SQLListExpr listExpr = new SQLListExpr();

         for(SQLExpr value : values) {
            listExpr.addItem(value);
         }

         valueExpr = listExpr;
      }

      SQLSetStatement stmt = new SQLSetStatement(paramExpr, valueExpr, this.dbType);
      stmt.setOption(option);
      return stmt;
   }

   public PGCreateIndexStatement parseCreateIndex(boolean acceptCreate) {
      if (acceptCreate) {
         this.accept(Token.CREATE);
      }

      PGCreateIndexStatement stmt = new PGCreateIndexStatement(this.getDbType());
      stmt.setType("");
      if (this.lexer.token() == Token.UNIQUE) {
         stmt.setType("UNIQUE");
         this.lexer.nextToken();
      }

      this.accept(Token.INDEX);
      if (this.lexer.token() != Token.ON) {
         stmt.setName(this.exprParser.name());
      }

      this.accept(Token.ON);
      stmt.setTable(this.exprParser.name());
      if (this.lexer.token() == Token.USING) {
         this.lexer.nextToken();
         String using = this.lexer.stringVal();
         this.accept(Token.IDENTIFIER);
         stmt.setUsing(using);
      }

      this.accept(Token.LPAREN);

      while(true) {
         PGSQLIndexSpec spec = new PGSQLIndexSpec();
         stmt.getSpecList().add(spec);
         spec.setName(this.exprParser.expr());
         if (this.lexer.identifierEquals("COLLATE")) {
            this.lexer.nextToken();
            spec.setCollateParam(this.exprParser.expr());
         }

         if (this.lexer.token() != Token.ASC && !this.lexer.identifierEquals("NULLS") && this.lexer.token() != Token.COMMA && this.lexer.token() != Token.RPAREN) {
            spec.setOpclass(this.exprParser.name());
         }

         if (this.lexer.token() == Token.ASC) {
            this.lexer.nextToken();
            spec.setAsc(true);
         } else if (this.lexer.token() == Token.DESC) {
            this.lexer.nextToken();
            spec.setDesc(true);
         }

         if (this.lexer.identifierEquals("NULLS")) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.FIRST) {
               spec.setNullsFirst(true);
               this.lexer.nextToken();
            } else if (this.lexer.identifierEquals("LAST")) {
               spec.setNullsLast(true);
               this.lexer.nextToken();
            }
         }

         if (this.lexer.token() != Token.COMMA) {
            this.accept(Token.RPAREN);
            if (this.lexer.token() == Token.WITH) {
               this.lexer.nextToken();
               this.accept(Token.LPAREN);

               while(true) {
                  SQLUpdateSetItem item = this.exprParser.parseUpdateSetItem();
                  stmt.getWithList().add(item);
                  if (this.lexer.token() != Token.COMMA) {
                     this.accept(Token.RPAREN);
                     break;
                  }

                  this.lexer.nextToken();
               }
            }

            if (this.lexer.token() == Token.TABLESPACE) {
               this.lexer.nextToken();
               SQLName tablespace = this.exprParser.name();
               stmt.setTablespace(tablespace);
            }

            SQLExpr sqlExpr = this.parseWhere();
            if (sqlExpr != null) {
               stmt.setWhere(sqlExpr);
            }

            return stmt;
         }

         this.lexer.nextToken();
      }
   }

   public SQLExpr parseWhere() {
      if (this.lexer.token() != Token.WHERE) {
         return null;
      } else {
         this.lexer.nextTokenIdent();
         List<String> beforeComments = null;
         if (this.lexer.hasComment() && this.lexer.isKeepComments()) {
            beforeComments = this.lexer.readAndResetComments();
         }

         SQLExpr where;
         if (this.lexer.token() == Token.IDENTIFIER) {
            String ident = this.lexer.stringVal();
            long hash_lower = this.lexer.hash_lower();
            this.lexer.nextTokenEq();
            SQLExpr identExpr;
            if (this.lexer.token() == Token.LITERAL_CHARS) {
               String literal = this.lexer.stringVal();
               if (hash_lower == FnvHash.Constants.TIMESTAMP) {
                  identExpr = new SQLTimestampExpr(literal);
                  this.lexer.nextToken();
               } else if (hash_lower == FnvHash.Constants.DATE) {
                  identExpr = new SQLDateExpr(literal);
                  this.lexer.nextToken();
               } else if (hash_lower == FnvHash.Constants.REAL) {
                  identExpr = new SQLRealExpr(Float.parseFloat(literal));
                  this.lexer.nextToken();
               } else {
                  identExpr = new SQLIdentifierExpr(ident, hash_lower);
               }
            } else {
               identExpr = new SQLIdentifierExpr(ident, hash_lower);
            }

            if (this.lexer.token() == Token.DOT) {
               identExpr = this.exprParser.primaryRest(identExpr);
            }

            if (this.lexer.token() == Token.EQ) {
               this.lexer.nextToken();

               SQLExpr rightExp;
               try {
                  rightExp = this.exprParser.bitOr();
               } catch (EOFParserException e) {
                  throw new ParserException("EOF, " + ident + "=", e);
               }

               where = new SQLBinaryOpExpr(identExpr, SQLBinaryOperator.Equality, rightExp, this.dbType);
               switch (this.lexer.token()) {
                  case BETWEEN:
                  case IS:
                  case EQ:
                  case IN:
                  case CONTAINS:
                  case BANG_TILDE_STAR:
                  case TILDE_EQ:
                  case LT:
                  case LTEQ:
                  case LTEQGT:
                  case GT:
                  case GTEQ:
                  case LTGT:
                  case BANGEQ:
                  case LIKE:
                  case NOT:
                     where = this.exprParser.relationalRest(where);
                  default:
                     SQLExpr var11 = this.exprParser.andRest(where);
                     var11 = this.exprParser.xorRest(var11);
                     where = this.exprParser.orRest(var11);
               }
            } else {
               identExpr = this.exprParser.primaryRest(identExpr);
               where = this.exprParser.exprRest(identExpr);
            }
         } else {
            while(this.lexer.token() == Token.HINT) {
               this.lexer.nextToken();
            }

            where = this.exprParser.expr();

            while(this.lexer.token() == Token.HINT) {
               this.lexer.nextToken();
            }
         }

         if (beforeComments != null) {
            where.addBeforeComment(beforeComments);
         }

         if (this.lexer.hasComment() && this.lexer.isKeepComments() && this.lexer.token() != Token.INSERT) {
            where.addAfterComment(this.lexer.readAndResetComments());
         }

         return where;
      }
   }

   public SQLCreateTableParser getSQLCreateTableParser() {
      return new PGCreateTableParser(this.exprParser);
   }

   protected PGAlterIndexStatement parseAlterIndex() {
      PGAlterIndexStatement stmt = new PGAlterIndexStatement();
      this.accept(Token.INDEX);
      if (this.lexer.token() == Token.IF) {
         this.accept(Token.IF);
         this.accept(Token.EXISTS);
         stmt.setSetIfExists(true);
      }

      if (this.lexer.token() == Token.ALL) {
         this.accept(Token.ALL);
         this.accept(Token.IN);
         this.accept(Token.TABLESPACE);
         stmt.setSetAllIn(true);
         stmt.setName(new SQLIdentifierExpr(this.lexer.stringVal()));
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("OWNED")) {
            this.lexer.nextToken();
            this.accept(Token.BY);
            stmt.setSetOwnedBy(true);

            while(true) {
               stmt.getRoleList().add(new SQLIdentifierExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
               if (this.lexer.token() != Token.COMMA) {
                  break;
               }

               this.lexer.nextToken();
            }
         }

         if (this.lexer.token() == Token.SET) {
            this.accept(Token.SET);
            stmt.setType(PGAlterIndexStatement.SetType.Set);
            this.accept(Token.TABLESPACE);
            stmt.setNewTableSpace(this.exprParser.name());
            if (this.lexer.token() == Token.NOWAIT) {
               stmt.setSetNowait(true);
               this.lexer.nextToken();
            }
         }
      } else {
         stmt.setName(new SQLIdentifierExpr(this.lexer.stringVal()));
         this.lexer.nextToken();
      }

      if (this.lexer.token() == Token.SET) {
         this.accept(Token.SET);
         stmt.setType(PGAlterIndexStatement.SetType.Set);
         if (this.lexer.token() == Token.TABLESPACE) {
            this.accept(Token.TABLESPACE);
            stmt.setNewTableSpace(this.exprParser.name());
         }

         if (this.lexer.token() == Token.LPAREN) {
            this.accept(Token.LPAREN);

            while(true) {
               SQLUpdateSetItem item = this.exprParser.parseUpdateSetItem();
               stmt.getParameterList().add(item);
               if (this.lexer.token() != Token.COMMA) {
                  this.lexer.nextToken();
                  if (this.lexer.token() == Token.RPAREN) {
                     this.accept(Token.RPAREN);
                  }
                  break;
               }

               this.lexer.nextToken();
            }
         }
      }

      if (this.lexer.token() == Token.RESET) {
         this.accept(Token.RESET);
         stmt.setType(PGAlterIndexStatement.SetType.Reset);
         if (this.lexer.token() == Token.LPAREN) {
            this.accept(Token.LPAREN);

            while(true) {
               stmt.getItemList().add(new SQLIdentifierExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
               if (this.lexer.token() != Token.COMMA) {
                  this.lexer.nextToken();
                  if (this.lexer.token() == Token.RPAREN) {
                     this.accept(Token.RPAREN);
                  }
                  break;
               }

               this.lexer.nextToken();
            }
         }
      }

      if (this.lexer.identifierEquals("RENAME")) {
         this.lexer.nextToken();
         this.accept(Token.TO);
         stmt.setRenameTo(this.exprParser.name());
      }

      return stmt;
   }

   public PGAlterSequenceStatement parseAlterSequence() {
      PGAlterSequenceStatement stmt = new PGAlterSequenceStatement();
      this.accept(Token.SEQUENCE);
      if (this.lexer.token() == Token.IF) {
         this.accept(Token.IF);
         this.accept(Token.EXISTS);
         stmt.setIfExists(true);
      }

      stmt.setDbType(this.dbType);
      stmt.setName(this.exprParser.name());

      while(this.lexer.token() != Token.SEMI) {
         if (this.lexer.token() != Token.START && !this.lexer.identifierEquals(FnvHash.Constants.START)) {
            if (this.lexer.identifierEquals("INCREMENT")) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.BY) {
                  this.accept(Token.BY);
                  stmt.setBy(true);
               }

               stmt.setIncrementBy(this.exprParser.integerExpr());
            } else if (this.lexer.token() == Token.CACHE) {
               this.lexer.nextToken();
               stmt.setCache(Boolean.TRUE);
               stmt.setCacheValue(this.exprParser.integerExpr());
            } else if (this.lexer.token() == Token.RESTART) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.WITH) {
                  this.accept(Token.WITH);
                  stmt.setRestart(true);
               }

               stmt.setRestartWith(this.exprParser.integerExpr());
            } else if (this.lexer.identifierEquals("MINVALUE")) {
               this.lexer.nextToken();
               stmt.setMinValue(this.exprParser.integerExpr());
            } else if (this.lexer.identifierEquals("MAXVALUE")) {
               this.lexer.nextToken();
               stmt.setMaxValue(this.exprParser.integerExpr());
            } else if (this.lexer.identifierEquals("NO")) {
               this.lexer.nextToken();
               if (this.lexer.identifierEquals("MAXVALUE")) {
                  this.lexer.nextToken();
                  stmt.setNoMaxValue(true);
               } else if (this.lexer.identifierEquals("MINVALUE")) {
                  this.lexer.nextToken();
                  stmt.setNoMinValue(true);
               } else {
                  if (!this.lexer.identifierEquals("CYCLE")) {
                     break;
                  }

                  this.lexer.nextToken();
                  stmt.setCycle(true);
                  stmt.setCycleNo(Boolean.TRUE);
               }
            } else if (this.lexer.identifierEquals("CYCLE")) {
               this.lexer.nextToken();
               stmt.setCycle(Boolean.TRUE);
            } else if (this.lexer.identifierEquals("OWNED")) {
               this.lexer.nextToken();
               this.accept(Token.BY);
               stmt.setOwnedBy(true);
               stmt.setOwnedByName(this.exprParser.expr());
            } else if (this.lexer.identifierEquals("NONE")) {
               stmt.setNone(true);
               this.lexer.nextToken();
            } else if (this.lexer.identifierEquals("OWNER")) {
               this.lexer.nextToken();
               this.lexer.nextToken();
               stmt.setOwnerTo(true);
               stmt.setNewOwner(new SQLIdentifierExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
            } else if (this.lexer.identifierEquals("RENAME")) {
               this.lexer.nextToken();
               this.lexer.nextToken();
               stmt.setRenameTo(true);
               stmt.setNewName(new SQLIdentifierExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
            } else {
               if (this.lexer.token() != Token.SET) {
                  break;
               }

               this.lexer.nextToken();
               this.lexer.nextToken();
               stmt.setSetSchema(true);
               stmt.setNewSchema(new SQLIdentifierExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
            }
         } else {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.WITH) {
               this.accept(Token.WITH);
               stmt.setStart(true);
            }

            stmt.setStartWith(this.exprParser.integerExpr());
         }
      }

      return stmt;
   }

   public SQLStatement parseAlter() {
      Lexer.SavePoint mark = this.lexer.mark();
      this.accept(Token.ALTER);
      if (this.lexer.token() == Token.TABLE) {
         return this.parseAlterTable();
      } else if (this.lexer.token() == Token.SEQUENCE) {
         return this.parseAlterSequence();
      } else if (this.lexer.token() == Token.INDEX) {
         return this.parseAlterIndex();
      } else if (this.lexer.token() == Token.VIEW) {
         return this.parseAlterView();
      } else {
         this.lexer.reset(mark);
         return super.parseAlter();
      }
   }

   protected PGAlterTableStatement parseAlterTable() {
      this.lexer.nextToken();
      PGAlterTableStatement stmt = new PGAlterTableStatement();
      if (this.lexer.token() == Token.IF) {
         this.lexer.nextToken();
         this.accept(Token.EXISTS);
         stmt.setIfExists(true);
      }

      if (this.lexer.token() == Token.ONLY) {
         this.lexer.nextToken();
         stmt.setOnly(true);
      }

      if (this.lexer.token() == Token.ALL) {
         stmt.addItem(this.parseAlterTableTablespace());
         return stmt;
      } else {
         stmt.setName(this.exprParser.name());

         while(true) {
            if (this.lexer.token() == Token.COMMA) {
               this.lexer.nextToken();
            }

            if (this.lexer.token() == Token.EOF) {
               return stmt;
            }

            if (this.lexer.identifierEquals(FnvHash.Constants.RENAME)) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.CONSTRAINT) {
                  stmt.addItem(this.parseAlterTableRenameConstraint());
               } else if (this.lexer.token() == Token.TO) {
                  stmt.addItem(this.parseAlterTableRenameTo());
               } else {
                  stmt.addItem(this.parseAlterTableRenameColumn());
               }

               return stmt;
            }

            if (this.lexer.token() == Token.SET) {
               this.lexer.mark();
               this.lexer.nextToken();
               if (this.lexer.token() == Token.SCHEMA) {
                  this.lexer.nextToken();
                  PGAlterTableSetSchema item = new PGAlterTableSetSchema();
                  item.setSchema(this.exprParser.expr());
                  stmt.addItem(item);
                  return stmt;
               }

               if (this.lexer.token() == Token.WITH || this.lexer.identifierEquals("DISTRIBUTED")) {
                  stmt.addItem(this.parseAlterTableSetWith());
                  return stmt;
               }

               if (this.lexer.token() == Token.WITHOUT) {
                  this.lexer.nextToken();
                  stmt.addItem(this.parseAlterTableSetReset());
               } else if (this.lexer.token() == Token.TABLESPACE) {
                  PGAlterTableSetTableSpace item = new PGAlterTableSetTableSpace();
                  this.lexer.nextToken();
                  item.setName(this.exprParser.expr());
                  stmt.addItem(item);
               } else {
                  stmt.addItem(this.parseAlterTableSetReset());
               }
            } else if (this.lexer.token() == Token.RESET) {
               stmt.addItem(this.parseAlterTableSetReset());
            } else {
               if (this.lexer.identifierEquals(FnvHash.Constants.ADD)) {
                  this.lexer.nextToken();
                  if (this.lexer.token() != Token.CONSTRAINT) {
                     stmt.addItem(this.parseAlterTableAddColumn());
                     continue;
                  }

                  if (this.lexer.token() == Token.CONSTRAINT) {
                     stmt.addItem(this.parseAlterTableAddConstraint());
                     continue;
                  }
               }

               if (this.lexer.token() == Token.DROP) {
                  this.lexer.nextToken();
                  if (this.lexer.token() == Token.CONSTRAINT) {
                     stmt.addItem(this.parseAlterTableDropConstraint());
                  } else {
                     stmt.addItem(this.parseAlterTableDropColumn());
                  }
               } else if (this.lexer.token() == Token.ALTER) {
                  this.lexer.nextToken();
                  if (this.lexer.token() == Token.COLUMN) {
                     this.lexer.nextToken();
                  }

                  if (this.lexer.token() == Token.COLUMN) {
                     stmt.addItem(this.parseAlterTableAlterColumnOptions());
                  } else {
                     stmt.addItem(this.parseAlterTableAlterColumn());
                  }
               } else if (this.lexer.identifierEquals("VALIDATE")) {
                  PGAlterTableValidateConstraint item = new PGAlterTableValidateConstraint();
                  this.lexer.nextToken();
                  this.accept(Token.CONSTRAINT);
                  item.setConstraint(this.exprParser.expr());
                  stmt.addItem(item);
               } else if (this.lexer.token() != Token.DISABLE && this.lexer.token() != Token.ENABLE) {
                  if (this.lexer.identifierEquals("CLUSTER")) {
                     this.lexer.nextToken();
                     PGAlterTableCluster item = new PGAlterTableCluster();
                     this.accept(Token.ON);
                     item.setIndex(this.exprParser.expr());
                     stmt.addItem(item);
                  } else if (!this.lexer.identifierEquals("INHERIT") && !this.lexer.identifierEquals("NO")) {
                     if (this.lexer.token() == Token.OF) {
                        PGAlterTableOf item = new PGAlterTableOf();
                        this.lexer.nextToken();
                        item.setOf(true);
                        item.setTypeName(this.exprParser.expr());
                        stmt.addItem(item);
                     } else if (this.lexer.token() == Token.NOT) {
                        PGAlterTableOf item = new PGAlterTableOf();
                        this.lexer.nextToken();
                        item.setNotOf(true);
                        this.lexer.nextToken();
                        stmt.addItem(item);
                     } else {
                        if (!this.lexer.identifierEquals("OWNER")) {
                           return stmt;
                        }

                        this.lexer.nextToken();
                        PGAlterTableOf item = new PGAlterTableOf();
                        item.setOwn(true);
                        this.accept(Token.TO);
                        item.setNewOwner(this.exprParser.expr());
                        stmt.addItem(item);
                     }
                  } else {
                     PGAlterTableInheriteOrNotParentTable item = new PGAlterTableInheriteOrNotParentTable();
                     item.setInherite(this.lexer.identifierEquals("INHERIT"));
                     this.lexer.nextToken();
                     if (!item.isInherite()) {
                        this.lexer.nextToken();
                     }

                     item.setParentTable(this.exprParser.expr());
                     stmt.addItem(item);
                  }
               } else {
                  PGAlterTableDisableEnabelTrigger item = new PGAlterTableDisableEnabelTrigger();
                  item.setEnable(this.lexer.token() == Token.ENABLE);
                  this.lexer.nextToken();
                  this.accept(Token.TRIGGER);
                  if (this.lexer.token() == Token.ALL) {
                     this.lexer.nextToken();
                     item.setType(PGAlterTableDisableEnabelTrigger.Type.all);
                  } else if (this.lexer.token() == Token.USER) {
                     this.lexer.nextToken();
                     item.setType(PGAlterTableDisableEnabelTrigger.Type.user);
                  } else if (this.lexer.token() == Token.IDENTIFIER) {
                     item.setTrigger(this.exprParser.expr());
                  }

                  stmt.addItem(item);
               }
            }
         }
      }
   }

   private PGAlterTableSetNewTableSpace parseAlterTableTablespace() {
      this.lexer.nextToken();
      this.accept(Token.IN);
      this.accept(Token.TABLESPACE);
      SQLName name = this.exprParser.name();
      PGAlterTableSetNewTableSpace item = new PGAlterTableSetNewTableSpace();
      item.setName(name);
      if (this.lexer.identifierEquals("OWNED")) {
         this.lexer.nextToken();
         this.accept(Token.BY);

         while(true) {
            SQLExpr owner = this.exprParser.expr();
            item.addOwner(owner);
            if (this.lexer.token() == Token.SET) {
               break;
            }

            this.accept(Token.COMMA);
         }
      }

      this.accept(Token.SET);
      this.accept(Token.TABLESPACE);
      SQLExpr expr = this.exprParser.expr();
      item.setNewTablespace(expr);
      if (this.lexer.token() == Token.NOWAIT) {
         item.setNowait(true);
      }

      return item;
   }

   private PGAlterTableRenameColumn parseAlterTableRenameColumn() {
      if (this.lexer.token() == Token.COLUMN) {
         this.lexer.nextToken();
      }

      PGAlterTableRenameColumn item = new PGAlterTableRenameColumn();
      item.setCol(this.exprParser.expr());
      this.accept(Token.TO);
      item.setTo(this.exprParser.expr());
      return item;
   }

   private PGAlterTableRenameConstraint parseAlterTableRenameConstraint() {
      this.accept(Token.CONSTRAINT);
      PGAlterTableRenameConstraint item = new PGAlterTableRenameConstraint();
      item.setCol(this.exprParser.expr());
      this.accept(Token.TO);
      item.setTo(this.exprParser.expr());
      return item;
   }

   private PGAlterTableRenameTo parseAlterTableRenameTo() {
      this.lexer.nextToken();
      PGAlterTableRenameTo item = new PGAlterTableRenameTo();
      item.setTo(this.exprParser.expr());
      return item;
   }

   private PGAlterTableSetWith parseAlterTableSetWith() {
      PGAlterTableSetWith item = new PGAlterTableSetWith();
      if (this.lexer.token() == Token.WITH) {
         this.lexer.nextToken();
         item.setDistributeType(PGAlterTableSetWith.DistributeType.with);
         this.accept(Token.LPAREN);
         this.acceptIdentifier("REORGANIZE");
         this.accept(Token.EQ);
         SQLExpr expr = this.exprParser.expr();
         item.setWithReorgnize(expr.toString().equalsIgnoreCase("true"));
         this.accept(Token.RPAREN);
      } else if (this.lexer.identifierEquals("DISTRIBUTED")) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.BY) {
            this.lexer.nextToken();
            item.setDistributeType(PGAlterTableSetWith.DistributeType.by);
            this.accept(Token.LPAREN);

            do {
               PGAlterTableSetWith.PGAlterTableDistributeByOption option = new PGAlterTableSetWith.PGAlterTableDistributeByOption();
               option.setColumnName(this.exprParser.expr());
               if (this.lexer.token() != Token.COMMA && this.lexer.token() != Token.RPAREN) {
                  option.setOpClass(this.exprParser.expr());
               }

               if (this.lexer.token() == Token.COMMA) {
                  this.lexer.nextToken();
               }

               item.addOption(option);
            } while(this.lexer.token() != Token.RPAREN);

            this.accept(Token.RPAREN);
         } else if (this.lexer.identifierEquals("RANDOMLY")) {
            this.lexer.nextToken();
            item.setDistributeType(PGAlterTableSetWith.DistributeType.randomly);
         } else if (this.lexer.identifierEquals("REPLICATED")) {
            this.lexer.nextToken();
            item.setDistributeType(PGAlterTableSetWith.DistributeType.replicated);
         }
      }

      return item;
   }

   private PGAlterTableSetReset parseAlterTableSetReset() {
      PGAlterTableSetReset item = new PGAlterTableSetReset();
      if (this.lexer.identifierEquals("WITHOUT")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("CLUSTER")) {
            item.setSet(true);
            item.setCluster(true);
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("OIDS")) {
            item.setSet(true);
            item.setOids(true);
            this.lexer.nextToken();
         }
      } else if (this.lexer.token() == Token.RESET) {
         item.setSet(false);
         this.lexer.nextToken();
         this.accept(Token.LPAREN);

         do {
            PGAlterTableSetReset.StorageParameter parameter = new PGAlterTableSetReset.StorageParameter();
            parameter.setParameter(this.exprParser.expr());
            item.addParameter(parameter);
            if (this.lexer.token() == Token.COMMA && this.lexer.token() != Token.RPAREN) {
               this.lexer.nextToken();
            }
         } while(this.lexer.token() != Token.RPAREN);

         this.lexer.nextToken();
      } else {
         item.setSet(true);
         this.accept(Token.LPAREN);
         PGAlterTableSetReset.StorageParameter parameter = new PGAlterTableSetReset.StorageParameter();
         SQLExpr expr = this.exprParser.expr();
         if (expr instanceof SQLBinaryOpExpr) {
            SQLBinaryOpExpr bin = (SQLBinaryOpExpr)expr;
            parameter.setParameter(bin.getLeft());
            parameter.setValue(bin.getRight());
         } else {
            parameter.setParameter(expr);
            this.accept(Token.EQ);
            parameter.setValue(this.exprParser.expr());
         }

         item.addParameter(parameter);
         this.accept(Token.RPAREN);
      }

      return item;
   }

   protected PGAlterTableAddColumn parseAlterTableAddColumn() {
      if (this.lexer.token() == Token.COLUMN) {
         this.lexer.nextToken();
      }

      PGAlterTableAddColumn item = new PGAlterTableAddColumn();
      PGColumnDefinition col = new PGColumnDefinition();
      col.setName(this.exprParser.name());
      col.setType(this.exprParser.expr());
      item.addColumn(col);
      if (this.lexer.token() == Token.DEFAULT) {
         this.lexer.nextToken();
         SQLExpr defaultExpr = this.exprParser.expr();
         col.setDefaultExpr(defaultExpr);
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.COLLATE)) {
         this.lexer.nextToken();
         col.setCollateExpr(this.exprParser.expr());
      }

      if (this.lexer.identifierEquals("ENCODING")) {
         this.lexer.nextToken();
         this.accept(Token.LPAREN);

         do {
            col.addEncoding(this.exprParser.expr());
            if (this.lexer.token() == Token.COMMA) {
               this.lexer.nextToken();
            }
         } while(this.lexer.token() != Token.RPAREN);

         this.lexer.nextToken();
      }

      return item;
   }

   private PGAlterTableAddConstraint parseAlterTableAddConstraint() {
      PGAlterTableAddConstraint item = new PGAlterTableAddConstraint();
      this.lexer.nextToken();
      PGAlterTableAddConstraint.PGAlterTableAddConstraintUsingIndex idx = new PGAlterTableAddConstraint.PGAlterTableAddConstraintUsingIndex();
      idx.setConstraint(this.exprParser.expr());
      if (this.lexer.token() == Token.UNIQUE) {
         this.lexer.nextToken();
         idx.setType(PGAlterTableAddConstraint.PGAlterTableAddConstraintUsingIndex.ConstraintType.unique);
      } else {
         this.lexer.nextToken();
         this.lexer.nextToken();
         idx.setType(PGAlterTableAddConstraint.PGAlterTableAddConstraintUsingIndex.ConstraintType.primaryKey);
      }

      this.lexer.nextToken();
      this.lexer.nextToken();
      idx.setIndexName(this.exprParser.name());
      if (this.lexer.identifierEquals("DEFERRABLE")) {
         this.lexer.nextToken();
         idx.setStrategy(PGAlterTableAddConstraint.PGAlterTableAddConstraintUsingIndex.ConstraintStrategy.deferable);
      } else if (this.lexer.token() == Token.NOT) {
         this.lexer.nextToken();
         this.lexer.nextToken();
         idx.setStrategy(PGAlterTableAddConstraint.PGAlterTableAddConstraintUsingIndex.ConstraintStrategy.notDeferable);
      } else if (this.lexer.identifierEquals("INITIALLY")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("DEFERRED")) {
            idx.setStrategy(PGAlterTableAddConstraint.PGAlterTableAddConstraintUsingIndex.ConstraintStrategy.initiallyDefered);
         } else {
            idx.setStrategy(PGAlterTableAddConstraint.PGAlterTableAddConstraintUsingIndex.ConstraintStrategy.initiallyImmediate);
         }

         this.lexer.nextToken();
      }

      item.setUsingIndex(idx);
      return item;
   }

   private PGAlterTableDropColumn parseAlterTableDropColumn() {
      PGAlterTableDropColumn item = new PGAlterTableDropColumn();
      if (this.lexer.token() == Token.COLUMN) {
         this.lexer.nextToken();
      }

      if (this.lexer.token() == Token.IF) {
         this.lexer.nextToken();
         item.setIfExists(true);
         this.lexer.nextToken();
      }

      item.setColumnName(this.exprParser.expr());
      if (this.lexer.token() == Token.RESTRICT) {
         this.lexer.nextToken();
         item.setType(PGAlterTableDropColumn.DropColumType.restrict);
      } else if (this.lexer.token() == Token.CASCADE) {
         this.lexer.nextToken();
         item.setType(PGAlterTableDropColumn.DropColumType.cascade);
      }

      return item;
   }

   private PGAlterTableDropConstraint parseAlterTableDropConstraint() {
      this.lexer.nextToken();
      PGAlterTableDropConstraint item = new PGAlterTableDropConstraint();
      if (this.lexer.token() == Token.IF) {
         this.lexer.nextToken();
         this.lexer.nextToken();
         item.setIfExists(true);
      }

      item.setConstraint(this.exprParser.expr());
      if (this.lexer.token() == Token.RESTRICT) {
         this.lexer.nextToken();
         item.setType(PGAlterTableDropConstraint.DorpType.restrict);
      } else if (this.lexer.token() == Token.CASCADE) {
         this.lexer.nextToken();
         item.setType(PGAlterTableDropConstraint.DorpType.cascade);
      }

      return item;
   }

   private PGAlterTableAlterColumn parseAlterTableAlterColumn() {
      PGAlterTableAlterColumn item = new PGAlterTableAlterColumn();
      item.setColumn(this.exprParser.expr());
      if (this.lexer.token() == Token.SET) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("DATA")) {
            this.lexer.nextToken();
            item.setType(PGAlterTableAlterColumn.Type.setType);
            this.accept(Token.TYPE);
            item.setDataType(this.exprParser.expr());
            if (this.lexer.identifierEquals("COLLATE")) {
               this.lexer.nextToken();
               item.setCollation(this.exprParser.expr());
            }

            if (this.lexer.token() == Token.USING) {
               this.lexer.nextToken();
               item.setUsingExpression(this.exprParser.expr());
            }
         } else if (this.lexer.token() == Token.DEFAULT) {
            this.lexer.nextToken();
            item.setType(PGAlterTableAlterColumn.Type.setDefault);
            item.setDefaultExpression(this.exprParser.expr());
         } else if (this.lexer.token() == Token.NOT) {
            this.lexer.nextToken();
            item.setType(PGAlterTableAlterColumn.Type.setNotNull);
            this.accept(Token.NULL);
         } else if (this.lexer.identifierEquals("STATISTICS")) {
            item.setType(PGAlterTableAlterColumn.Type.setStatistics);
            this.lexer.nextToken();
            item.setStatics(this.exprParser.expr());
         }
      } else if (this.lexer.token() == Token.TYPE) {
         this.lexer.nextToken();
         item.setType(PGAlterTableAlterColumn.Type.setType);
         item.setDataType(this.exprParser.expr());
         if (this.lexer.identifierEquals("COLLATE")) {
            this.lexer.nextToken();
            item.setCollation(this.exprParser.expr());
         }

         if (this.lexer.token() == Token.USING) {
            this.lexer.nextToken();
            item.setUsingExpression(this.exprParser.expr());
         }
      } else if (this.lexer.token() == Token.DROP) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.DEFAULT) {
            item.setType(PGAlterTableAlterColumn.Type.dropDefault);
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.NOT) {
            item.setType(PGAlterTableAlterColumn.Type.dropNotNull);
            this.lexer.nextToken();
            this.accept(Token.NULL);
         }
      }

      return item;
   }

   private PGAlterTableAlterColumnOptions parseAlterTableAlterColumnOptions() {
      this.lexer.nextToken();
      PGAlterTableAlterColumnOptions item = new PGAlterTableAlterColumnOptions();
      if (this.lexer.token() == Token.SET) {
         item.setSet(true);
         this.lexer.nextToken();
         this.accept(Token.LPAREN);

         do {
            PGAlterTableAlterColumnOptions.PGAlterTableAlterColumnOptionValue option = new PGAlterTableAlterColumnOptions.PGAlterTableAlterColumnOptionValue();
            SQLExpr expr = this.exprParser.expr();
            if (expr instanceof SQLBinaryOpExpr) {
               SQLBinaryOpExpr bin = (SQLBinaryOpExpr)expr;
               option.setAttribute(bin.getLeft());
               option.setValue(bin.getRight());
            } else {
               option.setAttribute(expr);
               this.accept(Token.EQ);
               option.setValue(this.exprParser.expr());
            }

            item.addOption(option);
            if (this.lexer.token() == Token.COMMA) {
               this.lexer.nextToken();
            }
         } while(this.lexer.token() != Token.RPAREN);

         this.lexer.nextToken();
      } else {
         item.setSet(false);
         this.lexer.nextToken();
         this.accept(Token.LPAREN);

         do {
            PGAlterTableAlterColumnOptions.PGAlterTableAlterColumnOptionValue option = new PGAlterTableAlterColumnOptions.PGAlterTableAlterColumnOptionValue();
            SQLExpr expr = this.exprParser.expr();
            option.setAttribute(expr);
            item.addOption(option);
            if (this.lexer.token() == Token.COMMA) {
               this.lexer.nextToken();
            }
         } while(this.lexer.token() != Token.RPAREN);

         this.lexer.nextToken();
      }

      return item;
   }

   public PGCreateDatabaseStatement parseCreateDatabase() {
      if (this.lexer.token() == Token.CREATE) {
         this.lexer.nextToken();
      }

      if (this.lexer.token() == Token.DATABASE) {
         this.lexer.nextToken();
      }

      PGCreateDatabaseStatement stmt = new PGCreateDatabaseStatement();
      stmt.setName(this.exprParser.name());
      if (this.lexer.token() == Token.WITH) {
         this.lexer.nextToken();
      }

      if (this.lexer.identifierEquals("OWNER")) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.EQ) {
            this.lexer.nextToken();
         }

         stmt.setOwner(this.exprParser.expr());
      }

      if (this.lexer.identifierEquals("TEMPLATE")) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.EQ) {
            this.lexer.nextToken();
         }

         stmt.setTemplate(this.exprParser.expr());
      }

      if (this.lexer.identifierEquals("ENCODING")) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.EQ) {
            this.lexer.nextToken();
         }

         stmt.setEncoding(this.exprParser.expr());
      }

      if (this.lexer.identifierEquals("LC_COLLATE")) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.EQ) {
            this.lexer.nextToken();
         }

         stmt.setLcCollate(this.exprParser.expr());
      }

      if (this.lexer.identifierEquals("LC_CTYPE")) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.EQ) {
            this.lexer.nextToken();
         }

         stmt.setCtype(this.exprParser.expr());
      }

      if (this.lexer.token() == Token.TABLESPACE) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.EQ) {
            this.lexer.nextToken();
         }

         stmt.setTablespace(this.exprParser.expr());
      }

      if (this.lexer.identifierEquals("CONNECTION")) {
         this.lexer.nextToken();
         this.lexer.nextToken();
         if (this.lexer.token() == Token.EQ) {
            this.lexer.nextToken();
         }

         stmt.setLimit(this.exprParser.expr());
      }

      return stmt;
   }

   public PGCreateTableStatement parseCreateTable() {
      PGCreateTableParser parser = new PGCreateTableParser(this.exprParser);
      return parser.parseCreateTable();
   }

   public SQLStatement parseCreate() {
      char markChar = this.lexer.current();
      int markBp = this.lexer.bp();
      List<String> comments = null;
      if (this.lexer.isKeepComments() && this.lexer.hasComment()) {
         comments = this.lexer.readAndResetComments();
      }

      this.accept(Token.CREATE);
      boolean global = false;
      if (this.lexer.identifierEquals(FnvHash.Constants.GLOBAL)) {
         this.lexer.nextToken();
         global = true;
      }

      boolean local = false;
      if (this.lexer.identifierEquals(FnvHash.Constants.LOCAL)) {
         this.lexer.nextToken();
         local = true;
      }

      boolean temporary = false;
      if (this.lexer.identifierEquals(FnvHash.Constants.TEMPORARY) || this.lexer.token() == Token.TEMPORARY) {
         this.lexer.nextToken();
         temporary = true;
      }

      boolean temp = false;
      if (this.lexer.token() == Token.TEMP || this.lexer.identifierEquals("TEMP")) {
         this.lexer.nextToken();
         temp = true;
      }

      boolean unlogged = false;
      if (this.lexer.token() == Token.UNLOGGED || this.lexer.identifierEquals("UNLOGGED")) {
         this.lexer.nextToken();
         unlogged = true;
      }

      boolean nonclustered = false;
      if (this.lexer.identifierEquals(FnvHash.Constants.NONCLUSTERED)) {
         this.lexer.nextToken();
         nonclustered = true;
      }

      boolean external = false;
      if (this.lexer.identifierEquals(FnvHash.Constants.EXTERNAL)) {
         this.lexer.nextToken();
         external = true;
      }

      Token token = this.lexer.token();
      switch (this.lexer.token()) {
         case NOT:
         case INDEX:
         case UNIQUE:
            PGCreateIndexStatement createIndex = this.parseCreateIndex(false);
            if (nonclustered) {
               createIndex.setType("NONCLUSTERED");
            }

            return createIndex;
         case TABLE:
            this.lexer.reset(markBp, markChar, Token.CREATE);
            SQLCreateTableParser createTableParser = this.getSQLCreateTableParser();
            SQLCreateTableStatement stmt = createTableParser.parseCreateTable();
            if (comments != null) {
               stmt.addBeforeComment(comments);
            }

            return stmt;
         case SEQUENCE:
            PGCreateSeqenceStatement stmt3 = new PGCreateSeqenceStatement();
            if (temporary) {
               stmt3.setTemporary(true);
            }

            if (temp) {
               stmt3.setTemp(true);
            }

            return this.parseCreateSequenceGP(stmt3);
         case DATABASE:
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("LINK")) {
               this.lexer.reset(markBp, markChar, Token.CREATE);
               return this.parseCreateDbLink();
            }

            this.lexer.reset(markBp, markChar, Token.CREATE);
            PGCreateDatabaseStatement gpCreateDatabaseStatement = this.parseCreateDatabase();
            if (comments != null) {
               gpCreateDatabaseStatement.addBeforeComment(comments);
               List<String> var15 = null;
            }

            return gpCreateDatabaseStatement;
         case SCHEMA:
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("LINK")) {
               this.lexer.reset(markBp, markChar, Token.CREATE);
               return this.parseCreateDbLink();
            }

            this.lexer.reset(markBp, markChar, Token.CREATE);
            PGCreateSchemaStatement gpCreateSchemaStatement = this.parseCreateSchema();
            if (comments != null) {
               gpCreateSchemaStatement.addBeforeComment(comments);
               List<String> var14 = null;
            }

            return gpCreateSchemaStatement;
         case USER:
            this.lexer.reset(markBp, markChar, Token.CREATE);
            return this.parseCreateUser();
         case FUNCTION:
            this.lexer.reset(markBp, markChar, Token.CREATE);
            SQLCreateFunctionStatement sqlCreateFunctionStatement = this.parseCreateFunction();
            return sqlCreateFunctionStatement;
         case TABLESPACE:
            this.lexer.reset(markBp, markChar, Token.CREATE);
            return this.parseCreateTableSpace();
         default:
            if (token != Token.OR) {
               if (this.lexer.identifierEquals(FnvHash.Constants.PUBLIC)) {
                  this.lexer.nextToken();
                  if (this.lexer.identifierEquals("SYNONYM")) {
                     this.lexer.reset(markBp, markChar, Token.CREATE);
                     return this.parseCreateSynonym();
                  } else {
                     this.lexer.reset(markBp, markChar, Token.CREATE);
                     return this.parseCreateDbLink();
                  }
               } else if (this.lexer.identifierEquals("SHARE")) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateDbLink();
               } else if (this.lexer.identifierEquals("SYNONYM")) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateSynonym();
               } else if (token == Token.VIEW) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateView();
               } else if (token == Token.TRIGGER) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateTrigger();
               } else if (token == Token.PROCEDURE) {
                  SQLCreateProcedureStatement sqlCreateProcedureStatement = this.parseCreateProcedure();
                  sqlCreateProcedureStatement.setCreate(true);
                  return sqlCreateProcedureStatement;
               } else if (this.lexer.identifierEquals(FnvHash.Constants.BITMAP)) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateIndex(true);
               } else if (this.lexer.identifierEquals(FnvHash.Constants.MATERIALIZED)) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateMaterializedView();
               } else if (this.lexer.identifierEquals(FnvHash.Constants.TYPE)) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateType();
               } else if (this.lexer.identifierEquals(FnvHash.Constants.EXTERNAL)) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  SQLCreateTableStatement createTable = this.parseCreateTable();
                  if (comments != null) {
                     createTable.addBeforeComment(comments);
                     List<String> var16 = null;
                  }

                  return createTable;
               } else if (this.lexer.identifierEquals(FnvHash.Constants.TABLEGROUP)) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateTableGroup();
               } else if (this.lexer.identifierEquals(FnvHash.Constants.DIMENSION)) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateTable();
               } else if (this.lexer.identifierEquals(FnvHash.Constants.ROLE)) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateRole();
               } else if (this.lexer.identifierEquals(FnvHash.Constants.RESOURCE)) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateResourceGroup();
               } else if (this.lexer.token() == Token.FOREIGN) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateTable();
               } else if (!this.lexer.identifierEquals("CLUSTER") && !this.lexer.identifierEquals("SPATIAL") && !this.lexer.identifierEquals("BITMAP") && !this.lexer.identifierEquals("CONTEXT")) {
                  if (this.lexer.identifierEquals("DOMAIN")) {
                     this.lexer.reset(markBp, markChar, Token.CREATE);
                     SQLCreateDomainStatement createDomain = this.parseCreateDomain();
                     return createDomain;
                  } else if (this.lexer.identifierEquals("DIRECTORY")) {
                     this.lexer.reset(markBp, markChar, Token.CREATE);
                     SQLCreateDirectoryStatement createDirectory = this.parseCreateDirectory();
                     return createDirectory;
                  } else if (this.lexer.identifierEquals(FnvHash.Constants.PACKAGE)) {
                     this.lexer.reset(markBp, markChar, Token.CREATE);
                     return this.parseCreatePackage();
                  } else if (this.lexer.token() == Token.RECURSIVE) {
                     this.lexer.nextToken();
                     if (this.lexer.token() == Token.VIEW) {
                        this.lexer.reset(markBp, markChar, Token.CREATE);
                        return this.parseCreateView();
                     } else {
                        throw new ParserException("TODO " + this.lexer.info());
                     }
                  } else {
                     throw new ParserException("TODO " + this.lexer.info());
                  }
               } else {
                  this.lexer.nextToken();
                  this.lexer.nextToken();
                  if (this.lexer.token() == Token.USING) {
                     this.lexer.reset(markBp, markChar, Token.CREATE);
                     SQLCreateContextStatement contextStatement = this.parseCreateContext();
                     return contextStatement;
                  } else {
                     this.lexer.reset(markBp, markChar, Token.CREATE);
                     SQLCreateIndexStatement createIndex4 = this.parseCreateIndex(true);
                     if (nonclustered) {
                        createIndex4.setType("NONCLUSTERED");
                     }

                     return createIndex4;
                  }
               }
            } else {
               this.lexer.nextToken();
               this.accept(Token.REPLACE);
               if (this.lexer.token() == Token.TEMP || this.lexer.token() == Token.TEMPORARY) {
                  this.lexer.nextToken();
                  if (this.lexer.token() == Token.VIEW) {
                     this.lexer.reset(markBp, markChar, Token.CREATE);
                     return this.parseCreateView();
                  }
               }

               if (this.lexer.token() == Token.RECURSIVE) {
                  this.lexer.nextToken();
                  if (this.lexer.token() == Token.VIEW) {
                     this.lexer.reset(markBp, markChar, Token.CREATE);
                     return this.parseCreateView();
                  }
               }

               if (this.lexer.identifierEquals(FnvHash.Constants.FORCE)) {
                  this.lexer.nextToken();
               }

               if (this.lexer.token() == Token.PROCEDURE) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateProcedure();
               } else if (this.lexer.token() == Token.VIEW) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateView();
               } else if (this.lexer.token() == Token.TRIGGER) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateTrigger();
               } else if (this.lexer.token() == Token.FUNCTION) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateFunction();
               } else if (this.lexer.identifierEquals(FnvHash.Constants.PACKAGE)) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreatePackage();
               } else if (this.lexer.identifierEquals(FnvHash.Constants.TYPE)) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateType();
               } else if (this.lexer.identifierEquals(FnvHash.Constants.PUBLIC)) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateSynonym();
               } else if (this.lexer.identifierEquals(FnvHash.Constants.SYNONYM)) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateSynonym();
               } else if (this.lexer.token() != Token.INDEX && !this.lexer.identifierEquals("CLUSTER") && this.lexer.token() != Token.NOT && this.lexer.token() != Token.UNIQUE && !this.lexer.identifierEquals("SPATIAL") && !this.lexer.identifierEquals("BITMAP")) {
                  if (this.lexer.identifierEquals("CONTEXT")) {
                     this.lexer.reset(markBp, markChar, Token.CREATE);
                     SQLCreateContextStatement contextStatement = this.parseCreateContext();
                     return contextStatement;
                  } else if (this.lexer.identifierEquals("DIRECTORY")) {
                     this.lexer.reset(markBp, markChar, Token.CREATE);
                     SQLCreateDirectoryStatement createDirectory = this.parseCreateDirectory();
                     return createDirectory;
                  } else {
                     throw new ParserException("TODO " + this.lexer.info());
                  }
               } else {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  SQLCreateIndexStatement createIndex5 = this.parseCreateIndex(true);
                  if (nonclustered) {
                     createIndex5.setType("NONCLUSTERED");
                  }

                  return createIndex5;
               }
            }
      }
   }

   public SQLGrantStatement parseGrant() throws ParserException {
      this.accept(Token.GRANT);
      PGGrantStatement stmt = new PGGrantStatement();
      this.parsePrivileages(stmt.getPrivileges(), stmt);
      boolean isOn = false;
      if (this.lexer.token() == Token.ON) {
         this.lexer.nextToken();
         isOn = true;
         switch (this.lexer.token()) {
            case TABLE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.TABLE);
            case INDEX:
            case UNIQUE:
            case SEQUENCE:
            case SCHEMA:
            case TABLESPACE:
            default:
               break;
            case DATABASE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.DATABASE);
               break;
            case USER:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.USER);
               break;
            case FUNCTION:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.FUNCTION);
               break;
            case PROCEDURE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.PROCEDURE);
               break;
            case IDENTIFIER:
               stmt.setResourceType(SQLObjectType.TABLE);
         }

         if (stmt.getResourceType() != null && this.lexer.token() == Token.COLONCOLON) {
            this.lexer.nextToken();
         }

         if (stmt.getResourceType() != SQLObjectType.TABLE && stmt.getResourceType() != null) {
            SQLExpr expr;
            if (this.lexer.token() == Token.DOT) {
               expr = new SQLAllColumnExpr();
               this.lexer.nextToken();
            } else {
               expr = this.exprParser.expr();
            }

            stmt.setResource(expr);
         } else if (this.lexer.token() == Token.ALL) {
            this.lexer.nextToken();
            this.acceptIdentifier("TABLES");
            this.accept(Token.IN);
            this.accept(Token.SCHEMA);
            PGSchemaTables c = new PGSchemaTables();
            c.add(this.exprParser.expr());

            while(this.lexer.token() == Token.COMMA) {
               if (this.lexer.token() == Token.COMMA) {
                  this.lexer.nextToken();
               }

               SQLExpr expr = this.exprParser.expr();
               c.add(expr);
            }

            stmt.setResource(c);
         } else {
            PGSQLObjectCollection c = new PGSQLObjectCollection();
            SQLExpr expr = this.exprParser.expr();
            c.add((SQLObject)expr);

            while(this.lexer.token() == Token.COMMA) {
               if (this.lexer.token() == Token.COMMA) {
                  this.lexer.nextToken();
               }

               expr = this.exprParser.expr();
               c.add((SQLObject)expr);
            }

            stmt.setResource(c);
         }
      }

      if (!isOn) {
         stmt.setResourceType(SQLObjectType.ROLE);
         stmt.setResource(this.exprParser.expr());
      }

      if (this.lexer.token() == Token.TO) {
         this.lexer.nextToken();
         if (this.lexer.token() != Token.GROUP && !this.lexer.identifierEquals("GROUP")) {
            while(true) {
               SQLExpr user = this.parseUser();
               stmt.getUsers().add(user);
               if (this.lexer.token() != Token.COMMA) {
                  break;
               }

               this.lexer.nextToken();
            }
         } else {
            this.lexer.nextToken();

            while(true) {
               SQLExpr role = this.exprParser.expr();
               stmt.addGroup(role);
               if (this.lexer.token() != Token.COMMA) {
                  break;
               }

               this.lexer.nextToken();
            }
         }
      }

      if (this.lexer.token() == Token.WITH) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.GRANT) {
            this.lexer.nextToken();
            this.acceptIdentifier("OPTION");
            stmt.setWithGrantOption(true);
         }

         label97:
         while(true) {
            while(!this.lexer.identifierEquals("MAX_QUERIES_PER_HOUR")) {
               if (this.lexer.identifierEquals("MAX_UPDATES_PER_HOUR")) {
                  this.lexer.nextToken();
                  stmt.setMaxUpdatesPerHour(this.exprParser.primary());
               } else if (this.lexer.identifierEquals("MAX_CONNECTIONS_PER_HOUR")) {
                  this.lexer.nextToken();
                  stmt.setMaxConnectionsPerHour(this.exprParser.primary());
               } else {
                  if (!this.lexer.identifierEquals("MAX_USER_CONNECTIONS")) {
                     break label97;
                  }

                  this.lexer.nextToken();
                  stmt.setMaxUserConnections(this.exprParser.primary());
               }
            }

            this.lexer.nextToken();
            stmt.setMaxQueriesPerHour(this.exprParser.primary());
         }
      }

      if (this.lexer.identifierEquals("ADMIN")) {
         this.lexer.nextToken();
         this.acceptIdentifier("OPTION");
         stmt.setAdminOption(true);
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.IDENTIFIED)) {
         this.lexer.nextToken();
         this.accept(Token.BY);
         if (this.lexer.identifierEquals("PASSWORD")) {
            this.lexer.nextToken();
            String password = this.lexer.stringVal();
            this.accept(Token.LITERAL_CHARS);
            stmt.setIdentifiedByPassword(password);
         } else {
            stmt.setIdentifiedBy(this.exprParser.expr());
         }
      }

      if (this.lexer.token() == Token.WITH) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.GRANT) {
            this.lexer.nextToken();
            this.acceptIdentifier("OPTION");
            stmt.setWithGrantOption(true);
         }
      }

      return stmt;
   }

   protected void parsePrivileages(List<SQLPrivilegeItem> privileges, SQLObject parent) {
      while(true) {
         String privilege = null;
         if (this.lexer.token() == Token.ALL) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("PRIVILEGES")) {
               privilege = "ALL PRIVILEGES";
               this.lexer.nextToken();
            } else {
               privilege = "ALL";
            }
         } else if (this.lexer.token() == Token.SELECT) {
            privilege = "SELECT";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.UPDATE) {
            privilege = "UPDATE";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.DELETE) {
            privilege = "DELETE";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.INSERT) {
            privilege = "INSERT";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.INDEX) {
            this.lexer.nextToken();
            privilege = "INDEX";
         } else if (this.lexer.token() == Token.TRIGGER) {
            this.lexer.nextToken();
            privilege = "TRIGGER";
         } else if (this.lexer.token() == Token.REFERENCES) {
            privilege = "REFERENCES";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.DESC) {
            privilege = "DESCRIBE";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.TRUNCATE) {
            privilege = "TRUNCATE";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.CREATE) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.TABLE) {
               privilege = "CREATE TABLE";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.SESSION) {
               privilege = "CREATE SESSION";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.TABLESPACE) {
               privilege = "CREATE TABLESPACE";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.USER) {
               privilege = "CREATE USER";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.VIEW) {
               privilege = "CREATE VIEW";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.PROCEDURE) {
               privilege = "CREATE PROCEDURE";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.SEQUENCE) {
               privilege = "CREATE SEQUENCE";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.ANY) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.TABLE) {
                  this.lexer.nextToken();
                  privilege = "CREATE ANY TABLE";
               } else {
                  if (!this.lexer.identifierEquals("MATERIALIZED")) {
                     throw new ParserException("TODO : " + this.lexer.token() + " " + this.lexer.stringVal());
                  }

                  this.lexer.nextToken();
                  this.accept(Token.VIEW);
                  privilege = "CREATE ANY MATERIALIZED VIEW";
               }
            } else if (this.lexer.identifierEquals("SYNONYM")) {
               privilege = "CREATE SYNONYM";
               this.lexer.nextToken();
            } else if (this.lexer.identifierEquals("ROUTINE")) {
               privilege = "CREATE ROUTINE";
               this.lexer.nextToken();
            } else if (this.lexer.identifierEquals("TEMPORARY")) {
               this.lexer.nextToken();
               this.acceptIdentifier("TABLES");
               privilege = "CREATE TEMPORARY TABLES";
            } else if (this.lexer.token() == Token.ON) {
               privilege = "CREATE";
            } else {
               if (this.lexer.token() != Token.COMMA) {
                  throw new ParserException("TODO : " + this.lexer.token() + " " + this.lexer.stringVal());
               }

               privilege = "CREATE";
            }
         } else if (this.lexer.token() == Token.ALTER) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.TABLE) {
               privilege = "ALTER TABLE";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.SESSION) {
               privilege = "ALTER SESSION";
               this.lexer.nextToken();
            } else if (this.lexer.identifierEquals(FnvHash.Constants.ROUTINE)) {
               privilege = "ALTER ROUTINE";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.ANY) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.TABLE) {
                  this.lexer.nextToken();
                  privilege = "ALTER ANY TABLE";
               } else {
                  if (!this.lexer.identifierEquals("MATERIALIZED")) {
                     throw new ParserException("TODO : " + this.lexer.token() + " " + this.lexer.stringVal());
                  }

                  this.lexer.nextToken();
                  this.accept(Token.VIEW);
                  privilege = "ALTER ANY MATERIALIZED VIEW";
               }
            } else {
               if (this.lexer.token() != Token.ON && this.lexer.token() != Token.COMMA) {
                  throw new ParserException("TODO : " + this.lexer.token() + " " + this.lexer.stringVal());
               }

               privilege = "ALTER";
            }
         } else if (this.lexer.token() == Token.DROP) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.DROP) {
               privilege = "DROP TABLE";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.SESSION) {
               privilege = "DROP SESSION";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.ANY) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.TABLE) {
                  this.lexer.nextToken();
                  privilege = "DROP ANY TABLE";
               } else {
                  if (!this.lexer.identifierEquals("MATERIALIZED")) {
                     throw new ParserException("TODO : " + this.lexer.token() + " " + this.lexer.stringVal());
                  }

                  this.lexer.nextToken();
                  this.accept(Token.VIEW);
                  privilege = "DROP ANY MATERIALIZED VIEW";
               }
            } else {
               privilege = "DROP";
            }
         } else if (this.lexer.identifierEquals("USAGE")) {
            privilege = "USAGE";
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("EXECUTE")) {
            privilege = "EXECUTE";
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("PROXY")) {
            privilege = "PROXY";
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("QUERY")) {
            this.lexer.nextToken();
            this.acceptIdentifier("REWRITE");
            privilege = "QUERY REWRITE";
         } else if (this.lexer.identifierEquals("GLOBAL")) {
            this.lexer.nextToken();
            this.acceptIdentifier("QUERY");
            this.acceptIdentifier("REWRITE");
            privilege = "GLOBAL QUERY REWRITE";
         } else if (this.lexer.identifierEquals("INHERIT")) {
            this.lexer.nextToken();
            this.acceptIdentifier("PRIVILEGES");
            privilege = "INHERIT PRIVILEGES";
         } else if (this.lexer.identifierEquals("EVENT")) {
            this.lexer.nextToken();
            privilege = "EVENT";
         } else if (this.lexer.identifierEquals("FILE")) {
            this.lexer.nextToken();
            privilege = "FILE";
         } else if (this.lexer.identifierEquals("DESCRIBE")) {
            this.lexer.nextToken();
            privilege = "DESCRIBE";
         } else if (this.lexer.token() == Token.GRANT) {
            this.lexer.nextToken();
            this.acceptIdentifier("OPTION");
            if (this.lexer.token() == Token.FOR) {
               privilege = "GRANT OPTION FOR";
               this.lexer.nextToken();
            } else {
               privilege = "GRANT OPTION";
            }
         } else if (this.lexer.token() == Token.LOCK) {
            this.lexer.nextToken();
            this.acceptIdentifier("TABLES");
            privilege = "LOCK TABLES";
         } else if (this.lexer.identifierEquals("PROCESS")) {
            this.lexer.nextToken();
            privilege = "PROCESS";
         } else if (this.lexer.identifierEquals("RELOAD")) {
            this.lexer.nextToken();
            privilege = "RELOAD";
         } else if (this.lexer.identifierEquals("CONNECT")) {
            privilege = "CONNECT";
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("RESOURCE")) {
            this.lexer.nextToken();
            privilege = "RESOURCE";
         } else if (this.lexer.token() == Token.CONNECT) {
            this.lexer.nextToken();
            privilege = "CONNECT";
         } else if (this.lexer.identifierEquals("REPLICATION")) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("SLAVE")) {
               this.lexer.nextToken();
               privilege = "REPLICATION SLAVE";
            } else {
               this.acceptIdentifier("CLIENT");
               privilege = "REPLICATION CLIENT";
            }
         } else if (this.lexer.token() == Token.SHOW) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.VIEW) {
               this.lexer.nextToken();
               privilege = "SHOW VIEW";
            } else if (this.lexer.identifierEquals("DATABASES")) {
               this.acceptIdentifier("DATABASES");
               privilege = "SHOW DATABASES";
            } else {
               privilege = "SHOW";
            }
         } else if (this.lexer.identifierEquals("SHUTDOWN")) {
            this.lexer.nextToken();
            privilege = "SHUTDOWN";
         } else if (this.lexer.identifierEquals("SUPER")) {
            this.lexer.nextToken();
            privilege = "SUPER";
         } else if (this.lexer.identifierEquals("CONTROL")) {
            this.lexer.nextToken();
            privilege = "CONTROL";
         } else if (this.lexer.identifierEquals("IMPERSONATE")) {
            this.lexer.nextToken();
            privilege = "IMPERSONATE";
         } else if (this.lexer.identifierEquals("LOAD")) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("DATA")) {
               this.lexer.nextToken();
               privilege = "LOAD DATA";
            }
         } else if (this.lexer.identifierEquals("DUMP")) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("DATA")) {
               this.lexer.nextToken();
               privilege = "DUMP DATA";
            }
         } else if (this.lexer.identifierEquals("DBA")) {
            this.lexer.nextToken();
            privilege = "DBA";
         } else if (this.lexer.identifierEquals("READ")) {
            this.lexer.nextToken();
            privilege = "READ";
         } else if (this.lexer.token() == Token.LITERAL_CHARS) {
            privilege = this.lexer.stringVal();
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.IDENTIFIER && JdbcUtils.isDmDbType(this.dbType)) {
            privilege = this.lexer.stringVal();
            this.lexer.nextToken();
         }

         if (privilege != null) {
            SQLExpr expr = new SQLIdentifierExpr(privilege);
            SQLPrivilegeItem privilegeItem = new SQLPrivilegeItem();
            privilegeItem.setAction(expr);
            if (this.lexer.token() == Token.LPAREN) {
               this.lexer.nextToken();

               while(true) {
                  privilegeItem.getColumns().add(this.exprParser.name());
                  if (this.lexer.token() != Token.COMMA) {
                     this.accept(Token.RPAREN);
                     break;
                  }

                  this.lexer.nextToken();
               }
            }

            expr.setParent(parent);
            privileges.add(privilegeItem);
         }

         if (this.lexer.token() != Token.COMMA) {
            return;
         }

         this.lexer.nextToken();
      }
   }

   public PGAlterViewStatement parseAlterView() {
      PGAlterViewStatement stmt = new PGAlterViewStatement();
      this.accept(Token.VIEW);
      if (this.lexer.token() == Token.IF) {
         this.accept(Token.IF);
         this.accept(Token.EXISTS);
         stmt.setIfExists(true);
      }

      stmt.setDbType(this.dbType);
      SQLName viewName = this.exprParser.name();
      stmt.setViewName(viewName);
      if (this.lexer.identifierEquals("RENAME")) {
         stmt.setRenameTo(true);
         this.lexer.nextToken();
         this.accept(Token.TO);
         SQLName newName = this.exprParser.name();
         stmt.setNewViewName(newName);
      } else if (this.lexer.token() == Token.ALTER) {
         stmt.setAlter(true);
         this.lexer.nextToken();
         if (this.lexer.token() == Token.COLUMN) {
            this.lexer.nextToken();
         }

         SQLName columnName = this.exprParser.name();
         stmt.setColumnName(columnName);
         if (this.lexer.token() == Token.SET) {
            stmt.setSetDefault(true);
            this.accept(Token.SET);
            this.accept(Token.DEFAULT);
            SQLExpr expr = this.exprParser.expr();
            stmt.setDefaultValue(expr);
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.DROP) {
            stmt.setDropDefault(true);
            this.accept(Token.DROP);
            this.accept(Token.DEFAULT);
         }
      } else if (this.lexer.identifierEquals("OWNER")) {
         stmt.setOwnerTo(true);
         this.lexer.nextToken();
         this.accept(Token.TO);
         stmt.setNewOwner(new SQLIdentifierExpr(this.lexer.stringVal()));
         this.lexer.nextToken();
      } else if (this.lexer.token() == Token.SET) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.SCHEMA) {
            stmt.setSetSchema(true);
            this.lexer.nextToken();
            stmt.setNewSchema(new SQLIdentifierExpr(this.lexer.stringVal()));
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.LPAREN) {
            stmt.setSet(true);
            this.accept(Token.LPAREN);
            if (this.lexer.text.contains("=")) {
               while(true) {
                  SQLUpdateSetItem item = this.exprParser.parseUpdateSetItem();
                  stmt.getParameterList().add(item);
                  if (this.lexer.token() != Token.COMMA) {
                     break;
                  }

                  this.lexer.nextToken();
               }
            } else {
               while(true) {
                  stmt.getItemList().add(new SQLIdentifierExpr(this.lexer.stringVal()));
                  this.lexer.nextToken();
                  if (this.lexer.token() != Token.COMMA) {
                     break;
                  }

                  this.lexer.nextToken();
               }
            }

            this.lexer.nextToken();
            if (this.lexer.token() == Token.RPAREN) {
               this.accept(Token.RPAREN);
            }
         }
      } else if (this.lexer.token() == Token.RESET) {
         stmt.setReset(true);
         this.accept(Token.RESET);
         if (this.lexer.token() == Token.LPAREN) {
            this.accept(Token.LPAREN);

            while(true) {
               stmt.getItemList().add(new SQLIdentifierExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
               if (this.lexer.token() != Token.COMMA) {
                  this.lexer.nextToken();
                  if (this.lexer.token() == Token.RPAREN) {
                     this.accept(Token.RPAREN);
                  }
                  break;
               }

               this.lexer.nextToken();
            }
         }
      }

      return stmt;
   }

   public SQLStatement parseCreateSequenceGP(PGCreateSeqenceStatement stmt) {
      stmt.setDbType(this.dbType);
      this.accept(Token.SEQUENCE);
      SQLName name = this.exprParser.name();
      stmt.setSqeunceName(name);
      if (this.lexer.identifierEquals("INCREMENT")) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.BY) {
            stmt.setIncrementBy(true);
            this.lexer.nextToken();
         } else {
            stmt.setIncrement(true);
         }

         stmt.setIncrementValue(this.exprParser.integerExpr());
      }

      if (this.lexer.identifierEquals("MINVALUE")) {
         stmt.setMin(true);
         this.lexer.nextToken();
         stmt.setMinValue(this.exprParser.integerExpr());
      }

      if (this.lexer.identifierEquals("MAXVALUE")) {
         stmt.setMax(true);
         this.lexer.nextToken();
         stmt.setMaxValue(this.exprParser.integerExpr());
      }

      if (this.lexer.identifierEquals("NO")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("MAXVALUE")) {
            this.lexer.nextToken();
            stmt.setNoMax(true);
         } else if (this.lexer.identifierEquals("MINVALUE")) {
            this.lexer.nextToken();
            stmt.setNoMin(true);
         }
      }

      if (this.lexer.token() == Token.START) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.WITH) {
            stmt.setStartWith(true);
            this.lexer.nextToken();
         } else {
            stmt.setStart(true);
         }

         stmt.setStartValue(this.exprParser.integerExpr());
      }

      if (this.lexer.token() == Token.CACHE) {
         stmt.setCache(true);
         this.lexer.nextToken();
         stmt.setCacheName(this.exprParser.integerExpr());
      }

      if (this.lexer.identifierEquals("NO")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("CYCLE")) {
            stmt.setNoCycle(true);
            this.lexer.nextToken();
         }
      }

      if (this.lexer.identifierEquals("CYCLE")) {
         stmt.setCycle(true);
         this.lexer.nextToken();
      }

      if (this.lexer.identifierEquals("OWNED")) {
         this.lexer.nextToken();
         this.accept(Token.BY);
         stmt.setOwnedBy(true);
         stmt.setOwnedByName(this.exprParser.expr());
      }

      return stmt;
   }

   public SQLStatement parseCreateTableSpace() {
      PGCreateTableSpaceStatement stmt = new PGCreateTableSpaceStatement();
      stmt.setDbType(this.dbType);
      this.accept(Token.CREATE);
      this.accept(Token.TABLESPACE);
      stmt.setTableSpaceName(this.exprParser.name());
      if (this.lexer.identifierEquals("OWNER")) {
         stmt.setOwner(true);
         this.lexer.nextToken();
         stmt.setOwnerName(this.exprParser.name());
      }

      if (!this.lexer.identifierEquals("LOCATION")) {
         throw new ParserException("LOCATION MISSING " + this.lexer.info());
      } else {
         this.lexer.nextToken();
         stmt.setLocationDir(this.exprParser.name());
         if (this.lexer.token() == Token.WITH) {
            stmt.setWith(true);
            this.accept(Token.WITH);
            this.accept(Token.LPAREN);
            boolean firstParam = true;

            while(true) {
               SQLUpdateSetItem item = this.exprParser.parseUpdateSetItem();
               if (firstParam) {
                  String content = item.getColumn().toString();
                  if (!content.toLowerCase().contains("content")) {
                     throw new ParserException("syntax error first content<id> missing " + this.lexer.info());
                  }
               }

               stmt.getParameterList().add(item);
               if (this.lexer.token() != Token.COMMA) {
                  this.accept(Token.RPAREN);
                  break;
               }

               this.lexer.nextToken();
               firstParam = false;
            }
         }

         return stmt;
      }
   }

   public SQLCreateViewStatement parseCreateView() {
      PGCreateViewStatement stmt = new PGCreateViewStatement();
      stmt.setDbType(this.dbType);
      if (this.lexer.token() == Token.CREATE) {
         this.lexer.nextToken();
      }

      if (this.lexer.token() == Token.OR) {
         this.accept(Token.OR);
         this.accept(Token.REPLACE);
         stmt.setOrReplace(true);
      }

      if (this.lexer.token() == Token.TEMP) {
         this.lexer.nextToken();
         stmt.setTemp(true);
      }

      if (this.lexer.token() == Token.TEMPORARY) {
         this.lexer.nextToken();
         stmt.setTemporary(true);
      }

      if (this.lexer.token() == Token.RECURSIVE) {
         this.accept(Token.RECURSIVE);
         this.accept(Token.VIEW);
         stmt.setRecursiveView(true);
         stmt.setViewName(this.exprParser.name());
         this.accept(Token.LPAREN);

         while(true) {
            stmt.getColumnList().add(new SQLIdentifierExpr(this.lexer.stringVal()));
            this.lexer.nextToken();
            if (this.lexer.token() != Token.COMMA) {
               this.accept(Token.RPAREN);
               this.accept(Token.AS);
               PGSelectStatement gpSelectStatement = this.parseSelect();
               stmt.setSubQuery(gpSelectStatement.getSelect());
               break;
            }

            this.lexer.nextToken();
         }
      } else {
         this.accept(Token.VIEW);
         stmt.setViewName(this.exprParser.name());
         if (this.lexer.token() == Token.LPAREN) {
            while(true) {
               stmt.getColumnList().add(new SQLIdentifierExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
               if (this.lexer.token() != Token.COMMA) {
                  this.accept(Token.RPAREN);
                  break;
               }

               this.lexer.nextToken();
            }
         }

         if (this.lexer.token() == Token.WITH) {
            stmt.setWithOption(true);
            this.lexer.nextToken();
            this.accept(Token.LPAREN);

            while(true) {
               SQLUpdateSetItem item = this.exprParser.parseUpdateSetItem();
               stmt.getWithList().add(item);
               if (this.lexer.token() != Token.COMMA) {
                  this.accept(Token.RPAREN);
                  break;
               }

               this.lexer.nextToken();
            }
         }

         this.accept(Token.AS);
         if (this.lexer.token() == Token.WITH) {
            stmt.setAsWithRecursive(true);
            SQLStatement sqlStatement = this.parseWith();
            stmt.setWithSubqueryClause(sqlStatement);
            PGSelectStatement gpSelectStatement = (PGSelectStatement)sqlStatement;
            Boolean recursive = gpSelectStatement.getSelect().getWithSubQuery().getRecursive();
            if (!recursive) {
               throw new ParserException("syntax error, not recursive" + this.lexer.info());
            }
         } else {
            PGSelectStatement gpSelectStatement = this.parseSelect();
            stmt.setSubQuery(gpSelectStatement.getSelect());
            if (this.lexer.token() == Token.WITH) {
               this.lexer.nextToken();
               if (this.lexer.identifierEquals("CASCADED")) {
                  stmt.setWithCascaded(true);
                  this.lexer.nextToken();
               } else if (this.lexer.identifierEquals("LOCAL")) {
                  stmt.setWithLocal(true);
                  this.lexer.nextToken();
               }

               this.accept(Token.CHECK);
               if (!this.lexer.identifierEquals("OPTION")) {
                  throw new ParserException("syntax error OPTION missing " + this.lexer.info());
               }

               this.lexer.nextToken();
            }
         }
      }

      return stmt;
   }

   protected SQLDropStatement parseDropDatabase() {
      this.accept(Token.DATABASE);
      SQLDropDatabaseStatement stmt = new SQLDropDatabaseStatement(this.getDbType());
      if (this.lexer.token() == Token.IF) {
         this.lexer.nextToken();
         this.accept(Token.EXISTS);
         stmt.setIfExists(true);
      }

      SQLName name = this.exprParser.name();
      stmt.setDatabase((SQLExpr)name);
      this.lexer.nextToken();
      return stmt;
   }

   protected SQLDropSequenceStatement parseDropSequence(boolean acceptDrop) {
      PGDropSequenceStatement stmt = new PGDropSequenceStatement();
      stmt.setDbType(this.dbType);
      if (acceptDrop) {
         this.accept(Token.DROP);
      }

      this.accept(Token.SEQUENCE);
      if (this.lexer.token() == Token.IF) {
         this.lexer.nextToken();
         this.accept(Token.EXISTS);
         stmt.setIfExists(true);
      }

      while(true) {
         stmt.getSeqList().add(new SQLIdentifierExpr(this.lexer.stringVal()));
         this.lexer.nextToken();
         if (this.lexer.token() != Token.COMMA) {
            if (this.lexer.token() == Token.CASCADE) {
               stmt.setCascade(true);
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.RESTRICT) {
               stmt.setRestrict(true);
               this.lexer.nextToken();
            }

            return stmt;
         }

         this.lexer.nextToken();
      }
   }

   protected SQLDropTableStatement parseDropTable(boolean acceptDrop) {
      if (acceptDrop) {
         this.accept(Token.DROP);
      }

      this.accept(Token.TABLE);
      SQLDropTableStatement stmt = new SQLDropTableStatement(this.getDbType());
      if (this.lexer.token() == Token.IF) {
         this.lexer.nextToken();
         this.accept(Token.EXISTS);
         stmt.setIfExists(true);
      }

      while(true) {
         SQLName name = this.exprParser.name();
         stmt.addPartition(new SQLExprTableSource(name));
         if (this.lexer.token() != Token.COMMA) {
            if (this.lexer.token() == Token.RESTRICT) {
               this.lexer.nextToken();
               stmt.setRestrict(true);
            } else if (this.lexer.token() == Token.CASCADE) {
               this.lexer.nextToken();
               stmt.setCascade(true);
            }

            return stmt;
         }

         this.lexer.nextToken();
      }
   }

   protected SQLDropViewStatement parseDropView(boolean acceptDrop) {
      if (acceptDrop) {
         this.accept(Token.DROP);
      }

      SQLDropViewStatement stmt = new SQLDropViewStatement(this.getDbType());
      this.accept(Token.VIEW);
      if (this.lexer.token() == Token.IF) {
         this.lexer.nextToken();
         this.accept(Token.EXISTS);
         stmt.setIfExists(true);
      }

      while(true) {
         SQLName name = this.exprParser.name();
         stmt.addPartition(new SQLExprTableSource(name));
         if (this.lexer.token() != Token.COMMA) {
            if (this.lexer.token() == Token.RESTRICT) {
               this.lexer.nextToken();
               stmt.setRestrict(true);
            } else if (this.lexer.token() == Token.CASCADE) {
               this.lexer.nextToken();
               stmt.setCascade(true);
            }

            return stmt;
         }

         this.lexer.nextToken();
      }
   }

   public SQLStatement parseRollback() {
      this.lexer.nextToken();
      SQLRollbackStatement stmt = new SQLRollbackStatement(this.getDbType());
      if (this.lexer.identifierEquals("WORK")) {
         stmt.setWork(true);
         this.lexer.nextToken();
      } else if (this.lexer.identifierEquals("TRANSACTION")) {
         stmt.setTransaction(true);
         this.lexer.nextToken();
      }

      if (this.lexer.token() == Token.TO) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("SAVEPOINT")) {
            stmt.setHasSavepoint(true);
            this.lexer.nextToken();
         }

         stmt.setTo(this.exprParser.name());
      }

      return stmt;
   }

   public SQLStatement parseDrop() {
      List<String> beforeComments = null;
      if (this.lexer.isKeepComments() && this.lexer.hasComment()) {
         beforeComments = this.lexer.readAndResetComments();
      }

      Lexer.SavePoint mark = this.lexer.mark();
      this.lexer.nextToken();
      List<SQLCommentHint> hints = null;
      if (this.lexer.token() == Token.HINT) {
         hints = this.exprParser.parseHints();
      }

      boolean temporary = false;
      if (this.lexer.token() == Token.TEMPORARY || this.lexer.identifierEquals(FnvHash.Constants.TEMPORARY)) {
         this.lexer.nextToken();
         temporary = true;
      }

      boolean physical = false;
      if (this.lexer.identifierEquals(FnvHash.Constants.PHYSICAL)) {
         this.lexer.nextToken();
         physical = true;
      }

      Lexer.SavePoint mark2 = null;
      if (this.lexer.identifierEquals("CONTEXT") && this.dbType == DbType.dm) {
         mark2 = this.lexer.mark();
         this.lexer.nextToken();
      }

      switch (this.lexer.token()) {
         case TABLE:
            SQLDropTableStatement dropTable = this.parseDropTable(false);
            if (temporary) {
               dropTable.setTemporary(true);
            }

            if (hints != null) {
               dropTable.setHints(hints);
            }

            return dropTable;
         case INDEX:
         case UNIQUE:
         case USER:
         case FUNCTION:
         case PROCEDURE:
         case IDENTIFIER:
         default:
            this.lexer.reset(mark);
            return super.parseDrop();
         case SEQUENCE:
            return this.parseDropSequence(false);
         case DATABASE:
            return this.parseDropDatabase();
         case SCHEMA:
            return this.parseDropSchema();
         case TABLESPACE:
            return this.parseDropTablespace(false);
         case VIEW:
            return this.parseDropView(false);
      }
   }
}
