public int bulkCopyColumnValuesByAnd(
      final String entityName, final Map updateColumns, final Map criteria) {
    int result = 0;

    if ((entityName == null) || (updateColumns == null) || updateColumns.isEmpty()) {
      return 0;
    }

    try {
      final ModelEntity modelEntity = delegatorInterface.getModelEntity(entityName);

      final GenericHelper entityHelper = delegatorInterface.getEntityHelper(entityName);

      final ModelFieldTypeReader modelFieldTypeReader =
          ModelFieldTypeReader.getModelFieldTypeReader(entityHelper.getHelperName());

      final ArrayList<EntityConditionParam> params = new ArrayList<EntityConditionParam>();

      // generate the update sql
      final StringBuilder updateSql = new StringBuilder("UPDATE ");

      updateSql.append(modelEntity.getTableName(entityHelper.getHelperName()));
      updateSql.append(" SET ");

      if (!modelEntity.areFields(updateColumns.keySet())) {
        throw new GenericModelException(
            "At least one of the passed fields for update is not valid: "
                + updateColumns.keySet().toString());
      }

      if (!modelEntity.areFields(updateColumns.values())) {
        throw new GenericModelException(
            "At least one of the passed fields for update is not valid: "
                + updateColumns.values().toString());
      }

      for (final Iterator iterator = updateColumns.keySet().iterator(); iterator.hasNext(); ) {
        final String column = (String) iterator.next();
        updateSql.append(" ");
        final ModelField toModelField = modelEntity.getField(column);
        updateSql.append(toModelField.getColName());
        updateSql.append(" = ");
        final ModelField fromModelField = modelEntity.getField((String) updateColumns.get(column));
        updateSql.append(fromModelField.getColName());
        if (iterator.hasNext()) {
          updateSql.append(", ");
        }
      }

      if ((criteria != null) && !criteria.isEmpty()) {
        if (!modelEntity.areFields(criteria.keySet())) {
          throw new GenericModelException(
              "At least one of the passed fields is not valid: " + criteria.keySet().toString());
        }

        // generate the where clause
        final EntityFieldMap entityCondition = new EntityFieldMap(criteria, EntityOperator.AND);

        final String entityCondWhereString = entityCondition.makeWhereString(modelEntity, params);

        if (entityCondWhereString.length() > 0) {
          updateSql.append(" WHERE ");
          updateSql.append(entityCondWhereString);
        }
      }

      final SQLProcessor processor = new AutoCommitSQLProcessor(entityHelper.getHelperName());
      final String sql = updateSql.toString();

      if (log.isDebugEnabled()) {
        log.debug("Running bulk update SQL: '" + sql + '\'');
      }

      processor.prepareStatement(sql);

      for (final EntityConditionParam conditionParam : params) {
        SqlJdbcUtil.setValue(
            processor,
            conditionParam.getModelField(),
            modelEntity.getEntityName(),
            conditionParam.getFieldValue(),
            modelFieldTypeReader);
      }

      try {
        result = processor.executeUpdate();
      } finally {
        processor.close();
      }
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    } catch (final NoClassDefFoundError e) {
      // under JDK 1.3 unit tests - javax.sql.XADataSource cannot be found.
      // this shouldn't affect runtime - application servers should ship the jar
    }

    return result;
  }
  public int bulkUpdateByPrimaryKey(
      final String entityName, final Map<String, ?> updateValues, final List<Long> keys) {
    int result = 0;

    if ((entityName == null)
        || (updateValues == null)
        || updateValues.isEmpty()
        || (keys == null)
        || keys.isEmpty()) {
      return 0;
    }

    try {
      final GenericHelper entityHelper = delegatorInterface.getEntityHelper(entityName);
      final ModelEntity modelEntity = delegatorInterface.getModelEntity(entityName);

      final List<String> pks = modelEntity.getPkFieldNames();
      if (pks.size() != 1) {
        throw new DataAccessException(
            "BulkUpdateByPrimaryKey only works for single column keys at this moment.");
      }
      final String pkName = pks.get(0);

      final Updater updater =
          new Updater(
              ModelFieldTypeReader.getModelFieldTypeReader(entityHelper.getHelperName()),
              entityName);
      final List<Updater.Value> params = new ArrayList<Updater.Value>();

      final StringBuilder updateSql = new StringBuilder("UPDATE ");

      updateSql.append(modelEntity.getTableName(entityHelper.getHelperName()));
      updateSql.append(" SET ");
      // generate the update sql
      for (final Iterator<String> iterator = updateValues.keySet().iterator();
          iterator.hasNext(); ) {
        final String column = iterator.next();
        updateSql.append(" ");
        final ModelField field = modelEntity.getField(column);
        updateSql.append(field.getColName());
        updateSql.append(" = ");
        params.add(updater.create(field, updateValues.get(column)));
        updateSql.append("? ");
        if (iterator.hasNext()) {
          updateSql.append(", ");
        }
      }

      // generate the where clause
      updateSql.append(" WHERE ");

      // batch the update
      final int batchSize = getQueryBatchSize();

      int currentIndex = 0;

      while (currentIndex < keys.size()) {
        int i = 0;
        final StringBuilder idClause = new StringBuilder();
        final ArrayList<Long> idParams = new ArrayList<Long>();
        for (final Iterator<Long> iterator = keys.subList(currentIndex, keys.size()).iterator();
            iterator.hasNext() && (i < batchSize);
            i++) {
          final Long key = iterator.next();
          idClause.append(" ");
          idClause.append(pkName);
          idClause.append(" = ");
          idParams.add(key);
          idClause.append("? ");

          if (iterator.hasNext() && ((i + 1) < batchSize)) {
            idClause.append(" or ");
          }
        }

        final SQLProcessor processor = new AutoCommitSQLProcessor(entityHelper.getHelperName());
        processor.prepareStatement(updateSql.toString() + idClause.toString());
        for (final Updater.Value param : params) {
          param.setValue(processor);
        }
        for (final Long idParam : idParams) {
          processor.setValue(idParam);
        }

        try {
          result = processor.executeUpdate();
        } finally {
          processor.close();
        }
        currentIndex += i;
      }
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    } catch (final SQLException e) {
      throw new DataAccessException(e);
    } catch (final NoClassDefFoundError e) {
      // under JDK 1.3 unit tests - javax.sql.XADataSource cannot be found.
      // this shouldn't affect runtime - application servers should ship the jar
    }
    return result;
  }