/**
   * Opens this database. The database should be opened after construction. or reopened by the
   * close(int closemode) method during a "shutdown compact". Closes the log if there is an error.
   */
  void reopen() throws HsqlException {

    boolean isNew;

    setState(DATABASE_OPENING);

    try {
      databaseProperties = new HsqlDatabaseProperties(this);
      isNew = !DatabaseURL.isFileBasedDatabaseType(sType) || !databaseProperties.checkFileExists();

      if (isNew && urlProperties.isPropertyTrue("ifexists")) {
        throw Trace.error(Trace.DATABASE_NOT_EXISTS, sName);
      }

      databaseProperties.load();
      databaseProperties.setURLProperties(urlProperties);
      compiledStatementManager.reset();

      nameManager = new HsqlNameManager();
      granteeManager = new GranteeManager(this);
      userManager = new UserManager(this);
      hAlias = Library.getAliasMap();
      schemaManager = new SchemaManager(this);
      bReferentialIntegrity = true;
      sessionManager = new SessionManager(this);
      txManager = new TransactionManager(this);
      collation = new Collation();
      dbInfo = DatabaseInformation.newDatabaseInformation(this);

      databaseProperties.setDatabaseVariables();

      if (DatabaseURL.isFileBasedDatabaseType(sType)) {
        logger.openLog(this);
      }

      if (isNew) {
        sessionManager
            .getSysSession()
            .sqlExecuteDirectNoPreChecks("CREATE USER SA PASSWORD \"\" ADMIN");
        logger.synchLogForce();
      }

      dbInfo.setWithContent(true);
    } catch (Throwable e) {
      logger.closeLog(Database.CLOSEMODE_IMMEDIATELY);
      logger.releaseLock();
      setState(DATABASE_SHUTDOWN);
      clearStructures();
      DatabaseManager.removeDatabase(this);

      if (!(e instanceof HsqlException)) {
        e = Trace.error(Trace.GENERAL_ERROR, e.toString());
      }

      throw (HsqlException) e;
    }

    setState(DATABASE_ONLINE);
  }
  /**
   * Opens this database. The database should be opened after construction. or reopened by the
   * close(int closemode) method during a "shutdown compact". Closes the log if there is an error.
   */
  void reopen() throws HsqlException {

    setState(DATABASE_OPENING);

    try {
      User sysUser;

      isNew =
          (sType == DatabaseManager.S_MEM
              || !HsqlProperties.checkFileExists(sPath, isFilesInJar(), getClass()));
      databaseProperties = new HsqlDatabaseProperties(this);

      databaseProperties.load();
      databaseProperties.setURLProperties(urlProperties);
      compiledStatementManager.reset();

      tTable = new HsqlArrayList();
      userManager = new UserManager();
      hAlias = Library.getAliasMap();
      nameManager = new HsqlNameManager();
      triggerNameList = new DatabaseObjectNames();
      indexNameList = new DatabaseObjectNames();
      constraintNameList = new DatabaseObjectNames();
      sequenceManager = new SequenceManager();
      bReferentialIntegrity = true;
      sysUser = userManager.createSysUser(this);
      sessionManager = new SessionManager(this, sysUser);
      dInfo = DatabaseInformation.newDatabaseInformation(this);

      if (sType != DatabaseManager.S_MEM) {
        logger.openLog(this);
      }

      if (isNew) {
        sessionManager
            .getSysSession()
            .sqlExecuteDirectNoPreChecks("CREATE USER SA PASSWORD \"\" ADMIN");
      }

      dInfo.setWithContent(true);
    } catch (Throwable e) {
      logger.closeLog(Database.CLOSEMODE_IMMEDIATELY);
      logger.releaseLock();
      setState(DATABASE_SHUTDOWN);
      clearStructures();

      if (!(e instanceof HsqlException)) {
        e = Trace.error(Trace.GENERAL_ERROR, e.toString());
      }

      throw (HsqlException) e;
    }

    setState(DATABASE_ONLINE);
  }
  /**
   * Ensures that under the correct conditions the system table producer's table cache, if any, is
   * set dirty.
   *
   * <p>This call is require to ensure that up-to-date versions are generated if necessary in
   * response to following system table requests.
   *
   * <p>The result argument, if non-null, is checked for update status. If it is an update result
   * with an update count, then the call must have come from a successful SELECT INTO statement, in
   * which a case a new table was created and all system tables reporting in the tables, columns,
   * indexes, etc. are dirty.
   *
   * <p>If the Result argument is null, then the call must have come from a DDL statement other than
   * a set statement, in which case a database object was created, dropped, altered or a permission
   * was granted or revoked, meaning that potentially all cached ssytem table are dirty.
   *
   * @param r A Result to test for update status, indicating the a table was created as the result
   *     of executing a SELECT INTO statement.
   */
  void setMetaDirty(Result r) {

    if (r == null || (r.iMode == Result.UPDATECOUNT && r.iUpdateCount > 0)) {
      nextDDLSCN();
      dInfo.setDirty();
    }
  }
  /**
   * Ensures system table producer's table cache, if it exists, is set dirty. After this call
   * up-to-date versions are generated in response to system table requests.
   *
   * <p>Also resets all prepared statements if a change to database structure can possibly affect
   * any existing prepared statement's validity.
   *
   * <p>The argument is false if the change to the database structure does not affect the prepared
   * statement, such as when a new table is added.
   *
   * <p>The argument is typically true when a database object is dropped, altered or a permission
   * was revoked.
   *
   * @param resetPrepared If true, reset all prepared statements.
   */
  public void setMetaDirty(boolean resetPrepared) {

    if (dbInfo != null) {
      dbInfo.setDirty();
    }

    if (resetPrepared) {
      compiledStatementManager.resetStatements();
    }
  }
  /**
   * Opens this database. The database can be opened by the constructor, or reopened by the
   * close(int closemode) method during a "shutdown compact".
   *
   * @see #close(int closemode)
   * @throws SQLException if a database access error occurs
   */
  private void open() throws SQLException {

    boolean newdatabase;
    User sysUser;

    if (sName.length() == 0) {
      throw Trace.error(Trace.GENERAL_ERROR, "bad database name");
    }

    setState(DATABASE_OPENING);
    compiledStatementManager.reset();

    tTable = new HsqlArrayList();
    aAccess = new UserManager();
    hAlias = Library.getAliasMap();
    triggerNameList = new DatabaseObjectNames();
    indexNameList = new DatabaseObjectNames();
    bReferentialIntegrity = true;
    newdatabase = false;
    sysUser = aAccess.createSysUser(this);
    sessionManager = new SessionManager(this, sysUser);
    databaseProperties = new HsqlDatabaseProperties(this);
    dInfo = DatabaseInformation.newDatabaseInformation(this);

    if (sName.equals(".")) {
      newdatabase = true;
    } else {

      // create properties file if not exits and report if new file
      newdatabase = !databaseProperties.load();

      logger.openLog(this, sName);
    }

    if (newdatabase) {
      execute("CREATE USER SA PASSWORD \"\" ADMIN", sessionManager.getSysSession());
    }

    setState(DATABASE_ONLINE);
    dInfo.setWithContent(true);
  }
  /**
   * Retruns the specified user-defined table or view visible within the context of the specified
   * Session, or any system table of the given name. It excludes any temp tables created in
   * different Sessions. Throws if the table does not exist in the context.
   */
  public Table getTable(Session session, String name) throws HsqlException {

    Table t = findUserTable(session, name);

    if (t == null) {
      t = dInfo.getSystemTable(session, name);
    }

    if (t == null) {
      throw Trace.error(Trace.TABLE_NOT_FOUND, name);
    }

    return t;
  }
  /**
   * Retrieves the specified user-defined table or view visible within the context of the specified
   * Session, or any system table of the given name. This excludes any temp tables created in
   * different Sessions.
   *
   * @param name of the table or view to retrieve
   * @param session the Session within which to search for user tables
   * @return the user table or view, or system table
   * @throws SQLException if there is no such table or view
   */
  Table getTable(String name, Session session) throws SQLException {

    Table t = findUserTable(name, session);

    if (t == null) {
      t = dInfo.getSystemTable(name, session);
    }

    if (t == null) {
      throw Trace.error(Trace.TABLE_NOT_FOUND, name);
    }

    return t;
  }