Open Source Repository

Home /hibernate/hibernate-3.2.4.ga | Repository Home


org/hibernate/hql/ast/exec/MultiTableUpdateExecutor.java
// $Id: MultiTableUpdateExecutor.java 11287 2007-03-15 11:38:25Z [email protected] $
package org.hibernate.hql.ast.exec;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.exception.JDBCExceptionHelper;
import org.hibernate.hql.ast.HqlSqlWalker;
import org.hibernate.hql.ast.tree.AssignmentSpecification;
import org.hibernate.hql.ast.tree.FromElement;
import org.hibernate.hql.ast.tree.UpdateStatement;
import org.hibernate.param.ParameterSpecification;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.Update;
import org.hibernate.util.StringHelper;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Implementation of MultiTableUpdateExecutor.
 *
 @author Steve Ebersole
 */
public class MultiTableUpdateExecutor extends AbstractStatementExecutor {
  private static final Log log = LogFactory.getLogMultiTableUpdateExecutor.class );

  private final Queryable persister;
  private final String idInsertSelect;
  private final String[] updates;
  private final ParameterSpecification[][] hqlParameters;

  public MultiTableUpdateExecutor(HqlSqlWalker walker) {
    superwalker, log );

    if !walker.getSessionFactoryHelper().getFactory().getDialect().supportsTemporaryTables() ) {
      throw new HibernateException"cannot perform multi-table updates using dialect not supporting temp tables" );
    }

    UpdateStatement updateStatement = UpdateStatement walker.getAST();
    FromElement fromElement = updateStatement.getFromClause().getFromElement();
    String bulkTargetAlias = fromElement.getTableAlias();
    this.persister = fromElement.getQueryable();

    this.idInsertSelect = generateIdInsertSelectpersister, bulkTargetAlias, updateStatement.getWhereClause() );
    log.trace"Generated ID-INSERT-SELECT SQL (multi-table update) : " +  idInsertSelect );

    String[] tableNames = persister.getConstraintOrderedTableNameClosure();
    String[][] columnNames = persister.getContraintOrderedTableKeyColumnClosure();

    String idSubselect = generateIdSubselectpersister );
    List assignmentSpecifications = walker.getAssignmentSpecifications();

    updates = new String[tableNames.length];
    hqlParameters = new ParameterSpecification[tableNames.length][];
    for int tableIndex = 0; tableIndex < tableNames.length; tableIndex++ ) {
      boolean affected = false;
      List parameterList = new ArrayList();
      Update update = new UpdategetFactory().getDialect() )
          .setTableNametableNames[tableIndex] )
          .setWhere"(" + StringHelper.join", ", columnNames[tableIndex] ) ") IN (" + idSubselect + ")" );
      if getFactory().getSettings().isCommentsEnabled() ) {
        update.setComment"bulk update" );
      }
      final Iterator itr = assignmentSpecifications.iterator();
      while itr.hasNext() ) {
        final AssignmentSpecification specification = AssignmentSpecification itr.next();
        if specification.affectsTabletableNames[tableIndex] ) ) {
          affected = true;
          update.appendAssignmentFragmentspecification.getSqlAssignmentFragment() );
          if specification.getParameters() != null ) {
            for int paramIndex = 0; paramIndex < specification.getParameters().length; paramIndex++ ) {
              parameterList.addspecification.getParameters()[paramIndex] );
            }
          }
        }
      }
      if affected ) {
        updates[tableIndex= update.toStatementString();
        hqlParameters[tableIndexParameterSpecification[] ) parameterList.toArraynew ParameterSpecification[0] );
      }
    }
  }

  public Queryable getAffectedQueryable() {
    return persister;
  }

  public String[] getSqlStatements() {
    return updates;
  }

  public int execute(QueryParameters parameters, SessionImplementor sessionthrows HibernateException {
    coordinateSharedCacheCleanupsession );

    createTemporaryTableIfNecessarypersister, session );

    try {
      // First, save off the pertinent ids, as the return value
      PreparedStatement ps = null;
      int resultCount = 0;
      try {
        try {
          ps = session.getBatcher().prepareStatementidInsertSelect );
          int parameterStart = getWalker().getNumberOfParametersInSetClause();
          List allParams = getWalker().getParameters();
          Iterator whereParams = allParams.subListparameterStart, allParams.size() ).iterator();
          int sum = 1// jdbc params are 1-based
          while whereParams.hasNext() ) {
            sum += ( ( ParameterSpecification whereParams.next() ).bindps, parameters, session, sum );
          }
          resultCount = ps.executeUpdate();
        }
        finally {
          if ps != null ) {
            session.getBatcher().closeStatementps );
          }
        }
      }
      catchSQLException e ) {
        throw JDBCExceptionHelper.convert(
            getFactory().getSQLExceptionConverter(),
                e,
                "could not insert/select ids for bulk update",
                idInsertSelect
          );
      }

      // Start performing the updates
      for int i = 0; i < updates.length; i++ ) {
        if updates[i== null ) {
          continue;
        }
        try {
          try {
            ps = session.getBatcher().prepareStatementupdates[i] );
            if hqlParameters[i!= null ) {
              int position = 1// jdbc params are 1-based
              for int x = 0; x < hqlParameters[i].length; x++ ) {
                position += hqlParameters[i][x].bindps, parameters, session, position );
              }
            }
            ps.executeUpdate();
          }
          finally {
            if ps != null ) {
              session.getBatcher().closeStatementps );
            }
          }
        }
        catchSQLException e ) {
          throw JDBCExceptionHelper.convert(
              getFactory().getSQLExceptionConverter(),
                  e,
                  "error performing bulk update",
                  updates[i]
            );
        }
      }

      return resultCount;
    }
    finally {
      dropTemporaryTableIfNecessarypersister, session );
    }
  }

  protected Queryable[] getAffectedQueryables() {
    return new Queryable[] { persister };
  }
}