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

« back to all changes in this revision

Viewing changes to src/org/hibernate/persister/collection/AbstractCollectionPersister.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: AbstractCollectionPersister.java 10901 2006-11-30 21:50:48Z epbernard $
 
2
package org.hibernate.persister.collection;
 
3
 
 
4
import java.io.Serializable;
 
5
import java.sql.PreparedStatement;
 
6
import java.sql.ResultSet;
 
7
import java.sql.SQLException;
 
8
import java.util.Arrays;
 
9
import java.util.HashMap;
 
10
import java.util.Iterator;
 
11
import java.util.Map;
 
12
 
 
13
import org.apache.commons.logging.Log;
 
14
import org.apache.commons.logging.LogFactory;
 
15
import org.hibernate.AssertionFailure;
 
16
import org.hibernate.FetchMode;
 
17
import org.hibernate.HibernateException;
 
18
import org.hibernate.MappingException;
 
19
import org.hibernate.QueryException;
 
20
import org.hibernate.TransientObjectException;
 
21
import org.hibernate.jdbc.Expectation;
 
22
import org.hibernate.jdbc.Expectations;
 
23
import org.hibernate.cache.CacheConcurrencyStrategy;
 
24
import org.hibernate.cache.CacheException;
 
25
import org.hibernate.cache.entry.CacheEntryStructure;
 
26
import org.hibernate.cache.entry.StructuredCollectionCacheEntry;
 
27
import org.hibernate.cache.entry.StructuredMapCacheEntry;
 
28
import org.hibernate.cache.entry.UnstructuredCacheEntry;
 
29
import org.hibernate.cfg.Configuration;
 
30
import org.hibernate.collection.PersistentCollection;
 
31
import org.hibernate.dialect.Dialect;
 
32
import org.hibernate.engine.EntityKey;
 
33
import org.hibernate.engine.PersistenceContext;
 
34
import org.hibernate.engine.SessionFactoryImplementor;
 
35
import org.hibernate.engine.SessionImplementor;
 
36
import org.hibernate.engine.SubselectFetch;
 
37
import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
 
38
import org.hibernate.exception.JDBCExceptionHelper;
 
39
import org.hibernate.exception.SQLExceptionConverter;
 
40
import org.hibernate.id.IdentifierGenerator;
 
41
import org.hibernate.loader.collection.CollectionInitializer;
 
42
import org.hibernate.mapping.Collection;
 
43
import org.hibernate.mapping.Column;
 
44
import org.hibernate.mapping.Formula;
 
45
import org.hibernate.mapping.IdentifierCollection;
 
46
import org.hibernate.mapping.IndexedCollection;
 
47
import org.hibernate.mapping.List;
 
48
import org.hibernate.mapping.Selectable;
 
49
import org.hibernate.mapping.Table;
 
50
import org.hibernate.metadata.CollectionMetadata;
 
51
import org.hibernate.persister.entity.EntityPersister;
 
52
import org.hibernate.persister.entity.Loadable;
 
53
import org.hibernate.persister.entity.PropertyMapping;
 
54
import org.hibernate.pretty.MessageHelper;
 
55
import org.hibernate.sql.Alias;
 
56
import org.hibernate.sql.SelectFragment;
 
57
import org.hibernate.sql.SimpleSelect;
 
58
import org.hibernate.sql.Template;
 
59
import org.hibernate.type.AbstractComponentType;
 
60
import org.hibernate.type.CollectionType;
 
61
import org.hibernate.type.EntityType;
 
62
import org.hibernate.type.Type;
 
63
import org.hibernate.util.ArrayHelper;
 
64
import org.hibernate.util.CollectionHelper;
 
65
import org.hibernate.util.FilterHelper;
 
66
import org.hibernate.util.StringHelper;
 
67
 
 
68
 
 
69
/**
 
70
 * Base implementation of the <tt>QueryableCollection</tt> interface.
 
71
 *
 
72
 * @author Gavin King
 
73
 * @see BasicCollectionPersister
 
74
 * @see OneToManyPersister
 
75
 */
 
76
public abstract class AbstractCollectionPersister
 
77
                implements CollectionMetadata, SQLLoadableCollection {
 
78
        // TODO: encapsulate the protected instance variables!
 
79
 
 
80
        private final String role;
 
81
 
 
82
        //SQL statements
 
83
        private final String sqlDeleteString;
 
84
        private final String sqlInsertRowString;
 
85
        private final String sqlUpdateRowString;
 
86
        private final String sqlDeleteRowString;
 
87
        private final String sqlSelectSizeString;
 
88
        private final String sqlSelectRowByIndexString;
 
89
        private final String sqlDetectRowByIndexString;
 
90
        private final String sqlDetectRowByElementString;
 
91
 
 
92
        private final String sqlOrderByString;
 
93
        protected final String sqlWhereString;
 
94
        private final String sqlOrderByStringTemplate;
 
95
        private final String sqlWhereStringTemplate;
 
96
        private final boolean hasOrder;
 
97
        protected final boolean hasWhere;
 
98
        private final int baseIndex;
 
99
        
 
100
        private final String nodeName;
 
101
        private final String elementNodeName;
 
102
        private final String indexNodeName;
 
103
 
 
104
        protected final boolean indexContainsFormula;
 
105
        protected final boolean elementIsPureFormula;
 
106
        
 
107
        //types
 
108
        private final Type keyType;
 
109
        private final Type indexType;
 
110
        protected final Type elementType;
 
111
        private final Type identifierType;
 
112
 
 
113
        //columns
 
114
        protected final String[] keyColumnNames;
 
115
        protected final String[] indexColumnNames;
 
116
        protected final String[] indexFormulaTemplates;
 
117
        protected final String[] indexFormulas;
 
118
        protected final boolean[] indexColumnIsSettable;
 
119
        protected final String[] elementColumnNames;
 
120
        protected final String[] elementFormulaTemplates;
 
121
        protected final String[] elementFormulas;
 
122
        protected final boolean[] elementColumnIsSettable;
 
123
        protected final boolean[] elementColumnIsInPrimaryKey;
 
124
        protected final String[] indexColumnAliases;
 
125
        protected final String[] elementColumnAliases;
 
126
        protected final String[] keyColumnAliases;
 
127
        
 
128
        protected final String identifierColumnName;
 
129
        private final String identifierColumnAlias;
 
130
        //private final String unquotedIdentifierColumnName;
 
131
 
 
132
        protected final String qualifiedTableName;
 
133
 
 
134
        private final String queryLoaderName;
 
135
 
 
136
        private final boolean isPrimitiveArray;
 
137
        private final boolean isArray;
 
138
        protected final boolean hasIndex;
 
139
        protected final boolean hasIdentifier;
 
140
        private final boolean isLazy;
 
141
        private final boolean isExtraLazy;
 
142
        private final boolean isInverse;
 
143
        private final boolean isMutable;
 
144
        private final boolean isVersioned;
 
145
        protected final int batchSize;
 
146
        private final FetchMode fetchMode;
 
147
        private final boolean hasOrphanDelete;
 
148
        private final boolean subselectLoadable;
 
149
 
 
150
        //extra information about the element type
 
151
        private final Class elementClass;
 
152
        private final String entityName;
 
153
 
 
154
        private final Dialect dialect;
 
155
        private final SQLExceptionConverter sqlExceptionConverter;
 
156
        private final SessionFactoryImplementor factory;
 
157
        private final EntityPersister ownerPersister;
 
158
        private final IdentifierGenerator identifierGenerator;
 
159
        private final PropertyMapping elementPropertyMapping;
 
160
        private final EntityPersister elementPersister;
 
161
        private final CacheConcurrencyStrategy cache;
 
162
        private final CollectionType collectionType;
 
163
        private CollectionInitializer initializer;
 
164
        
 
165
        private final CacheEntryStructure cacheEntryStructure;
 
166
 
 
167
        // dynamic filters for the collection
 
168
        private final FilterHelper filterHelper;
 
169
 
 
170
        // dynamic filters specifically for many-to-many inside the collection
 
171
        private final FilterHelper manyToManyFilterHelper;
 
172
 
 
173
        private final String manyToManyWhereString;
 
174
        private final String manyToManyWhereTemplate;
 
175
 
 
176
        private final String manyToManyOrderByString;
 
177
        private final String manyToManyOrderByTemplate;
 
178
 
 
179
        // custom sql
 
180
        private final boolean insertCallable;
 
181
        private final boolean updateCallable;
 
182
        private final boolean deleteCallable;
 
183
        private final boolean deleteAllCallable;
 
184
        private ExecuteUpdateResultCheckStyle insertCheckStyle;
 
185
        private ExecuteUpdateResultCheckStyle updateCheckStyle;
 
186
        private ExecuteUpdateResultCheckStyle deleteCheckStyle;
 
187
        private ExecuteUpdateResultCheckStyle deleteAllCheckStyle;
 
188
 
 
189
        private final Serializable[] spaces;
 
190
 
 
191
        private Map collectionPropertyColumnAliases = new HashMap();
 
192
        private Map collectionPropertyColumnNames = new HashMap();
 
193
 
 
194
        private static final Log log = LogFactory.getLog( AbstractCollectionPersister.class );
 
195
 
 
196
        public AbstractCollectionPersister(
 
197
                        final Collection collection,
 
198
                        final CacheConcurrencyStrategy cache,
 
199
                        final Configuration cfg,
 
200
                        final SessionFactoryImplementor factory)
 
201
        throws MappingException, CacheException {
 
202
 
 
203
                this.factory = factory;
 
204
                this.cache = cache;
 
205
                if ( factory.getSettings().isStructuredCacheEntriesEnabled() ) {
 
206
                        cacheEntryStructure = collection.isMap() ? 
 
207
                                        (CacheEntryStructure) new StructuredMapCacheEntry() : 
 
208
                                        (CacheEntryStructure) new StructuredCollectionCacheEntry();
 
209
                }
 
210
                else {
 
211
                        cacheEntryStructure = new UnstructuredCacheEntry();
 
212
                }
 
213
                
 
214
                dialect = factory.getDialect();
 
215
                sqlExceptionConverter = factory.getSQLExceptionConverter();
 
216
                collectionType = collection.getCollectionType();
 
217
                role = collection.getRole();
 
218
                entityName = collection.getOwnerEntityName();
 
219
                ownerPersister = factory.getEntityPersister(entityName);
 
220
                queryLoaderName = collection.getLoaderName();
 
221
                nodeName = collection.getNodeName();
 
222
                isMutable = collection.isMutable();
 
223
 
 
224
                Table table = collection.getCollectionTable();
 
225
                fetchMode = collection.getElement().getFetchMode();
 
226
                elementType = collection.getElement().getType();
 
227
                //isSet = collection.isSet();
 
228
                //isSorted = collection.isSorted();
 
229
                isPrimitiveArray = collection.isPrimitiveArray();
 
230
                isArray = collection.isArray();
 
231
                subselectLoadable = collection.isSubselectLoadable();
 
232
                
 
233
                qualifiedTableName = table.getQualifiedName( 
 
234
                                dialect,
 
235
                                factory.getSettings().getDefaultCatalogName(),
 
236
                                factory.getSettings().getDefaultSchemaName() 
 
237
                        );
 
238
 
 
239
                int spacesSize = 1 + collection.getSynchronizedTables().size();
 
240
                spaces = new String[spacesSize];
 
241
                spaces[0] = qualifiedTableName;
 
242
                Iterator iter = collection.getSynchronizedTables().iterator();
 
243
                for ( int i = 1; i < spacesSize; i++ ) {
 
244
                        spaces[i] = (String) iter.next();
 
245
                }
 
246
                
 
247
                sqlOrderByString = collection.getOrderBy();
 
248
                hasOrder = sqlOrderByString != null;
 
249
                sqlOrderByStringTemplate = hasOrder ?
 
250
                                Template.renderOrderByStringTemplate(sqlOrderByString, dialect, factory.getSqlFunctionRegistry()) :
 
251
                                null;
 
252
                sqlWhereString = StringHelper.isNotEmpty( collection.getWhere() ) ? "( " + collection.getWhere() + ") " : null;
 
253
                hasWhere = sqlWhereString != null;
 
254
                sqlWhereStringTemplate = hasWhere ?
 
255
                                Template.renderWhereStringTemplate(sqlWhereString, dialect, factory.getSqlFunctionRegistry()) :
 
256
                                null;
 
257
 
 
258
                hasOrphanDelete = collection.hasOrphanDelete();
 
259
 
 
260
                int batch = collection.getBatchSize();
 
261
                if ( batch == -1 ) {
 
262
                        batch = factory.getSettings().getDefaultBatchFetchSize();
 
263
                }
 
264
                batchSize = batch;
 
265
 
 
266
                isVersioned = collection.isOptimisticLocked();
 
267
                
 
268
                // KEY
 
269
 
 
270
                keyType = collection.getKey().getType();
 
271
                iter = collection.getKey().getColumnIterator();
 
272
                int keySpan = collection.getKey().getColumnSpan();
 
273
                keyColumnNames = new String[keySpan];
 
274
                keyColumnAliases = new String[keySpan];
 
275
                int k = 0;
 
276
                while ( iter.hasNext() ) {
 
277
                        // NativeSQL: collect key column and auto-aliases
 
278
                        Column col = ( (Column) iter.next() );
 
279
                        keyColumnNames[k] = col.getQuotedName(dialect);
 
280
                        keyColumnAliases[k] = col.getAlias(dialect);
 
281
                        k++;
 
282
                }
 
283
                
 
284
                //unquotedKeyColumnNames = StringHelper.unQuote(keyColumnAliases);
 
285
 
 
286
                //ELEMENT
 
287
 
 
288
                String elemNode = collection.getElementNodeName();
 
289
                if ( elementType.isEntityType() ) {
 
290
                        String entityName = ( (EntityType) elementType ).getAssociatedEntityName();
 
291
                        elementPersister = factory.getEntityPersister(entityName);
 
292
                        if ( elemNode==null ) {
 
293
                                elemNode = cfg.getClassMapping(entityName).getNodeName();
 
294
                        }
 
295
                        // NativeSQL: collect element column and auto-aliases
 
296
                        
 
297
                }
 
298
                else {
 
299
                        elementPersister = null;
 
300
                }               
 
301
                elementNodeName = elemNode;
 
302
 
 
303
                int elementSpan = collection.getElement().getColumnSpan();
 
304
                elementColumnAliases = new String[elementSpan];
 
305
                elementColumnNames = new String[elementSpan];
 
306
                elementFormulaTemplates = new String[elementSpan];
 
307
                elementFormulas = new String[elementSpan];
 
308
                elementColumnIsSettable = new boolean[elementSpan];
 
309
                elementColumnIsInPrimaryKey = new boolean[elementSpan];
 
310
                boolean isPureFormula = true;
 
311
                boolean hasNotNullableColumns = false;
 
312
                int j = 0;
 
313
                iter = collection.getElement().getColumnIterator();
 
314
                while ( iter.hasNext() ) {
 
315
                        Selectable selectable = (Selectable) iter.next();
 
316
                        elementColumnAliases[j] = selectable.getAlias(dialect);
 
317
                        if ( selectable.isFormula() ) {
 
318
                                Formula form = (Formula) selectable;
 
319
                                elementFormulaTemplates[j] = form.getTemplate(dialect, factory.getSqlFunctionRegistry());
 
320
                                elementFormulas[j] = form.getFormula();
 
321
                        }
 
322
                        else {
 
323
                                Column col = (Column) selectable;
 
324
                                elementColumnNames[j] = col.getQuotedName(dialect);
 
325
                                elementColumnIsSettable[j] = true;
 
326
                                elementColumnIsInPrimaryKey[j] = !col.isNullable();
 
327
                                if ( !col.isNullable() ) {
 
328
                                        hasNotNullableColumns = true;
 
329
                                }
 
330
                                isPureFormula = false;
 
331
                        }
 
332
                        j++;
 
333
                }
 
334
                elementIsPureFormula = isPureFormula;
 
335
                
 
336
                //workaround, for backward compatibility of sets with no
 
337
                //not-null columns, assume all columns are used in the
 
338
                //row locator SQL
 
339
                if ( !hasNotNullableColumns ) {
 
340
                        Arrays.fill( elementColumnIsInPrimaryKey, true );
 
341
                }
 
342
 
 
343
 
 
344
                // INDEX AND ROW SELECT
 
345
 
 
346
                hasIndex = collection.isIndexed();
 
347
                if (hasIndex) {
 
348
                        // NativeSQL: collect index column and auto-aliases
 
349
                        IndexedCollection indexedCollection = (IndexedCollection) collection;
 
350
                        indexType = indexedCollection.getIndex().getType();
 
351
                        int indexSpan = indexedCollection.getIndex().getColumnSpan();
 
352
                        iter = indexedCollection.getIndex().getColumnIterator();
 
353
                        indexColumnNames = new String[indexSpan];
 
354
                        indexFormulaTemplates = new String[indexSpan];
 
355
                        indexFormulas = new String[indexSpan];
 
356
                        indexColumnIsSettable = new boolean[indexSpan];
 
357
                        indexColumnAliases = new String[indexSpan];
 
358
                        int i = 0;
 
359
                        boolean hasFormula = false;
 
360
                        while ( iter.hasNext() ) {
 
361
                                Selectable s = (Selectable) iter.next();
 
362
                                indexColumnAliases[i] = s.getAlias(dialect);
 
363
                                if ( s.isFormula() ) {
 
364
                                        Formula indexForm = (Formula) s;
 
365
                                        indexFormulaTemplates[i] = indexForm.getTemplate(dialect, factory.getSqlFunctionRegistry());
 
366
                                        indexFormulas[i] = indexForm.getFormula();
 
367
                                        hasFormula = true;
 
368
                                }
 
369
                                else {
 
370
                                        Column indexCol = (Column) s;
 
371
                                        indexColumnNames[i] = indexCol.getQuotedName(dialect);
 
372
                                        indexColumnIsSettable[i] = true;
 
373
                                }
 
374
                                i++;
 
375
                        }
 
376
                        indexContainsFormula = hasFormula;
 
377
                        baseIndex = indexedCollection.isList() ? 
 
378
                                        ( (List) indexedCollection ).getBaseIndex() : 0;
 
379
 
 
380
                        indexNodeName = indexedCollection.getIndexNodeName(); 
 
381
 
 
382
                }
 
383
                else {
 
384
                        indexContainsFormula = false;
 
385
                        indexColumnIsSettable = null;
 
386
                        indexFormulaTemplates = null;
 
387
                        indexFormulas = null;
 
388
                        indexType = null;
 
389
                        indexColumnNames = null;
 
390
                        indexColumnAliases = null;
 
391
                        baseIndex = 0;
 
392
                        indexNodeName = null;
 
393
                }
 
394
                
 
395
                hasIdentifier = collection.isIdentified();
 
396
                if (hasIdentifier) {
 
397
                        if ( collection.isOneToMany() ) {
 
398
                                throw new MappingException( "one-to-many collections with identifiers are not supported" );
 
399
                        }
 
400
                        IdentifierCollection idColl = (IdentifierCollection) collection;
 
401
                        identifierType = idColl.getIdentifier().getType();
 
402
                        iter = idColl.getIdentifier().getColumnIterator();
 
403
                        Column col = ( Column ) iter.next();
 
404
                        identifierColumnName = col.getQuotedName(dialect);
 
405
                        identifierColumnAlias = col.getAlias(dialect);
 
406
                        //unquotedIdentifierColumnName = identifierColumnAlias;
 
407
                        identifierGenerator = idColl.getIdentifier().createIdentifierGenerator( 
 
408
                                        factory.getDialect(),
 
409
                                        factory.getSettings().getDefaultCatalogName(),
 
410
                                        factory.getSettings().getDefaultSchemaName(),
 
411
                                        null
 
412
                                );
 
413
                }
 
414
                else {
 
415
                        identifierType = null;
 
416
                        identifierColumnName = null;
 
417
                        identifierColumnAlias = null;
 
418
                        //unquotedIdentifierColumnName = null;
 
419
                        identifierGenerator = null;
 
420
                }
 
421
                
 
422
                //GENERATE THE SQL:
 
423
                                
 
424
                //sqlSelectString = sqlSelectString();
 
425
                //sqlSelectRowString = sqlSelectRowString();
 
426
 
 
427
                if ( collection.getCustomSQLInsert() == null ) {
 
428
                        sqlInsertRowString = generateInsertRowString();
 
429
                        insertCallable = false;
 
430
                        insertCheckStyle = ExecuteUpdateResultCheckStyle.COUNT;
 
431
                }
 
432
                else {
 
433
                        sqlInsertRowString = collection.getCustomSQLInsert();
 
434
                        insertCallable = collection.isCustomInsertCallable();
 
435
                        insertCheckStyle = collection.getCustomSQLInsertCheckStyle() == null
 
436
                                        ? ExecuteUpdateResultCheckStyle.determineDefault( collection.getCustomSQLInsert(), insertCallable )
 
437
                            : collection.getCustomSQLInsertCheckStyle();
 
438
                }
 
439
 
 
440
                if ( collection.getCustomSQLUpdate() == null ) {
 
441
                        sqlUpdateRowString = generateUpdateRowString();
 
442
                        updateCallable = false;
 
443
                        updateCheckStyle = ExecuteUpdateResultCheckStyle.COUNT;
 
444
                }
 
445
                else {
 
446
                        sqlUpdateRowString = collection.getCustomSQLUpdate();
 
447
                        updateCallable = collection.isCustomUpdateCallable();
 
448
                        updateCheckStyle = collection.getCustomSQLUpdateCheckStyle() == null
 
449
                                        ? ExecuteUpdateResultCheckStyle.determineDefault( collection.getCustomSQLUpdate(), insertCallable )
 
450
                            : collection.getCustomSQLUpdateCheckStyle();
 
451
                }
 
452
 
 
453
                if ( collection.getCustomSQLDelete() == null ) {
 
454
                        sqlDeleteRowString = generateDeleteRowString();
 
455
                        deleteCallable = false;
 
456
                        deleteCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
 
457
                }
 
458
                else {
 
459
                        sqlDeleteRowString = collection.getCustomSQLDelete();
 
460
                        deleteCallable = collection.isCustomDeleteCallable();
 
461
                        deleteCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
 
462
                }
 
463
 
 
464
                if ( collection.getCustomSQLDeleteAll() == null ) {
 
465
                        sqlDeleteString = generateDeleteString();
 
466
                        deleteAllCallable = false;
 
467
                        deleteAllCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
 
468
                }
 
469
                else {
 
470
                        sqlDeleteString = collection.getCustomSQLDeleteAll();
 
471
                        deleteAllCallable = collection.isCustomDeleteAllCallable();
 
472
                        deleteAllCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
 
473
                }
 
474
 
 
475
                sqlSelectSizeString = generateSelectSizeString(  collection.isIndexed() && !collection.isMap() );
 
476
                sqlDetectRowByIndexString = generateDetectRowByIndexString();
 
477
                sqlDetectRowByElementString = generateDetectRowByElementString();
 
478
                sqlSelectRowByIndexString = generateSelectRowByIndexString();
 
479
                
 
480
                logStaticSQL();
 
481
                
 
482
                isLazy = collection.isLazy();
 
483
                isExtraLazy = collection.isExtraLazy();
 
484
 
 
485
                isInverse = collection.isInverse();
 
486
 
 
487
                if ( collection.isArray() ) {
 
488
                        elementClass = ( (org.hibernate.mapping.Array) collection ).getElementClass();
 
489
                }
 
490
                else {
 
491
                        // for non-arrays, we don't need to know the element class
 
492
                        elementClass = null; //elementType.returnedClass();
 
493
                }
 
494
 
 
495
                if ( elementType.isComponentType() ) {
 
496
                        elementPropertyMapping = new CompositeElementPropertyMapping( 
 
497
                                        elementColumnNames,
 
498
                                        elementFormulaTemplates,
 
499
                                        (AbstractComponentType) elementType,
 
500
                                        factory 
 
501
                                );
 
502
                }
 
503
                else if ( !elementType.isEntityType() ) {
 
504
                        elementPropertyMapping = new ElementPropertyMapping( 
 
505
                                        elementColumnNames,
 
506
                                        elementType 
 
507
                                );
 
508
                }
 
509
                else {
 
510
                        if ( elementPersister instanceof PropertyMapping ) { //not all classpersisters implement PropertyMapping!
 
511
                                elementPropertyMapping = (PropertyMapping) elementPersister;
 
512
                        }
 
513
                        else {
 
514
                                elementPropertyMapping = new ElementPropertyMapping( 
 
515
                                                elementColumnNames,
 
516
                                                elementType 
 
517
                                        );
 
518
                        }
 
519
                }
 
520
                        
 
521
                // Handle any filters applied to this collection
 
522
                filterHelper = new FilterHelper( collection.getFilterMap(), dialect, factory.getSqlFunctionRegistry() );
 
523
 
 
524
                // Handle any filters applied to this collection for many-to-many
 
525
                manyToManyFilterHelper = new FilterHelper( collection.getManyToManyFilterMap(), dialect, factory.getSqlFunctionRegistry() );
 
526
                manyToManyWhereString = StringHelper.isNotEmpty( collection.getManyToManyWhere() ) ?
 
527
                                "( " + collection.getManyToManyWhere() + " )" :
 
528
                                null;
 
529
                manyToManyWhereTemplate = manyToManyWhereString == null ?
 
530
                                null :
 
531
                                Template.renderWhereStringTemplate( manyToManyWhereString, factory.getDialect(), factory.getSqlFunctionRegistry() );
 
532
                manyToManyOrderByString = collection.getManyToManyOrdering();
 
533
                manyToManyOrderByTemplate = manyToManyOrderByString == null
 
534
                                ? null
 
535
                    : Template.renderOrderByStringTemplate( manyToManyOrderByString, factory.getDialect(), factory.getSqlFunctionRegistry() );
 
536
 
 
537
                initCollectionPropertyMap();
 
538
        }
 
539
 
 
540
        public void postInstantiate() throws MappingException {
 
541
                initializer = queryLoaderName == null ?
 
542
                                createCollectionInitializer( CollectionHelper.EMPTY_MAP ) :
 
543
                                new NamedQueryCollectionInitializer( queryLoaderName, this );
 
544
        }
 
545
 
 
546
        protected void logStaticSQL() {
 
547
                if ( log.isDebugEnabled() ) {
 
548
                        log.debug( "Static SQL for collection: " + getRole() );
 
549
                        if ( getSQLInsertRowString() != null ) {
 
550
                                log.debug( " Row insert: " + getSQLInsertRowString() );
 
551
                        }
 
552
                        if ( getSQLUpdateRowString() != null ) {
 
553
                                log.debug( " Row update: " + getSQLUpdateRowString() );
 
554
                        }
 
555
                        if ( getSQLDeleteRowString() != null ) {
 
556
                                log.debug( " Row delete: " + getSQLDeleteRowString() );
 
557
                        }
 
558
                        if ( getSQLDeleteString() != null ) {
 
559
                                log.debug( " One-shot delete: " + getSQLDeleteString() );
 
560
                        }
 
561
                }
 
562
        }
 
563
 
 
564
        public void initialize(Serializable key, SessionImplementor session) throws HibernateException {
 
565
                getAppropriateInitializer( key, session ).initialize( key, session );
 
566
        }
 
567
 
 
568
        protected CollectionInitializer getAppropriateInitializer(Serializable key, SessionImplementor session) {
 
569
                if ( queryLoaderName != null ) {
 
570
                        //if there is a user-specified loader, return that
 
571
                        //TODO: filters!?
 
572
                        return initializer;
 
573
                }
 
574
                CollectionInitializer subselectInitializer = getSubselectInitializer( key, session );
 
575
                if ( subselectInitializer != null ) {
 
576
                        return subselectInitializer;
 
577
                }
 
578
                else if ( session.getEnabledFilters().isEmpty() ) {
 
579
                        return initializer;
 
580
                }
 
581
                else {
 
582
                        return createCollectionInitializer( session.getEnabledFilters() );
 
583
                }
 
584
        }
 
585
 
 
586
        private CollectionInitializer getSubselectInitializer(Serializable key, SessionImplementor session) {
 
587
 
 
588
                if ( !isSubselectLoadable() ) {
 
589
                        return null;
 
590
                }
 
591
                
 
592
                final PersistenceContext persistenceContext = session.getPersistenceContext();
 
593
                
 
594
                SubselectFetch subselect = persistenceContext.getBatchFetchQueue()
 
595
                        .getSubselect( new EntityKey( key, getOwnerEntityPersister(), session.getEntityMode() ) );
 
596
                
 
597
                if (subselect == null) {
 
598
                        return null;
 
599
                }
 
600
                else {
 
601
                        
 
602
                        // Take care of any entities that might have
 
603
                        // been evicted!        
 
604
                        Iterator iter = subselect.getResult().iterator();
 
605
                        while ( iter.hasNext() ) {
 
606
                                if ( !persistenceContext.containsEntity( (EntityKey) iter.next() ) ) {
 
607
                                        iter.remove();
 
608
                                }
 
609
                        }       
 
610
                        
 
611
                        // Run a subquery loader
 
612
                        return createSubselectInitializer( subselect, session );
 
613
                }
 
614
        }
 
615
 
 
616
        protected abstract CollectionInitializer createSubselectInitializer(SubselectFetch subselect, SessionImplementor session);
 
617
 
 
618
        protected abstract CollectionInitializer createCollectionInitializer(Map enabledFilters)
 
619
                        throws MappingException;
 
620
 
 
621
        public CacheConcurrencyStrategy getCache() {
 
622
                return cache;
 
623
        }
 
624
 
 
625
        public boolean hasCache() {
 
626
                return cache != null;
 
627
        }
 
628
 
 
629
        public CollectionType getCollectionType() {
 
630
                return collectionType;
 
631
        }
 
632
 
 
633
        protected String getSQLWhereString(String alias) {
 
634
                return StringHelper.replace( sqlWhereStringTemplate, Template.TEMPLATE, alias );
 
635
        }
 
636
 
 
637
        public String getSQLOrderByString(String alias) {
 
638
                return hasOrdering() ? 
 
639
                        StringHelper.replace( sqlOrderByStringTemplate, Template.TEMPLATE, alias ) : "";
 
640
        }
 
641
 
 
642
        public String getManyToManyOrderByString(String alias) {
 
643
                if ( isManyToMany() && manyToManyOrderByString != null ) {
 
644
                        return StringHelper.replace( manyToManyOrderByTemplate, Template.TEMPLATE, alias );
 
645
                }
 
646
                else {
 
647
                        return "";
 
648
                }
 
649
        }
 
650
        public FetchMode getFetchMode() {
 
651
                return fetchMode;
 
652
        }
 
653
 
 
654
        public boolean hasOrdering() {
 
655
                return hasOrder;
 
656
        }
 
657
 
 
658
        public boolean hasManyToManyOrdering() {
 
659
                return isManyToMany() && manyToManyOrderByTemplate != null;
 
660
        }
 
661
 
 
662
        public boolean hasWhere() {
 
663
                return hasWhere;
 
664
        }
 
665
 
 
666
        protected String getSQLDeleteString() {
 
667
                return sqlDeleteString;
 
668
        }
 
669
 
 
670
        protected String getSQLInsertRowString() {
 
671
                return sqlInsertRowString;
 
672
        }
 
673
 
 
674
        protected String getSQLUpdateRowString() {
 
675
                return sqlUpdateRowString;
 
676
        }
 
677
 
 
678
        protected String getSQLDeleteRowString() {
 
679
                return sqlDeleteRowString;
 
680
        }
 
681
 
 
682
        public Type getKeyType() {
 
683
                return keyType;
 
684
        }
 
685
 
 
686
        public Type getIndexType() {
 
687
                return indexType;
 
688
        }
 
689
 
 
690
        public Type getElementType() {
 
691
                return elementType;
 
692
        }
 
693
 
 
694
        /**
 
695
         * Return the element class of an array, or null otherwise
 
696
         */
 
697
        public Class getElementClass() { //needed by arrays
 
698
                return elementClass;
 
699
        }
 
700
 
 
701
        public Object readElement(ResultSet rs, Object owner, String[] aliases, SessionImplementor session) 
 
702
        throws HibernateException, SQLException {
 
703
                return getElementType().nullSafeGet( rs, aliases, session, owner );
 
704
        }
 
705
 
 
706
        public Object readIndex(ResultSet rs, String[] aliases, SessionImplementor session) 
 
707
        throws HibernateException, SQLException {
 
708
                Object index = getIndexType().nullSafeGet( rs, aliases, session, null );
 
709
                if ( index == null ) {
 
710
                        throw new HibernateException( "null index column for collection: " + role );
 
711
                }
 
712
                index = decrementIndexByBase( index );
 
713
                return index;
 
714
        }
 
715
 
 
716
        protected Object decrementIndexByBase(Object index) {
 
717
                if (baseIndex!=0) {
 
718
                        index = new Integer( ( (Integer) index ).intValue() - baseIndex );
 
719
                }
 
720
                return index;
 
721
        }
 
722
 
 
723
        public Object readIdentifier(ResultSet rs, String alias, SessionImplementor session) 
 
724
        throws HibernateException, SQLException {
 
725
                Object id = getIdentifierType().nullSafeGet( rs, alias, session, null );
 
726
                if ( id == null ) {
 
727
                        throw new HibernateException( "null identifier column for collection: " + role );
 
728
                }
 
729
                return id;
 
730
        }
 
731
 
 
732
        public Object readKey(ResultSet rs, String[] aliases, SessionImplementor session) 
 
733
        throws HibernateException, SQLException {
 
734
                return getKeyType().nullSafeGet( rs, aliases, session, null );
 
735
        }
 
736
 
 
737
        /**
 
738
         * Write the key to a JDBC <tt>PreparedStatement</tt>
 
739
         */
 
740
        protected int writeKey(PreparedStatement st, Serializable key, int i, SessionImplementor session)
 
741
                        throws HibernateException, SQLException {
 
742
                
 
743
                if ( key == null ) {
 
744
                        throw new NullPointerException( "null key for collection: " + role );  //an assertion
 
745
                }
 
746
                getKeyType().nullSafeSet( st, key, i, session );
 
747
                return i + keyColumnAliases.length;
 
748
        }
 
749
 
 
750
        /**
 
751
         * Write the element to a JDBC <tt>PreparedStatement</tt>
 
752
         */
 
753
        protected int writeElement(PreparedStatement st, Object elt, int i, SessionImplementor session)
 
754
                        throws HibernateException, SQLException {
 
755
                getElementType().nullSafeSet(st, elt, i, elementColumnIsSettable, session);
 
756
                return i + ArrayHelper.countTrue(elementColumnIsSettable);
 
757
 
 
758
        }
 
759
 
 
760
        /**
 
761
         * Write the index to a JDBC <tt>PreparedStatement</tt>
 
762
         */
 
763
        protected int writeIndex(PreparedStatement st, Object index, int i, SessionImplementor session)
 
764
                        throws HibernateException, SQLException {
 
765
                getIndexType().nullSafeSet( st, incrementIndexByBase(index), i, indexColumnIsSettable, session );
 
766
                return i + ArrayHelper.countTrue(indexColumnIsSettable);
 
767
        }
 
768
 
 
769
        protected Object incrementIndexByBase(Object index) {
 
770
                if (baseIndex!=0) {
 
771
                        index = new Integer( ( (Integer) index ).intValue() + baseIndex );
 
772
                }
 
773
                return index;
 
774
        }
 
775
 
 
776
        /**
 
777
         * Write the element to a JDBC <tt>PreparedStatement</tt>
 
778
         */
 
779
        protected int writeElementToWhere(PreparedStatement st, Object elt, int i, SessionImplementor session)
 
780
                        throws HibernateException, SQLException {
 
781
                if (elementIsPureFormula) {
 
782
                        throw new AssertionFailure("cannot use a formula-based element in the where condition");
 
783
                }
 
784
                getElementType().nullSafeSet(st, elt, i, elementColumnIsInPrimaryKey, session);
 
785
                return i + elementColumnAliases.length;
 
786
 
 
787
        }
 
788
 
 
789
        /**
 
790
         * Write the index to a JDBC <tt>PreparedStatement</tt>
 
791
         */
 
792
        protected int writeIndexToWhere(PreparedStatement st, Object index, int i, SessionImplementor session)
 
793
                        throws HibernateException, SQLException {
 
794
                if (indexContainsFormula) {
 
795
                        throw new AssertionFailure("cannot use a formula-based index in the where condition");
 
796
                }
 
797
                getIndexType().nullSafeSet( st, incrementIndexByBase(index), i, session );
 
798
                return i + indexColumnAliases.length;
 
799
        }
 
800
 
 
801
        /**
 
802
         * Write the identifier to a JDBC <tt>PreparedStatement</tt>
 
803
         */
 
804
        public int writeIdentifier(PreparedStatement st, Object id, int i, SessionImplementor session)
 
805
                        throws HibernateException, SQLException {
 
806
                
 
807
                getIdentifierType().nullSafeSet( st, id, i, session );
 
808
                return i + 1;
 
809
        }
 
810
 
 
811
        public boolean isPrimitiveArray() {
 
812
                return isPrimitiveArray;
 
813
        }
 
814
 
 
815
        public boolean isArray() {
 
816
                return isArray;
 
817
        }
 
818
 
 
819
        public String[] getKeyColumnAliases(String suffix) {
 
820
                return new Alias( suffix ).toAliasStrings( keyColumnAliases );
 
821
        }
 
822
 
 
823
        public String[] getElementColumnAliases(String suffix) {
 
824
                return new Alias( suffix ).toAliasStrings( elementColumnAliases );
 
825
        }
 
826
 
 
827
        public String[] getIndexColumnAliases(String suffix) {
 
828
                if ( hasIndex ) {
 
829
                        return new Alias( suffix ).toAliasStrings( indexColumnAliases );
 
830
                }
 
831
                else {
 
832
                        return null;
 
833
                }
 
834
        }
 
835
 
 
836
        public String getIdentifierColumnAlias(String suffix) {
 
837
                if ( hasIdentifier ) {
 
838
                        return new Alias( suffix ).toAliasString( identifierColumnAlias );
 
839
                }
 
840
                else {
 
841
                        return null;
 
842
                }
 
843
        }
 
844
        
 
845
        public String getIdentifierColumnName() {
 
846
                if ( hasIdentifier ) {
 
847
                        return identifierColumnName;
 
848
                } else {
 
849
                        return null;
 
850
                }
 
851
        }
 
852
 
 
853
        /**
 
854
         * Generate a list of collection index, key and element columns
 
855
         */
 
856
        public String selectFragment(String alias, String columnSuffix) {
 
857
                SelectFragment frag = generateSelectFragment( alias, columnSuffix );
 
858
                appendElementColumns( frag, alias );
 
859
                appendIndexColumns( frag, alias );
 
860
                appendIdentifierColumns( frag, alias );
 
861
 
 
862
                return frag.toFragmentString()
 
863
                                .substring( 2 ); //strip leading ','
 
864
        }
 
865
 
 
866
        protected String generateSelectSizeString(boolean isIntegerIndexed) {
 
867
                String selectValue = isIntegerIndexed ? 
 
868
                        "max(" + getIndexColumnNames()[0] + ") + 1": //lists, arrays
 
869
                        "count(" + getElementColumnNames()[0] + ")"; //sets, maps, bags
 
870
                return new SimpleSelect(dialect)
 
871
                                .setTableName( getTableName() )
 
872
                                .addCondition( getKeyColumnNames(), "=?" )
 
873
                                .addColumn(selectValue)
 
874
                                .toStatementString();
 
875
        }
 
876
 
 
877
        protected String generateDetectRowByIndexString() {
 
878
                if ( !hasIndex() ) {
 
879
                        return null;
 
880
                }
 
881
                return new SimpleSelect(dialect)
 
882
                                .setTableName( getTableName() )
 
883
                                .addCondition( getKeyColumnNames(), "=?" )
 
884
                                .addCondition( getIndexColumnNames(), "=?" )
 
885
                                .addCondition( indexFormulas, "=?" )
 
886
                                .addColumn("1")
 
887
                                .toStatementString();
 
888
        }
 
889
 
 
890
        protected String generateSelectRowByIndexString() {
 
891
                if ( !hasIndex() ) {
 
892
                        return null;
 
893
                }
 
894
                return new SimpleSelect(dialect)
 
895
                                .setTableName( getTableName() )
 
896
                                .addCondition( getKeyColumnNames(), "=?" )
 
897
                                .addCondition( getIndexColumnNames(), "=?" )
 
898
                                .addCondition( indexFormulas, "=?" )
 
899
                                .addColumns( getElementColumnNames(), elementColumnAliases )
 
900
                                .addColumns( indexFormulas, indexColumnAliases )
 
901
                                .toStatementString();
 
902
        }
 
903
 
 
904
        protected String generateDetectRowByElementString() {
 
905
                return new SimpleSelect(dialect)
 
906
                                .setTableName( getTableName() )
 
907
                                .addCondition( getKeyColumnNames(), "=?" )
 
908
                                .addCondition( getElementColumnNames(), "=?" )
 
909
                                .addCondition( elementFormulas, "=?" )
 
910
                                .addColumn("1")
 
911
                                .toStatementString();
 
912
        }
 
913
 
 
914
        protected SelectFragment generateSelectFragment(String alias, String columnSuffix) {
 
915
                return new SelectFragment()
 
916
                                .setSuffix( columnSuffix )
 
917
                                .addColumns( alias, keyColumnNames, keyColumnAliases );
 
918
        }
 
919
 
 
920
        protected void appendElementColumns(SelectFragment frag, String elemAlias) {
 
921
                for ( int i=0; i<elementColumnIsSettable.length; i++ ) {
 
922
                        if ( elementColumnIsSettable[i] ) {
 
923
                                frag.addColumn( elemAlias, elementColumnNames[i], elementColumnAliases[i] );
 
924
                        }
 
925
                        else {
 
926
                                frag.addFormula( elemAlias, elementFormulaTemplates[i], elementColumnAliases[i] );
 
927
                        }
 
928
                }
 
929
        }
 
930
 
 
931
        protected void appendIndexColumns(SelectFragment frag, String alias) {
 
932
                if ( hasIndex ) {
 
933
                        for ( int i=0; i<indexColumnIsSettable.length; i++ ) {
 
934
                                if ( indexColumnIsSettable[i] ) {
 
935
                                        frag.addColumn( alias, indexColumnNames[i], indexColumnAliases[i] );
 
936
                                }
 
937
                                else {
 
938
                                        frag.addFormula( alias, indexFormulaTemplates[i], indexColumnAliases[i] );
 
939
                                }
 
940
                        }
 
941
                }
 
942
        }
 
943
 
 
944
        protected void appendIdentifierColumns(SelectFragment frag, String alias) {
 
945
                if ( hasIdentifier ) {
 
946
                        frag.addColumn( alias, identifierColumnName, identifierColumnAlias );
 
947
                }
 
948
        }
 
949
 
 
950
        public String[] getIndexColumnNames() {
 
951
                return indexColumnNames;
 
952
        }
 
953
 
 
954
        public String[] getIndexFormulas() {
 
955
                return indexFormulas;
 
956
        }
 
957
 
 
958
        public String[] getIndexColumnNames(String alias) {
 
959
                return qualify(alias, indexColumnNames, indexFormulaTemplates);
 
960
 
 
961
        }
 
962
 
 
963
        public String[] getElementColumnNames(String alias) {
 
964
                return qualify(alias, elementColumnNames, elementFormulaTemplates);
 
965
        }
 
966
        
 
967
        private static String[] qualify(String alias, String[] columnNames, String[] formulaTemplates) {
 
968
                int span = columnNames.length;
 
969
                String[] result = new String[span];
 
970
                for (int i=0; i<span; i++) {
 
971
                        if ( columnNames[i]==null ) {
 
972
                                result[i] = StringHelper.replace( formulaTemplates[i], Template.TEMPLATE, alias );
 
973
                        }
 
974
                        else {
 
975
                                result[i] = StringHelper.qualify( alias, columnNames[i] );
 
976
                        }
 
977
                }
 
978
                return result;
 
979
        }
 
980
 
 
981
        public String[] getElementColumnNames() {
 
982
                return elementColumnNames; //TODO: something with formulas...
 
983
        }
 
984
 
 
985
        public String[] getKeyColumnNames() {
 
986
                return keyColumnNames;
 
987
        }
 
988
 
 
989
        public boolean hasIndex() {
 
990
                return hasIndex;
 
991
        }
 
992
 
 
993
        public boolean isLazy() {
 
994
                return isLazy;
 
995
        }
 
996
 
 
997
        public boolean isInverse() {
 
998
                return isInverse;
 
999
        }
 
1000
 
 
1001
        public String getTableName() {
 
1002
                return qualifiedTableName;
 
1003
        }
 
1004
 
 
1005
        public void remove(Serializable id, SessionImplementor session) throws HibernateException {
 
1006
 
 
1007
                if ( !isInverse && isRowDeleteEnabled() ) {
 
1008
 
 
1009
                        if ( log.isDebugEnabled() ) {
 
1010
                                log.debug( 
 
1011
                                                "Deleting collection: " + 
 
1012
                                                MessageHelper.collectionInfoString( this, id, getFactory() ) 
 
1013
                                        );
 
1014
                        }
 
1015
 
 
1016
                        // Remove all the old entries
 
1017
 
 
1018
                        try {
 
1019
                                int offset = 1;
 
1020
                                PreparedStatement st = null;
 
1021
                                Expectation expectation = Expectations.appropriateExpectation( getDeleteAllCheckStyle() );
 
1022
                                boolean callable = isDeleteAllCallable();
 
1023
                                boolean useBatch = expectation.canBeBatched();
 
1024
                                String sql = getSQLDeleteString();
 
1025
                                if ( useBatch ) {
 
1026
                                        if ( callable ) {
 
1027
                                                st = session.getBatcher().prepareBatchCallableStatement( sql );
 
1028
                                        }
 
1029
                                        else {
 
1030
                                                st = session.getBatcher().prepareBatchStatement( sql );
 
1031
                                        }
 
1032
                                }
 
1033
                                else {
 
1034
                                        if ( callable ) {
 
1035
                                                st = session.getBatcher().prepareCallableStatement( sql );
 
1036
                                        }
 
1037
                                        else {
 
1038
                                                st = session.getBatcher().prepareStatement( sql );
 
1039
                                        }
 
1040
                                }
 
1041
 
 
1042
 
 
1043
                                try {
 
1044
                                        offset+= expectation.prepare( st );
 
1045
 
 
1046
                                        writeKey( st, id, offset, session );
 
1047
                                        if ( useBatch ) {
 
1048
                                                session.getBatcher().addToBatch( expectation );
 
1049
                                        }
 
1050
                                        else {
 
1051
                                                expectation.verifyOutcome( st.executeUpdate(), st, -1 );
 
1052
                                        }
 
1053
                                }
 
1054
                                catch ( SQLException sqle ) {
 
1055
                                        if ( useBatch ) {
 
1056
                                                session.getBatcher().abortBatch( sqle );
 
1057
                                        }
 
1058
                                        throw sqle;
 
1059
                                }
 
1060
                                finally {
 
1061
                                        if ( !useBatch ) {
 
1062
                                                session.getBatcher().closeStatement( st );
 
1063
                                        }
 
1064
                                }
 
1065
 
 
1066
                                if ( log.isDebugEnabled() ) {
 
1067
                                        log.debug( "done deleting collection" );
 
1068
                                }
 
1069
                        }
 
1070
                        catch ( SQLException sqle ) {
 
1071
                                throw JDBCExceptionHelper.convert(
 
1072
                                        sqlExceptionConverter,
 
1073
                                        sqle,
 
1074
                                        "could not delete collection: " + 
 
1075
                                        MessageHelper.collectionInfoString( this, id, getFactory() ),
 
1076
                                        getSQLDeleteString()
 
1077
                                        );
 
1078
                        }
 
1079
 
 
1080
                }
 
1081
 
 
1082
        }
 
1083
 
 
1084
        public void recreate(PersistentCollection collection, Serializable id, SessionImplementor session)
 
1085
                        throws HibernateException {
 
1086
 
 
1087
                if ( !isInverse && isRowInsertEnabled() ) {
 
1088
 
 
1089
                        if ( log.isDebugEnabled() ) {
 
1090
                                log.debug( 
 
1091
                                                "Inserting collection: " + 
 
1092
                                                MessageHelper.collectionInfoString( this, id, getFactory() ) 
 
1093
                                        );
 
1094
                        }
 
1095
 
 
1096
                        try {
 
1097
                                //create all the new entries
 
1098
                                Iterator entries = collection.entries(this);
 
1099
                                if ( entries.hasNext() ) {
 
1100
                                        collection.preInsert( this );
 
1101
                                        int i = 0;
 
1102
                                        int count = 0;
 
1103
                                        while ( entries.hasNext() ) {
 
1104
 
 
1105
                                                final Object entry = entries.next();
 
1106
                                                if ( collection.entryExists( entry, i ) ) {
 
1107
                                                        int offset = 1;
 
1108
                                                        PreparedStatement st = null;
 
1109
                                                        Expectation expectation = Expectations.appropriateExpectation( getInsertCheckStyle() );
 
1110
                                                        boolean callable = isInsertCallable();
 
1111
                                                        boolean useBatch = expectation.canBeBatched();
 
1112
                                                        String sql = getSQLInsertRowString();
 
1113
 
 
1114
                                                        if ( useBatch ) {
 
1115
                                                                if ( callable ) {
 
1116
                                                                        st = session.getBatcher().prepareBatchCallableStatement( sql );
 
1117
                                                                }
 
1118
                                                                else {
 
1119
                                                                        st = session.getBatcher().prepareBatchStatement( sql );
 
1120
                                                                }
 
1121
                                                        }
 
1122
                                                        else {
 
1123
                                                                if ( callable ) {
 
1124
                                                                        st = session.getBatcher().prepareCallableStatement( sql );
 
1125
                                                                }
 
1126
                                                                else {
 
1127
                                                                        st = session.getBatcher().prepareStatement( sql );
 
1128
                                                                }
 
1129
                                                        }
 
1130
 
 
1131
 
 
1132
                                                        try {
 
1133
                                                                offset+= expectation.prepare( st );
 
1134
 
 
1135
                                                                //TODO: copy/paste from insertRows()
 
1136
                                                                int loc = writeKey( st, id, offset, session );
 
1137
                                                                if ( hasIdentifier ) {
 
1138
                                                                        loc = writeIdentifier( st, collection.getIdentifier(entry, i), loc, session );
 
1139
                                                                }
 
1140
                                                                if ( hasIndex /*&& !indexIsFormula*/ ) {
 
1141
                                                                        loc = writeIndex( st, collection.getIndex(entry, i, this), loc, session );
 
1142
                                                                }
 
1143
                                                                loc = writeElement(st, collection.getElement(entry), loc, session );
 
1144
 
 
1145
                                                                if ( useBatch ) {
 
1146
                                                                        session.getBatcher().addToBatch( expectation );
 
1147
                                                                }
 
1148
                                                                else {
 
1149
                                                                        expectation.verifyOutcome( st.executeUpdate(), st, -1 );
 
1150
                                                                }
 
1151
 
 
1152
                                                                collection.afterRowInsert( this, entry, i );
 
1153
                                                                count++;
 
1154
                                                        }
 
1155
                                                        catch ( SQLException sqle ) {
 
1156
                                                                if ( useBatch ) {
 
1157
                                                                        session.getBatcher().abortBatch( sqle );
 
1158
                                                                }
 
1159
                                                                throw sqle;
 
1160
                                                        }
 
1161
                                                        finally {
 
1162
                                                                if ( !useBatch ) {
 
1163
                                                                        session.getBatcher().closeStatement( st );
 
1164
                                                                }
 
1165
                                                        }
 
1166
 
 
1167
                                                }
 
1168
                                                i++;
 
1169
                                        }
 
1170
 
 
1171
                                        if ( log.isDebugEnabled() ) {
 
1172
                                                log.debug( "done inserting collection: " + count + " rows inserted" );
 
1173
                                        }
 
1174
 
 
1175
                                }
 
1176
                                else {
 
1177
                                        if ( log.isDebugEnabled() ) {
 
1178
                                                log.debug( "collection was empty" );
 
1179
                                        }
 
1180
                                }
 
1181
                        }
 
1182
                        catch ( SQLException sqle ) {
 
1183
                                throw JDBCExceptionHelper.convert(
 
1184
                                        sqlExceptionConverter,
 
1185
                                        sqle,
 
1186
                                        "could not insert collection: " + 
 
1187
                                        MessageHelper.collectionInfoString( this, id, getFactory() ),
 
1188
                                        getSQLInsertRowString()
 
1189
                                        );
 
1190
                        }
 
1191
                }
 
1192
        }
 
1193
        
 
1194
        protected boolean isRowDeleteEnabled() {
 
1195
                return true;
 
1196
        }
 
1197
 
 
1198
        public void deleteRows(PersistentCollection collection, Serializable id, SessionImplementor session)
 
1199
                        throws HibernateException {
 
1200
 
 
1201
                if ( !isInverse && isRowDeleteEnabled() ) {
 
1202
 
 
1203
                        if ( log.isDebugEnabled() ) {
 
1204
                                log.debug( 
 
1205
                                                "Deleting rows of collection: " + 
 
1206
                                                MessageHelper.collectionInfoString( this, id, getFactory() ) 
 
1207
                                        );
 
1208
                        }
 
1209
                        
 
1210
                        boolean deleteByIndex = !isOneToMany() && hasIndex && !indexContainsFormula;
 
1211
                        
 
1212
                        try {
 
1213
                                //delete all the deleted entries
 
1214
                                Iterator deletes = collection.getDeletes( this, !deleteByIndex );
 
1215
                                if ( deletes.hasNext() ) {
 
1216
                                        int offset = 1;
 
1217
                                        int count = 0;
 
1218
                                        while ( deletes.hasNext() ) {
 
1219
                                                PreparedStatement st = null;
 
1220
                                                Expectation expectation = Expectations.appropriateExpectation( getDeleteCheckStyle() );
 
1221
                                                boolean callable = isDeleteCallable();
 
1222
                                                boolean useBatch = expectation.canBeBatched();
 
1223
                                                String sql = getSQLDeleteRowString();
 
1224
 
 
1225
                                                if ( useBatch ) {
 
1226
                                                        if ( callable ) {
 
1227
                                                                st = session.getBatcher().prepareBatchCallableStatement( sql );
 
1228
                                                        }
 
1229
                                                        else {
 
1230
                                                                st = session.getBatcher().prepareBatchStatement( sql );
 
1231
                                                        }
 
1232
                                                }
 
1233
                                                else {
 
1234
                                                        if ( callable ) {
 
1235
                                                                st = session.getBatcher().prepareCallableStatement( sql );
 
1236
                                                        }
 
1237
                                                        else {
 
1238
                                                                st = session.getBatcher().prepareStatement( sql );
 
1239
                                                        }
 
1240
                                                }
 
1241
 
 
1242
                                                try {
 
1243
                                                        expectation.prepare( st );
 
1244
 
 
1245
                                                        Object entry = deletes.next();
 
1246
                                                        int loc = offset;
 
1247
                                                        if ( hasIdentifier ) {
 
1248
                                                                writeIdentifier( st, entry, loc, session );
 
1249
                                                        }
 
1250
                                                        else {
 
1251
                                                                loc = writeKey( st, id, loc, session );
 
1252
                                                                if ( deleteByIndex ) {
 
1253
                                                                        writeIndexToWhere( st, entry, loc, session );
 
1254
                                                                }
 
1255
                                                                else {
 
1256
                                                                        writeElementToWhere( st, entry, loc, session );
 
1257
                                                                }
 
1258
                                                        }
 
1259
 
 
1260
                                                        if ( useBatch ) {
 
1261
                                                                session.getBatcher().addToBatch( expectation );
 
1262
                                                        }
 
1263
                                                        else {
 
1264
                                                                expectation.verifyOutcome( st.executeUpdate(), st, -1 );
 
1265
                                                        }
 
1266
                                                        count++;
 
1267
                                                }
 
1268
                                                catch ( SQLException sqle ) {
 
1269
                                                        if ( useBatch ) {
 
1270
                                                                session.getBatcher().abortBatch( sqle );
 
1271
                                                        }
 
1272
                                                        throw sqle;
 
1273
                                                }
 
1274
                                                finally {
 
1275
                                                        if ( !useBatch ) {
 
1276
                                                                session.getBatcher().closeStatement( st );
 
1277
                                                        }
 
1278
                                                }
 
1279
 
 
1280
                                                if ( log.isDebugEnabled() ) {
 
1281
                                                        log.debug( "done deleting collection rows: " + count + " deleted" );
 
1282
                                                }
 
1283
                                        }
 
1284
                                }
 
1285
                                else {
 
1286
                                        if ( log.isDebugEnabled() ) {
 
1287
                                                log.debug( "no rows to delete" );
 
1288
                                        }
 
1289
                                }
 
1290
                        }
 
1291
                        catch ( SQLException sqle ) {
 
1292
                                throw JDBCExceptionHelper.convert(
 
1293
                                        sqlExceptionConverter,
 
1294
                                        sqle,
 
1295
                                        "could not delete collection rows: " + 
 
1296
                                        MessageHelper.collectionInfoString( this, id, getFactory() ),
 
1297
                                        getSQLDeleteRowString()
 
1298
                                        );
 
1299
                        }
 
1300
                }
 
1301
        }
 
1302
        
 
1303
        protected boolean isRowInsertEnabled() {
 
1304
                return true;
 
1305
        }
 
1306
 
 
1307
        public void insertRows(PersistentCollection collection, Serializable id, SessionImplementor session)
 
1308
                        throws HibernateException {
 
1309
 
 
1310
                if ( !isInverse && isRowInsertEnabled() ) {
 
1311
 
 
1312
                        if ( log.isDebugEnabled() ) {
 
1313
                                log.debug( 
 
1314
                                                "Inserting rows of collection: " + 
 
1315
                                                MessageHelper.collectionInfoString( this, id, getFactory() ) 
 
1316
                                        );
 
1317
                        }
 
1318
 
 
1319
                        try {
 
1320
                                //insert all the new entries
 
1321
                                collection.preInsert( this );
 
1322
                                Iterator entries = collection.entries( this );
 
1323
                                Expectation expectation = Expectations.appropriateExpectation( getInsertCheckStyle() );
 
1324
                                boolean callable = isInsertCallable();
 
1325
                                boolean useBatch = expectation.canBeBatched();
 
1326
                                String sql = getSQLInsertRowString();
 
1327
                                int i = 0;
 
1328
                                int count = 0;
 
1329
                                while ( entries.hasNext() ) {
 
1330
                                        int offset = 1;
 
1331
                                        Object entry = entries.next();
 
1332
                                        PreparedStatement st = null;
 
1333
                                        if ( collection.needsInserting( entry, i, elementType ) ) {
 
1334
 
 
1335
                                                if ( useBatch ) {
 
1336
                                                        if ( st == null ) {
 
1337
                                                                if ( callable ) {
 
1338
                                                                        st = session.getBatcher().prepareBatchCallableStatement( sql );
 
1339
                                                                }
 
1340
                                                                else {
 
1341
                                                                        st = session.getBatcher().prepareBatchStatement( sql );
 
1342
                                                                }
 
1343
                                                        }
 
1344
                                                }
 
1345
                                                else {
 
1346
                                                        if ( callable ) {
 
1347
                                                                st = session.getBatcher().prepareCallableStatement( sql );
 
1348
                                                        }
 
1349
                                                        else {
 
1350
                                                                st = session.getBatcher().prepareStatement( sql );
 
1351
                                                        }
 
1352
                                                }
 
1353
 
 
1354
                                                try {
 
1355
                                                        offset += expectation.prepare( st );
 
1356
                                                        //TODO: copy/paste from recreate()
 
1357
                                                        offset = writeKey( st, id, offset, session );
 
1358
                                                        if ( hasIdentifier ) {
 
1359
                                                                offset = writeIdentifier( st, collection.getIdentifier(entry, i), offset, session );
 
1360
                                                        }
 
1361
                                                        if ( hasIndex /*&& !indexIsFormula*/ ) {
 
1362
                                                                offset = writeIndex( st, collection.getIndex(entry, i, this), offset, session );
 
1363
                                                        }
 
1364
                                                        writeElement(st, collection.getElement(entry), offset, session );
 
1365
 
 
1366
                                                        if ( useBatch ) {
 
1367
                                                                session.getBatcher().addToBatch( expectation );
 
1368
                                                        }
 
1369
                                                        else {
 
1370
                                                                expectation.verifyOutcome( st.executeUpdate(), st, -1 );
 
1371
                                                        }
 
1372
                                                        collection.afterRowInsert( this, entry, i );
 
1373
                                                        count++;
 
1374
                                                }
 
1375
                                                catch ( SQLException sqle ) {
 
1376
                                                        if ( useBatch ) {
 
1377
                                                                session.getBatcher().abortBatch( sqle );
 
1378
                                                        }
 
1379
                                                        throw sqle;
 
1380
                                                }
 
1381
                                                finally {
 
1382
                                                        if ( !useBatch ) {
 
1383
                                                                session.getBatcher().closeStatement( st );
 
1384
                                                        }
 
1385
                                                }
 
1386
                                        }
 
1387
                                        i++;
 
1388
                                }
 
1389
                                if ( log.isDebugEnabled() ) {
 
1390
                                        log.debug( "done inserting rows: " + count + " inserted" );
 
1391
                                }
 
1392
                        }
 
1393
                        catch ( SQLException sqle ) {
 
1394
                                throw JDBCExceptionHelper.convert(
 
1395
                                        sqlExceptionConverter,
 
1396
                                        sqle,
 
1397
                                        "could not insert collection rows: " + 
 
1398
                                        MessageHelper.collectionInfoString( this, id, getFactory() ),
 
1399
                                        getSQLInsertRowString()
 
1400
                                        );
 
1401
                        }
 
1402
 
 
1403
                }
 
1404
        }
 
1405
 
 
1406
 
 
1407
        public String getRole() {
 
1408
                return role;
 
1409
        }
 
1410
 
 
1411
        public String getOwnerEntityName() {
 
1412
                return entityName;
 
1413
        }
 
1414
 
 
1415
        public EntityPersister getOwnerEntityPersister() {
 
1416
                return ownerPersister;
 
1417
        }
 
1418
 
 
1419
        public IdentifierGenerator getIdentifierGenerator() {
 
1420
                return identifierGenerator;
 
1421
        }
 
1422
 
 
1423
        public Type getIdentifierType() {
 
1424
                return identifierType;
 
1425
        }
 
1426
 
 
1427
        public boolean hasOrphanDelete() {
 
1428
                return hasOrphanDelete;
 
1429
        }
 
1430
 
 
1431
        public Type toType(String propertyName) throws QueryException {
 
1432
                if ( "index".equals( propertyName ) ) {
 
1433
                        return indexType;
 
1434
                }
 
1435
                return elementPropertyMapping.toType( propertyName );
 
1436
        }
 
1437
 
 
1438
        public abstract boolean isManyToMany();
 
1439
 
 
1440
        public String getManyToManyFilterFragment(String alias, Map enabledFilters) {
 
1441
                StringBuffer buffer = new StringBuffer();
 
1442
                manyToManyFilterHelper.render( buffer, alias, enabledFilters );
 
1443
 
 
1444
                if ( manyToManyWhereString != null ) {
 
1445
                        buffer.append( " and " )
 
1446
                                        .append( StringHelper.replace( manyToManyWhereTemplate, Template.TEMPLATE, alias ) );
 
1447
                }
 
1448
 
 
1449
                return buffer.toString();
 
1450
        }
 
1451
 
 
1452
        public String[] toColumns(String alias, String propertyName)
 
1453
                        throws QueryException {
 
1454
 
 
1455
                if ( "index".equals( propertyName ) ) {
 
1456
                        if ( isManyToMany() ) {
 
1457
                                throw new QueryException( "index() function not supported for many-to-many association" );
 
1458
                        }
 
1459
                        return StringHelper.qualify( alias, indexColumnNames );
 
1460
                }
 
1461
 
 
1462
                return elementPropertyMapping.toColumns( alias, propertyName );
 
1463
        }
 
1464
 
 
1465
        public String[] toColumns(String propertyName)
 
1466
                        throws QueryException {
 
1467
 
 
1468
                if ( "index".equals( propertyName ) ) {
 
1469
                        if ( isManyToMany() ) {
 
1470
                                throw new QueryException( "index() function not supported for many-to-many association" );
 
1471
                        }
 
1472
                        return indexColumnNames;
 
1473
                }
 
1474
 
 
1475
                return elementPropertyMapping.toColumns( propertyName );
 
1476
        }
 
1477
 
 
1478
        public Type getType() {
 
1479
                return elementPropertyMapping.getType(); //==elementType ??
 
1480
        }
 
1481
 
 
1482
        public String getName() {
 
1483
                return getRole();
 
1484
        }
 
1485
 
 
1486
        public EntityPersister getElementPersister() {
 
1487
                if ( elementPersister == null ) {
 
1488
                        throw new AssertionFailure( "not an association" );
 
1489
                }
 
1490
                return ( Loadable ) elementPersister;
 
1491
        }
 
1492
 
 
1493
        public boolean isCollection() {
 
1494
                return true;
 
1495
        }
 
1496
 
 
1497
        public Serializable[] getCollectionSpaces() {
 
1498
                return spaces;
 
1499
        }
 
1500
 
 
1501
        protected abstract String generateDeleteString();
 
1502
 
 
1503
        protected abstract String generateDeleteRowString();
 
1504
 
 
1505
        protected abstract String generateUpdateRowString();
 
1506
 
 
1507
        protected abstract String generateInsertRowString();
 
1508
 
 
1509
        public void updateRows(PersistentCollection collection, Serializable id, SessionImplementor session) 
 
1510
        throws HibernateException {
 
1511
 
 
1512
                if ( !isInverse && collection.isRowUpdatePossible() ) {
 
1513
 
 
1514
                        if ( log.isDebugEnabled() ) {
 
1515
                                log.debug( "Updating rows of collection: " + role + "#" + id );
 
1516
                        }
 
1517
 
 
1518
                        //update all the modified entries
 
1519
                        int count = doUpdateRows( id, collection, session );
 
1520
 
 
1521
                        if ( log.isDebugEnabled() ) {
 
1522
                                log.debug( "done updating rows: " + count + " updated" );
 
1523
                        }
 
1524
                }
 
1525
        }
 
1526
 
 
1527
        protected abstract int doUpdateRows(Serializable key, PersistentCollection collection, SessionImplementor session) 
 
1528
        throws HibernateException;
 
1529
 
 
1530
        public CollectionMetadata getCollectionMetadata() {
 
1531
                return this;
 
1532
        }
 
1533
 
 
1534
        public SessionFactoryImplementor getFactory() {
 
1535
                return factory;
 
1536
        }
 
1537
 
 
1538
        protected String filterFragment(String alias) throws MappingException {
 
1539
                return hasWhere() ? " and " + getSQLWhereString( alias ) : "";
 
1540
        }
 
1541
 
 
1542
        public String filterFragment(String alias, Map enabledFilters) throws MappingException {
 
1543
 
 
1544
                StringBuffer sessionFilterFragment = new StringBuffer();
 
1545
                filterHelper.render( sessionFilterFragment, alias, enabledFilters );
 
1546
 
 
1547
                return sessionFilterFragment.append( filterFragment( alias ) ).toString();
 
1548
        }
 
1549
 
 
1550
        public String oneToManyFilterFragment(String alias) throws MappingException {
 
1551
                return "";
 
1552
        }
 
1553
 
 
1554
        protected boolean isInsertCallable() {
 
1555
                return insertCallable;
 
1556
        }
 
1557
 
 
1558
        protected ExecuteUpdateResultCheckStyle getInsertCheckStyle() {
 
1559
                return insertCheckStyle;
 
1560
        }
 
1561
 
 
1562
        protected boolean isUpdateCallable() {
 
1563
                return updateCallable;
 
1564
        }
 
1565
 
 
1566
        protected ExecuteUpdateResultCheckStyle getUpdateCheckStyle() {
 
1567
                return updateCheckStyle;
 
1568
        }
 
1569
 
 
1570
        protected boolean isDeleteCallable() {
 
1571
                return deleteCallable;
 
1572
        }
 
1573
 
 
1574
        protected ExecuteUpdateResultCheckStyle getDeleteCheckStyle() {
 
1575
                return deleteCheckStyle;
 
1576
        }
 
1577
 
 
1578
        protected boolean isDeleteAllCallable() {
 
1579
                return deleteAllCallable;
 
1580
        }
 
1581
 
 
1582
        protected ExecuteUpdateResultCheckStyle getDeleteAllCheckStyle() {
 
1583
                return deleteAllCheckStyle;
 
1584
        }
 
1585
 
 
1586
        public String toString() {
 
1587
                return StringHelper.unqualify( getClass().getName() ) + '(' + role + ')';
 
1588
        }
 
1589
 
 
1590
        public boolean isVersioned() {
 
1591
                return isVersioned && getOwnerEntityPersister().isVersioned();
 
1592
        }
 
1593
        
 
1594
        public String getNodeName() {
 
1595
                return nodeName;
 
1596
        }
 
1597
 
 
1598
        public String getElementNodeName() {
 
1599
                return elementNodeName;
 
1600
        }
 
1601
 
 
1602
        public String getIndexNodeName() {
 
1603
                return indexNodeName;
 
1604
        }
 
1605
 
 
1606
        protected SQLExceptionConverter getSQLExceptionConverter() {
 
1607
                return sqlExceptionConverter;
 
1608
        }
 
1609
 
 
1610
        public CacheEntryStructure getCacheEntryStructure() {
 
1611
                return cacheEntryStructure;
 
1612
        }
 
1613
 
 
1614
        public boolean isAffectedByEnabledFilters(SessionImplementor session) {
 
1615
                return filterHelper.isAffectedBy( session.getEnabledFilters() ) ||
 
1616
                        ( isManyToMany() && manyToManyFilterHelper.isAffectedBy( session.getEnabledFilters() ) );
 
1617
        }
 
1618
 
 
1619
        public boolean isSubselectLoadable() {
 
1620
                return subselectLoadable;
 
1621
        }
 
1622
        
 
1623
        public boolean isMutable() {
 
1624
                return isMutable;
 
1625
        }
 
1626
 
 
1627
        public String[] getCollectionPropertyColumnAliases(String propertyName, String suffix) {
 
1628
                String rawAliases[] = (String[]) collectionPropertyColumnAliases.get(propertyName);
 
1629
 
 
1630
                if ( rawAliases == null ) {
 
1631
                        return null;
 
1632
                }
 
1633
                
 
1634
                String result[] = new String[rawAliases.length];
 
1635
                for ( int i=0; i<rawAliases.length; i++ ) {
 
1636
                        result[i] = new Alias(suffix).toUnquotedAliasString( rawAliases[i] );
 
1637
                }
 
1638
                return result;
 
1639
        }
 
1640
        
 
1641
        //TODO: formulas ?
 
1642
        public void initCollectionPropertyMap() {
 
1643
 
 
1644
                initCollectionPropertyMap( "key", keyType, keyColumnAliases, keyColumnNames );
 
1645
                initCollectionPropertyMap( "element", elementType, elementColumnAliases, elementColumnNames );
 
1646
                if (hasIndex) {
 
1647
                        initCollectionPropertyMap( "index", indexType, indexColumnAliases, indexColumnNames );
 
1648
                }
 
1649
                if (hasIdentifier) {
 
1650
                        initCollectionPropertyMap( 
 
1651
                                        "id", 
 
1652
                                        identifierType, 
 
1653
                                        new String[] { identifierColumnAlias }, 
 
1654
                                        new String[] { identifierColumnName } 
 
1655
                                );
 
1656
                }
 
1657
        }
 
1658
 
 
1659
        private void initCollectionPropertyMap(String aliasName, Type type, String[] columnAliases, String[] columnNames) {
 
1660
                
 
1661
                collectionPropertyColumnAliases.put(aliasName, columnAliases);
 
1662
                collectionPropertyColumnNames.put(aliasName, columnNames);
 
1663
        
 
1664
                if( type.isComponentType() ) {
 
1665
                        AbstractComponentType ct = (AbstractComponentType) type;
 
1666
                        String[] propertyNames = ct.getPropertyNames();
 
1667
                        for (int i = 0; i < propertyNames.length; i++) {
 
1668
                                String name = propertyNames[i];
 
1669
                                collectionPropertyColumnAliases.put( aliasName + "." + name, columnAliases[i] );
 
1670
                                collectionPropertyColumnNames.put( aliasName + "." + name, columnNames[i] );
 
1671
                        }
 
1672
                } 
 
1673
                
 
1674
        }
 
1675
 
 
1676
        public int getSize(Serializable key, SessionImplementor session) {
 
1677
                try {
 
1678
                        PreparedStatement st = session.getBatcher().prepareSelectStatement(sqlSelectSizeString);
 
1679
                        try {
 
1680
                                getKeyType().nullSafeSet(st, key, 1, session);
 
1681
                                ResultSet rs = st.executeQuery();
 
1682
                                try {
 
1683
                                        return rs.next() ? rs.getInt(1) - baseIndex : 0;
 
1684
                                }
 
1685
                                finally {
 
1686
                                        rs.close();
 
1687
                                }
 
1688
                        }
 
1689
                        finally {
 
1690
                                session.getBatcher().closeStatement( st );
 
1691
                        }
 
1692
                }
 
1693
                catch (SQLException sqle) {
 
1694
                        throw JDBCExceptionHelper.convert(
 
1695
                                        getFactory().getSQLExceptionConverter(),
 
1696
                                        sqle,
 
1697
                                        "could not retrieve collection size: " + 
 
1698
                                        MessageHelper.collectionInfoString( this, key, getFactory() ),
 
1699
                                        sqlSelectSizeString
 
1700
                                );
 
1701
                }
 
1702
        }
 
1703
        
 
1704
        public boolean indexExists(Serializable key, Object index, SessionImplementor session) {
 
1705
                return exists(key, incrementIndexByBase(index), getIndexType(), sqlDetectRowByIndexString, session);
 
1706
        }
 
1707
 
 
1708
        public boolean elementExists(Serializable key, Object element, SessionImplementor session) {
 
1709
                return exists(key, element, getElementType(), sqlDetectRowByElementString, session);
 
1710
        }
 
1711
 
 
1712
        private boolean exists(Serializable key, Object indexOrElement, Type indexOrElementType, String sql, SessionImplementor session) {
 
1713
                try {
 
1714
                        PreparedStatement st = session.getBatcher().prepareSelectStatement(sql);
 
1715
                        try {
 
1716
                                getKeyType().nullSafeSet(st, key, 1, session);
 
1717
                                indexOrElementType.nullSafeSet( st, indexOrElement, keyColumnNames.length + 1, session );
 
1718
                                ResultSet rs = st.executeQuery();
 
1719
                                try {
 
1720
                                        return rs.next();
 
1721
                                }
 
1722
                                finally {
 
1723
                                        rs.close();
 
1724
                                }
 
1725
                        }
 
1726
                        catch( TransientObjectException e ) {
 
1727
                                return false;
 
1728
                        }
 
1729
                        finally {
 
1730
                                session.getBatcher().closeStatement( st );
 
1731
                        }
 
1732
                }
 
1733
                catch (SQLException sqle) {
 
1734
                        throw JDBCExceptionHelper.convert(
 
1735
                                        getFactory().getSQLExceptionConverter(),
 
1736
                                        sqle,
 
1737
                                        "could not check row existence: " + 
 
1738
                                        MessageHelper.collectionInfoString( this, key, getFactory() ),
 
1739
                                        sqlSelectSizeString
 
1740
                                );
 
1741
                }
 
1742
        }
 
1743
 
 
1744
        public Object getElementByIndex(Serializable key, Object index, SessionImplementor session, Object owner) {
 
1745
                try {
 
1746
                        PreparedStatement st = session.getBatcher().prepareSelectStatement(sqlSelectRowByIndexString);
 
1747
                        try {
 
1748
                                getKeyType().nullSafeSet(st, key, 1, session);
 
1749
                                getIndexType().nullSafeSet( st, incrementIndexByBase(index), keyColumnNames.length + 1, session );
 
1750
                                ResultSet rs = st.executeQuery();
 
1751
                                try {
 
1752
                                        if ( rs.next() ) {
 
1753
                                                return getElementType().nullSafeGet(rs, elementColumnAliases, session, owner);
 
1754
                                        }
 
1755
                                        else {
 
1756
                                                return null;
 
1757
                                        }
 
1758
                                }
 
1759
                                finally {
 
1760
                                        rs.close();
 
1761
                                }
 
1762
                        }
 
1763
                        finally {
 
1764
                                session.getBatcher().closeStatement( st );
 
1765
                        }
 
1766
                }
 
1767
                catch (SQLException sqle) {
 
1768
                        throw JDBCExceptionHelper.convert(
 
1769
                                        getFactory().getSQLExceptionConverter(),
 
1770
                                        sqle,
 
1771
                                        "could not read row: " + 
 
1772
                                        MessageHelper.collectionInfoString( this, key, getFactory() ),
 
1773
                                        sqlSelectSizeString
 
1774
                                );
 
1775
                }
 
1776
        }
 
1777
 
 
1778
        public boolean isExtraLazy() {
 
1779
                return isExtraLazy;
 
1780
        }
 
1781
        
 
1782
        protected Dialect getDialect() {
 
1783
                return dialect;
 
1784
        }
 
1785
}