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

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