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

import com.chenyang.druid.DbType;
import com.chenyang.druid.sql.ast.SQLExpr;
import com.chenyang.druid.sql.ast.SQLName;
import com.chenyang.druid.sql.ast.SQLStatement;
import com.chenyang.druid.sql.ast.expr.SQLCharExpr;
import com.chenyang.druid.sql.ast.expr.SQLIntegerExpr;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableAddColumn;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableAddConstraint;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableAddPartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableAlterColumn;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableArchivePartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableDeleteByCondition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableDisableConstraint;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableDisableKeys;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableDisableLifecycle;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableEnableConstraint;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableEnableKeys;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableEnableLifecycle;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableExchangePartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableMergePartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTablePartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTablePartitionSetProperties;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableRecoverPartitions;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableRenameColumn;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableRenamePartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableReplaceColumn;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableSetComment;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableSetLifecycle;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableSetLocation;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableSetOption;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableSubpartitionAvailablePartitionNum;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableTouch;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableUnarchivePartition;
import com.chenyang.druid.sql.ast.statement.SQLAlterViewRenameStatement;
import com.chenyang.druid.sql.ast.statement.SQLAssignItem;
import com.chenyang.druid.sql.ast.statement.SQLCheck;
import com.chenyang.druid.sql.ast.statement.SQLColumnDefinition;
import com.chenyang.druid.sql.ast.statement.SQLConstraint;
import com.chenyang.druid.sql.ast.statement.SQLPrimaryKey;
import com.chenyang.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.chenyang.druid.sql.ast.statement.SQLUnique;
import com.chenyang.druid.sql.dialect.hive.ast.HiveGrantPrinciple;
import com.chenyang.druid.sql.dialect.hive.ast.stmt.HiveAlterDatabaseStatement;
import com.chenyang.druid.sql.parser.Lexer;
import com.chenyang.druid.sql.parser.ParserException;
import com.chenyang.druid.sql.parser.SQLExprParser;
import com.chenyang.druid.sql.parser.SQLStatementParser;
import com.chenyang.druid.sql.parser.Token;
import com.chenyang.druid.util.FnvHash;

public class HiveAlterStatementParser extends SQLStatementParser {
   HiveAlterStatementParser(String sql) {
      super((SQLExprParser)(new HiveExprParser(sql)));
      this.dbType = DbType.hive;
   }

   public HiveAlterStatementParser(SQLExprParser exprParser) {
      super(exprParser);
      this.dbType = DbType.hive;
   }

   public HiveAlterStatementParser(Lexer lexer) {
      super((SQLExprParser)(new HiveExprParser(lexer)));
      this.dbType = DbType.hive;
   }

   public SQLStatement parseAlter() {
      Lexer.SavePoint mark = this.lexer.mark();
      this.accept(Token.ALTER);
      if (this.lexer.token() != Token.TABLE) {
         if (this.lexer.token() == Token.VIEW) {
            this.lexer.nextToken();
            SQLName viewName = this.exprParser.name();
            if (this.lexer.identifierEquals("RENAME")) {
               this.lexer.nextToken();
               this.accept(Token.TO);
               SQLAlterViewRenameStatement stmt = new SQLAlterViewRenameStatement();
               stmt.setName(viewName);
               SQLName newName = this.exprParser.name();
               stmt.setTo(newName);
               return stmt;
            } else {
               throw new ParserException("TODO " + this.lexer.info());
            }
         } else if (this.lexer.token() == Token.INDEX) {
            this.lexer.reset(mark);
            return this.parseAlterIndex();
         } else if (this.lexer.token() == Token.DATABASE) {
            this.lexer.reset(mark);
            return this.parseAlterDatabase();
         } else if (this.lexer.token() == Token.SCHEMA) {
            this.lexer.reset(mark);
            return this.parseAlterSchema();
         } else if (this.lexer.identifierEquals(FnvHash.Constants.RESOURCE)) {
            this.lexer.reset(mark);
            return this.parseAlterResourceGroup();
         } else {
            throw new ParserException("TODO " + this.lexer.info());
         }
      } else {
         this.lexer.nextToken();
         SQLAlterTableStatement stmt = new SQLAlterTableStatement(this.getDbType());
         if (this.lexer.token() == Token.IF) {
            this.lexer.nextToken();
            this.accept(Token.EXISTS);
            stmt.setIfExists(true);
         }

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

         while(true) {
            while(this.lexer.token() == Token.DROP) {
               this.parseAlterDrop(stmt);
            }

            if (!this.lexer.identifierEquals(FnvHash.Constants.ADD)) {
               if (this.lexer.token() != Token.DISABLE) {
                  if (this.lexer.token() != Token.ENABLE) {
                     if (this.lexer.token() != Token.ALTER) {
                        if (this.lexer.token() != Token.DELETE) {
                           if (!this.lexer.identifierEquals(FnvHash.Constants.CHANGE)) {
                              if (!this.lexer.identifierEquals(FnvHash.Constants.EXCHANGE)) {
                                 if (this.lexer.token() != Token.WITH) {
                                    if (!this.lexer.identifierEquals("RENAME")) {
                                       if (this.lexer.token() != Token.SET) {
                                          if (this.lexer.token() != Token.PARTITION) {
                                             if (!this.lexer.identifierEquals("TOUCH")) {
                                                if (!this.lexer.identifierEquals(FnvHash.Constants.ARCHIVE)) {
                                                   if (!this.lexer.identifierEquals(FnvHash.Constants.UNARCHIVE)) {
                                                      if (!this.lexer.identifierEquals(FnvHash.Constants.SUBPARTITION_AVAILABLE_PARTITION_NUM)) {
                                                         if (DbType.odps != this.dbType || !this.lexer.identifierEquals("MERGE")) {
                                                            if (DbType.odps != this.dbType || !this.lexer.identifierEquals(FnvHash.Constants.CLUSTERED)) {
                                                               if (DbType.odps != this.dbType || !this.lexer.identifierEquals(FnvHash.Constants.SORTED)) {
                                                                  if (stmt.getClusteredBy().size() <= 0 && stmt.getSortedBy().size() <= 0 || this.lexer.token() != Token.INTO) {
                                                                     if (this.lexer.token() != Token.REPLACE) {
                                                                        if (DbType.hive != this.dbType || !this.lexer.identifierEquals(FnvHash.Constants.RECOVER)) {
                                                                           return stmt;
                                                                        }

                                                                        this.lexer.nextToken();
                                                                        this.acceptIdentifier("PARTITIONS");
                                                                        stmt.addItem(new SQLAlterTableRecoverPartitions());
                                                                     } else {
                                                                        SQLAlterTableReplaceColumn item = this.parseAlterTableReplaceColumn();
                                                                        stmt.addItem(item);
                                                                     }
                                                                  } else {
                                                                     this.lexer.nextToken();
                                                                     if (this.lexer.token() != Token.LITERAL_INT) {
                                                                        throw new ParserException("into buckets must be integer. " + this.lexer.info());
                                                                     }

                                                                     int num = this.lexer.integerValue().intValue();
                                                                     this.lexer.nextToken();
                                                                     if (this.lexer.identifierEquals(FnvHash.Constants.BUCKETS)) {
                                                                        stmt.setBuckets(num);
                                                                        this.lexer.nextToken();
                                                                     } else {
                                                                        this.acceptIdentifier("SHARDS");
                                                                        stmt.setShards(num);
                                                                     }
                                                                  }
                                                               } else {
                                                                  this.lexer.nextToken();
                                                                  this.accept(Token.BY);
                                                                  this.accept(Token.LPAREN);

                                                                  while(true) {
                                                                     SQLSelectOrderByItem item = this.exprParser.parseSelectOrderByItem();
                                                                     stmt.addSortedByItem(item);
                                                                     if (this.lexer.token() != Token.COMMA) {
                                                                        this.accept(Token.RPAREN);
                                                                        break;
                                                                     }

                                                                     this.lexer.nextToken();
                                                                  }
                                                               }
                                                            } else {
                                                               this.lexer.nextToken();
                                                               this.accept(Token.BY);
                                                               this.accept(Token.LPAREN);

                                                               while(true) {
                                                                  SQLSelectOrderByItem item = this.exprParser.parseSelectOrderByItem();
                                                                  stmt.addClusteredByItem(item);
                                                                  if (this.lexer.token() != Token.COMMA) {
                                                                     this.accept(Token.RPAREN);
                                                                     break;
                                                                  }

                                                                  this.lexer.nextToken();
                                                               }
                                                            }
                                                         } else {
                                                            this.lexer.nextToken();
                                                            boolean ifExists = false;
                                                            if (this.lexer.token() == Token.IF) {
                                                               this.lexer.nextToken();
                                                               this.accept(Token.EXISTS);
                                                               ifExists = true;
                                                            }

                                                            if (this.lexer.token() != Token.PARTITION) {
                                                               this.acceptIdentifier("SMALLFILES");
                                                               stmt.setMergeSmallFiles(true);
                                                            } else {
                                                               SQLAlterTableMergePartition item = new SQLAlterTableMergePartition();

                                                               while(true) {
                                                                  item.addPartition(this.getExprParser().parsePartitionSpec());
                                                                  if (this.lexer.token() != Token.COMMA) {
                                                                     this.accept(Token.OVERWRITE);
                                                                     item.setOverwritePartition(this.getExprParser().parsePartitionSpec());
                                                                     if (ifExists) {
                                                                        item.setIfExists(true);
                                                                     }

                                                                     stmt.addItem(item);
                                                                     break;
                                                                  }

                                                                  this.lexer.nextToken();
                                                               }
                                                            }
                                                         }
                                                      } else {
                                                         this.lexer.nextToken();
                                                         this.accept(Token.EQ);
                                                         SQLIntegerExpr num = this.exprParser.integerExpr();
                                                         SQLAlterTableSubpartitionAvailablePartitionNum item = new SQLAlterTableSubpartitionAvailablePartitionNum();
                                                         item.setNumber(num);
                                                         stmt.addItem(item);
                                                      }
                                                   } else {
                                                      this.lexer.nextToken();
                                                      this.accept(Token.PARTITION);
                                                      SQLAlterTableUnarchivePartition item = new SQLAlterTableUnarchivePartition();
                                                      this.accept(Token.LPAREN);
                                                      this.parseAssignItems(item.getPartitions(), item, false);
                                                      this.accept(Token.RPAREN);
                                                      stmt.addItem(item);
                                                   }
                                                } else {
                                                   this.lexer.nextToken();
                                                   this.accept(Token.PARTITION);
                                                   SQLAlterTableArchivePartition item = new SQLAlterTableArchivePartition();
                                                   this.accept(Token.LPAREN);
                                                   this.parseAssignItems(item.getPartitions(), item, false);
                                                   this.accept(Token.RPAREN);
                                                   stmt.addItem(item);
                                                }
                                             } else {
                                                this.lexer.nextToken();
                                                SQLAlterTableTouch item = new SQLAlterTableTouch();
                                                if (this.lexer.token() == Token.PARTITION) {
                                                   this.lexer.nextToken();
                                                   this.accept(Token.LPAREN);
                                                   this.parseAssignItems(item.getPartition(), item);
                                                   this.accept(Token.RPAREN);
                                                }

                                                stmt.addItem(item);
                                             }
                                          } else {
                                             this.lexer.nextToken();
                                             SQLAlterTableRenamePartition renamePartition = new SQLAlterTableRenamePartition();
                                             this.accept(Token.LPAREN);
                                             this.parseAssignItems(renamePartition.getPartition(), renamePartition);
                                             this.accept(Token.RPAREN);
                                             if (this.lexer.token() == Token.ENABLE) {
                                                this.lexer.nextToken();
                                                if (this.lexer.identifierEquals("LIFECYCLE")) {
                                                   this.lexer.nextToken();
                                                }

                                                SQLAlterTableEnableLifecycle enableLifeCycle = new SQLAlterTableEnableLifecycle();

                                                for(SQLAssignItem condition : renamePartition.getPartition()) {
                                                   enableLifeCycle.getPartition().add(condition);
                                                   condition.setParent(enableLifeCycle);
                                                }

                                                stmt.addItem(enableLifeCycle);
                                             } else if (this.lexer.token() == Token.DISABLE) {
                                                this.lexer.nextToken();
                                                if (this.lexer.identifierEquals("LIFECYCLE")) {
                                                   this.lexer.nextToken();
                                                }

                                                SQLAlterTableDisableLifecycle disableLifeCycle = new SQLAlterTableDisableLifecycle();

                                                for(SQLAssignItem condition : renamePartition.getPartition()) {
                                                   disableLifeCycle.getPartition().add(condition);
                                                   condition.setParent(disableLifeCycle);
                                                }

                                                stmt.addItem(disableLifeCycle);
                                             } else {
                                                if (DbType.odps == this.dbType) {
                                                   if (this.lexer.identifierEquals("MERGE")) {
                                                      SQLAlterTablePartition alterTablePartition = new SQLAlterTablePartition();

                                                      for(SQLAssignItem condition : renamePartition.getPartition()) {
                                                         alterTablePartition.getPartition().add(condition);
                                                         condition.setParent(alterTablePartition);
                                                      }

                                                      stmt.addItem(alterTablePartition);
                                                      continue;
                                                   }

                                                   if (this.lexer.token() == Token.SET) {
                                                      SQLAlterTablePartitionSetProperties alterTablePartition = new SQLAlterTablePartitionSetProperties();

                                                      for(SQLAssignItem condition : renamePartition.getPartition()) {
                                                         alterTablePartition.getPartition().add(condition);
                                                         condition.setParent(alterTablePartition);
                                                      }

                                                      this.lexer.nextToken();
                                                      this.acceptIdentifier("PARTITIONPROPERTIES");
                                                      this.accept(Token.LPAREN);
                                                      this.parseAssignItems(alterTablePartition.getPartitionProperties(), alterTablePartition);
                                                      this.accept(Token.RPAREN);
                                                      stmt.addItem(alterTablePartition);
                                                      continue;
                                                   }
                                                }

                                                this.acceptIdentifier("RENAME");
                                                this.accept(Token.TO);
                                                this.accept(Token.PARTITION);
                                                this.accept(Token.LPAREN);
                                                this.parseAssignItems(renamePartition.getTo(), renamePartition);
                                                this.accept(Token.RPAREN);
                                                stmt.addItem(renamePartition);
                                             }
                                          }
                                       } else {
                                          this.lexer.nextToken();
                                          if (this.lexer.token() == Token.COMMENT) {
                                             this.lexer.nextToken();
                                             SQLAlterTableSetComment setComment = new SQLAlterTableSetComment();
                                             setComment.setComment(this.exprParser.primary());
                                             stmt.addItem(setComment);
                                          } else if (this.lexer.identifierEquals(FnvHash.Constants.LIFECYCLE)) {
                                             this.lexer.nextToken();
                                             SQLAlterTableSetLifecycle setLifecycle = new SQLAlterTableSetLifecycle();
                                             setLifecycle.setLifecycle(this.exprParser.primary());
                                             stmt.addItem(setLifecycle);
                                          } else if (this.lexer.identifierEquals(FnvHash.Constants.LOCATION)) {
                                             this.lexer.nextToken();
                                             SQLAlterTableSetLocation setLocation = new SQLAlterTableSetLocation();
                                             setLocation.setLocation(this.exprParser.primary());
                                             stmt.addItem(setLocation);
                                          } else {
                                             if (!this.lexer.identifierEquals(FnvHash.Constants.TBLPROPERTIES)) {
                                                throw new ParserException("TODO " + this.lexer.info());
                                             }

                                             this.lexer.nextToken();
                                             SQLAlterTableSetOption setOption = new SQLAlterTableSetOption();
                                             this.accept(Token.LPAREN);

                                             while(true) {
                                                SQLAssignItem item = this.exprParser.parseAssignItem();
                                                setOption.addOption(item);
                                                if (this.lexer.token() != Token.COMMA) {
                                                   this.accept(Token.RPAREN);
                                                   stmt.addItem(setOption);
                                                   break;
                                                }

                                                this.lexer.nextToken();
                                             }
                                          }
                                       }
                                    } else {
                                       stmt.addItem(this.parseAlterTableRename());
                                    }
                                 } else {
                                    this.lexer.nextToken();
                                    this.acceptIdentifier("NOCHECK");
                                    this.acceptIdentifier("ADD");
                                    SQLConstraint check = this.exprParser.parseConstaint();
                                    SQLAlterTableAddConstraint addCheck = new SQLAlterTableAddConstraint();
                                    addCheck.setWithNoCheck(true);
                                    addCheck.setConstraint(check);
                                    stmt.addItem(addCheck);
                                 }
                              } else {
                                 this.lexer.nextToken();
                                 this.accept(Token.PARTITION);
                                 SQLAlterTableExchangePartition item = new SQLAlterTableExchangePartition();
                                 this.accept(Token.LPAREN);

                                 while(true) {
                                    SQLExpr partition = this.exprParser.name();
                                    if (this.lexer.token() == Token.EQ) {
                                       this.lexer.nextToken();
                                       SQLExpr value = this.exprParser.primary();
                                       partition = new SQLAssignItem(partition, value);
                                    }

                                    item.addPartition(partition);
                                    if (this.lexer.token() != Token.COMMA) {
                                       this.accept(Token.RPAREN);
                                       this.accept(Token.WITH);
                                       this.accept(Token.TABLE);
                                       SQLName table = this.exprParser.name();
                                       item.setTable(table);
                                       if (this.lexer.token() == Token.WITH) {
                                          this.lexer.nextToken();
                                          this.acceptIdentifier("VALIDATION");
                                          item.setValidation(true);
                                       } else if (this.lexer.identifierEquals(FnvHash.Constants.WITHOUT)) {
                                          this.lexer.nextToken();
                                          this.acceptIdentifier("VALIDATION");
                                          item.setValidation(false);
                                       }

                                       stmt.addItem(item);
                                       break;
                                    }

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

                              SQLName columnName = this.exprParser.name();
                              if (this.lexer.identifierEquals("RENAME")) {
                                 this.lexer.nextToken();
                                 this.accept(Token.TO);
                                 SQLName toName = this.exprParser.name();
                                 SQLAlterTableRenameColumn renameColumn = new SQLAlterTableRenameColumn();
                                 renameColumn.setColumn(columnName);
                                 renameColumn.setTo(toName);
                                 stmt.addItem(renameColumn);
                              } else if (this.lexer.token() == Token.COMMENT) {
                                 this.lexer.nextToken();
                                 SQLExpr comment;
                                 if (this.lexer.token() == Token.LITERAL_ALIAS) {
                                    String alias = this.lexer.stringVal();
                                    if (alias.length() > 2 && alias.charAt(0) == '"' && alias.charAt(alias.length() - 1) == '"') {
                                       alias = alias.substring(1, alias.length() - 1);
                                    }

                                    comment = new SQLCharExpr(alias);
                                    this.lexer.nextToken();
                                 } else {
                                    comment = this.exprParser.primary();
                                 }

                                 SQLColumnDefinition column = new SQLColumnDefinition();
                                 column.setDbType(this.dbType);
                                 column.setName(columnName);
                                 column.setComment(comment);
                                 SQLAlterTableAlterColumn changeColumn = new SQLAlterTableAlterColumn();
                                 changeColumn.setColumn(column);
                                 stmt.addItem(changeColumn);
                              } else {
                                 SQLColumnDefinition column = this.exprParser.parseColumn();
                                 SQLAlterTableAlterColumn alterColumn = new SQLAlterTableAlterColumn();
                                 alterColumn.setColumn(column);
                                 alterColumn.setOriginColumn(columnName);
                                 if (this.lexer.identifierEquals(FnvHash.Constants.AFTER)) {
                                    this.lexer.nextToken();
                                    SQLName after = this.exprParser.name();
                                    alterColumn.setAfter(after);
                                 }

                                 stmt.addItem(alterColumn);
                              }
                           }
                        } else {
                           this.lexer.nextToken();
                           if (this.lexer.token() != Token.WHERE) {
                              throw new ParserException("TODO " + this.lexer.info());
                           }

                           this.lexer.nextToken();
                           SQLAlterTableDeleteByCondition alterColumn = new SQLAlterTableDeleteByCondition();
                           alterColumn.setWhere(this.exprParser.expr());
                           stmt.addItem(alterColumn);
                        }
                     } else {
                        this.lexer.nextToken();
                        if (this.lexer.token() == Token.COLUMN) {
                           SQLAlterTableAlterColumn alterColumn = this.parseAlterColumn();
                           stmt.addItem(alterColumn);
                           if (this.dbType == DbType.postgresql && this.lexer.token() == Token.COMMA) {
                              this.lexer.nextToken();
                           }
                        } else {
                           if (this.lexer.token() != Token.LITERAL_ALIAS) {
                              throw new ParserException("TODO " + this.lexer.info());
                           }

                           SQLAlterTableAlterColumn alterColumn = this.parseAlterColumn();
                           stmt.addItem(alterColumn);
                        }
                     }
                  } else {
                     this.lexer.nextToken();
                     if (this.lexer.token() == Token.CONSTRAINT) {
                        this.lexer.nextToken();
                        SQLAlterTableEnableConstraint item = new SQLAlterTableEnableConstraint();
                        item.setConstraintName(this.exprParser.name());
                        stmt.addItem(item);
                     } else if (this.lexer.identifierEquals("LIFECYCLE")) {
                        this.lexer.nextToken();
                        SQLAlterTableEnableLifecycle item = new SQLAlterTableEnableLifecycle();
                        stmt.addItem(item);
                     } else {
                        this.acceptIdentifier("KEYS");
                        SQLAlterTableEnableKeys item = new SQLAlterTableEnableKeys();
                        stmt.addItem(item);
                     }
                  }
               } else {
                  this.lexer.nextToken();
                  if (this.lexer.token() == Token.CONSTRAINT) {
                     this.lexer.nextToken();
                     SQLAlterTableDisableConstraint item = new SQLAlterTableDisableConstraint();
                     item.setConstraintName(this.exprParser.name());
                     stmt.addItem(item);
                  } else if (this.lexer.identifierEquals("LIFECYCLE")) {
                     this.lexer.nextToken();
                     SQLAlterTableDisableLifecycle item = new SQLAlterTableDisableLifecycle();
                     stmt.addItem(item);
                  } else {
                     this.acceptIdentifier("KEYS");
                     SQLAlterTableDisableKeys item = new SQLAlterTableDisableKeys();
                     stmt.addItem(item);
                  }
               }
            } else {
               this.lexer.nextToken();
               boolean ifNotExists = false;
               if (this.lexer.token() == Token.IF) {
                  this.lexer.nextToken();
                  this.accept(Token.NOT);
                  this.accept(Token.EXISTS);
                  ifNotExists = true;
               }

               if (this.lexer.token() == Token.PRIMARY) {
                  SQLPrimaryKey primaryKey = this.exprParser.parsePrimaryKey();
                  SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(primaryKey);
                  stmt.addItem(item);
               } else if (this.lexer.token() == Token.UNIQUE) {
                  SQLUnique unique = this.exprParser.parseUnique();
                  SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(unique);
                  stmt.addItem(item);
               } else if (this.lexer.token() == Token.IDENTIFIER) {
                  SQLAlterTableAddColumn item = this.parseAlterTableAddColumn();
                  stmt.addItem(item);
               } else if (this.lexer.token() == Token.LPAREN) {
                  if (this.dbType == DbType.h2) {
                     this.lexer.nextToken();
                     SQLAlterTableAddColumn item = this.parseAlterTableAddColumn();
                     stmt.addItem(item);
                     this.accept(Token.RPAREN);
                  }
               } else if (this.lexer.token() == Token.COLUMN) {
                  this.lexer.nextToken();
                  SQLAlterTableAddColumn item = this.parseAlterTableAddColumn();
                  stmt.addItem(item);
               } else if (this.lexer.token() == Token.CHECK) {
                  SQLCheck check = this.exprParser.parseCheck();
                  SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(check);
                  stmt.addItem(item);
               } else if (this.lexer.token() == Token.CONSTRAINT) {
                  SQLConstraint constraint = this.exprParser.parseConstaint();
                  SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(constraint);
                  stmt.addItem(item);
               } else if (this.lexer.token() == Token.FOREIGN) {
                  SQLConstraint constraint = this.exprParser.parseForeignKey();
                  SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(constraint);
                  stmt.addItem(item);
               } else if (this.lexer.token() == Token.PARTITION) {
                  while(true) {
                     this.lexer.nextToken();
                     SQLAlterTableAddPartition addPartition = new SQLAlterTableAddPartition();
                     addPartition.setIfNotExists(ifNotExists);
                     this.accept(Token.LPAREN);
                     this.parseAssignItems(addPartition.getPartitions(), addPartition, false);
                     this.accept(Token.RPAREN);
                     if (this.lexer.identifierEquals(FnvHash.Constants.LOCATION)) {
                        this.lexer.nextToken();
                        SQLExpr location = this.exprParser.primary();
                        addPartition.setLocation(location);
                     }

                     stmt.addItem(addPartition);
                     if (this.lexer.token() != Token.PARTITION) {
                        if (this.lexer.token() != Token.COMMA) {
                           break;
                        }

                        this.lexer.nextToken();
                        if (!this.lexer.identifierEquals("ADD") && this.lexer.token() != Token.PARTITION) {
                           break;
                        }
                     }
                  }
               } else {
                  if (this.lexer.token() != Token.DEFAULT) {
                     throw new ParserException("TODO " + this.lexer.info());
                  }

                  SQLConstraint constraint = this.exprParser.parseConstaint();
                  SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(constraint);
                  stmt.addItem(item);
               }
            }
         }
      }
   }

   protected SQLStatement parseAlterDatabase() {
      this.accept(Token.ALTER);
      if (this.lexer.token() == Token.SCHEMA) {
         this.lexer.nextToken();
      } else {
         this.accept(Token.DATABASE);
      }

      HiveAlterDatabaseStatement stmt = new HiveAlterDatabaseStatement();
      stmt.setName(this.exprParser.name());
      if (this.lexer.token() == Token.SET) {
         this.lexer.nextToken();
         if (this.lexer.identifierEquals(FnvHash.Constants.DBPROPERTIES)) {
            this.lexer.nextToken();
            this.exprParser.parseAssignItem(stmt.getProperties(), stmt);
         } else if (this.lexer.identifierEquals(FnvHash.Constants.OWNER)) {
            this.lexer.nextToken();
            this.exprParser.getDbType();
            SQLExpr user = this.parseUserPrinciple();
            stmt.user = user;
         } else if (this.lexer.identifierEquals(FnvHash.Constants.LOCATION)) {
            this.lexer.nextToken();
            stmt.location = this.exprParser.name();
         } else {
            if (!this.lexer.identifierEquals(FnvHash.Constants.MANAGEDLOCATION)) {
               throw new ParserException("TODO " + this.lexer.info());
            }

            this.lexer.nextToken();
            stmt.managedlocation = this.exprParser.name();
         }
      }

      return stmt;
   }

   protected SQLExpr parseUserPrinciple() {
      HiveGrantPrinciple owner = new HiveGrantPrinciple();
      if (this.lexer.token() != Token.USER && !this.lexer.identifierEquals("USER")) {
         if (this.lexer.identifierEquals("ROLE")) {
            owner.setRole(true);
            this.lexer.nextToken();
         } else {
            owner.setRole(true);
         }
      } else {
         owner.setUser(true);
         this.lexer.nextToken();
      }

      SQLExpr expr = this.exprParser.expr();
      owner.setExpr(expr);
      return owner;
   }

   protected SQLStatement parseAlterSchema() {
      return this.parseAlterDatabase();
   }
}
