1
//$Id: QueryTranslatorImpl.java 11081 2007-01-23 16:31:13Z steve.ebersole@jboss.com $
2
package org.hibernate.hql.classic;
4
import java.io.Serializable;
5
import java.lang.reflect.Constructor;
6
import java.sql.PreparedStatement;
7
import java.sql.ResultSet;
8
import java.sql.SQLException;
9
import java.util.ArrayList;
10
import java.util.HashMap;
11
import java.util.HashSet;
12
import java.util.Iterator;
13
import java.util.List;
17
import org.apache.commons.collections.SequencedHashMap;
18
import org.apache.commons.logging.Log;
19
import org.apache.commons.logging.LogFactory;
21
import org.hibernate.HibernateException;
22
import org.hibernate.LockMode;
23
import org.hibernate.MappingException;
24
import org.hibernate.QueryException;
25
import org.hibernate.ScrollableResults;
26
import org.hibernate.dialect.Dialect;
27
import org.hibernate.engine.JoinSequence;
28
import org.hibernate.engine.QueryParameters;
29
import org.hibernate.engine.SessionFactoryImplementor;
30
import org.hibernate.engine.SessionImplementor;
31
import org.hibernate.event.EventSource;
32
import org.hibernate.exception.JDBCExceptionHelper;
33
import org.hibernate.hql.FilterTranslator;
34
import org.hibernate.hql.HolderInstantiator;
35
import org.hibernate.hql.NameGenerator;
36
import org.hibernate.hql.ParameterTranslations;
37
import org.hibernate.impl.IteratorImpl;
38
import org.hibernate.loader.BasicLoader;
39
import org.hibernate.persister.collection.CollectionPersister;
40
import org.hibernate.persister.collection.QueryableCollection;
41
import org.hibernate.persister.entity.Loadable;
42
import org.hibernate.persister.entity.PropertyMapping;
43
import org.hibernate.persister.entity.Queryable;
44
import org.hibernate.sql.JoinFragment;
45
import org.hibernate.sql.QuerySelect;
46
import org.hibernate.transform.ResultTransformer;
47
import org.hibernate.type.AssociationType;
48
import org.hibernate.type.EntityType;
49
import org.hibernate.type.Type;
50
import org.hibernate.type.TypeFactory;
51
import org.hibernate.util.ArrayHelper;
52
import org.hibernate.util.ReflectHelper;
53
import org.hibernate.util.StringHelper;
56
* An instance of <tt>QueryTranslator</tt> translates a Hibernate
57
* query string to SQL.
59
public class QueryTranslatorImpl extends BasicLoader implements FilterTranslator {
61
private static final String[] NO_RETURN_ALIASES = new String[] {};
63
private final String queryIdentifier;
64
private final String queryString;
66
private final Map typeMap = new SequencedHashMap();
67
private final Map collections = new SequencedHashMap();
68
private List returnedTypes = new ArrayList();
69
private final List fromTypes = new ArrayList();
70
private final List scalarTypes = new ArrayList();
71
private final Map namedParameters = new HashMap();
72
private final Map aliasNames = new HashMap();
73
private final Map oneToOneOwnerNames = new HashMap();
74
private final Map uniqueKeyOwnerReferences = new HashMap();
75
private final Map decoratedPropertyMappings = new HashMap();
77
private final List scalarSelectTokens = new ArrayList();
78
private final List whereTokens = new ArrayList();
79
private final List havingTokens = new ArrayList();
80
private final Map joins = new SequencedHashMap();
81
private final List orderByTokens = new ArrayList();
82
private final List groupByTokens = new ArrayList();
83
private final Set querySpaces = new HashSet();
84
private final Set entitiesToFetch = new HashSet();
86
private final Map pathAliases = new HashMap();
87
private final Map pathJoins = new HashMap();
89
private Queryable[] persisters;
91
private EntityType[] ownerAssociationTypes;
92
private String[] names;
93
private boolean[] includeInSelect;
94
private int selectLength;
95
private Type[] returnTypes;
96
private Type[] actualReturnTypes;
97
private String[][] scalarColumnNames;
98
private Map tokenReplacements;
99
private int nameCount = 0;
100
private int parameterCount = 0;
101
private boolean distinct = false;
102
private boolean compiled;
103
private String sqlString;
104
private Class holderClass;
105
private Constructor holderConstructor;
106
private boolean hasScalars;
107
private boolean shallowQuery;
108
private QueryTranslatorImpl superQuery;
110
private QueryableCollection collectionPersister;
111
private int collectionOwnerColumn = -1;
112
private String collectionOwnerName;
113
private String fetchName;
115
private String[] suffixes;
117
private Map enabledFilters;
119
private static final Log log = LogFactory.getLog( QueryTranslatorImpl.class );
122
* Construct a query translator
124
* @param queryIdentifier A unique identifier for the query of which this
125
* translation is part; typically this is the original, user-supplied query string.
126
* @param queryString The "preprocessed" query string; at the very least
127
* already processed by {@link org.hibernate.hql.QuerySplitter}.
128
* @param enabledFilters Any enabled filters.
129
* @param factory The session factory.
131
public QueryTranslatorImpl(
132
String queryIdentifier,
135
SessionFactoryImplementor factory) {
137
this.queryIdentifier = queryIdentifier;
138
this.queryString = queryString;
139
this.enabledFilters = enabledFilters;
143
* Construct a query translator; this form used internally.
145
* @param queryString The query string to process.
146
* @param enabledFilters Any enabled filters.
147
* @param factory The session factory.
149
public QueryTranslatorImpl(
152
SessionFactoryImplementor factory) {
153
this( queryString, queryString, enabledFilters, factory );
157
* Compile a subquery.
159
* @param superquery The containing query of the query to be compiled.
161
* @throws org.hibernate.MappingException Indicates problems resolving
162
* things referenced in the query.
163
* @throws org.hibernate.QueryException Generally some form of syntatic
166
void compile(QueryTranslatorImpl superquery) throws QueryException, MappingException {
167
this.tokenReplacements = superquery.tokenReplacements;
168
this.superQuery = superquery;
169
this.shallowQuery = true;
170
this.enabledFilters = superquery.getEnabledFilters();
176
* Compile a "normal" query. This method may be called multiple
177
* times. Subsequent invocations are no-ops.
179
public synchronized void compile(
181
boolean scalar) throws QueryException, MappingException {
183
this.tokenReplacements = replacements;
184
this.shallowQuery = scalar;
190
* Compile a filter. This method may be called multiple
191
* times. Subsequent invocations are no-ops.
193
public synchronized void compile(
194
String collectionRole,
196
boolean scalar) throws QueryException, MappingException {
198
if ( !isCompiled() ) {
199
addFromAssociation( "this", collectionRole );
200
compile( replacements, scalar );
205
* Compile the query (generate the SQL).
207
* @throws org.hibernate.MappingException Indicates problems resolving
208
* things referenced in the query.
209
* @throws org.hibernate.QueryException Generally some form of syntatic
212
private void compile() throws QueryException, MappingException {
214
log.trace( "compiling query" );
216
ParserHelper.parse( new PreprocessingParser( tokenReplacements ),
218
ParserHelper.HQL_SEPARATORS,
222
catch ( QueryException qe ) {
223
qe.setQueryString( queryString );
226
catch ( MappingException me ) {
229
catch ( Exception e ) {
230
log.debug( "unexpected query compilation problem", e );
232
QueryException qe = new QueryException( "Incorrect query syntax", e );
233
qe.setQueryString( queryString );
243
public String getSQLString() {
247
public List collectSqlStrings() {
248
return ArrayHelper.toList( new String[] { sqlString } );
251
public String getQueryString() {
256
* Persisters for the return values of a <tt>find()</tt> style query.
258
* @return an array of <tt>EntityPersister</tt>s.
260
protected Loadable[] getEntityPersisters() {
265
* Types of the return values of an <tt>iterate()</tt> style query.
267
* @return an array of <tt>Type</tt>s.
269
public Type[] getReturnTypes() {
270
return actualReturnTypes;
273
public String[] getReturnAliases() {
274
// return aliases not supported in classic translator!
275
return NO_RETURN_ALIASES;
278
public String[][] getColumnNames() {
279
return scalarColumnNames;
282
private static void logQuery(String hql, String sql) {
283
if ( log.isDebugEnabled() ) {
284
log.debug( "HQL: " + hql );
285
log.debug( "SQL: " + sql );
289
void setAliasName(String alias, String name) {
290
aliasNames.put( alias, name );
293
public String getAliasName(String alias) {
294
String name = ( String ) aliasNames.get( alias );
295
if ( name == null ) {
296
if ( superQuery != null ) {
297
name = superQuery.getAliasName( alias );
306
String unalias(String path) {
307
String alias = StringHelper.root( path );
308
String name = getAliasName( alias );
309
if ( name != null ) {
310
return name + path.substring( alias.length() );
317
void addEntityToFetch(String name, String oneToOneOwnerName, AssociationType ownerAssociationType) {
318
addEntityToFetch( name );
319
if ( oneToOneOwnerName != null ) oneToOneOwnerNames.put( name, oneToOneOwnerName );
320
if ( ownerAssociationType != null ) uniqueKeyOwnerReferences.put( name, ownerAssociationType );
323
private void addEntityToFetch(String name) {
324
entitiesToFetch.add( name );
327
private int nextCount() {
328
return ( superQuery == null ) ? nameCount++ : superQuery.nameCount++;
331
String createNameFor(String type) {
332
return StringHelper.generateAlias( type, nextCount() );
335
String createNameForCollection(String role) {
336
return StringHelper.generateAlias( role, nextCount() );
339
private String getType(String name) {
340
String type = ( String ) typeMap.get( name );
341
if ( type == null && superQuery != null ) {
342
type = superQuery.getType( name );
347
private String getRole(String name) {
348
String role = ( String ) collections.get( name );
349
if ( role == null && superQuery != null ) {
350
role = superQuery.getRole( name );
355
boolean isName(String name) {
356
return aliasNames.containsKey( name ) ||
357
typeMap.containsKey( name ) ||
358
collections.containsKey( name ) || (
359
superQuery != null && superQuery.isName( name )
363
PropertyMapping getPropertyMapping(String name) throws QueryException {
364
PropertyMapping decorator = getDecoratedPropertyMapping( name );
365
if ( decorator != null ) return decorator;
367
String type = getType( name );
368
if ( type == null ) {
369
String role = getRole( name );
370
if ( role == null ) {
371
throw new QueryException( "alias not found: " + name );
373
return getCollectionPersister( role ); //.getElementPropertyMapping();
376
Queryable persister = getEntityPersister( type );
377
if ( persister == null ) throw new QueryException( "persistent class not found: " + type );
382
private PropertyMapping getDecoratedPropertyMapping(String name) {
383
return ( PropertyMapping ) decoratedPropertyMappings.get( name );
386
void decoratePropertyMapping(String name, PropertyMapping mapping) {
387
decoratedPropertyMappings.put( name, mapping );
390
private Queryable getEntityPersisterForName(String name) throws QueryException {
391
String type = getType( name );
392
Queryable persister = getEntityPersister( type );
393
if ( persister == null ) throw new QueryException( "persistent class not found: " + type );
397
Queryable getEntityPersisterUsingImports(String className) {
398
final String importedClassName = getFactory().getImportedClassName( className );
399
if ( importedClassName == null ) {
403
return ( Queryable ) getFactory().getEntityPersister( importedClassName );
405
catch ( MappingException me ) {
410
Queryable getEntityPersister(String entityName) throws QueryException {
412
return ( Queryable ) getFactory().getEntityPersister( entityName );
414
catch ( Exception e ) {
415
throw new QueryException( "persistent class not found: " + entityName );
419
QueryableCollection getCollectionPersister(String role) throws QueryException {
421
return ( QueryableCollection ) getFactory().getCollectionPersister( role );
423
catch ( ClassCastException cce ) {
424
throw new QueryException( "collection role is not queryable: " + role );
426
catch ( Exception e ) {
427
throw new QueryException( "collection role not found: " + role );
431
void addType(String name, String type) {
432
typeMap.put( name, type );
435
void addCollection(String name, String role) {
436
collections.put( name, role );
439
void addFrom(String name, String type, JoinSequence joinSequence)
440
throws QueryException {
441
addType( name, type );
442
addFrom( name, joinSequence );
445
void addFromCollection(String name, String collectionRole, JoinSequence joinSequence)
446
throws QueryException {
447
//register collection role
448
addCollection( name, collectionRole );
449
addJoin( name, joinSequence );
452
void addFrom(String name, JoinSequence joinSequence)
453
throws QueryException {
454
fromTypes.add( name );
455
addJoin( name, joinSequence );
458
void addFromClass(String name, Queryable classPersister)
459
throws QueryException {
460
JoinSequence joinSequence = new JoinSequence( getFactory() )
461
.setRoot( classPersister, name );
462
//crossJoins.add(name);
463
addFrom( name, classPersister.getEntityName(), joinSequence );
466
void addSelectClass(String name) {
467
returnedTypes.add( name );
470
void addSelectScalar(Type type) {
471
scalarTypes.add( type );
474
void appendWhereToken(String token) {
475
whereTokens.add( token );
478
void appendHavingToken(String token) {
479
havingTokens.add( token );
482
void appendOrderByToken(String token) {
483
orderByTokens.add( token );
486
void appendGroupByToken(String token) {
487
groupByTokens.add( token );
490
void appendScalarSelectToken(String token) {
491
scalarSelectTokens.add( token );
494
void appendScalarSelectTokens(String[] tokens) {
495
scalarSelectTokens.add( tokens );
498
void addFromJoinOnly(String name, JoinSequence joinSequence) throws QueryException {
499
addJoin( name, joinSequence.getFromPart() );
502
void addJoin(String name, JoinSequence joinSequence) throws QueryException {
503
if ( !joins.containsKey( name ) ) joins.put( name, joinSequence );
506
void addNamedParameter(String name) {
507
if ( superQuery != null ) superQuery.addNamedParameter( name );
508
Integer loc = new Integer( parameterCount++ );
509
Object o = namedParameters.get( name );
511
namedParameters.put( name, loc );
513
else if ( o instanceof Integer ) {
514
ArrayList list = new ArrayList( 4 );
517
namedParameters.put( name, list );
520
( ( ArrayList ) o ).add( loc );
524
public int[] getNamedParameterLocs(String name) throws QueryException {
525
Object o = namedParameters.get( name );
527
QueryException qe = new QueryException( ERROR_NAMED_PARAMETER_DOES_NOT_APPEAR + name );
528
qe.setQueryString( queryString );
531
if ( o instanceof Integer ) {
532
return new int[]{ ( ( Integer ) o ).intValue() };
535
return ArrayHelper.toIntArray( ( ArrayList ) o );
539
private void renderSQL() throws QueryException, MappingException {
542
if ( returnedTypes.size() == 0 && scalarTypes.size() == 0 ) {
543
//ie no select clause in HQL
544
returnedTypes = fromTypes;
545
rtsize = returnedTypes.size();
548
rtsize = returnedTypes.size();
549
Iterator iter = entitiesToFetch.iterator();
550
while ( iter.hasNext() ) {
551
returnedTypes.add( iter.next() );
554
int size = returnedTypes.size();
555
persisters = new Queryable[size];
556
names = new String[size];
557
owners = new int[size];
558
ownerAssociationTypes = new EntityType[size];
559
suffixes = new String[size];
560
includeInSelect = new boolean[size];
561
for ( int i = 0; i < size; i++ ) {
562
String name = ( String ) returnedTypes.get( i );
563
//if ( !isName(name) ) throw new QueryException("unknown type: " + name);
564
persisters[i] = getEntityPersisterForName( name );
565
// TODO: cannot use generateSuffixes() - it handles the initial suffix differently.
566
suffixes[i] = ( size == 1 ) ? "" : Integer.toString( i ) + '_';
568
includeInSelect[i] = !entitiesToFetch.contains( name );
569
if ( includeInSelect[i] ) selectLength++;
570
if ( name.equals( collectionOwnerName ) ) collectionOwnerColumn = i;
571
String oneToOneOwner = ( String ) oneToOneOwnerNames.get( name );
572
owners[i] = ( oneToOneOwner == null ) ? -1 : returnedTypes.indexOf( oneToOneOwner );
573
ownerAssociationTypes[i] = (EntityType) uniqueKeyOwnerReferences.get( name );
576
if ( ArrayHelper.isAllNegative( owners ) ) owners = null;
578
String scalarSelect = renderScalarSelect(); //Must be done here because of side-effect! yuck...
580
int scalarSize = scalarTypes.size();
581
hasScalars = scalarTypes.size() != rtsize;
583
returnTypes = new Type[scalarSize];
584
for ( int i = 0; i < scalarSize; i++ ) {
585
returnTypes[i] = ( Type ) scalarTypes.get( i );
588
QuerySelect sql = new QuerySelect( getFactory().getDialect() );
589
sql.setDistinct( distinct );
591
if ( !shallowQuery ) {
592
renderIdentifierSelect( sql );
593
renderPropertiesSelect( sql );
596
if ( collectionPersister != null ) {
597
sql.addSelectFragmentString( collectionPersister.selectFragment( fetchName, "__" ) );
600
if ( hasScalars || shallowQuery ) sql.addSelectFragmentString( scalarSelect );
602
//TODO: for some dialects it would be appropriate to add the renderOrderByPropertiesSelect() to other select strings
603
mergeJoins( sql.getJoinFragment() );
605
sql.setWhereTokens( whereTokens.iterator() );
607
sql.setGroupByTokens( groupByTokens.iterator() );
608
sql.setHavingTokens( havingTokens.iterator() );
609
sql.setOrderByTokens( orderByTokens.iterator() );
611
if ( collectionPersister != null && collectionPersister.hasOrdering() ) {
612
sql.addOrderBy( collectionPersister.getSQLOrderByString( fetchName ) );
615
scalarColumnNames = NameGenerator.generateColumnNames( returnTypes, getFactory() );
617
// initialize the Set of queried identifier spaces (ie. tables)
618
Iterator iter = collections.values().iterator();
619
while ( iter.hasNext() ) {
620
CollectionPersister p = getCollectionPersister( ( String ) iter.next() );
621
addQuerySpaces( p.getCollectionSpaces() );
623
iter = typeMap.keySet().iterator();
624
while ( iter.hasNext() ) {
625
Queryable p = getEntityPersisterForName( ( String ) iter.next() );
626
addQuerySpaces( p.getQuerySpaces() );
629
sqlString = sql.toQueryString();
631
if ( holderClass != null ) holderConstructor = ReflectHelper.getConstructor( holderClass, returnTypes );
634
actualReturnTypes = returnTypes;
637
actualReturnTypes = new Type[selectLength];
639
for ( int i = 0; i < persisters.length; i++ ) {
640
if ( includeInSelect[i] ) {
641
actualReturnTypes[j++] = TypeFactory.manyToOne( persisters[i].getEntityName(), shallowQuery );
648
private void renderIdentifierSelect(QuerySelect sql) {
649
int size = returnedTypes.size();
651
for ( int k = 0; k < size; k++ ) {
652
String name = ( String ) returnedTypes.get( k );
653
String suffix = size == 1 ? "" : Integer.toString( k ) + '_';
654
sql.addSelectFragmentString( persisters[k].identifierSelectFragment( name, suffix ) );
659
/*private String renderOrderByPropertiesSelect() {
660
StringBuffer buf = new StringBuffer(10);
662
//add the columns we are ordering by to the select ID select clause
663
Iterator iter = orderByTokens.iterator();
664
while ( iter.hasNext() ) {
665
String token = (String) iter.next();
666
if ( token.lastIndexOf(".") > 0 ) {
667
//ie. it is of form "foo.bar", not of form "asc" or "desc"
668
buf.append(StringHelper.COMMA_SPACE).append(token);
672
return buf.toString();
675
private void renderPropertiesSelect(QuerySelect sql) {
676
int size = returnedTypes.size();
677
for ( int k = 0; k < size; k++ ) {
678
String suffix = size == 1 ? "" : Integer.toString( k ) + '_';
679
String name = ( String ) returnedTypes.get( k );
680
sql.addSelectFragmentString( persisters[k].propertySelectFragment( name, suffix, false ) );
685
* WARNING: side-effecty
687
private String renderScalarSelect() {
689
boolean isSubselect = superQuery != null;
691
StringBuffer buf = new StringBuffer( 20 );
693
if ( scalarTypes.size() == 0 ) {
694
//ie. no select clause
695
int size = returnedTypes.size();
696
for ( int k = 0; k < size; k++ ) {
698
scalarTypes.add( TypeFactory.manyToOne( persisters[k].getEntityName(), shallowQuery ) );
700
String[] idColumnNames = persisters[k].getIdentifierColumnNames();
701
for ( int i = 0; i < idColumnNames.length; i++ ) {
702
buf.append( returnedTypes.get( k ) ).append( '.' ).append( idColumnNames[i] );
703
if ( !isSubselect ) buf.append( " as " ).append( NameGenerator.scalarName( k, i ) );
704
if ( i != idColumnNames.length - 1 || k != size - 1 ) buf.append( ", " );
711
//there _was_ a select clause
712
Iterator iter = scalarSelectTokens.iterator();
714
boolean nolast = false; //real hacky...
715
int parenCount = 0; // used to count the nesting of parentheses
716
while ( iter.hasNext() ) {
717
Object next = iter.next();
718
if ( next instanceof String ) {
719
String token = ( String ) next;
721
if ( "(".equals( token ) ) {
724
else if ( ")".equals( token ) ) {
728
String lc = token.toLowerCase();
729
if ( lc.equals( ", " ) ) {
734
if ( !isSubselect && parenCount == 0 ) {
737
.append( NameGenerator.scalarName( x, 0 ) );
742
if ( lc.equals( "distinct" ) || lc.equals( "all" ) ) {
748
String[] tokens = ( String[] ) next;
749
for ( int i = 0; i < tokens.length; i++ ) {
750
buf.append( tokens[i] );
751
if ( !isSubselect ) {
753
.append( NameGenerator.scalarName( c, i ) );
755
if ( i != tokens.length - 1 ) buf.append( ", " );
760
if ( !isSubselect && !nolast ) {
763
.append( NameGenerator.scalarName( x, 0 ) );
768
return buf.toString();
771
private void mergeJoins(JoinFragment ojf) throws MappingException, QueryException {
773
Iterator iter = joins.entrySet().iterator();
774
while ( iter.hasNext() ) {
775
Map.Entry me = ( Map.Entry ) iter.next();
776
String name = ( String ) me.getKey();
777
JoinSequence join = ( JoinSequence ) me.getValue();
778
join.setSelector( new JoinSequence.Selector() {
779
public boolean includeSubclasses(String alias) {
780
boolean include = returnedTypes.contains( alias ) && !isShallowQuery();
785
if ( typeMap.containsKey( name ) ) {
786
ojf.addFragment( join.toJoinFragment( enabledFilters, true ) );
788
else if ( collections.containsKey( name ) ) {
789
ojf.addFragment( join.toJoinFragment( enabledFilters, true ) );
792
//name from a super query (a bit inelegant that it shows up here)
799
public final Set getQuerySpaces() {
804
* Is this query called by scroll() or iterate()?
806
* @return true if it is, false if it is called by find() or list()
808
boolean isShallowQuery() {
812
void addQuerySpaces(Serializable[] spaces) {
813
for ( int i = 0; i < spaces.length; i++ ) {
814
querySpaces.add( spaces[i] );
816
if ( superQuery != null ) superQuery.addQuerySpaces( spaces );
819
void setDistinct(boolean distinct) {
820
this.distinct = distinct;
823
boolean isSubquery() {
824
return superQuery != null;
828
* Overrides method from Loader
830
public CollectionPersister[] getCollectionPersisters() {
831
return collectionPersister == null ? null : new CollectionPersister[] { collectionPersister };
834
protected String[] getCollectionSuffixes() {
835
return collectionPersister == null ? null : new String[] { "__" };
838
void setCollectionToFetch(String role, String name, String ownerName, String entityName)
839
throws QueryException {
841
collectionPersister = getCollectionPersister( role );
842
collectionOwnerName = ownerName;
843
if ( collectionPersister.getElementType().isEntityType() ) {
844
addEntityToFetch( entityName );
848
protected String[] getSuffixes() {
852
protected String[] getAliases() {
857
* Used for collection filters
859
private void addFromAssociation(final String elementName, final String collectionRole)
860
throws QueryException {
861
//q.addCollection(collectionName, collectionRole);
862
QueryableCollection persister = getCollectionPersister( collectionRole );
863
Type collectionElementType = persister.getElementType();
864
if ( !collectionElementType.isEntityType() ) {
865
throw new QueryException( "collection of values in filter: " + elementName );
868
String[] keyColumnNames = persister.getKeyColumnNames();
869
//if (keyColumnNames.length!=1) throw new QueryException("composite-key collection in filter: " + collectionRole);
871
String collectionName;
872
JoinSequence join = new JoinSequence( getFactory() );
873
collectionName = persister.isOneToMany() ?
875
createNameForCollection( collectionRole );
876
join.setRoot( persister, collectionName );
877
if ( !persister.isOneToMany() ) {
879
addCollection( collectionName, collectionRole );
881
join.addJoin( ( AssociationType ) persister.getElementType(),
883
JoinFragment.INNER_JOIN,
884
persister.getElementColumnNames(collectionName) );
886
catch ( MappingException me ) {
887
throw new QueryException( me );
890
join.addCondition( collectionName, keyColumnNames, " = ?" );
891
//if ( persister.hasWhere() ) join.addCondition( persister.getSQLWhereString(collectionName) );
892
EntityType elemType = ( EntityType ) collectionElementType;
893
addFrom( elementName, elemType.getAssociatedEntityName(), join );
897
String getPathAlias(String path) {
898
return ( String ) pathAliases.get( path );
901
JoinSequence getPathJoin(String path) {
902
return ( JoinSequence ) pathJoins.get( path );
905
void addPathAliasAndJoin(String path, String alias, JoinSequence joinSequence) {
906
pathAliases.put( path, alias );
907
pathJoins.put( path, joinSequence );
910
public List list(SessionImplementor session, QueryParameters queryParameters)
911
throws HibernateException {
912
return list( session, queryParameters, getQuerySpaces(), actualReturnTypes );
916
* Return the query results as an iterator
918
public Iterator iterate(QueryParameters queryParameters, EventSource session)
919
throws HibernateException {
921
boolean stats = session.getFactory().getStatistics().isStatisticsEnabled();
923
if ( stats ) startTime = System.currentTimeMillis();
927
PreparedStatement st = prepareQueryStatement( queryParameters, false, session );
928
ResultSet rs = getResultSet( st, queryParameters.hasAutoDiscoverScalarTypes(), false, queryParameters.getRowSelection(), session );
929
HolderInstantiator hi = HolderInstantiator.createClassicHolderInstantiator(holderConstructor, queryParameters.getResultTransformer());
930
Iterator result = new IteratorImpl( rs, st, session, returnTypes, getColumnNames(), hi );
933
session.getFactory().getStatisticsImplementor().queryExecuted(
934
"HQL: " + queryString,
936
System.currentTimeMillis() - startTime
943
catch ( SQLException sqle ) {
944
throw JDBCExceptionHelper.convert(
945
getFactory().getSQLExceptionConverter(),
947
"could not execute query using iterate",
954
public int executeUpdate(QueryParameters queryParameters, SessionImplementor session) throws HibernateException {
955
throw new UnsupportedOperationException( "Not supported! Use the AST translator...");
958
protected Object getResultColumnOrRow(Object[] row, ResultTransformer transformer, ResultSet rs, SessionImplementor session)
959
throws SQLException, HibernateException {
960
row = toResultRow( row );
962
String[][] scalarColumns = getColumnNames();
963
int queryCols = returnTypes.length;
964
if ( holderClass == null && queryCols == 1 ) {
965
return returnTypes[0].nullSafeGet( rs, scalarColumns[0], session, null );
968
row = new Object[queryCols];
969
for ( int i = 0; i < queryCols; i++ )
970
row[i] = returnTypes[i].nullSafeGet( rs, scalarColumns[i], session, null );
974
else if ( holderClass == null ) {
975
return row.length == 1 ? row[0] : row;
983
protected List getResultList(List results, ResultTransformer resultTransformer) throws QueryException {
984
if ( holderClass != null ) {
985
for ( int i = 0; i < results.size(); i++ ) {
986
Object[] row = ( Object[] ) results.get( i );
988
results.set( i, holderConstructor.newInstance( row ) );
990
catch ( Exception e ) {
991
throw new QueryException( "could not instantiate: " + holderClass, e );
998
private Object[] toResultRow(Object[] row) {
999
if ( selectLength == row.length ) {
1003
Object[] result = new Object[selectLength];
1005
for ( int i = 0; i < row.length; i++ ) {
1006
if ( includeInSelect[i] ) result[j++] = row[i];
1012
void setHolderClass(Class clazz) {
1013
holderClass = clazz;
1016
protected LockMode[] getLockModes(Map lockModes) {
1017
// unfortunately this stuff can't be cached because
1018
// it is per-invocation, not constant for the
1019
// QueryTranslator instance
1020
HashMap nameLockModes = new HashMap();
1021
if ( lockModes != null ) {
1022
Iterator iter = lockModes.entrySet().iterator();
1023
while ( iter.hasNext() ) {
1024
Map.Entry me = ( Map.Entry ) iter.next();
1025
nameLockModes.put( getAliasName( ( String ) me.getKey() ),
1029
LockMode[] lockModeArray = new LockMode[names.length];
1030
for ( int i = 0; i < names.length; i++ ) {
1031
LockMode lm = ( LockMode ) nameLockModes.get( names[i] );
1032
if ( lm == null ) lm = LockMode.NONE;
1033
lockModeArray[i] = lm;
1035
return lockModeArray;
1038
protected String applyLocks(String sql, Map lockModes, Dialect dialect) throws QueryException {
1039
// can't cache this stuff either (per-invocation)
1040
final String result;
1041
if ( lockModes == null || lockModes.size() == 0 ) {
1045
Map aliasedLockModes = new HashMap();
1046
Iterator iter = lockModes.entrySet().iterator();
1047
while ( iter.hasNext() ) {
1048
Map.Entry me = ( Map.Entry ) iter.next();
1049
aliasedLockModes.put( getAliasName( ( String ) me.getKey() ), me.getValue() );
1051
Map keyColumnNames = null;
1052
if ( dialect.forUpdateOfColumns() ) {
1053
keyColumnNames = new HashMap();
1054
for ( int i = 0; i < names.length; i++ ) {
1055
keyColumnNames.put( names[i], persisters[i].getIdentifierColumnNames() );
1058
result = dialect.applyLocksToSql( sql, aliasedLockModes, keyColumnNames );
1060
logQuery( queryString, result );
1064
protected boolean upgradeLocks() {
1068
protected int[] getCollectionOwners() {
1069
return new int[] { collectionOwnerColumn };
1072
protected boolean isCompiled() {
1076
public String toString() {
1080
protected int[] getOwners() {
1084
protected EntityType[] getOwnerAssociationTypes() {
1085
return ownerAssociationTypes;
1088
public Class getHolderClass() {
1092
public Map getEnabledFilters() {
1093
return enabledFilters;
1096
public ScrollableResults scroll(final QueryParameters queryParameters,
1097
final SessionImplementor session)
1098
throws HibernateException {
1099
HolderInstantiator hi = HolderInstantiator.createClassicHolderInstantiator(holderConstructor, queryParameters.getResultTransformer());
1100
return scroll( queryParameters, returnTypes, hi, session );
1103
public String getQueryIdentifier() {
1104
return queryIdentifier;
1107
protected boolean isSubselectLoadingEnabled() {
1108
return hasSubselectLoadableCollections();
1111
public void validateScrollability() throws HibernateException {
1112
// This is the legacy behaviour for HQL queries...
1113
if ( getCollectionPersisters() != null ) {
1114
throw new HibernateException( "Cannot scroll queries which initialize collections" );
1118
public boolean containsCollectionFetches() {
1122
public boolean isManipulationStatement() {
1123
// classic parser does not support bulk manipulation statements
1127
public ParameterTranslations getParameterTranslations() {
1128
return new ParameterTranslations() {
1130
public boolean supportsOrdinalParameterMetadata() {
1131
// classic translator does not support collection of ordinal
1136
public int getOrdinalParameterCount() {
1137
return 0; // not known!
1140
public int getOrdinalParameterSqlLocation(int ordinalPosition) {
1141
return 0; // not known!
1144
public Type getOrdinalParameterExpectedType(int ordinalPosition) {
1145
return null; // not known!
1148
public Set getNamedParameterNames() {
1149
return namedParameters.keySet();
1152
public int[] getNamedParameterSqlLocations(String name) {
1153
return getNamedParameterLocs( name );
1156
public Type getNamedParameterExpectedType(String name) {
1157
return null; // not known!