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

import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLGrantStatement;
import com.alibaba.druid.sql.ast.statement.SQLObjectType;
import com.alibaba.druid.sql.ast.statement.SQLPrivilegeItem;
import com.alibaba.druid.sql.ast.statement.SQLRevokeStatement;
import com.alibaba.druid.sql.dialect.hive.ast.HiveGrantPrinciple;
import com.alibaba.druid.sql.parser.Lexer;
import com.alibaba.druid.sql.parser.ParserException;
import com.alibaba.druid.sql.parser.SQLExprParser;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.druid.sql.parser.Token;
import com.alibaba.druid.util.FnvHash;
import com.alibaba.druid.util.JdbcUtils;
import java.util.List;

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

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

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

   public SQLGrantStatement parseGrant() {
      this.accept(Token.GRANT);
      SQLGrantStatement stmt = new SQLGrantStatement(this.getDbType());
      this.parsePrivileages(stmt.getPrivileges(), stmt);
      if (this.lexer.token() == Token.ON) {
         this.lexer.nextToken();
         switch (this.lexer.token()) {
            case PROCEDURE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.PROCEDURE);
               break;
            case FUNCTION:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.FUNCTION);
               break;
            case TABLE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.TABLE);
               break;
            case USER:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.USER);
               break;
            case DATABASE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.DATABASE);
               break;
            case IDENTIFIER:
               if (this.lexer.identifierEquals("SYSTEM")) {
                  this.lexer.nextToken();
                  stmt.setResourceType(SQLObjectType.SYSTEM);
               } else if (this.lexer.identifierEquals("DIRECTORY")) {
                  this.lexer.nextToken();
                  stmt.setResourceType(SQLObjectType.DIRECTORY);
               }
         }

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

         SQLExpr expr;
         if (this.lexer.token() == Token.DOT) {
            expr = new SQLAllColumnExpr();
            this.lexer.nextToken();
         } else {
            expr = this.exprParser.expr();
         }

         if (stmt.getResourceType() != SQLObjectType.TABLE && stmt.getResourceType() != null) {
            stmt.setResource(expr);
         } else {
            stmt.setResource(new SQLExprTableSource(expr));
         }
      }

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

         while(true) {
            SQLExpr user = this.parseUserPrinciple();
            stmt.getUsers().add(user);
            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);
         }

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

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

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

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

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

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

      return stmt;
   }

   protected void parsePrivileages(List<SQLPrivilegeItem> privileges, SQLObject parent) {
      while(true) {
         String privilege = null;
         if (this.lexer.token() == Token.ALL) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("PRIVILEGES")) {
               privilege = "ALL PRIVILEGES";
               this.lexer.nextToken();
            } else {
               privilege = "ALL";
            }
         } else if (this.lexer.token() == Token.SELECT) {
            privilege = "SELECT";
            this.lexer.nextToken();
         } else if (this.lexer.identifierEquals("MSCK")) {
            privilege = "MSCK";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.EXPLAIN) {
            privilege = "EXPLAIN";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.UPDATE) {
            privilege = "UPDATE";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.DELETE) {
            privilege = "DELETE";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.INSERT) {
            privilege = "INSERT";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.INDEX) {
            this.lexer.nextToken();
            privilege = "INDEX";
         } else if (this.lexer.token() == Token.TRIGGER) {
            this.lexer.nextToken();
            privilege = "TRIGGER";
         } else if (this.lexer.token() == Token.REFERENCES) {
            privilege = "REFERENCES";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.DESC) {
            privilege = "DESCRIBE";
            this.lexer.nextToken();
         } else if (this.lexer.token() == Token.TRUNCATE) {
            privilege = "TRUNCATE TABLE";
            this.accept(Token.TRUNCATE);
            this.accept(Token.TABLE);
         } else if (this.lexer.token() == Token.ANALYZE) {
            privilege = "ANALYZE TABLE";
            this.accept(Token.ANALYZE);
            this.accept(Token.TABLE);
         } else if (this.lexer.token() == Token.ROLE) {
            privilege = "";

            while(true) {
               privilege = privilege + "role ";
               this.lexer.nextToken();
               SQLExpr name = this.exprParser.name();
               privilege = privilege + name;
               if (this.lexer.token() != Token.COMMA) {
                  break;
               }

               privilege = privilege + ",";
               this.lexer.nextToken();
            }
         } else if (this.lexer.token() == Token.CREATE) {
            this.lexer.nextToken();
            if (this.lexer.token() == Token.TABLE) {
               this.lexer.nextToken();
               privilege = "CREATE TABLE";
               if (this.lexer.token() == Token.AS) {
                  this.accept(Token.AS);
                  this.accept(Token.SELECT);
                  privilege = "CREATE TABLE as select";
               }
            } else if (this.lexer.token() == Token.DATABASE) {
               privilege = "CREATE DATABASE";
               this.lexer.nextToken();
            } else if (this.lexer.identifierEquals("MACRO")) {
               privilege = "CREATE MACRO";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.FUNCTION) {
               privilege = "CREATE FUNCTION";
               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.INDEX) {
               privilege = "CREATE INDEX";
               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();
               if (this.lexer.identifierEquals("LOCATION")) {
                  this.lexer.nextToken();
                  privilege = "ALTER TABLE LOCATION";
               } else if (this.lexer.identifierEquals("ADD")) {
                  this.lexer.nextToken();
                  this.lexer.nextToken();
                  privilege = "ALTER TABLE ADD PARTITION";
               } else if (this.lexer.identifierEquals("DROP ")) {
                  this.lexer.nextToken();
                  this.lexer.nextToken();
                  privilege = "ALTER TABLE DROP PARTITION";
               }
            } else if (this.lexer.token() == Token.INDEX) {
               this.lexer.nextToken();
               privilege = "ALTER INDEX ";
               if (this.lexer.identifierEquals("REBUILD")) {
                  this.lexer.nextToken();
                  privilege = "ALTER INDEX REBUILD";
               } else if (this.lexer.identifierEquals("PROPERTIES")) {
                  this.lexer.nextToken();
                  privilege = "ALTER INDEX PROPERTIES";
               }
            } else if (this.lexer.token() == Token.DATABASE) {
               privilege = "ALTER DATABASE";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.PARTITION) {
               privilege = "ALTER PARTITION LOCATION";
               this.lexer.nextToken();
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.VIEW) {
               privilege = "ALTER VIEW ";
               this.lexer.nextToken();
               if (this.lexer.identifierEquals("RENAME")) {
                  this.lexer.nextToken();
                  privilege = "ALTER VIEW RENAME";
               } else if (this.lexer.identifierEquals("PROPERTIES")) {
                  this.lexer.nextToken();
                  privilege = "ALTER VIEW PROPERTIES";
               }
            } 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.identifierEquals("MACRO")) {
               privilege = "DROP MACRO";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.INDEX) {
               privilege = "DROP INDEX";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.DATABASE) {
               privilege = "DROP DATABASE";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.FUNCTION) {
               privilege = "DROP FUNCTION";
               this.lexer.nextToken();
            } else if (this.lexer.token() == Token.VIEW) {
               this.lexer.nextToken();
               privilege = "DROP VIEW";
               if (this.lexer.identifierEquals("PROPERTIES")) {
                  privilege = "DROP VIEW PROPERTIES";
                  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 COLUMNS";
            } else if (this.lexer.identifierEquals("PARTITIONS")) {
               this.acceptIdentifier("PARTITIONS");
               privilege = "SHOW PARTITIONS";
            } else if (this.lexer.identifierEquals("COLUMNS")) {
               this.acceptIdentifier("COLUMNS");
               privilege = "SHOW COLUMNS";
            } else if (this.lexer.token() == Token.TABLE) {
               this.accept(Token.TABLE);
               if (this.lexer.identifierEquals("STATUS")) {
                  this.acceptIdentifier("STATUS");
                  privilege = "SHOW TABLE STATUS";
               } else if (this.lexer.identifierEquals("PROPERTIES")) {
                  this.acceptIdentifier("PROPERTIES");
                  privilege = "SHOW TABLE PROPERTIES";
               } else {
                  privilege = "SHOW TABLE";
               }
            } else if (this.lexer.token() == Token.CREATE) {
               this.accept(Token.CREATE);
               this.accept(Token.TABLE);
               privilege = "SHOW CREATE TABLE";
            } 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 {
               privilege = "LOAD";
            }
         } 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();
      }
   }

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

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

   public SQLRevokeStatement parseRevoke() {
      this.accept(Token.REVOKE);
      SQLRevokeStatement stmt = new SQLRevokeStatement(this.dbType);
      if (this.lexer.token() == Token.GRANT) {
         this.lexer.nextToken();
         this.acceptIdentifier("OPTION");
         stmt.setGrantOption(true);
         if (this.lexer.token() == Token.FOR) {
            this.lexer.nextToken();
         }
      }

      this.parsePrivileages(stmt.getPrivileges(), stmt);
      if (this.lexer.token() == Token.ON) {
         this.lexer.nextToken();
         switch (this.lexer.token()) {
            case PROCEDURE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.PROCEDURE);
               break;
            case FUNCTION:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.FUNCTION);
               break;
            case TABLE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.TABLE);
               break;
            case USER:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.USER);
               break;
            case DATABASE:
               this.lexer.nextToken();
               stmt.setResourceType(SQLObjectType.DATABASE);
               break;
            case IDENTIFIER:
               if (this.lexer.identifierEquals("SYSTEM")) {
                  this.lexer.nextToken();
                  stmt.setResourceType(SQLObjectType.SYSTEM);
               } else if (this.lexer.identifierEquals("DIRECTORY")) {
                  this.lexer.nextToken();
                  stmt.setResourceType(SQLObjectType.DIRECTORY);
               }
         }

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

         SQLExpr expr;
         if (this.lexer.token() == Token.DOT) {
            expr = new SQLAllColumnExpr();
            this.lexer.nextToken();
         } else {
            expr = this.exprParser.expr();
         }

         if (stmt.getResourceType() != SQLObjectType.TABLE && stmt.getResourceType() != null) {
            stmt.setResource(expr);
         } else {
            stmt.setResource(new SQLExprTableSource(expr));
         }
      }

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

         while(true) {
            SQLExpr user = this.parseUserPrinciple();
            stmt.getUsers().add(user);
            if (this.lexer.token() != Token.COMMA) {
               break;
            }

            this.lexer.nextToken();
         }
      }

      if (this.lexer.identifierEquals("CASCADE") && JdbcUtils.isDmDbType(this.dbType)) {
         stmt.setCascade(true);
         this.lexer.nextToken();
      }

      if (this.lexer.identifierEquals("RESTRICT") && JdbcUtils.isDmDbType(this.dbType)) {
         stmt.setRestrict(true);
         this.lexer.nextToken();
      }

      return stmt;
   }
}
