/**
   * Retrieves a MULTI Result describing three aspects of the CompiledStatement prepared from the
   * SQL argument for execution in this session context:
   *
   * <p>
   *
   * <ol>
   *   <li>An PREPARE_ACK mode Result describing id of the statement prepared by this request. This
   *       is used by the JDBC implementation to later identify to the engine which prepared
   *       statement to execute.
   *   <li>A DATA mode result describing the statement's result set metadata. This is used to
   *       generate the JDBC ResultSetMetaData object returned by PreparedStatement.getMetaData and
   *       CallableStatement.getMetaData.
   *   <li>A DATA mode result describing the statement's parameter metdata. This is used to by the
   *       JDBC implementation to determine how to send parameters back to the engine when executing
   *       the statement. It is also used to construct the JDBC ParameterMetaData object for
   *       PreparedStatements and CallableStatements.
   *
   * @param sql a string describing the desired statement object
   * @throws HsqlException is a database access error occurs
   * @return a MULTI Result describing the compiled statement.
   */
  private Result sqlPrepare(String sql, int type) {

    CompiledStatement cs = null;
    int csid = compiledStatementManager.getStatementID(sql);
    Result rsmd;
    Result pmd;

    // ...check valid...
    if (csid > 0 && compiledStatementManager.isValid(csid, iId)) {
      cs = compiledStatementManager.getStatement(csid);
      rsmd = cs.describeResultSet();
      pmd = cs.describeParameters();

      return Result.newPrepareResponse(csid, rsmd, pmd);
    }

    // ...compile or (re)validate
    try {
      cs = sqlCompileStatement(sql, type);
    } catch (Throwable t) {
      return new Result(t, sql);
    }

    // boucherb@users
    // TODO:  It is still unclear to me as to whether, in the case of revalidation
    //        v.s. first compilation, the newly created CompiledStatement
    //        object should replace the old one in the CompiledStatementManager
    //        repository.  If, for instance, a table column has been dropped and
    //        then a column with the same name is added with different data type,
    //        constraints, etc., the existing CompiledStatement object is not
    //        equivalent in its effect and perhaps runs the risk of corrupting
    //        the database.  For instance, a CompiledStatement contains
    //        fixed mappings from positions in a column value expression array
    //        to column positions in the target table.  Thus, an alteration to a
    //        target table may leave an existing CompiledStatement's SQL
    //        character sequence valid, but not its execution plan.
    //        OTOH, simply replacing the old execution plan with a new one
    //        may also be undesirable, as the intended and actual effects
    //        may become divergent. Once again, for example, if a column name
    //        comes to mean a different column, then by blindly replacing the
    //        old CompiledStatement with the new, inserting, updating
    //        or predicating happens upon an unintended column.
    //        The only DDL operations that raise such dangers are sequences
    //        involving dropping a columns and then adding an incompatible one
    //        of the same name at the same position or alterations that
    //        change the positions of columns.  All other alterations to
    //        database objects should, in theory, allow the original
    //        CompiledStatement to continue to operate as intended.
    if (csid <= 0) {
      csid = compiledStatementManager.registerStatement(cs);
    }

    compiledStatementManager.setValidated(csid, iId, dDatabase.getDDLSCN());

    rsmd = cs.describeResultSet();
    pmd = cs.describeParameters();

    return Result.newPrepareResponse(csid, rsmd, pmd);
  }