Open Source Repository

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


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

import java.sql.PreparedStatement;
import java.sql.Connection;
import java.sql.Statement;

import org.hibernate.HibernateException;
import org.hibernate.action.BulkOperationCleanupAction;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.transaction.Isolater;
import org.hibernate.engine.transaction.IsolatedWork;
import org.hibernate.event.EventSource;
import org.hibernate.hql.ast.HqlSqlWalker;
import org.hibernate.hql.ast.SqlGenerator;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.InsertSelect;
import org.hibernate.sql.Select;
import org.hibernate.sql.SelectFragment;
import org.hibernate.util.StringHelper;

import antlr.RecognitionException;
import antlr.collections.AST;

import org.apache.commons.logging.Log;

/**
 * Implementation of AbstractStatementExecutor.
 *
 @author Steve Ebersole
 */
public abstract class AbstractStatementExecutor implements StatementExecutor {

  private final Log log;
  private final HqlSqlWalker walker;

  public AbstractStatementExecutor(HqlSqlWalker walker, Log log) {
    this.walker = walker;
    this.log = log;
  }

  protected HqlSqlWalker getWalker() {
    return walker;
  }

  protected SessionFactoryImplementor getFactory() {
    return walker.getSessionFactoryHelper().getFactory();
  }

  protected abstract Queryable[] getAffectedQueryables();

  protected String generateIdInsertSelect(Queryable persister, String tableAlias, AST whereClause) {
    Select select = new SelectgetFactory().getDialect() );
    SelectFragment selectFragment = new SelectFragment()
        .addColumnstableAlias, persister.getIdentifierColumnNames(), persister.getIdentifierColumnNames() );
    select.setSelectClauseselectFragment.toFragmentString().substring) );

    String rootTableName = persister.getTableName();
    String fromJoinFragment = persister.fromJoinFragmenttableAlias, true, false );
    String whereJoinFragment = persister.whereJoinFragmenttableAlias, true, false );

    select.setFromClauserootTableName + ' ' + tableAlias + fromJoinFragment );

    if whereJoinFragment == null ) {
      whereJoinFragment = "";
    }
    else {
      whereJoinFragment = whereJoinFragment.trim();
      if whereJoinFragment.startsWith"and" ) ) {
        whereJoinFragment = whereJoinFragment.substring);
      }
    }

    String userWhereClause = "";
    if whereClause.getNumberOfChildren() != ) {
      // If a where clause was specified in the update/delete query, use it to limit the
      // returned ids here...
      try {
        SqlGenerator sqlGenerator = new SqlGeneratorgetFactory() );
        sqlGenerator.whereClausewhereClause );
        userWhereClause = sqlGenerator.getSQL().substring);  // strip the " where "
      }
      catch RecognitionException e ) {
        throw new HibernateException"Unable to generate id select for DML operation", e );
      }
      if whereJoinFragment.length() ) {
        whereJoinFragment += " and ";
      }
    }

    select.setWhereClausewhereJoinFragment + userWhereClause );

    InsertSelect insert = new InsertSelectgetFactory().getDialect() );
    if getFactory().getSettings().isCommentsEnabled() ) {
      insert.setComment"insert-select for " + persister.getEntityName() " ids" );
    }
    insert.setTableNamepersister.getTemporaryIdTableName() );
    insert.setSelectselect );
    return insert.toStatementString();
  }

  protected String generateIdSubselect(Queryable persister) {
    return "select " + StringHelper.join", ", persister.getIdentifierColumnNames() ) +
              " from " + persister.getTemporaryIdTableName();
  }

  protected void createTemporaryTableIfNecessary(final Queryable persister, final SessionImplementor session) {
    // Don't really know all the codes required to adequately decipher returned jdbc exceptions here.
    // simply allow the failure to be eaten and the subsequent insert-selects/deletes should fail
    IsolatedWork work = new IsolatedWork() {
      public void doWork(Connection connectionthrows HibernateException {
        Statement stmnt = null;
        try {
          stmnt = connection.createStatement();
          stmnt.executeUpdatepersister.getTemporaryIdTableDDL() );
        }
        catchThrowable t ) {
          log.debug"unable to create temporary id table [" + t.getMessage() "]" );
        }
        finally {
          if stmnt != null ) {
            try {
              stmnt.close();
            }
            catchThrowable ignore ) {
              // ignore
            }
          }
        }
      }
    };
    if shouldIsolateTemporaryTableDDL() ) {
      if getFactory().getSettings().isDataDefinitionInTransactionSupported() ) {
        Isolater.doIsolatedWorkwork, session );
      }
      else {
        Isolater.doNonTransactedWorkwork, session );
      }
    }
    else {
      work.doWorksession.getJDBCContext().getConnectionManager().getConnection() );
      session.getJDBCContext().getConnectionManager().afterStatement();
    }
  }

  protected void dropTemporaryTableIfNecessary(final Queryable persister, final SessionImplementor session) {
    if getFactory().getDialect().dropTemporaryTableAfterUse() ) {
      IsolatedWork work = new IsolatedWork() {
        public void doWork(Connection connectionthrows HibernateException {
          Statement stmnt = null;
          try {
            stmnt = connection.createStatement();
            stmnt.executeUpdate"drop table " + persister.getTemporaryIdTableName() );
          }
          catchThrowable t ) {
            log.warn"unable to drop temporary id table after use [" + t.getMessage() "]" );
          }
          finally {
            if stmnt != null ) {
              try {
                stmnt.close();
              }
              catchThrowable ignore ) {
                // ignore
              }
            }
          }
        }
      };

      if shouldIsolateTemporaryTableDDL() ) {
        if getFactory().getSettings().isDataDefinitionInTransactionSupported() ) {
          Isolater.doIsolatedWorkwork, session );
        }
        else {
          Isolater.doNonTransactedWorkwork, session );
        }
      }
      else {
        work.doWorksession.getJDBCContext().getConnectionManager().getConnection() );
        session.getJDBCContext().getConnectionManager().afterStatement();
      }
    }
    else {
      // at the very least cleanup the data :)
      PreparedStatement ps = null;
      try {
        ps = session.getBatcher().prepareStatement"delete from " + persister.getTemporaryIdTableName() );
        ps.executeUpdate();
      }
      catchThrowable t ) {
        log.warn"unable to cleanup temporary id table after use [" + t + "]" );
      }
      finally {
        if ps != null ) {
          try {
            session.getBatcher().closeStatementps );
          }
          catchThrowable ignore ) {
            // ignore
          }
        }
      }
    }
  }

  protected void coordinateSharedCacheCleanup(SessionImplementor session) {
    BulkOperationCleanupAction action = new BulkOperationCleanupActionsession, getAffectedQueryables() );

    action.init();

    if session.isEventSource() ) {
      ( ( EventSource session ).getActionQueue().addActionaction );
    }
  }

  protected boolean shouldIsolateTemporaryTableDDL() {
    Boolean dialectVote = getFactory().getDialect().performTemporaryTableDDLInIsolation();
    if dialectVote != null ) {
      return dialectVote.booleanValue();
    }
    else {
      return getFactory().getSettings().isDataDefinitionImplicitCommit();
    }
  }
}