protected int doUpdateRows(
      Serializable id, PersistentCollection collection, SessionImplementor session)
      throws HibernateException {

    if (ArrayHelper.isAllFalse(elementColumnIsSettable)) return 0;

    try {
      PreparedStatement st = null;
      boolean callable = isUpdateCallable();
      Iterator entries = collection.entries(this);
      try {
        int i = 0;
        int count = 0;
        while (entries.hasNext()) {
          int offset = 1;
          Object entry = entries.next();
          if (collection.needsUpdating(entry, i, elementType)) {
            if (st == null) {
              if (callable) {
                CallableStatement callstatement =
                    session.getBatcher().prepareBatchCallableStatement(getSQLUpdateRowString());
                callstatement.registerOutParameter(
                    offset++,
                    Types
                        .NUMERIC); // TODO: should we require users to return number of update rows
                                   // ? (we cant make it return this without changing
                                   // collectionpersister interface)
                st = callstatement;
              } else {
                st = session.getBatcher().prepareBatchStatement(getSQLUpdateRowString());
              }
            }

            int loc = writeElement(st, collection.getElement(entry), offset, session);
            if (hasIdentifier) {
              loc = writeIdentifier(st, collection.getIdentifier(entry, i), loc, session);
            } else {
              loc = writeKey(st, id, loc, session);
              if (hasIndex && !indexContainsFormula) {
                loc = writeIndexToWhere(st, collection.getIndex(entry, i, this), loc, session);
              } else {
                loc =
                    writeElementToWhere(st, collection.getSnapshotElement(entry, i), loc, session);
              }
            }
            session.getBatcher().addToBatch(1);
            count++;
          }
          i++;
        }
        return count;
      } catch (SQLException sqle) {
        session.getBatcher().abortBatch(sqle);
        throw sqle;
      }
    } catch (SQLException sqle) {
      throw JDBCExceptionHelper.convert(
          getSQLExceptionConverter(),
          sqle,
          "could not update collection rows: "
              + MessageHelper.collectionInfoString(this, id, getFactory()),
          getSQLUpdateRowString());
    }
  }
  protected int doUpdateRows(
      Serializable id, PersistentCollection collection, SessionImplementor session)
      throws HibernateException {

    // we finish all the "removes" first to take care of possible unique
    // constraints and so that we can take better advantage of batching

    try {
      int count = 0;
      if (isRowDeleteEnabled()) {
        boolean useBatch = true;
        PreparedStatement st = null;
        // update removed rows fks to null
        try {
          int i = 0;

          Iterator entries = collection.entries(this);
          int offset = 1;
          Expectation expectation = Expectations.NONE;
          while (entries.hasNext()) {

            Object entry = entries.next();
            if (collection.needsUpdating(
                entry, i, elementType)) { // will still be issued when it used to be null
              if (st == null) {
                String sql = getSQLDeleteRowString();
                if (isDeleteCallable()) {
                  expectation = Expectations.appropriateExpectation(getDeleteCheckStyle());
                  useBatch = expectation.canBeBatched();
                  st =
                      useBatch
                          ? session.getBatcher().prepareBatchCallableStatement(sql)
                          : session.getBatcher().prepareCallableStatement(sql);
                  offset += expectation.prepare(st);
                } else {
                  st = session.getBatcher().prepareBatchStatement(getSQLDeleteRowString());
                }
              }
              int loc = writeKey(st, id, offset, session);
              writeElementToWhere(st, collection.getSnapshotElement(entry, i), loc, session);
              if (useBatch) {
                session.getBatcher().addToBatch(expectation);
              } else {
                expectation.verifyOutcome(st.executeUpdate(), st, -1);
              }
              count++;
            }
            i++;
          }
        } catch (SQLException sqle) {
          if (useBatch) {
            session.getBatcher().abortBatch(sqle);
          }
          throw sqle;
        } finally {
          if (!useBatch) {
            session.getBatcher().closeStatement(st);
          }
        }
      }

      if (isRowInsertEnabled()) {
        Expectation expectation = Expectations.appropriateExpectation(getInsertCheckStyle());
        boolean callable = isInsertCallable();
        boolean useBatch = expectation.canBeBatched();
        String sql = getSQLInsertRowString();
        PreparedStatement st = null;
        // now update all changed or added rows fks
        try {
          int i = 0;
          Iterator entries = collection.entries(this);
          while (entries.hasNext()) {
            Object entry = entries.next();
            int offset = 1;
            if (collection.needsUpdating(entry, i, elementType)) {
              if (useBatch) {
                if (st == null) {
                  if (callable) {
                    st = session.getBatcher().prepareBatchCallableStatement(sql);
                  } else {
                    st = session.getBatcher().prepareBatchStatement(sql);
                  }
                }
              } else {
                if (callable) {
                  st = session.getBatcher().prepareCallableStatement(sql);
                } else {
                  st = session.getBatcher().prepareStatement(sql);
                }
              }

              offset += expectation.prepare(st);

              int loc = writeKey(st, id, offset, session);
              if (hasIndex && !indexContainsFormula) {
                loc = writeIndexToWhere(st, collection.getIndex(entry, i, this), loc, session);
              }

              writeElementToWhere(st, collection.getElement(entry), loc, session);

              if (useBatch) {
                session.getBatcher().addToBatch(expectation);
              } else {
                expectation.verifyOutcome(st.executeUpdate(), st, -1);
              }
              count++;
            }
            i++;
          }
        } catch (SQLException sqle) {
          if (useBatch) {
            session.getBatcher().abortBatch(sqle);
          }
          throw sqle;
        } finally {
          if (!useBatch) {
            session.getBatcher().closeStatement(st);
          }
        }
      }

      return count;
    } catch (SQLException sqle) {
      throw getFactory()
          .getSQLExceptionHelper()
          .convert(
              sqle,
              "could not update collection rows: "
                  + MessageHelper.collectionInfoString(this, id, getFactory()),
              getSQLInsertRowString());
    }
  }