From 5457b6c707b5a0eab8ae1e26a0de82f71ef351e0 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Wed, 6 Jul 2011 15:08:36 -0700 Subject: [PATCH] HHH-6411 : Integrate new metamodel into SingleTableEntityPersister --- .../internal/SessionFactoryImpl.java | 16 +- .../entity/AbstractEntityPersister.java | 353 +++++++++++++++--- .../entity/SingleTableEntityPersister.java | 296 +++++++++++++-- 3 files changed, 569 insertions(+), 96 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index 8b9da3bb05..03ee76c9e3 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -540,8 +540,6 @@ public final class SessionFactoryImpl this.currentSessionContext = null; this.sqlFunctionRegistry = null; this.transactionEnvironment = null; - this.jdbcServices = null; - this.dialect = null; this.sessionFactoryOptions = sessionFactoryOptions; @@ -560,6 +558,9 @@ public final class SessionFactoryImpl .getService( SessionFactoryServiceRegistryFactory.class ) .buildServiceRegistry( this, metadata ); + this.jdbcServices = this.serviceRegistry.getService( JdbcServices.class ); + this.dialect = this.jdbcServices.getDialect(); + // TODO: get SQL functions from a new service // this.sqlFunctionRegistry = new SQLFunctionRegistry( getDialect(), cfg.getSqlFunctions() ); @@ -754,8 +755,7 @@ public final class SessionFactoryImpl Iterator iter = entityPersisters.values().iterator(); while ( iter.hasNext() ) { final EntityPersister persister = ( ( EntityPersister ) iter.next() ); - // TODO: broken - //persister.postInstantiate(); + persister.postInstantiate(); registerEntityNameResolvers( persister ); } @@ -959,19 +959,17 @@ public final class SessionFactoryImpl } public JdbcServices getJdbcServices() { - return jdbcServices; + return jdbcServices; } public Dialect getDialect() { if ( serviceRegistry == null ) { throw new IllegalStateException( "Cannot determine dialect because serviceRegistry is null." ); } - return dialect; - //return getJdbcServices().getDialect(); + return dialect; } - public Interceptor getInterceptor() - { + public Interceptor getInterceptor() { return sessionFactoryOptions.getInterceptor(); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 2f0f531691..71741cd580 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -42,10 +42,13 @@ import org.hibernate.AssertionFailure; import org.hibernate.EntityMode; import org.hibernate.FetchMode; import org.hibernate.HibernateException; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.function.SQLFunctionRegistry; import org.hibernate.engine.internal.Versioning; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; +import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.Mapping; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -92,7 +95,11 @@ import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; import org.hibernate.mapping.Selectable; import org.hibernate.metadata.ClassMetadata; +import org.hibernate.metamodel.binding.AttributeBinding; import org.hibernate.metamodel.binding.EntityBinding; +import org.hibernate.metamodel.relational.DerivedValue; +import org.hibernate.metamodel.relational.Identifier; +import org.hibernate.metamodel.relational.SimpleValue; import org.hibernate.pretty.MessageHelper; import org.hibernate.property.BackrefPropertyAccessor; import org.hibernate.sql.Alias; @@ -771,62 +778,233 @@ public abstract class AbstractEntityPersister new StructuredCacheEntry(this) : new UnstructuredCacheEntry(); this.entityMetamodel = new EntityMetamodel( entityBinding, factory ); - rootTableKeyColumnNames = null; - rootTableKeyColumnReaders = null; - rootTableKeyColumnReaderTemplates = null; - identifierAliases = null; - identifierColumnSpan = -1; - versionColumnName = null; - hasFormulaProperties = false; - batchSize = -1; - hasSubselectLoadableCollections = false; - rowIdName = null; - lazyProperties = null; - sqlWhereString = null; - sqlWhereStringTemplate = null; - propertyColumnSpans = null; - propertySubclassNames = null; - propertyColumnAliases = null; - propertyColumnNames = null; - propertyColumnFormulaTemplates = null; - propertyColumnReaderTemplates = null; - propertyColumnWriters = null; - propertyColumnUpdateable = null; - propertyColumnInsertable = null; - propertyUniqueness = null; - propertySelectable = null; - lazyPropertyNames = null; - lazyPropertyNumbers = null; - lazyPropertyTypes = null; - lazyPropertyColumnAliases = null; - subclassPropertyNameClosure = null; - subclassPropertySubclassNameClosure = null; - subclassPropertyTypeClosure = null; - subclassPropertyFormulaTemplateClosure = null; - subclassPropertyColumnNameClosure = null; - subclassPropertyColumnReaderClosure = null; - subclassPropertyColumnReaderTemplateClosure = null; - subclassPropertyFetchModeClosure = null; - subclassPropertyNullabilityClosure = null; - propertyDefinedOnSubclass = null; - subclassPropertyColumnNumberClosure = null; - subclassPropertyFormulaNumberClosure = null; - subclassPropertyCascadeStyleClosure = null; - subclassColumnClosure = null; - subclassColumnLazyClosure = null; - subclassColumnAliasClosure = null; - subclassColumnSelectableClosure = null; - subclassColumnReaderTemplateClosure = null; - subclassFormulaClosure = null; - subclassFormulaTemplateClosure = null; - subclassFormulaAliasClosure = null; - subclassFormulaLazyClosure = null; - filterHelper = null; - loaderName = null; - queryLoader = null; + int batch = entityBinding.getBatchSize(); + if ( batch == -1 ) { + batch = factory.getSettings().getDefaultBatchFetchSize(); + } + batchSize = batch; + hasSubselectLoadableCollections = entityBinding.hasSubselectLoadableCollections(); + + propertyMapping = new BasicEntityPropertyMapping( this ); + + // IDENTIFIER + + identifierColumnSpan = entityBinding.getEntityIdentifier().getValueBinding().getValuesSpan(); + rootTableKeyColumnNames = new String[identifierColumnSpan]; + rootTableKeyColumnReaders = new String[identifierColumnSpan]; + rootTableKeyColumnReaderTemplates = new String[identifierColumnSpan]; + identifierAliases = new String[identifierColumnSpan]; + + rowIdName = entityBinding.getRowId(); + + loaderName = entityBinding.getLoaderName(); + + int i = 0; + for ( org.hibernate.metamodel.relational.Column col : entityBinding.getBaseTable().getPrimaryKey().getColumns() ) { + rootTableKeyColumnNames[i] = col.getColumnName().encloseInQuotesIfQuoted( factory.getDialect() ); + if ( col.getReadFragment() == null ) { + rootTableKeyColumnReaders[i] = rootTableKeyColumnNames[i]; + rootTableKeyColumnReaderTemplates[i] = getTemplateFromColumn( col, factory ); + } + else { + rootTableKeyColumnReaders[i] = col.getReadFragment(); + rootTableKeyColumnReaderTemplates[i] = getTemplateFromString( col.getReadFragment(), factory ); + } + // TODO: Fix when HHH-6337 is fixed; for now assume entityBinding is the root + // identifierAliases[i] = col.getAlias( factory.getDialect(), entityBinding.getRootEntityBinding().getBaseTable() ); + identifierAliases[i] = col.getAlias( factory.getDialect() ); + i++; + } + + // VERSION + + if ( entityBinding.isVersioned() ) { + // Use AttributeBinding.getValues() due to HHH-6380 + Iterator valueIterator = entityBinding.getVersioningValueBinding().getValues().iterator(); + SimpleValue versionValue = valueIterator.next(); + if ( ! ( versionValue instanceof org.hibernate.metamodel.relational.Column ) || valueIterator.hasNext() ) { + throw new MappingException( "Version must be a single column value." ); + } + org.hibernate.metamodel.relational.Column versionColumn = + ( org.hibernate.metamodel.relational.Column ) versionValue; + versionColumnName = versionColumn.getColumnName().encloseInQuotesIfQuoted( factory.getDialect() ); + } + else { + versionColumnName = null; + } + + //WHERE STRING + + sqlWhereString = StringHelper.isNotEmpty( entityBinding.getWhereFilter() ) ? "( " + entityBinding.getWhereFilter() + ") " : null; + sqlWhereStringTemplate = getTemplateFromString( sqlWhereString, factory ); + + // PROPERTIES + + final boolean lazyAvailable = isInstrumented(); + + int hydrateSpan = entityMetamodel.getPropertySpan(); + propertyColumnSpans = new int[hydrateSpan]; + propertySubclassNames = new String[hydrateSpan]; + propertyColumnAliases = new String[hydrateSpan][]; + propertyColumnNames = new String[hydrateSpan][]; + propertyColumnFormulaTemplates = new String[hydrateSpan][]; + propertyColumnReaderTemplates = new String[hydrateSpan][]; + propertyColumnWriters = new String[hydrateSpan][]; + propertyUniqueness = new boolean[hydrateSpan]; + propertySelectable = new boolean[hydrateSpan]; + propertyColumnUpdateable = new boolean[hydrateSpan][]; + propertyColumnInsertable = new boolean[hydrateSpan][]; + HashSet thisClassProperties = new HashSet(); + + lazyProperties = new HashSet(); + ArrayList lazyNames = new ArrayList(); + ArrayList lazyNumbers = new ArrayList(); + ArrayList lazyTypes = new ArrayList(); + ArrayList lazyColAliases = new ArrayList(); + + i = 0; + boolean foundFormula = false; + for ( AttributeBinding prop : entityBinding.getAttributeBindingClosure() ) { + if ( prop == entityBinding.getEntityIdentifier().getValueBinding() ) { + // entity identifier is not considered a "normal" property + continue; + } + + thisClassProperties.add( prop ); + + int span = prop.getValuesSpan(); + propertyColumnSpans[i] = span; + propertySubclassNames[i] = prop.getEntityBinding().getEntity().getName(); + String[] colNames = new String[span]; + String[] colAliases = new String[span]; + String[] colReaderTemplates = new String[span]; + String[] colWriters = new String[span]; + String[] formulaTemplates = new String[span]; + int k = 0; + for ( SimpleValue thing : prop.getValues() ) { + colAliases[k] = thing.getAlias( factory.getDialect() ); + if ( thing instanceof DerivedValue ) { + foundFormula = true; + formulaTemplates[ k ] = getTemplateFromString( ( (DerivedValue) thing ).getExpression(), factory ); + } + else { + org.hibernate.metamodel.relational.Column col = ( org.hibernate.metamodel.relational.Column ) thing; + colNames[k] = col.getColumnName().encloseInQuotesIfQuoted( factory.getDialect() ); + colReaderTemplates[k] = getTemplateFromColumn( col, factory ); + colWriters[k] = col.getWriteFragment(); + } + k++; + } + propertyColumnNames[i] = colNames; + propertyColumnFormulaTemplates[i] = formulaTemplates; + propertyColumnReaderTemplates[i] = colReaderTemplates; + propertyColumnWriters[i] = colWriters; + propertyColumnAliases[i] = colAliases; + + if ( lazyAvailable && prop.isLazy() ) { + lazyProperties.add( prop.getAttribute().getName() ); + lazyNames.add( prop.getAttribute().getName() ); + lazyNumbers.add( i ); + lazyTypes.add( prop.getHibernateTypeDescriptor().getExplicitType()); + lazyColAliases.add( colAliases ); + } + + propertyColumnUpdateable[i] = prop.getColumnUpdateability(); + propertyColumnInsertable[i] = prop.getColumnInsertability(); + + // TODO: fix this when backrefs are working + //propertySelectable[i] = prop.isBackRef(); + propertySelectable[i] = true; + + propertyUniqueness[i] = prop.isAlternateUniqueKey(); + + i++; + + } + hasFormulaProperties = foundFormula; + lazyPropertyColumnAliases = ArrayHelper.to2DStringArray( lazyColAliases ); + lazyPropertyNames = ArrayHelper.toStringArray( lazyNames ); + lazyPropertyNumbers = ArrayHelper.toIntArray( lazyNumbers ); + lazyPropertyTypes = ArrayHelper.toTypeArray( lazyTypes ); + + // SUBCLASS PROPERTY CLOSURE + + ArrayList columns = new ArrayList(); + ArrayList columnsLazy = new ArrayList(); + ArrayList columnReaderTemplates = new ArrayList(); + ArrayList aliases = new ArrayList(); + ArrayList formulas = new ArrayList(); + ArrayList formulaAliases = new ArrayList(); + ArrayList formulaTemplates = new ArrayList(); + ArrayList formulasLazy = new ArrayList(); + ArrayList types = new ArrayList(); + ArrayList names = new ArrayList(); + ArrayList classes = new ArrayList(); + ArrayList templates = new ArrayList(); + ArrayList propColumns = new ArrayList(); + ArrayList propColumnReaders = new ArrayList(); + ArrayList propColumnReaderTemplates = new ArrayList(); + ArrayList joinedFetchesList = new ArrayList(); + ArrayList cascades = new ArrayList(); + ArrayList definedBySubclass = new ArrayList(); + ArrayList propColumnNumbers = new ArrayList(); + ArrayList propFormulaNumbers = new ArrayList(); + ArrayList columnSelectables = new ArrayList(); + ArrayList propNullables = new ArrayList(); + + subclassColumnClosure = ArrayHelper.toStringArray( columns ); + subclassColumnAliasClosure = ArrayHelper.toStringArray( aliases ); + subclassColumnLazyClosure = ArrayHelper.toBooleanArray( columnsLazy ); + subclassColumnSelectableClosure = ArrayHelper.toBooleanArray( columnSelectables ); + subclassColumnReaderTemplateClosure = ArrayHelper.toStringArray( columnReaderTemplates ); + + subclassFormulaClosure = ArrayHelper.toStringArray( formulas ); + subclassFormulaTemplateClosure = ArrayHelper.toStringArray( formulaTemplates ); + subclassFormulaAliasClosure = ArrayHelper.toStringArray( formulaAliases ); + subclassFormulaLazyClosure = ArrayHelper.toBooleanArray( formulasLazy ); + + subclassPropertyNameClosure = ArrayHelper.toStringArray( names ); + subclassPropertySubclassNameClosure = ArrayHelper.toStringArray( classes ); + subclassPropertyTypeClosure = ArrayHelper.toTypeArray( types ); + subclassPropertyNullabilityClosure = ArrayHelper.toBooleanArray( propNullables ); + subclassPropertyFormulaTemplateClosure = ArrayHelper.to2DStringArray( templates ); + subclassPropertyColumnNameClosure = ArrayHelper.to2DStringArray( propColumns ); + subclassPropertyColumnReaderClosure = ArrayHelper.to2DStringArray( propColumnReaders ); + subclassPropertyColumnReaderTemplateClosure = ArrayHelper.to2DStringArray( propColumnReaderTemplates ); + subclassPropertyColumnNumberClosure = ArrayHelper.to2DIntArray( propColumnNumbers ); + subclassPropertyFormulaNumberClosure = ArrayHelper.to2DIntArray( propFormulaNumbers ); + + subclassPropertyCascadeStyleClosure = cascades.toArray( new CascadeStyle[ cascades.size() ] ); + subclassPropertyFetchModeClosure = joinedFetchesList.toArray( new FetchMode[ joinedFetchesList.size() ] ); + + propertyDefinedOnSubclass = ArrayHelper.toBooleanArray( definedBySubclass ); + + Map filterDefaultConditionsByName = new HashMap(); + for ( FilterDefinition filterDefinition : entityBinding.getFilterDefinitions() ) { + filterDefaultConditionsByName.put( filterDefinition.getFilterName(), filterDefinition.getDefaultFilterCondition() ); + } + filterHelper = new FilterHelper( filterDefaultConditionsByName, factory.getDialect(), factory.getSqlFunctionRegistry() ); + temporaryIdTableName = null; temporaryIdTableDDL = null; - propertyMapping = null; + } + + protected static String getTemplateFromString(String string, SessionFactoryImplementor factory) { + return string == null ? + null : + Template.renderWhereStringTemplate( string, factory.getDialect(), factory.getSqlFunctionRegistry() ); + } + + public String getTemplateFromColumn(org.hibernate.metamodel.relational.Column column, SessionFactoryImplementor factory) { + String templateString; + if ( column.getReadFragment() != null ) { + templateString = getTemplateFromString( column.getReadFragment(), factory ); + } + else { + String columnName = column.getColumnName().encloseInQuotesIfQuoted( factory.getDialect() ); + templateString = Template.TEMPLATE + '.' + columnName; + } + return templateString; } protected String generateLazySelectString() { @@ -1824,6 +2002,73 @@ public abstract class AbstractEntityPersister } + /** + * Must be called by subclasses, at the end of their constructors + */ + protected void initSubclassPropertyAliasesMap(EntityBinding model) throws MappingException { + + // ALIASES + + // TODO: Fix when subclasses are working (HHH-6337) + //internalInitSubclassPropertyAliasesMap( null, model.getSubclassPropertyClosureIterator() ); + + // aliases for identifier ( alias.id ); skip if the entity defines a non-id property named 'id' + if ( ! entityMetamodel.hasNonIdentifierPropertyNamedId() ) { + subclassPropertyAliases.put( ENTITY_ID, getIdentifierAliases() ); + subclassPropertyColumnNames.put( ENTITY_ID, getIdentifierColumnNames() ); + } + + // aliases named identifier ( alias.idname ) + if ( hasIdentifierProperty() ) { + subclassPropertyAliases.put( getIdentifierPropertyName(), getIdentifierAliases() ); + subclassPropertyColumnNames.put( getIdentifierPropertyName(), getIdentifierColumnNames() ); + } + + // aliases for composite-id's + if ( getIdentifierType().isComponentType() ) { + // Fetch embedded identifiers propertynames from the "virtual" identifier component + CompositeType componentId = ( CompositeType ) getIdentifierType(); + String[] idPropertyNames = componentId.getPropertyNames(); + String[] idAliases = getIdentifierAliases(); + String[] idColumnNames = getIdentifierColumnNames(); + + for ( int i = 0; i < idPropertyNames.length; i++ ) { + if ( entityMetamodel.hasNonIdentifierPropertyNamedId() ) { + subclassPropertyAliases.put( + ENTITY_ID + "." + idPropertyNames[i], + new String[] { idAliases[i] } + ); + subclassPropertyColumnNames.put( + ENTITY_ID + "." + getIdentifierPropertyName() + "." + idPropertyNames[i], + new String[] { idColumnNames[i] } + ); + } +// if (hasIdentifierProperty() && !ENTITY_ID.equals( getIdentifierPropertyName() ) ) { + if ( hasIdentifierProperty() ) { + subclassPropertyAliases.put( + getIdentifierPropertyName() + "." + idPropertyNames[i], + new String[] { idAliases[i] } + ); + subclassPropertyColumnNames.put( + getIdentifierPropertyName() + "." + idPropertyNames[i], + new String[] { idColumnNames[i] } + ); + } + else { + // embedded composite ids ( alias.idname1, alias.idname2 ) + subclassPropertyAliases.put( idPropertyNames[i], new String[] { idAliases[i] } ); + subclassPropertyColumnNames.put( idPropertyNames[i], new String[] { idColumnNames[i] } ); + } + } + } + + if ( entityMetamodel.isPolymorphic() ) { + subclassPropertyAliases.put( ENTITY_CLASS, new String[] { getDiscriminatorAlias() } ); + subclassPropertyColumnNames.put( ENTITY_CLASS, new String[] { getDiscriminatorColumnName() } ); + } + + } + private void internalInitSubclassPropertyAliasesMap(String path, Iterator propertyIterator) { while ( propertyIterator.hasNext() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java index ff5de7580d..cc293e6c83 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java @@ -47,7 +47,12 @@ import org.hibernate.mapping.Selectable; import org.hibernate.mapping.Subclass; import org.hibernate.mapping.Table; import org.hibernate.mapping.Value; +import org.hibernate.metamodel.binding.AttributeBinding; +import org.hibernate.metamodel.binding.CustomSQL; import org.hibernate.metamodel.binding.EntityBinding; +import org.hibernate.metamodel.relational.DerivedValue; +import org.hibernate.metamodel.relational.SimpleValue; +import org.hibernate.metamodel.relational.TableSpecification; import org.hibernate.sql.InFragment; import org.hibernate.sql.Insert; import org.hibernate.sql.SelectFragment; @@ -120,6 +125,8 @@ public class SingleTableEntityPersister extends AbstractEntityPersister { private static final Object NULL_DISCRIMINATOR = new MarkerObject(""); private static final Object NOT_NULL_DISCRIMINATOR = new MarkerObject(""); + private static final String NULL_STRING = "null"; + private static final String NOT_NULL_STRING = "not null"; //INITIALIZATION: @@ -447,39 +454,262 @@ public class SingleTableEntityPersister extends AbstractEntityPersister { super( entityBinding, cacheAccessStrategy, factory ); - //TODO: implement!!!! initializing final fields to make compiler happy... - joinSpan = -1; - qualifiedTableNames = null; - isInverseTable = null; - isNullableTable = null; - keyColumnNames = null; - cascadeDeleteEnabled = null; - hasSequentialSelects = false; - spaces = null; - subclassClosure = null; - subclassTableNameClosure = null; - subclassTableIsLazyClosure = null; - isInverseSubclassTable = null; - isNullableSubclassTable = null; - subclassTableSequentialSelect = null; - subclassTableKeyColumnClosure = null; - isClassOrSuperclassTable = null; - propertyTableNumbers = null; - subclassPropertyTableNumberClosure = null; - subclassColumnTableNumberClosure = null; - subclassFormulaTableNumberClosure = null; - forceDiscriminator = false; - discriminatorColumnName = null; - discriminatorColumnReaders = null; - discriminatorColumnReaderTemplate = null; - discriminatorFormula = null; - discriminatorFormulaTemplate = null; - discriminatorAlias = null; - discriminatorType = null; - discriminatorSQLValue = null; - discriminatorInsertable = false; - constraintOrderedTableNames = null; - constraintOrderedKeyColumnNames = null; + // CLASS + TABLE + + // TODO: fix when joins are working (HHH-6391) + //joinSpan = entityBinding.getJoinClosureSpan() + 1; + joinSpan = 1; + qualifiedTableNames = new String[joinSpan]; + isInverseTable = new boolean[joinSpan]; + isNullableTable = new boolean[joinSpan]; + keyColumnNames = new String[joinSpan][]; + + // TODO: fix when EntityBinhding.getRootEntityBinding() exists (HHH-6337) + //final Table table = entityBinding.getRootEntityBinding().getBaseTable(); + final TableSpecification table = entityBinding.getBaseTable(); + qualifiedTableNames[0] = table.getQualifiedName( factory.getDialect() ); + isInverseTable[0] = false; + isNullableTable[0] = false; + keyColumnNames[0] = getIdentifierColumnNames(); + cascadeDeleteEnabled = new boolean[joinSpan]; + + // Custom sql + customSQLInsert = new String[joinSpan]; + customSQLUpdate = new String[joinSpan]; + customSQLDelete = new String[joinSpan]; + insertCallable = new boolean[joinSpan]; + updateCallable = new boolean[joinSpan]; + deleteCallable = new boolean[joinSpan]; + insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[joinSpan]; + updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[joinSpan]; + deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[joinSpan]; + + initializeCustomSql( entityBinding.getCustomInsert(), 0, customSQLInsert, insertCallable, insertResultCheckStyles ); + initializeCustomSql( entityBinding.getCustomUpdate(), 0, customSQLUpdate, updateCallable, updateResultCheckStyles ); + initializeCustomSql( entityBinding.getCustomDelete(), 0, customSQLDelete, deleteCallable, deleteResultCheckStyles ); + + // JOINS + + // TODO: add join stuff when HHH-6391 is working + + constraintOrderedTableNames = new String[qualifiedTableNames.length]; + constraintOrderedKeyColumnNames = new String[qualifiedTableNames.length][]; + for ( int i = qualifiedTableNames.length - 1, position = 0; i >= 0; i--, position++ ) { + constraintOrderedTableNames[position] = qualifiedTableNames[i]; + constraintOrderedKeyColumnNames[position] = keyColumnNames[i]; + } + + spaces = ArrayHelper.join( + qualifiedTableNames, + ArrayHelper.toStringArray( entityBinding.getSynchronizedTableNames() ) + ); + + final boolean lazyAvailable = isInstrumented(); + + boolean hasDeferred = false; + ArrayList subclassTables = new ArrayList(); + ArrayList joinKeyColumns = new ArrayList(); + ArrayList isConcretes = new ArrayList(); + ArrayList isDeferreds = new ArrayList(); + ArrayList isInverses = new ArrayList(); + ArrayList isNullables = new ArrayList(); + ArrayList isLazies = new ArrayList(); + subclassTables.add( qualifiedTableNames[0] ); + joinKeyColumns.add( getIdentifierColumnNames() ); + isConcretes.add(Boolean.TRUE); + isDeferreds.add(Boolean.FALSE); + isInverses.add(Boolean.FALSE); + isNullables.add(Boolean.FALSE); + isLazies.add(Boolean.FALSE); + + // TODO: add join stuff when HHH-6391 is working + + + subclassTableSequentialSelect = ArrayHelper.toBooleanArray(isDeferreds); + subclassTableNameClosure = ArrayHelper.toStringArray(subclassTables); + subclassTableIsLazyClosure = ArrayHelper.toBooleanArray(isLazies); + subclassTableKeyColumnClosure = ArrayHelper.to2DStringArray( joinKeyColumns ); + isClassOrSuperclassTable = ArrayHelper.toBooleanArray(isConcretes); + isInverseSubclassTable = ArrayHelper.toBooleanArray(isInverses); + isNullableSubclassTable = ArrayHelper.toBooleanArray(isNullables); + hasSequentialSelects = hasDeferred; + + // DISCRIMINATOR + + // TODO: fix this when can get subclass info from EntityBinding (HHH-6337) + // for now set hasSubclasses to false + //hasSubclasses = entityBinding.hasSubclasses(); + boolean hasSubclasses = false; + + //polymorphic = ! entityBinding.isRoot() || entityBinding.hasSubclasses(); + boolean isPolymorphic = ! entityBinding.isRoot() || hasSubclasses; + final Object discriminatorValue; + if ( isPolymorphic ) { + org.hibernate.metamodel.relational.Value discrimValue = + entityBinding.getEntityDiscriminator().getValueBinding().getValue(); + if (discrimValue==null) { + throw new MappingException("discriminator mapping required for single table polymorphic persistence"); + } + forceDiscriminator = entityBinding.getEntityDiscriminator().isForced(); + if ( ! SimpleValue.class.isInstance( discrimValue ) ) { + throw new MappingException( "discriminator must be mapped to a single column or formula." ); + } + if ( DerivedValue.class.isInstance( discrimValue ) ) { + DerivedValue formula = ( DerivedValue ) discrimValue; + discriminatorFormula = formula.getExpression(); + discriminatorFormulaTemplate = getTemplateFromString( formula.getExpression(), factory ); + discriminatorColumnName = null; + discriminatorColumnReaders = null; + discriminatorColumnReaderTemplate = null; + discriminatorAlias = "clazz_"; + } + else if ( org.hibernate.metamodel.relational.Column.class.isInstance( discrimValue ) ) { + org.hibernate.metamodel.relational.Column column = ( org.hibernate.metamodel.relational.Column ) discrimValue; + discriminatorColumnName = column.getColumnName().encloseInQuotesIfQuoted( factory.getDialect() ); + discriminatorColumnReaders = + column.getReadFragment() == null ? + column.getColumnName().encloseInQuotesIfQuoted( factory.getDialect() ) : + column.getReadFragment(); + discriminatorColumnReaderTemplate = getTemplateFromColumn( column, factory ); + // TODO: fix this when EntityBinding.getRootEntityBinding() is implemented; + // for now, assume entityBinding is the root + //discriminatorAlias = column.getAlias( factory.getDialect(), entityBinding.getRootEntityBinding().getBaseTable ); + discriminatorAlias = column.getAlias( factory.getDialect() ); + discriminatorFormula = null; + discriminatorFormulaTemplate = null; + } + else { + throw new MappingException( "Unknown discriminator value type:" + discrimValue.toLoggableString() ); + } + discriminatorType = + entityBinding + .getEntityDiscriminator() + .getValueBinding() + .getHibernateTypeDescriptor() + .getExplicitType(); + if ( entityBinding.getDiscriminatorValue() == null ) { + discriminatorValue = NULL_DISCRIMINATOR; + discriminatorSQLValue = InFragment.NULL; + discriminatorInsertable = false; + } + else if ( entityBinding.getDiscriminatorValue().equals( NULL_STRING ) ) { + discriminatorValue = NOT_NULL_DISCRIMINATOR; + discriminatorSQLValue = InFragment.NOT_NULL; + discriminatorInsertable = false; + } + else if ( entityBinding.getDiscriminatorValue().equals( NOT_NULL_STRING ) ) { + discriminatorValue = NOT_NULL_DISCRIMINATOR; + discriminatorSQLValue = InFragment.NOT_NULL; + discriminatorInsertable = false; + } + else { + discriminatorInsertable = + entityBinding.getEntityDiscriminator().isInserted() && + ! DerivedValue.class.isInstance( discrimValue ); + try { + DiscriminatorType dtype = ( DiscriminatorType ) discriminatorType; + discriminatorValue = dtype.stringToObject( entityBinding.getDiscriminatorValue() ); + discriminatorSQLValue = dtype.objectToSQLString( discriminatorValue, factory.getDialect() ); + } + catch (ClassCastException cce) { + throw new MappingException("Illegal discriminator type: " + discriminatorType.getName() ); + } + catch (Exception e) { + throw new MappingException("Could not format discriminator value to SQL string", e); + } + } + } + else { + forceDiscriminator = false; + discriminatorInsertable = false; + discriminatorColumnName = null; + discriminatorColumnReaders = null; + discriminatorColumnReaderTemplate = null; + discriminatorAlias = null; + discriminatorType = null; + discriminatorValue = null; + discriminatorSQLValue = null; + discriminatorFormula = null; + discriminatorFormulaTemplate = null; + } + + // PROPERTIES + + propertyTableNumbers = new int[ getPropertySpan() ]; + int i=0; + for( AttributeBinding attributeBinding : entityBinding.getAttributeBindingClosure() ) { + // TODO: fix when joins are working (HHH-6391) + //propertyTableNumbers[i++] = entityBinding.getJoinNumber( attributeBinding); + if ( attributeBinding == entityBinding.getEntityIdentifier().getValueBinding() ) { + continue; // skip identifier binding + } + propertyTableNumbers[ i++ ] = 0; + } + + //TODO: code duplication with JoinedSubclassEntityPersister + + ArrayList columnJoinNumbers = new ArrayList(); + ArrayList formulaJoinedNumbers = new ArrayList(); + ArrayList propertyJoinNumbers = new ArrayList(); + + // TODO: fix when subclasses are working (HHH-6337) + //for ( AttributeBinding prop : entityBinding.getSubclassAttributeBindingClosure() ) { + for ( AttributeBinding prop : entityBinding.getAttributeBindingClosure() ) { + // TODO: fix when joins are working (HHH-6391) + //int join = entityBinding.getJoinNumber(prop); + int join = 0; + propertyJoinNumbers.add(join); + + //propertyTableNumbersByName.put( prop.getName(), join ); + propertyTableNumbersByNameAndSubclass.put( + prop.getEntityBinding().getEntity().getName() + '.' + prop.getAttribute().getName(), + join + ); + + for ( SimpleValue simpleValue : prop.getValues() ) { + if ( DerivedValue.class.isInstance( simpleValue ) ) { + formulaJoinedNumbers.add( join ); + } + else { + columnJoinNumbers.add( join ); + } + } + } + subclassColumnTableNumberClosure = ArrayHelper.toIntArray(columnJoinNumbers); + subclassFormulaTableNumberClosure = ArrayHelper.toIntArray(formulaJoinedNumbers); + subclassPropertyTableNumberClosure = ArrayHelper.toIntArray(propertyJoinNumbers); + + // TODO; fix when subclasses are working (HHH-6337) + //int subclassSpan = entityBinding.getSubclassSpan() + 1; + int subclassSpan = 1; + subclassClosure = new String[subclassSpan]; + subclassClosure[0] = getEntityName(); + if ( isPolymorphic ) { + subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() ); + } + + // SUBCLASSES + + // TODO; fix when subclasses are working (HHH-6337) + + initLockers(); + + initSubclassPropertyAliasesMap( entityBinding ); + + postConstruct( mapping ); + } + + private static void initializeCustomSql( + CustomSQL customSql, + int i, + String[] sqlStrings, + boolean[] callable, + ExecuteUpdateResultCheckStyle[] checkStyles) { + sqlStrings[i] = customSql != null ? customSql.getSql(): null; + callable[i] = sqlStrings[i] != null && customSql.isCallable(); + checkStyles[i] = customSql != null && customSql.getCheckStyle() != null ? + customSql.getCheckStyle() : + ExecuteUpdateResultCheckStyle.determineDefault( sqlStrings[i], callable[i] ); } protected boolean isInverseTable(int j) {