Save This Page
Home » Hibernate-3.3.2.GA » org.hibernate » hql » classic » [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.hql.classic;
   26   
   27   import java.io.Serializable;
   28   import java.lang.reflect.Constructor;
   29   import java.sql.PreparedStatement;
   30   import java.sql.ResultSet;
   31   import java.sql.SQLException;
   32   import java.util.ArrayList;
   33   import java.util.HashMap;
   34   import java.util.HashSet;
   35   import java.util.Iterator;
   36   import java.util.LinkedHashMap;
   37   import java.util.List;
   38   import java.util.Map;
   39   import java.util.Set;
   40   
   41   import org.slf4j.Logger;
   42   import org.slf4j.LoggerFactory;
   43   
   44   import org.hibernate.HibernateException;
   45   import org.hibernate.LockMode;
   46   import org.hibernate.MappingException;
   47   import org.hibernate.QueryException;
   48   import org.hibernate.ScrollableResults;
   49   import org.hibernate.dialect.Dialect;
   50   import org.hibernate.engine.JoinSequence;
   51   import org.hibernate.engine.QueryParameters;
   52   import org.hibernate.engine.SessionFactoryImplementor;
   53   import org.hibernate.engine.SessionImplementor;
   54   import org.hibernate.event.EventSource;
   55   import org.hibernate.exception.JDBCExceptionHelper;
   56   import org.hibernate.hql.FilterTranslator;
   57   import org.hibernate.hql.HolderInstantiator;
   58   import org.hibernate.hql.NameGenerator;
   59   import org.hibernate.hql.ParameterTranslations;
   60   import org.hibernate.impl.IteratorImpl;
   61   import org.hibernate.loader.BasicLoader;
   62   import org.hibernate.persister.collection.CollectionPersister;
   63   import org.hibernate.persister.collection.QueryableCollection;
   64   import org.hibernate.persister.entity.Loadable;
   65   import org.hibernate.persister.entity.PropertyMapping;
   66   import org.hibernate.persister.entity.Queryable;
   67   import org.hibernate.sql.JoinFragment;
   68   import org.hibernate.sql.QuerySelect;
   69   import org.hibernate.transform.ResultTransformer;
   70   import org.hibernate.type.AssociationType;
   71   import org.hibernate.type.EntityType;
   72   import org.hibernate.type.Type;
   73   import org.hibernate.type.TypeFactory;
   74   import org.hibernate.util.ArrayHelper;
   75   import org.hibernate.util.ReflectHelper;
   76   import org.hibernate.util.StringHelper;
   77   
   78   /**
   79    * An instance of <tt>QueryTranslator</tt> translates a Hibernate
   80    * query string to SQL.
   81    */
   82   public class QueryTranslatorImpl extends BasicLoader implements FilterTranslator {
   83   
   84   	private static final String[] NO_RETURN_ALIASES = new String[] {};
   85   
   86   	private final String queryIdentifier;
   87   	private final String queryString;
   88   
   89   	private final Map typeMap = new LinkedHashMap();
   90   	private final Map collections = new LinkedHashMap();
   91   	private List returnedTypes = new ArrayList();
   92   	private final List fromTypes = new ArrayList();
   93   	private final List scalarTypes = new ArrayList();
   94   	private final Map namedParameters = new HashMap();
   95   	private final Map aliasNames = new HashMap();
   96   	private final Map oneToOneOwnerNames = new HashMap();
   97   	private final Map uniqueKeyOwnerReferences = new HashMap();
   98   	private final Map decoratedPropertyMappings = new HashMap();
   99   
  100   	private final List scalarSelectTokens = new ArrayList();
  101   	private final List whereTokens = new ArrayList();
  102   	private final List havingTokens = new ArrayList();
  103   	private final Map joins = new LinkedHashMap();
  104   	private final List orderByTokens = new ArrayList();
  105   	private final List groupByTokens = new ArrayList();
  106   	private final Set querySpaces = new HashSet();
  107   	private final Set entitiesToFetch = new HashSet();
  108   
  109   	private final Map pathAliases = new HashMap();
  110   	private final Map pathJoins = new HashMap();
  111   
  112   	private Queryable[] persisters;
  113   	private int[] owners;
  114   	private EntityType[] ownerAssociationTypes;
  115   	private String[] names;
  116   	private boolean[] includeInSelect;
  117   	private int selectLength;
  118   	private Type[] returnTypes;
  119   	private Type[] actualReturnTypes;
  120   	private String[][] scalarColumnNames;
  121   	private Map tokenReplacements;
  122   	private int nameCount = 0;
  123   	private int parameterCount = 0;
  124   	private boolean distinct = false;
  125   	private boolean compiled;
  126   	private String sqlString;
  127   	private Class holderClass;
  128   	private Constructor holderConstructor;
  129   	private boolean hasScalars;
  130   	private boolean shallowQuery;
  131   	private QueryTranslatorImpl superQuery;
  132   
  133   	private QueryableCollection collectionPersister;
  134   	private int collectionOwnerColumn = -1;
  135   	private String collectionOwnerName;
  136   	private String fetchName;
  137   
  138   	private String[] suffixes;
  139   
  140   	private Map enabledFilters;
  141   
  142   	private static final Logger log = LoggerFactory.getLogger( QueryTranslatorImpl.class );
  143   
  144   	/**
  145   	 * Construct a query translator
  146   	 *
  147   	 * @param queryIdentifier A unique identifier for the query of which this
  148   	 * translation is part; typically this is the original, user-supplied query string.
  149   	 * @param queryString The "preprocessed" query string; at the very least
  150   	 * already processed by {@link org.hibernate.hql.QuerySplitter}.
  151   	 * @param enabledFilters Any enabled filters.
  152   	 * @param factory The session factory.
  153   	 */
  154   	public QueryTranslatorImpl(
  155   			String queryIdentifier,
  156   	        String queryString,
  157   	        Map enabledFilters,
  158   	        SessionFactoryImplementor factory) {
  159   		super( factory );
  160   		this.queryIdentifier = queryIdentifier;
  161   		this.queryString = queryString;
  162   		this.enabledFilters = enabledFilters;
  163   	}
  164   
  165   	/**
  166   	 * Construct a query translator; this form used internally.
  167   	 *
  168   	 * @param queryString The query string to process.
  169   	 * @param enabledFilters Any enabled filters.
  170   	 * @param factory The session factory.
  171   	 */
  172   	public QueryTranslatorImpl(
  173   	        String queryString,
  174   	        Map enabledFilters,
  175   	        SessionFactoryImplementor factory) {
  176   		this( queryString, queryString, enabledFilters, factory );
  177   	}
  178   
  179   	/**
  180   	 * Compile a subquery.
  181   	 *
  182   	 * @param superquery The containing query of the query to be compiled.
  183   	 *
  184   	 * @throws org.hibernate.MappingException Indicates problems resolving
  185   	 * things referenced in the query.
  186   	 * @throws org.hibernate.QueryException Generally some form of syntatic
  187   	 * failure.
  188   	 */
  189   	void compile(QueryTranslatorImpl superquery) throws QueryException, MappingException {
  190   		this.tokenReplacements = superquery.tokenReplacements;
  191   		this.superQuery = superquery;
  192   		this.shallowQuery = true;
  193   		this.enabledFilters = superquery.getEnabledFilters();
  194   		compile();
  195   	}
  196   
  197   
  198   	/**
  199   	 * Compile a "normal" query. This method may be called multiple
  200   	 * times. Subsequent invocations are no-ops.
  201   	 */
  202   	public synchronized void compile(
  203   			Map replacements,
  204   			boolean scalar) throws QueryException, MappingException {
  205   		if ( !compiled ) {
  206   			this.tokenReplacements = replacements;
  207   			this.shallowQuery = scalar;
  208   			compile();
  209   		}
  210   	}
  211   
  212   	/**
  213   	 * Compile a filter. This method may be called multiple
  214   	 * times. Subsequent invocations are no-ops.
  215   	 */
  216   	public synchronized void compile(
  217   			String collectionRole,
  218   			Map replacements,
  219   			boolean scalar) throws QueryException, MappingException {
  220   
  221   		if ( !isCompiled() ) {
  222   			addFromAssociation( "this", collectionRole );
  223   			compile( replacements, scalar );
  224   		}
  225   	}
  226   
  227   	/**
  228   	 * Compile the query (generate the SQL).
  229   	 *
  230   	 * @throws org.hibernate.MappingException Indicates problems resolving
  231   	 * things referenced in the query.
  232   	 * @throws org.hibernate.QueryException Generally some form of syntatic
  233   	 * failure.
  234   	 */
  235   	private void compile() throws QueryException, MappingException {
  236   
  237   		log.trace( "compiling query" );
  238   		try {
  239   			ParserHelper.parse( new PreprocessingParser( tokenReplacements ),
  240   					queryString,
  241   					ParserHelper.HQL_SEPARATORS,
  242   					this );
  243   			renderSQL();
  244   		}
  245   		catch ( QueryException qe ) {
  246   			qe.setQueryString( queryString );
  247   			throw qe;
  248   		}
  249   		catch ( MappingException me ) {
  250   			throw me;
  251   		}
  252   		catch ( Exception e ) {
  253   			log.debug( "unexpected query compilation problem", e );
  254   			e.printStackTrace();
  255   			QueryException qe = new QueryException( "Incorrect query syntax", e );
  256   			qe.setQueryString( queryString );
  257   			throw qe;
  258   		}
  259   
  260   		postInstantiate();
  261   
  262   		compiled = true;
  263   
  264   	}
  265   
  266   	public String getSQLString() {
  267   		return sqlString;
  268   	}
  269   
  270   	public List collectSqlStrings() {
  271   		return ArrayHelper.toList( new String[] { sqlString } );
  272   	}
  273   
  274   	public String getQueryString() {
  275   		return queryString;
  276   	}
  277   
  278   	/**
  279   	 * Persisters for the return values of a <tt>find()</tt> style query.
  280   	 *
  281   	 * @return an array of <tt>EntityPersister</tt>s.
  282   	 */
  283   	protected Loadable[] getEntityPersisters() {
  284   		return persisters;
  285   	}
  286   
  287   	/**
  288   	 * Types of the return values of an <tt>iterate()</tt> style query.
  289   	 *
  290   	 * @return an array of <tt>Type</tt>s.
  291   	 */
  292   	public Type[] getReturnTypes() {
  293   		return actualReturnTypes;
  294   	}
  295   	
  296   	public String[] getReturnAliases() {
  297   		// return aliases not supported in classic translator!
  298   		return NO_RETURN_ALIASES;
  299   	}
  300   
  301   	public String[][] getColumnNames() {
  302   		return scalarColumnNames;
  303   	}
  304   
  305   	private static void logQuery(String hql, String sql) {
  306   		if ( log.isDebugEnabled() ) {
  307   			log.debug( "HQL: " + hql );
  308   			log.debug( "SQL: " + sql );
  309   		}
  310   	}
  311   
  312   	void setAliasName(String alias, String name) {
  313   		aliasNames.put( alias, name );
  314   	}
  315   
  316   	public String getAliasName(String alias) {
  317   		String name = ( String ) aliasNames.get( alias );
  318   		if ( name == null ) {
  319   			if ( superQuery != null ) {
  320   				name = superQuery.getAliasName( alias );
  321   			}
  322   			else {
  323   				name = alias;
  324   			}
  325   		}
  326   		return name;
  327   	}
  328   
  329   	String unalias(String path) {
  330   		String alias = StringHelper.root( path );
  331   		String name = getAliasName( alias );
  332   		if ( name != null ) {
  333   			return name + path.substring( alias.length() );
  334   		}
  335   		else {
  336   			return path;
  337   		}
  338   	}
  339   
  340   	void addEntityToFetch(String name, String oneToOneOwnerName, AssociationType ownerAssociationType) {
  341   		addEntityToFetch( name );
  342   		if ( oneToOneOwnerName != null ) oneToOneOwnerNames.put( name, oneToOneOwnerName );
  343   		if ( ownerAssociationType != null ) uniqueKeyOwnerReferences.put( name, ownerAssociationType );
  344   	}
  345   
  346   	private void addEntityToFetch(String name) {
  347   		entitiesToFetch.add( name );
  348   	}
  349   
  350   	private int nextCount() {
  351   		return ( superQuery == null ) ? nameCount++ : superQuery.nameCount++;
  352   	}
  353   
  354   	String createNameFor(String type) {
  355   		return StringHelper.generateAlias( type, nextCount() );
  356   	}
  357   
  358   	String createNameForCollection(String role) {
  359   		return StringHelper.generateAlias( role, nextCount() );
  360   	}
  361   
  362   	private String getType(String name) {
  363   		String type = ( String ) typeMap.get( name );
  364   		if ( type == null && superQuery != null ) {
  365   			type = superQuery.getType( name );
  366   		}
  367   		return type;
  368   	}
  369   
  370   	private String getRole(String name) {
  371   		String role = ( String ) collections.get( name );
  372   		if ( role == null && superQuery != null ) {
  373   			role = superQuery.getRole( name );
  374   		}
  375   		return role;
  376   	}
  377   
  378   	boolean isName(String name) {
  379   		return aliasNames.containsKey( name ) ||
  380   				typeMap.containsKey( name ) ||
  381   				collections.containsKey( name ) || (
  382   				superQuery != null && superQuery.isName( name )
  383   				);
  384   	}
  385   
  386   	PropertyMapping getPropertyMapping(String name) throws QueryException {
  387   		PropertyMapping decorator = getDecoratedPropertyMapping( name );
  388   		if ( decorator != null ) return decorator;
  389   
  390   		String type = getType( name );
  391   		if ( type == null ) {
  392   			String role = getRole( name );
  393   			if ( role == null ) {
  394   				throw new QueryException( "alias not found: " + name );
  395   			}
  396   			return getCollectionPersister( role ); //.getElementPropertyMapping();
  397   		}
  398   		else {
  399   			Queryable persister = getEntityPersister( type );
  400   			if ( persister == null ) throw new QueryException( "persistent class not found: " + type );
  401   			return persister;
  402   		}
  403   	}
  404   
  405   	private PropertyMapping getDecoratedPropertyMapping(String name) {
  406   		return ( PropertyMapping ) decoratedPropertyMappings.get( name );
  407   	}
  408   
  409   	void decoratePropertyMapping(String name, PropertyMapping mapping) {
  410   		decoratedPropertyMappings.put( name, mapping );
  411   	}
  412   
  413   	private Queryable getEntityPersisterForName(String name) throws QueryException {
  414   		String type = getType( name );
  415   		Queryable persister = getEntityPersister( type );
  416   		if ( persister == null ) throw new QueryException( "persistent class not found: " + type );
  417   		return persister;
  418   	}
  419   
  420   	Queryable getEntityPersisterUsingImports(String className) {
  421   		final String importedClassName = getFactory().getImportedClassName( className );
  422   		if ( importedClassName == null ) {
  423   			return null;
  424   		}
  425   		try {
  426   			return ( Queryable ) getFactory().getEntityPersister( importedClassName );
  427   		}
  428   		catch ( MappingException me ) {
  429   			return null;
  430   		}
  431   	}
  432   
  433   	Queryable getEntityPersister(String entityName) throws QueryException {
  434   		try {
  435   			return ( Queryable ) getFactory().getEntityPersister( entityName );
  436   		}
  437   		catch ( Exception e ) {
  438   			throw new QueryException( "persistent class not found: " + entityName );
  439   		}
  440   	}
  441   
  442   	QueryableCollection getCollectionPersister(String role) throws QueryException {
  443   		try {
  444   			return ( QueryableCollection ) getFactory().getCollectionPersister( role );
  445   		}
  446   		catch ( ClassCastException cce ) {
  447   			throw new QueryException( "collection role is not queryable: " + role );
  448   		}
  449   		catch ( Exception e ) {
  450   			throw new QueryException( "collection role not found: " + role );
  451   		}
  452   	}
  453   
  454   	void addType(String name, String type) {
  455   		typeMap.put( name, type );
  456   	}
  457   
  458   	void addCollection(String name, String role) {
  459   		collections.put( name, role );
  460   	}
  461   
  462   	void addFrom(String name, String type, JoinSequence joinSequence)
  463   			throws QueryException {
  464   		addType( name, type );
  465   		addFrom( name, joinSequence );
  466   	}
  467   
  468   	void addFromCollection(String name, String collectionRole, JoinSequence joinSequence)
  469   			throws QueryException {
  470   		//register collection role
  471   		addCollection( name, collectionRole );
  472   		addJoin( name, joinSequence );
  473   	}
  474   
  475   	void addFrom(String name, JoinSequence joinSequence)
  476   			throws QueryException {
  477   		fromTypes.add( name );
  478   		addJoin( name, joinSequence );
  479   	}
  480   
  481   	void addFromClass(String name, Queryable classPersister)
  482   			throws QueryException {
  483   		JoinSequence joinSequence = new JoinSequence( getFactory() )
  484   				.setRoot( classPersister, name );
  485   		//crossJoins.add(name);
  486   		addFrom( name, classPersister.getEntityName(), joinSequence );
  487   	}
  488   
  489   	void addSelectClass(String name) {
  490   		returnedTypes.add( name );
  491   	}
  492   
  493   	void addSelectScalar(Type type) {
  494   		scalarTypes.add( type );
  495   	}
  496   
  497   	void appendWhereToken(String token) {
  498   		whereTokens.add( token );
  499   	}
  500   
  501   	void appendHavingToken(String token) {
  502   		havingTokens.add( token );
  503   	}
  504   
  505   	void appendOrderByToken(String token) {
  506   		orderByTokens.add( token );
  507   	}
  508   
  509   	void appendGroupByToken(String token) {
  510   		groupByTokens.add( token );
  511   	}
  512   
  513   	void appendScalarSelectToken(String token) {
  514   		scalarSelectTokens.add( token );
  515   	}
  516   
  517   	void appendScalarSelectTokens(String[] tokens) {
  518   		scalarSelectTokens.add( tokens );
  519   	}
  520   
  521   	void addFromJoinOnly(String name, JoinSequence joinSequence) throws QueryException {
  522   		addJoin( name, joinSequence.getFromPart() );
  523   	}
  524   
  525   	void addJoin(String name, JoinSequence joinSequence) throws QueryException {
  526   		if ( !joins.containsKey( name ) ) joins.put( name, joinSequence );
  527   	}
  528   
  529   	void addNamedParameter(String name) {
  530   		if ( superQuery != null ) superQuery.addNamedParameter( name );
  531   		Integer loc = new Integer( parameterCount++ );
  532   		Object o = namedParameters.get( name );
  533   		if ( o == null ) {
  534   			namedParameters.put( name, loc );
  535   		}
  536   		else if ( o instanceof Integer ) {
  537   			ArrayList list = new ArrayList( 4 );
  538   			list.add( o );
  539   			list.add( loc );
  540   			namedParameters.put( name, list );
  541   		}
  542   		else {
  543   			( ( ArrayList ) o ).add( loc );
  544   		}
  545   	}
  546   
  547   	public int[] getNamedParameterLocs(String name) throws QueryException {
  548   		Object o = namedParameters.get( name );
  549   		if ( o == null ) {
  550   			QueryException qe = new QueryException( ERROR_NAMED_PARAMETER_DOES_NOT_APPEAR + name );
  551   			qe.setQueryString( queryString );
  552   			throw qe;
  553   		}
  554   		if ( o instanceof Integer ) {
  555   			return new int[]{ ( ( Integer ) o ).intValue() };
  556   		}
  557   		else {
  558   			return ArrayHelper.toIntArray( ( ArrayList ) o );
  559   		}
  560   	}
  561   
  562   	private void renderSQL() throws QueryException, MappingException {
  563   
  564   		final int rtsize;
  565   		if ( returnedTypes.size() == 0 && scalarTypes.size() == 0 ) {
  566   			//ie no select clause in HQL
  567   			returnedTypes = fromTypes;
  568   			rtsize = returnedTypes.size();
  569   		}
  570   		else {
  571   			rtsize = returnedTypes.size();
  572   			Iterator iter = entitiesToFetch.iterator();
  573   			while ( iter.hasNext() ) {
  574   				returnedTypes.add( iter.next() );
  575   			}
  576   		}
  577   		int size = returnedTypes.size();
  578   		persisters = new Queryable[size];
  579   		names = new String[size];
  580   		owners = new int[size];
  581   		ownerAssociationTypes = new EntityType[size];
  582   		suffixes = new String[size];
  583   		includeInSelect = new boolean[size];
  584   		for ( int i = 0; i < size; i++ ) {
  585   			String name = ( String ) returnedTypes.get( i );
  586   			//if ( !isName(name) ) throw new QueryException("unknown type: " + name);
  587   			persisters[i] = getEntityPersisterForName( name );
  588   			// TODO: cannot use generateSuffixes() - it handles the initial suffix differently.
  589   			suffixes[i] = ( size == 1 ) ? "" : Integer.toString( i ) + '_';
  590   			names[i] = name;
  591   			includeInSelect[i] = !entitiesToFetch.contains( name );
  592   			if ( includeInSelect[i] ) selectLength++;
  593   			if ( name.equals( collectionOwnerName ) ) collectionOwnerColumn = i;
  594   			String oneToOneOwner = ( String ) oneToOneOwnerNames.get( name );
  595   			owners[i] = ( oneToOneOwner == null ) ? -1 : returnedTypes.indexOf( oneToOneOwner );
  596   			ownerAssociationTypes[i] = (EntityType) uniqueKeyOwnerReferences.get( name );
  597   		}
  598   
  599   		if ( ArrayHelper.isAllNegative( owners ) ) owners = null;
  600   
  601   		String scalarSelect = renderScalarSelect(); //Must be done here because of side-effect! yuck...
  602   
  603   		int scalarSize = scalarTypes.size();
  604   		hasScalars = scalarTypes.size() != rtsize;
  605   
  606   		returnTypes = new Type[scalarSize];
  607   		for ( int i = 0; i < scalarSize; i++ ) {
  608   			returnTypes[i] = ( Type ) scalarTypes.get( i );
  609   		}
  610   
  611   		QuerySelect sql = new QuerySelect( getFactory().getDialect() );
  612   		sql.setDistinct( distinct );
  613   
  614   		if ( !shallowQuery ) {
  615   			renderIdentifierSelect( sql );
  616   			renderPropertiesSelect( sql );
  617   		}
  618   
  619   		if ( collectionPersister != null ) {
  620   			sql.addSelectFragmentString( collectionPersister.selectFragment( fetchName, "__" ) );
  621   		}
  622   
  623   		if ( hasScalars || shallowQuery ) sql.addSelectFragmentString( scalarSelect );
  624   
  625   		//TODO: for some dialects it would be appropriate to add the renderOrderByPropertiesSelect() to other select strings
  626   		mergeJoins( sql.getJoinFragment() );
  627   
  628   		sql.setWhereTokens( whereTokens.iterator() );
  629   
  630   		sql.setGroupByTokens( groupByTokens.iterator() );
  631   		sql.setHavingTokens( havingTokens.iterator() );
  632   		sql.setOrderByTokens( orderByTokens.iterator() );
  633   
  634   		if ( collectionPersister != null && collectionPersister.hasOrdering() ) {
  635   			sql.addOrderBy( collectionPersister.getSQLOrderByString( fetchName ) );
  636   		}
  637   
  638   		scalarColumnNames = NameGenerator.generateColumnNames( returnTypes, getFactory() );
  639   
  640   		// initialize the Set of queried identifier spaces (ie. tables)
  641   		Iterator iter = collections.values().iterator();
  642   		while ( iter.hasNext() ) {
  643   			CollectionPersister p = getCollectionPersister( ( String ) iter.next() );
  644   			addQuerySpaces( p.getCollectionSpaces() );
  645   		}
  646   		iter = typeMap.keySet().iterator();
  647   		while ( iter.hasNext() ) {
  648   			Queryable p = getEntityPersisterForName( ( String ) iter.next() );
  649   			addQuerySpaces( p.getQuerySpaces() );
  650   		}
  651   
  652   		sqlString = sql.toQueryString();
  653   
  654   		if ( holderClass != null ) holderConstructor = ReflectHelper.getConstructor( holderClass, returnTypes );
  655   
  656   		if ( hasScalars ) {
  657   			actualReturnTypes = returnTypes;
  658   		}
  659   		else {
  660   			actualReturnTypes = new Type[selectLength];
  661   			int j = 0;
  662   			for ( int i = 0; i < persisters.length; i++ ) {
  663   				if ( includeInSelect[i] ) {
  664   					actualReturnTypes[j++] = TypeFactory.manyToOne( persisters[i].getEntityName(), shallowQuery );
  665   				}
  666   			}
  667   		}
  668   
  669   	}
  670   
  671   	private void renderIdentifierSelect(QuerySelect sql) {
  672   		int size = returnedTypes.size();
  673   
  674   		for ( int k = 0; k < size; k++ ) {
  675   			String name = ( String ) returnedTypes.get( k );
  676   			String suffix = size == 1 ? "" : Integer.toString( k ) + '_';
  677   			sql.addSelectFragmentString( persisters[k].identifierSelectFragment( name, suffix ) );
  678   		}
  679   
  680   	}
  681   
  682   	/*private String renderOrderByPropertiesSelect() {
  683   		StringBuffer buf = new StringBuffer(10);
  684   
  685   		//add the columns we are ordering by to the select ID select clause
  686   		Iterator iter = orderByTokens.iterator();
  687   		while ( iter.hasNext() ) {
  688   			String token = (String) iter.next();
  689   			if ( token.lastIndexOf(".") > 0 ) {
  690   				//ie. it is of form "foo.bar", not of form "asc" or "desc"
  691   				buf.append(StringHelper.COMMA_SPACE).append(token);
  692   			}
  693   		}
  694   
  695   		return buf.toString();
  696   	}*/
  697   
  698   	private void renderPropertiesSelect(QuerySelect sql) {
  699   		int size = returnedTypes.size();
  700   		for ( int k = 0; k < size; k++ ) {
  701   			String suffix = size == 1 ? "" : Integer.toString( k ) + '_';
  702   			String name = ( String ) returnedTypes.get( k );
  703   			sql.addSelectFragmentString( persisters[k].propertySelectFragment( name, suffix, false ) );
  704   		}
  705   	}
  706   
  707   	/**
  708   	 * WARNING: side-effecty
  709   	 */
  710   	private String renderScalarSelect() {
  711   
  712   		boolean isSubselect = superQuery != null;
  713   
  714   		StringBuffer buf = new StringBuffer( 20 );
  715   
  716   		if ( scalarTypes.size() == 0 ) {
  717   			//ie. no select clause
  718   			int size = returnedTypes.size();
  719   			for ( int k = 0; k < size; k++ ) {
  720   
  721   				scalarTypes.add( TypeFactory.manyToOne( persisters[k].getEntityName(), shallowQuery ) );
  722   
  723   				String[] idColumnNames = persisters[k].getIdentifierColumnNames();
  724   				for ( int i = 0; i < idColumnNames.length; i++ ) {
  725   					buf.append( returnedTypes.get( k ) ).append( '.' ).append( idColumnNames[i] );
  726   					if ( !isSubselect ) buf.append( " as " ).append( NameGenerator.scalarName( k, i ) );
  727   					if ( i != idColumnNames.length - 1 || k != size - 1 ) buf.append( ", " );
  728   				}
  729   
  730   			}
  731   
  732   		}
  733   		else {
  734   			//there _was_ a select clause
  735   			Iterator iter = scalarSelectTokens.iterator();
  736   			int c = 0;
  737   			boolean nolast = false; //real hacky...
  738   			int parenCount = 0; // used to count the nesting of parentheses
  739   			while ( iter.hasNext() ) {
  740   				Object next = iter.next();
  741   				if ( next instanceof String ) {
  742   					String token = ( String ) next;
  743   
  744   					if ( "(".equals( token ) ) {
  745   						parenCount++;
  746   					}
  747   					else if ( ")".equals( token ) ) {
  748   						parenCount--;
  749   					}
  750   
  751   					String lc = token.toLowerCase();
  752   					if ( lc.equals( ", " ) ) {
  753   						if ( nolast ) {
  754   							nolast = false;
  755   						}
  756   						else {
  757   							if ( !isSubselect && parenCount == 0 ) {
  758   								int x = c++;
  759   								buf.append( " as " )
  760   										.append( NameGenerator.scalarName( x, 0 ) );
  761   							}
  762   						}
  763   					}
  764   					buf.append( token );
  765   					if ( lc.equals( "distinct" ) || lc.equals( "all" ) ) {
  766   						buf.append( ' ' );
  767   					}
  768   				}
  769   				else {
  770   					nolast = true;
  771   					String[] tokens = ( String[] ) next;
  772   					for ( int i = 0; i < tokens.length; i++ ) {
  773   						buf.append( tokens[i] );
  774   						if ( !isSubselect ) {
  775   							buf.append( " as " )
  776   									.append( NameGenerator.scalarName( c, i ) );
  777   						}
  778   						if ( i != tokens.length - 1 ) buf.append( ", " );
  779   					}
  780   					c++;
  781   				}
  782   			}
  783   			if ( !isSubselect && !nolast ) {
  784   				int x = c++;
  785   				buf.append( " as " )
  786   						.append( NameGenerator.scalarName( x, 0 ) );
  787   			}
  788   
  789   		}
  790   
  791   		return buf.toString();
  792   	}
  793   
  794   	private void mergeJoins(JoinFragment ojf) throws MappingException, QueryException {
  795   
  796   		Iterator iter = joins.entrySet().iterator();
  797   		while ( iter.hasNext() ) {
  798   			Map.Entry me = ( Map.Entry ) iter.next();
  799   			String name = ( String ) me.getKey();
  800   			JoinSequence join = ( JoinSequence ) me.getValue();
  801   			join.setSelector( new JoinSequence.Selector() {
  802   				public boolean includeSubclasses(String alias) {
  803   					boolean include = returnedTypes.contains( alias ) && !isShallowQuery();
  804   					return include;
  805   				}
  806   			} );
  807   
  808   			if ( typeMap.containsKey( name ) ) {
  809   				ojf.addFragment( join.toJoinFragment( enabledFilters, true ) );
  810   			}
  811   			else if ( collections.containsKey( name ) ) {
  812   				ojf.addFragment( join.toJoinFragment( enabledFilters, true ) );
  813   			}
  814   			else {
  815   				//name from a super query (a bit inelegant that it shows up here)
  816   			}
  817   
  818   		}
  819   
  820   	}
  821   
  822   	public final Set getQuerySpaces() {
  823   		return querySpaces;
  824   	}
  825   
  826   	/**
  827   	 * Is this query called by scroll() or iterate()?
  828   	 *
  829   	 * @return true if it is, false if it is called by find() or list()
  830   	 */
  831   	boolean isShallowQuery() {
  832   		return shallowQuery;
  833   	}
  834   
  835   	void addQuerySpaces(Serializable[] spaces) {
  836   		for ( int i = 0; i < spaces.length; i++ ) {
  837   			querySpaces.add( spaces[i] );
  838   		}
  839   		if ( superQuery != null ) superQuery.addQuerySpaces( spaces );
  840   	}
  841   
  842   	void setDistinct(boolean distinct) {
  843   		this.distinct = distinct;
  844   	}
  845   
  846   	boolean isSubquery() {
  847   		return superQuery != null;
  848   	}
  849   
  850   	/**
  851   	 * Overrides method from Loader
  852   	 */
  853   	public CollectionPersister[] getCollectionPersisters() {
  854   		return collectionPersister == null ? null : new CollectionPersister[] { collectionPersister };
  855   	}
  856   
  857   	protected String[] getCollectionSuffixes() {
  858   		return collectionPersister == null ? null : new String[] { "__" };
  859   	}
  860   
  861   	void setCollectionToFetch(String role, String name, String ownerName, String entityName)
  862   			throws QueryException {
  863   		fetchName = name;
  864   		collectionPersister = getCollectionPersister( role );
  865   		collectionOwnerName = ownerName;
  866   		if ( collectionPersister.getElementType().isEntityType() ) {
  867   			addEntityToFetch( entityName );
  868   		}
  869   	}
  870   
  871   	protected String[] getSuffixes() {
  872   		return suffixes;
  873   	}
  874   
  875   	protected String[] getAliases() {
  876   		return names;
  877   	}
  878   
  879   	/**
  880   	 * Used for collection filters
  881   	 */
  882   	private void addFromAssociation(final String elementName, final String collectionRole)
  883   			throws QueryException {
  884   		//q.addCollection(collectionName, collectionRole);
  885   		QueryableCollection persister = getCollectionPersister( collectionRole );
  886   		Type collectionElementType = persister.getElementType();
  887   		if ( !collectionElementType.isEntityType() ) {
  888   			throw new QueryException( "collection of values in filter: " + elementName );
  889   		}
  890   
  891   		String[] keyColumnNames = persister.getKeyColumnNames();
  892   		//if (keyColumnNames.length!=1) throw new QueryException("composite-key collection in filter: " + collectionRole);
  893   
  894   		String collectionName;
  895   		JoinSequence join = new JoinSequence( getFactory() );
  896   		collectionName = persister.isOneToMany() ?
  897   				elementName :
  898   				createNameForCollection( collectionRole );
  899   		join.setRoot( persister, collectionName );
  900   		if ( !persister.isOneToMany() ) {
  901   			//many-to-many
  902   			addCollection( collectionName, collectionRole );
  903   			try {
  904   				join.addJoin( ( AssociationType ) persister.getElementType(),
  905   						elementName,
  906   						JoinFragment.INNER_JOIN,
  907   						persister.getElementColumnNames(collectionName) );
  908   			}
  909   			catch ( MappingException me ) {
  910   				throw new QueryException( me );
  911   			}
  912   		}
  913   		join.addCondition( collectionName, keyColumnNames, " = ?" );
  914   		//if ( persister.hasWhere() ) join.addCondition( persister.getSQLWhereString(collectionName) );
  915   		EntityType elemType = ( EntityType ) collectionElementType;
  916   		addFrom( elementName, elemType.getAssociatedEntityName(), join );
  917   
  918   	}
  919   
  920   	String getPathAlias(String path) {
  921   		return ( String ) pathAliases.get( path );
  922   	}
  923   
  924   	JoinSequence getPathJoin(String path) {
  925   		return ( JoinSequence ) pathJoins.get( path );
  926   	}
  927   
  928   	void addPathAliasAndJoin(String path, String alias, JoinSequence joinSequence) {
  929   		pathAliases.put( path, alias );
  930   		pathJoins.put( path, joinSequence );
  931   	}
  932   
  933   	public List list(SessionImplementor session, QueryParameters queryParameters)
  934   			throws HibernateException {
  935   		return list( session, queryParameters, getQuerySpaces(), actualReturnTypes );
  936   	}
  937   
  938   	/**
  939   	 * Return the query results as an iterator
  940   	 */
  941   	public Iterator iterate(QueryParameters queryParameters, EventSource session)
  942   			throws HibernateException {
  943   
  944   		boolean stats = session.getFactory().getStatistics().isStatisticsEnabled();
  945   		long startTime = 0;
  946   		if ( stats ) startTime = System.currentTimeMillis();
  947   
  948   		try {
  949   
  950   			PreparedStatement st = prepareQueryStatement( queryParameters, false, session );
  951   			ResultSet rs = getResultSet( st, queryParameters.hasAutoDiscoverScalarTypes(), false, queryParameters.getRowSelection(), session );
  952   			HolderInstantiator hi = HolderInstantiator.createClassicHolderInstantiator(holderConstructor, queryParameters.getResultTransformer());
  953   			Iterator result = new IteratorImpl( rs, st, session, returnTypes, getColumnNames(), hi );
  954   
  955   			if ( stats ) {
  956   				session.getFactory().getStatisticsImplementor().queryExecuted(
  957   						"HQL: " + queryString,
  958   						0,
  959   						System.currentTimeMillis() - startTime
  960   					);
  961   			}
  962   
  963   			return result;
  964   
  965   		}
  966   		catch ( SQLException sqle ) {
  967   			throw JDBCExceptionHelper.convert( 
  968   					getFactory().getSQLExceptionConverter(),
  969   					sqle,
  970   					"could not execute query using iterate",
  971   					getSQLString() 
  972   				);
  973   		}
  974   
  975   	}
  976   
  977   	public int executeUpdate(QueryParameters queryParameters, SessionImplementor session) throws HibernateException {
  978   		throw new UnsupportedOperationException( "Not supported!  Use the AST translator...");
  979   	}
  980   
  981   	protected Object getResultColumnOrRow(Object[] row, ResultTransformer transformer, ResultSet rs, SessionImplementor session)
  982   			throws SQLException, HibernateException {
  983   		row = toResultRow( row );
  984   		if ( hasScalars ) {
  985   			String[][] scalarColumns = getColumnNames();
  986   			int queryCols = returnTypes.length;
  987   			if ( holderClass == null && queryCols == 1 ) {
  988   				return returnTypes[0].nullSafeGet( rs, scalarColumns[0], session, null );
  989   			}
  990   			else {
  991   				row = new Object[queryCols];
  992   				for ( int i = 0; i < queryCols; i++ )
  993   					row[i] = returnTypes[i].nullSafeGet( rs, scalarColumns[i], session, null );
  994   				return row;
  995   			}
  996   		}
  997   		else if ( holderClass == null ) {
  998   			return row.length == 1 ? row[0] : row;
  999   		}
 1000   		else {
 1001   			return row;
 1002   		}
 1003   
 1004   	}
 1005   
 1006   	protected List getResultList(List results, ResultTransformer resultTransformer) throws QueryException {
 1007   		if ( holderClass != null ) {
 1008   			for ( int i = 0; i < results.size(); i++ ) {
 1009   				Object[] row = ( Object[] ) results.get( i );
 1010   				try {
 1011   					results.set( i, holderConstructor.newInstance( row ) );
 1012   				}
 1013   				catch ( Exception e ) {
 1014   					throw new QueryException( "could not instantiate: " + holderClass, e );
 1015   				}
 1016   			}
 1017   		}
 1018   		return results;
 1019   	}
 1020   
 1021   	private Object[] toResultRow(Object[] row) {
 1022   		if ( selectLength == row.length ) {
 1023   			return row;
 1024   		}
 1025   		else {
 1026   			Object[] result = new Object[selectLength];
 1027   			int j = 0;
 1028   			for ( int i = 0; i < row.length; i++ ) {
 1029   				if ( includeInSelect[i] ) result[j++] = row[i];
 1030   			}
 1031   			return result;
 1032   		}
 1033   	}
 1034   
 1035   	void setHolderClass(Class clazz) {
 1036   		holderClass = clazz;
 1037   	}
 1038   
 1039   	protected LockMode[] getLockModes(Map lockModes) {
 1040   		// unfortunately this stuff can't be cached because
 1041   		// it is per-invocation, not constant for the
 1042   		// QueryTranslator instance
 1043   		HashMap nameLockModes = new HashMap();
 1044   		if ( lockModes != null ) {
 1045   			Iterator iter = lockModes.entrySet().iterator();
 1046   			while ( iter.hasNext() ) {
 1047   				Map.Entry me = ( Map.Entry ) iter.next();
 1048   				nameLockModes.put( getAliasName( ( String ) me.getKey() ),
 1049   						me.getValue() );
 1050   			}
 1051   		}
 1052   		LockMode[] lockModeArray = new LockMode[names.length];
 1053   		for ( int i = 0; i < names.length; i++ ) {
 1054   			LockMode lm = ( LockMode ) nameLockModes.get( names[i] );
 1055   			if ( lm == null ) lm = LockMode.NONE;
 1056   			lockModeArray[i] = lm;
 1057   		}
 1058   		return lockModeArray;
 1059   	}
 1060   
 1061   	protected String applyLocks(String sql, Map lockModes, Dialect dialect) throws QueryException {
 1062   		// can't cache this stuff either (per-invocation)
 1063   		final String result;
 1064   		if ( lockModes == null || lockModes.size() == 0 ) {
 1065   			result = sql;
 1066   		}
 1067   		else {
 1068   			Map aliasedLockModes = new HashMap();
 1069   			Iterator iter = lockModes.entrySet().iterator();
 1070   			while ( iter.hasNext() ) {
 1071   				Map.Entry me = ( Map.Entry ) iter.next();
 1072   				aliasedLockModes.put( getAliasName( ( String ) me.getKey() ), me.getValue() );
 1073   			}
 1074   			Map keyColumnNames = null;
 1075   			if ( dialect.forUpdateOfColumns() ) {
 1076   				keyColumnNames = new HashMap();
 1077   				for ( int i = 0; i < names.length; i++ ) {
 1078   					keyColumnNames.put( names[i], persisters[i].getIdentifierColumnNames() );
 1079   				}
 1080   			}
 1081   			result = dialect.applyLocksToSql( sql, aliasedLockModes, keyColumnNames );
 1082   		}
 1083   		logQuery( queryString, result );
 1084   		return result;
 1085   	}
 1086   
 1087   	protected boolean upgradeLocks() {
 1088   		return true;
 1089   	}
 1090   
 1091   	protected int[] getCollectionOwners() {
 1092   		return new int[] { collectionOwnerColumn };
 1093   	}
 1094   
 1095   	protected boolean isCompiled() {
 1096   		return compiled;
 1097   	}
 1098   
 1099   	public String toString() {
 1100   		return queryString;
 1101   	}
 1102   
 1103   	protected int[] getOwners() {
 1104   		return owners;
 1105   	}
 1106   
 1107   	protected EntityType[] getOwnerAssociationTypes() {
 1108   		return ownerAssociationTypes;
 1109   	}
 1110   
 1111   	public Class getHolderClass() {
 1112   		return holderClass;
 1113   	}
 1114   
 1115   	public Map getEnabledFilters() {
 1116   		return enabledFilters;
 1117   	}
 1118   
 1119   	public ScrollableResults scroll(final QueryParameters queryParameters,
 1120   									final SessionImplementor session)
 1121   			throws HibernateException {
 1122   		HolderInstantiator hi = HolderInstantiator.createClassicHolderInstantiator(holderConstructor, queryParameters.getResultTransformer());
 1123   		return scroll( queryParameters, returnTypes, hi, session );
 1124   	}
 1125   
 1126   	public String getQueryIdentifier() {
 1127   		return queryIdentifier;
 1128   	}
 1129   
 1130   	protected boolean isSubselectLoadingEnabled() {
 1131   		return hasSubselectLoadableCollections();
 1132   	}
 1133   
 1134   	public void validateScrollability() throws HibernateException {
 1135   		// This is the legacy behaviour for HQL queries...
 1136   		if ( getCollectionPersisters() != null ) {
 1137   			throw new HibernateException( "Cannot scroll queries which initialize collections" );
 1138   		}
 1139   	}
 1140   
 1141   	public boolean containsCollectionFetches() {
 1142   		return false;
 1143   	}
 1144   
 1145   	public boolean isManipulationStatement() {
 1146   		// classic parser does not support bulk manipulation statements
 1147   		return false;
 1148   	}
 1149   
 1150   	public ParameterTranslations getParameterTranslations() {
 1151   		return new ParameterTranslations() {
 1152   
 1153   			public boolean supportsOrdinalParameterMetadata() {
 1154   				// classic translator does not support collection of ordinal
 1155   				// param metadata
 1156   				return false;
 1157   			}
 1158   
 1159   			public int getOrdinalParameterCount() {
 1160   				return 0; // not known!
 1161   			}
 1162   
 1163   			public int getOrdinalParameterSqlLocation(int ordinalPosition) {
 1164   				return 0; // not known!
 1165   			}
 1166   
 1167   			public Type getOrdinalParameterExpectedType(int ordinalPosition) {
 1168   				return null; // not known!
 1169   			}
 1170   
 1171   			public Set getNamedParameterNames() {
 1172   				return namedParameters.keySet();
 1173   			}
 1174   
 1175   			public int[] getNamedParameterSqlLocations(String name) {
 1176   				return getNamedParameterLocs( name );
 1177   			}
 1178   
 1179   			public Type getNamedParameterExpectedType(String name) {
 1180   				return null; // not known!
 1181   			}
 1182   		};
 1183   	}
 1184   }

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