HHH-6381 Adding a actual assertion which tests the optional part. Also applying formatting styles.

This commit is contained in:
Hardy Ferentschik 2011-07-06 14:46:07 +02:00
parent 20559966b3
commit d1eec59c08
3 changed files with 218 additions and 204 deletions

View File

@ -96,7 +96,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
private final boolean[] subclassTableSequentialSelect; private final boolean[] subclassTableSequentialSelect;
private final boolean[] subclassTableIsLazyClosure; private final boolean[] subclassTableIsLazyClosure;
// subclass discrimination works by assigning particular // subclass discrimination works by assigning particular
// values to certain combinations of null primary key // values to certain combinations of null primary key
// values in the outer join using an SQL CASE // values in the outer join using an SQL CASE
@ -110,9 +110,9 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
private final String discriminatorSQLString; private final String discriminatorSQLString;
//Span of the tables directly mapped by this entity and super-classes, if any // Span of the tables directly mapped by this entity and super-classes, if any
private final int coreTableSpan; private final int coreTableSpan;
// only contains values for SecondaryTables ie. not tables part of the "coreTableSpan" // only contains values for SecondaryTables, ie. not tables part of the "coreTableSpan"
private final boolean[] isNullableTable; private final boolean[] isNullableTable;
//INITIALIZATION: //INITIALIZATION:
@ -133,8 +133,8 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
discriminatorValue = new Integer( persistentClass.getSubclassId() ); discriminatorValue = new Integer( persistentClass.getSubclassId() );
discriminatorSQLString = discriminatorValue.toString(); discriminatorSQLString = discriminatorValue.toString();
} }
catch (Exception e) { catch ( Exception e ) {
throw new MappingException("Could not format discriminator value to SQL string", e ); throw new MappingException( "Could not format discriminator value to SQL string", e );
} }
} }
else { else {
@ -165,136 +165,135 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
factory.getSettings().getDefaultCatalogName(), factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName() factory.getSettings().getDefaultSchemaName()
); );
tables.add(tabname); tables.add( tabname );
String[] keyCols = new String[idColumnSpan]; String[] keyCols = new String[idColumnSpan];
String[] keyColReaders = new String[idColumnSpan]; String[] keyColReaders = new String[idColumnSpan];
String[] keyColReaderTemplates = new String[idColumnSpan]; String[] keyColReaderTemplates = new String[idColumnSpan];
Iterator citer = key.getColumnIterator(); Iterator citer = key.getColumnIterator();
for ( int k=0; k<idColumnSpan; k++ ) { for ( int k = 0; k < idColumnSpan; k++ ) {
Column column = (Column) citer.next(); Column column = (Column) citer.next();
keyCols[k] = column.getQuotedName( factory.getDialect() ); keyCols[k] = column.getQuotedName( factory.getDialect() );
keyColReaders[k] = column.getReadExpr( factory.getDialect() ); keyColReaders[k] = column.getReadExpr( factory.getDialect() );
keyColReaderTemplates[k] = column.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() ); keyColReaderTemplates[k] = column.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
} }
keyColumns.add(keyCols); keyColumns.add( keyCols );
keyColumnReaders.add(keyColReaders); keyColumnReaders.add( keyColReaders );
keyColumnReaderTemplates.add(keyColReaderTemplates); keyColumnReaderTemplates.add( keyColReaderTemplates );
cascadeDeletes.add( key.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete() ); cascadeDeletes.add( key.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete() );
} }
//Span of the tables directly mapped by this entity and super-classes, if any //Span of the tables directly mapped by this entity and super-classes, if any
coreTableSpan = tables.size(); coreTableSpan = tables.size();
isNullableTable = new boolean[persistentClass.getJoinClosureSpan()]; isNullableTable = new boolean[persistentClass.getJoinClosureSpan()];
int tabIndex = 0; int tableIndex = 0;
Iterator joinIter = persistentClass.getJoinClosureIterator(); Iterator joinIter = persistentClass.getJoinClosureIterator();
while ( joinIter.hasNext() ) { while ( joinIter.hasNext() ) {
Join join = (Join) joinIter.next(); Join join = (Join) joinIter.next();
isNullableTable[tabIndex++] = join.isOptional();
Table tab = join.getTable(); isNullableTable[tableIndex++] = join.isOptional();
String tabname = tab.getQualifiedName( Table table = join.getTable();
String tableName = table.getQualifiedName(
factory.getDialect(), factory.getDialect(),
factory.getSettings().getDefaultCatalogName(), factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName() factory.getSettings().getDefaultSchemaName()
); );
tables.add(tabname); tables.add( tableName );
KeyValue key = join.getKey(); KeyValue key = join.getKey();
int joinIdColumnSpan = key.getColumnSpan(); int joinIdColumnSpan = key.getColumnSpan();
String[] keyCols = new String[joinIdColumnSpan]; String[] keyCols = new String[joinIdColumnSpan];
String[] keyColReaders = new String[joinIdColumnSpan]; String[] keyColReaders = new String[joinIdColumnSpan];
String[] keyColReaderTemplates = new String[joinIdColumnSpan]; String[] keyColReaderTemplates = new String[joinIdColumnSpan];
Iterator citer = key.getColumnIterator(); Iterator citer = key.getColumnIterator();
for ( int k=0; k<joinIdColumnSpan; k++ ) { for ( int k = 0; k < joinIdColumnSpan; k++ ) {
Column column = (Column) citer.next(); Column column = (Column) citer.next();
keyCols[k] = column.getQuotedName( factory.getDialect() ); keyCols[k] = column.getQuotedName( factory.getDialect() );
keyColReaders[k] = column.getReadExpr( factory.getDialect() ); keyColReaders[k] = column.getReadExpr( factory.getDialect() );
keyColReaderTemplates[k] = column.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() ); keyColReaderTemplates[k] = column.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
} }
keyColumns.add(keyCols); keyColumns.add( keyCols );
keyColumnReaders.add(keyColReaders); keyColumnReaders.add( keyColReaders );
keyColumnReaderTemplates.add(keyColReaderTemplates); keyColumnReaderTemplates.add( keyColReaderTemplates );
cascadeDeletes.add( key.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete() ); cascadeDeletes.add( key.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete() );
} }
naturalOrderTableNames = ArrayHelper.toStringArray( tables ); naturalOrderTableNames = ArrayHelper.toStringArray( tables );
naturalOrderTableKeyColumns = ArrayHelper.to2DStringArray(keyColumns); naturalOrderTableKeyColumns = ArrayHelper.to2DStringArray( keyColumns );
naturalOrderTableKeyColumnReaders = ArrayHelper.to2DStringArray(keyColumnReaders); naturalOrderTableKeyColumnReaders = ArrayHelper.to2DStringArray( keyColumnReaders );
naturalOrderTableKeyColumnReaderTemplates = ArrayHelper.to2DStringArray(keyColumnReaderTemplates); naturalOrderTableKeyColumnReaderTemplates = ArrayHelper.to2DStringArray( keyColumnReaderTemplates );
naturalOrderCascadeDeleteEnabled = ArrayHelper.toBooleanArray(cascadeDeletes); naturalOrderCascadeDeleteEnabled = ArrayHelper.toBooleanArray( cascadeDeletes );
ArrayList subtables = new ArrayList(); ArrayList subtables = new ArrayList();
ArrayList isConcretes = new ArrayList(); ArrayList isConcretes = new ArrayList();
ArrayList isDeferreds = new ArrayList(); ArrayList isDeferreds = new ArrayList();
ArrayList isLazies = new ArrayList(); ArrayList isLazies = new ArrayList();
keyColumns = new ArrayList(); keyColumns = new ArrayList();
titer = persistentClass.getSubclassTableClosureIterator(); titer = persistentClass.getSubclassTableClosureIterator();
while ( titer.hasNext() ) { while ( titer.hasNext() ) {
Table tab = (Table) titer.next(); Table tab = (Table) titer.next();
isConcretes.add( persistentClass.isClassOrSuperclassTable(tab) ); isConcretes.add( persistentClass.isClassOrSuperclassTable( tab ) );
isDeferreds.add(Boolean.FALSE); isDeferreds.add( Boolean.FALSE );
isLazies.add(Boolean.FALSE); isLazies.add( Boolean.FALSE );
String tabname = tab.getQualifiedName( String tabname = tab.getQualifiedName(
factory.getDialect(), factory.getDialect(),
factory.getSettings().getDefaultCatalogName(), factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName() factory.getSettings().getDefaultSchemaName()
); );
subtables.add(tabname); subtables.add( tabname );
String[] key = new String[idColumnSpan]; String[] key = new String[idColumnSpan];
Iterator citer = tab.getPrimaryKey().getColumnIterator(); Iterator citer = tab.getPrimaryKey().getColumnIterator();
for ( int k=0; k<idColumnSpan; k++ ) { for ( int k = 0; k < idColumnSpan; k++ ) {
key[k] = ( (Column) citer.next() ).getQuotedName( factory.getDialect() ); key[k] = ( (Column) citer.next() ).getQuotedName( factory.getDialect() );
} }
keyColumns.add(key); keyColumns.add( key );
} }
//Add joins //Add joins
joinIter = persistentClass.getSubclassJoinClosureIterator(); joinIter = persistentClass.getSubclassJoinClosureIterator();
while ( joinIter.hasNext() ) { while ( joinIter.hasNext() ) {
Join join = (Join) joinIter.next(); Join join = (Join) joinIter.next();
Table tab = join.getTable(); Table tab = join.getTable();
isConcretes.add( persistentClass.isClassOrSuperclassTable(tab) ); isConcretes.add( persistentClass.isClassOrSuperclassTable( tab ) );
isDeferreds.add( join.isSequentialSelect() ); isDeferreds.add( join.isSequentialSelect() );
isLazies.add(join.isLazy()); isLazies.add( join.isLazy() );
String tabname = tab.getQualifiedName( String tabname = tab.getQualifiedName(
factory.getDialect(), factory.getDialect(),
factory.getSettings().getDefaultCatalogName(), factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName() factory.getSettings().getDefaultSchemaName()
); );
subtables.add(tabname); subtables.add( tabname );
String[] key = new String[idColumnSpan]; String[] key = new String[idColumnSpan];
Iterator citer = tab.getPrimaryKey().getColumnIterator(); Iterator citer = tab.getPrimaryKey().getColumnIterator();
for ( int k=0; k<idColumnSpan; k++ ) { for ( int k = 0; k < idColumnSpan; k++ ) {
key[k] = ( (Column) citer.next() ).getQuotedName( factory.getDialect() ); key[k] = ( (Column) citer.next() ).getQuotedName( factory.getDialect() );
} }
keyColumns.add(key); keyColumns.add( key );
} }
String [] naturalOrderSubclassTableNameClosure = ArrayHelper.toStringArray(subtables); String[] naturalOrderSubclassTableNameClosure = ArrayHelper.toStringArray( subtables );
String[][] naturalOrderSubclassTableKeyColumnClosure = ArrayHelper.to2DStringArray(keyColumns); String[][] naturalOrderSubclassTableKeyColumnClosure = ArrayHelper.to2DStringArray( keyColumns );
isClassOrSuperclassTable = ArrayHelper.toBooleanArray(isConcretes); isClassOrSuperclassTable = ArrayHelper.toBooleanArray( isConcretes );
subclassTableSequentialSelect = ArrayHelper.toBooleanArray(isDeferreds); subclassTableSequentialSelect = ArrayHelper.toBooleanArray( isDeferreds );
subclassTableIsLazyClosure = ArrayHelper.toBooleanArray(isLazies); subclassTableIsLazyClosure = ArrayHelper.toBooleanArray( isLazies );
constraintOrderedTableNames = new String[naturalOrderSubclassTableNameClosure.length]; constraintOrderedTableNames = new String[naturalOrderSubclassTableNameClosure.length];
constraintOrderedKeyColumnNames = new String[naturalOrderSubclassTableNameClosure.length][]; constraintOrderedKeyColumnNames = new String[naturalOrderSubclassTableNameClosure.length][];
int currentPosition = 0; int currentPosition = 0;
for ( int i = naturalOrderSubclassTableNameClosure.length - 1; i >= 0 ; i--, currentPosition++ ) { for ( int i = naturalOrderSubclassTableNameClosure.length - 1; i >= 0; i--, currentPosition++ ) {
constraintOrderedTableNames[currentPosition] = naturalOrderSubclassTableNameClosure[i]; constraintOrderedTableNames[currentPosition] = naturalOrderSubclassTableNameClosure[i];
constraintOrderedKeyColumnNames[currentPosition] = naturalOrderSubclassTableKeyColumnClosure[i]; constraintOrderedKeyColumnNames[currentPosition] = naturalOrderSubclassTableKeyColumnClosure[i];
} }
/** /**
* Suppose an entity Client extends Person, mapped to the tables CLIENT and PERSON respectively. * Suppose an entity Client extends Person, mapped to the tables CLIENT and PERSON respectively.
@ -305,15 +304,15 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
* the first table as it will the driving table. * the first table as it will the driving table.
* tableNames -> CLIENT, PERSON * tableNames -> CLIENT, PERSON
*/ */
tableSpan = naturalOrderTableNames.length; tableSpan = naturalOrderTableNames.length;
tableNames = reverse(naturalOrderTableNames, coreTableSpan); tableNames = reverse( naturalOrderTableNames, coreTableSpan );
tableKeyColumns = reverse(naturalOrderTableKeyColumns, coreTableSpan); tableKeyColumns = reverse( naturalOrderTableKeyColumns, coreTableSpan );
tableKeyColumnReaders = reverse(naturalOrderTableKeyColumnReaders, coreTableSpan); tableKeyColumnReaders = reverse( naturalOrderTableKeyColumnReaders, coreTableSpan );
tableKeyColumnReaderTemplates = reverse(naturalOrderTableKeyColumnReaderTemplates, coreTableSpan); tableKeyColumnReaderTemplates = reverse( naturalOrderTableKeyColumnReaderTemplates, coreTableSpan );
subclassTableNameClosure = reverse(naturalOrderSubclassTableNameClosure, coreTableSpan); subclassTableNameClosure = reverse( naturalOrderSubclassTableNameClosure, coreTableSpan );
subclassTableKeyColumnClosure = reverse(naturalOrderSubclassTableKeyColumnClosure, coreTableSpan); subclassTableKeyColumnClosure = reverse( naturalOrderSubclassTableKeyColumnClosure, coreTableSpan );
spaces = ArrayHelper.join( spaces = ArrayHelper.join(
tableNames, tableNames,
ArrayHelper.toStringArray( persistentClass.getSynchronizedTables() ) ArrayHelper.toStringArray( persistentClass.getSynchronizedTables() )
@ -331,71 +330,71 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan]; deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
PersistentClass pc = persistentClass; PersistentClass pc = persistentClass;
int jk = coreTableSpan-1; int jk = coreTableSpan - 1;
while (pc!=null) { while ( pc != null ) {
customSQLInsert[jk] = pc.getCustomSQLInsert(); customSQLInsert[jk] = pc.getCustomSQLInsert();
insertCallable[jk] = customSQLInsert[jk] != null && pc.isCustomInsertCallable(); insertCallable[jk] = customSQLInsert[jk] != null && pc.isCustomInsertCallable();
insertResultCheckStyles[jk] = pc.getCustomSQLInsertCheckStyle() == null insertResultCheckStyles[jk] = pc.getCustomSQLInsertCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( ? ExecuteUpdateResultCheckStyle.determineDefault(
customSQLInsert[jk], insertCallable[jk] customSQLInsert[jk], insertCallable[jk]
) )
: pc.getCustomSQLInsertCheckStyle(); : pc.getCustomSQLInsertCheckStyle();
customSQLUpdate[jk] = pc.getCustomSQLUpdate(); customSQLUpdate[jk] = pc.getCustomSQLUpdate();
updateCallable[jk] = customSQLUpdate[jk] != null && pc.isCustomUpdateCallable(); updateCallable[jk] = customSQLUpdate[jk] != null && pc.isCustomUpdateCallable();
updateResultCheckStyles[jk] = pc.getCustomSQLUpdateCheckStyle() == null updateResultCheckStyles[jk] = pc.getCustomSQLUpdateCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[jk], updateCallable[jk] ) ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[jk], updateCallable[jk] )
: pc.getCustomSQLUpdateCheckStyle(); : pc.getCustomSQLUpdateCheckStyle();
customSQLDelete[jk] = pc.getCustomSQLDelete(); customSQLDelete[jk] = pc.getCustomSQLDelete();
deleteCallable[jk] = customSQLDelete[jk] != null && pc.isCustomDeleteCallable(); deleteCallable[jk] = customSQLDelete[jk] != null && pc.isCustomDeleteCallable();
deleteResultCheckStyles[jk] = pc.getCustomSQLDeleteCheckStyle() == null deleteResultCheckStyles[jk] = pc.getCustomSQLDeleteCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[jk], deleteCallable[jk] ) ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[jk], deleteCallable[jk] )
: pc.getCustomSQLDeleteCheckStyle(); : pc.getCustomSQLDeleteCheckStyle();
jk--; jk--;
pc = pc.getSuperclass(); pc = pc.getSuperclass();
} }
if ( jk != -1 ) { if ( jk != -1 ) {
throw new AssertionFailure( "Tablespan does not match height of joined-subclass hiearchy." ); throw new AssertionFailure( "Tablespan does not match height of joined-subclass hiearchy." );
} }
joinIter = persistentClass.getJoinClosureIterator(); joinIter = persistentClass.getJoinClosureIterator();
int j = coreTableSpan; int j = coreTableSpan;
while ( joinIter.hasNext() ) { while ( joinIter.hasNext() ) {
Join join = (Join) joinIter.next(); Join join = (Join) joinIter.next();
customSQLInsert[j] = join.getCustomSQLInsert(); customSQLInsert[j] = join.getCustomSQLInsert();
insertCallable[j] = customSQLInsert[j] != null && join.isCustomInsertCallable(); insertCallable[j] = customSQLInsert[j] != null && join.isCustomInsertCallable();
insertResultCheckStyles[j] = join.getCustomSQLInsertCheckStyle() == null insertResultCheckStyles[j] = join.getCustomSQLInsertCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[j], insertCallable[j] ) ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[j], insertCallable[j] )
: join.getCustomSQLInsertCheckStyle(); : join.getCustomSQLInsertCheckStyle();
customSQLUpdate[j] = join.getCustomSQLUpdate(); customSQLUpdate[j] = join.getCustomSQLUpdate();
updateCallable[j] = customSQLUpdate[j] != null && join.isCustomUpdateCallable(); updateCallable[j] = customSQLUpdate[j] != null && join.isCustomUpdateCallable();
updateResultCheckStyles[j] = join.getCustomSQLUpdateCheckStyle() == null updateResultCheckStyles[j] = join.getCustomSQLUpdateCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[j], updateCallable[j] ) ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[j], updateCallable[j] )
: join.getCustomSQLUpdateCheckStyle(); : join.getCustomSQLUpdateCheckStyle();
customSQLDelete[j] = join.getCustomSQLDelete(); customSQLDelete[j] = join.getCustomSQLDelete();
deleteCallable[j] = customSQLDelete[j] != null && join.isCustomDeleteCallable(); deleteCallable[j] = customSQLDelete[j] != null && join.isCustomDeleteCallable();
deleteResultCheckStyles[j] = join.getCustomSQLDeleteCheckStyle() == null deleteResultCheckStyles[j] = join.getCustomSQLDeleteCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[j], deleteCallable[j] ) ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[j], deleteCallable[j] )
: join.getCustomSQLDeleteCheckStyle(); : join.getCustomSQLDeleteCheckStyle();
j++; j++;
} }
// PROPERTIES // PROPERTIES
int hydrateSpan = getPropertySpan(); int hydrateSpan = getPropertySpan();
naturalOrderPropertyTableNumbers = new int[hydrateSpan]; naturalOrderPropertyTableNumbers = new int[hydrateSpan];
propertyTableNumbers = new int[hydrateSpan]; propertyTableNumbers = new int[hydrateSpan];
Iterator iter = persistentClass.getPropertyClosureIterator(); Iterator iter = persistentClass.getPropertyClosureIterator();
int i=0; int i = 0;
while( iter.hasNext() ) { while ( iter.hasNext() ) {
Property prop = (Property) iter.next(); Property prop = (Property) iter.next();
String tabname = prop.getValue().getTable().getQualifiedName( String tabname = prop.getValue().getTable().getQualifiedName(
factory.getDialect(), factory.getDialect(),
factory.getSettings().getDefaultCatalogName(), factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName() factory.getSettings().getDefaultSchemaName()
); );
propertyTableNumbers[i] = getTableId(tabname, tableNames); propertyTableNumbers[i] = getTableId( tabname, tableNames );
naturalOrderPropertyTableNumbers[i] = getTableId(tabname, naturalOrderTableNames); naturalOrderPropertyTableNumbers[i] = getTableId( tabname, naturalOrderTableNames );
i++; i++;
} }
@ -416,47 +415,47 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
factory.getSettings().getDefaultCatalogName(), factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName() factory.getSettings().getDefaultSchemaName()
); );
Integer tabnum = new Integer( getTableId(tabname, subclassTableNameClosure) ); Integer tabnum = new Integer( getTableId( tabname, subclassTableNameClosure ) );
propTableNumbers.add(tabnum); propTableNumbers.add( tabnum );
Iterator citer = prop.getColumnIterator(); Iterator citer = prop.getColumnIterator();
while ( citer.hasNext() ) { while ( citer.hasNext() ) {
Selectable thing = (Selectable) citer.next(); Selectable thing = (Selectable) citer.next();
if ( thing.isFormula() ) { if ( thing.isFormula() ) {
formulaTableNumbers.add(tabnum); formulaTableNumbers.add( tabnum );
} }
else { else {
columnTableNumbers.add(tabnum); columnTableNumbers.add( tabnum );
} }
} }
} }
subclassColumnTableNumberClosure = ArrayHelper.toIntArray(columnTableNumbers); subclassColumnTableNumberClosure = ArrayHelper.toIntArray( columnTableNumbers );
subclassPropertyTableNumberClosure = ArrayHelper.toIntArray(propTableNumbers); subclassPropertyTableNumberClosure = ArrayHelper.toIntArray( propTableNumbers );
subclassFormulaTableNumberClosure = ArrayHelper.toIntArray(formulaTableNumbers); subclassFormulaTableNumberClosure = ArrayHelper.toIntArray( formulaTableNumbers );
// SUBCLASSES // SUBCLASSES
int subclassSpan = persistentClass.getSubclassSpan() + 1; int subclassSpan = persistentClass.getSubclassSpan() + 1;
subclassClosure = new String[subclassSpan]; subclassClosure = new String[subclassSpan];
subclassClosure[subclassSpan-1] = getEntityName(); subclassClosure[subclassSpan - 1] = getEntityName();
if ( persistentClass.isPolymorphic() ) { if ( persistentClass.isPolymorphic() ) {
subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() ); subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() );
discriminatorValues = new String[subclassSpan]; discriminatorValues = new String[subclassSpan];
discriminatorValues[subclassSpan-1] = discriminatorSQLString; discriminatorValues[subclassSpan - 1] = discriminatorSQLString;
notNullColumnTableNumbers = new int[subclassSpan]; notNullColumnTableNumbers = new int[subclassSpan];
final int id = getTableId( final int id = getTableId(
persistentClass.getTable().getQualifiedName( persistentClass.getTable().getQualifiedName(
factory.getDialect(), factory.getDialect(),
factory.getSettings().getDefaultCatalogName(), factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName() factory.getSettings().getDefaultSchemaName()
), ),
subclassTableNameClosure subclassTableNameClosure
); );
notNullColumnTableNumbers[subclassSpan-1] = id; notNullColumnTableNumbers[subclassSpan - 1] = id;
notNullColumnNames = new String[subclassSpan]; notNullColumnNames = new String[subclassSpan];
notNullColumnNames[subclassSpan-1] = subclassTableKeyColumnClosure[id][0]; //( (Column) model.getTable().getPrimaryKey().getColumnIterator().next() ).getName(); notNullColumnNames[subclassSpan - 1] = subclassTableKeyColumnClosure[id][0]; //( (Column) model.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
} }
else { else {
discriminatorValues = null; discriminatorValues = null;
@ -465,7 +464,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
} }
iter = persistentClass.getSubclassIterator(); iter = persistentClass.getSubclassIterator();
int k=0; int k = 0;
while ( iter.hasNext() ) { while ( iter.hasNext() ) {
Subclass sc = (Subclass) iter.next(); Subclass sc = (Subclass) iter.next();
subclassClosure[k] = sc.getEntityName(); subclassClosure[k] = sc.getEntityName();
@ -478,28 +477,28 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
subclassesByDiscriminatorValue.put( subclassId, sc.getEntityName() ); subclassesByDiscriminatorValue.put( subclassId, sc.getEntityName() );
discriminatorValues[k] = subclassId.toString(); discriminatorValues[k] = subclassId.toString();
int id = getTableId( int id = getTableId(
sc.getTable().getQualifiedName( sc.getTable().getQualifiedName(
factory.getDialect(), factory.getDialect(),
factory.getSettings().getDefaultCatalogName(), factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName() factory.getSettings().getDefaultSchemaName()
), ),
subclassTableNameClosure subclassTableNameClosure
); );
notNullColumnTableNumbers[k] = id; notNullColumnTableNumbers[k] = id;
notNullColumnNames[k] = subclassTableKeyColumnClosure[id][0]; //( (Column) sc.getTable().getPrimaryKey().getColumnIterator().next() ).getName(); notNullColumnNames[k] = subclassTableKeyColumnClosure[id][0]; //( (Column) sc.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
} }
} }
catch (Exception e) { catch ( Exception e ) {
throw new MappingException("Error parsing discriminator value", e ); throw new MappingException( "Error parsing discriminator value", e );
} }
k++; k++;
} }
initLockers(); initLockers();
initSubclassPropertyAliasesMap(persistentClass); initSubclassPropertyAliasesMap( persistentClass );
postConstruct(mapping); postConstruct( mapping );
} }
@ -523,7 +522,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
spaces = null; spaces = null;
subclassClosure = null; subclassClosure = null;
subclassTableNameClosure = null; subclassTableNameClosure = null;
subclassTableKeyColumnClosure= null; subclassTableKeyColumnClosure = null;
isClassOrSuperclassTable = null; isClassOrSuperclassTable = null;
naturalOrderPropertyTableNumbers = null; naturalOrderPropertyTableNumbers = null;
propertyTableNumbers = null; propertyTableNumbers = null;
@ -543,16 +542,16 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
} }
protected boolean isNullableTable(int j) { protected boolean isNullableTable(int j) {
if (j < coreTableSpan) if ( j < coreTableSpan ) {
return false; return false;
return isNullableTable[j-coreTableSpan]; }
return isNullableTable[j - coreTableSpan];
} }
protected boolean isSubclassTableSequentialSelect(int j) { protected boolean isSubclassTableSequentialSelect(int j) {
return subclassTableSequentialSelect[j] && !isClassOrSuperclassTable[j]; return subclassTableSequentialSelect[j] && !isClassOrSuperclassTable[j];
} }
/*public void postInstantiate() throws MappingException { /*public void postInstantiate() throws MappingException {
super.postInstantiate(); super.postInstantiate();
//TODO: other lock modes? //TODO: other lock modes?
@ -560,7 +559,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
}*/ }*/
public String getSubclassPropertyTableName(int i) { public String getSubclassPropertyTableName(int i) {
return subclassTableNameClosure[ subclassPropertyTableNumberClosure[i] ]; return subclassTableNameClosure[subclassPropertyTableNumberClosure[i]];
} }
public Type getDiscriminatorType() { public Type getDiscriminatorType() {
@ -573,7 +572,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
public String getSubclassForDiscriminatorValue(Object value) { public String getSubclassForDiscriminatorValue(Object value) {
return (String) subclassesByDiscriminatorValue.get(value); return (String) subclassesByDiscriminatorValue.get( value );
} }
public Serializable[] getPropertySpaces() { public Serializable[] getPropertySpaces() {
@ -594,7 +593,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
} }
protected boolean isPropertyOfTable(int property, int j) { protected boolean isPropertyOfTable(int property, int j) {
return naturalOrderPropertyTableNumbers[property]==j; return naturalOrderPropertyTableNumbers[property] == j;
} }
/** /**
@ -622,62 +621,64 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
throw new JDBCException( "could not load by id: " + MessageHelper.infoString(this, id), sqle ); throw new JDBCException( "could not load by id: " + MessageHelper.infoString(this, id), sqle );
} }
}*/ }*/
private static final void reverse(Object[] objects, int len) { private static final void reverse(Object[] objects, int len) {
Object[] temp = new Object[len]; Object[] temp = new Object[len];
for (int i=0; i<len; i++) { for ( int i = 0; i < len; i++ ) {
temp[i] = objects[len-i-1]; temp[i] = objects[len - i - 1];
} }
for (int i=0; i<len; i++) { for ( int i = 0; i < len; i++ ) {
objects[i] = temp[i]; objects[i] = temp[i];
} }
} }
/** /**
* Reverse the first n elements of the incoming array * Reverse the first n elements of the incoming array
*
* @param objects * @param objects
* @param n * @param n
* @return New array with the first n elements in reversed order *
* @return New array with the first n elements in reversed order
*/ */
private static final String[] reverse(String [] objects, int n) { private static String[] reverse(String[] objects, int n) {
int size = objects.length; int size = objects.length;
String[] temp = new String[size]; String[] temp = new String[size];
for (int i=0; i<n; i++) { for ( int i = 0; i < n; i++ ) {
temp[i] = objects[n-i-1]; temp[i] = objects[n - i - 1];
} }
for (int i=n; i < size; i++) { for ( int i = n; i < size; i++ ) {
temp[i] = objects[i];
}
return temp;
}
/**
* Reverse the first n elements of the incoming array
* @param objects
* @param n
* @return New array with the first n elements in reversed order
*/
private static final String[][] reverse(String[][] objects, int n) {
int size = objects.length;
String[][] temp = new String[size][];
for (int i=0; i<n; i++) {
temp[i] = objects[n-i-1];
}
for (int i=n; i<size; i++) {
temp[i] = objects[i]; temp[i] = objects[i];
} }
return temp; return temp;
} }
/**
* Reverse the first n elements of the incoming array
*
* @param objects
* @param n
*
* @return New array with the first n elements in reversed order
*/
private static String[][] reverse(String[][] objects, int n) {
int size = objects.length;
String[][] temp = new String[size][];
for ( int i = 0; i < n; i++ ) {
temp[i] = objects[n - i - 1];
}
for ( int i = n; i < size; i++ ) {
temp[i] = objects[i];
}
return temp;
}
public String fromTableFragment(String alias) { public String fromTableFragment(String alias) {
return getTableName() + ' ' + alias; return getTableName() + ' ' + alias;
} }
@ -687,28 +688,28 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
} }
private static int getTableId(String tableName, String[] tables) { private static int getTableId(String tableName, String[] tables) {
for ( int j=0; j<tables.length; j++ ) { for ( int j = 0; j < tables.length; j++ ) {
if ( tableName.equals( tables[j] ) ) { if ( tableName.equals( tables[j] ) ) {
return j; return j;
} }
} }
throw new AssertionFailure("Table " + tableName + " not found"); throw new AssertionFailure( "Table " + tableName + " not found" );
} }
public void addDiscriminatorToSelect(SelectFragment select, String name, String suffix) { public void addDiscriminatorToSelect(SelectFragment select, String name, String suffix) {
if ( hasSubclasses() ) { if ( hasSubclasses() ) {
select.setExtraSelectList( discriminatorFragment(name), getDiscriminatorAlias() ); select.setExtraSelectList( discriminatorFragment( name ), getDiscriminatorAlias() );
} }
} }
private CaseFragment discriminatorFragment(String alias) { private CaseFragment discriminatorFragment(String alias) {
CaseFragment cases = getFactory().getDialect().createCaseFragment(); CaseFragment cases = getFactory().getDialect().createCaseFragment();
for ( int i=0; i<discriminatorValues.length; i++ ) { for ( int i = 0; i < discriminatorValues.length; i++ ) {
cases.addWhenColumnNotNull( cases.addWhenColumnNotNull(
generateTableAlias( alias, notNullColumnTableNumbers[i] ), generateTableAlias( alias, notNullColumnTableNumbers[i] ),
notNullColumnNames[i], notNullColumnNames[i],
discriminatorValues[i] discriminatorValues[i]
); );
} }
@ -717,12 +718,12 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
public String filterFragment(String alias) { public String filterFragment(String alias) {
return hasWhere() ? return hasWhere() ?
" and " + getSQLWhereString( generateFilterConditionAlias( alias ) ) : " and " + getSQLWhereString( generateFilterConditionAlias( alias ) ) :
""; "";
} }
public String generateFilterConditionAlias(String rootAlias) { public String generateFilterConditionAlias(String rootAlias) {
return generateTableAlias( rootAlias, tableSpan-1 ); return generateTableAlias( rootAlias, tableSpan - 1 );
} }
public String[] getIdentifierColumnNames() { public String[] getIdentifierColumnNames() {
@ -735,23 +736,21 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
public String[] getIdentifierColumnReaders() { public String[] getIdentifierColumnReaders() {
return tableKeyColumnReaders[0]; return tableKeyColumnReaders[0];
} }
public String[] toColumns(String alias, String propertyName) throws QueryException {
if ( ENTITY_CLASS.equals(propertyName) ) { public String[] toColumns(String alias, String propertyName) throws QueryException {
if ( ENTITY_CLASS.equals( propertyName ) ) {
// This doesn't actually seem to work but it *might* // This doesn't actually seem to work but it *might*
// work on some dbs. Also it doesn't work if there // work on some dbs. Also it doesn't work if there
// are multiple columns of results because it // are multiple columns of results because it
// is not accounting for the suffix: // is not accounting for the suffix:
// return new String[] { getDiscriminatorColumnName() }; // return new String[] { getDiscriminatorColumnName() };
return new String[] { discriminatorFragment(alias).toFragmentString() }; return new String[] { discriminatorFragment( alias ).toFragmentString() };
} }
else { else {
return super.toColumns(alias, propertyName); return super.toColumns( alias, propertyName );
} }
} }
protected int[] getPropertyTableNumbersInSelect() { protected int[] getPropertyTableNumbersInSelect() {
@ -797,18 +796,18 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
protected boolean isSubclassTableLazy(int j) { protected boolean isSubclassTableLazy(int j) {
return subclassTableIsLazyClosure[j]; return subclassTableIsLazyClosure[j];
} }
protected boolean isClassOrSuperclassTable(int j) { protected boolean isClassOrSuperclassTable(int j) {
return isClassOrSuperclassTable[j]; return isClassOrSuperclassTable[j];
} }
public String getPropertyTableName(String propertyName) { public String getPropertyTableName(String propertyName) {
Integer index = getEntityMetamodel().getPropertyIndexOrNull(propertyName); Integer index = getEntityMetamodel().getPropertyIndexOrNull( propertyName );
if ( index == null ) { if ( index == null ) {
return null; return null;
} }
return tableNames[ propertyTableNumbers[ index.intValue() ] ]; return tableNames[propertyTableNumbers[index.intValue()]];
} }
public String[] getConstraintOrderedTableNameClosure() { public String[] getConstraintOrderedTableNameClosure() {

View File

@ -23,11 +23,12 @@
*/ */
package org.hibernate.test.annotations.inheritance.joined; package org.hibernate.test.annotations.inheritance.joined;
import org.hibernate.Session; import java.math.BigInteger;
import org.hibernate.Transaction;
import org.junit.Test; import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@ -42,32 +43,47 @@ public class JoinedSubclassAndSecondaryTable extends BaseCoreFunctionalTestCase
Session s = openSession(); Session s = openSession();
Transaction tx = s.beginTransaction(); Transaction tx = s.beginTransaction();
SwimmingPool sp = new SwimmingPool(); SwimmingPool sp = new SwimmingPool();
//sp.setAddress( "Park Avenue" );
s.persist( sp ); s.persist( sp );
s.flush(); s.flush();
s.clear(); s.clear();
SwimmingPool sp2 = (SwimmingPool)s.get(SwimmingPool.class, sp.getId()); BigInteger rowCount = getTableRowCount( s );
assertEquals( sp.getAddress(), null); assertEquals(
"The address table is marked as optional. For null values no database row should be created",
PoolAddress addr = new PoolAddress(); BigInteger.valueOf( 0 ),
addr.setAddress("Park Avenue"); rowCount
sp2.setAddress(addr); );
SwimmingPool sp2 = (SwimmingPool) s.get( SwimmingPool.class, sp.getId() );
assertEquals( sp.getAddress(), null );
PoolAddress address = new PoolAddress();
address.setAddress( "Park Avenue" );
sp2.setAddress( address );
s.flush(); s.flush();
s.clear(); s.clear();
sp2 = (SwimmingPool)s.get(SwimmingPool.class, sp.getId()); sp2 = (SwimmingPool) s.get( SwimmingPool.class, sp.getId() );
rowCount = getTableRowCount( s );
assertEquals(
"Now we should have a row in the pool address table ",
BigInteger.valueOf( 1 ),
rowCount
);
assertFalse( sp2.getAddress() == null ); assertFalse( sp2.getAddress() == null );
assertEquals( sp2.getAddress().getAddress(), "Park Avenue"); assertEquals( sp2.getAddress().getAddress(), "Park Avenue" );
tx.rollback(); tx.rollback();
s.close(); s.close();
} }
private BigInteger getTableRowCount(Session s) {
return (BigInteger) s.createSQLQuery( "select count(*) from POOL_ADDRESS" ).uniqueResult();
}
@Override @Override
protected Class[] getAnnotatedClasses() { protected Class[] getAnnotatedClasses() {
return new Class[] { Pool.class, SwimmingPool.class }; return new Class[] { Pool.class, SwimmingPool.class };
} }
} }

View File

@ -409,5 +409,4 @@ public abstract class BaseCoreFunctionalTestCase extends BaseUnitTestCase {
return true; return true;
} }
} }
} }