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

« back to all changes in this revision

Viewing changes to src/org/hibernate/persister/entity/SingleTableEntityPersister.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: SingleTableEntityPersister.java 10040 2006-06-22 19:51:43Z steve.ebersole@jboss.com $
 
2
package org.hibernate.persister.entity;
 
3
 
 
4
import java.io.Serializable;
 
5
import java.util.ArrayList;
 
6
import java.util.HashMap;
 
7
import java.util.HashSet;
 
8
import java.util.Iterator;
 
9
import java.util.Map;
 
10
 
 
11
import org.hibernate.EntityMode;
 
12
import org.hibernate.HibernateException;
 
13
import org.hibernate.MappingException;
 
14
import org.hibernate.cache.CacheConcurrencyStrategy;
 
15
import org.hibernate.engine.Mapping;
 
16
import org.hibernate.engine.SessionFactoryImplementor;
 
17
import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
 
18
import org.hibernate.mapping.Column;
 
19
import org.hibernate.mapping.Formula;
 
20
import org.hibernate.mapping.Join;
 
21
import org.hibernate.mapping.PersistentClass;
 
22
import org.hibernate.mapping.Property;
 
23
import org.hibernate.mapping.Selectable;
 
24
import org.hibernate.mapping.Subclass;
 
25
import org.hibernate.mapping.Table;
 
26
import org.hibernate.mapping.Value;
 
27
import org.hibernate.sql.InFragment;
 
28
import org.hibernate.sql.Insert;
 
29
import org.hibernate.sql.SelectFragment;
 
30
import org.hibernate.type.AssociationType;
 
31
import org.hibernate.type.DiscriminatorType;
 
32
import org.hibernate.type.Type;
 
33
import org.hibernate.util.ArrayHelper;
 
34
import org.hibernate.util.MarkerObject;
 
35
 
 
36
/**
 
37
 * The default implementation of the <tt>EntityPersister</tt> interface.
 
38
 * Implements the "table-per-class-hierarchy" or "roll-up" mapping strategy
 
39
 * for an entity class and its inheritence hierarchy.  This is implemented
 
40
 * as a single table holding all classes in the hierarchy with a discrimator
 
41
 * column used to determine which concrete class is referenced.
 
42
 *
 
43
 * @author Gavin King
 
44
 */
 
45
public class SingleTableEntityPersister extends AbstractEntityPersister {
 
46
 
 
47
        // the class hierarchy structure
 
48
        private final int joinSpan;
 
49
        private final String[] qualifiedTableNames;
 
50
        private final boolean[] isInverseTable;
 
51
        private final boolean[] isNullableTable;
 
52
        private final String[][] keyColumnNames;
 
53
        private final boolean[] cascadeDeleteEnabled;
 
54
        private final boolean hasSequentialSelects;
 
55
        
 
56
        private final String[] spaces;
 
57
 
 
58
        private final String[] subclassClosure;
 
59
 
 
60
        private final String[] subclassTableNameClosure;
 
61
        private final boolean[] subclassTableIsLazyClosure;
 
62
        private final boolean[] isInverseSubclassTable;
 
63
        private final boolean[] isNullableSubclassTable;
 
64
        private final boolean[] subclassTableSequentialSelect;
 
65
        private final String[][] subclassTableKeyColumnClosure;
 
66
        private final boolean[] isClassOrSuperclassTable;
 
67
 
 
68
        // properties of this class, including inherited properties
 
69
        private final int[] propertyTableNumbers;
 
70
 
 
71
        // the closure of all columns used by the entire hierarchy including
 
72
        // subclasses and superclasses of this class
 
73
        private final int[] subclassPropertyTableNumberClosure;
 
74
 
 
75
        private final int[] subclassColumnTableNumberClosure;
 
76
        private final int[] subclassFormulaTableNumberClosure;
 
77
 
 
78
        // discriminator column
 
79
        private final Map subclassesByDiscriminatorValue = new HashMap();
 
80
        private final boolean forceDiscriminator;
 
81
        private final String discriminatorColumnName;
 
82
        private final String discriminatorFormula;
 
83
        private final String discriminatorFormulaTemplate;
 
84
        private final String discriminatorAlias;
 
85
        private final Type discriminatorType;
 
86
        private final String discriminatorSQLValue;
 
87
        private final boolean discriminatorInsertable;
 
88
 
 
89
        private final String[] constraintOrderedTableNames;
 
90
        private final String[][] constraintOrderedKeyColumnNames;
 
91
 
 
92
        //private final Map propertyTableNumbersByName = new HashMap();
 
93
        private final Map propertyTableNumbersByNameAndSubclass = new HashMap();
 
94
        
 
95
        private final Map sequentialSelectStringsByEntityName = new HashMap();
 
96
 
 
97
        private static final Object NULL_DISCRIMINATOR = new MarkerObject("<null discriminator>");
 
98
        private static final Object NOT_NULL_DISCRIMINATOR = new MarkerObject("<not null discriminator>");
 
99
 
 
100
        //INITIALIZATION:
 
101
 
 
102
        public SingleTableEntityPersister(
 
103
                        final PersistentClass persistentClass, 
 
104
                        final CacheConcurrencyStrategy cache,
 
105
                        final SessionFactoryImplementor factory,
 
106
                        final Mapping mapping)
 
107
        throws HibernateException {
 
108
 
 
109
                super(persistentClass, cache, factory);
 
110
 
 
111
                // CLASS + TABLE
 
112
 
 
113
                joinSpan = persistentClass.getJoinClosureSpan()+1;
 
114
                qualifiedTableNames = new String[joinSpan];
 
115
                isInverseTable = new boolean[joinSpan];
 
116
                isNullableTable = new boolean[joinSpan];
 
117
                keyColumnNames = new String[joinSpan][];
 
118
                final Table table = persistentClass.getRootTable();
 
119
                qualifiedTableNames[0] = table.getQualifiedName( 
 
120
                                factory.getDialect(), 
 
121
                                factory.getSettings().getDefaultCatalogName(), 
 
122
                                factory.getSettings().getDefaultSchemaName() 
 
123
                );
 
124
                isInverseTable[0] = false;
 
125
                isNullableTable[0] = false;
 
126
                keyColumnNames[0] = getIdentifierColumnNames();
 
127
                cascadeDeleteEnabled = new boolean[joinSpan];
 
128
 
 
129
                // Custom sql
 
130
                customSQLInsert = new String[joinSpan];
 
131
                customSQLUpdate = new String[joinSpan];
 
132
                customSQLDelete = new String[joinSpan];
 
133
                insertCallable = new boolean[joinSpan];
 
134
                updateCallable = new boolean[joinSpan];
 
135
                deleteCallable = new boolean[joinSpan];
 
136
                insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[joinSpan];
 
137
                updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[joinSpan];
 
138
                deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[joinSpan];
 
139
 
 
140
                customSQLInsert[0] = persistentClass.getCustomSQLInsert();
 
141
                insertCallable[0] = customSQLInsert[0] != null && persistentClass.isCustomInsertCallable();
 
142
                insertResultCheckStyles[0] = persistentClass.getCustomSQLInsertCheckStyle() == null
 
143
                                                                          ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[0], insertCallable[0] )
 
144
                                                                          : persistentClass.getCustomSQLInsertCheckStyle();
 
145
                customSQLUpdate[0] = persistentClass.getCustomSQLUpdate();
 
146
                updateCallable[0] = customSQLUpdate[0] != null && persistentClass.isCustomUpdateCallable();
 
147
                updateResultCheckStyles[0] = persistentClass.getCustomSQLUpdateCheckStyle() == null
 
148
                                                                          ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[0], updateCallable[0] )
 
149
                                                                          : persistentClass.getCustomSQLUpdateCheckStyle();
 
150
                customSQLDelete[0] = persistentClass.getCustomSQLDelete();
 
151
                deleteCallable[0] = customSQLDelete[0] != null && persistentClass.isCustomDeleteCallable();
 
152
                deleteResultCheckStyles[0] = persistentClass.getCustomSQLDeleteCheckStyle() == null
 
153
                                                                          ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[0], deleteCallable[0] )
 
154
                                                                          : persistentClass.getCustomSQLDeleteCheckStyle();
 
155
 
 
156
                // JOINS
 
157
 
 
158
                Iterator joinIter = persistentClass.getJoinClosureIterator();
 
159
                int j = 1;
 
160
                while ( joinIter.hasNext() ) {
 
161
                        Join join = (Join) joinIter.next();
 
162
                        qualifiedTableNames[j] = join.getTable().getQualifiedName( 
 
163
                                        factory.getDialect(), 
 
164
                                        factory.getSettings().getDefaultCatalogName(), 
 
165
                                        factory.getSettings().getDefaultSchemaName() 
 
166
                        );
 
167
                        isInverseTable[j] = join.isInverse();
 
168
                        isNullableTable[j] = join.isOptional();
 
169
                        cascadeDeleteEnabled[j] = join.getKey().isCascadeDeleteEnabled() && 
 
170
                                factory.getDialect().supportsCascadeDelete();
 
171
 
 
172
                        customSQLInsert[j] = join.getCustomSQLInsert();
 
173
                        insertCallable[j] = customSQLInsert[j] != null && join.isCustomInsertCallable();
 
174
                        insertResultCheckStyles[j] = join.getCustomSQLInsertCheckStyle() == null
 
175
                                                      ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[j], insertCallable[j] )
 
176
                                                  : join.getCustomSQLInsertCheckStyle();
 
177
                        customSQLUpdate[j] = join.getCustomSQLUpdate();
 
178
                        updateCallable[j] = customSQLUpdate[j] != null && join.isCustomUpdateCallable();
 
179
                        updateResultCheckStyles[j] = join.getCustomSQLUpdateCheckStyle() == null
 
180
                                                      ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[j], updateCallable[j] )
 
181
                                                  : join.getCustomSQLUpdateCheckStyle();
 
182
                        customSQLDelete[j] = join.getCustomSQLDelete();
 
183
                        deleteCallable[j] = customSQLDelete[j] != null && join.isCustomDeleteCallable();
 
184
                        deleteResultCheckStyles[j] = join.getCustomSQLDeleteCheckStyle() == null
 
185
                                                      ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[j], deleteCallable[j] )
 
186
                                                  : join.getCustomSQLDeleteCheckStyle();
 
187
 
 
188
                        Iterator iter = join.getKey().getColumnIterator();
 
189
                        keyColumnNames[j] = new String[ join.getKey().getColumnSpan() ];
 
190
                        int i = 0;
 
191
                        while ( iter.hasNext() ) {
 
192
                                Column col = (Column) iter.next();
 
193
                                keyColumnNames[j][i++] = col.getQuotedName( factory.getDialect() );
 
194
                        }
 
195
 
 
196
                        j++;
 
197
                }
 
198
 
 
199
                constraintOrderedTableNames = new String[qualifiedTableNames.length];
 
200
                constraintOrderedKeyColumnNames = new String[qualifiedTableNames.length][];
 
201
                for ( int i = qualifiedTableNames.length - 1, position = 0; i >= 0; i--, position++ ) {
 
202
                        constraintOrderedTableNames[position] = qualifiedTableNames[i];
 
203
                        constraintOrderedKeyColumnNames[position] = keyColumnNames[i];
 
204
                }
 
205
 
 
206
                spaces = ArrayHelper.join(
 
207
                                qualifiedTableNames, 
 
208
                                ArrayHelper.toStringArray( persistentClass.getSynchronizedTables() )
 
209
                );
 
210
                
 
211
                final boolean lazyAvailable = isInstrumented(EntityMode.POJO);
 
212
 
 
213
                boolean hasDeferred = false;
 
214
                ArrayList subclassTables = new ArrayList();
 
215
                ArrayList joinKeyColumns = new ArrayList();
 
216
                ArrayList isConcretes = new ArrayList();
 
217
                ArrayList isDeferreds = new ArrayList();
 
218
                ArrayList isInverses = new ArrayList();
 
219
                ArrayList isNullables = new ArrayList();
 
220
                ArrayList isLazies = new ArrayList();
 
221
                subclassTables.add( qualifiedTableNames[0] );
 
222
                joinKeyColumns.add( getIdentifierColumnNames() );
 
223
                isConcretes.add(Boolean.TRUE);
 
224
                isDeferreds.add(Boolean.FALSE);
 
225
                isInverses.add(Boolean.FALSE);
 
226
                isNullables.add(Boolean.FALSE);
 
227
                isLazies.add(Boolean.FALSE);
 
228
                joinIter = persistentClass.getSubclassJoinClosureIterator();
 
229
                while ( joinIter.hasNext() ) {
 
230
                        Join join = (Join) joinIter.next();
 
231
                        isConcretes.add( new Boolean( persistentClass.isClassOrSuperclassJoin(join) ) );
 
232
                        isDeferreds.add( new Boolean( join.isSequentialSelect() ) );
 
233
                        isInverses.add( new Boolean( join.isInverse() ) );
 
234
                        isNullables.add( new Boolean( join.isOptional() ) );
 
235
                        isLazies.add( new Boolean( lazyAvailable && join.isLazy() ) );
 
236
                        if ( join.isSequentialSelect() && !persistentClass.isClassOrSuperclassJoin(join) ) hasDeferred = true;
 
237
                        subclassTables.add( join.getTable().getQualifiedName( 
 
238
                                        factory.getDialect(), 
 
239
                                        factory.getSettings().getDefaultCatalogName(), 
 
240
                                        factory.getSettings().getDefaultSchemaName() 
 
241
                        ) );
 
242
                        Iterator iter = join.getKey().getColumnIterator();
 
243
                        String[] keyCols = new String[ join.getKey().getColumnSpan() ];
 
244
                        int i = 0;
 
245
                        while ( iter.hasNext() ) {
 
246
                                Column col = (Column) iter.next();
 
247
                                keyCols[i++] = col.getQuotedName( factory.getDialect() );
 
248
                        }
 
249
                        joinKeyColumns.add(keyCols);
 
250
                }
 
251
                
 
252
                subclassTableSequentialSelect = ArrayHelper.toBooleanArray(isDeferreds);
 
253
                subclassTableNameClosure = ArrayHelper.toStringArray(subclassTables);
 
254
                subclassTableIsLazyClosure = ArrayHelper.toBooleanArray(isLazies);
 
255
                subclassTableKeyColumnClosure = ArrayHelper.to2DStringArray(joinKeyColumns);
 
256
                isClassOrSuperclassTable = ArrayHelper.toBooleanArray(isConcretes);
 
257
                isInverseSubclassTable = ArrayHelper.toBooleanArray(isInverses);
 
258
                isNullableSubclassTable = ArrayHelper.toBooleanArray(isNullables);
 
259
                hasSequentialSelects = hasDeferred;
 
260
 
 
261
                // DISCRIMINATOR
 
262
 
 
263
                final Object discriminatorValue;
 
264
                if ( persistentClass.isPolymorphic() ) {
 
265
                        Value discrimValue = persistentClass.getDiscriminator();
 
266
                        if (discrimValue==null) {
 
267
                                throw new MappingException("discriminator mapping required for single table polymorphic persistence");
 
268
                        }
 
269
                        forceDiscriminator = persistentClass.isForceDiscriminator();
 
270
                        Selectable selectable = (Selectable) discrimValue.getColumnIterator().next();
 
271
                        if ( discrimValue.hasFormula() ) {
 
272
                                Formula formula = (Formula) selectable;
 
273
                                discriminatorFormula = formula.getFormula();
 
274
                                discriminatorFormulaTemplate = formula.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
 
275
                                discriminatorColumnName = null;
 
276
                                discriminatorAlias = "clazz_";
 
277
                        }
 
278
                        else {
 
279
                                Column column = (Column) selectable;
 
280
                                discriminatorColumnName = column.getQuotedName( factory.getDialect() );
 
281
                                discriminatorAlias = column.getAlias( factory.getDialect(), persistentClass.getRootTable() );
 
282
                                discriminatorFormula = null;
 
283
                                discriminatorFormulaTemplate = null;
 
284
                        }
 
285
                        discriminatorType = persistentClass.getDiscriminator().getType();
 
286
                        if ( persistentClass.isDiscriminatorValueNull() ) {
 
287
                                discriminatorValue = NULL_DISCRIMINATOR;
 
288
                                discriminatorSQLValue = InFragment.NULL;
 
289
                                discriminatorInsertable = false;
 
290
                        }
 
291
                        else if ( persistentClass.isDiscriminatorValueNotNull() ) {
 
292
                                discriminatorValue = NOT_NULL_DISCRIMINATOR;
 
293
                                discriminatorSQLValue = InFragment.NOT_NULL;
 
294
                                discriminatorInsertable = false;
 
295
                        }
 
296
                        else {
 
297
                                discriminatorInsertable = persistentClass.isDiscriminatorInsertable() && !discrimValue.hasFormula();
 
298
                                try {
 
299
                                        DiscriminatorType dtype = (DiscriminatorType) discriminatorType;
 
300
                                        discriminatorValue = dtype.stringToObject( persistentClass.getDiscriminatorValue() );
 
301
                                        discriminatorSQLValue = dtype.objectToSQLString( discriminatorValue, factory.getDialect() );
 
302
                                }
 
303
                                catch (ClassCastException cce) {
 
304
                                        throw new MappingException("Illegal discriminator type: " + discriminatorType.getName() );
 
305
                                }
 
306
                                catch (Exception e) {
 
307
                                        throw new MappingException("Could not format discriminator value to SQL string", e);
 
308
                                }
 
309
                        }
 
310
                }
 
311
                else {
 
312
                        forceDiscriminator = false;
 
313
                        discriminatorInsertable = false;
 
314
                        discriminatorColumnName = null;
 
315
                        discriminatorAlias = null;
 
316
                        discriminatorType = null;
 
317
                        discriminatorValue = null;
 
318
                        discriminatorSQLValue = null;
 
319
                        discriminatorFormula = null;
 
320
                        discriminatorFormulaTemplate = null;
 
321
                }
 
322
 
 
323
                // PROPERTIES
 
324
 
 
325
                propertyTableNumbers = new int[ getPropertySpan() ];
 
326
                Iterator iter = persistentClass.getPropertyClosureIterator();
 
327
                int i=0;
 
328
                while( iter.hasNext() ) {
 
329
                        Property prop = (Property) iter.next();
 
330
                        propertyTableNumbers[i++] = persistentClass.getJoinNumber(prop);
 
331
 
 
332
                }
 
333
 
 
334
                //TODO: code duplication with JoinedSubclassEntityPersister
 
335
                
 
336
                ArrayList columnJoinNumbers = new ArrayList();
 
337
                ArrayList formulaJoinedNumbers = new ArrayList();
 
338
                ArrayList propertyJoinNumbers = new ArrayList();
 
339
                
 
340
                iter = persistentClass.getSubclassPropertyClosureIterator();
 
341
                while ( iter.hasNext() ) {
 
342
                        Property prop = (Property) iter.next();
 
343
                        Integer join = new Integer( persistentClass.getJoinNumber(prop) );
 
344
                        propertyJoinNumbers.add(join);
 
345
 
 
346
                        //propertyTableNumbersByName.put( prop.getName(), join );
 
347
                        propertyTableNumbersByNameAndSubclass.put( 
 
348
                                        prop.getPersistentClass().getEntityName() + '.' + prop.getName(), 
 
349
                                        join 
 
350
                        );
 
351
 
 
352
                        Iterator citer = prop.getColumnIterator();
 
353
                        while ( citer.hasNext() ) {
 
354
                                Selectable thing = (Selectable) citer.next();
 
355
                                if ( thing.isFormula() ) {
 
356
                                        formulaJoinedNumbers.add(join);
 
357
                                }
 
358
                                else {
 
359
                                        columnJoinNumbers.add(join);
 
360
                                }
 
361
                        }
 
362
                }
 
363
                subclassColumnTableNumberClosure = ArrayHelper.toIntArray(columnJoinNumbers);
 
364
                subclassFormulaTableNumberClosure = ArrayHelper.toIntArray(formulaJoinedNumbers);
 
365
                subclassPropertyTableNumberClosure = ArrayHelper.toIntArray(propertyJoinNumbers);
 
366
 
 
367
                int subclassSpan = persistentClass.getSubclassSpan() + 1;
 
368
                subclassClosure = new String[subclassSpan];
 
369
                subclassClosure[0] = getEntityName();
 
370
                if ( persistentClass.isPolymorphic() ) {
 
371
                        subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() );
 
372
                }
 
373
 
 
374
                // SUBCLASSES
 
375
                if ( persistentClass.isPolymorphic() ) {
 
376
                        iter = persistentClass.getSubclassIterator();
 
377
                        int k=1;
 
378
                        while ( iter.hasNext() ) {
 
379
                                Subclass sc = (Subclass) iter.next();
 
380
                                subclassClosure[k++] = sc.getEntityName();
 
381
                                if ( sc.isDiscriminatorValueNull() ) {
 
382
                                        subclassesByDiscriminatorValue.put( NULL_DISCRIMINATOR, sc.getEntityName() );
 
383
                                }
 
384
                                else if ( sc.isDiscriminatorValueNotNull() ) {
 
385
                                        subclassesByDiscriminatorValue.put( NOT_NULL_DISCRIMINATOR, sc.getEntityName() );
 
386
                                }
 
387
                                else {
 
388
                                        try {
 
389
                                                DiscriminatorType dtype = (DiscriminatorType) discriminatorType;
 
390
                                                subclassesByDiscriminatorValue.put(
 
391
                                                        dtype.stringToObject( sc.getDiscriminatorValue() ),
 
392
                                                        sc.getEntityName()
 
393
                                                );
 
394
                                        }
 
395
                                        catch (ClassCastException cce) {
 
396
                                                throw new MappingException("Illegal discriminator type: " + discriminatorType.getName() );
 
397
                                        }
 
398
                                        catch (Exception e) {
 
399
                                                throw new MappingException("Error parsing discriminator value", e);
 
400
                                        }
 
401
                                }
 
402
                        }
 
403
                }
 
404
 
 
405
                initLockers();
 
406
 
 
407
                initSubclassPropertyAliasesMap(persistentClass);
 
408
                
 
409
                postConstruct(mapping);
 
410
 
 
411
        }
 
412
 
 
413
        protected boolean isInverseTable(int j) {
 
414
                return isInverseTable[j];
 
415
        }
 
416
 
 
417
        protected boolean isInverseSubclassTable(int j) {
 
418
                return isInverseSubclassTable[j];
 
419
        }
 
420
 
 
421
        public String getDiscriminatorColumnName() {
 
422
                return discriminatorColumnName;
 
423
        }
 
424
 
 
425
        protected String getDiscriminatorAlias() {
 
426
                return discriminatorAlias;
 
427
        }
 
428
 
 
429
        protected String getDiscriminatorFormulaTemplate() {
 
430
                return discriminatorFormulaTemplate;
 
431
        }
 
432
 
 
433
        public String getTableName() {
 
434
                return qualifiedTableNames[0];
 
435
        }
 
436
 
 
437
        public Type getDiscriminatorType() {
 
438
                return discriminatorType;
 
439
        }
 
440
 
 
441
        public String getDiscriminatorSQLValue() {
 
442
                return discriminatorSQLValue;
 
443
        }
 
444
 
 
445
        public String[] getSubclassClosure() {
 
446
                return subclassClosure;
 
447
        }
 
448
 
 
449
        public String getSubclassForDiscriminatorValue(Object value) {
 
450
                if (value==null) {
 
451
                        return (String) subclassesByDiscriminatorValue.get(NULL_DISCRIMINATOR);
 
452
                }
 
453
                else {
 
454
                        String result = (String) subclassesByDiscriminatorValue.get(value);
 
455
                        if (result==null) result = (String) subclassesByDiscriminatorValue.get(NOT_NULL_DISCRIMINATOR);
 
456
                        return result;
 
457
                }
 
458
        }
 
459
 
 
460
        public Serializable[] getPropertySpaces() {
 
461
                return spaces;
 
462
        }
 
463
 
 
464
        //Access cached SQL
 
465
 
 
466
        protected boolean isDiscriminatorFormula() {
 
467
                return discriminatorColumnName==null;
 
468
        }
 
469
 
 
470
        protected String getDiscriminatorFormula() {
 
471
                return discriminatorFormula;
 
472
        }
 
473
 
 
474
        protected String getTableName(int j) {
 
475
                return qualifiedTableNames[j];
 
476
        }
 
477
        
 
478
        protected String[] getKeyColumns(int j) {
 
479
                return keyColumnNames[j];
 
480
        }
 
481
        
 
482
        protected boolean isTableCascadeDeleteEnabled(int j) {
 
483
                return cascadeDeleteEnabled[j];
 
484
        }
 
485
        
 
486
        protected boolean isPropertyOfTable(int property, int j) {
 
487
                return propertyTableNumbers[property]==j;
 
488
        }
 
489
 
 
490
        protected boolean isSubclassTableSequentialSelect(int j) {
 
491
                return subclassTableSequentialSelect[j] && !isClassOrSuperclassTable[j];
 
492
        }
 
493
        
 
494
        // Execute the SQL:
 
495
 
 
496
        public String fromTableFragment(String name) {
 
497
                return getTableName() + ' ' + name;
 
498
        }
 
499
 
 
500
        public String filterFragment(String alias) throws MappingException {
 
501
                String result = discriminatorFilterFragment(alias);
 
502
                if ( hasWhere() ) result += " and " + getSQLWhereString(alias);
 
503
                return result;
 
504
        }
 
505
        
 
506
        public String oneToManyFilterFragment(String alias) throws MappingException {
 
507
                return forceDiscriminator ?
 
508
                        discriminatorFilterFragment(alias) :
 
509
                        "";
 
510
        }
 
511
 
 
512
        private String discriminatorFilterFragment(String alias) throws MappingException {
 
513
                if ( needsDiscriminator() ) {
 
514
                        InFragment frag = new InFragment();
 
515
 
 
516
                        if ( isDiscriminatorFormula() ) {
 
517
                                frag.setFormula( alias, getDiscriminatorFormulaTemplate() );
 
518
                        }
 
519
                        else {
 
520
                                frag.setColumn( alias, getDiscriminatorColumnName() );
 
521
                        }
 
522
 
 
523
                        String[] subclasses = getSubclassClosure();
 
524
                        for ( int i=0; i<subclasses.length; i++ ) {
 
525
                                final Queryable queryable = (Queryable) getFactory().getEntityPersister( subclasses[i] );
 
526
                                if ( !queryable.isAbstract() ) frag.addValue( queryable.getDiscriminatorSQLValue() );
 
527
                        }
 
528
 
 
529
                        StringBuffer buf = new StringBuffer(50)
 
530
                                .append(" and ")
 
531
                                .append( frag.toFragmentString() );
 
532
 
 
533
                        return buf.toString();
 
534
                }
 
535
                else {
 
536
                        return "";
 
537
                }
 
538
        }
 
539
 
 
540
        private boolean needsDiscriminator() {
 
541
                return forceDiscriminator || isInherited();
 
542
        }
 
543
 
 
544
        public String getSubclassPropertyTableName(int i) {
 
545
                return subclassTableNameClosure[ subclassPropertyTableNumberClosure[i] ];
 
546
        }
 
547
 
 
548
        protected void addDiscriminatorToSelect(SelectFragment select, String name, String suffix) {
 
549
                if ( isDiscriminatorFormula() ) {
 
550
                        select.addFormula( name, getDiscriminatorFormulaTemplate(), getDiscriminatorAlias() );
 
551
                }
 
552
                else {
 
553
                        select.addColumn( name, getDiscriminatorColumnName(),  getDiscriminatorAlias() );
 
554
                }
 
555
        }
 
556
        
 
557
        protected int[] getPropertyTableNumbersInSelect() {
 
558
                return propertyTableNumbers;
 
559
        }
 
560
 
 
561
        protected int getSubclassPropertyTableNumber(int i) {
 
562
                return subclassPropertyTableNumberClosure[i];
 
563
        }
 
564
 
 
565
        public int getTableSpan() {
 
566
                return joinSpan;
 
567
        }
 
568
 
 
569
        protected void addDiscriminatorToInsert(Insert insert) {
 
570
 
 
571
                if (discriminatorInsertable) {
 
572
                        insert.addColumn( getDiscriminatorColumnName(), discriminatorSQLValue );
 
573
                }
 
574
 
 
575
        }
 
576
 
 
577
        protected int[] getSubclassColumnTableNumberClosure() {
 
578
                return subclassColumnTableNumberClosure;
 
579
        }
 
580
 
 
581
        protected int[] getSubclassFormulaTableNumberClosure() {
 
582
                return subclassFormulaTableNumberClosure;
 
583
        }
 
584
 
 
585
        protected int[] getPropertyTableNumbers() {
 
586
                return propertyTableNumbers;
 
587
        }
 
588
                
 
589
        protected boolean isSubclassPropertyDeferred(String propertyName, String entityName) {
 
590
                return hasSequentialSelects && 
 
591
                        isSubclassTableSequentialSelect( getSubclassPropertyTableNumber(propertyName, entityName) );
 
592
        }
 
593
        
 
594
        public boolean hasSequentialSelect() {
 
595
                return hasSequentialSelects;
 
596
        }
 
597
        
 
598
        private int getSubclassPropertyTableNumber(String propertyName, String entityName) {
 
599
                Type type = propertyMapping.toType(propertyName);
 
600
                if ( type.isAssociationType() && ( (AssociationType) type ).useLHSPrimaryKey() ) return 0;
 
601
                final Integer tabnum = (Integer) propertyTableNumbersByNameAndSubclass.get(entityName + '.' + propertyName);
 
602
                return tabnum==null ? 0 : tabnum.intValue();
 
603
        }
 
604
        
 
605
        protected String getSequentialSelect(String entityName) {
 
606
                return (String) sequentialSelectStringsByEntityName.get(entityName);
 
607
        }
 
608
 
 
609
        private String generateSequentialSelect(Loadable persister) {
 
610
                //if ( this==persister || !hasSequentialSelects ) return null;
 
611
 
 
612
                //note that this method could easily be moved up to BasicEntityPersister,
 
613
                //if we ever needed to reuse it from other subclasses
 
614
                
 
615
                //figure out which tables need to be fetched
 
616
                AbstractEntityPersister subclassPersister = (AbstractEntityPersister) persister;
 
617
                HashSet tableNumbers = new HashSet();
 
618
                String[] props = subclassPersister.getPropertyNames();
 
619
                String[] classes = subclassPersister.getPropertySubclassNames();
 
620
                for ( int i=0; i<props.length; i++ ) {
 
621
                        int propTableNumber = getSubclassPropertyTableNumber( props[i], classes[i] );
 
622
                        if ( isSubclassTableSequentialSelect(propTableNumber) && !isSubclassTableLazy(propTableNumber) ) {
 
623
                                tableNumbers.add( new Integer(propTableNumber) );
 
624
                        }
 
625
                }
 
626
                if ( tableNumbers.isEmpty() ) return null;
 
627
                
 
628
                //figure out which columns are needed
 
629
                ArrayList columnNumbers = new ArrayList();
 
630
                final int[] columnTableNumbers = getSubclassColumnTableNumberClosure();
 
631
                for ( int i=0; i<getSubclassColumnClosure().length; i++ ) {
 
632
                        if ( tableNumbers.contains( new Integer( columnTableNumbers[i] ) ) ) {
 
633
                                columnNumbers.add( new Integer(i) );
 
634
                        }
 
635
                }
 
636
                
 
637
                //figure out which formulas are needed
 
638
                ArrayList formulaNumbers = new ArrayList();
 
639
                final int[] formulaTableNumbers = getSubclassColumnTableNumberClosure();
 
640
                for ( int i=0; i<getSubclassFormulaTemplateClosure().length; i++ ) {
 
641
                        if ( tableNumbers.contains( new Integer( formulaTableNumbers[i] ) ) ) {
 
642
                                formulaNumbers.add( new Integer(i) );
 
643
                        }
 
644
                }
 
645
                
 
646
                //render the SQL
 
647
                return renderSelect( 
 
648
                        ArrayHelper.toIntArray(tableNumbers),
 
649
                        ArrayHelper.toIntArray(columnNumbers),
 
650
                        ArrayHelper.toIntArray(formulaNumbers)
 
651
                );
 
652
        }
 
653
                
 
654
                
 
655
        protected String[] getSubclassTableKeyColumns(int j) {
 
656
                return subclassTableKeyColumnClosure[j];
 
657
        }
 
658
 
 
659
        public String getSubclassTableName(int j) {
 
660
                return subclassTableNameClosure[j];
 
661
        }
 
662
 
 
663
        public int getSubclassTableSpan() {
 
664
                return subclassTableNameClosure.length;
 
665
        }
 
666
 
 
667
        protected boolean isClassOrSuperclassTable(int j) {
 
668
                return isClassOrSuperclassTable[j];
 
669
        }
 
670
 
 
671
        protected boolean isSubclassTableLazy(int j) {
 
672
                return subclassTableIsLazyClosure[j];
 
673
        }
 
674
        
 
675
        protected boolean isNullableTable(int j) {
 
676
                return isNullableTable[j];
 
677
        }
 
678
        
 
679
        protected boolean isNullableSubclassTable(int j) {
 
680
                return isNullableSubclassTable[j];
 
681
        }
 
682
 
 
683
        public String getPropertyTableName(String propertyName) {
 
684
                Integer index = getEntityMetamodel().getPropertyIndexOrNull(propertyName);
 
685
                if (index==null) return null;
 
686
                return qualifiedTableNames[ propertyTableNumbers[ index.intValue() ] ];
 
687
        }
 
688
        
 
689
        public void postInstantiate() {
 
690
                super.postInstantiate();
 
691
                if (hasSequentialSelects) {
 
692
                        String[] entityNames = getSubclassClosure();
 
693
                        for ( int i=1; i<entityNames.length; i++ ) {
 
694
                                Loadable loadable = (Loadable) getFactory().getEntityPersister( entityNames[i] );
 
695
                                if ( !loadable.isAbstract() ) { //perhaps not really necessary...
 
696
                                        String sequentialSelect = generateSequentialSelect(loadable);
 
697
                                        sequentialSelectStringsByEntityName.put( entityNames[i], sequentialSelect );
 
698
                                }
 
699
                        }
 
700
                }
 
701
        }
 
702
 
 
703
        public boolean isMultiTable() {
 
704
                return getTableSpan() > 1;
 
705
        }
 
706
 
 
707
        public String[] getConstraintOrderedTableNameClosure() {
 
708
                return constraintOrderedTableNames;
 
709
        }
 
710
 
 
711
        public String[][] getContraintOrderedTableKeyColumnClosure() {
 
712
                return constraintOrderedKeyColumnNames;
 
713
        }
 
714
}