package com.chenyang.druid.sql.repository;

import com.chenyang.druid.DbType;
import com.chenyang.druid.sql.SQLUtils;
import com.chenyang.druid.sql.ast.SQLDataType;
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.SQLAllColumnExpr;
import com.chenyang.druid.sql.ast.expr.SQLIdentifierExpr;
import com.chenyang.druid.sql.ast.expr.SQLIntegerExpr;
import com.chenyang.druid.sql.ast.expr.SQLPropertyExpr;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLColumnConstraint;
import com.chenyang.druid.sql.ast.statement.SQLColumnDefinition;
import com.chenyang.druid.sql.ast.statement.SQLCreateFunctionStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateIndexStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateSequenceStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropIndexStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropSequenceStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLExprTableSource;
import com.chenyang.druid.sql.ast.statement.SQLSelect;
import com.chenyang.druid.sql.ast.statement.SQLSelectItem;
import com.chenyang.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.chenyang.druid.sql.ast.statement.SQLSelectStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowColumnsStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowCreateTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLShowTablesStatement;
import com.chenyang.druid.sql.ast.statement.SQLTableSource;
import com.chenyang.druid.sql.ast.statement.SQLUseStatement;
import com.chenyang.druid.sql.dialect.oracle.ast.stmt.OracleCreateTableStatement;
import com.chenyang.druid.sql.dialect.oracle.visitor.OracleASTVisitorAdapter;
import com.chenyang.druid.sql.repository.function.Function;
import com.chenyang.druid.sql.visitor.SQLASTVisitor;
import com.chenyang.druid.sql.visitor.SQLASTVisitorAdapter;
import com.chenyang.druid.support.logging.Log;
import com.chenyang.druid.support.logging.LogFactory;
import com.chenyang.druid.util.FnvHash;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class SchemaRepository {
   private static Log LOG = LogFactory.getLog(SchemaRepository.class);
   private Schema defaultSchema;
   protected DbType dbType;
   protected DbType schemaDbType;
   protected SQLASTVisitor consoleVisitor;
   protected Map<String, Schema> schemas;
   protected final Map<Long, Function> internalFunctions;
   protected SchemaLoader schemaLoader;

   public SchemaRepository() {
      this.schemas = new LinkedHashMap();
      this.internalFunctions = new ConcurrentHashMap(16, 0.75F, 1);
   }

   public SchemaRepository(DbType dbType) {
      this(dbType, dbType);
   }

   public SchemaRepository(DbType dbType, DbType schemaDbType) {
      this.schemas = new LinkedHashMap();
      this.internalFunctions = new ConcurrentHashMap(16, 0.75F, 1);
      if (dbType == null) {
         dbType = DbType.other;
      }

      if (schemaDbType == null) {
         schemaDbType = dbType;
      }

      this.dbType = dbType;
      this.schemaDbType = schemaDbType;
      switch (dbType) {
         case oracle:
            this.consoleVisitor = new OracleConsoleSchemaVisitor();
            break;
         default:
            this.consoleVisitor = new DefaultConsoleSchemaVisitor();
      }

   }

   public DbType getDbType() {
      return this.dbType;
   }

   public String getDefaultSchemaName() {
      return this.getDefaultSchema().getName();
   }

   public void setDefaultSchema(String name) {
      if (name == null) {
         this.defaultSchema = null;
      } else {
         String normalizedName = SQLUtils.normalize(name).toLowerCase();
         Schema defaultSchema = (Schema)this.schemas.get(normalizedName);
         if (defaultSchema != null) {
            this.defaultSchema = defaultSchema;
         } else if (this.defaultSchema != null && this.defaultSchema.getName() == null) {
            this.defaultSchema.setName(name);
            this.schemas.put(normalizedName, this.defaultSchema);
         } else {
            defaultSchema = new Schema(this);
            defaultSchema.setName(name);
            this.schemas.put(normalizedName, defaultSchema);
            this.defaultSchema = defaultSchema;
         }
      }
   }

   public Schema findSchema(String schema) {
      return this.findSchema(schema, false);
   }

   protected Schema findSchema(String name, boolean create) {
      if (name != null && name.length() != 0) {
         name = SQLUtils.normalize(name);
         String normalizedName = name.toLowerCase();
         if (this.getDefaultSchema() != null && this.defaultSchema.getName() == null && create) {
            this.defaultSchema.setName(name);
            this.schemas.put(normalizedName, this.defaultSchema);
            return this.defaultSchema;
         } else {
            Schema schema = (Schema)this.schemas.get(normalizedName);
            if (schema == null && create) {
               int p = name.indexOf(46);
               String catalog = null;
               if (p != -1) {
                  catalog = name.substring(0, p);
               }

               schema = new Schema(this, catalog, name);
               this.schemas.put(normalizedName, schema);
            }

            return schema;
         }
      } else {
         return this.getDefaultSchema();
      }
   }

   public Schema getDefaultSchema() {
      if (this.defaultSchema == null) {
         this.defaultSchema = new Schema(this);
      }

      return this.defaultSchema;
   }

   public void setDefaultSchema(Schema schema) {
      this.defaultSchema = schema;
   }

   public SchemaObject findTable(String tableName) {
      if (tableName.indexOf(46) != -1) {
         SQLExpr expr = SQLUtils.toSQLExpr(tableName, this.dbType);
         if (!(expr instanceof SQLIdentifierExpr)) {
            return this.findTable((SQLName)expr);
         }
      }

      SchemaObject object = this.getDefaultSchema().findTable(tableName);
      if (object != null) {
         return object;
      } else {
         String ddl = this.loadDDL(tableName);
         if (ddl == null) {
            return null;
         } else {
            DbType schemaDbType = this.schemaDbType;
            if (schemaDbType == null) {
               schemaDbType = this.dbType;
            }

            SchemaObject schemaObject = this.acceptDDL(ddl, schemaDbType);
            return schemaObject != null ? schemaObject : this.getDefaultSchema().findTable(tableName);
         }
      }
   }

   public SchemaObject findView(String viewName) {
      SchemaObject object = this.getDefaultSchema().findView(viewName);
      if (object != null) {
         return object;
      } else {
         String ddl = this.loadDDL(viewName);
         if (ddl == null) {
            return null;
         } else {
            this.acceptDDL(ddl);
            return this.getDefaultSchema().findView(viewName);
         }
      }
   }

   public SchemaObject findTable(long tableNameHash) {
      return this.getDefaultSchema().findTable(tableNameHash);
   }

   public SchemaObject findTableOrView(String tableName) {
      return this.findTableOrView(tableName, true);
   }

   public SchemaObject findTableOrView(String tableName, boolean onlyCurrent) {
      Schema schema = this.getDefaultSchema();
      SchemaObject object = schema.findTableOrView(tableName);
      if (object != null) {
         return object;
      } else {
         for(Schema s : this.schemas.values()) {
            if (s != schema) {
               object = schema.findTableOrView(tableName);
               if (object != null) {
                  return object;
               }
            }
         }

         String ddl = this.loadDDL(tableName);
         if (ddl == null) {
            return null;
         } else {
            this.acceptDDL(ddl);
            object = schema.findTableOrView(tableName);
            if (object != null) {
               return object;
            } else {
               for(Schema s : this.schemas.values()) {
                  if (s != schema) {
                     object = schema.findTableOrView(tableName);
                     if (object != null) {
                        return object;
                     }
                  }
               }

               return null;
            }
         }
      }
   }

   public Collection<Schema> getSchemas() {
      return this.schemas.values();
   }

   public SchemaObject findFunction(String functionName) {
      return this.getDefaultSchema().findFunction(functionName);
   }

   public void acceptDDL(String ddl) {
      this.acceptDDL(ddl, this.schemaDbType);
   }

   public SchemaObject acceptDDL(String ddl, DbType dbType) {
      List<SQLStatement> stmtList = SQLUtils.parseStatements(ddl, dbType);

      for(SQLStatement stmt : stmtList) {
         if (stmt instanceof SQLCreateTableStatement) {
            SchemaObject schemaObject = this.acceptCreateTable((SQLCreateTableStatement)stmt);
            if (stmtList.size() == 1) {
               return schemaObject;
            }
         } else {
            this.accept(stmt);
         }
      }

      return null;
   }

   public void accept(SQLStatement stmt) {
      stmt.accept(this.consoleVisitor);
   }

   public boolean isSequence(String name) {
      return this.getDefaultSchema().isSequence(name);
   }

   public SchemaObject findTable(SQLTableSource tableSource, String alias) {
      return this.getDefaultSchema().findTable(tableSource, alias);
   }

   public SQLColumnDefinition findColumn(SQLTableSource tableSource, SQLSelectItem selectItem) {
      return this.getDefaultSchema().findColumn(tableSource, selectItem);
   }

   public SQLColumnDefinition findColumn(SQLTableSource tableSource, SQLExpr expr) {
      return this.getDefaultSchema().findColumn(tableSource, expr);
   }

   public SchemaObject findTable(SQLTableSource tableSource, SQLSelectItem selectItem) {
      return this.getDefaultSchema().findTable(tableSource, selectItem);
   }

   public SchemaObject findTable(SQLTableSource tableSource, SQLExpr expr) {
      return this.getDefaultSchema().findTable(tableSource, expr);
   }

   public Map<String, SchemaObject> getTables(SQLTableSource x) {
      return this.getDefaultSchema().getTables(x);
   }

   public int getTableCount() {
      return this.getDefaultSchema().getTableCount();
   }

   public Collection<SchemaObject> getObjects() {
      return this.getDefaultSchema().getObjects();
   }

   public int getViewCount() {
      return this.getDefaultSchema().getViewCount();
   }

   public void resolve(SQLSelectStatement stmt, SchemaResolveVisitor.Option... options) {
      if (stmt != null) {
         SchemaResolveVisitor resolveVisitor = this.createResolveVisitor(options);
         resolveVisitor.visit(stmt);
      }
   }

   public void resolve(SQLSelectQueryBlock queryBlock, SchemaResolveVisitor.Option... options) {
      if (queryBlock != null) {
         SchemaResolveVisitor resolveVisitor = this.createResolveVisitor(options);
         resolveVisitor.visit(queryBlock);
      }
   }

   public void resolve(SQLStatement stmt, SchemaResolveVisitor.Option... options) {
      if (stmt != null) {
         SchemaResolveVisitor resolveVisitor = this.createResolveVisitor(options);
         if (stmt instanceof SQLSelectStatement) {
            resolveVisitor.visit((SQLSelectStatement)stmt);
         } else {
            stmt.accept(resolveVisitor);
         }

      }
   }

   private SchemaResolveVisitor createResolveVisitor(SchemaResolveVisitor.Option... options) {
      int optionsValue = SchemaResolveVisitor.Option.of(options);
      SchemaResolveVisitor resolveVisitor;
      switch (this.dbType) {
         case oracle:
            resolveVisitor = new SchemaResolveVisitorFactory.OracleResolveVisitor(this, optionsValue);
            break;
         case mysql:
         case mariadb:
         case sqlite:
            resolveVisitor = new SchemaResolveVisitorFactory.MySqlResolveVisitor(this, optionsValue);
            break;
         case sqlserver:
            resolveVisitor = new SchemaResolveVisitorFactory.SQLServerResolveVisitor(this, optionsValue);
            break;
         case greenplum:
            resolveVisitor = new SchemaResolveVisitorFactory.GPResolveVisitor(this, optionsValue);
            break;
         case kingbase:
            resolveVisitor = new SchemaResolveVisitorFactory.KingbaseResolveVisitor(this, optionsValue);
            break;
         default:
            resolveVisitor = new SchemaResolveVisitorFactory.SQLResolveVisitor(this, optionsValue);
      }

      return resolveVisitor;
   }

   public String resolve(String input) {
      SchemaResolveVisitor visitor = this.createResolveVisitor(SchemaResolveVisitor.Option.ResolveAllColumn, SchemaResolveVisitor.Option.ResolveIdentifierAlias);
      List<SQLStatement> stmtList = SQLUtils.parseStatements(input, this.dbType);

      for(SQLStatement stmt : stmtList) {
         stmt.accept(visitor);
      }

      return SQLUtils.toSQLString(stmtList, this.dbType);
   }

   public String console(String input) {
      StringBuffer buf = new StringBuffer();

      for(SQLStatement stmt : SQLUtils.parseStatements(input, this.dbType)) {
         if (stmt instanceof SQLShowColumnsStatement) {
            SQLShowColumnsStatement showColumns = (SQLShowColumnsStatement)stmt;
            SQLName db = showColumns.getDatabase();
            Schema schema;
            if (db == null) {
               schema = this.getDefaultSchema();
            } else {
               schema = this.findSchema(db.getSimpleName());
            }

            SQLName table = null;
            SchemaObject schemaObject = null;
            if (schema != null) {
               table = showColumns.getTable();
               schemaObject = schema.findTable(table.nameHashCode64());
            }

            if (schemaObject == null) {
               buf.append("ERROR 1146 (42S02): Table '" + table + "' doesn't exist\n");
            }
         } else if (stmt instanceof SQLShowCreateTableStatement) {
            SQLShowCreateTableStatement showCreateTableStmt = (SQLShowCreateTableStatement)stmt;
            SQLName table = showCreateTableStmt.getName();
            SchemaObject schemaObject = this.findTable(table);
            if (schemaObject == null) {
               buf.append("ERROR 1146 (42S02): Table '" + table + "' doesn't exist\n");
            }
         } else if (stmt instanceof SQLShowTablesStatement) {
            SQLShowTablesStatement showTables = (SQLShowTablesStatement)stmt;
            SQLName database = showTables.getDatabase();
            Schema schema;
            if (database == null) {
               schema = this.getDefaultSchema();
            } else {
               schema = this.findSchema(database.getSimpleName());
            }

            if (schema != null) {
               for(String table : schema.showTables()) {
                  buf.append(table);
                  buf.append('\n');
               }
            }
         } else {
            stmt.accept(this.consoleVisitor);
         }
      }

      if (buf.length() == 0) {
         return "\n";
      } else {
         return buf.toString();
      }
   }

   public SchemaObject findTable(SQLName name) {
      if (name instanceof SQLIdentifierExpr) {
         return this.findTable(((SQLIdentifierExpr)name).getName());
      } else if (name instanceof SQLPropertyExpr) {
         SQLPropertyExpr propertyExpr = (SQLPropertyExpr)name;
         SQLExpr owner = propertyExpr.getOwner();
         String catalog = null;
         String schema;
         if (owner instanceof SQLIdentifierExpr) {
            schema = ((SQLIdentifierExpr)owner).getName();
         } else {
            if (!(owner instanceof SQLPropertyExpr)) {
               return null;
            }

            schema = ((SQLPropertyExpr)owner).getName();
            catalog = ((SQLPropertyExpr)owner).getOwnernName();
         }

         long tableHashCode64 = propertyExpr.nameHashCode64();
         Schema schemaObj = this.findSchema(schema, false);
         if (schemaObj != null) {
            SchemaObject table = schemaObj.findTable(tableHashCode64);
            if (table != null) {
               return table;
            }
         }

         String ddl = this.loadDDL(catalog, schema, propertyExpr.getName());
         if (ddl == null) {
            schemaObj = this.findSchema(schema, true);
         } else {
            List<SQLStatement> stmtList = SQLUtils.parseStatements(ddl, this.schemaDbType);

            for(SQLStatement stmt : stmtList) {
               this.accept(stmt);
            }

            if (stmtList.size() == 1) {
               SQLStatement stmt = (SQLStatement)stmtList.get(0);
               if (stmt instanceof SQLCreateTableStatement) {
                  SQLCreateTableStatement createStmt = (SQLCreateTableStatement)stmt;
                  String schemaName = createStmt.getSchema();
                  schemaObj = this.findSchema(schemaName, true);
               }
            }
         }

         return schemaObj == null ? null : schemaObj.findTable(tableHashCode64);
      } else {
         return null;
      }
   }

   private boolean renameTable(SQLName name, SQLName to) {
      Schema schema;
      if (name instanceof SQLPropertyExpr) {
         String schemaName = ((SQLPropertyExpr)name).getOwnernName();
         schema = this.findSchema(schemaName);
      } else {
         schema = this.getDefaultSchema();
      }

      if (schema == null) {
         return false;
      } else {
         long nameHashCode64 = name.nameHashCode64();
         SchemaObject schemaObject = schema.findTable(nameHashCode64);
         if (schemaObject != null) {
            schema.objects.remove(nameHashCode64);
         }

         return true;
      }
   }

   public SchemaObject findTable(SQLExprTableSource x) {
      if (x == null) {
         return null;
      } else {
         SQLExpr expr = x.getExpr();
         return expr instanceof SQLName ? this.findTable((SQLName)expr) : null;
      }
   }

   SchemaObject acceptCreateTable(SQLCreateTableStatement x) {
      SQLCreateTableStatement x1 = x.clone();
      String schemaName = x1.getSchema();
      Schema schema = this.findSchema(schemaName, true);
      SQLSelect select = x1.getSelect();
      if (select != null) {
         select.accept(this.createResolveVisitor(SchemaResolveVisitor.Option.ResolveAllColumn));
         SQLSelectQueryBlock queryBlock = select.getFirstQueryBlock();
         this.resolve(queryBlock);
         if (queryBlock != null) {
            for(SQLSelectItem selectItem : queryBlock.getSelectList()) {
               SQLExpr selectItemExpr = selectItem.getExpr();
               if (!(selectItemExpr instanceof SQLAllColumnExpr) && (!(selectItemExpr instanceof SQLPropertyExpr) || !((SQLPropertyExpr)selectItemExpr).getName().equals("*"))) {
                  SQLColumnDefinition column = null;
                  if (selectItemExpr instanceof SQLName) {
                     SQLColumnDefinition resolvedColumn = ((SQLName)selectItemExpr).getResolvedColumn();
                     if (resolvedColumn != null) {
                        column = new SQLColumnDefinition();
                        column.setDataType(selectItem.computeDataType());
                        if (DbType.mysql == this.dbType) {
                           if (resolvedColumn.getDefaultExpr() != null) {
                              column.setDefaultExpr(resolvedColumn.getDefaultExpr().clone());
                           }

                           if (resolvedColumn.getConstraints().size() > 0) {
                              for(SQLColumnConstraint constraint : resolvedColumn.getConstraints()) {
                                 column.addConstraint(constraint.clone());
                              }
                           }

                           if (resolvedColumn.getComment() != null) {
                              column.setComment(resolvedColumn.getComment());
                           }
                        }
                     }
                  }

                  if (column == null) {
                     column = new SQLColumnDefinition();
                     column.setDataType(selectItem.computeDataType());
                  }

                  String name = selectItem.computeAlias();
                  column.setName(name);
                  column.setDbType(this.dbType);
                  x1.addColumn(column);
               }
            }

            if (x1.getTableElementList().size() > 0) {
               x1.setSelect((SQLSelect)null);
            }
         }
      }

      SQLExprTableSource like = x1.getLike();
      if (like != null) {
         SchemaObject tableObject = null;
         SQLName name = like.getName();
         if (name != null) {
            tableObject = this.findTable(name);
         }

         SQLCreateTableStatement tableStmt = null;
         if (tableObject != null) {
            SQLStatement stmt = tableObject.getStatement();
            if (stmt instanceof SQLCreateTableStatement) {
               tableStmt = (SQLCreateTableStatement)stmt;
            }
         }

         if (tableStmt != null) {
            SQLName tableName = x1.getName();
            tableStmt.cloneTo(x1);
            x1.setName(tableName);
            x1.setLike((SQLExprTableSource)null);
         }
      }

      x1.setSchema(null);
      String name = x1.computeName();
      SchemaObject table = schema.findTableOrView(name);
      if (table != null) {
         if (x1.isIfNotExists()) {
            return table;
         }

         LOG.info("replaced table '" + name + "'");
      }

      table = new SchemaObject(schema, name, SchemaObjectType.Table, x1);
      schema.objects.put(table.nameHashCode64(), table);
      return table;
   }

   boolean acceptDropTable(SQLDropTableStatement x) {
      for(SQLExprTableSource table : x.getTableSources()) {
         String schemaName = table.getSchema();
         Schema schema = this.findSchema(schemaName, false);
         if (schema != null) {
            long nameHashCode64 = table.getName().nameHashCode64();
            schema.objects.remove(nameHashCode64);
         }
      }

      return true;
   }

   boolean acceptView(SQLCreateViewStatement x) {
      String schemaName = x.getSchema();
      Schema schema = this.findSchema(schemaName, true);
      String name = x.computeName();
      SchemaObject view = schema.findTableOrView(name);
      if (view != null) {
         return false;
      } else {
         SchemaObject object = new SchemaObject(schema, name, SchemaObjectType.View, x.clone());
         schema.objects.put(object.nameHashCode64(), object);
         return true;
      }
   }

   boolean acceptView(SQLAlterViewStatement x) {
      String schemaName = x.getSchema();
      Schema schema = this.findSchema(schemaName, true);
      String name = x.computeName();
      SchemaObject view = schema.findTableOrView(name);
      if (view != null) {
         return false;
      } else {
         SchemaObject object = new SchemaObject(schema, name, SchemaObjectType.View, x.clone());
         schema.objects.put(object.nameHashCode64(), object);
         return true;
      }
   }

   boolean acceptDropIndex(SQLDropIndexStatement x) {
      if (x.getTableName() == null) {
         return false;
      } else {
         SQLName table = x.getTableName().getName();
         SchemaObject object = this.findTable(table);
         if (object != null) {
            SQLCreateTableStatement stmt = (SQLCreateTableStatement)object.getStatement();
            if (stmt != null) {
               stmt.apply(x);
               return true;
            }
         }

         return false;
      }
   }

   boolean acceptCreateIndex(SQLCreateIndexStatement x) {
      String schemaName = x.getSchema();
      Schema schema = this.findSchema(schemaName, true);
      String name = x.getName().getSimpleName();
      SchemaObject object = new SchemaObject(schema, name, SchemaObjectType.Index, x.clone());
      schema.objects.put(object.nameHashCode64(), object);
      return true;
   }

   boolean acceptCreateFunction(SQLCreateFunctionStatement x) {
      String schemaName = x.getSchema();
      Schema schema = this.findSchema(schemaName, true);
      String name = x.getName().getSimpleName();
      SchemaObject object = new SchemaObject(schema, name, SchemaObjectType.Function, x.clone());
      schema.functions.put(object.nameHashCode64(), object);
      return true;
   }

   boolean acceptAlterTable(SQLAlterTableStatement x) {
      String schemaName = x.getSchema();
      Schema schema = this.findSchema(schemaName, true);
      SchemaObject object = schema.findTable(x.nameHashCode64());
      if (object != null) {
         SQLCreateTableStatement stmt = (SQLCreateTableStatement)object.getStatement();
         if (stmt != null) {
            stmt.apply(x);
            return true;
         }
      }

      return false;
   }

   public boolean acceptCreateSequence(SQLCreateSequenceStatement x) {
      String schemaName = x.getSchema();
      Schema schema = this.findSchema(schemaName, true);
      String name = x.getName().getSimpleName();
      SchemaObject object = new SchemaObject(schema, name, SchemaObjectType.Sequence);
      schema.objects.put(object.nameHashCode64(), object);
      return false;
   }

   public boolean acceptDropSequence(SQLDropSequenceStatement x) {
      String schemaName = x.getSchema();
      Schema schema = this.findSchema(schemaName, true);
      long nameHashCode64 = x.getName().nameHashCode64();
      schema.objects.remove(nameHashCode64);
      return false;
   }

   public SQLDataType findFuntionReturnType(long functionNameHashCode) {
      return functionNameHashCode != FnvHash.Constants.LEN && functionNameHashCode != FnvHash.Constants.LENGTH ? null : SQLIntegerExpr.DATA_TYPE;
   }

   protected String loadDDL(String table) {
      if (table == null) {
         return null;
      } else {
         table = SQLUtils.normalize(table, this.schemaDbType);
         return this.schemaLoader != null ? this.schemaLoader.loadDDL(null, null, table) : null;
      }
   }

   protected String loadDDL(String schema, String table) {
      if (table == null) {
         return null;
      } else {
         table = SQLUtils.normalize(table, this.dbType);
         if (schema != null) {
            schema = SQLUtils.normalize(schema, this.dbType);
         }

         return this.schemaLoader != null ? this.schemaLoader.loadDDL(null, schema, table) : null;
      }
   }

   protected String loadDDL(String catalog, String schema, String table) {
      if (table == null) {
         return null;
      } else {
         table = SQLUtils.normalize(table, this.dbType);
         if (schema != null) {
            schema = SQLUtils.normalize(schema, this.dbType);
         }

         if (catalog != null) {
            catalog = SQLUtils.normalize(catalog, this.dbType);
         }

         return this.schemaLoader != null ? this.schemaLoader.loadDDL(catalog, schema, table) : null;
      }
   }

   public SchemaLoader getSchemaLoader() {
      return this.schemaLoader;
   }

   public void setSchemaLoader(SchemaLoader schemaLoader) {
      this.schemaLoader = schemaLoader;
   }

   public class OracleConsoleSchemaVisitor extends OracleASTVisitorAdapter {
      public boolean visit(SQLDropSequenceStatement x) {
         SchemaRepository.this.acceptDropSequence(x);
         return false;
      }

      public boolean visit(SQLCreateSequenceStatement x) {
         SchemaRepository.this.acceptCreateSequence(x);
         return false;
      }

      public boolean visit(OracleCreateTableStatement x) {
         this.visit((SQLCreateTableStatement)x);
         return false;
      }

      public boolean visit(SQLCreateTableStatement x) {
         SchemaRepository.this.acceptCreateTable(x);
         return false;
      }

      public boolean visit(SQLDropTableStatement x) {
         SchemaRepository.this.acceptDropTable(x);
         return false;
      }

      public boolean visit(SQLCreateViewStatement x) {
         SchemaRepository.this.acceptView(x);
         return false;
      }

      public boolean visit(SQLAlterViewStatement x) {
         SchemaRepository.this.acceptView(x);
         return false;
      }

      public boolean visit(SQLCreateIndexStatement x) {
         SchemaRepository.this.acceptCreateIndex(x);
         return false;
      }

      public boolean visit(SQLCreateFunctionStatement x) {
         SchemaRepository.this.acceptCreateFunction(x);
         return false;
      }

      public boolean visit(SQLAlterTableStatement x) {
         SchemaRepository.this.acceptAlterTable(x);
         return false;
      }

      public boolean visit(SQLUseStatement x) {
         String schema = x.getDatabase().getSimpleName();
         SchemaRepository.this.setDefaultSchema(schema);
         return false;
      }

      public boolean visit(SQLDropIndexStatement x) {
         SchemaRepository.this.acceptDropIndex(x);
         return false;
      }
   }

   public class DefaultConsoleSchemaVisitor extends SQLASTVisitorAdapter {
      public boolean visit(SQLDropSequenceStatement x) {
         SchemaRepository.this.acceptDropSequence(x);
         return false;
      }

      public boolean visit(SQLCreateSequenceStatement x) {
         SchemaRepository.this.acceptCreateSequence(x);
         return false;
      }

      public boolean visit(SQLCreateTableStatement x) {
         SchemaRepository.this.acceptCreateTable(x);
         return false;
      }

      public boolean visit(SQLDropTableStatement x) {
         SchemaRepository.this.acceptDropTable(x);
         return false;
      }

      public boolean visit(SQLCreateViewStatement x) {
         SchemaRepository.this.acceptView(x);
         return false;
      }

      public boolean visit(SQLAlterViewStatement x) {
         SchemaRepository.this.acceptView(x);
         return false;
      }

      public boolean visit(SQLCreateIndexStatement x) {
         SchemaRepository.this.acceptCreateIndex(x);
         return false;
      }

      public boolean visit(SQLCreateFunctionStatement x) {
         SchemaRepository.this.acceptCreateFunction(x);
         return false;
      }

      public boolean visit(SQLAlterTableStatement x) {
         SchemaRepository.this.acceptAlterTable(x);
         return false;
      }

      public boolean visit(SQLDropIndexStatement x) {
         SchemaRepository.this.acceptDropIndex(x);
         return false;
      }
   }

   public interface SchemaLoader {
      String loadDDL(String var1, String var2, String var3);
   }
}
