package com.alibaba.druid.sql.dialect.gauss.parser;

import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.ast.SQLCommentHint;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.ast.expr.SQLCurrentOfCursorExpr;
import com.alibaba.druid.sql.ast.expr.SQLDateExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLListExpr;
import com.alibaba.druid.sql.ast.expr.SQLQueryExpr;
import com.alibaba.druid.sql.ast.expr.SQLRealExpr;
import com.alibaba.druid.sql.ast.expr.SQLTimestampExpr;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableAlterColumn;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLCommitStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateContextStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateDirectoryStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateDomainStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateFunctionStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateIndexStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateProcedureStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateViewStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropDatabaseStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropRoleStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropSequenceStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropViewStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
import com.alibaba.druid.sql.ast.statement.SQLObjectType;
import com.alibaba.druid.sql.ast.statement.SQLPrivilegeItem;
import com.alibaba.druid.sql.ast.statement.SQLRollbackStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSetStatement;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem;
import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement;
import com.alibaba.druid.sql.ast.statement.SQLWithSubqueryClause;
import com.alibaba.druid.sql.dialect.gauss.ast.GaussSQLIndexSpec;
import com.alibaba.druid.sql.dialect.gauss.ast.expr.GaussSQLObjectCollection;
import com.alibaba.druid.sql.dialect.gauss.ast.expr.GaussSchemaTables;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussAlterDatabaseStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussAlterGroupStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussAlterIndexStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussAlterRoleStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussAlterSchemaStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussAlterSequenceStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussAlterSessionStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussAlterSynonymStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussAlterSystemKillSessionStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussAlterTableSpaceStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussAlterTableStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussAlterTriggerStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussAlterViewStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussConnectToStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussCreateDatabaseStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussCreateGroupStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussCreateIndexStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussCreateMaterializedViewStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussCreateRoleStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussCreateSchemaStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussCreateSeqenceStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussCreateSynonymStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussCreateTableSpaceStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussCreateTableStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussCreateTriggerStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussCreateViewStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussDeleteStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussDropSchemaStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussDropSequenceStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussDropTriggerStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussGrantStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussInsertStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussRevokeStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussSelectStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussShowStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussStartTransactionStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.GaussUpdateStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableAddColumn;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableAddConstraint;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableAlterColumn;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableAlterColumnOptions;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableCluster;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableDisableEnabelTrigger;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableDropColumn;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableDropConstraint;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableInheriteOrNotParentTable;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableModify;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableOf;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableRenameColumn;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableRenameConstraint;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableRenameTo;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableSetNewTableSpace;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableSetReset;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableSetSchema;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableSetTableSpace;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableSetWith;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterTableValidateConstraint;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussAlterUserStatement;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussColumnDefinition;
import com.alibaba.druid.sql.dialect.gauss.ast.stmt.alterTable.GaussCreateUserStatement;
import com.alibaba.druid.sql.parser.EOFParserException;
import com.alibaba.druid.sql.parser.Lexer;
import com.alibaba.druid.sql.parser.ParserException;
import com.alibaba.druid.sql.parser.SQLCreateTableParser;
import com.alibaba.druid.sql.parser.SQLExprParser;
import com.alibaba.druid.sql.parser.SQLParserFeature;
import com.alibaba.druid.sql.parser.SQLSelectParser;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.druid.sql.parser.Token;
import com.alibaba.druid.util.FnvHash;
import com.alibaba.druid.util.JdbcUtils;
import java.util.ArrayList;
import java.util.List;

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

   public GaussSQLStatementParser(GaussExprParser parser) {
      super((SQLExprParser)parser);
   }

   public GaussSQLStatementParser(String sql) {
      super((SQLExprParser)(new GaussExprParser(sql)));
   }

   public GaussSQLStatementParser(String sql, SQLParserFeature... features) {
      super((SQLExprParser)(new GaussExprParser(sql, features)));
   }

   public GaussSQLStatementParser(Lexer lexer) {
      super((SQLExprParser)(new GaussExprParser(lexer)));
   }

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

   public SQLUpdateStatement parseUpdateStatement() {
      this.accept(Token.UPDATE);
      GaussUpdateStatement udpateStatement = new GaussUpdateStatement();
      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 GaussInsertStatement parseInsert() {
      GaussInsertStatement stmt = new GaussInsertStatement();
      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("DUPLICATE")) {
            this.acceptIdentifier("DUPLICATE");
            this.accept(Token.KEY);
            this.accept(Token.UPDATE);
            List<SQLExpr> duplicateKeyUpdate = stmt.getDuplicateKeyUpdate();

            while(true) {
               SQLName name = this.exprParser.name();
               this.accept(Token.EQ);

               SQLExpr value;
               try {
                  value = this.exprParser.expr();
               } catch (EOFParserException e) {
                  throw new ParserException("EOF, " + name + "=", e);
               }

               SQLBinaryOpExpr assignment = new SQLBinaryOpExpr(name, SQLBinaryOperator.Equality, value);
               assignment.setParent(stmt);
               duplicateKeyUpdate.add(assignment);
               if (this.lexer.token() != Token.COMMA) {
                  break;
               }

               this.lexer.nextTokenIdent();
            }
         }

         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 GaussCreateSchemaStatement parseCreateSchema() {
      this.accept(Token.CREATE);
      this.accept(Token.SCHEMA);
      GaussCreateSchemaStatement stmt = new GaussCreateSchemaStatement();
      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);
      GaussAlterSchemaStatement stmt = new GaussAlterSchemaStatement();
      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());
      }

      if (this.lexer.token() == Token.WITH) {
         this.accept(Token.WITH);
         stmt.setWith(true);
         stmt.setWithValue(new SQLIdentifierExpr(this.lexer.stringVal()));
         this.lexer.nextToken();
         return stmt;
      } else {
         return stmt;
      }
   }

   protected GaussAlterDatabaseStatement parseAlterDatabase() {
      GaussAlterDatabaseStatement stmt = new GaussAlterDatabaseStatement();
      this.accept(Token.ALTER);
      this.accept(Token.DATABASE);
      stmt.setName(this.exprParser.name());
      if (this.lexer.token() == Token.WITH) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.ENABLE) {
            stmt.setEnable(true);
            this.lexer.nextToken();
            stmt.setPrivateValue(this.exprParser.name());
            stmt.setObjectValue(this.exprParser.name());
         } else if (this.lexer.token() == Token.ENABLE) {
            stmt.setEnable(true);
            this.lexer.nextToken();
            stmt.setPrivateValue(this.exprParser.name());
            stmt.setObjectValue(this.exprParser.name());
         } else {
            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(GaussAlterDatabaseStatement.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(GaussAlterDatabaseStatement.SetType.Reset);
         if (this.lexer.token() != Token.ALL) {
            stmt.setParamter(this.exprParser.expr());
         } else {
            this.accept(Token.ALL);
         }
      }

      return stmt;
   }

   public GaussDropSchemaStatement parseDropSchema() {
      GaussDropSchemaStatement stmt = new GaussDropSchemaStatement();
      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 GaussDeleteStatement parseDeleteStatement() {
      this.lexer.nextToken();
      GaussDeleteStatement deleteStatement = new GaussDeleteStatement();
      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:
            GaussStartTransactionStatement 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 GaussStartTransactionStatement parseBegin() {
      GaussStartTransactionStatement stmt = new GaussStartTransactionStatement();
      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);
      GaussConnectToStatement stmt = new GaussConnectToStatement();
      SQLName target = this.exprParser.name();
      stmt.setTarget(target);
      return stmt;
   }

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

   public SQLStatement parseWith() {
      SQLWithSubqueryClause with = this.parseWithQuery();
      if (this.lexer.token() == Token.INSERT) {
         GaussInsertStatement 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) {
            GaussDeleteStatement stmt = this.parseDeleteStatement();
            stmt.setWith(with);
            return stmt;
         } else if (this.lexer.token() == Token.UPDATE) {
            GaussUpdateStatement stmt = (GaussUpdateStatement)this.parseUpdateStatement();
            stmt.setWith(with);
            return stmt;
         } else {
            throw new ParserException("TODO. " + this.lexer.info());
         }
      } else {
         GaussSelectStatement 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);
      GaussShowStatement stmt = new GaussShowStatement();
      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();
         if (this.lexer.token() == Token.LITERAL_CHARS) {
            SQLIdentifierExpr sqlExpr = (SQLIdentifierExpr)values.get(0);
            values.clear();
            values.add(new SQLIdentifierExpr(sqlExpr.toString() + " PASSWORD " + this.exprParser.name().toString()));
         }
      } else if (hash == FnvHash.Constants.NAMES) {
         paramExpr = new SQLIdentifierExpr(parameter);
         this.lexer.nextToken();
         values.add(this.exprParser.primary());
      } else if (hash == FnvHash.Constants.CURRENT_SCHEMA) {
         this.lexer.nextToken();
         paramExpr = new SQLIdentifierExpr(parameter + (this.lexer.token().equals(Token.EQ) ? " = " : " TO "));
         this.lexer.nextToken();
         values.add(this.exprParser.primary());
      } else if (hash == FnvHash.Constants.XML) {
         this.lexer.nextToken();
         paramExpr = new SQLIdentifierExpr(parameter + " " + this.lexer.stringVal());
         this.lexer.nextToken();
         values.add(this.exprParser.primary());
      } else {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.FROM) {
            paramExpr = new SQLIdentifierExpr(parameter);
            this.lexer.nextToken();
            values.add(new SQLIdentifierExpr("FROM CURRENT "));
            this.lexer.nextToken();
         } else {
            paramExpr = new SQLIdentifierExpr(parameter + (this.lexer.token().equals(Token.EQ) ? " = " : " TO "));
         }

         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.toString();
      stmt.setOption(option);
      return stmt;
   }

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

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

      this.accept(Token.INDEX);
      if (this.lexer.identifierEquals("CONCURRENTLY")) {
         this.lexer.nextToken();
         stmt.setConcurrently(true);
      }

      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) {
         GaussSQLIndexSpec spec = new GaussSQLIndexSpec();
         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 GaussCreateTableParser(this.exprParser);
   }

   protected GaussAlterIndexStatement parseAlterIndex() {
      GaussAlterIndexStatement stmt = new GaussAlterIndexStatement();
      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(GaussAlterIndexStatement.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(GaussAlterIndexStatement.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(GaussAlterIndexStatement.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 GaussAlterSequenceStatement parseAlterSequence(boolean b) {
      GaussAlterSequenceStatement stmt = new GaussAlterSequenceStatement();
      if (b) {
         stmt.setLarge(true);
      }

      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(false);
      } else if (this.lexer.token() == Token.INDEX) {
         return this.parseAlterIndex();
      } else if (this.lexer.identifierEquals(FnvHash.Constants.MATERIALIZED)) {
         this.lexer.nextToken();
         return this.parseAlterView(true);
      } else if (this.lexer.token() == Token.VIEW) {
         return this.parseAlterView(false);
      } else if (this.lexer.token() == Token.TRIGGER) {
         return this.parseAlterTrigger();
      } else if (this.lexer.token() == Token.SESSION) {
         return this.parseAlterSession();
      } else if (this.lexer.identifierEquals("SYSTEM")) {
         return this.parseAlterSystemKillSession();
      } else if (this.lexer.token() == Token.TABLESPACE) {
         return this.parseAlterTablespace();
      } else if (this.lexer.token() == Token.USER) {
         this.lexer.reset(mark);
         return this.parseAlterUser();
      } else if (this.lexer.token() == Token.ROLE) {
         this.lexer.reset(mark);
         return this.parseAlterRole();
      } else if (this.lexer.token() == Token.GROUP) {
         this.lexer.reset(mark);
         return this.parseAlterGroup();
      } else {
         if (this.lexer.identifierEquals("LARGE")) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.SEQUENCE) {
               return this.parseAlterSequence(true);
            }
         } else if (this.lexer.identifierEquals("SYNONYM")) {
            this.lexer.reset(mark);
            return this.parseAlterSynonym();
         }

         this.lexer.reset(mark);
         return super.parseAlter();
      }
   }

   private SQLStatement parseAlterTrigger() {
      GaussAlterTriggerStatement stmt = new GaussAlterTriggerStatement();
      this.accept(Token.TRIGGER);
      stmt.setName(this.exprParser.name());
      this.lexer.nextToken();
      stmt.setTableName(this.exprParser.name());
      if (this.lexer.identifierEquals("RENAME")) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.TO) {
            stmt.setRenameTo(true);
            this.lexer.nextToken();
         }
      }

      stmt.setNewName(this.exprParser.name());
      return stmt;
   }

   public GaussAlterUserStatement parseAlterUser() {
      this.accept(Token.ALTER);
      this.accept(Token.USER);
      GaussAlterUserStatement stmt = new GaussAlterUserStatement();
      stmt.setUser(this.exprParser.name());
      if (this.lexer.identifierEquals("RENAME")) {
         stmt.setRenameTo(true);
         this.lexer.nextToken();
         this.accept(Token.TO);
         stmt.setNewName(this.exprParser.name());
         return stmt;
      } else if (this.lexer.identifierEquals("ACCOUNT")) {
         stmt.setAccount(true);
         this.lexer.nextToken();
         if (this.lexer.token() == Token.LOCK) {
            stmt.setLock(true);
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("UNLOCK")) {
            stmt.setUnlock(true);
            this.lexer.nextToken();
         }

         return stmt;
      } else {
         if (this.lexer.identifierEquals("ENCRYPTED")) {
            stmt.setEncrypted(true);
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("UNENCRYPTED")) {
            stmt.setUnencrypted(true);
            this.lexer.nextToken();
         }

         if (this.lexer.identifierEquals("PASSWORD")) {
            stmt.setPasswordFlag(true);
            this.lexer.nextToken();
         } else {
            this.acceptIdentifier("IDENTIFIED");
            this.accept(Token.BY);
         }

         stmt.setPassword(this.exprParser.primary());
         if (this.lexer.identifierEquals("EXPIRED")) {
            stmt.setExpired(true);
            this.lexer.nextToken();
         }

         if (this.lexer.token() == Token.DISABLE) {
            stmt.setDisable(true);
            this.lexer.nextToken();
         }

         return stmt;
      }
   }

   public GaussAlterRoleStatement parseAlterRole() {
      this.accept(Token.ALTER);
      this.accept(Token.ROLE);
      GaussAlterRoleStatement stmt = new GaussAlterRoleStatement();
      stmt.setUser(this.exprParser.name());
      if (this.lexer.identifierEquals("RENAME")) {
         stmt.setRenameTo(true);
         this.lexer.nextToken();
         this.accept(Token.TO);
         stmt.setNewName(this.exprParser.name());
         return stmt;
      } else if (this.lexer.identifierEquals("ACCOUNT")) {
         stmt.setAccount(true);
         this.lexer.nextToken();
         if (this.lexer.token() == Token.LOCK) {
            stmt.setLock(true);
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("UNLOCK")) {
            stmt.setUnlock(true);
            this.lexer.nextToken();
         }

         return stmt;
      } else {
         if (this.lexer.identifierEquals("ENCRYPTED")) {
            stmt.setEncrypted(true);
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("UNENCRYPTED")) {
            stmt.setUnencrypted(true);
            this.lexer.nextToken();
         }

         if (this.lexer.identifierEquals("PASSWORD")) {
            stmt.setPasswordFlag(true);
            this.lexer.nextToken();
         } else {
            this.acceptIdentifier("IDENTIFIED");
            this.accept(Token.BY);
         }

         stmt.setPassword(this.exprParser.primary());
         if (this.lexer.identifierEquals("EXPIRED")) {
            stmt.setExpired(true);
            this.lexer.nextToken();
         }

         if (this.lexer.token() == Token.DISABLE) {
            stmt.setDisable(true);
            this.lexer.nextToken();
         }

         return stmt;
      }
   }

   public GaussAlterGroupStatement parseAlterGroup() {
      this.accept(Token.ALTER);
      this.accept(Token.GROUP);
      GaussAlterGroupStatement stmt = new GaussAlterGroupStatement();
      stmt.setGroupName(this.exprParser.name());
      if (this.lexer.identifierEquals("RENAME")) {
         stmt.setRenameTo(true);
         this.lexer.nextToken();
         this.accept(Token.TO);
         stmt.setNewName(this.exprParser.name());
         return stmt;
      } else {
         if (this.lexer.identifierEquals("ADD")) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.USER) {
               stmt.setAddUser(true);
               this.lexer.nextToken();
            }
         } else if (this.lexer.token() == Token.DROP) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.USER) {
               stmt.setDropUser(true);
               this.lexer.nextToken();
            }
         }

         SQLListExpr listExpr = new SQLListExpr();
         this.exprParser.exprList(listExpr.getItems(), listExpr);
         stmt.setNames(listExpr);
         return stmt;
      }
   }

   private GaussAlterTableSpaceStatement parseAlterTablespace() {
      GaussAlterTableSpaceStatement stmt = new GaussAlterTableSpaceStatement();
      this.accept(Token.TABLESPACE);
      stmt.setTableSpaceName(new SQLIdentifierExpr(this.lexer.stringVal()));
      this.lexer.nextToken();
      if (this.lexer.identifierEquals("RENAME")) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.TO) {
            stmt.setRenameTo(true);
            this.lexer.nextToken();
            stmt.setNewTableSpaceName(new SQLIdentifierExpr(this.lexer.stringVal()));
            this.lexer.nextToken();
         }
      } else if (this.lexer.identifierEquals("OWNER")) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.TO) {
            stmt.setOwnerTo(true);
            this.lexer.nextToken();
            stmt.setOwnerName(new SQLIdentifierExpr(this.lexer.stringVal()));
            this.lexer.nextToken();
         }
      } else if (this.lexer.identifierEquals("RESIZE")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("MAXSIZE")) {
            stmt.setResizeMaxsize(true);
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("UNLIMITED")) {
               stmt.setUnlimited(true);
            } else {
               stmt.setSpaceSize(this.exprParser.name());
               this.lexer.nextToken();
            }
         }
      }

      return stmt;
   }

   public GaussAlterSessionStatement parseAlterSession() {
      this.accept(Token.SESSION);
      this.accept(Token.SET);
      GaussAlterSessionStatement stmt = new GaussAlterSessionStatement();
      if (this.lexer.token() == Token.SESSION) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("CHARACTERISTICS")) {
            this.lexer.nextToken();
            this.accept(Token.AS);
            stmt.setSessionCharacteristicsAs(true);
            if (this.lexer.identifierEquals("TRANSACTION")) {
               this.lexer.nextToken();
               stmt.setTransaction(true);
            }

            if (this.lexer.identifierEquals("ISOLATION")) {
               this.lexer.nextToken();
               if (this.lexer.identifierEquals("LEVEL")) {
                  this.lexer.nextToken();
                  stmt.setIsolationLevel(true);
               }
            }

            if (this.lexer.identifierEquals("READ")) {
               this.lexer.nextToken();
               if (this.lexer.identifierEquals("COMMITTED")) {
                  this.lexer.nextToken();
                  stmt.setReadCommitted(true);
                  return stmt;
               }

               if (this.lexer.identifierEquals("UNCOMMITTED")) {
                  this.lexer.nextToken();
                  stmt.setReadUncommitted(true);
                  return stmt;
               }

               if (this.lexer.identifierEquals("ONLY")) {
                  this.lexer.nextToken();
                  stmt.setReadOnly(true);
                  return stmt;
               }

               if (this.lexer.identifierEquals("WRITE")) {
                  this.lexer.nextToken();
                  stmt.setReadWrite(true);
                  return stmt;
               }
            }
         } else if (this.lexer.identifierEquals("AUTHORIZATION")) {
            this.lexer.nextToken();
            stmt.setSessionAuthorization(true);
            if (this.lexer.token() == Token.DEFAULT) {
               this.lexer.nextToken();
               stmt.setSessionAuthorizationDefault(true);
            } else {
               stmt.setRoleName(new SQLIdentifierExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
               if (this.lexer.identifierEquals("PASSWORD")) {
                  stmt.setPassword(true);
                  this.lexer.nextToken();
                  stmt.setPasswordValue(this.exprParser.name());
                  this.lexer.nextToken();
                  return stmt;
               }
            }
         }
      } else {
         if (this.lexer.identifierEquals("FROM")) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("CURRENT")) {
               this.lexer.nextToken();
               stmt.setFromCurrent(true);
            }

            return stmt;
         }

         if (this.lexer.identifierEquals("CURRENT_SCHEMA")) {
            this.lexer.nextToken();
            stmt.setCurrentSchema(true);
            if (this.lexer.token() == Token.TO) {
               this.lexer.nextToken();
               stmt.setCurrentSchemaTo(true);
            } else if (this.lexer.token() == Token.EQ) {
               this.lexer.nextToken();
               stmt.setCurrentSchemaEq(true);
            }

            if (this.lexer.token() == Token.DEFAULT) {
               this.lexer.nextToken();
               stmt.setCurrentSchemaDefault(true);
            } else {
               stmt.setSchema(new SQLIdentifierExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
            }

            return stmt;
         }

         if (this.lexer.identifierEquals("TIME")) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("ZONE")) {
               stmt.setTimeZone(true);
               this.lexer.nextToken();
               stmt.setTimeZoneValue(new SQLIdentifierExpr(this.lexer.stringVal()));
               return stmt;
            }
         } else {
            if (this.lexer.identifierEquals("SCHEMA")) {
               stmt.setSetSchema(true);
               this.lexer.nextToken();
               stmt.setSchema(new SQLIdentifierExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
               return stmt;
            }

            if (this.lexer.identifierEquals("NAMES")) {
               stmt.setNames(true);
               this.lexer.nextToken();
               stmt.setEncodingName(new SQLIdentifierExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
               return stmt;
            }

            if (this.lexer.identifierEquals("ROLE")) {
               stmt.setRole(true);
               this.lexer.nextToken();
               stmt.setRoleName(new SQLIdentifierExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
               if (this.lexer.identifierEquals("PASSWORD")) {
                  stmt.setPassword(true);
                  this.lexer.nextToken();
                  stmt.setPasswordValue(this.exprParser.name());
                  this.lexer.nextToken();
                  return stmt;
               }
            } else if (this.lexer.identifierEquals("XML")) {
               this.lexer.nextToken();
               if (this.lexer.identifierEquals("OPTION")) {
                  stmt.setXmlOption(true);
                  this.lexer.nextToken();
                  if (this.lexer.identifierEquals("DOCUMENT")) {
                     stmt.setDocument(true);
                     this.lexer.nextToken();
                     return stmt;
                  }

                  if (this.lexer.identifierEquals("CONTENT")) {
                     stmt.setDocument(true);
                     this.lexer.nextToken();
                     return stmt;
                  }
               }

               stmt.setEncodingName(new SQLIdentifierExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
               return stmt;
            }
         }
      }

      stmt.setConfigParameter(new SQLIdentifierExpr(this.lexer.stringVal()));
      this.lexer.nextToken();
      if (this.lexer.token() == Token.TO) {
         this.lexer.nextToken();
         stmt.setConfigParameterTo(true);
      } else if (this.lexer.token() == Token.EQ) {
         this.lexer.nextToken();
         stmt.setConfigParameterEq(true);
      }

      if (this.lexer.token() == Token.DEFAULT) {
         stmt.setConfigParameterDefault(true);
      } else {
         stmt.setValue(new SQLIdentifierExpr(this.lexer.stringVal()));
      }

      return stmt;
   }

   public GaussAlterSystemKillSessionStatement parseAlterSystemKillSession() {
      GaussAlterSystemKillSessionStatement stmt = new GaussAlterSystemKillSessionStatement();
      if (this.lexer.identifierEquals("SYSTEM")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("KILL")) {
            this.lexer.nextToken();
            this.accept(Token.SESSION);
            stmt.setConfigParameter(this.exprParser.expr());
            if (this.lexer.identifierEquals("IMMEDIATE")) {
               stmt.setImmediate(true);
               this.lexer.nextToken();
            }
         }
      }

      return stmt;
   }

   protected GaussAlterTableStatement parseAlterTable() {
      this.lexer.nextToken();
      GaussAlterTableStatement stmt = new GaussAlterTableStatement();
      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());
         if (this.lexer.identifierEquals("MODIFY")) {
            stmt.setModify(true);
            this.lexer.nextToken();
            GaussAlterTableModify gaussAlterTableModify = new GaussAlterTableModify();
            if (this.lexer.token() != Token.LPAREN) {
               SQLColumnDefinition columnDef = this.exprParser.parseColumn();
               gaussAlterTableModify.addColumn(columnDef);
            } else {
               this.lexer.nextToken();

               while(true) {
                  SQLColumnDefinition columnDef = this.exprParser.parseColumn();
                  gaussAlterTableModify.addColumn(columnDef);
                  if (this.lexer.token() != Token.COMMA) {
                     this.accept(Token.RPAREN);
                     break;
                  }

                  this.lexer.nextToken();
               }
            }

            stmt.addItem(gaussAlterTableModify);
         }

         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();
                  GaussAlterTableSetSchema item = new GaussAlterTableSetSchema();
                  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) {
                  GaussAlterTableSetTableSpace item = new GaussAlterTableSetTableSpace();
                  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")) {
                  GaussAlterTableValidateConstraint item = new GaussAlterTableValidateConstraint();
                  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();
                     GaussAlterTableCluster item = new GaussAlterTableCluster();
                     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) {
                        GaussAlterTableOf item = new GaussAlterTableOf();
                        this.lexer.nextToken();
                        item.setOf(true);
                        item.setTypeName(this.exprParser.expr());
                        stmt.addItem(item);
                     } else if (this.lexer.token() == Token.NOT) {
                        GaussAlterTableOf item = new GaussAlterTableOf();
                        this.lexer.nextToken();
                        item.setNotOf(true);
                        this.lexer.nextToken();
                        stmt.addItem(item);
                     } else if (this.lexer.identifierEquals("OWNER")) {
                        this.lexer.nextToken();
                        GaussAlterTableOf item = new GaussAlterTableOf();
                        item.setOwn(true);
                        this.accept(Token.TO);
                        item.setNewOwner(this.exprParser.expr());
                        stmt.addItem(item);
                     }
                  } else {
                     GaussAlterTableInheriteOrNotParentTable item = new GaussAlterTableInheriteOrNotParentTable();
                     item.setInherite(this.lexer.identifierEquals("INHERIT"));
                     this.lexer.nextToken();
                     if (!item.isInherite()) {
                        this.lexer.nextToken();
                     }

                     item.setParentTable(this.exprParser.expr());
                     stmt.addItem(item);
                  }
               } else {
                  GaussAlterTableDisableEnabelTrigger item = new GaussAlterTableDisableEnabelTrigger();
                  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(GaussAlterTableDisableEnabelTrigger.Type.all);
                  } else if (this.lexer.token() == Token.USER) {
                     this.lexer.nextToken();
                     item.setType(GaussAlterTableDisableEnabelTrigger.Type.user);
                  } else if (this.lexer.token() == Token.IDENTIFIER) {
                     item.setTrigger(this.exprParser.expr());
                  }

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

   private GaussAlterTableSetNewTableSpace parseAlterTableTablespace() {
      this.lexer.nextToken();
      this.accept(Token.IN);
      this.accept(Token.TABLESPACE);
      SQLName name = this.exprParser.name();
      GaussAlterTableSetNewTableSpace item = new GaussAlterTableSetNewTableSpace();
      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 GaussAlterTableRenameColumn parseAlterTableRenameColumn() {
      if (this.lexer.token() == Token.COLUMN) {
         this.lexer.nextToken();
      }

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

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

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

   private GaussAlterTableSetWith parseAlterTableSetWith() {
      GaussAlterTableSetWith item = new GaussAlterTableSetWith();
      if (this.lexer.token() == Token.WITH) {
         this.lexer.nextToken();
         item.setDistributeType(GaussAlterTableSetWith.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(GaussAlterTableSetWith.DistributeType.by);
            this.accept(Token.LPAREN);

            do {
               GaussAlterTableSetWith.GaussAlterTableDistributeByOption option = new GaussAlterTableSetWith.GaussAlterTableDistributeByOption();
               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(GaussAlterTableSetWith.DistributeType.randomly);
         } else if (this.lexer.identifierEquals("REPLICATED")) {
            this.lexer.nextToken();
            item.setDistributeType(GaussAlterTableSetWith.DistributeType.replicated);
         }
      }

      return item;
   }

   private GaussAlterTableSetReset parseAlterTableSetReset() {
      GaussAlterTableSetReset item = new GaussAlterTableSetReset();
      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 {
            GaussAlterTableSetReset.StorageParameter parameter = new GaussAlterTableSetReset.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);
         GaussAlterTableSetReset.StorageParameter parameter = new GaussAlterTableSetReset.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 GaussAlterTableAddColumn parseAlterTableAddColumn() {
      if (this.lexer.token() == Token.COLUMN) {
         this.lexer.nextToken();
      }

      GaussAlterTableAddColumn item = new GaussAlterTableAddColumn();
      GaussColumnDefinition col = new GaussColumnDefinition();
      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 GaussAlterTableAddConstraint parseAlterTableAddConstraint() {
      GaussAlterTableAddConstraint item = new GaussAlterTableAddConstraint();
      this.lexer.nextToken();
      GaussAlterTableAddConstraint.GaussAlterTableAddConstraintUsingIndex idx = new GaussAlterTableAddConstraint.GaussAlterTableAddConstraintUsingIndex();
      idx.setConstraint(this.exprParser.expr());
      if (this.lexer.token() == Token.UNIQUE) {
         this.lexer.nextToken();
         idx.setType(GaussAlterTableAddConstraint.GaussAlterTableAddConstraintUsingIndex.ConstraintType.unique);
      } else {
         this.lexer.nextToken();
         this.lexer.nextToken();
         idx.setType(GaussAlterTableAddConstraint.GaussAlterTableAddConstraintUsingIndex.ConstraintType.primaryKey);
      }

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

         this.lexer.nextToken();
      }

      item.setUsingIndex(idx);
      return item;
   }

   private GaussAlterTableDropColumn parseAlterTableDropColumn() {
      GaussAlterTableDropColumn item = new GaussAlterTableDropColumn();
      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(GaussAlterTableDropColumn.DropColumType.restrict);
      } else if (this.lexer.token() == Token.CASCADE) {
         this.lexer.nextToken();
         item.setType(GaussAlterTableDropColumn.DropColumType.cascade);
      }

      return item;
   }

   private GaussAlterTableDropConstraint parseAlterTableDropConstraint() {
      this.lexer.nextToken();
      GaussAlterTableDropConstraint item = new GaussAlterTableDropConstraint();
      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(GaussAlterTableDropConstraint.DorpType.restrict);
      } else if (this.lexer.token() == Token.CASCADE) {
         this.lexer.nextToken();
         item.setType(GaussAlterTableDropConstraint.DorpType.cascade);
      }

      return item;
   }

   private GaussAlterTableAlterColumn parseAlterTableAlterColumn() {
      GaussAlterTableAlterColumn item = new GaussAlterTableAlterColumn();
      item.setColumn(this.exprParser.expr());
      if (this.lexer.token() == Token.SET) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("DATA")) {
            this.lexer.nextToken();
            item.setType(GaussAlterTableAlterColumn.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(GaussAlterTableAlterColumn.Type.setDefault);
            item.setDefaultExpression(this.exprParser.expr());
         } else if (this.lexer.token() == Token.NOT) {
            this.lexer.nextToken();
            item.setType(GaussAlterTableAlterColumn.Type.setNotNull);
            this.accept(Token.NULL);
         } else if (this.lexer.identifierEquals("STATISTICS")) {
            item.setType(GaussAlterTableAlterColumn.Type.setStatistics);
            this.lexer.nextToken();
            item.setStatics(this.exprParser.expr());
         }
      } else if (this.lexer.token() == Token.TYPE) {
         this.lexer.nextToken();
         item.setType(GaussAlterTableAlterColumn.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(GaussAlterTableAlterColumn.Type.dropDefault);
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.NOT) {
            item.setType(GaussAlterTableAlterColumn.Type.dropNotNull);
            this.lexer.nextToken();
            this.accept(Token.NULL);
         }
      }

      return item;
   }

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

         do {
            GaussAlterTableAlterColumnOptions.GaussAlterTableAlterColumnOptionValue option = new GaussAlterTableAlterColumnOptions.GaussAlterTableAlterColumnOptionValue();
            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 {
            GaussAlterTableAlterColumnOptions.GaussAlterTableAlterColumnOptionValue option = new GaussAlterTableAlterColumnOptions.GaussAlterTableAlterColumnOptionValue();
            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 GaussCreateDatabaseStatement parseCreateDatabase() {
      if (this.lexer.token() == Token.CREATE) {
         this.lexer.nextToken();
      }

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

      GaussCreateDatabaseStatement stmt = new GaussCreateDatabaseStatement();
      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("ENCODING")) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.EQ) {
            this.lexer.nextToken();
         }

         stmt.setEncoding(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("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 GaussCreateTableStatement parseCreateTable() {
      GaussCreateTableParser parser = new GaussCreateTableParser(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 large = false;
      if (this.lexer.identifierEquals("LARGE")) {
         this.lexer.nextToken();
         large = 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;
      }

      boolean constraint = false;
      if (this.lexer.token() == Token.CONSTRAINT) {
         this.lexer.nextToken();
         constraint = true;
      }

      Token token = this.lexer.token();
      switch (this.lexer.token()) {
         case NOT:
         case INDEX:
         case UNIQUE:
            GaussCreateIndexStatement 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:
            GaussCreateSeqenceStatement stmt3 = new GaussCreateSeqenceStatement();
            if (large) {
               stmt3.setLarge(true);
            }

            return this.parseCreateSequenceGauss(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);
            GaussCreateDatabaseStatement GaussCreateDatabaseStatement = this.parseCreateDatabase();
            if (comments != null) {
               GaussCreateDatabaseStatement.addBeforeComment(comments);
               List<String> var17 = null;
            }

            return GaussCreateDatabaseStatement;
         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);
            GaussCreateSchemaStatement GaussCreateSchemaStatement = this.parseCreateSchema();
            if (comments != null) {
               GaussCreateSchemaStatement.addBeforeComment(comments);
               List<String> var16 = null;
            }

            return GaussCreateSchemaStatement;
         case USER:
            this.lexer.reset(markBp, markChar, Token.CREATE);
            return this.parseCreateUser();
         case ROLE:
            this.lexer.reset(markBp, markChar, Token.CREATE);
            return this.parseCreateRole();
         case GROUP:
            this.lexer.reset(markBp, markChar, Token.CREATE);
            return this.parseCreateGroup();
         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();
         case TRIGGER:
            this.lexer.reset(markBp, markChar, Token.CREATE);
            return this.parseCreateTrigger(constraint);
         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> var18 = 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 createIndex2 = this.parseCreateIndex(true);
                     if (nonclustered) {
                        createIndex2.setType("NONCLUSTERED");
                     }

                     return createIndex2;
                  }
               }
            } 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 createIndex3 = this.parseCreateIndex(true);
                  if (nonclustered) {
                     createIndex3.setType("NONCLUSTERED");
                  }

                  return createIndex3;
               }
            }
      }
   }

   public GaussGrantStatement parseGrant() throws ParserException {
      this.accept(Token.GRANT);
      GaussGrantStatement stmt = new GaussGrantStatement();
      this.parsePrivileages(stmt.getPrivileges(), stmt);
      if (this.lexer.token() == Token.ON) {
         this.lexer.nextToken();
         switch (this.lexer.token()) {
            case TABLE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.TABLE);
            case INDEX:
            case UNIQUE:
            case SEQUENCE:
            case ROLE:
            case GROUP:
            case TRIGGER:
            default:
               break;
            case DATABASE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.DATABASE);
               break;
            case SCHEMA:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.SCHEMA);
               break;
            case USER:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.USER);
               break;
            case FUNCTION:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.FUNCTION);
               break;
            case TABLESPACE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.TABLESPACE);
               break;
            case PROCEDURE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.PROCEDURE);
               break;
            case DOMAIN:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.DOMAIN);
               break;
            case TYPE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.TYPE);
               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);
            GaussSchemaTables c = new GaussSchemaTables();
            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 {
            GaussSQLObjectCollection c = new GaussSQLObjectCollection();
            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 (this.lexer.token() == Token.IDENTIFIER) {
         stmt.setRoleName(new SQLIdentifierExpr(this.lexer.stringVal()));
         this.lexer.nextToken();
      }

      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);
         }

         label101:
         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 label101;
                  }

                  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;
   }

   public GaussRevokeStatement parseRevoke() throws ParserException {
      this.accept(Token.REVOKE);
      GaussRevokeStatement stmt = new GaussRevokeStatement();
      if (this.lexer.token() == Token.GRANT) {
         this.lexer.nextToken();
         this.acceptIdentifier("OPTION");
         stmt.setGrantOptionFor(true);
         if (this.lexer.token() == Token.FOR) {
            this.lexer.nextToken();
         }
      }

      this.parsePrivileages(stmt.getPrivileges(), stmt);
      if (this.lexer.token() == Token.ON) {
         this.lexer.nextToken();
         switch (this.lexer.token()) {
            case TABLE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.TABLE);
            case INDEX:
            case UNIQUE:
            case SEQUENCE:
            case ROLE:
            case GROUP:
            case TRIGGER:
            default:
               break;
            case DATABASE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.DATABASE);
               break;
            case SCHEMA:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.SCHEMA);
               break;
            case USER:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.USER);
               break;
            case FUNCTION:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.FUNCTION);
               break;
            case TABLESPACE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.TABLESPACE);
               break;
            case PROCEDURE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.PROCEDURE);
               break;
            case DOMAIN:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.DOMAIN);
               break;
            case TYPE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.TYPE);
               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);
            GaussSchemaTables c = new GaussSchemaTables();
            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 {
            GaussSQLObjectCollection c = new GaussSQLObjectCollection();
            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 (this.lexer.token() == Token.IDENTIFIER) {
         stmt.setRoleName(new SQLIdentifierExpr(this.lexer.stringVal()));
         this.lexer.nextToken();
      }

      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.CASCADE) {
         stmt.setCascade(true);
         this.lexer.nextToken();
      }

      if (this.lexer.token() == Token.RESTRICT) {
         stmt.setRestrict(true);
         this.lexer.nextToken();
      }

      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.DROP) {
            privilege = "DROP";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.TEMPORARY) {
            this.lexer.nextToken();
            privilege = "TEMPORARY";
         } else if (this.lexer.token() == Token.TEMP) {
            this.lexer.nextToken();
            privilege = "TEMP";
         } else if (this.lexer.token() == Token.COMMENT) {
            privilege = "COMMENT";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.INDEX) {
            privilege = "INDEX";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.VACUUM) {
            privilege = "VACUUM";
            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 GaussAlterViewStatement parseAlterView(boolean b) {
      GaussAlterViewStatement stmt = new GaussAlterViewStatement();
      if (b) {
         stmt.setMaterialized(true);
      }

      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.setRename(true);
         this.lexer.nextToken();
         if (this.lexer.token() != Token.TO) {
            if (this.lexer.token() == Token.COLUMN) {
               stmt.setColumn(true);
               this.lexer.nextToken();
            }

            SQLName columnName = this.exprParser.name();
            stmt.setColumnName(columnName);
            this.accept(Token.TO);
            stmt.setColumnTo(true);
            columnName = this.exprParser.name();
            stmt.setNewColumnName(columnName);
            return stmt;
         }

         this.accept(Token.TO);
         stmt.setRenameTo(true);
         SQLName columnName = this.exprParser.name();
         stmt.setNewViewName(columnName);
      } 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 parseCreateSequenceGauss(GaussCreateSeqenceStatement stmt) {
      stmt.setDbType(this.dbType);
      this.accept(Token.SEQUENCE);
      SQLName name = this.exprParser.name();
      stmt.setSqeunceName(name);

      int i;
      do {
         i = 0;
         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());
            i = 1;
         }

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

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

         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);
            }

            i = 1;
         }

         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());
            i = 1;
         }

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

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

            i = 1;
         }

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

         if (this.lexer.identifierEquals("OWNED")) {
            this.lexer.nextToken();
            this.accept(Token.BY);
            stmt.setOwnedBy(true);
            stmt.setOwnedByName(this.exprParser.expr());
            i = 1;
         }
      } while(i != 0);

      return stmt;
   }

   public SQLStatement parseCreateTableSpace() {
      GaussCreateTableSpaceStatement stmt = new GaussCreateTableSpaceStatement();
      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("RELATIVE")) {
         stmt.setRelative(true);
         this.lexer.nextToken();
      }

      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;
            }
         }

         if (this.lexer.identifierEquals("MAXSIZE")) {
            this.lexer.nextToken();
            stmt.setMaxsize(this.exprParser.name());
            this.lexer.nextToken();
         }

         return stmt;
      }
   }

   public SQLCreateViewStatement parseCreateView() {
      GaussCreateViewStatement stmt = new GaussCreateViewStatement();
      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);
               GaussSelectStatement GaussSelectStatement = this.parseSelect();
               stmt.setSubQuery(GaussSelectStatement.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);
            GaussSelectStatement GaussSelectStatement = (GaussSelectStatement)sqlStatement;
            Boolean recursive = GaussSelectStatement.getSelect().getWithSubQuery().getRecursive();
            if (!recursive) {
               throw new ParserException("syntax error, not recursive" + this.lexer.info());
            }
         } else {
            GaussSelectStatement GaussSelectStatement = this.parseSelect();
            stmt.setSubQuery(GaussSelectStatement.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;
   }

   public GaussCreateMaterializedViewStatement parseCreateMaterializedView() {
      GaussCreateMaterializedViewStatement stmt = new GaussCreateMaterializedViewStatement();
      stmt.setDbType(this.dbType);
      this.accept(Token.CREATE);
      this.acceptIdentifier("MATERIALIZED");
      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);
         GaussSelectStatement gaussSelectStatement = (GaussSelectStatement)sqlStatement;
         Boolean recursive = gaussSelectStatement.getSelect().getWithSubQuery().getRecursive();
         if (!recursive) {
            throw new ParserException("syntax error, not recursive" + this.lexer.info());
         }
      } else {
         GaussSelectStatement gaussSelectStatement = this.parseSelect();
         stmt.setSubQuery(gaussSelectStatement.getSelect());
      }

      if (this.lexer.token() == Token.WITH) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("NO")) {
            stmt.setNo(true);
            this.lexer.nextToken();
         }

         if (this.lexer.identifierEquals("DATA")) {
            stmt.setWithData(true);
            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 acceptLarge) {
      GaussDropSequenceStatement stmt = new GaussDropSequenceStatement();
      stmt.setDbType(this.dbType);
      if (acceptLarge) {
         stmt.setLarge(true);
      }

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

      while(true) {
         String s = this.lexer.stringVal();
         this.lexer.nextToken();
         if (this.lexer.token() == Token.DOT) {
            this.lexer.nextToken();
            s = s + "." + this.lexer.stringVal();
            this.lexer.nextToken();
         }

         stmt.getSeqList().add(new SQLIdentifierExpr(s));
         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;
      }

      boolean large = false;
      if (this.lexer.identifierEquals("LARGE")) {
         this.lexer.nextToken();
         large = 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 GROUP:
         case FUNCTION:
         case PROCEDURE:
         case DOMAIN:
         case TYPE:
         case IDENTIFIER:
         default:
            this.lexer.reset(mark);
            return super.parseDrop();
         case SEQUENCE:
            return this.parseDropSequence(large);
         case DATABASE:
            return this.parseDropDatabase();
         case SCHEMA:
            return this.parseDropSchema();
         case ROLE:
            return this.parseDropRole();
         case TABLESPACE:
            return this.parseDropTablespace(false);
         case TRIGGER:
            return this.parseDropTrigger();
         case VIEW:
            return this.parseDropView(false);
      }
   }

   private SQLStatement parseDropTrigger() {
      this.lexer.nextToken();
      GaussDropTriggerStatement stmt = new GaussDropTriggerStatement();
      if (this.lexer.token() == Token.IF) {
         this.lexer.nextToken();
         this.accept(Token.EXISTS);
         stmt.setIfExists(true);
      }

      SQLName name = this.exprParser.name();
      stmt.setName(name);
      this.lexer.nextToken();
      stmt.setTableName(this.exprParser.name());
      if (this.lexer.token() == Token.CASCADE) {
         this.lexer.nextToken();
         stmt.setCascade(true);
      }

      if (this.lexer.token() == Token.RESTRICT) {
         this.lexer.nextToken();
         stmt.setRestrict(true);
      }

      return stmt;
   }

   public GaussCreateUserStatement parseCreateUser() {
      this.accept(Token.CREATE);
      this.accept(Token.USER);
      GaussCreateUserStatement stmt = new GaussCreateUserStatement();
      stmt.setUser(this.exprParser.name());
      if (this.lexer.identifierEquals("ENCRYPTED")) {
         stmt.setEncrypted(true);
         this.lexer.nextToken();
      } else if (this.lexer.identifierEquals("UNENCRYPTED")) {
         stmt.setUnencrypted(true);
         this.lexer.nextToken();
      }

      if (this.lexer.identifierEquals("PASSWORD")) {
         stmt.setPasswordFlag(true);
         this.lexer.nextToken();
      } else {
         this.acceptIdentifier("IDENTIFIED");
         this.accept(Token.BY);
      }

      stmt.setPassword(this.exprParser.primary());
      if (this.lexer.identifierEquals("EXPIRED")) {
         stmt.setExpired(true);
         this.lexer.nextToken();
      }

      if (this.lexer.token() == Token.DISABLE) {
         stmt.setDisable(true);
         this.lexer.nextToken();
      }

      return stmt;
   }

   public GaussCreateGroupStatement parseCreateGroup() {
      this.accept(Token.CREATE);
      this.accept(Token.GROUP);
      GaussCreateGroupStatement stmt = new GaussCreateGroupStatement();
      stmt.setUser(this.exprParser.name());
      if (this.lexer.identifierEquals("ENCRYPTED")) {
         stmt.setEncrypted(true);
         this.lexer.nextToken();
      } else if (this.lexer.identifierEquals("UNENCRYPTED")) {
         stmt.setUnencrypted(true);
         this.lexer.nextToken();
      }

      if (this.lexer.identifierEquals("PASSWORD")) {
         stmt.setPasswordFlag(true);
         this.lexer.nextToken();
      } else {
         this.acceptIdentifier("IDENTIFIED");
         this.accept(Token.BY);
      }

      stmt.setPassword(this.exprParser.primary());
      if (this.lexer.identifierEquals("EXPIRED")) {
         stmt.setExpired(true);
         this.lexer.nextToken();
      }

      if (this.lexer.token() == Token.DISABLE) {
         stmt.setDisable(true);
         this.lexer.nextToken();
      }

      return stmt;
   }

   public SQLStatement parseCreateSynonym() {
      GaussCreateSynonymStatement stmt = new GaussCreateSynonymStatement();
      this.accept(Token.CREATE);
      if (this.lexer.token() == Token.OR) {
         this.lexer.nextToken();
         this.accept(Token.REPLACE);
         stmt.setOrReplace(true);
      }

      this.lexer.nextToken();
      stmt.setName(new SQLIdentifierExpr(this.lexer.stringVal()));
      this.lexer.nextToken();
      this.lexer.nextToken();
      stmt.setObject(this.exprParser.name());
      this.lexer.nextToken();
      return stmt;
   }

   public SQLStatement parseAlterSynonym() {
      GaussAlterSynonymStatement stmt = new GaussAlterSynonymStatement();
      this.accept(Token.ALTER);
      this.acceptIdentifier("SYNONYM");
      stmt.setName(new SQLIdentifierExpr(this.lexer.stringVal()));
      this.lexer.nextToken();
      this.lexer.nextToken();
      this.lexer.nextToken();
      stmt.setNewName(this.exprParser.name());
      this.lexer.nextToken();
      return stmt;
   }

   public SQLStatement parseCreateRole() {
      this.accept(Token.CREATE);
      this.accept(Token.ROLE);
      GaussCreateRoleStatement stmt = new GaussCreateRoleStatement();
      stmt.setName(this.exprParser.name());
      if (this.lexer.identifierEquals("ENCRYPTED")) {
         stmt.setEncrypted(true);
         this.lexer.nextToken();
      } else if (this.lexer.identifierEquals("UNENCRYPTED")) {
         stmt.setUnencrypted(true);
         this.lexer.nextToken();
      }

      if (this.lexer.identifierEquals("PASSWORD")) {
         stmt.setPasswordFlag(true);
         this.lexer.nextToken();
      } else {
         this.acceptIdentifier("IDENTIFIED");
         this.accept(Token.BY);
      }

      stmt.setPassword(this.exprParser.primary());
      if (this.lexer.identifierEquals("EXPIRED")) {
         stmt.setExpired(true);
         this.lexer.nextToken();
      }

      if (this.lexer.token() == Token.DISABLE) {
         stmt.setDisable(true);
         this.lexer.nextToken();
      }

      return stmt;
   }

   protected SQLStatement parseDropRole() {
      this.accept(Token.ROLE);
      SQLDropRoleStatement stmt = new SQLDropRoleStatement();
      stmt.setDbType(this.dbType);
      if (this.lexer.token() == Token.IF) {
         this.lexer.nextToken();
         this.accept(Token.EXISTS);
         stmt.setIfExists(true);
      }

      SQLListExpr listExpr = new SQLListExpr();
      this.exprParser.exprList(listExpr.getItems(), listExpr);
      stmt.setNames(listExpr);
      return stmt;
   }

   public SQLStatement parseCreateTrigger(boolean constraint) {
      GaussCreateTriggerStatement stmt = new GaussCreateTriggerStatement(this.getDbType());
      this.accept(Token.CREATE);
      if (constraint) {
         this.lexer.nextToken();
         stmt.setConstraint(true);
      }

      this.accept(Token.TRIGGER);
      stmt.setName(new SQLIdentifierExpr(this.lexer.stringVal()));
      this.lexer.nextToken();
      if (this.lexer.identifierEquals(FnvHash.Constants.BEFORE)) {
         stmt.setTriggerType(GaussCreateTriggerStatement.TriggerType.BEFORE);
         this.lexer.nextToken();
      } else if (this.lexer.identifierEquals(FnvHash.Constants.AFTER)) {
         stmt.setTriggerType(GaussCreateTriggerStatement.TriggerType.AFTER);
         this.lexer.nextToken();
      } else if (this.lexer.identifierEquals(FnvHash.Constants.INSTEAD)) {
         this.lexer.nextToken();
         this.accept(Token.OF);
         stmt.setTriggerType(GaussCreateTriggerStatement.TriggerType.INSTEAD_OF);
      }

      while(true) {
         if (this.lexer.token() == Token.INSERT) {
            this.lexer.nextToken();
            stmt.setInsert(true);
         } else if (this.lexer.token() == Token.UPDATE) {
            this.lexer.nextToken();
            stmt.setUpdate(true);
            if (this.lexer.token() == Token.OF) {
               this.lexer.nextToken();
               this.exprParser.names(stmt.getUpdateOfColumns(), stmt);
            }
         } else if (this.lexer.token() == Token.DELETE) {
            this.lexer.nextToken();
            stmt.setDelete(true);
         }

         if (this.lexer.token() != Token.COMMA && this.lexer.token() != Token.OR) {
            this.accept(Token.ON);
            stmt.setOn(this.exprParser.name());
            if (this.lexer.token() == Token.FOR) {
               this.lexer.nextToken();
               this.acceptIdentifier("EACH");
               this.accept(Token.ROW);
               stmt.setForEachRow(true);
               if (this.lexer.token() == Token.FOLLOWS || this.lexer.token() == Token.PRECEDES) {
                  SQLName order = new SQLIdentifierExpr(this.lexer.stringVal());
                  stmt.setTriggerOrder(order);
                  this.lexer.nextToken();
                  if (this.lexer.token() == Token.IDENTIFIER) {
                     SQLName name = this.exprParser.name();
                     stmt.setOtherTriggerName(name);
                  }
               }
            }

            if (this.lexer.token() == Token.WHEN) {
               this.lexer.nextToken();
               SQLExpr condition = this.exprParser.expr();
               stmt.setWhen(condition);
            }

            if (this.lexer.token() == Token.EXECUTE) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.PROCEDURE) {
                  stmt.setExecuteProcedure(true);
                  this.lexer.nextToken();
               }
            }

            stmt.setFunctionName(this.exprParser.expr());
            return stmt;
         }

         this.lexer.nextToken();
      }
   }
}
