~ubuntu-branches/ubuntu/wily/libhibernate3-java/wily-proposed

« back to all changes in this revision

Viewing changes to src/org/hibernate/hql/classic/QueryTranslatorImpl.java

  • Committer: Bazaar Package Importer
  • Author(s): Torsten Werner
  • Date: 2007-10-14 14:43:34 UTC
  • Revision ID: james.westby@ubuntu.com-20071014144334-eamc8i0q10gs1aro
Tags: upstream-3.2.5
ImportĀ upstreamĀ versionĀ 3.2.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//$Id: QueryTranslatorImpl.java 11081 2007-01-23 16:31:13Z steve.ebersole@jboss.com $
 
2
package org.hibernate.hql.classic;
 
3
 
 
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;
 
14
import java.util.Map;
 
15
import java.util.Set;
 
16
 
 
17
import org.apache.commons.collections.SequencedHashMap;
 
18
import org.apache.commons.logging.Log;
 
19
import org.apache.commons.logging.LogFactory;
 
20
 
 
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;
 
54
 
 
55
/**
 
56
 * An instance of <tt>QueryTranslator</tt> translates a Hibernate
 
57
 * query string to SQL.
 
58
 */
 
59
public class QueryTranslatorImpl extends BasicLoader implements FilterTranslator {
 
60
 
 
61
        private static final String[] NO_RETURN_ALIASES = new String[] {};
 
62
 
 
63
        private final String queryIdentifier;
 
64
        private final String queryString;
 
65
 
 
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();
 
76
 
 
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();
 
85
 
 
86
        private final Map pathAliases = new HashMap();
 
87
        private final Map pathJoins = new HashMap();
 
88
 
 
89
        private Queryable[] persisters;
 
90
        private int[] owners;
 
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;
 
109
 
 
110
        private QueryableCollection collectionPersister;
 
111
        private int collectionOwnerColumn = -1;
 
112
        private String collectionOwnerName;
 
113
        private String fetchName;
 
114
 
 
115
        private String[] suffixes;
 
116
 
 
117
        private Map enabledFilters;
 
118
 
 
119
        private static final Log log = LogFactory.getLog( QueryTranslatorImpl.class );
 
120
 
 
121
        /**
 
122
         * Construct a query translator
 
123
         *
 
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.
 
130
         */
 
131
        public QueryTranslatorImpl(
 
132
                        String queryIdentifier,
 
133
                String queryString,
 
134
                Map enabledFilters,
 
135
                SessionFactoryImplementor factory) {
 
136
                super( factory );
 
137
                this.queryIdentifier = queryIdentifier;
 
138
                this.queryString = queryString;
 
139
                this.enabledFilters = enabledFilters;
 
140
        }
 
141
 
 
142
        /**
 
143
         * Construct a query translator; this form used internally.
 
144
         *
 
145
         * @param queryString The query string to process.
 
146
         * @param enabledFilters Any enabled filters.
 
147
         * @param factory The session factory.
 
148
         */
 
149
        public QueryTranslatorImpl(
 
150
                String queryString,
 
151
                Map enabledFilters,
 
152
                SessionFactoryImplementor factory) {
 
153
                this( queryString, queryString, enabledFilters, factory );
 
154
        }
 
155
 
 
156
        /**
 
157
         * Compile a subquery.
 
158
         *
 
159
         * @param superquery The containing query of the query to be compiled.
 
160
         *
 
161
         * @throws org.hibernate.MappingException Indicates problems resolving
 
162
         * things referenced in the query.
 
163
         * @throws org.hibernate.QueryException Generally some form of syntatic
 
164
         * failure.
 
165
         */
 
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();
 
171
                compile();
 
172
        }
 
173
 
 
174
 
 
175
        /**
 
176
         * Compile a "normal" query. This method may be called multiple
 
177
         * times. Subsequent invocations are no-ops.
 
178
         */
 
179
        public synchronized void compile(
 
180
                        Map replacements,
 
181
                        boolean scalar) throws QueryException, MappingException {
 
182
                if ( !compiled ) {
 
183
                        this.tokenReplacements = replacements;
 
184
                        this.shallowQuery = scalar;
 
185
                        compile();
 
186
                }
 
187
        }
 
188
 
 
189
        /**
 
190
         * Compile a filter. This method may be called multiple
 
191
         * times. Subsequent invocations are no-ops.
 
192
         */
 
193
        public synchronized void compile(
 
194
                        String collectionRole,
 
195
                        Map replacements,
 
196
                        boolean scalar) throws QueryException, MappingException {
 
197
 
 
198
                if ( !isCompiled() ) {
 
199
                        addFromAssociation( "this", collectionRole );
 
200
                        compile( replacements, scalar );
 
201
                }
 
202
        }
 
203
 
 
204
        /**
 
205
         * Compile the query (generate the SQL).
 
206
         *
 
207
         * @throws org.hibernate.MappingException Indicates problems resolving
 
208
         * things referenced in the query.
 
209
         * @throws org.hibernate.QueryException Generally some form of syntatic
 
210
         * failure.
 
211
         */
 
212
        private void compile() throws QueryException, MappingException {
 
213
 
 
214
                log.trace( "compiling query" );
 
215
                try {
 
216
                        ParserHelper.parse( new PreprocessingParser( tokenReplacements ),
 
217
                                        queryString,
 
218
                                        ParserHelper.HQL_SEPARATORS,
 
219
                                        this );
 
220
                        renderSQL();
 
221
                }
 
222
                catch ( QueryException qe ) {
 
223
                        qe.setQueryString( queryString );
 
224
                        throw qe;
 
225
                }
 
226
                catch ( MappingException me ) {
 
227
                        throw me;
 
228
                }
 
229
                catch ( Exception e ) {
 
230
                        log.debug( "unexpected query compilation problem", e );
 
231
                        e.printStackTrace();
 
232
                        QueryException qe = new QueryException( "Incorrect query syntax", e );
 
233
                        qe.setQueryString( queryString );
 
234
                        throw qe;
 
235
                }
 
236
 
 
237
                postInstantiate();
 
238
 
 
239
                compiled = true;
 
240
 
 
241
        }
 
242
 
 
243
        public String getSQLString() {
 
244
                return sqlString;
 
245
        }
 
246
 
 
247
        public List collectSqlStrings() {
 
248
                return ArrayHelper.toList( new String[] { sqlString } );
 
249
        }
 
250
 
 
251
        public String getQueryString() {
 
252
                return queryString;
 
253
        }
 
254
 
 
255
        /**
 
256
         * Persisters for the return values of a <tt>find()</tt> style query.
 
257
         *
 
258
         * @return an array of <tt>EntityPersister</tt>s.
 
259
         */
 
260
        protected Loadable[] getEntityPersisters() {
 
261
                return persisters;
 
262
        }
 
263
 
 
264
        /**
 
265
         * Types of the return values of an <tt>iterate()</tt> style query.
 
266
         *
 
267
         * @return an array of <tt>Type</tt>s.
 
268
         */
 
269
        public Type[] getReturnTypes() {
 
270
                return actualReturnTypes;
 
271
        }
 
272
 
 
273
        public String[] getReturnAliases() {
 
274
                // return aliases not supported in classic translator!
 
275
                return NO_RETURN_ALIASES;
 
276
        }
 
277
 
 
278
        public String[][] getColumnNames() {
 
279
                return scalarColumnNames;
 
280
        }
 
281
 
 
282
        private static void logQuery(String hql, String sql) {
 
283
                if ( log.isDebugEnabled() ) {
 
284
                        log.debug( "HQL: " + hql );
 
285
                        log.debug( "SQL: " + sql );
 
286
                }
 
287
        }
 
288
 
 
289
        void setAliasName(String alias, String name) {
 
290
                aliasNames.put( alias, name );
 
291
        }
 
292
 
 
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 );
 
298
                        }
 
299
                        else {
 
300
                                name = alias;
 
301
                        }
 
302
                }
 
303
                return name;
 
304
        }
 
305
 
 
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() );
 
311
                }
 
312
                else {
 
313
                        return path;
 
314
                }
 
315
        }
 
316
 
 
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 );
 
321
        }
 
322
 
 
323
        private void addEntityToFetch(String name) {
 
324
                entitiesToFetch.add( name );
 
325
        }
 
326
 
 
327
        private int nextCount() {
 
328
                return ( superQuery == null ) ? nameCount++ : superQuery.nameCount++;
 
329
        }
 
330
 
 
331
        String createNameFor(String type) {
 
332
                return StringHelper.generateAlias( type, nextCount() );
 
333
        }
 
334
 
 
335
        String createNameForCollection(String role) {
 
336
                return StringHelper.generateAlias( role, nextCount() );
 
337
        }
 
338
 
 
339
        private String getType(String name) {
 
340
                String type = ( String ) typeMap.get( name );
 
341
                if ( type == null && superQuery != null ) {
 
342
                        type = superQuery.getType( name );
 
343
                }
 
344
                return type;
 
345
        }
 
346
 
 
347
        private String getRole(String name) {
 
348
                String role = ( String ) collections.get( name );
 
349
                if ( role == null && superQuery != null ) {
 
350
                        role = superQuery.getRole( name );
 
351
                }
 
352
                return role;
 
353
        }
 
354
 
 
355
        boolean isName(String name) {
 
356
                return aliasNames.containsKey( name ) ||
 
357
                                typeMap.containsKey( name ) ||
 
358
                                collections.containsKey( name ) || (
 
359
                                superQuery != null && superQuery.isName( name )
 
360
                                );
 
361
        }
 
362
 
 
363
        PropertyMapping getPropertyMapping(String name) throws QueryException {
 
364
                PropertyMapping decorator = getDecoratedPropertyMapping( name );
 
365
                if ( decorator != null ) return decorator;
 
366
 
 
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 );
 
372
                        }
 
373
                        return getCollectionPersister( role ); //.getElementPropertyMapping();
 
374
                }
 
375
                else {
 
376
                        Queryable persister = getEntityPersister( type );
 
377
                        if ( persister == null ) throw new QueryException( "persistent class not found: " + type );
 
378
                        return persister;
 
379
                }
 
380
        }
 
381
 
 
382
        private PropertyMapping getDecoratedPropertyMapping(String name) {
 
383
                return ( PropertyMapping ) decoratedPropertyMappings.get( name );
 
384
        }
 
385
 
 
386
        void decoratePropertyMapping(String name, PropertyMapping mapping) {
 
387
                decoratedPropertyMappings.put( name, mapping );
 
388
        }
 
389
 
 
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 );
 
394
                return persister;
 
395
        }
 
396
 
 
397
        Queryable getEntityPersisterUsingImports(String className) {
 
398
                final String importedClassName = getFactory().getImportedClassName( className );
 
399
                if ( importedClassName == null ) {
 
400
                        return null;
 
401
                }
 
402
                try {
 
403
                        return ( Queryable ) getFactory().getEntityPersister( importedClassName );
 
404
                }
 
405
                catch ( MappingException me ) {
 
406
                        return null;
 
407
                }
 
408
        }
 
409
 
 
410
        Queryable getEntityPersister(String entityName) throws QueryException {
 
411
                try {
 
412
                        return ( Queryable ) getFactory().getEntityPersister( entityName );
 
413
                }
 
414
                catch ( Exception e ) {
 
415
                        throw new QueryException( "persistent class not found: " + entityName );
 
416
                }
 
417
        }
 
418
 
 
419
        QueryableCollection getCollectionPersister(String role) throws QueryException {
 
420
                try {
 
421
                        return ( QueryableCollection ) getFactory().getCollectionPersister( role );
 
422
                }
 
423
                catch ( ClassCastException cce ) {
 
424
                        throw new QueryException( "collection role is not queryable: " + role );
 
425
                }
 
426
                catch ( Exception e ) {
 
427
                        throw new QueryException( "collection role not found: " + role );
 
428
                }
 
429
        }
 
430
 
 
431
        void addType(String name, String type) {
 
432
                typeMap.put( name, type );
 
433
        }
 
434
 
 
435
        void addCollection(String name, String role) {
 
436
                collections.put( name, role );
 
437
        }
 
438
 
 
439
        void addFrom(String name, String type, JoinSequence joinSequence)
 
440
                        throws QueryException {
 
441
                addType( name, type );
 
442
                addFrom( name, joinSequence );
 
443
        }
 
444
 
 
445
        void addFromCollection(String name, String collectionRole, JoinSequence joinSequence)
 
446
                        throws QueryException {
 
447
                //register collection role
 
448
                addCollection( name, collectionRole );
 
449
                addJoin( name, joinSequence );
 
450
        }
 
451
 
 
452
        void addFrom(String name, JoinSequence joinSequence)
 
453
                        throws QueryException {
 
454
                fromTypes.add( name );
 
455
                addJoin( name, joinSequence );
 
456
        }
 
457
 
 
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 );
 
464
        }
 
465
 
 
466
        void addSelectClass(String name) {
 
467
                returnedTypes.add( name );
 
468
        }
 
469
 
 
470
        void addSelectScalar(Type type) {
 
471
                scalarTypes.add( type );
 
472
        }
 
473
 
 
474
        void appendWhereToken(String token) {
 
475
                whereTokens.add( token );
 
476
        }
 
477
 
 
478
        void appendHavingToken(String token) {
 
479
                havingTokens.add( token );
 
480
        }
 
481
 
 
482
        void appendOrderByToken(String token) {
 
483
                orderByTokens.add( token );
 
484
        }
 
485
 
 
486
        void appendGroupByToken(String token) {
 
487
                groupByTokens.add( token );
 
488
        }
 
489
 
 
490
        void appendScalarSelectToken(String token) {
 
491
                scalarSelectTokens.add( token );
 
492
        }
 
493
 
 
494
        void appendScalarSelectTokens(String[] tokens) {
 
495
                scalarSelectTokens.add( tokens );
 
496
        }
 
497
 
 
498
        void addFromJoinOnly(String name, JoinSequence joinSequence) throws QueryException {
 
499
                addJoin( name, joinSequence.getFromPart() );
 
500
        }
 
501
 
 
502
        void addJoin(String name, JoinSequence joinSequence) throws QueryException {
 
503
                if ( !joins.containsKey( name ) ) joins.put( name, joinSequence );
 
504
        }
 
505
 
 
506
        void addNamedParameter(String name) {
 
507
                if ( superQuery != null ) superQuery.addNamedParameter( name );
 
508
                Integer loc = new Integer( parameterCount++ );
 
509
                Object o = namedParameters.get( name );
 
510
                if ( o == null ) {
 
511
                        namedParameters.put( name, loc );
 
512
                }
 
513
                else if ( o instanceof Integer ) {
 
514
                        ArrayList list = new ArrayList( 4 );
 
515
                        list.add( o );
 
516
                        list.add( loc );
 
517
                        namedParameters.put( name, list );
 
518
                }
 
519
                else {
 
520
                        ( ( ArrayList ) o ).add( loc );
 
521
                }
 
522
        }
 
523
 
 
524
        public int[] getNamedParameterLocs(String name) throws QueryException {
 
525
                Object o = namedParameters.get( name );
 
526
                if ( o == null ) {
 
527
                        QueryException qe = new QueryException( ERROR_NAMED_PARAMETER_DOES_NOT_APPEAR + name );
 
528
                        qe.setQueryString( queryString );
 
529
                        throw qe;
 
530
                }
 
531
                if ( o instanceof Integer ) {
 
532
                        return new int[]{ ( ( Integer ) o ).intValue() };
 
533
                }
 
534
                else {
 
535
                        return ArrayHelper.toIntArray( ( ArrayList ) o );
 
536
                }
 
537
        }
 
538
 
 
539
        private void renderSQL() throws QueryException, MappingException {
 
540
 
 
541
                final int rtsize;
 
542
                if ( returnedTypes.size() == 0 && scalarTypes.size() == 0 ) {
 
543
                        //ie no select clause in HQL
 
544
                        returnedTypes = fromTypes;
 
545
                        rtsize = returnedTypes.size();
 
546
                }
 
547
                else {
 
548
                        rtsize = returnedTypes.size();
 
549
                        Iterator iter = entitiesToFetch.iterator();
 
550
                        while ( iter.hasNext() ) {
 
551
                                returnedTypes.add( iter.next() );
 
552
                        }
 
553
                }
 
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 ) + '_';
 
567
                        names[i] = name;
 
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 );
 
574
                }
 
575
 
 
576
                if ( ArrayHelper.isAllNegative( owners ) ) owners = null;
 
577
 
 
578
                String scalarSelect = renderScalarSelect(); //Must be done here because of side-effect! yuck...
 
579
 
 
580
                int scalarSize = scalarTypes.size();
 
581
                hasScalars = scalarTypes.size() != rtsize;
 
582
 
 
583
                returnTypes = new Type[scalarSize];
 
584
                for ( int i = 0; i < scalarSize; i++ ) {
 
585
                        returnTypes[i] = ( Type ) scalarTypes.get( i );
 
586
                }
 
587
 
 
588
                QuerySelect sql = new QuerySelect( getFactory().getDialect() );
 
589
                sql.setDistinct( distinct );
 
590
 
 
591
                if ( !shallowQuery ) {
 
592
                        renderIdentifierSelect( sql );
 
593
                        renderPropertiesSelect( sql );
 
594
                }
 
595
 
 
596
                if ( collectionPersister != null ) {
 
597
                        sql.addSelectFragmentString( collectionPersister.selectFragment( fetchName, "__" ) );
 
598
                }
 
599
 
 
600
                if ( hasScalars || shallowQuery ) sql.addSelectFragmentString( scalarSelect );
 
601
 
 
602
                //TODO: for some dialects it would be appropriate to add the renderOrderByPropertiesSelect() to other select strings
 
603
                mergeJoins( sql.getJoinFragment() );
 
604
 
 
605
                sql.setWhereTokens( whereTokens.iterator() );
 
606
 
 
607
                sql.setGroupByTokens( groupByTokens.iterator() );
 
608
                sql.setHavingTokens( havingTokens.iterator() );
 
609
                sql.setOrderByTokens( orderByTokens.iterator() );
 
610
 
 
611
                if ( collectionPersister != null && collectionPersister.hasOrdering() ) {
 
612
                        sql.addOrderBy( collectionPersister.getSQLOrderByString( fetchName ) );
 
613
                }
 
614
 
 
615
                scalarColumnNames = NameGenerator.generateColumnNames( returnTypes, getFactory() );
 
616
 
 
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() );
 
622
                }
 
623
                iter = typeMap.keySet().iterator();
 
624
                while ( iter.hasNext() ) {
 
625
                        Queryable p = getEntityPersisterForName( ( String ) iter.next() );
 
626
                        addQuerySpaces( p.getQuerySpaces() );
 
627
                }
 
628
 
 
629
                sqlString = sql.toQueryString();
 
630
 
 
631
                if ( holderClass != null ) holderConstructor = ReflectHelper.getConstructor( holderClass, returnTypes );
 
632
 
 
633
                if ( hasScalars ) {
 
634
                        actualReturnTypes = returnTypes;
 
635
                }
 
636
                else {
 
637
                        actualReturnTypes = new Type[selectLength];
 
638
                        int j = 0;
 
639
                        for ( int i = 0; i < persisters.length; i++ ) {
 
640
                                if ( includeInSelect[i] ) {
 
641
                                        actualReturnTypes[j++] = TypeFactory.manyToOne( persisters[i].getEntityName(), shallowQuery );
 
642
                                }
 
643
                        }
 
644
                }
 
645
 
 
646
        }
 
647
 
 
648
        private void renderIdentifierSelect(QuerySelect sql) {
 
649
                int size = returnedTypes.size();
 
650
 
 
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 ) );
 
655
                }
 
656
 
 
657
        }
 
658
 
 
659
        /*private String renderOrderByPropertiesSelect() {
 
660
                StringBuffer buf = new StringBuffer(10);
 
661
 
 
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);
 
669
                        }
 
670
                }
 
671
 
 
672
                return buf.toString();
 
673
        }*/
 
674
 
 
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 ) );
 
681
                }
 
682
        }
 
683
 
 
684
        /**
 
685
         * WARNING: side-effecty
 
686
         */
 
687
        private String renderScalarSelect() {
 
688
 
 
689
                boolean isSubselect = superQuery != null;
 
690
 
 
691
                StringBuffer buf = new StringBuffer( 20 );
 
692
 
 
693
                if ( scalarTypes.size() == 0 ) {
 
694
                        //ie. no select clause
 
695
                        int size = returnedTypes.size();
 
696
                        for ( int k = 0; k < size; k++ ) {
 
697
 
 
698
                                scalarTypes.add( TypeFactory.manyToOne( persisters[k].getEntityName(), shallowQuery ) );
 
699
 
 
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( ", " );
 
705
                                }
 
706
 
 
707
                        }
 
708
 
 
709
                }
 
710
                else {
 
711
                        //there _was_ a select clause
 
712
                        Iterator iter = scalarSelectTokens.iterator();
 
713
                        int c = 0;
 
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;
 
720
 
 
721
                                        if ( "(".equals( token ) ) {
 
722
                                                parenCount++;
 
723
                                        }
 
724
                                        else if ( ")".equals( token ) ) {
 
725
                                                parenCount--;
 
726
                                        }
 
727
 
 
728
                                        String lc = token.toLowerCase();
 
729
                                        if ( lc.equals( ", " ) ) {
 
730
                                                if ( nolast ) {
 
731
                                                        nolast = false;
 
732
                                                }
 
733
                                                else {
 
734
                                                        if ( !isSubselect && parenCount == 0 ) {
 
735
                                                                int x = c++;
 
736
                                                                buf.append( " as " )
 
737
                                                                                .append( NameGenerator.scalarName( x, 0 ) );
 
738
                                                        }
 
739
                                                }
 
740
                                        }
 
741
                                        buf.append( token );
 
742
                                        if ( lc.equals( "distinct" ) || lc.equals( "all" ) ) {
 
743
                                                buf.append( ' ' );
 
744
                                        }
 
745
                                }
 
746
                                else {
 
747
                                        nolast = true;
 
748
                                        String[] tokens = ( String[] ) next;
 
749
                                        for ( int i = 0; i < tokens.length; i++ ) {
 
750
                                                buf.append( tokens[i] );
 
751
                                                if ( !isSubselect ) {
 
752
                                                        buf.append( " as " )
 
753
                                                                        .append( NameGenerator.scalarName( c, i ) );
 
754
                                                }
 
755
                                                if ( i != tokens.length - 1 ) buf.append( ", " );
 
756
                                        }
 
757
                                        c++;
 
758
                                }
 
759
                        }
 
760
                        if ( !isSubselect && !nolast ) {
 
761
                                int x = c++;
 
762
                                buf.append( " as " )
 
763
                                                .append( NameGenerator.scalarName( x, 0 ) );
 
764
                        }
 
765
 
 
766
                }
 
767
 
 
768
                return buf.toString();
 
769
        }
 
770
 
 
771
        private void mergeJoins(JoinFragment ojf) throws MappingException, QueryException {
 
772
 
 
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();
 
781
                                        return include;
 
782
                                }
 
783
                        } );
 
784
 
 
785
                        if ( typeMap.containsKey( name ) ) {
 
786
                                ojf.addFragment( join.toJoinFragment( enabledFilters, true ) );
 
787
                        }
 
788
                        else if ( collections.containsKey( name ) ) {
 
789
                                ojf.addFragment( join.toJoinFragment( enabledFilters, true ) );
 
790
                        }
 
791
                        else {
 
792
                                //name from a super query (a bit inelegant that it shows up here)
 
793
                        }
 
794
 
 
795
                }
 
796
 
 
797
        }
 
798
 
 
799
        public final Set getQuerySpaces() {
 
800
                return querySpaces;
 
801
        }
 
802
 
 
803
        /**
 
804
         * Is this query called by scroll() or iterate()?
 
805
         *
 
806
         * @return true if it is, false if it is called by find() or list()
 
807
         */
 
808
        boolean isShallowQuery() {
 
809
                return shallowQuery;
 
810
        }
 
811
 
 
812
        void addQuerySpaces(Serializable[] spaces) {
 
813
                for ( int i = 0; i < spaces.length; i++ ) {
 
814
                        querySpaces.add( spaces[i] );
 
815
                }
 
816
                if ( superQuery != null ) superQuery.addQuerySpaces( spaces );
 
817
        }
 
818
 
 
819
        void setDistinct(boolean distinct) {
 
820
                this.distinct = distinct;
 
821
        }
 
822
 
 
823
        boolean isSubquery() {
 
824
                return superQuery != null;
 
825
        }
 
826
 
 
827
        /**
 
828
         * Overrides method from Loader
 
829
         */
 
830
        public CollectionPersister[] getCollectionPersisters() {
 
831
                return collectionPersister == null ? null : new CollectionPersister[] { collectionPersister };
 
832
        }
 
833
 
 
834
        protected String[] getCollectionSuffixes() {
 
835
                return collectionPersister == null ? null : new String[] { "__" };
 
836
        }
 
837
 
 
838
        void setCollectionToFetch(String role, String name, String ownerName, String entityName)
 
839
                        throws QueryException {
 
840
                fetchName = name;
 
841
                collectionPersister = getCollectionPersister( role );
 
842
                collectionOwnerName = ownerName;
 
843
                if ( collectionPersister.getElementType().isEntityType() ) {
 
844
                        addEntityToFetch( entityName );
 
845
                }
 
846
        }
 
847
 
 
848
        protected String[] getSuffixes() {
 
849
                return suffixes;
 
850
        }
 
851
 
 
852
        protected String[] getAliases() {
 
853
                return names;
 
854
        }
 
855
 
 
856
        /**
 
857
         * Used for collection filters
 
858
         */
 
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 );
 
866
                }
 
867
 
 
868
                String[] keyColumnNames = persister.getKeyColumnNames();
 
869
                //if (keyColumnNames.length!=1) throw new QueryException("composite-key collection in filter: " + collectionRole);
 
870
 
 
871
                String collectionName;
 
872
                JoinSequence join = new JoinSequence( getFactory() );
 
873
                collectionName = persister.isOneToMany() ?
 
874
                                elementName :
 
875
                                createNameForCollection( collectionRole );
 
876
                join.setRoot( persister, collectionName );
 
877
                if ( !persister.isOneToMany() ) {
 
878
                        //many-to-many
 
879
                        addCollection( collectionName, collectionRole );
 
880
                        try {
 
881
                                join.addJoin( ( AssociationType ) persister.getElementType(),
 
882
                                                elementName,
 
883
                                                JoinFragment.INNER_JOIN,
 
884
                                                persister.getElementColumnNames(collectionName) );
 
885
                        }
 
886
                        catch ( MappingException me ) {
 
887
                                throw new QueryException( me );
 
888
                        }
 
889
                }
 
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 );
 
894
 
 
895
        }
 
896
 
 
897
        String getPathAlias(String path) {
 
898
                return ( String ) pathAliases.get( path );
 
899
        }
 
900
 
 
901
        JoinSequence getPathJoin(String path) {
 
902
                return ( JoinSequence ) pathJoins.get( path );
 
903
        }
 
904
 
 
905
        void addPathAliasAndJoin(String path, String alias, JoinSequence joinSequence) {
 
906
                pathAliases.put( path, alias );
 
907
                pathJoins.put( path, joinSequence );
 
908
        }
 
909
 
 
910
        public List list(SessionImplementor session, QueryParameters queryParameters)
 
911
                        throws HibernateException {
 
912
                return list( session, queryParameters, getQuerySpaces(), actualReturnTypes );
 
913
        }
 
914
 
 
915
        /**
 
916
         * Return the query results as an iterator
 
917
         */
 
918
        public Iterator iterate(QueryParameters queryParameters, EventSource session)
 
919
                        throws HibernateException {
 
920
 
 
921
                boolean stats = session.getFactory().getStatistics().isStatisticsEnabled();
 
922
                long startTime = 0;
 
923
                if ( stats ) startTime = System.currentTimeMillis();
 
924
 
 
925
                try {
 
926
 
 
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 );
 
931
 
 
932
                        if ( stats ) {
 
933
                                session.getFactory().getStatisticsImplementor().queryExecuted(
 
934
                                                "HQL: " + queryString,
 
935
                                                0,
 
936
                                                System.currentTimeMillis() - startTime
 
937
                                        );
 
938
                        }
 
939
 
 
940
                        return result;
 
941
 
 
942
                }
 
943
                catch ( SQLException sqle ) {
 
944
                        throw JDBCExceptionHelper.convert(
 
945
                                        getFactory().getSQLExceptionConverter(),
 
946
                                        sqle,
 
947
                                        "could not execute query using iterate",
 
948
                                        getSQLString()
 
949
                                );
 
950
                }
 
951
 
 
952
        }
 
953
 
 
954
        public int executeUpdate(QueryParameters queryParameters, SessionImplementor session) throws HibernateException {
 
955
                throw new UnsupportedOperationException( "Not supported!  Use the AST translator...");
 
956
        }
 
957
 
 
958
        protected Object getResultColumnOrRow(Object[] row, ResultTransformer transformer, ResultSet rs, SessionImplementor session)
 
959
                        throws SQLException, HibernateException {
 
960
                row = toResultRow( row );
 
961
                if ( hasScalars ) {
 
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 );
 
966
                        }
 
967
                        else {
 
968
                                row = new Object[queryCols];
 
969
                                for ( int i = 0; i < queryCols; i++ )
 
970
                                        row[i] = returnTypes[i].nullSafeGet( rs, scalarColumns[i], session, null );
 
971
                                return row;
 
972
                        }
 
973
                }
 
974
                else if ( holderClass == null ) {
 
975
                        return row.length == 1 ? row[0] : row;
 
976
                }
 
977
                else {
 
978
                        return row;
 
979
                }
 
980
 
 
981
        }
 
982
 
 
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 );
 
987
                                try {
 
988
                                        results.set( i, holderConstructor.newInstance( row ) );
 
989
                                }
 
990
                                catch ( Exception e ) {
 
991
                                        throw new QueryException( "could not instantiate: " + holderClass, e );
 
992
                                }
 
993
                        }
 
994
                }
 
995
                return results;
 
996
        }
 
997
 
 
998
        private Object[] toResultRow(Object[] row) {
 
999
                if ( selectLength == row.length ) {
 
1000
                        return row;
 
1001
                }
 
1002
                else {
 
1003
                        Object[] result = new Object[selectLength];
 
1004
                        int j = 0;
 
1005
                        for ( int i = 0; i < row.length; i++ ) {
 
1006
                                if ( includeInSelect[i] ) result[j++] = row[i];
 
1007
                        }
 
1008
                        return result;
 
1009
                }
 
1010
        }
 
1011
 
 
1012
        void setHolderClass(Class clazz) {
 
1013
                holderClass = clazz;
 
1014
        }
 
1015
 
 
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() ),
 
1026
                                                me.getValue() );
 
1027
                        }
 
1028
                }
 
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;
 
1034
                }
 
1035
                return lockModeArray;
 
1036
        }
 
1037
 
 
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 ) {
 
1042
                        result = sql;
 
1043
                }
 
1044
                else {
 
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() );
 
1050
                        }
 
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() );
 
1056
                                }
 
1057
                        }
 
1058
                        result = dialect.applyLocksToSql( sql, aliasedLockModes, keyColumnNames );
 
1059
                }
 
1060
                logQuery( queryString, result );
 
1061
                return result;
 
1062
        }
 
1063
 
 
1064
        protected boolean upgradeLocks() {
 
1065
                return true;
 
1066
        }
 
1067
 
 
1068
        protected int[] getCollectionOwners() {
 
1069
                return new int[] { collectionOwnerColumn };
 
1070
        }
 
1071
 
 
1072
        protected boolean isCompiled() {
 
1073
                return compiled;
 
1074
        }
 
1075
 
 
1076
        public String toString() {
 
1077
                return queryString;
 
1078
        }
 
1079
 
 
1080
        protected int[] getOwners() {
 
1081
                return owners;
 
1082
        }
 
1083
 
 
1084
        protected EntityType[] getOwnerAssociationTypes() {
 
1085
                return ownerAssociationTypes;
 
1086
        }
 
1087
 
 
1088
        public Class getHolderClass() {
 
1089
                return holderClass;
 
1090
        }
 
1091
 
 
1092
        public Map getEnabledFilters() {
 
1093
                return enabledFilters;
 
1094
        }
 
1095
 
 
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 );
 
1101
        }
 
1102
 
 
1103
        public String getQueryIdentifier() {
 
1104
                return queryIdentifier;
 
1105
        }
 
1106
 
 
1107
        protected boolean isSubselectLoadingEnabled() {
 
1108
                return hasSubselectLoadableCollections();
 
1109
        }
 
1110
 
 
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" );
 
1115
                }
 
1116
        }
 
1117
 
 
1118
        public boolean containsCollectionFetches() {
 
1119
                return false;
 
1120
        }
 
1121
 
 
1122
        public boolean isManipulationStatement() {
 
1123
                // classic parser does not support bulk manipulation statements
 
1124
                return false;
 
1125
        }
 
1126
 
 
1127
        public ParameterTranslations getParameterTranslations() {
 
1128
                return new ParameterTranslations() {
 
1129
 
 
1130
                        public boolean supportsOrdinalParameterMetadata() {
 
1131
                                // classic translator does not support collection of ordinal
 
1132
                                // param metadata
 
1133
                                return false;
 
1134
                        }
 
1135
 
 
1136
                        public int getOrdinalParameterCount() {
 
1137
                                return 0; // not known!
 
1138
                        }
 
1139
 
 
1140
                        public int getOrdinalParameterSqlLocation(int ordinalPosition) {
 
1141
                                return 0; // not known!
 
1142
                        }
 
1143
 
 
1144
                        public Type getOrdinalParameterExpectedType(int ordinalPosition) {
 
1145
                                return null; // not known!
 
1146
                        }
 
1147
 
 
1148
                        public Set getNamedParameterNames() {
 
1149
                                return namedParameters.keySet();
 
1150
                        }
 
1151
 
 
1152
                        public int[] getNamedParameterSqlLocations(String name) {
 
1153
                                return getNamedParameterLocs( name );
 
1154
                        }
 
1155
 
 
1156
                        public Type getNamedParameterExpectedType(String name) {
 
1157
                                return null; // not known!
 
1158
                        }
 
1159
                };
 
1160
        }
 
1161
}