/**
   * @see org.apache.derby.iapi.sql.ResultSet#cleanUp
   * @exception StandardException Thrown on error
   */
  public void cleanUp() throws StandardException {
    if (rowHolder != null) {
      rowHolder.close();
    }

    if (rs != null) {
      try {
        rs.close();
      } catch (Throwable t) {
        throw StandardException.unexpectedUserException(t);
      }
      rs = null;
    }

    // Close the ps if it needs to be instantiated on each execution
    if (!vtiRS.isReuseablePs() && ps != null) {
      try {
        ps.close();
        ps = null;
      } catch (Throwable t) {
        throw StandardException.unexpectedUserException(t);
      }
    }
    super.cleanUp();
  } // end of cleanUp
  public void finish() throws StandardException {

    if ((ps != null) && !vtiRS.isReuseablePs()) {
      try {
        ps.close();
        ps = null;
      } catch (Throwable t) {
        throw StandardException.unexpectedUserException(t);
      }
    }
    super.finish();
  } // end of finish
  /** @exception StandardException Standard Derby error policy */
  protected void openCore() throws StandardException {
    /* We must instantiate the VTI on each execution if any of the
     * parameters contain a ?.
     */
    if (ps == null) {
      ps = (PreparedStatement) vtiRS.getVTIConstructor().invoke(activation);
    }

    if (ps instanceof DeferModification) {
      try {
        ((DeferModification) ps)
            .modificationNotify(DeferModification.INSERT_STATEMENT, constants.deferred);
      } catch (Throwable t) {
        throw StandardException.unexpectedUserException(t);
      }
    }

    ExecRow row = getNextRowCore(sourceResultSet);

    try {
      rs = ps.executeQuery();
    } catch (Throwable t) {
      throw StandardException.unexpectedUserException(t);
    }

    /* Get or re-use the row changer.
     * NOTE: We need to set ourself as the top result set
     * if this is not the 1st execution.  (Done in constructor
     * for 1st execution.)
     */
    if (!firstExecute) {
      lcc.getStatementContext().setTopResultSet(this, subqueryTrackingArray);
    }

    /* The source does not know whether or not we are doing a
     * deferred mode insert.  If we are, then we must clear the
     * index scan info from the activation so that the row changer
     * does not re-use that information (which won't be valid for
     * a deferred mode insert).
     */
    if (constants.deferred) {
      activation.clearIndexScanInfo();
    }

    if (firstExecute && constants.deferred) {
      Properties properties = new Properties();

      /*
       ** If deferred we save a copy of the entire row.
       */
      rowHolder = new TemporaryRowHolderImpl(activation, properties);
    }

    while (row != null) {
      /*
       ** If we're doing a deferred insert, insert into the temporary
       ** conglomerate.  Otherwise, insert directly into the permanent
       ** conglomerates using the rowChanger.
       */
      if (constants.deferred) {
        rowHolder.insert(row);
      } else {
        insertIntoVTI(rs, row);
      }

      rowCount++;

      // No need to do a next on a single row source
      if (constants.singleRowSource) {
        row = null;
      } else {
        row = getNextRowCore(sourceResultSet);
      }
    }

    /*
     ** If it's a deferred insert, scan the temporary conglomerate and
     ** insert the rows into the permanent conglomerates using rowChanger.
     */
    if (constants.deferred) {
      CursorResultSet tempRS = rowHolder.getResultSet();
      try {
        tempRS.open();
        while ((row = tempRS.getNextRow()) != null) {
          insertIntoVTI(rs, row);
        }
      } finally {
        sourceResultSet.clearCurrentRow();
        tempRS.close();
      }
    }

    if (rowHolder != null) {
      rowHolder.close();
      // rowHolder kept across opens
    }
  } // end of normalInsertCore