/**
   * 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);
  }
  /**
   * Closes this Database using the specified mode.
   *
   * <p>
   *
   * <ol>
   *   <LI>closemode -1 performs SHUTDOWN IMMEDIATELY, equivalent to a poweroff or crash.
   *   <LI>closemode 0 performs a normal SHUTDOWN that checkpoints the database normally.
   *   <LI>closemode 1 performs a shutdown compact that scripts out the contents of any CACHED
   *       tables to the log then deletes the existing *.data file that contains the data for all
   *       CACHED table before the normal checkpoint process which in turn creates a new, compact
   *       *.data file.
   * </ol>
   */
  void close(int closemode) throws HsqlException {

    HsqlException he = null;

    setState(DATABASE_CLOSING);
    sessionManager.closeAllSessions();
    sessionManager.clearAll();

    // fredt - impact of possible error conditions in closing the log
    // should be investigated for the CLOSEMODE_COMPACT mode
    logger.closeLog(closemode);

    try {
      if (closemode == CLOSEMODE_COMPACT && !filesReadOnly) {
        clearStructures();
        reopen();
        setState(DATABASE_CLOSING);
        logger.closeLog(CLOSEMODE_NORMAL);
      }
    } catch (Throwable t) {
      if (t instanceof HsqlException) {
        he = (HsqlException) t;
      } else {
        he = Trace.error(Trace.GENERAL_ERROR, t.toString());
      }
    }

    classLoader = null;

    logger.releaseLock();
    setState(DATABASE_SHUTDOWN);
    clearStructures();

    // fredt - this could change to avoid removing a db from the
    // DatabaseManager repository if there are pending getDatabase()
    // calls
    DatabaseManager.removeDatabase(this);

    if (he != null) {
      throw he;
    }
  }
  /**
   * Closes this Database using the specified mode.
   *
   * <p>
   *
   * <ol>
   *   <LI>closemode -1 performs SHUTDOWN IMMEDIATELY, equivalent to a poweroff or crash.
   *   <LI>closemode 0 performs a normal SHUTDOWN that checkpoints the database normally.
   *   <LI>closemode 1 performs a shutdown compact that scripts out the contents of any CACHED
   *       tables to the log then deletes the existing *.data file that contains the data for all
   *       CACHED table before the normal checkpoint process which in turn creates a new, compact
   *       *.data file.
   * </ol>
   *
   * @param closemode which type of close to perform
   * @throws SQLException if a database access error occurs
   * @see Logger#closeLog(int)
   */
  void close(int closemode) throws SQLException {

    SQLException se;
    HsqlRuntime rt;

    se = null;
    rt = HsqlRuntime.getHsqlRuntime();

    synchronized (rt.findOrCreateDatabaseMutex(sName)) {
      setState(DATABASE_CLOSING);

      try {
        logger.closeLog(closemode);

        // tony_lai@users 20020820
        // The database re-open and close has been moved from
        // Log#close(int closemode) for saving memory usage.
        // Doing so the instances of Log and other objects are no longer
        // referenced, and therefore can be garbage collected if necessary.
        if (closemode == 1) {
          open();
          logger.closeLog(0);
        }
      } catch (Throwable t) {
        if (t instanceof SQLException) {
          se = (SQLException) t;
        } else {
          se = Trace.error(Trace.GENERAL_ERROR, t.toString());
        }
      }

      classLoader = null;

      logger.releaseLock();
      rt.removeDatabase(this);
      this.setState(DATABASE_SHUTDOWN);
    }

    if (se != null) {
      throw se;
    }
  }