Home » hibernate-entitymanager-3.3.2.GA » org.hibernate » engine » query » [javadoc | source]
    1   package org.hibernate.engine.query;
    2   
    3   import org.hibernate.hql.QuerySplitter;
    4   import org.hibernate.hql.QueryTranslator;
    5   import org.hibernate.hql.ParameterTranslations;
    6   import org.hibernate.hql.FilterTranslator;
    7   import org.hibernate.util.ArrayHelper;
    8   import org.hibernate.util.EmptyIterator;
    9   import org.hibernate.util.JoinedIterator;
   10   import org.hibernate.util.IdentitySet;
   11   import org.hibernate.HibernateException;
   12   import org.hibernate.ScrollableResults;
   13   import org.hibernate.QueryException;
   14   import org.hibernate.type.Type;
   15   import org.hibernate.engine.SessionFactoryImplementor;
   16   import org.hibernate.engine.QueryParameters;
   17   import org.hibernate.engine.SessionImplementor;
   18   import org.hibernate.engine.RowSelection;
   19   import org.hibernate.event.EventSource;
   20   import org.apache.commons.logging.Log;
   21   import org.apache.commons.logging.LogFactory;
   22   
   23   import java.io.Serializable;
   24   import java.util.Map;
   25   import java.util.Set;
   26   import java.util.HashSet;
   27   import java.util.List;
   28   import java.util.ArrayList;
   29   import java.util.Iterator;
   30   import java.util.HashMap;
   31   
   32   /**
   33    * Defines a query execution plan for an HQL query (or filter).
   34    *
   35    * @author <a href="mailto:steve@hibernate.org">Steve Ebersole </a>
   36    */
   37   public class HQLQueryPlan implements Serializable {
   38   
   39   	// TODO : keep seperate notions of QT[] here for shallow/non-shallow queries...
   40   
   41   	private static final Log log = LogFactory.getLog( HQLQueryPlan.class );
   42   
   43   	private final String sourceQuery;
   44   	private final QueryTranslator[] translators;
   45   	private final String[] sqlStrings;
   46   
   47   	private final ParameterMetadata parameterMetadata;
   48   	private final ReturnMetadata returnMetadata;
   49   	private final Set querySpaces;
   50   
   51   	private final Set enabledFilterNames;
   52   	private final boolean shallow;
   53   
   54   
   55   	public HQLQueryPlan(String hql, boolean shallow, Map enabledFilters, SessionFactoryImplementor factory) {
   56   		this( hql, null, shallow, enabledFilters, factory );
   57   	}
   58   
   59   	protected HQLQueryPlan(String hql, String collectionRole, boolean shallow, Map enabledFilters, SessionFactoryImplementor factory) {
   60   		this.sourceQuery = hql;
   61   		this.shallow = shallow;
   62   
   63   		Set copy = new HashSet();
   64   		copy.addAll( enabledFilters.keySet() );
   65   		this.enabledFilterNames = java.util.Collections.unmodifiableSet( copy );
   66   
   67   		Set combinedQuerySpaces = new HashSet();
   68   		String[] concreteQueryStrings = QuerySplitter.concreteQueries( hql, factory );
   69   		final int length = concreteQueryStrings.length;
   70   		translators = new QueryTranslator[length];
   71   		List sqlStringList = new ArrayList();
   72   		for ( int i=0; i<length; i++ ) {
   73   			if ( collectionRole == null ) {
   74   				translators[i] = factory.getSettings()
   75   						.getQueryTranslatorFactory()
   76   						.createQueryTranslator( hql, concreteQueryStrings[i], enabledFilters, factory );
   77   				translators[i].compile( factory.getSettings().getQuerySubstitutions(), shallow );
   78   			}
   79   			else {
   80   				translators[i] = factory.getSettings()
   81   						.getQueryTranslatorFactory()
   82   						.createFilterTranslator( hql, concreteQueryStrings[i], enabledFilters, factory );
   83   				( ( FilterTranslator ) translators[i] ).compile( collectionRole, factory.getSettings().getQuerySubstitutions(), shallow );
   84   			}
   85   			combinedQuerySpaces.addAll( translators[i].getQuerySpaces() );
   86   			sqlStringList.addAll( translators[i].collectSqlStrings() );
   87   		}
   88   
   89   		this.sqlStrings = ArrayHelper.toStringArray( sqlStringList );
   90   		this.querySpaces = combinedQuerySpaces;
   91   
   92   		if ( length == 0 ) {
   93   			parameterMetadata = new ParameterMetadata( null, null );
   94   			returnMetadata = null;
   95   		}
   96   		else {
   97   			this.parameterMetadata = buildParameterMetadata( translators[0].getParameterTranslations(), hql );
   98   			if ( translators[0].isManipulationStatement() ) {
   99   				returnMetadata = null;
  100   			}
  101   			else {
  102   				if ( length > 1 ) {
  103   					final int returns = translators[0].getReturnTypes().length;
  104   					returnMetadata = new ReturnMetadata( translators[0].getReturnAliases(), new Type[returns] );
  105   				}
  106   				else {
  107   					returnMetadata = new ReturnMetadata( translators[0].getReturnAliases(), translators[0].getReturnTypes() );
  108   				}
  109   			}
  110   		}
  111   	}
  112   
  113   	public String getSourceQuery() {
  114   		return sourceQuery;
  115   	}
  116   
  117   	public Set getQuerySpaces() {
  118   		return querySpaces;
  119   	}
  120   
  121   	public ParameterMetadata getParameterMetadata() {
  122   		return parameterMetadata;
  123   	}
  124   
  125   	public ReturnMetadata getReturnMetadata() {
  126   		return returnMetadata;
  127   	}
  128   
  129   	public Set getEnabledFilterNames() {
  130   		return enabledFilterNames;
  131   	}
  132   
  133   	public String[] getSqlStrings() {
  134   		return sqlStrings;
  135   	}
  136   
  137   	public Set getUtilizedFilterNames() {
  138   		// TODO : add this info to the translator and aggregate it here...
  139   		return null;
  140   	}
  141   
  142   	public boolean isShallow() {
  143   		return shallow;
  144   	}
  145   
  146   	public List performList(
  147   			QueryParameters queryParameters,
  148   	        SessionImplementor session) throws HibernateException {
  149   		if ( log.isTraceEnabled() ) {
  150   			log.trace( "find: " + getSourceQuery() );
  151   			queryParameters.traceParameters( session.getFactory() );
  152   		}
  153   		boolean hasLimit = queryParameters.getRowSelection() != null &&
  154   		                   queryParameters.getRowSelection().definesLimits();
  155   		boolean needsLimit = hasLimit && translators.length > 1;
  156   		QueryParameters queryParametersToUse;
  157   		if ( needsLimit ) {
  158   			log.warn( "firstResult/maxResults specified on polymorphic query; applying in memory!" );
  159   			RowSelection selection = new RowSelection();
  160   			selection.setFetchSize( queryParameters.getRowSelection().getFetchSize() );
  161   			selection.setTimeout( queryParameters.getRowSelection().getTimeout() );
  162   			queryParametersToUse = queryParameters.createCopyUsing( selection );
  163   		}
  164   		else {
  165   			queryParametersToUse = queryParameters;
  166   		}
  167   
  168   		List combinedResults = new ArrayList();
  169   		IdentitySet distinction = new IdentitySet();
  170   		int includedCount = -1;
  171   		translator_loop: for ( int i = 0; i < translators.length; i++ ) {
  172   			List tmp = translators[i].list( session, queryParametersToUse );
  173   			if ( needsLimit ) {
  174   				// NOTE : firstRow is zero-based
  175   				int first = queryParameters.getRowSelection().getFirstRow() == null
  176   				            ? 0
  177   			                : queryParameters.getRowSelection().getFirstRow().intValue();
  178   				int max = queryParameters.getRowSelection().getMaxRows() == null
  179   				            ? -1
  180   			                : queryParameters.getRowSelection().getMaxRows().intValue();
  181   				final int size = tmp.size();
  182   				for ( int x = 0; x < size; x++ ) {
  183   					final Object result = tmp.get( x );
  184   					if ( distinction.add( result ) ) {
  185   						continue;
  186   					}
  187   					includedCount++;
  188   					if ( includedCount < first ) {
  189   						continue;
  190   					}
  191   					combinedResults.add( result );
  192   					if ( max >= 0 && includedCount > max ) {
  193   						// break the outer loop !!!
  194   						break translator_loop;
  195   					}
  196   				}
  197   			}
  198   			else {
  199   				combinedResults.addAll( tmp );
  200   			}
  201   		}
  202   		return combinedResults;
  203   	}
  204   
  205   	public Iterator performIterate(
  206   			QueryParameters queryParameters,
  207   	        EventSource session) throws HibernateException {
  208   		if ( log.isTraceEnabled() ) {
  209   			log.trace( "iterate: " + getSourceQuery() );
  210   			queryParameters.traceParameters( session.getFactory() );
  211   		}
  212   		if ( translators.length == 0 ) {
  213   			return EmptyIterator.INSTANCE;
  214   		}
  215   
  216   		Iterator[] results = null;
  217   		boolean many = translators.length > 1;
  218   		if (many) {
  219   			results = new Iterator[translators.length];
  220   		}
  221   
  222   		Iterator result = null;
  223   		for ( int i = 0; i < translators.length; i++ ) {
  224   			result = translators[i].iterate( queryParameters, session );
  225   			if (many) results[i] = result;
  226   		}
  227   
  228   		return many ? new JoinedIterator(results) : result;
  229   	}
  230   
  231   	public ScrollableResults performScroll(
  232   			QueryParameters queryParameters,
  233   	        SessionImplementor session) throws HibernateException {
  234   		if ( log.isTraceEnabled() ) {
  235   			log.trace( "iterate: " + getSourceQuery() );
  236   			queryParameters.traceParameters( session.getFactory() );
  237   		}
  238   		if ( translators.length != 1 ) {
  239   			throw new QueryException( "implicit polymorphism not supported for scroll() queries" );
  240   		}
  241   		if ( queryParameters.getRowSelection().definesLimits() && translators[0].containsCollectionFetches() ) {
  242   			throw new QueryException( "firstResult/maxResults not supported in conjunction with scroll() of a query containing collection fetches" );
  243   		}
  244   
  245   		return translators[0].scroll( queryParameters, session );
  246   	}
  247   
  248   	public int performExecuteUpdate(QueryParameters queryParameters, SessionImplementor session)
  249   			throws HibernateException {
  250   		if ( log.isTraceEnabled() ) {
  251   			log.trace( "executeUpdate: " + getSourceQuery() );
  252   			queryParameters.traceParameters( session.getFactory() );
  253   		}
  254   		if ( translators.length != 1 ) {
  255   			log.warn( "manipulation query [" + getSourceQuery() + "] resulted in [" + translators.length + "] split queries" );
  256   		}
  257   		int result = 0;
  258   		for ( int i = 0; i < translators.length; i++ ) {
  259   			result += translators[i].executeUpdate( queryParameters, session );
  260   		}
  261   		return result;
  262   	}
  263   
  264   	private ParameterMetadata buildParameterMetadata(ParameterTranslations parameterTranslations, String hql) {
  265   		long start = System.currentTimeMillis();
  266   		ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( hql );
  267   		long end = System.currentTimeMillis();
  268   		if ( log.isTraceEnabled() ) {
  269   			log.trace( "HQL param location recognition took " + (end - start) + " mills (" + hql + ")" );
  270   		}
  271   
  272   		int ordinalParamCount = parameterTranslations.getOrdinalParameterCount();
  273   		int[] locations = ArrayHelper.toIntArray( recognizer.getOrdinalParameterLocationList() );
  274   		if ( parameterTranslations.supportsOrdinalParameterMetadata() && locations.length != ordinalParamCount ) {
  275   			throw new HibernateException( "ordinal parameter mismatch" );
  276   		}
  277   		ordinalParamCount = locations.length;
  278   		OrdinalParameterDescriptor[] ordinalParamDescriptors = new OrdinalParameterDescriptor[ordinalParamCount];
  279   		for ( int i = 1; i <= ordinalParamCount; i++ ) {
  280   			ordinalParamDescriptors[ i - 1 ] = new OrdinalParameterDescriptor(
  281   					i,
  282   			        parameterTranslations.supportsOrdinalParameterMetadata()
  283   		                    ? parameterTranslations.getOrdinalParameterExpectedType( i )
  284   		                    : null,
  285   			        locations[ i - 1 ]
  286   			);
  287   		}
  288   
  289   		Iterator itr = recognizer.getNamedParameterLocationMap().entrySet().iterator();
  290   		Map namedParamDescriptorMap = new HashMap();
  291   		while( itr.hasNext() ) {
  292   			final Map.Entry entry = ( Map.Entry ) itr.next();
  293   			final String name = ( String ) entry.getKey();
  294   			final int[] locArray = ArrayHelper.toIntArray( ( List ) entry.getValue() );
  295   			namedParamDescriptorMap.put(
  296   					name,
  297   					new NamedParameterDescriptor(
  298   							name,
  299   					        parameterTranslations.getNamedParameterExpectedType( name ),
  300   					        locArray
  301   					)
  302   			);
  303   		}
  304   
  305   		return new ParameterMetadata( ordinalParamDescriptors, namedParamDescriptorMap );
  306   	}
  307   
  308   	public QueryTranslator[] getTranslators() {
  309   		QueryTranslator[] copy = new QueryTranslator[translators.length];
  310   		System.arraycopy(translators, 0, copy, 0, copy.length);
  311   		return copy;
  312   	}
  313   }

Save This Page
Home » hibernate-entitymanager-3.3.2.GA » org.hibernate » engine » query » [javadoc | source]