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

import com.chenyang.druid.DbType;
import com.chenyang.druid.sql.ast.SQLCommentHint;
import com.chenyang.druid.sql.ast.SQLExpr;
import com.chenyang.druid.sql.ast.SQLName;
import com.chenyang.druid.sql.ast.SQLObject;
import com.chenyang.druid.sql.ast.SQLStatement;
import com.chenyang.druid.sql.ast.expr.SQLAllColumnExpr;
import com.chenyang.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.chenyang.druid.sql.ast.expr.SQLBinaryOperator;
import com.chenyang.druid.sql.ast.expr.SQLCharExpr;
import com.chenyang.druid.sql.ast.expr.SQLCurrentOfCursorExpr;
import com.chenyang.druid.sql.ast.expr.SQLDateExpr;
import com.chenyang.druid.sql.ast.expr.SQLIdentifierExpr;
import com.chenyang.druid.sql.ast.expr.SQLListExpr;
import com.chenyang.druid.sql.ast.expr.SQLQueryExpr;
import com.chenyang.druid.sql.ast.expr.SQLRealExpr;
import com.chenyang.druid.sql.ast.expr.SQLTimestampExpr;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableAlterColumn;
import com.chenyang.druid.sql.ast.statement.SQLColumnDefinition;
import com.chenyang.druid.sql.ast.statement.SQLCommitStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateContextStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateDirectoryStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateDomainStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateFunctionStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateIndexStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateProcedureStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropDatabaseStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropRoleStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropSequenceStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLExprTableSource;
import com.chenyang.druid.sql.ast.statement.SQLInsertStatement;
import com.chenyang.druid.sql.ast.statement.SQLObjectType;
import com.chenyang.druid.sql.ast.statement.SQLPrivilegeItem;
import com.chenyang.druid.sql.ast.statement.SQLRollbackStatement;
import com.chenyang.druid.sql.ast.statement.SQLSelect;
import com.chenyang.druid.sql.ast.statement.SQLSetStatement;
import com.chenyang.druid.sql.ast.statement.SQLTableSource;
import com.chenyang.druid.sql.ast.statement.SQLUpdateSetItem;
import com.chenyang.druid.sql.ast.statement.SQLUpdateStatement;
import com.chenyang.druid.sql.ast.statement.SQLWithSubqueryClause;
import com.chenyang.druid.sql.dialect.db2.ast.DB2SQLIndexSpec;
import com.chenyang.druid.sql.dialect.db2.ast.expr.DB2SQLObjectCollection;
import com.chenyang.druid.sql.dialect.db2.ast.expr.DB2SchemaTables;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2AlterDatabaseStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2AlterGroupStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2AlterIndexStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2AlterRoleStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2AlterSchemaStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2AlterSequenceStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2AlterSessionStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2AlterSynonymStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2AlterSystemKillSessionStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2AlterTableSpaceStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2AlterTableStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2AlterTriggerStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2AlterViewStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2ConnectToStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2CreateDatabaseStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2CreateGroupStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2CreateIndexStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2CreateMaterializedViewStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2CreateRoleStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2CreateSchemaStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2CreateSeqenceStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2CreateSynonymStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2CreateTableSpaceStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2CreateTableStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2CreateTriggerStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2CreateViewStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2DeleteStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2DropConnectionStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2DropSchemaStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2DropSequenceStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2DropTriggerStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2GrantStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2InsertStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2RevokeStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2SelectStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2SetConnectionStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2SetSessionStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2SetTransactionStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2ShowStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2StartTransactionStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.DB2UpdateStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableAddColumn;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableAddConstraint;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableAlterColumn;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableAlterColumnOptions;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableCluster;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableDisableEnabelTrigger;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableDropColumn;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableDropConstraint;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableInheriteOrNotParentTable;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableModify;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableOf;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableRenameColumn;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableRenameConstraint;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableRenameTo;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableSetNewTableSpace;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableSetReset;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableSetSchema;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableSetTableSpace;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableSetWith;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterTableValidateConstraint;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2AlterUserStatement;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2ColumnDefinition;
import com.chenyang.druid.sql.dialect.db2.ast.stmt.alterTable.DB2CreateUserStatement;
import com.chenyang.druid.sql.parser.EOFParserException;
import com.chenyang.druid.sql.parser.Lexer;
import com.chenyang.druid.sql.parser.ParserException;
import com.chenyang.druid.sql.parser.SQLCreateTableParser;
import com.chenyang.druid.sql.parser.SQLExprParser;
import com.chenyang.druid.sql.parser.SQLParserFeature;
import com.chenyang.druid.sql.parser.SQLSelectParser;
import com.chenyang.druid.sql.parser.SQLStatementParser;
import com.chenyang.druid.sql.parser.Token;
import com.chenyang.druid.util.FnvHash;
import com.chenyang.druid.util.JdbcUtils;
import java.util.ArrayList;
import java.util.List;

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

   public DB2SQLStatementParser(DB2ExprParser parser) {
      super((SQLExprParser)parser);
   }

   public DB2SQLStatementParser(String sql) {
      super((SQLExprParser)(new DB2ExprParser(sql)));
   }

   public DB2SQLStatementParser(String sql, SQLParserFeature... features) {
      super((SQLExprParser)(new DB2ExprParser(sql, features)));
   }

   public DB2SQLStatementParser(Lexer lexer) {
      super((SQLExprParser)(new DB2ExprParser(lexer)));
   }

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

   public SQLUpdateStatement parseUpdateStatement() {
      this.accept(Token.UPDATE);
      DB2UpdateStatement udpateStatement = new DB2UpdateStatement();
      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 DB2InsertStatement parseInsert() {
      DB2InsertStatement stmt = new DB2InsertStatement();
      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 DB2CreateSchemaStatement parseCreateSchema() {
      this.accept(Token.CREATE);
      this.accept(Token.SCHEMA);
      DB2CreateSchemaStatement stmt = new DB2CreateSchemaStatement();

      while(this.lexer.token() != Token.COMMA && this.lexer.token() != Token.EOF) {
         stmt.setSchemaName(this.exprParser.name());
         if (this.lexer.identifierEquals("AUTHORIZATION")) {
            this.lexer.nextToken();
            stmt.setAuthorization(true);
            SQLIdentifierExpr userName = (SQLIdentifierExpr)this.exprParser.expr();
            stmt.setUserName(userName);
         }

         if (this.lexer.identifierEquals("PATH")) {
            stmt.setPath(true);
            this.lexer.nextToken();
            stmt.setSchemaPath(this.exprParser.expr());
         }

         if (this.lexer.token() == Token.CREATE) {
            SQLStatement statement = this.parseStatement();
            stmt.addElement(statement);
         } else if (this.lexer.identifierEquals("DATA_VERSION_RETENTION_TIME")) {
            stmt.setDataVersionRetentionTime(true);
            this.lexer.nextToken();
            stmt.setDataVersionRetentionTimeNum(this.exprParser.expr());
         }
      }

      return stmt;
   }

   protected SQLStatement parseAlterSchema() {
      this.accept(Token.ALTER);
      this.accept(Token.SCHEMA);
      DB2AlterSchemaStatement stmt = new DB2AlterSchemaStatement();
      stmt.setSchemaName(this.exprParser.name());
      if (this.lexer.identifierEquals(FnvHash.Constants.RENAME)) {
         this.lexer.nextToken();
         this.accept(Token.TO);
         stmt.setNewName(this.exprParser.identifier());
      } else if (this.lexer.identifierEquals("AUTHORIZATION")) {
         this.lexer.nextToken();
         this.accept(Token.TO);
         stmt.setNewOwner(this.exprParser.identifier());
      } else if (this.lexer.token() == Token.SET) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("PATH")) {
            stmt.setPath(true);
            this.lexer.nextToken();
            stmt.setSchemaPath(this.exprParser.expr());
         }
      } else if (this.lexer.identifierEquals("DATA_VERSION_RETENTION_TIME")) {
         stmt.setDataVersionRetentionTime(true);
         this.lexer.nextToken();
         stmt.setDataVersionRetentionTimeNum(this.exprParser.expr());
         if (this.lexer.identifierEquals("NOCASCADE")) {
            this.lexer.nextToken();
         }
      }

      return stmt;
   }

   protected DB2AlterDatabaseStatement parseAlterDatabase() {
      DB2AlterDatabaseStatement stmt = new DB2AlterDatabaseStatement();
      this.accept(Token.ALTER);
      this.accept(Token.DATABASE);
      stmt.setName(this.exprParser.name());
      if (this.lexer.token() == Token.SET) {
         stmt.setSet(true);
         this.lexer.nextToken();
         if (this.lexer.token() == Token.DEFAULT) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("SCHEMA")) {
               stmt.setDefaultSchema(true);
               this.lexer.nextToken();
               stmt.setDefaultSchemaName(new SQLIdentifierExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
            } else if (this.lexer.identifierEquals("CHARACTER")) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.SET) {
                  this.lexer.nextToken();
                  if (this.lexer.identifierEquals("LATIN9")) {
                     stmt.setDefaultCharacterSetLatin9(true);
                     this.lexer.nextToken();
                  }
               }
            }
         }
      } 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.identifierEquals("COLLECT")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("HISTORY")) {
            stmt.setCollectHistory(true);
            this.lexer.nextToken();
            stmt.setCollectHistoryType(new SQLIdentifierExpr(this.lexer.stringVal()));
            this.lexer.nextToken();
         }
      } else if (this.lexer.identifierEquals("DATA_VERSION_RETENTION_TIME")) {
         stmt.setDataVersionRetentionTime(true);
         this.lexer.nextToken();
         stmt.setDataVersionRetentionTimeNum(new SQLIdentifierExpr(this.lexer.numberString()));
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("NOCASCADE")) {
            stmt.setNocascade(true);
            this.lexer.nextToken();
         }
      } else if (this.lexer.identifierEquals("GROOM")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("BACKUPSET")) {
            stmt.setGroomBackupset(true);
            this.lexer.nextToken();
            stmt.setGroomBackupsetNum(this.exprParser.expr());
            this.lexer.nextToken();
         }
      }

      return stmt;
   }

   public DB2DropSchemaStatement parseDropSchema() {
      DB2DropSchemaStatement stmt = new DB2DropSchemaStatement();
      stmt.setDbType(this.dbType);
      this.accept(Token.SCHEMA);
      stmt.setSchema(this.exprParser.name());
      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;
   }

   public DB2DeleteStatement parseDeleteStatement() {
      this.lexer.nextToken();
      DB2DeleteStatement deleteStatement = new DB2DeleteStatement();
      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.identifierEquals("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:
            DB2StartTransactionStatement 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 DB2StartTransactionStatement parseBegin() {
      DB2StartTransactionStatement stmt = new DB2StartTransactionStatement();
      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);
      DB2ConnectToStatement stmt = new DB2ConnectToStatement();
      SQLName target = this.exprParser.name();
      stmt.setTarget(target);
      return stmt;
   }

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

   public SQLStatement parseWith() {
      SQLWithSubqueryClause with = this.parseWithQuery();
      if (this.lexer.token() == Token.INSERT) {
         DB2InsertStatement 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) {
            DB2DeleteStatement stmt = this.parseDeleteStatement();
            stmt.setWith(with);
            return stmt;
         } else if (this.lexer.token() == Token.UPDATE) {
            DB2UpdateStatement stmt = (DB2UpdateStatement)this.parseUpdateStatement();
            stmt.setWith(with);
            return stmt;
         } else {
            throw new ParserException("TODO. " + this.lexer.info());
         }
      } else {
         DB2SelectStatement 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);
      DB2ShowStatement stmt = new DB2ShowStatement();
      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();
      if (this.lexer.identifierEquals("TRANSACTION")) {
         return this.parseDb2SetTransactionStatement();
      } else if (this.lexer.token() == Token.SESSION) {
         return this.parseDb2SetSessionStatement();
      } else if (this.lexer.identifierEquals("CONNECTION")) {
         return this.parseDb2SetConnectionStatement();
      } else {
         long hash = this.lexer.hash_lower();
         String parameter = null;
         SQLExpr paramExpr = null;
         List<SQLExpr> values = new ArrayList();
         SQLIdentifierExpr var12;
         if (hash == FnvHash.Constants.TIME) {
            this.lexer.nextToken();
            this.acceptIdentifier("ZONE");
            var12 = 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 {
            parameter = this.lexer.stringVal();
            this.lexer.nextToken();
            var12 = new SQLIdentifierExpr(parameter + (this.lexer.token().equals(Token.EQ) ? " = " : " TO "));
            this.lexer.nextToken();
            SQLListExpr listExpr = new SQLListExpr();
            this.exprParser.exprList(listExpr.getItems(), listExpr);

            for(SQLExpr item : listExpr.getItems()) {
               values.add(item);
            }

            this.lexer.nextToken();
         }

         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(var12, valueExpr, this.dbType);
         stmt.toString();
         stmt.setOption((SQLSetStatement.Option)null);
         return stmt;
      }
   }

   private DB2SetTransactionStatement parseDb2SetTransactionStatement() {
      DB2SetTransactionStatement stmt = new DB2SetTransactionStatement();
      stmt.setTransaction(true);
      this.lexer.nextToken();
      if (this.lexer.identifierEquals("READ")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("WRITE")) {
            stmt.setReadWrite(true);
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.ONLY) {
            stmt.setReadOnly(true);
            this.lexer.nextToken();
         }
      } else if (this.lexer.identifierEquals("ISOLATION")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("LEVEL")) {
            stmt.setIsolationLevel(true);
            this.lexer.nextToken();
         }

         if (this.lexer.identifierEquals("SERIALIZABLE")) {
            stmt.setSerializable(true);
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("READ")) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("UNCOMMITTED")) {
               stmt.setReadUncommitted(true);
               this.lexer.nextToken();
            } else if (this.lexer.identifierEquals("COMMITTED")) {
               stmt.setReadCommitted(true);
               this.lexer.nextToken();
            }
         } else if (this.lexer.identifierEquals("REPEATABLE")) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("READ")) {
               stmt.setRepeatableRead(true);
               this.lexer.nextToken();
            }
         }
      }

      return stmt;
   }

   private SQLStatement parseDb2SetSessionStatement() {
      DB2SetSessionStatement stmt = new DB2SetSessionStatement();
      this.lexer.nextToken();
      if (this.lexer.identifierEquals("READ")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("WRITE")) {
            stmt.setReadWrite(true);
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.ONLY) {
            stmt.setReadOnly(true);
            this.lexer.nextToken();
         }
      }

      return stmt;
   }

   private SQLStatement parseDb2SetConnectionStatement() {
      DB2SetConnectionStatement stmt = new DB2SetConnectionStatement();
      this.lexer.nextToken();
      stmt.setHostType(this.exprParser.name());
      if (this.lexer.token() == Token.DATABASE) {
         stmt.setDatabase(true);
         this.lexer.nextToken();
         stmt.setDatabaseName(this.exprParser.expr());
      }

      if (this.lexer.identifierEquals("IPADDR")) {
         stmt.setIpaddr(true);
         this.lexer.nextToken();
         stmt.setIpAddress(this.exprParser.expr());
      }

      if (this.lexer.identifierEquals("IPMASK")) {
         stmt.setIpMask(true);
         this.lexer.nextToken();
         stmt.setIpAddressMask(this.exprParser.expr());
      }

      if (this.lexer.identifierEquals("AUTH")) {
         stmt.setAuth(true);
         this.lexer.nextToken();
         stmt.setAuthType(this.exprParser.expr());
      }

      return stmt;
   }

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

      DB2CreateIndexStatement stmt = new DB2CreateIndexStatement(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) {
         DB2SQLIndexSpec spec = new DB2SQLIndexSpec();
         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 DB2CreateTableParser(this.exprParser);
   }

   protected DB2AlterIndexStatement parseAlterIndex() {
      DB2AlterIndexStatement stmt = new DB2AlterIndexStatement();
      this.accept(Token.INDEX);
      stmt.setName(new SQLIdentifierExpr(this.lexer.stringVal()));
      this.lexer.nextToken();
      if (this.lexer.token() == Token.WITH) {
         this.accept(Token.WITH);
         this.accept(Token.TABLESPACE);
         stmt.setSetTableSpace(true);
         stmt.setNewTableSpace(this.exprParser.name());
      }

      if (this.lexer.identifierEquals("REORGANIZE")) {
         stmt.setReorganize(true);
         this.lexer.nextToken();
         if (this.lexer.token() == Token.ON) {
            stmt.setOn(true);
            this.lexer.nextToken();
            stmt.setTableName(new SQLIdentifierExpr(this.lexer.stringVal()));
            this.lexer.nextToken();
         }
      }

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

      return stmt;
   }

   public DB2AlterSequenceStatement parseAlterSequence(boolean b) {
      DB2AlterSequenceStatement stmt = new DB2AlterSequenceStatement();
      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.identifierEquals("VIEWS")) {
         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() {
      DB2AlterTriggerStatement stmt = new DB2AlterTriggerStatement();
      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 DB2AlterUserStatement parseAlterUser() {
      this.accept(Token.ALTER);
      this.accept(Token.USER);
      DB2AlterUserStatement stmt = new DB2AlterUserStatement();
      stmt.setUser(this.exprParser.name());
      if (this.lexer.identifierEquals("RENAME")) {
         this.lexer.nextToken();
         this.accept(Token.TO);
         stmt.setRenameTo(true);
         stmt.setNewName(this.exprParser.name());
      }

      if (this.lexer.token() == Token.RESET) {
         this.lexer.nextToken();
         this.acceptIdentifier("ACCOUNT");
         stmt.setResetAccount(true);
      }

      if (this.lexer.token() == Token.WITH) {
         stmt.setWith(true);
         this.lexer.nextToken();
      }

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

      if (this.lexer.identifierEquals("EXPIRE")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("PASSWORD")) {
            stmt.setExpirePassword(true);
            this.lexer.nextToken();
         }
      }

      if (this.lexer.identifierEquals("PASSWORDEXPIRY")) {
         stmt.setPasswordexpiry(true);
         this.lexer.nextToken();
         stmt.setPasswordexpiryDay(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("AUTH")) {
         stmt.setAuth(true);
         this.lexer.nextToken();
         stmt.setAuthType(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("SYSID")) {
         stmt.setSysid(true);
         this.lexer.nextToken();
         stmt.setSysidValue(this.exprParser.primary());
      }

      if (this.lexer.token() == Token.IN) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.GROUP) {
            stmt.setInGroup(true);
            this.lexer.nextToken();
         }

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

      if (this.lexer.token() == Token.IN) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("RESOURCEGROUP")) {
            stmt.setInResourcegroup(true);
            this.lexer.nextToken();
         }

         stmt.setInResourcegroupRsg(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("VALID")) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.UNTIL) {
            stmt.setValidUntil(true);
            this.lexer.nextToken();
         }

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

      if (this.lexer.identifierEquals("DEFPRIORITY")) {
         stmt.setDefpriority(true);
         this.lexer.nextToken();
         stmt.setDefpriorityType(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("MAXPRIORITY")) {
         stmt.setMaxpriority(true);
         this.lexer.nextToken();
         stmt.setMaxpriorityType(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("ROWSETLIMIT")) {
         stmt.setRowsetlimit(true);
         this.lexer.nextToken();
         stmt.setRslimit(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("SESSIONTIMEOUT")) {
         stmt.setSessiontimeout(true);
         this.lexer.nextToken();
         stmt.setSessiontimeoutValue(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("QUERYTIMEOUT")) {
         stmt.setQuerytimeout(true);
         this.lexer.nextToken();
         stmt.setQuerytimeoutValue(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("CONCURRENT")) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.SESSION) {
            this.lexer.nextToken();
            stmt.setConcurrentSessions(true);
         }

         stmt.setConcurrentSessionsValue(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("SECURITY")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("LABEL")) {
            this.lexer.nextToken();
            stmt.setSecurityLabel(true);
         }

         stmt.setConcurrentSessionsValue(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("AUDIT")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("CATEGORY")) {
            this.lexer.nextToken();
            stmt.setAuditCategory(true);
         }

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

      if (this.lexer.identifierEquals("COLLECT")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("HISTORY")) {
            this.lexer.nextToken();
            stmt.setCollectHistory(true);
         }

         stmt.setCollectHistoryType(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("ALLOW")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("CROSS")) {
            this.lexer.nextToken();
         }

         if (this.lexer.identifierEquals("JOIN")) {
            this.lexer.nextToken();
         }

         stmt.setAllowCrossJoin(true);
         stmt.setAllowCrossJoinType(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("ACCESS")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("TIME")) {
            this.lexer.nextToken();
            stmt.setAccessTime(true);
         }

         SQLListExpr listExpr = new SQLListExpr();
         if (this.lexer.token() != Token.ALL && this.lexer.token() != Token.DEFAULT) {
            this.lexer.nextToken();
            this.exprParser.exprList(listExpr.getItems(), listExpr);
            stmt.setAccessTimeList(listExpr);
            this.lexer.nextToken();
         } else {
            stmt.setAccessTimeValue(new SQLIdentifierExpr(this.lexer.token().name));
            this.lexer.nextToken();
         }
      }

      return stmt;
   }

   public DB2AlterRoleStatement parseAlterRole() {
      this.accept(Token.ALTER);
      this.accept(Token.ROLE);
      DB2AlterRoleStatement stmt = new DB2AlterRoleStatement();
      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 DB2AlterGroupStatement parseAlterGroup() {
      this.accept(Token.ALTER);
      this.accept(Token.GROUP);
      DB2AlterGroupStatement stmt = new DB2AlterGroupStatement();
      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 DB2AlterTableSpaceStatement parseAlterTablespace() {
      DB2AlterTableSpaceStatement stmt = new DB2AlterTableSpaceStatement();
      this.accept(Token.TABLESPACE);
      stmt.setTableSpaceName(new SQLIdentifierExpr(this.lexer.stringVal()));
      this.lexer.nextToken();

      do {
         if (this.lexer.identifierEquals("MANAGED")) {
            this.lexer.nextToken();
            this.accept(Token.BY);
            stmt.setManagedBy(true);
            if (this.lexer.token() == Token.DATABASE) {
               stmt.setManagedType(new SQLIdentifierExpr(this.lexer.token().name));
            } else {
               stmt.setManagedType(new SQLIdentifierExpr(this.lexer.stringVal()));
            }

            this.lexer.nextToken();
         }

         if (this.lexer.identifierEquals("EXTENTSIZE")) {
            stmt.setExtentsize(true);
            this.lexer.nextToken();
            stmt.setExtentsizeNum(this.exprParser.expr());
         }

         if (this.lexer.identifierEquals("BUFFERPOOL")) {
            stmt.setBufferpoo(true);
            this.lexer.nextToken();
            stmt.setBufferpoolName(this.exprParser.name());
         }

         if (this.lexer.identifierEquals("AUTORESIZE")) {
            stmt.setAutoresize(true);
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("YES")) {
               stmt.setYesOrNo(true);
            } else {
               stmt.setYesOrNo(false);
            }

            this.lexer.nextToken();
         }

         if (this.lexer.identifierEquals("MAXSIZE")) {
            stmt.setMaxsize(true);
            this.lexer.nextToken();
            stmt.setMaxsizeNum(this.exprParser.expr());
         }
      } while(this.lexer.token() != Token.EOF);

      return stmt;
   }

   public DB2AlterSessionStatement parseAlterSession() {
      this.accept(Token.SESSION);
      DB2AlterSessionStatement stmt = new DB2AlterSessionStatement();
      stmt.setSessionId(this.exprParser.expr());
      if (this.lexer.identifierEquals("ROLLBACK")) {
         stmt.setRollback(true);
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("TRANSACTION")) {
            stmt.setTransaction(true);
            this.lexer.nextToken();
            return stmt;
         }
      }

      if (this.lexer.token() == Token.SET) {
         stmt.setSet(true);
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("PRIORITY")) {
            this.lexer.nextToken();
            this.accept(Token.TO);
            stmt.setPriorityTo(true);
            stmt.setPriority(this.exprParser.name());
            return stmt;
         }
      }

      if (this.lexer.identifierEquals("ADD")) {
         stmt.setAdd(true);
         this.lexer.nextToken();
      }

      if (this.lexer.identifierEquals("REMOVE")) {
         stmt.setRemove(true);
         this.lexer.nextToken();
      }

      if (this.lexer.identifierEquals("TAG")) {
         stmt.setTag(true);
         this.lexer.nextToken();
         stmt.setTagValue(this.exprParser.name());
         return stmt;
      } else {
         return stmt;
      }
   }

   public DB2AlterSystemKillSessionStatement parseAlterSystemKillSession() {
      DB2AlterSystemKillSessionStatement stmt = new DB2AlterSystemKillSessionStatement();
      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 DB2AlterTableStatement parseAlterTable() {
      this.lexer.nextToken();
      DB2AlterTableStatement stmt = new DB2AlterTableStatement();
      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();
            DB2AlterTableModify DB2AlterTableModify = new DB2AlterTableModify();
            this.accept(Token.COLUMN);
            if (this.lexer.token() != Token.LPAREN) {
               SQLColumnDefinition columnDef = this.exprParser.parseColumn();
               DB2AlterTableModify.addColumn(columnDef);
            } else {
               this.lexer.nextToken();

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

                  this.lexer.nextToken();
               }
            }

            stmt.addItem(DB2AlterTableModify);
         }

         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.identifierEquals("PRIVILEGES")) {
                  this.lexer.nextToken();
                  this.accept(Token.TO);
                  stmt.setPrivileges(true);
                  stmt.setTableSource(this.exprParser.name());
                  return stmt;
               }

               if (this.lexer.token() == Token.SCHEMA) {
                  this.lexer.nextToken();
                  DB2AlterTableSetSchema item = new DB2AlterTableSetSchema();
                  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) {
                  DB2AlterTableSetTableSpace item = new DB2AlterTableSetTableSpace();
                  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")) {
                  DB2AlterTableValidateConstraint item = new DB2AlterTableValidateConstraint();
                  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();
                     DB2AlterTableCluster item = new DB2AlterTableCluster();
                     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) {
                        DB2AlterTableOf item = new DB2AlterTableOf();
                        this.lexer.nextToken();
                        item.setOf(true);
                        item.setTypeName(this.exprParser.expr());
                        stmt.addItem(item);
                     } else if (this.lexer.token() == Token.NOT) {
                        DB2AlterTableOf item = new DB2AlterTableOf();
                        this.lexer.nextToken();
                        item.setNotOf(true);
                        this.lexer.nextToken();
                        stmt.addItem(item);
                     } else if (this.lexer.identifierEquals("OWNER")) {
                        this.lexer.nextToken();
                        DB2AlterTableOf item = new DB2AlterTableOf();
                        item.setOwn(true);
                        this.accept(Token.TO);
                        item.setNewOwner(this.exprParser.expr());
                        stmt.addItem(item);
                     }
                  } else {
                     DB2AlterTableInheriteOrNotParentTable item = new DB2AlterTableInheriteOrNotParentTable();
                     item.setInherite(this.lexer.identifierEquals("INHERIT"));
                     this.lexer.nextToken();
                     if (!item.isInherite()) {
                        this.lexer.nextToken();
                     }

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

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

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

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

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

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

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

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

      return item;
   }

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

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

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

         this.lexer.nextToken();
      }

      item.setUsingIndex(idx);
      return item;
   }

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

      return item;
   }

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

      return item;
   }

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

      return item;
   }

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

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

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

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

         if (this.lexer.identifierEquals("CHARACTER")) {
            this.lexer.nextToken();
         }

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

         if (this.lexer.identifierEquals("LATIN9")) {
            this.lexer.nextToken();
         }

         if (this.lexer.identifierEquals("COLLATION")) {
            this.lexer.nextToken();
         }

         if (this.lexer.identifierEquals("BINARY")) {
            stmt.setWithAndSoOn(true);
            this.lexer.nextToken();
         }
      }

      if (this.lexer.identifierEquals("COLLECT")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("HISTORY")) {
            stmt.setCollectHistory(true);
            this.lexer.nextToken();
            stmt.setCollectHistoryType(new SQLIdentifierExpr(this.lexer.stringVal()));
            this.lexer.nextToken();
         }
      }

      if (this.lexer.identifierEquals("DATA_VERSION_RETENTION_TIME")) {
         stmt.setDataVersionRetentionTime(true);
         this.lexer.nextToken();
         stmt.setDataVersionRetentionTimeNum(new SQLIdentifierExpr(this.lexer.integerValue() + ""));
         this.lexer.nextToken();
      }

      return stmt;
   }

   public DB2CreateTableStatement parseCreateTable() {
      DB2CreateTableParser parser = new DB2CreateTableParser(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:
            DB2CreateIndexStatement 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:
            DB2CreateSeqenceStatement stmt2 = new DB2CreateSeqenceStatement();
            if (large) {
               stmt2.setLarge(true);
            }

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

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

            return DB2CreateSchemaStatement;
         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) {
               this.lexer.nextToken();
               this.accept(Token.REPLACE);
               if (this.lexer.identifierEquals(FnvHash.Constants.MATERIALIZED)) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateMaterializedView();
               } else {
                  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 createIndex2 = this.parseCreateIndex(true);
                     if (nonclustered) {
                        createIndex2.setType("NONCLUSTERED");
                     }

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

                  return createIndex3;
               }
            }
      }
   }

   public DB2GrantStatement parseGrant() throws ParserException {
      this.accept(Token.GRANT);
      DB2GrantStatement stmt = new DB2GrantStatement();
      this.parsePrivileages(stmt.getPrivileges(), stmt);
      if (this.lexer.token() == Token.ON) {
         stmt.setOn(true);
         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);
            DB2SchemaTables c = new DB2SchemaTables();
            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 {
            DB2SQLObjectCollection c = new DB2SQLObjectCollection();
            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);
         }
      } else {
         this.parseAdminPrivileages(stmt.getPrivileges(), stmt);
         this.accept(Token.IN);
      }

      if (this.lexer.token() == Token.IDENTIFIER) {
         String databaseName = this.lexer.stringVal();
         this.lexer.nextToken();
         this.lexer.nextToken();
         if (this.lexer.token() == Token.ALL) {
            stmt.setRoleName(new SQLIdentifierExpr(databaseName + ".ALL"));
            this.lexer.nextToken();
         } else {
            stmt.setRoleName(this.exprParser.expr());
         }
      } else if (this.lexer.token() == Token.ALL) {
         this.lexer.nextToken();
         this.lexer.nextToken();
         stmt.setRoleName(new SQLIdentifierExpr("ALL.ALL"));
         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);
         }
      }

      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 DB2RevokeStatement parseRevoke() throws ParserException {
      this.accept(Token.REVOKE);
      DB2RevokeStatement stmt = new DB2RevokeStatement();
      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) {
         stmt.setOn(true);
         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);
            DB2SchemaTables c = new DB2SchemaTables();
            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 {
            DB2SQLObjectCollection c = new DB2SQLObjectCollection();
            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);
         }
      } else {
         this.parseAdminPrivileages(stmt.getPrivileges(), stmt);
         this.accept(Token.IN);
      }

      if (this.lexer.token() == Token.IDENTIFIER) {
         String databaseName = this.lexer.stringVal();
         this.lexer.nextToken();
         this.lexer.nextToken();
         if (this.lexer.token() == Token.ALL) {
            stmt.setRoleName(new SQLIdentifierExpr(databaseName + ".ALL"));
            this.lexer.nextToken();
         } else {
            stmt.setRoleName(this.exprParser.name());
         }
      } else if (this.lexer.token() == Token.ALL) {
         this.lexer.nextToken();
         this.lexer.nextToken();
         stmt.setRoleName(new SQLIdentifierExpr("ALL.ALL"));
         this.lexer.nextToken();
      }

      if (this.lexer.token() == Token.FROM) {
         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();
            }
         }
      }

      return stmt;
   }

   protected void parseAdminPrivileages(List<SQLPrivilegeItem> privileges, SQLObject parent) {
      while(true) {
         String privilege = null;
         if (this.lexer.token() == Token.ALL) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("ADMIN")) {
               privilege = "ALL ADMIN";
               this.lexer.nextToken();
            }
         } else if (this.lexer.identifierEquals("BACKUP")) {
            privilege = "BACKUP";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.CREATE) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("AGGREGATE")) {
               privilege = "CREATE AGGREGATE";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.DATABASE) {
               privilege = "CREATE DATABASE";
               this.lexer.nextToken();
            } else if (this.lexer.identifierEquals("EXTERNAL")) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.TABLE) {
                  privilege = "CREATE EXTERNAL TABLE";
                  this.lexer.nextToken();
               }
            } else if (this.lexer.token() == Token.FUNCTION) {
               privilege = "CREATE FUNCTION";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.GROUP) {
               privilege = "CREATE GROUP";
               this.lexer.nextToken();
            } else if (this.lexer.identifierEquals("LIBRARY")) {
               privilege = "CREATE LIBRARY";
               this.lexer.nextToken();
            } else if (this.lexer.identifierEquals("MATERIALIZED")) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.VIEW) {
                  privilege = "CREATE MATERIALIZED VIEW";
                  this.lexer.nextToken();
               }
            } else if (this.lexer.token() == Token.PROCEDURE) {
               privilege = "CREATE PROCEDURE";
               this.lexer.nextToken();
            } else if (this.lexer.identifierEquals("SCHEDULER")) {
               this.lexer.nextToken();
               if (this.lexer.identifierEquals("RULE")) {
                  privilege = "CREATE SCHEDULER RULE";
                  this.lexer.nextToken();
               }
            } else if (this.lexer.token() == Token.SEQUENCE) {
               privilege = "CREATE SEQUENCE";
               this.lexer.nextToken();
            } else if (this.lexer.identifierEquals("SYNONYM")) {
               privilege = "CREATE SYNONYM";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.TABLE) {
               privilege = "CREATE TABLE";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.TEMP) {
               this.lexer.nextToken();
               if (this.lexer.token() == Token.TABLE) {
                  privilege = "CREATE TEMP TABLE";
                  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.identifierEquals("MANAGE")) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("HARDWARE")) {
               privilege = "MANAGE HARDWARE";
               this.lexer.nextToken();
            } else if (this.lexer.identifierEquals("SECURITY")) {
               privilege = "MANAGE SECURITY";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.SYSTEM) {
               privilege = "MANAGE SYSTEM";
               this.lexer.nextToken();
            }
         } else if (this.lexer.identifierEquals("RESTORE")) {
            privilege = "RESTORE";
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("HARDWARE")) {
            privilege = "HARDWARE";
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("SECURITY")) {
            privilege = "SECURITY";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.SYSTEM) {
            privilege = "SYSTEM";
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("AGGREGATE")) {
            privilege = "AGGREGATE";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.DATABASE) {
            privilege = "DATABASE";
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("EXTERNAL")) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.TABLE) {
               privilege = "EXTERNAL TABLE";
               this.lexer.nextToken();
            }
         } else if (this.lexer.token() == Token.FUNCTION) {
            privilege = "FUNCTION";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.GROUP) {
            privilege = "GROUP";
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("LIBRARY")) {
            privilege = "LIBRARY";
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("MATERIALIZED")) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.VIEW) {
               privilege = "MATERIALIZED VIEW";
               this.lexer.nextToken();
            }
         } else if (this.lexer.token() == Token.PROCEDURE) {
            privilege = "PROCEDURE";
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("SCHEDULER")) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("RULE")) {
               privilege = "SCHEDULER RULE";
               this.lexer.nextToken();
            }
         } else if (this.lexer.token() == Token.SEQUENCE) {
            privilege = "SEQUENCE";
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("SYNONYM")) {
            privilege = "SYNONYM";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.TABLE) {
            privilege = "TABLE";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.TEMP) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.TABLE) {
               privilege = "TEMP TABLE";
               this.lexer.nextToken();
            }
         } else if (this.lexer.token() == Token.USER) {
            privilege = "USER";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.VIEW) {
            privilege = "VIEW";
            this.lexer.nextToken();
         }

         if (privilege != null) {
            SQLExpr expr = new SQLIdentifierExpr(privilege);
            SQLPrivilegeItem privilegeItem = new SQLPrivilegeItem();
            privilegeItem.setAction(expr);
            expr.setParent(parent);
            privileges.add(privilegeItem);
         }

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

         this.lexer.nextToken();
      }
   }

   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.identifierEquals("LABEL")) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("ACCESS")) {
               privilege = "LABEL ACCESS";
               this.lexer.nextToken();
            }

            if (this.lexer.token() == Token.RESTRICT) {
               privilege = "LABEL RESTRICT";
               this.lexer.nextToken();
            }

            if (this.lexer.identifierEquals("EXPAND")) {
               privilege = "LABEL EXPAND";
               this.lexer.nextToken();
            }
         } else if (this.lexer.identifierEquals("ABORT")) {
            privilege = "ABORT";
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("LIST")) {
            privilege = "LIST";
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("UNFENCE")) {
            privilege = "UNFENCE";
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("GENSTATS")) {
            privilege = "GENSTATS";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.EXECUTE) {
            privilege = "EXECUTE";
            this.lexer.nextToken();
            if (this.lexer.token() == Token.AS) {
               privilege = "EXECUTE AS";
               this.lexer.nextToken();
            }
         } 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 DB2AlterViewStatement parseAlterView(boolean b) {
      DB2AlterViewStatement stmt = new DB2AlterViewStatement();
      stmt.setDbType(this.dbType);
      if (b) {
         stmt.setMaterialized(true);
      }

      if (this.lexer.token() == Token.VIEW) {
         this.accept(Token.VIEW);
         stmt.setView(true);
         SQLName viewName = this.exprParser.name();
         stmt.setViewName(viewName);
         if (this.lexer.identifierEquals("RENAME")) {
            stmt.setRename(true);
            this.lexer.nextToken();
            SQLName newName = this.exprParser.name();
            stmt.setNewViewName(newName);
         } 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) {
            stmt.setSet(true);
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("PRIVILEGES")) {
               this.lexer.nextToken();
               this.accept(Token.TO);
               stmt.setPrivilegesTo(true);
               stmt.setNewViewName(new SQLIdentifierExpr(this.lexer.stringVal()));
               this.lexer.nextToken();
            }
         }
      } else if (this.lexer.identifierEquals("VIEWS")) {
         this.lexer.nextToken();
         stmt.setViews(true);
         if (this.lexer.token() == Token.ON) {
            this.accept(Token.ON);
            stmt.setOn(true);
            stmt.setTableName(new SQLIdentifierExpr(this.lexer.stringVal()));
            this.lexer.nextToken();
         }
      }

      if (this.lexer.identifierEquals("MATERIALIZE")) {
         stmt.setMaterialize(true);
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("REFRESH")) {
            stmt.setRefresh(true);
            this.lexer.nextToken();
         }

         if (this.lexer.identifierEquals("SUSPEND")) {
            stmt.setSuspend(true);
            this.lexer.nextToken();
         }
      }

      return stmt;
   }

   public SQLStatement parseCreateSequenceDB2(DB2CreateSeqenceStatement 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.token() == Token.AS) {
            stmt.setAs(true);
            this.lexer.nextToken();
            stmt.setDataType(this.exprParser.name());
            i = 1;
         }

         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() {
      DB2CreateTableSpaceStatement stmt = new DB2CreateTableSpaceStatement();
      stmt.setDbType(this.dbType);
      this.accept(Token.CREATE);
      this.accept(Token.TABLESPACE);
      stmt.setTableSpaceName(this.exprParser.name());

      do {
         if (this.lexer.token() == Token.IN) {
            stmt.setIn(true);
            this.lexer.nextToken();
            stmt.setGroupName(this.exprParser.name());
         }

         if (this.lexer.identifierEquals("MANAGED")) {
            this.lexer.nextToken();
            this.accept(Token.BY);
            stmt.setManagedBy(true);
            if (this.lexer.token() == Token.DATABASE) {
               stmt.setManagedType(new SQLIdentifierExpr(this.lexer.token().name));
            } else {
               stmt.setManagedType(new SQLIdentifierExpr(this.lexer.stringVal()));
            }

            this.lexer.nextToken();
         }

         if (this.lexer.identifierEquals("EXTENTSIZE")) {
            stmt.setExtentsize(true);
            this.lexer.nextToken();
            stmt.setExtentsizeNum(this.exprParser.expr());
         }

         if (this.lexer.identifierEquals("BUFFERPOOL")) {
            stmt.setBufferpoo(true);
            this.lexer.nextToken();
            stmt.setBufferpoolName(this.exprParser.name());
         }

         if (this.lexer.identifierEquals("AUTORESIZE")) {
            stmt.setAutoresize(true);
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("YES")) {
               stmt.setYesOrNo(true);
            } else {
               stmt.setYesOrNo(false);
            }

            this.lexer.nextToken();
         }

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

         if (this.lexer.identifierEquals("OVERHEAD")) {
            stmt.setOverhead(true);
            this.lexer.nextToken();
            stmt.setOverheadNum(this.exprParser.expr());
         }

         if (this.lexer.identifierEquals("TRANSFERRATE")) {
            stmt.setTransferrate(true);
            this.lexer.nextToken();
            stmt.setTransferrateNum(this.exprParser.expr());
         }

         if (this.lexer.identifierEquals("PAGESIZE")) {
            stmt.setPagesize(true);
            this.lexer.nextToken();
            stmt.setPagesizeNum(this.exprParser.expr());
         }

         if (this.lexer.identifierEquals("SEGSIZE")) {
            stmt.setSegsize(true);
            this.lexer.nextToken();
            stmt.setSegsizeNum(this.exprParser.expr());
         }

         if (this.lexer.identifierEquals("FILE")) {
            stmt.setFile(true);
            this.lexer.nextToken();
            stmt.setFileSpecification(this.exprParser.name());
         }
      } while(this.lexer.token() != Token.EOF);

      return stmt;
   }

   public SQLCreateViewStatement parseCreateView() {
      DB2CreateViewStatement stmt = new DB2CreateViewStatement();
      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);
               DB2SelectStatement DB2SelectStatement = this.parseSelect();
               stmt.setSubQuery(DB2SelectStatement.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);
            DB2SelectStatement DB2SelectStatement = (DB2SelectStatement)sqlStatement;
            Boolean recursive = DB2SelectStatement.getSelect().getWithSubQuery().getRecursive();
            if (!recursive) {
               throw new ParserException("syntax error, not recursive" + this.lexer.info());
            }
         } else {
            DB2SelectStatement DB2SelectStatement = this.parseSelect();
            stmt.setSubQuery(DB2SelectStatement.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 DB2CreateMaterializedViewStatement parseCreateMaterializedView() {
      DB2CreateMaterializedViewStatement stmt = new DB2CreateMaterializedViewStatement();
      stmt.setDbType(this.dbType);
      this.accept(Token.CREATE);
      if (this.lexer.token() == Token.OR) {
         this.accept(Token.OR);
         this.accept(Token.REPLACE);
         stmt.setOrReplace(true);
      }

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

      while(true) {
         SQLName name = this.exprParser.name();
         stmt.addPartition(new SQLExprTableSource(name));
         if (this.lexer.token() != Token.COMMA) {
            if (this.lexer.token() == Token.IF) {
               this.lexer.nextToken();
               this.accept(Token.EXISTS);
               stmt.setIfExists(true);
            }

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

      if (this.lexer.identifierEquals("CONNECTION")) {
         return this.parseDropConnection();
      } else {
         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 parseDropConnection() {
      DB2DropConnectionStatement stmt = new DB2DropConnectionStatement();
      this.lexer.nextToken();
      stmt.setConnectionId(this.exprParser.expr());
      return stmt;
   }

   private SQLStatement parseDropTrigger() {
      this.lexer.nextToken();
      DB2DropTriggerStatement stmt = new DB2DropTriggerStatement();
      SQLName name = this.exprParser.name();
      stmt.setName(name);
      return stmt;
   }

   public DB2CreateUserStatement parseCreateUser() {
      this.accept(Token.CREATE);
      this.accept(Token.USER);
      DB2CreateUserStatement stmt = new DB2CreateUserStatement();
      stmt.setUser(this.exprParser.name());
      if (this.lexer.token() == Token.WITH) {
         stmt.setWith(true);
         this.lexer.nextToken();
      }

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

      if (this.lexer.identifierEquals("EXPIRE")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("PASSWORD")) {
            stmt.setExpirePassword(true);
            this.lexer.nextToken();
         }
      }

      if (this.lexer.identifierEquals("PASSWORDEXPIRY")) {
         stmt.setPasswordexpiry(true);
         this.lexer.nextToken();
         stmt.setPasswordexpiryDay(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("AUTH")) {
         stmt.setAuth(true);
         this.lexer.nextToken();
         stmt.setAuthType(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("SYSID")) {
         stmt.setSysid(true);
         this.lexer.nextToken();
         stmt.setSysidValue(this.exprParser.primary());
      }

      if (this.lexer.token() == Token.IN) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.GROUP) {
            stmt.setInGroup(true);
            this.lexer.nextToken();
         }

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

      if (this.lexer.token() == Token.IN) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("RESOURCEGROUP")) {
            stmt.setInResourcegroup(true);
            this.lexer.nextToken();
         }

         stmt.setInResourcegroupRsg(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("VALID")) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.UNTIL) {
            stmt.setValidUntil(true);
            this.lexer.nextToken();
         }

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

      if (this.lexer.identifierEquals("DEFPRIORITY")) {
         stmt.setDefpriority(true);
         this.lexer.nextToken();
         stmt.setDefpriorityType(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("MAXPRIORITY")) {
         stmt.setMaxpriority(true);
         this.lexer.nextToken();
         stmt.setMaxpriorityType(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("ROWSETLIMIT")) {
         stmt.setRowsetlimit(true);
         this.lexer.nextToken();
         stmt.setRslimit(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("SESSIONTIMEOUT")) {
         stmt.setSessiontimeout(true);
         this.lexer.nextToken();
         stmt.setSessiontimeoutValue(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("QUERYTIMEOUT")) {
         stmt.setQuerytimeout(true);
         this.lexer.nextToken();
         stmt.setQuerytimeoutValue(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("CONCURRENT")) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.SESSION) {
            this.lexer.nextToken();
            stmt.setConcurrentSessions(true);
         }

         stmt.setConcurrentSessionsValue(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("SECURITY")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("LABEL")) {
            this.lexer.nextToken();
            stmt.setSecurityLabel(true);
         }

         stmt.setConcurrentSessionsValue(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("AUDIT")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("CATEGORY")) {
            this.lexer.nextToken();
            stmt.setAuditCategory(true);
         }

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

      if (this.lexer.identifierEquals("COLLECT")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("HISTORY")) {
            this.lexer.nextToken();
            stmt.setCollectHistory(true);
         }

         stmt.setCollectHistoryType(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("ALLOW")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("CROSS")) {
            this.lexer.nextToken();
         }

         if (this.lexer.identifierEquals("JOIN")) {
            this.lexer.nextToken();
         }

         stmt.setAllowCrossJoin(true);
         stmt.setAllowCrossJoinType(this.exprParser.primary());
      }

      if (this.lexer.identifierEquals("ACCESS")) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals("TIME")) {
            this.lexer.nextToken();
            stmt.setAccessTime(true);
         }

         SQLListExpr listExpr = new SQLListExpr();
         if (this.lexer.token() != Token.ALL && this.lexer.token() != Token.DEFAULT) {
            this.lexer.nextToken();
            this.exprParser.exprList(listExpr.getItems(), listExpr);
            stmt.setAccessTimeList(listExpr);
            this.lexer.nextToken();
         } else {
            stmt.setAccessTimeValue(new SQLIdentifierExpr(this.lexer.token().name));
            this.lexer.nextToken();
         }
      }

      return stmt;
   }

   public DB2CreateGroupStatement parseCreateGroup() {
      this.accept(Token.CREATE);
      this.accept(Token.GROUP);
      DB2CreateGroupStatement stmt = new DB2CreateGroupStatement();
      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() {
      DB2CreateSynonymStatement stmt = new DB2CreateSynonymStatement();
      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() {
      DB2AlterSynonymStatement stmt = new DB2AlterSynonymStatement();
      this.accept(Token.ALTER);
      this.acceptIdentifier("SYNONYM");
      stmt.setName(new SQLIdentifierExpr(this.lexer.stringVal()));
      this.lexer.nextToken();
      if (this.lexer.identifierEquals("RENAME")) {
         stmt.setRename(true);
         this.lexer.nextToken();
      } else if (this.lexer.identifierEquals("OWNER")) {
         stmt.setOwner(true);
         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);
      DB2CreateRoleStatement stmt = new DB2CreateRoleStatement();
      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) {
      DB2CreateTriggerStatement stmt = new DB2CreateTriggerStatement(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(DB2CreateTriggerStatement.TriggerType.BEFORE);
         this.lexer.nextToken();
      } else if (this.lexer.identifierEquals(FnvHash.Constants.AFTER)) {
         stmt.setTriggerType(DB2CreateTriggerStatement.TriggerType.AFTER);
         this.lexer.nextToken();
      } else if (this.lexer.identifierEquals(FnvHash.Constants.INSTEAD)) {
         this.lexer.nextToken();
         this.accept(Token.OF);
         stmt.setTriggerType(DB2CreateTriggerStatement.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();
      }
   }
}
