/**
   * @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
  /**
   * Copy columns from srcrow into destrow, or insert ROW_NUMBER.
   *
   * <p><b>FIXME</b> This is temporary. Window function treatment needs to generalized to work for
   * other window functions.
   *
   * @exception StandardException thrown on failure to open
   */
  public void populateFromSourceRow(ExecRow srcrow, ExecRow destrow) throws StandardException {
    int srcindex = 1;

    try {
      DataValueDescriptor[] columns = destrow.getRowArray();
      for (int index = 0; index < columns.length; index++) {

        if (referencedColumns != null && !referencedColumns.get(index)) {
          columns[index].setValue((long) this.rownumber);
        } else {
          destrow.setColumn(index + 1, srcrow.getColumn(srcindex));
          srcindex++;
        }
      }
    } catch (StandardException se) {
      throw se;
    } catch (Throwable t) {
      throw StandardException.unexpectedUserException(t);
    }
  }
  private void insertIntoVTI(ResultSet target, ExecRow row) throws StandardException {
    try {
      target.moveToInsertRow();

      DataValueDescriptor[] rowArray = row.getRowArray();
      for (int index = 0; index < rowArray.length; index++) {
        DataValueDescriptor dvd = rowArray[index];

        try {
          if (dvd.isNull()) target.updateNull(index + 1);
          else dvd.setInto(target, index + 1);
        } catch (Throwable t) {
          // backwards compatibility - 5.0 and before used
          // updateObject always.
          target.updateObject(index + 1, dvd.getObject());
        }
      }

      target.insertRow();
    } catch (Throwable t) {
      throw StandardException.unexpectedUserException(t);
    }
  }
  /** @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