KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hibernate > loader > hql > QueryLoader


1 // $Id: QueryLoader.java,v 1.19 2005/07/12 20:49:07 oneovthafew Exp $
2
package org.hibernate.loader.hql;
3
4 import java.sql.PreparedStatement JavaDoc;
5 import java.sql.ResultSet JavaDoc;
6 import java.sql.SQLException JavaDoc;
7 import java.util.HashMap JavaDoc;
8 import java.util.Iterator JavaDoc;
9 import java.util.List JavaDoc;
10 import java.util.Map JavaDoc;
11
12 import org.apache.commons.logging.Log;
13 import org.apache.commons.logging.LogFactory;
14 import org.hibernate.HibernateException;
15 import org.hibernate.LockMode;
16 import org.hibernate.QueryException;
17 import org.hibernate.ScrollableResults;
18 import org.hibernate.dialect.Dialect;
19 import org.hibernate.engine.QueryParameters;
20 import org.hibernate.engine.SessionFactoryImplementor;
21 import org.hibernate.engine.SessionImplementor;
22 import org.hibernate.engine.TypedValue;
23 import org.hibernate.event.EventSource;
24 import org.hibernate.exception.JDBCExceptionHelper;
25 import org.hibernate.hql.HolderInstantiator;
26 import org.hibernate.hql.QueryTranslator;
27 import org.hibernate.hql.ast.tree.FromElement;
28 import org.hibernate.hql.ast.tree.SelectClause;
29 import org.hibernate.impl.IteratorImpl;
30 import org.hibernate.loader.BasicLoader;
31 import org.hibernate.persister.collection.CollectionPersister;
32 import org.hibernate.persister.collection.QueryableCollection;
33 import org.hibernate.persister.entity.Loadable;
34 import org.hibernate.persister.entity.Queryable;
35 import org.hibernate.sql.ForUpdateFragment;
36 import org.hibernate.type.EntityType;
37 import org.hibernate.type.Type;
38 import org.hibernate.util.ArrayHelper;
39
40 /**
41  * A delegate that implements the Loader part of QueryTranslator.
42  * <p/>
43  * User: josh
44  * Date: Jan 3, 2004
45  * Time: 8:29:58 PM
46  */

47 public class QueryLoader extends BasicLoader {
48
49     private static final Log log = LogFactory.getLog( QueryLoader.class );
50     /**
51      * The query translator that is delegating to this object.
52      */

53     private QueryTranslator queryTranslator;
54
55     private Queryable[] entityPersisters;
56     private String JavaDoc[] entityAliases;
57     private String JavaDoc[] sqlAliases;
58     private String JavaDoc[] sqlAliasSuffixes;
59     private boolean[] includeInSelect;
60
61     private String JavaDoc[] collectionSuffixes;
62
63     private boolean hasScalars;
64     private String JavaDoc[][] scalarColumnNames;
65     //private Type[] sqlResultTypes;
66
private Type[] queryReturnTypes;
67     
68     private final Map JavaDoc sqlAliasByEntityAlias = new HashMap JavaDoc(8);
69
70     private EntityType[] ownerAssociationTypes;
71     private int[] owners;
72     private boolean[] entityEagerPropertyFetches;
73
74     private int[] collectionOwners;
75     private QueryableCollection[] collectionPersisters;
76
77     private int selectLength;
78     private HolderInstantiator holderInstantiator;
79     
80     private LockMode[] defaultLockModes;
81
82
83     /**
84      * Creates a new Loader implementation.
85      *
86      * @param queryTranslator The query translator that is the delegator.
87      * @param factory The factory from which this loader is being created.
88      */

89     public QueryLoader(final QueryTranslator queryTranslator,
90                        final SessionFactoryImplementor factory,
91                        final SelectClause selectClause) {
92         super( factory );
93         this.queryTranslator = queryTranslator;
94         initialize( selectClause );
95         postInstantiate();
96     }
97
98     private void initialize(SelectClause selectClause) {
99
100         List JavaDoc fromElementList = selectClause.getFromElementsForLoad();
101
102         hasScalars = selectClause.isScalarSelect();
103         scalarColumnNames = selectClause.getColumnNames();
104         //sqlResultTypes = selectClause.getSqlResultTypes();
105
queryReturnTypes = selectClause.getQueryReturnTypes();
106
107         holderInstantiator = new HolderInstantiator(
108                 selectClause.getConstructor(),
109                 selectClause.isMap(),
110                 selectClause.isList(),
111                 selectClause.getQueryReturnAliases()
112         );
113
114         List JavaDoc collectionFromElements = selectClause.getCollectionFromElements();
115         if ( collectionFromElements != null && collectionFromElements.size()!=0 ) {
116             int length = collectionFromElements.size();
117             collectionPersisters = new QueryableCollection[length];
118             collectionOwners = new int[length];
119             collectionSuffixes = new String JavaDoc[length];
120             for ( int i=0; i<length; i++ ) {
121                 FromElement collectionFromElement = (FromElement) collectionFromElements.get(i);
122                 collectionPersisters[i] = collectionFromElement.getQueryableCollection();
123                 collectionOwners[i] = fromElementList.indexOf( collectionFromElement.getOrigin() );
124 // collectionSuffixes[i] = collectionFromElement.getColumnAliasSuffix();
125
// collectionSuffixes[i] = Integer.toString( i ) + "_";
126
collectionSuffixes[i] = collectionFromElement.getCollectionSuffix();
127             }
128         }
129
130         int size = fromElementList.size();
131         entityPersisters = new Queryable[size];
132         entityEagerPropertyFetches = new boolean[size];
133         entityAliases = new String JavaDoc[size];
134         sqlAliases = new String JavaDoc[size];
135         sqlAliasSuffixes = new String JavaDoc[size];
136         includeInSelect = new boolean[size];
137         owners = new int[size];
138         ownerAssociationTypes = new EntityType[size];
139
140         for ( int i = 0; i < size; i++ ) {
141             final FromElement element = ( FromElement ) fromElementList.get( i );
142             entityPersisters[i] = ( Queryable ) element.getEntityPersister();
143
144             if ( entityPersisters[i] == null ) {
145                 throw new IllegalStateException JavaDoc( "No entity persister for " + element.toString() );
146             }
147             
148             entityEagerPropertyFetches[i] = element.isAllPropertyFetch();
149             sqlAliases[i] = element.getTableAlias();
150             entityAliases[i] = element.getClassAlias();
151             sqlAliasByEntityAlias.put( entityAliases[i], sqlAliases[i] );
152             // TODO should we just collect these like with the collections above?
153
sqlAliasSuffixes[i] = ( size == 1 ) ? "" : Integer.toString( i ) + "_";
154 // sqlAliasSuffixes[i] = element.getColumnAliasSuffix();
155
includeInSelect[i] = !element.isFetch();
156             if ( includeInSelect[i] ) selectLength++;
157             
158             owners[i] = -1; //by default
159
if ( element.isFetch() ) {
160                 if ( element.isCollectionJoin() || element.getQueryableCollection() != null ) {
161                     // This is now handled earlier in this method.
162
}
163                 else if ( element.getDataType().isEntityType() ) {
164                     EntityType entityType = ( EntityType ) element.getDataType();
165                     if ( entityType.isOneToOne() ) {
166                         owners[i] = fromElementList.indexOf( element.getOrigin() );
167                     }
168                     ownerAssociationTypes[i] = entityType;
169                 }
170             }
171         }
172         
173         //NONE, because its the requested lock mode, not the actual!
174
defaultLockModes = ArrayHelper.fillArray(LockMode.NONE, size);
175         
176     }
177
178     // -- Loader implementation --
179

180     public final void validateScrollability() throws HibernateException {
181         queryTranslator.validateScrollability();
182     }
183
184     protected boolean needsFecthingScroll() {
185         return queryTranslator.containsCollectionFetches();
186     }
187
188     public Loadable[] getEntityPersisters() {
189         return entityPersisters;
190     }
191
192     public String JavaDoc[] getAliases() {
193         return sqlAliases;
194     }
195
196     public String JavaDoc[] getSqlAliasSuffixes() {
197         return sqlAliasSuffixes;
198     }
199
200     public String JavaDoc[] getSuffixes() {
201         return getSqlAliasSuffixes();
202     }
203
204     public String JavaDoc[] getCollectionSuffixes() {
205         return collectionSuffixes;
206     }
207
208     protected String JavaDoc getQueryIdentifier() {
209         return queryTranslator.getQueryString();
210     }
211
212     /**
213      * The SQL query string to be called.
214      */

215     protected String JavaDoc getSQLString() {
216         return queryTranslator.getSQLString();
217     }
218
219     /**
220      * An (optional) persister for a collection to be initialized; only collection loaders
221      * return a non-null value
222      */

223     protected CollectionPersister[] getCollectionPersisters() {
224         return collectionPersisters;
225     }
226
227     protected int[] getCollectionOwners() {
228         return collectionOwners;
229     }
230
231     protected boolean[] getEntityEagerPropertyFetches() {
232         return entityEagerPropertyFetches;
233     }
234
235     /**
236      * An array of indexes of the entity that owns a one-to-one association
237      * to the entity at the given index (-1 if there is no "owner")
238      */

239     protected int[] getOwners() {
240         return owners;
241     }
242
243     protected EntityType[] getOwnerAssociationTypes() {
244         return ownerAssociationTypes;
245     }
246
247     // -- Loader overrides --
248

249     protected boolean isSubselectLoadingEnabled() {
250         return hasSubselectLoadableCollections();
251     }
252     
253     protected int bindNamedParameters(final PreparedStatement JavaDoc ps,
254                                       final Map JavaDoc namedParams,
255                                       final int start,
256                                       final SessionImplementor session)
257             throws SQLException JavaDoc, HibernateException {
258
259         if ( namedParams != null ) {
260             // assumes that types are all of span 1
261
Iterator JavaDoc iter = namedParams.entrySet().iterator();
262             int result = 0;
263             while ( iter.hasNext() ) {
264                 Map.Entry JavaDoc e = ( Map.Entry JavaDoc ) iter.next();
265                 String JavaDoc name = ( String JavaDoc ) e.getKey();
266                 TypedValue typedval = ( TypedValue ) e.getValue();
267                 int[] locs = getNamedParameterLocs( name );
268                 for ( int i = 0; i < locs.length; i++ ) {
269                     if ( log.isDebugEnabled() ) {
270                         log.debug( "bindNamedParameters() " +
271                                 typedval.getValue() + " -> " + name +
272                                 " [" + ( locs[i] + start ) + "]" );
273                     }
274                     typedval.getType().nullSafeSet( ps, typedval.getValue(), locs[i] + start, session );
275                 }
276                 result += locs.length;
277             }
278             return result;
279         }
280         else {
281             return 0;
282         }
283     }
284
285     /**
286      * @param lockModes a collection of lock modes specified dynamically via the Query interface
287      */

288     protected LockMode[] getLockModes(Map JavaDoc lockModes) {
289         
290         if ( lockModes==null || lockModes.size()==0 ) {
291             return defaultLockModes;
292         }
293         else {
294             // unfortunately this stuff can't be cached because
295
// it is per-invocation, not constant for the
296
// QueryTranslator instance
297

298             LockMode[] lockModeArray = new LockMode[entityAliases.length];
299             for ( int i = 0; i < entityAliases.length; i++ ) {
300                 LockMode lockMode = (LockMode) lockModes.get( entityAliases[i] );
301                 if ( lockMode == null ) {
302                     //NONE, because its the requested lock mode, not the actual!
303
lockMode = LockMode.NONE;
304                 }
305                 lockModeArray[i] = lockMode;
306             }
307             return lockModeArray;
308         }
309     }
310
311     protected String JavaDoc applyLocks(String JavaDoc sql, Map JavaDoc lockModes, Dialect dialect)
312             throws QueryException {
313
314         if ( lockModes == null || lockModes.size() == 0 ) {
315             return sql;
316         }
317         else {
318             // can't cache this stuff either (per-invocation)
319

320             //we are given a map of user alias -> lock mode
321
//create a new map of sql alias -> lock mode
322
final Map JavaDoc aliasedLockModes = new HashMap JavaDoc();
323             final Iterator JavaDoc iter = lockModes.entrySet().iterator();
324             while ( iter.hasNext() ) {
325                 Map.Entry JavaDoc me = ( Map.Entry JavaDoc ) iter.next();
326                 final String JavaDoc userAlias = ( String JavaDoc ) me.getKey();
327                 final String JavaDoc sqlAlias = (String JavaDoc) sqlAliasByEntityAlias.get( userAlias );
328                 if (sqlAlias==null) {
329                     throw new IllegalArgumentException JavaDoc("alias not found: " + userAlias);
330                 }
331                 aliasedLockModes.put( sqlAlias, me.getValue() );
332             }
333             
334             //if necessary, create a map of sql alias -> key columns
335
Map JavaDoc keyColumnNames = null;
336             if ( dialect.forUpdateOfColumns() ) {
337                 final Loadable[] persisters = getEntityPersisters();
338                 keyColumnNames = new HashMap JavaDoc();
339                 for ( int i = 0; i < sqlAliases.length; i++ ) {
340                     keyColumnNames.put( sqlAliases[i], persisters[i].getIdentifierColumnNames() );
341                 }
342             }
343             
344             return sql + new ForUpdateFragment( dialect, aliasedLockModes, keyColumnNames ).toFragmentString();
345
346         }
347     }
348
349     protected boolean upgradeLocks() {
350         return true;
351     }
352
353     protected Object JavaDoc getResultColumnOrRow(Object JavaDoc[] row, ResultSet JavaDoc rs, SessionImplementor session)
354             throws SQLException JavaDoc, HibernateException {
355
356         row = toResultRow( row );
357         boolean isHolder = holderInstantiator.isRequired();
358         if ( hasScalars ) {
359             String JavaDoc[][] scalarColumns = scalarColumnNames;
360             int queryCols = queryReturnTypes.length;
361             if ( !isHolder && queryCols == 1 ) {
362                 return queryReturnTypes[0].nullSafeGet( rs, scalarColumns[0], session, null );
363             }
364             else {
365                 row = new Object JavaDoc[queryCols];
366                 for ( int i = 0; i < queryCols; i++ ) {
367                     row[i] = queryReturnTypes[i].nullSafeGet( rs, scalarColumns[i], session, null );
368                 }
369                 return row;
370             }
371         }
372         else if ( !isHolder ) {
373             return row.length == 1 ? row[0] : row;
374         }
375         else {
376             return row;
377         }
378
379     }
380
381     protected List JavaDoc getResultList(List JavaDoc results) throws QueryException {
382         // meant to handle dynamic instantiation queries...
383
if ( holderInstantiator.isRequired() ) {
384             for ( int i = 0; i < results.size(); i++ ) {
385                 Object JavaDoc[] row = ( Object JavaDoc[] ) results.get( i );
386                 Object JavaDoc result = holderInstantiator.instantiate(row);
387                 results.set( i, result );
388             }
389         }
390         return results;
391     }
392
393     // --- Query translator methods ---
394

395     /**
396      * Delegats
397      *
398      * @param session
399      * @param queryParameters
400      * @return
401      * @throws HibernateException
402      */

403     public List JavaDoc list(SessionImplementor session, QueryParameters queryParameters)
404             throws HibernateException {
405         return list( session, queryParameters, queryTranslator.getQuerySpaces(), queryReturnTypes );
406     }
407
408     /**
409      * Return the query results as an iterator
410      */

411     public Iterator JavaDoc iterate(QueryParameters queryParameters, EventSource session)
412             throws HibernateException {
413
414         final boolean stats = session.getFactory().getStatistics().isStatisticsEnabled();
415         long startTime = 0;
416         if ( stats ) startTime = System.currentTimeMillis();
417
418         try {
419
420             final PreparedStatement JavaDoc st = prepareQueryStatement( queryParameters, false, session );
421             final ResultSet JavaDoc rs = getResultSet( st, queryParameters.getRowSelection(), session );
422             final Iterator JavaDoc result = new IteratorImpl(
423                     rs,
424                     st,
425                     session,
426                     queryReturnTypes,
427                     queryTranslator.getColumnNames(),
428                     holderInstantiator
429                 );
430
431             if ( stats ) {
432                 session.getFactory().getStatisticsImplementor().queryExecuted(
433                         "HQL: " + queryTranslator.getQueryString(),
434                         0,
435                         System.currentTimeMillis() - startTime );
436             }
437
438             return result;
439
440         }
441         catch ( SQLException JavaDoc sqle ) {
442             throw JDBCExceptionHelper.convert(
443                     getFactory().getSQLExceptionConverter(),
444                     sqle,
445                     "could not execute query using iterate",
446                     getSQLString()
447                 );
448         }
449
450     }
451
452     public ScrollableResults scroll(final QueryParameters queryParameters,
453                                     final SessionImplementor session)
454             throws HibernateException {
455         return scroll( queryParameters, queryReturnTypes, holderInstantiator, session );
456     }
457
458     // -- Implementation private methods --
459

460     private Object JavaDoc[] toResultRow(Object JavaDoc[] row) {
461         if ( selectLength == row.length ) {
462             return row;
463         }
464         else {
465             Object JavaDoc[] result = new Object JavaDoc[selectLength];
466             int j = 0;
467             for ( int i = 0; i < row.length; i++ ) {
468                 if ( includeInSelect[i] ) result[j++] = row[i];
469             }
470             return result;
471         }
472     }
473
474     /**
475      * Returns the locations of all occurrences of the named parameter.
476      */

477     private int[] getNamedParameterLocs(String JavaDoc name) throws QueryException {
478         return queryTranslator.getNamedParameterLocs( name );
479     }
480 }
481
Popular Tags