Open Source Repository

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



org/hibernate/engine/query/NativeSQLQueryPlan.java
package org.hibernate.engine.query;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.QueryException;
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
import org.hibernate.action.BulkOperationCleanupAction;
import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.TypedValue;
import org.hibernate.event.EventSource;
import org.hibernate.exception.JDBCExceptionHelper;
import org.hibernate.loader.custom.sql.SQLCustomQuery;
import org.hibernate.type.Type;
import org.hibernate.util.ArrayHelper;

/**
 * Defines a query execution plan for a native-SQL query.
 
 @author Steve Ebersole
 */
public class NativeSQLQueryPlan implements Serializable {
  private final String sourceQuery;

  private final SQLCustomQuery customQuery;

  private static final Log log = LogFactory.getLog(NativeSQLQueryPlan.class);

  public NativeSQLQueryPlan(
      NativeSQLQuerySpecification specification,
      SessionFactoryImplementor factory) {
    this.sourceQuery = specification.getQueryString();

    customQuery = new SQLCustomQuery(
        specification.getQueryString(),
        specification.getQueryReturns(),
        specification.getQuerySpaces(),
        factory );
  }

  public String getSourceQuery() {
    return sourceQuery;
  }

  public SQLCustomQuery getCustomQuery() {
    return customQuery;
  }

  private int[] getNamedParameterLocs(String namethrows QueryException {
    Object loc = customQuery.getNamedParameterBindPoints().getname );
    if loc == null ) {
      throw new QueryException(
          "Named parameter does not appear in Query: " + name,
          customQuery.getSQL() );
    }
    if loc instanceof Integer ) {
      return new int[] { ((Integerloc ).intValue() };
    }
    else {
      return ArrayHelper.toIntArray( (Listloc );
    }
  }

  /**
   * Bind positional parameter values to the <tt>PreparedStatement</tt>
   * (these are parameters specified by a JDBC-style ?).
   */
  private int bindPositionalParameters(final PreparedStatement st,
      final QueryParameters queryParameters, final int start,
      final SessionImplementor sessionthrows SQLException,
      HibernateException {

    final Object[] values = queryParameters
        .getFilteredPositionalParameterValues();
    final Type[] types = queryParameters
        .getFilteredPositionalParameterTypes();
    int span = 0;
    for (int i = 0; i < values.length; i++) {
      types[i].nullSafeSetst, values[i], start + span, session );
      span += types[i].getColumnSpansession.getFactory() );
    }
    return span;
  }

  /**
   * Bind named parameters to the <tt>PreparedStatement</tt>. This has an
   * empty implementation on this superclass and should be implemented by
   * subclasses (queries) which allow named parameters.
   */
  private int bindNamedParameters(final PreparedStatement ps,
      final Map namedParams, final int start,
      final SessionImplementor sessionthrows SQLException,
      HibernateException {

    if namedParams != null ) {
      // assumes that types are all of span 1
      Iterator iter = namedParams.entrySet().iterator();
      int result = 0;
      while iter.hasNext() ) {
        Map.Entry e = (Map.Entryiter.next();
        String name = (Stringe.getKey();
        TypedValue typedval = (TypedValuee.getValue();
        int[] locs = getNamedParameterLocsname );
        for (int i = 0; i < locs.length; i++) {
          if log.isDebugEnabled() ) {
            log.debug"bindNamedParameters() "
                + typedval.getValue() " -> " + name + " ["
                (locs[i+ start "]" );
          }
          typedval.getType().nullSafeSetps, typedval.getValue(),
              locs[i+ start, session );
        }
        result += locs.length;
      }
      return result;
    }
    else {
      return 0;
    }
  }

  protected void coordinateSharedCacheCleanup(SessionImplementor session) {
    BulkOperationCleanupAction action = new BulkOperationCleanupActionsession, getCustomQuery().getQuerySpaces() );

    action.init();

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

  public int performExecuteUpdate(QueryParameters queryParameters,
      SessionImplementor sessionthrows HibernateException {
    
    coordinateSharedCacheCleanupsession );
    
    if(queryParameters.isCallable()) {
      throw new IllegalArgumentException("callable not yet supported for native queries");
    }
    
    int result = 0;
    PreparedStatement ps;
    try {
      queryParameters.processFiltersthis.customQuery.getSQL(),
          session );
      String sql = queryParameters.getFilteredSQL();

      ps = session.getBatcher().prepareStatementsql );

      try {
        int col = 1;
        col += bindPositionalParametersps, queryParameters, col,
            session );
        col += bindNamedParametersps, queryParameters
            .getNamedParameters(), col, session );
        result = ps.executeUpdate();
      }
      finally {
        if ps != null ) {
          session.getBatcher().closeStatementps );
        }        
      }      
    }
    catch (SQLException sqle) {
      throw JDBCExceptionHelper.convertsession.getFactory()
          .getSQLExceptionConverter(), sqle,
          "could not execute native bulk manipulation query"this.sourceQuery );
    }

    return result;
  }
  
}