Index: 3rdParty_sources/hibernate-core/org/hibernate/boot/registry/classloading/internal/ClassLoaderServiceImpl.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/boot/registry/classloading/internal/ClassLoaderServiceImpl.java (.../ClassLoaderServiceImpl.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/boot/registry/classloading/internal/ClassLoaderServiceImpl.java (.../ClassLoaderServiceImpl.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -387,7 +387,8 @@ boolean set = false; try { - Thread.currentThread().setContextClassLoader( aggregatedClassLoader ); + Thread.currentThread().setContextClassLoader( + new TcclSafeAggregatedClassLoader( aggregatedClassLoader, tccl ) ); set = true; } catch (Exception ignore) { @@ -403,5 +404,30 @@ } } + + // TODO: Remove in ORM 5! See HHH-8818 + private class TcclSafeAggregatedClassLoader extends ClassLoader { + private final AggregatedClassLoader aggregatedClassLoader; + + private TcclSafeAggregatedClassLoader(AggregatedClassLoader aggregatedClassLoader, ClassLoader tccl) { + super(tccl); + this.aggregatedClassLoader = aggregatedClassLoader; + } + + @Override + public Enumeration getResources(String name) throws IOException { + return aggregatedClassLoader.getResources( name ); + } + @Override + protected URL findResource(String name) { + return aggregatedClassLoader.findResource( name ); + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + return aggregatedClassLoader.findClass( name ); + } + } + } Index: 3rdParty_sources/hibernate-core/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java (.../StrategySelectorBuilder.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java (.../StrategySelectorBuilder.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -93,6 +93,10 @@ import org.hibernate.engine.transaction.jta.platform.internal.WeblogicJtaPlatform; import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; import org.hibernate.engine.transaction.spi.TransactionFactory; +import org.hibernate.event.internal.EntityCopyAllowedLoggedObserver; +import org.hibernate.event.internal.EntityCopyAllowedObserver; +import org.hibernate.event.internal.EntityCopyNotAllowedObserver; +import org.hibernate.event.spi.EntityCopyObserver; import org.hibernate.hql.spi.MultiTableBulkIdStrategy; import org.hibernate.hql.spi.PersistentTableBulkIdStrategy; import org.hibernate.hql.spi.TemporaryTableBulkIdStrategy; @@ -162,6 +166,7 @@ addJtaPlatforms( strategySelector ); addTransactionFactories( strategySelector ); addMultiTableBulkIdStrategies( strategySelector ); + addEntityCopyObserverStrategies( strategySelector ); // apply auto-discovered registrations for ( StrategyRegistrationProvider provider : classLoaderService.loadJavaServices( StrategyRegistrationProvider.class ) ) { @@ -372,4 +377,22 @@ TemporaryTableBulkIdStrategy.class ); } + + private void addEntityCopyObserverStrategies(StrategySelectorImpl strategySelector) { + strategySelector.registerStrategyImplementor( + EntityCopyObserver.class, + EntityCopyNotAllowedObserver.SHORT_NAME, + EntityCopyNotAllowedObserver.class + ); + strategySelector.registerStrategyImplementor( + EntityCopyObserver.class, + EntityCopyAllowedObserver.SHORT_NAME, + EntityCopyAllowedObserver.class + ); + strategySelector.registerStrategyImplementor( + EntityCopyObserver.class, + EntityCopyAllowedLoggedObserver.SHORT_NAME, + EntityCopyAllowedLoggedObserver.class + ); + } } Index: 3rdParty_sources/hibernate-core/org/hibernate/cache/spi/entry/ReferenceCacheEntryImpl.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/cache/spi/entry/ReferenceCacheEntryImpl.java (.../ReferenceCacheEntryImpl.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/cache/spi/entry/ReferenceCacheEntryImpl.java (.../ReferenceCacheEntryImpl.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -25,24 +25,27 @@ import java.io.Serializable; +import org.hibernate.persister.entity.EntityPersister; + /** * Specialized CacheEntry for storing direct references to entity instances. * * @author Steve Ebersole */ public class ReferenceCacheEntryImpl implements CacheEntry { private final Object reference; - private final String subclass; + // passing the persister avoids a costly persister lookup by class name at cache retrieval time + private final EntityPersister subclassPersister; /** * Constructs a ReferenceCacheEntryImpl * * @param reference The reference entity instance - * @param subclass The specific subclass + * @param subclassPersister The specific subclass persister */ - public ReferenceCacheEntryImpl(Object reference, String subclass) { + public ReferenceCacheEntryImpl(Object reference, EntityPersister subclassPersister) { this.reference = reference; - this.subclass = subclass; + this.subclassPersister = subclassPersister; } /** @@ -61,9 +64,13 @@ @Override public String getSubclass() { - return subclass; + return subclassPersister.getEntityName(); } + public EntityPersister getSubclassPersister() { + return subclassPersister; + } + @Override public Object getVersion() { // reference data cannot be versioned Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/AnnotationBinder.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/AnnotationBinder.java (.../AnnotationBinder.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/AnnotationBinder.java (.../AnnotationBinder.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -1392,6 +1392,9 @@ if ( AnnotatedClassType.EMBEDDABLE_SUPERCLASS.equals( classType ) ) { bindFilters( classToProcess, entityBinder ); } + else { + break; + } classToProcess = classToProcess.getSuperclass(); } Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/AnnotationConfiguration.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/AnnotationConfiguration.java (.../AnnotationConfiguration.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/AnnotationConfiguration.java (.../AnnotationConfiguration.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -31,6 +31,7 @@ import org.hibernate.HibernateException; import org.hibernate.Interceptor; import org.hibernate.MappingException; +import org.hibernate.cfg.naming.NamingStrategyDelegator; import org.dom4j.Document; @@ -239,6 +240,12 @@ return this; } + @Override + public AnnotationConfiguration setNamingStrategyDelegator(NamingStrategyDelegator namingStrategyDelegator) { + super.setNamingStrategyDelegator( namingStrategyDelegator ); + return this; + } + @Deprecated protected class ExtendedMappingsImpl extends MappingsImpl { } Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/Configuration.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/Configuration.java (.../Configuration.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/Configuration.java (.../Configuration.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -80,6 +80,8 @@ import org.hibernate.cfg.annotations.NamedEntityGraphDefinition; import org.hibernate.cfg.annotations.NamedProcedureCallDefinition; import org.hibernate.cfg.annotations.reflection.JPAMetadataProvider; +import org.hibernate.cfg.naming.LegacyNamingStrategyDelegator; +import org.hibernate.cfg.naming.NamingStrategyDelegator; import org.hibernate.context.spi.CurrentTenantIdentifierResolver; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.MySQLDialect; @@ -247,7 +249,7 @@ private EntityNotFoundDelegate entityNotFoundDelegate; protected transient XMLHelper xmlHelper; - protected NamingStrategy namingStrategy; + private NamingStrategyDelegator namingStrategyDelegator; private SessionFactoryObserver sessionFactoryObserver; protected final SettingsFactory settingsFactory; @@ -349,7 +351,7 @@ mappedByResolver = new HashMap(); propertyRefResolver = new HashMap(); caches = new ArrayList(); - namingStrategy = EJB3NamingStrategy.INSTANCE; + namingStrategyDelegator = LegacyNamingStrategyDelegator.DEFAULT_INSTANCE; setEntityResolver( new EJB3DTDEntityResolver() ); anyMetaDefs = new HashMap(); propertiesAnnotatedWithMapsId = new HashMap>(); @@ -2454,22 +2456,61 @@ } public NamingStrategy getNamingStrategy() { - return namingStrategy; + if ( LegacyNamingStrategyDelegator.class.isInstance( namingStrategyDelegator ) ) { + return ( (LegacyNamingStrategyDelegator) namingStrategyDelegator ).getNamingStrategy(); + } + return null; } + public NamingStrategyDelegator getNamingStrategyDelegator() { + return namingStrategyDelegator; + } + /** - * Set a custom naming strategy + * Set the current naming strategy. An instance of {@link org.hibernate.cfg.naming.LegacyNamingStrategyDelegator} + * will be constructed with the specified naming strategy. * - * @param namingStrategy the NamingStrategy to set + * @param namingStrategy the {@link NamingStrategy} to set; must be non-null. * - * @return this for method chaining + * @return this for method chaining. + * + * @see org.hibernate.cfg.naming.LegacyNamingStrategyDelegator#LegacyNamingStrategyDelegator(NamingStrategy) */ public Configuration setNamingStrategy(NamingStrategy namingStrategy) { - this.namingStrategy = namingStrategy; + if ( namingStrategy == null ) { + throw new MappingException( "namingStrategy must be non-null" ); + } + setNamingStrategyDelegator( new LegacyNamingStrategyDelegator( namingStrategy ) ); return this; } /** + * Set a current naming strategy delegator. + * + * @param namingStrategyDelegator the {@link org.hibernate.cfg.naming.NamingStrategyDelegator} to set; + * must be non-null; if {@code namingStrategyDelegator} is an instance + * of {@link LegacyNamingStrategyDelegator}, then + * {@link LegacyNamingStrategyDelegator#getNamingStrategy()} must be non-null. + * @return this for method chaining. + * + * @throws org.hibernate.MappingException if {@code namingStrategyDelegator} is null. + * @throws org.hibernate.MappingException if {@code namingStrategyDelegator} is an instance + * of {@link LegacyNamingStrategyDelegator} and {@link LegacyNamingStrategyDelegator#getNamingStrategy()} + * is null. + */ + public Configuration setNamingStrategyDelegator(NamingStrategyDelegator namingStrategyDelegator) { + if ( namingStrategyDelegator == null ) { + throw new MappingException( "namingStrategyDelegator and namingStrategyDelegator.getNamingStrategy() must be non-null" ); + } + if ( LegacyNamingStrategyDelegator.class.isInstance( namingStrategyDelegator ) && + LegacyNamingStrategyDelegator.class.cast( namingStrategyDelegator ).getNamingStrategy() == null ) { + throw new MappingException( "namingStrategyDelegator.getNamingStrategy() must be non-null." ); + } + this.namingStrategyDelegator = namingStrategyDelegator; + return this; + } + + /** * Retrieve the IdentifierGeneratorFactory in effect for this configuration. * * @return This configuration's IdentifierGeneratorFactory. @@ -2799,13 +2840,21 @@ public NamingStrategy getNamingStrategy() { - return namingStrategy; + return Configuration.this.getNamingStrategy(); } public void setNamingStrategy(NamingStrategy namingStrategy) { - Configuration.this.namingStrategy = namingStrategy; + Configuration.this.setNamingStrategy( namingStrategy ); } + public NamingStrategyDelegator getNamingStrategyDelegator() { + return Configuration.this.getNamingStrategyDelegator(); + } + + public void setNamingStrategyDelegator(NamingStrategyDelegator namingStrategyDelegator) { + Configuration.this.setNamingStrategyDelegator( namingStrategyDelegator ); + } + public TypeResolver getTypeResolver() { return typeResolver; } @@ -3628,8 +3677,16 @@ } public NamingStrategy getNamingStrategy() { - return namingStrategy; + if ( LegacyNamingStrategyDelegator.class.isInstance( namingStrategyDelegator ) ) { + ( (LegacyNamingStrategyDelegator) namingStrategyDelegator ).getNamingStrategy(); + } + return null; } + + @Override + protected NamingStrategyDelegator getNamingStrategyDelegator() { + return namingStrategyDelegator; + } } protected class MetadataSourceQueue implements Serializable { Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/Ejb3Column.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/Ejb3Column.java (.../Ejb3Column.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/Ejb3Column.java (.../Ejb3Column.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -33,6 +33,7 @@ import org.hibernate.annotations.Index; import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.cfg.annotations.Nullability; +import org.hibernate.cfg.naming.NamingStrategyDelegate; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; import org.hibernate.mapping.Column; @@ -292,15 +293,15 @@ if ( propertyName != null ) { mappingColumn.setName( mappings.getObjectNameNormalizer().normalizeIdentifierQuoting( - mappings.getNamingStrategy().propertyToColumnName( propertyName ) + getNamingStrategyDelegate().determineImplicitPropertyColumnName( propertyName ) ) ); } //Do nothing otherwise } else { columnName = mappings.getObjectNameNormalizer().normalizeIdentifierQuoting( columnName ); - columnName = mappings.getNamingStrategy().columnName( columnName ); + columnName = getNamingStrategyDelegate().toPhysicalColumnName( columnName ); columnName = mappings.getObjectNameNormalizer().normalizeIdentifierQuoting( columnName ); mappingColumn.setName( columnName ); } @@ -367,11 +368,19 @@ } protected void addColumnBinding(SimpleValue value) { - String logicalColumnName = mappings.getNamingStrategy() - .logicalColumnName( this.logicalColumnName, propertyName ); + String logicalColumnName = + getNamingStrategyDelegate().determineLogicalColumnName( this.logicalColumnName, propertyName ); mappings.addColumnBinding( logicalColumnName, getMappingColumn(), value.getTable() ); } + protected NamingStrategyDelegate getNamingStrategyDelegate() { + return getNamingStrategyDelegate( mappings ); + } + + protected static NamingStrategyDelegate getNamingStrategyDelegate(Mappings mappings) { + return mappings.getNamingStrategyDelegator().getNamingStrategyDelegate( false ); + } + /** * Find appropriate table of the column. * It can come from a secondary table or from the main table of the persistent class @@ -481,9 +490,12 @@ final String sqlType = col.columnDefinition().equals( "" ) ? null : nameNormalizer.normalizeIdentifierQuoting( col.columnDefinition() ); - final String tableName = ! StringHelper.isEmpty(col.table()) - ? nameNormalizer.normalizeIdentifierQuoting( mappings.getNamingStrategy().tableName( col.table() ) ) - : ""; + final String tableName = + ! StringHelper.isEmpty(col.table()) + ? nameNormalizer.normalizeIdentifierQuoting( getNamingStrategyDelegate( mappings ).toPhysicalTableName( + col.table() + ) ) + : ""; final String columnName = nameNormalizer.normalizeIdentifierQuoting( col.name() ); Ejb3Column column = new Ejb3Column(); Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/Ejb3JoinColumn.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/Ejb3JoinColumn.java (.../Ejb3JoinColumn.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/Ejb3JoinColumn.java (.../Ejb3JoinColumn.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -63,6 +63,7 @@ //table name on the mapped by side if any private String mappedByTableName; private String mappedByEntityName; + private String mappedByJpaEntityName; private boolean JPA2ElementCollection; public void setJPA2ElementCollection(boolean JPA2ElementCollection) { @@ -309,7 +310,10 @@ setReferencedColumn( annJoin.referencedColumnName() ); final String tableName = !BinderHelper.isEmptyAnnotationValue( annJoin.table() ) - ? nameNormalizer.normalizeIdentifierQuoting( getMappings().getNamingStrategy().tableName( annJoin.table() ) ) : ""; + ? nameNormalizer.normalizeIdentifierQuoting( getNamingStrategyDelegate().toPhysicalTableName( + annJoin.table() + ) ) + : ""; setExplicitTableName( tableName ); } } @@ -450,14 +454,24 @@ if ( mappedBySide ) { String unquotedMappedbyTable = StringHelper.unquote( mappedByTableName ); - final String ownerObjectName = JPA2ElementCollection && mappedByEntityName != null ? - StringHelper.unqualify( mappedByEntityName ) : unquotedMappedbyTable; - columnName = getMappings().getNamingStrategy().foreignKeyColumnName( - mappedByPropertyName, - mappedByEntityName, - ownerObjectName, - unquotedLogicalReferenceColumn - ); + if ( JPA2ElementCollection ) { + columnName = getNamingStrategyDelegate().determineImplicitElementCollectionJoinColumnName( + mappedByEntityName, + mappedByJpaEntityName, + unquotedMappedbyTable, + unquotedLogicalReferenceColumn, + mappedByPropertyName + ); + } + else { + columnName = getNamingStrategyDelegate().determineImplicitEntityAssociationJoinColumnName( + mappedByEntityName, + mappedByJpaEntityName, + unquotedMappedbyTable, + unquotedLogicalReferenceColumn, + mappedByPropertyName + ); + } //one element was quoted so we quote if ( isRefColumnQuoted || StringHelper.isQuoted( mappedByTableName ) ) { columnName = StringHelper.quote( columnName ); @@ -466,11 +480,12 @@ else if ( ownerSide ) { String logicalTableName = getMappings().getLogicalTableName( referencedEntity.getTable() ); String unquotedLogicalTableName = StringHelper.unquote( logicalTableName ); - columnName = getMappings().getNamingStrategy().foreignKeyColumnName( - getPropertyName(), + columnName = getNamingStrategyDelegate().determineImplicitEntityAssociationJoinColumnName( referencedEntity.getEntityName(), + referencedEntity.getJpaEntityName(), unquotedLogicalTableName, - unquotedLogicalReferenceColumn + unquotedLogicalReferenceColumn, + getPropertyName() ); //one element was quoted so we quote if ( isRefColumnQuoted || StringHelper.isQuoted( logicalTableName ) ) { @@ -481,7 +496,7 @@ //is an intra-entity hierarchy table join so copy the name by default String logicalTableName = getMappings().getLogicalTableName( referencedEntity.getTable() ); String unquotedLogicalTableName = StringHelper.unquote( logicalTableName ); - columnName = getMappings().getNamingStrategy().joinKeyColumnName( + columnName = getNamingStrategyDelegate().toPhysicalJoinKeyColumnName( unquotedLogicalReferenceColumn, unquotedLogicalTableName ); @@ -523,8 +538,11 @@ final String referencedColumn = nameNormalizer.normalizeIdentifierQuoting( getReferencedColumn() ); final String unquotedLogColName = StringHelper.unquote( logicalColumnName ); final String unquotedRefColumn = StringHelper.unquote( referencedColumn ); - String logicalCollectionColumnName = getMappings().getNamingStrategy() - .logicalCollectionColumnName( unquotedLogColName, getPropertyName(), unquotedRefColumn ); + String logicalCollectionColumnName = getNamingStrategyDelegate().determineLogicalCollectionColumnName( + unquotedLogColName, + getPropertyName(), + unquotedRefColumn + ); if ( isLogicalColumnQuoted ) { logicalCollectionColumnName = StringHelper.quote( logicalCollectionColumnName ); @@ -639,7 +657,7 @@ if ( StringHelper.isNotEmpty( columnName ) ) { getMappingColumn().setName( applyNamingStrategy ? - getMappings().getNamingStrategy().columnName( columnName ) : + getNamingStrategyDelegate().toPhysicalColumnName( columnName ) : columnName ); } @@ -694,8 +712,9 @@ return joinColumns; } - public void setMappedBy(String entityName, String logicalTableName, String mappedByProperty) { + public void setMappedBy(String entityName, String jpaEntityName, String logicalTableName, String mappedByProperty) { this.mappedByEntityName = entityName; + this.mappedByJpaEntityName = jpaEntityName; this.mappedByTableName = logicalTableName; this.mappedByPropertyName = mappedByProperty; } Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/HbmBinder.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/HbmBinder.java (.../HbmBinder.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/HbmBinder.java (.../HbmBinder.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -36,6 +36,7 @@ import org.hibernate.FlushMode; import org.hibernate.MappingException; import org.hibernate.engine.OptimisticLockStyle; +import org.hibernate.cfg.naming.NamingStrategyDelegate; import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.engine.spi.NamedQueryDefinition; @@ -888,16 +889,23 @@ String physicalTableName; if ( tableNameNode == null ) { logicalTableName = StringHelper.unqualify( model.getEntityName() ); - physicalTableName = mappings.getNamingStrategy().classToTableName( model.getEntityName() ); + physicalTableName = getNamingStrategyDelegate( mappings ).determineImplicitPrimaryTableName( + model.getEntityName(), + model.getJpaEntityName() + ); } else { logicalTableName = tableNameNode.getValue(); - physicalTableName = mappings.getNamingStrategy().tableName( logicalTableName ); + physicalTableName = getNamingStrategyDelegate( mappings ).toPhysicalTableName( logicalTableName ); } mappings.addTableBinding( schema, catalog, logicalTableName, physicalTableName, denormalizedSuperTable ); return physicalTableName; } + private static NamingStrategyDelegate getNamingStrategyDelegate(Mappings mappings) { + return mappings.getNamingStrategyDelegator().getNamingStrategyDelegate( true ); + } + public static void bindJoinedSubclass(Element node, JoinedSubclass joinedSubclass, Mappings mappings, java.util.Map inheritedMetas) throws MappingException { @@ -1073,10 +1081,10 @@ column.setTypeIndex( count++ ); bindColumn( columnElement, column, isNullable ); String columnName = columnElement.attributeValue( "name" ); - String logicalColumnName = mappings.getNamingStrategy().logicalColumnName( + String logicalColumnName = getNamingStrategyDelegate( mappings ).determineLogicalColumnName( columnName, propertyPath ); - columnName = mappings.getNamingStrategy().columnName( columnName ); + columnName = getNamingStrategyDelegate( mappings ).toPhysicalColumnName( columnName ); columnName = quoteIdentifier( columnName, mappings ); column.setName( columnName ); if ( table != null ) { @@ -1129,10 +1137,10 @@ ( (ManyToOne) simpleValue ).markAsLogicalOneToOne(); } String columnName = columnAttribute.getValue(); - String logicalColumnName = mappings.getNamingStrategy().logicalColumnName( + String logicalColumnName = getNamingStrategyDelegate( mappings ).determineLogicalColumnName( columnName, propertyPath ); - columnName = mappings.getNamingStrategy().columnName( columnName ); + columnName = getNamingStrategyDelegate( mappings ).toPhysicalColumnName( columnName ); columnName = quoteIdentifier( columnName, mappings ); column.setName( columnName ); if ( table != null ) { @@ -1150,10 +1158,10 @@ Column column = new Column(); column.setValue( simpleValue ); bindColumn( node, column, isNullable ); - String columnName = mappings.getNamingStrategy().propertyToColumnName( propertyPath ); + String columnName = getNamingStrategyDelegate( mappings ).determineImplicitPropertyColumnName( propertyPath ); columnName = quoteIdentifier( columnName, mappings ); column.setName( columnName ); - String logicalName = mappings.getNamingStrategy().logicalColumnName( null, propertyPath ); + String logicalName = getNamingStrategyDelegate( mappings ).determineLogicalColumnName( null, propertyPath ); mappings.addColumnBinding( logicalName, column, table ); /* TODO: joinKeyColumnName & foreignKeyColumnName should be called either here or at a * slightly higer level in the stack (to get all the information we need) @@ -1482,21 +1490,33 @@ Attribute tableNode = node.attribute( "table" ); String tableName; if ( tableNode != null ) { - tableName = mappings.getNamingStrategy().tableName( tableNode.getValue() ); + tableName = getNamingStrategyDelegate( mappings ).toPhysicalTableName( tableNode.getValue() ); } else { //tableName = mappings.getNamingStrategy().propertyToTableName( className, path ); Table ownerTable = collection.getOwner().getTable(); //TODO mappings.getLogicalTableName(ownerTable) String logicalOwnerTableName = ownerTable.getName(); //FIXME we don't have the associated entity table name here, has to be done in a second pass - tableName = mappings.getNamingStrategy().collectionTableName( - collection.getOwner().getEntityName(), - logicalOwnerTableName , - null, - null, - path - ); + if ( node.element( "element" ) != null || node.element( "composite-element" ) != null ) { + tableName = getNamingStrategyDelegate( mappings ).determineImplicitElementCollectionTableName( + collection.getOwner().getClassName(), + collection.getOwner().getJpaEntityName(), + logicalOwnerTableName, + path + ); + } + else { + tableName = getNamingStrategyDelegate( mappings ).determineImplicitEntityAssociationJoinTableName( + collection.getOwner().getClassName(), + collection.getOwner().getJpaEntityName(), + logicalOwnerTableName, + null, + null, + null, + path + ); + } if ( ownerTable.isQuoted() ) { tableName = StringHelper.quote( tableName ); } Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/Mappings.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/Mappings.java (.../Mappings.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/Mappings.java (.../Mappings.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -38,6 +38,7 @@ import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.cfg.annotations.NamedEntityGraphDefinition; import org.hibernate.cfg.annotations.NamedProcedureCallDefinition; +import org.hibernate.cfg.naming.NamingStrategyDelegator; import org.hibernate.engine.ResultSetMappingDefinition; import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.engine.spi.NamedQueryDefinition; @@ -81,17 +82,44 @@ * Get the current naming strategy. * * @return The current naming strategy. + * + * @deprecated Use {@link #getNamingStrategyDelegator()} instead. */ + @Deprecated public NamingStrategy getNamingStrategy(); /** - * Set the current naming strategy. + * Set the current naming strategy. An instance of {@link org.hibernate.cfg.naming.LegacyNamingStrategyDelegator} + * will be constructed with the specified naming strategy. * - * @param namingStrategy The naming strategy to use. + * @param namingStrategy the {@link NamingStrategy} to set; must be non-null. + * + * @deprecated Use {@link #setNamingStrategyDelegator(org.hibernate.cfg.naming.NamingStrategyDelegator)} instead. + + * @see org.hibernate.cfg.naming.LegacyNamingStrategyDelegator#LegacyNamingStrategyDelegator(NamingStrategy) */ + @Deprecated public void setNamingStrategy(NamingStrategy namingStrategy); /** + * Get the current naming strategy delegate. + * + * @return The current naming strategy delegate. + */ + public NamingStrategyDelegator getNamingStrategyDelegator(); + + /** + * Set a current naming strategy delegator. + * + * @param namingStrategyDelegator the {@link org.hibernate.cfg.naming.NamingStrategyDelegator} to set; + * must be non-null; if {@code namingStrategyDelegator} is an instance + * of {@link org.hibernate.cfg.naming.LegacyNamingStrategyDelegator}, then + * {@link org.hibernate.cfg.naming.LegacyNamingStrategyDelegator#getNamingStrategy()} + * must be non-null. + */ + public void setNamingStrategyDelegator(NamingStrategyDelegator namingStrategyDelegator); + + /** * Returns the currently bound default schema name. * * @return The currently bound schema name Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/NamingStrategy.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/NamingStrategy.java (.../NamingStrategy.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/NamingStrategy.java (.../NamingStrategy.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -37,7 +37,10 @@ * @see ImprovedNamingStrategy * @author Gavin King * @author Emmanuel Bernard + * + * @deprecated A {@link org.hibernate.cfg.naming.NamingStrategyDelegator} should be used instead. */ +@Deprecated public interface NamingStrategy { /** * Return a table name for an entity class Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/ObjectNameNormalizer.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/ObjectNameNormalizer.java (.../ObjectNameNormalizer.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/ObjectNameNormalizer.java (.../ObjectNameNormalizer.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -23,6 +23,7 @@ */ package org.hibernate.cfg; +import org.hibernate.cfg.naming.NamingStrategyDelegator; import org.hibernate.internal.util.StringHelper; /** @@ -42,7 +43,10 @@ * @param strategy The naming strategy in effect * * @return The implicit name + * + * * @deprecated Replaced by {@link #determineImplicitName(org.hibernate.cfg.naming.NamingStrategyDelegator)}. */ + @Deprecated public String determineImplicitName(NamingStrategy strategy); /** @@ -52,8 +56,30 @@ * @param name The {@link ObjectNameNormalizer#normalizeIdentifierQuoting normalized} explicit object name. * * @return The strategy-handled name. + * + * @deprecated Replaced by {@link #determineImplicitName(org.hibernate.cfg.naming.NamingStrategyDelegator)}. */ + @Deprecated public String handleExplicitName(NamingStrategy strategy, String name); + + /** + * Called when the user supplied no explicit name/identifier for the given database object. + * + * @param strategyDelegator The naming strategy delegator in effect + * + * @return The implicit name + */ + public String determineImplicitName(NamingStrategyDelegator strategyDelegator); + + /** + * Called when the user has supplied an explicit name for the database object. + * + * @param strategyDelegator The naming strategy delegator in effect + * @param name The {@link ObjectNameNormalizer#normalizeIdentifierQuoting normalized} explicit object name. + * + * @return The strategy-handled name. + */ + public String handleExplicitName(NamingStrategyDelegator strategyDelegator, String name); } /** @@ -70,14 +96,14 @@ if ( StringHelper.isEmpty( explicitName ) ) { // No explicit name given, so allow the naming strategy the chance // to determine it based on the corresponding mapped java name - objectName = helper.determineImplicitName( getNamingStrategy() ); + objectName = helper.determineImplicitName( getNamingStrategyDelegator() ); } else { // An explicit name was given: // in some cases we allow the naming strategy to "fine tune" these, but first // handle any quoting for consistent handling in naming strategies objectName = normalizeIdentifierQuoting( explicitName ); - objectName = helper.handleExplicitName( getNamingStrategy(), objectName ); + objectName = helper.handleExplicitName( getNamingStrategyDelegator(), objectName ); return normalizeIdentifierQuoting( objectName ); } // Conceivable that the naming strategy could return a quoted identifier, or @@ -134,6 +160,16 @@ * Get the current {@link NamingStrategy}. * * @return The current {@link NamingStrategy}. + * + * @deprecated Replaced by {@link #getNamingStrategyDelegator()} */ + @Deprecated protected abstract NamingStrategy getNamingStrategy(); + + /** + * Get the current {@link org.hibernate.cfg.naming.NamingStrategyDelegator}. + * + * @return The current {@link org.hibernate.cfg.naming.NamingStrategyDelegator}. + */ + protected abstract NamingStrategyDelegator getNamingStrategyDelegator(); } Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/annotations/CollectionBinder.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/annotations/CollectionBinder.java (.../CollectionBinder.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/annotations/CollectionBinder.java (.../CollectionBinder.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -1205,7 +1205,9 @@ ); Table ownerTable = collValue.getOwner().getTable(); column.setMappedBy( - collValue.getOwner().getEntityName(), mappings.getLogicalTableName( ownerTable ), + collValue.getOwner().getEntityName(), + collValue.getOwner().getJpaEntityName(), + mappings.getLogicalTableName( ownerTable ), mappedByProperty ); // String header = ( mappedByProperty == null ) ? mappings.getLogicalTableName( ownerTable ) : mappedByProperty; @@ -1215,8 +1217,10 @@ //default value associationTableBinder.setDefaultName( collValue.getOwner().getEntityName(), + collValue.getOwner().getJpaEntityName(), mappings.getLogicalTableName( collValue.getOwner().getTable() ), collectionEntity != null ? collectionEntity.getEntityName() : null, + collectionEntity != null ? collectionEntity.getJpaEntityName() : null, collectionEntity != null ? mappings.getLogicalTableName( collectionEntity.getTable() ) : null, joinColumns[0].getPropertyName() ); Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/annotations/EntityBinder.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/annotations/EntityBinder.java (.../EntityBinder.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/annotations/EntityBinder.java (.../EntityBinder.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -83,6 +83,8 @@ import org.hibernate.cfg.PropertyHolder; import org.hibernate.cfg.UniqueConstraintHolder; import org.hibernate.engine.OptimisticLockStyle; +import org.hibernate.cfg.naming.NamingStrategyDelegate; +import org.hibernate.cfg.naming.NamingStrategyDelegator; import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.internal.CoreMessageLogger; @@ -542,20 +544,41 @@ private static class EntityTableNamingStrategyHelper implements ObjectNameNormalizer.NamingStrategyHelper { private final String entityName; + private final String jpaEntityName; - private EntityTableNamingStrategyHelper(String entityName) { + private EntityTableNamingStrategyHelper(String entityName, String jpaEntityName) { this.entityName = entityName; + this.jpaEntityName = jpaEntityName; } + @Override public String determineImplicitName(NamingStrategy strategy) { return strategy.classToTableName( entityName ); } + @Override public String handleExplicitName(NamingStrategy strategy, String name) { return strategy.tableName( name ); } + + @Override + public String determineImplicitName(NamingStrategyDelegator strategyDelegator) { + return getNamingStrategyDelegate( strategyDelegator ).determineImplicitPrimaryTableName( + entityName, + jpaEntityName + ); + } + + @Override + public String handleExplicitName(NamingStrategyDelegator strategyDelegator, String name) { + return getNamingStrategyDelegate( strategyDelegator ).toPhysicalTableName( name ); + } } + private static NamingStrategyDelegate getNamingStrategyDelegate(NamingStrategyDelegator strategyDelegator) { + return strategyDelegator.getNamingStrategyDelegate( false ); + } + public void bindTable( String schema, String catalog, @@ -564,7 +587,10 @@ String constraints, Table denormalizedSuperclassTable) { EntityTableObjectNameSource tableNameContext = new EntityTableObjectNameSource( tableName, name ); - EntityTableNamingStrategyHelper namingStrategyHelper = new EntityTableNamingStrategyHelper( name ); + EntityTableNamingStrategyHelper namingStrategyHelper = new EntityTableNamingStrategyHelper( + persistentClass.getEntityName(), + name + ); final Table table = TableBinder.buildAndFillTable( schema, catalog, @@ -758,6 +784,17 @@ public String handleExplicitName(NamingStrategy strategy, String name) { return strategy.tableName( name ); } + + @Override + public String determineImplicitName(NamingStrategyDelegator strategyDelegator) { + // todo : throw an error? + return null; + } + + @Override + public String handleExplicitName(NamingStrategyDelegator strategyDelegator, String name) { + return getNamingStrategyDelegate( strategyDelegator ).toPhysicalTableName( name ); + } } private static SecondaryTableNamingStrategyHelper SEC_TBL_NS_HELPER = new SecondaryTableNamingStrategyHelper(); Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/annotations/ResultsetMappingSecondPass.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/annotations/ResultsetMappingSecondPass.java (.../ResultsetMappingSecondPass.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/annotations/ResultsetMappingSecondPass.java (.../ResultsetMappingSecondPass.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -30,6 +30,7 @@ import java.util.List; import java.util.Map; import java.util.Set; + import javax.persistence.ColumnResult; import javax.persistence.ConstructorResult; import javax.persistence.EntityResult; @@ -52,7 +53,6 @@ import org.hibernate.mapping.Property; import org.hibernate.mapping.ToOne; import org.hibernate.mapping.Value; - import org.jboss.logging.Logger; /** @@ -62,16 +62,17 @@ private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, ResultsetMappingSecondPass.class.getName()); - private SqlResultSetMapping ann; - private Mappings mappings; - private boolean isDefault; + private final SqlResultSetMapping ann; + private final Mappings mappings; + private final boolean isDefault; public ResultsetMappingSecondPass(SqlResultSetMapping ann, Mappings mappings, boolean isDefault) { this.ann = ann; this.mappings = mappings; this.isDefault = isDefault; } + @Override public void doSecondPass(Map persistentClasses) throws MappingException { //TODO add parameters checkings if ( ann == null ) return; @@ -188,7 +189,7 @@ mappings.getObjectNameNormalizer().normalizeIdentifierQuoting( column.name() ), - null + column.type() != null ? mappings.getTypeResolver().heuristicType( column.type().getName() ) : null ) ); } @@ -199,7 +200,7 @@ columnReturns.add( new NativeSQLQueryScalarReturn( mappings.getObjectNameNormalizer().normalizeIdentifierQuoting( columnResult.name() ), - null + columnResult.type() != null ? mappings.getTypeResolver().heuristicType( columnResult.type().getName() ) : null ) ); } Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/annotations/TableBinder.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/annotations/TableBinder.java (.../TableBinder.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/annotations/TableBinder.java (.../TableBinder.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -40,6 +40,8 @@ import org.hibernate.cfg.ObjectNameNormalizer; import org.hibernate.cfg.ObjectNameSource; import org.hibernate.cfg.UniqueConstraintHolder; +import org.hibernate.cfg.naming.NamingStrategyDelegate; +import org.hibernate.cfg.naming.NamingStrategyDelegator; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; @@ -79,7 +81,9 @@ private String associatedEntityTable; private String propertyName; private String ownerEntity; + private String ownerJpaEntity; private String associatedEntity; + private String associatedJpaEntity; private boolean isJPA2ElementCollection; private List jpaIndexHolders; @@ -152,33 +156,56 @@ final String unquotedAssocTable = StringHelper.unquote( associatedEntityTable ); //@ElementCollection use ownerEntity_property instead of the cleaner ownerTableName_property - // ownerEntity can be null when the table name is explicitly set + // ownerEntity can be null when the table name is explicitly set; <== gb: doesn't seem to be true... final String ownerObjectName = isJPA2ElementCollection && ownerEntity != null ? StringHelper.unqualify( ownerEntity ) : unquotedOwnerTable; final ObjectNameSource nameSource = buildNameContext( ownerObjectName, - unquotedAssocTable ); + unquotedAssocTable + ); final boolean ownerEntityTableQuoted = StringHelper.isQuoted( ownerEntityTable ); final boolean associatedEntityTableQuoted = StringHelper.isQuoted( associatedEntityTable ); final ObjectNameNormalizer.NamingStrategyHelper namingStrategyHelper = new ObjectNameNormalizer.NamingStrategyHelper() { public String determineImplicitName(NamingStrategy strategy) { + throw new AssertionFailure( "method call should have been replaced by #determineImplicitName(NamingStrategyDelegate strategyDelegate)" ); + } - final String strategyResult = strategy.collectionTableName( - ownerEntity, - ownerObjectName, - associatedEntity, - unquotedAssocTable, - propertyName + public String handleExplicitName(NamingStrategy strategy, String name) { + return strategy.tableName( name ); + } - ); + @Override + public String determineImplicitName(NamingStrategyDelegator strategyDelegator) { + final NamingStrategyDelegate strategyDelegate = getNamingStrategyDelegate( strategyDelegator ); + final String strategyResult; + if ( isJPA2ElementCollection ) { + strategyResult = strategyDelegate.determineImplicitElementCollectionTableName( + ownerEntity, + ownerJpaEntity, + unquotedOwnerTable, + propertyName + ); + } + else { + strategyResult = strategyDelegate.determineImplicitEntityAssociationJoinTableName( + ownerEntity, + ownerJpaEntity, + unquotedOwnerTable, + associatedEntity, + associatedJpaEntity, + unquotedAssocTable, + propertyName + ); + } return ownerEntityTableQuoted || associatedEntityTableQuoted ? StringHelper.quote( strategyResult ) : strategyResult; } - public String handleExplicitName(NamingStrategy strategy, String name) { - return strategy.tableName( name ); + @Override + public String handleExplicitName(NamingStrategyDelegator strategyDelegator, String name) { + return getNamingStrategyDelegate( strategyDelegator ).toPhysicalTableName( name ); } }; @@ -197,21 +224,46 @@ ); } - - private ObjectNameSource buildNameContext(String unquotedOwnerTable, String unquotedAssocTable) { - String logicalName = mappings.getNamingStrategy().logicalCollectionTableName( - name, - unquotedOwnerTable, - unquotedAssocTable, - propertyName + private ObjectNameSource buildNameContext( + String unquotedOwnerTable, + String unquotedAssocTable) { + final NamingStrategyDelegate strategyDelegate = getNamingStrategyDelegate( + mappings.getNamingStrategyDelegator() ); + String logicalName; + if ( isJPA2ElementCollection ) { + logicalName = strategyDelegate.determineLogicalElementCollectionTableName( + name, + ownerEntity, + ownerJpaEntity, + unquotedOwnerTable, + propertyName + ); + } + else { + logicalName = strategyDelegate.determineLogicalEntityAssociationJoinTableName( + name, + ownerEntity, + ownerJpaEntity, + unquotedOwnerTable, + associatedEntity, + associatedJpaEntity, + unquotedAssocTable, + propertyName + ); + } if ( StringHelper.isQuoted( ownerEntityTable ) || StringHelper.isQuoted( associatedEntityTable ) ) { logicalName = StringHelper.quote( logicalName ); } return new AssociationTableNameSource( name, logicalName ); } + private NamingStrategyDelegate getNamingStrategyDelegate( + NamingStrategyDelegator strategyDelegator) { + return strategyDelegator.getNamingStrategyDelegate( false ); + } + public static Table buildAndFillTable( String schema, String catalog, @@ -598,12 +650,19 @@ } public void setDefaultName( - String ownerEntity, String ownerEntityTable, String associatedEntity, String associatedEntityTable, + String ownerEntity, + String ownerJpaEntity, + String ownerEntityTable, + String associatedEntity, + String associatedJpaEntity, + String associatedEntityTable, String propertyName ) { this.ownerEntity = ownerEntity; + this.ownerJpaEntity = ownerJpaEntity; this.ownerEntityTable = ownerEntityTable; this.associatedEntity = associatedEntity; + this.associatedJpaEntity = associatedJpaEntity; this.associatedEntityTable = associatedEntityTable; this.propertyName = propertyName; this.name = null; Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/HbmNamingStrategyDelegate.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/HbmNamingStrategyDelegate.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/HbmNamingStrategyDelegate.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,119 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat, Inc. and/or its affiliates or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat, Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.cfg.naming; + +import org.hibernate.internal.util.StringHelper; + +/** + * @author Gail Badner + */ +public class HbmNamingStrategyDelegate extends NamingStrategyDelegateAdapter { + + @Override + public String determineImplicitPrimaryTableName(String entityName, String jpaEntityName) { + return StringHelper.unqualify( entityName ); + } + + @Override + public String determineImplicitElementCollectionTableName( + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String propertyPath) { + return ownerEntityTable + + '_' + + StringHelper.unqualify( propertyPath ); + } + + @Override + public String determineImplicitElementCollectionJoinColumnName(String ownerEntityName, String ownerJpaEntityName, String ownerEntityTable, String referencedColumnName, String propertyPath) { + throw new UnsupportedOperationException( "Method not supported for Hibernate-specific mappings" ); + } + + @Override + public String determineImplicitEntityAssociationJoinTableName( + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String associatedEntityName, + String associatedJpaEntityName, + String associatedEntityTable, + String propertyPath) { + return ownerEntityTable + + '_' + + StringHelper.unqualify( propertyPath ); + } + + @Override + public String determineImplicitEntityAssociationJoinColumnName( + String propertyEntityName, String propertyJpaEntityName, String propertyTableName, String referencedColumnName, String propertyPath) { + throw new UnsupportedOperationException( "Method not supported for Hibernate-specific mappings" ); + } + + @Override + public String determineLogicalElementCollectionTableName( + String tableName, + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String propertyName) { + if ( tableName != null ) { + return tableName; + } + else { + return determineImplicitElementCollectionTableName( + ownerEntityName, + ownerJpaEntityName, + ownerEntityTable, + propertyName + ); + } + } + + @Override + public String determineLogicalEntityAssociationJoinTableName( + String tableName, + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String associatedEntityName, + String associatedJpaEntityName, + String associatedEntityTable, + String propertyName) { + if ( tableName != null ) { + return tableName; + } + else { + return determineImplicitEntityAssociationJoinTableName( + ownerEntityName, + ownerJpaEntityName, + ownerEntityTable, + associatedEntityName, + associatedJpaEntityName, + associatedEntityTable, + propertyName + ); + } + } +} Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/ImprovedNamingStrategyDelegator.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/ImprovedNamingStrategyDelegator.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/ImprovedNamingStrategyDelegator.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,57 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat, Inc. and/or its affiliates or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat, Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.cfg.naming; + +import java.io.Serializable; + +/** + * @author Gail Badner + */ +public class ImprovedNamingStrategyDelegator implements NamingStrategyDelegator, Serializable { + public static final NamingStrategyDelegator DEFAULT_INSTANCE = new ImprovedNamingStrategyDelegator(); + + private final NamingStrategyDelegate hbmNamingStrategyDelegate; + private final NamingStrategyDelegate jpaNamingStrategyDelegate; + + public ImprovedNamingStrategyDelegator() { + this( + new HbmNamingStrategyDelegate(), + new JpaNamingStrategyDelegate() + ); + } + + protected ImprovedNamingStrategyDelegator( + NamingStrategyDelegate hbmNamingStrategyDelegate, + NamingStrategyDelegate jpaNamingStrategyDelegate) { + this.hbmNamingStrategyDelegate = hbmNamingStrategyDelegate; + this.jpaNamingStrategyDelegate = jpaNamingStrategyDelegate; + } + + @Override + public NamingStrategyDelegate getNamingStrategyDelegate(boolean isHbm) { + return isHbm ? + hbmNamingStrategyDelegate : + jpaNamingStrategyDelegate; + } +} Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/JpaNamingStrategyDelegate.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/JpaNamingStrategyDelegate.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/JpaNamingStrategyDelegate.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,175 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat, Inc. and/or its affiliates or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat, Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.cfg.naming; + +import org.hibernate.AssertionFailure; +import org.hibernate.internal.util.StringHelper; + +/** + * @author Gail Badner + */ +public class JpaNamingStrategyDelegate extends NamingStrategyDelegateAdapter { + + @Override + public String determineImplicitPrimaryTableName(String entityName, String jpaEntityName) { + return StringHelper.unqualify( determineEntityNameToUse( entityName, jpaEntityName ) ); + } + + @Override + public String determineImplicitElementCollectionTableName( + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String propertyPath) { + // JPA states we should use the following as default: + // "The concatenation of the name of the containing entity and the name of the + // collection attribute, separated by an underscore. + // aka: + // if owning entity has a JPA entity name: {OWNER JPA ENTITY NAME}_{COLLECTION ATTRIBUTE NAME} + // otherwise: {OWNER ENTITY NAME}_{COLLECTION ATTRIBUTE NAME} + return determineEntityNameToUse( ownerEntityName, ownerJpaEntityName ) + + '_' + + StringHelper.unqualify( propertyPath ); + } + + @Override + public String determineImplicitElementCollectionJoinColumnName( + String ownerEntityName, String ownerJpaEntityName, String ownerEntityTable, String referencedColumnName, String propertyPath) { + // JPA states we should use the following as default: + // "The concatenation of the following: the name of the entity; "_"; the name of the + // referenced primary key column" + return determineEntityNameToUse( ownerEntityName, ownerJpaEntityName ) + + '_' + + referencedColumnName; + } + + @Override + public String determineImplicitEntityAssociationJoinTableName( + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String associatedEntityName, + String associatedJpaEntityName, + String associatedEntityTable, + String propertyPath) { + // JPA states we should use the following as default: + // "The concatenated names of the two associated primary entity tables (owning side + // first), separated by an underscore." + // aka: + // {OWNING SIDE PRIMARY TABLE NAME}_{NON-OWNING SIDE PRIMARY TABLE NAME} + + return ownerEntityTable + + '_' + + associatedEntityTable; + } + + @Override + public String determineImplicitEntityAssociationJoinColumnName( + String propertyEntityName, String propertyJpaEntityName, String propertyTableName, String referencedColumnName, String referencingPropertyName) { + // JPA states we should use the following as default: + // "The concatenation of the following: the name of the referencing relationship + // property or field of the referencing entity or embeddable class; "_"; the name + // of the referenced primary key column. If there is no such referencing relationship + // property or field in the entity, or if the join is for an element collection, the + // join column name is formed as the concatenation of the following: the name of the + // entity; "_"; the name of the referenced primary key column + // The part referring to an entity collection can be disregarded here since, determination of + // an element collection foreign key column name is covered by #entityAssociationJoinTableName(). + // + // For a unidirectional association: + // {PROPERTY_ENTITY_NAME}_{REFERENCED_COLUMN_NAME} + // For a bidirectional association: + // {REFERENCING_PROPERTY_NAME}_{REFERENCED_COLUMN_NAME} + final String header; + if ( referencingPropertyName == null ) { + // This is a unidirectional association. + header = determineEntityNameToUse( propertyEntityName, propertyJpaEntityName ); + } + else { + // This is a bidirectional association. + header = StringHelper.unqualify( referencingPropertyName ); + } + if ( header == null ) { + throw new AssertionFailure( "propertyJpaEntityName and referencingPropertyName cannot both be empty." ); + } + return toPhysicalColumnName( header + "_" + referencedColumnName ); + } + + @Override + public String determineLogicalElementCollectionTableName( + String tableName, + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String propertyName) { + if ( tableName != null ) { + return tableName; + } + else { + return determineImplicitElementCollectionTableName( + ownerEntityName, + ownerJpaEntityName, + ownerEntityTable, + propertyName + ); + } + } + + @Override + public String determineLogicalEntityAssociationJoinTableName( + String tableName, + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String associatedEntityName, + String associatedJpaEntityName, + String associatedEntityTable, + String propertyName) { + if ( tableName != null ) { + return tableName; + } + else { + return determineImplicitEntityAssociationJoinTableName( + ownerEntityName, + ownerJpaEntityName, + ownerEntityTable, + associatedEntityName, + associatedJpaEntityName, + associatedEntityTable, + propertyName + ); + } + } + + private String determineEntityNameToUse(String entityName, String jpaEntityName) { + if ( StringHelper.isNotEmpty( jpaEntityName ) ) { + // prefer the JPA entity name, if specified... + return jpaEntityName; + } + else { + // otherwise, use the Hibernate entity name + return StringHelper.unqualifyEntityName( entityName ); + } + } +} Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/LegacyHbmNamingStrategyDelegate.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/LegacyHbmNamingStrategyDelegate.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/LegacyHbmNamingStrategyDelegate.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,128 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat, Inc. and/or its affiliates or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat, Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.cfg.naming; + +/** + * @author Gail Badner + */ +@Deprecated +public class LegacyHbmNamingStrategyDelegate extends LegacyNamingStrategyDelegateAdapter { + + public LegacyHbmNamingStrategyDelegate(LegacyNamingStrategyDelegate.LegacyNamingStrategyDelegateContext context) { + super( context ); + } + + @Override + public String determineImplicitPrimaryTableName(String entityName, String jpaEntityName) { + return getNamingStrategy().classToTableName( entityName ); + } + + @Override + public String determineImplicitElementCollectionTableName( + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String propertyPath) { + return getNamingStrategy().collectionTableName( + ownerEntityName, + ownerEntityTable, + null, + null, + propertyPath + ); + } + + @Override + public String determineImplicitElementCollectionJoinColumnName( + String ownerEntityName, String ownerJpaEntityName, String ownerEntityTable, String referencedColumnName, String propertyPath) { + return getNamingStrategy().foreignKeyColumnName( + propertyPath, + ownerEntityName, + ownerEntityTable, + referencedColumnName + ); + } + + @Override + public String determineImplicitEntityAssociationJoinTableName( + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String associatedEntityName, + String associatedJpaEntityName, + String associatedEntityTable, + String propertyPath) { + return getNamingStrategy().collectionTableName( + ownerEntityName, + ownerEntityTable, + associatedEntityName, + associatedEntityTable, + propertyPath + ); + } + + @Override + public String determineImplicitEntityAssociationJoinColumnName( + String propertyEntityName, String propertyJpaEntityName, String propertyTableName, String referencedColumnName, String propertyPath) { + return getNamingStrategy().foreignKeyColumnName( + propertyPath, + propertyEntityName, + propertyTableName, + referencedColumnName + ); + } + + @Override + public String determineLogicalElementCollectionTableName( + String tableName, + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String propertyName) { + return getNamingStrategy().logicalCollectionTableName( + tableName, + ownerEntityTable, + null, + propertyName + ); + } + + @Override + public String determineLogicalEntityAssociationJoinTableName( + String tableName, + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String associatedEntityName, + String associatedJpaEntityName, + String associatedEntityTable, + String propertyName) { + return getNamingStrategy().logicalCollectionTableName( + tableName, + ownerEntityTable, + associatedEntityTable, + propertyName + ); + } +} Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/LegacyJpaNamingStrategyDelegate.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/LegacyJpaNamingStrategyDelegate.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/LegacyJpaNamingStrategyDelegate.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,131 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat, Inc. and/or its affiliates or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat, Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.cfg.naming; + +import org.hibernate.internal.util.StringHelper; + +/** + * @author Gail Badner + */ +@Deprecated +public class LegacyJpaNamingStrategyDelegate extends LegacyNamingStrategyDelegateAdapter { + + LegacyJpaNamingStrategyDelegate(LegacyNamingStrategyDelegate.LegacyNamingStrategyDelegateContext context) { + super( context ); + } + + @Override + public String determineImplicitPrimaryTableName(String entityName, String jpaEntityName) { + // jpaEntityname is being passed here in order to not cause a regression. See HHH-4312. + return getNamingStrategy().classToTableName( jpaEntityName ); + } + + @Override + public String determineImplicitElementCollectionTableName( + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String propertyPath) { + return getNamingStrategy().collectionTableName( + ownerEntityName, + StringHelper.unqualifyEntityName( ownerEntityName ), + null, + null, + propertyPath + ); + } + + @Override + public String determineImplicitElementCollectionJoinColumnName( + String ownerEntityName, String ownerJpaEntityName, String ownerEntityTable, String referencedColumnName, String propertyPath) { + return getNamingStrategy().foreignKeyColumnName( + propertyPath, + ownerEntityName, + StringHelper.unqualifyEntityName( ownerEntityName ), + referencedColumnName + ); + } + + @Override + public String determineImplicitEntityAssociationJoinTableName( + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String associatedEntityName, + String associatedJpaEntityName, + String associatedEntityTable, + String propertyPath) { + return getNamingStrategy().collectionTableName( + ownerEntityName, + ownerEntityTable, + associatedEntityName, + associatedEntityTable, + propertyPath + ); + } + + @Override + public String determineImplicitEntityAssociationJoinColumnName( + String propertyEntityName, String propertyJpaEntityName, String propertyTableName, String referencedColumnName, String propertyPath) { + return getNamingStrategy().foreignKeyColumnName( + propertyPath, + propertyEntityName, + propertyTableName, + referencedColumnName + ); + } + + @Override + public String determineLogicalElementCollectionTableName( + String tableName, + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String propertyName) { + return getNamingStrategy().logicalCollectionTableName( + tableName, + ownerEntityName == null ? null : StringHelper.unqualifyEntityName( ownerEntityName ), + null, + propertyName + ); + } + + @Override + public String determineLogicalEntityAssociationJoinTableName( + String tableName, + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String associatedEntityName, + String associatedJpaEntityName, + String associatedEntityTable, + String propertyName) { + return getNamingStrategy().logicalCollectionTableName( + tableName, + ownerEntityTable, + associatedEntityTable, + propertyName + ); + } +} Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/LegacyNamingStrategyDelegate.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/LegacyNamingStrategyDelegate.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/LegacyNamingStrategyDelegate.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,36 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat, Inc. and/or its affiliates or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat, Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.cfg.naming; + +import org.hibernate.cfg.NamingStrategy; + +/** + * @author Gail Badner + */ +@Deprecated +public interface LegacyNamingStrategyDelegate extends NamingStrategyDelegate { + public static interface LegacyNamingStrategyDelegateContext { + public NamingStrategy getNamingStrategy(); + } +} Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/LegacyNamingStrategyDelegateAdapter.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/LegacyNamingStrategyDelegateAdapter.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/LegacyNamingStrategyDelegateAdapter.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,74 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat, Inc. and/or its affiliates or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat, Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.cfg.naming; + +import java.io.Serializable; + +import org.hibernate.cfg.NamingStrategy; + +/** + * @author Gail Badner + */ +@Deprecated +public abstract class LegacyNamingStrategyDelegateAdapter implements NamingStrategyDelegate, Serializable { + private final LegacyNamingStrategyDelegate.LegacyNamingStrategyDelegateContext context; + + public LegacyNamingStrategyDelegateAdapter(LegacyNamingStrategyDelegate.LegacyNamingStrategyDelegateContext context) { + this.context = context; + } + + protected NamingStrategy getNamingStrategy() { + return context.getNamingStrategy(); + } + + @Override + public String toPhysicalTableName(String tableName) { + return getNamingStrategy().tableName( tableName ); + } + + @Override + public String toPhysicalColumnName(String columnName) { + return getNamingStrategy().columnName( columnName ); + } + + @Override + public String determineImplicitPropertyColumnName(String propertyPath) { + return getNamingStrategy().propertyToColumnName( propertyPath ); + } + + @Override + public String toPhysicalJoinKeyColumnName(String joinedColumn, String joinedTable) { + return getNamingStrategy().joinKeyColumnName( joinedColumn, joinedTable ); + } + + @Override + public String determineLogicalColumnName(String columnName, String propertyName) { + return getNamingStrategy().logicalColumnName( columnName, propertyName ); + } + + @Override + public String determineLogicalCollectionColumnName(String columnName, String propertyName, String referencedColumn) { + return getNamingStrategy().logicalCollectionColumnName( columnName, propertyName, referencedColumn ); + } +} Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/LegacyNamingStrategyDelegator.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/LegacyNamingStrategyDelegator.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/LegacyNamingStrategyDelegator.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,68 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat, Inc. and/or its affiliates or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat, Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.cfg.naming; + +import java.io.Serializable; + +import org.hibernate.cfg.EJB3NamingStrategy; +import org.hibernate.cfg.NamingStrategy; + +import static org.hibernate.cfg.naming.LegacyNamingStrategyDelegate.LegacyNamingStrategyDelegateContext; + +/** + * @deprecated Needed as a transitory implementation until the deprecated NamingStrategy contract + * can be removed. + * + * @author Gail Badner + */ +@Deprecated +public class LegacyNamingStrategyDelegator + implements NamingStrategyDelegator, LegacyNamingStrategyDelegateContext, Serializable { + public static final NamingStrategyDelegator DEFAULT_INSTANCE = new LegacyNamingStrategyDelegator(); + + private final NamingStrategy namingStrategy; + private final NamingStrategyDelegate hbmNamingStrategyDelegate; + private final NamingStrategyDelegate jpaNamingStrategyDelegate; + + public LegacyNamingStrategyDelegator() { + this( EJB3NamingStrategy.INSTANCE ); + } + + public LegacyNamingStrategyDelegator(NamingStrategy namingStrategy) { + this.namingStrategy = namingStrategy; + this.hbmNamingStrategyDelegate = new LegacyHbmNamingStrategyDelegate( this ); + this.jpaNamingStrategyDelegate = new LegacyJpaNamingStrategyDelegate( this ); + } + + public NamingStrategy getNamingStrategy() { + return namingStrategy; + } + + @Override + public NamingStrategyDelegate getNamingStrategyDelegate(boolean isHbm) { + return isHbm ? + hbmNamingStrategyDelegate : + jpaNamingStrategyDelegate; + } +} Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/NamingStrategyDelegate.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/NamingStrategyDelegate.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/NamingStrategyDelegate.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,173 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat, Inc. and/or its affiliates or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat, Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.cfg.naming; + +/** + * A + * @author Gail Badner + */ +public interface NamingStrategyDelegate { + + /** + * Determine the name of a entity's primary table when a name is not explicitly configured. + * + * @param entityName The fully qualified entity name + * @param jpaEntityName The entity name provided by the {@link javax.persistence.Entity} + * {@code name} attribute; or, if not mapped in this way, then the + * unqualified entity name. + * + * @return The implicit table name. + */ + public String determineImplicitPrimaryTableName(String entityName, String jpaEntityName); + + /** + * Determine the name of a property's column when a name is not explicitly configured. + * + * @param propertyPath The property path (not qualified by the entity name) + * @return The implicit column name. + */ + public String determineImplicitPropertyColumnName(String propertyPath); + + /** + * Determine the name of a collection table for a collection of (non-entity) values + * when a name is not explicitly configured. + * + * @param ownerEntityName The fully qualified entity name for the entity that owns the collection. + * @param ownerJpaEntityName The entity name provided by the {@link javax.persistence.Entity} + * {@code name} attribute for the entity that owns the collection; + * or, if not mapped in this way, then the unqualified owner entity name. + * @param ownerEntityTable The owner entity's physical primary table name; + * @param propertyPath The property path (not qualified by the entity name), + * @return The implicit table name. + */ + public String determineImplicitElementCollectionTableName( + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String propertyPath); + + /** + * Determine the name of the join column in a collection table for + * a collection of (non-entity) values when a name is not explicitly configured. + * + * @param ownerEntityName The fully qualified name of the entity that owns the collection. + * @param ownerJpaEntityName The entity name provided by the {@link javax.persistence.Entity} + * {@code name} attribute for the entity that owns the collection; + * or, if not mapped in this way, then the unqualified entity name. + * @param ownerEntityTable The owner entity's physical primary table name; + * @param referencedColumnName The physical name of the column that the join column references. + * @param propertyPath The property path (not qualified by the entity name), + * @return The implicit column name. + */ + public String determineImplicitElementCollectionJoinColumnName( + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String referencedColumnName, + String propertyPath); + + /** + * Determine the name of the join table for an entity (singular or plural) association when + * a name is not explicitly configured. + * + * @param ownerEntityName The fully qualified name of the entity that owns the association;. + * @param ownerJpaEntityName The entity name provided by the {@link javax.persistence.Entity} + * {@code name} attribute for the entity that owns the association; + * or, if not mapped in this way, then the unqualified owner entity name. + * @param ownerEntityTable The owner entity's physical primary table name; + * @param associatedEntityName The fully qualified name of the associated entity. + * @param associatedJpaEntityName The entity name provided by the {@link javax.persistence.Entity} + * {@code name} attribute for the associated entity; + * or, if not mapped in this way, then the unqualified associated entity name. + * @param associatedEntityTable The associated entity's physical primary table name; + * @param propertyPath The property path (not qualified by the entity name), + * @return The implicit table name. + */ + public String determineImplicitEntityAssociationJoinTableName( + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String associatedEntityName, + String associatedJpaEntityName, + String associatedEntityTable, + String propertyPath); + + /** + * Determine the name of join column for an entity (singular or plural) association when + * a name is not explicitly configured. + * + * @param propertyEntityName The fully qualified name of the entity that contains the association; + * @param propertyJpaEntityName The entity name provided by the {@link javax.persistence.Entity} + * {@code name} attribute for the entity that contains the association; + * or, if not mapped in this way, then the unqualified entity name. + * @param propertyTableName The physical primary table name for the entity that contains the association. + * @param referencedColumnName The physical name of the column that the join column references. + * @param propertyPath The property path (not qualified by the entity name), + * @return The implicit table name. + */ + public String determineImplicitEntityAssociationJoinColumnName( + String propertyEntityName, + String propertyJpaEntityName, + String propertyTableName, + String referencedColumnName, + String propertyPath); + + public String toPhysicalJoinKeyColumnName(String joinedColumn, String joinedTable); + + public String determineLogicalColumnName(String columnName, String propertyName); + + public String determineLogicalElementCollectionTableName( + String tableName, + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String propertyName); + + public String determineLogicalEntityAssociationJoinTableName( + String tableName, + String ownerEntityName, + String ownerJpaEntityName, + String ownerEntityTable, + String associatedEntityName, + String associatedJpaEntityName, + String associatedEntityTable, + String propertyName); + + public String determineLogicalCollectionColumnName(String columnName, String propertyName, String referencedColumn); + + /** + * Alter the table name given in the mapping document + * @param tableName a table name + * @return a table name + */ + public String toPhysicalTableName(String tableName); + + /** + * Alter the column name given in the mapping document + * @param columnName a column name + * @return a column name + */ + public String toPhysicalColumnName(String columnName); + +} Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/NamingStrategyDelegateAdapter.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/NamingStrategyDelegateAdapter.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/NamingStrategyDelegateAdapter.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,68 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat, Inc. and/or its affiliates or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat, Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.cfg.naming; + +import java.io.Serializable; + +import org.hibernate.internal.util.StringHelper; + +/** + * An "adapter" for {@link NamingStrategyDelegate} implementations to extend. + * + * @author Gail Badner + */ +public abstract class NamingStrategyDelegateAdapter implements NamingStrategyDelegate, Serializable { + + @Override + public String determineImplicitPropertyColumnName(String propertyPath) { + return StringHelper.unqualify( propertyPath ); + } + + @Override + public String toPhysicalTableName(String tableName) { + return tableName; + } + + @Override + public String toPhysicalColumnName(String columnName) { + return columnName; + } + + @Override + public String toPhysicalJoinKeyColumnName(String joinedColumn, String joinedTable) { + return toPhysicalColumnName( joinedColumn ); + } + + @Override + public String determineLogicalColumnName(String columnName, String propertyName) { + return StringHelper.isNotEmpty( columnName ) ? columnName : StringHelper.unqualify( propertyName ); + } + + @Override + public String determineLogicalCollectionColumnName(String columnName, String propertyName, String referencedColumn) { + return StringHelper.isNotEmpty( columnName ) ? + columnName : + StringHelper.unqualify( propertyName ) + "_" + referencedColumn; + } +} Index: 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/NamingStrategyDelegator.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/NamingStrategyDelegator.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/cfg/naming/NamingStrategyDelegator.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,45 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat, Inc. and/or its affiliates or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat, Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.cfg.naming; + +/** + * Provides access to the appropriate {@link NamingStrategyDelegate}, depending on whether a + * mapping is Hibernate-specific (i.e., hbm.xml). + * + * @author Gail Badner + * + * @see org.hibernate.cfg.naming.NamingStrategyDelegate + */ +public interface NamingStrategyDelegator { + + /** + * Returns the appropriate {@link NamingStrategyDelegate}. + * + * @param isHbm - true, if {@link NamingStrategyDelegate} is to be used for a + * hibernate-specific (hbm.xml) mapping; false, otherwise. + * + * @return the appropriate {@link NamingStrategyDelegate} + */ + public NamingStrategyDelegate getNamingStrategyDelegate(boolean isHbm); +} Index: 3rdParty_sources/hibernate-core/org/hibernate/dialect/FirebirdDialect.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/dialect/FirebirdDialect.java (.../FirebirdDialect.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/dialect/FirebirdDialect.java (.../FirebirdDialect.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -23,12 +23,21 @@ */ package org.hibernate.dialect; +import org.hibernate.dialect.function.StandardSQLFunction; +import org.hibernate.type.StandardBasicTypes; + /** * An SQL dialect for Firebird. * * @author Reha CENANI */ public class FirebirdDialect extends InterbaseDialect { + + public FirebirdDialect() { + super(); + registerFunction( "replace", new StandardSQLFunction( "replace", StandardBasicTypes.STRING ) ); + } + @Override public String getDropSequenceString(String sequenceName) { return "drop generator " + sequenceName; Index: 3rdParty_sources/hibernate-core/org/hibernate/dialect/Oracle8iDialect.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/dialect/Oracle8iDialect.java (.../Oracle8iDialect.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/dialect/Oracle8iDialect.java (.../Oracle8iDialect.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -529,7 +529,7 @@ @Override public String generateTemporaryTableName(String baseTableName) { final String name = super.generateTemporaryTableName( baseTableName ); - return name.length() > 30 ? name.substring( 1, 30 ) : name; + return name.length() > 30 ? name.substring( 0, 30 ) : name; } @Override Index: 3rdParty_sources/hibernate-core/org/hibernate/dialect/function/CastFunction.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/dialect/function/CastFunction.java (.../CastFunction.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/dialect/function/CastFunction.java (.../CastFunction.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -36,6 +36,11 @@ * @author Gavin King */ public class CastFunction implements SQLFunction { + /** + * Singleton access + */ + public static final CastFunction INSTANCE = new CastFunction(); + @Override public boolean hasArguments() { return true; @@ -55,7 +60,7 @@ @Override public String render(Type columnType, List args, SessionFactoryImplementor factory) throws QueryException { if ( args.size()!=2 ) { - throw new QueryException("cast() requires two arguments"); + throw new QueryException( "cast() requires two arguments; found : " + args.size() ); } final String type = (String) args.get( 1 ); final int[] sqlTypeCodes = factory.getTypeResolver().heuristicType( type ).sqlTypes( factory ); Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/internal/EntityEntryExtraStateHolder.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/engine/internal/EntityEntryExtraStateHolder.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/internal/EntityEntryExtraStateHolder.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,70 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.engine.internal; + +import org.hibernate.engine.spi.EntityEntryExtraState; + +/** + * Contains optional state from {@link org.hibernate.engine.spi.EntityEntry}. + * + * @author Emmanuel Bernard + */ +public class EntityEntryExtraStateHolder implements EntityEntryExtraState { + private EntityEntryExtraState next; + private Object[] deletedState; + + public Object[] getDeletedState() { + return deletedState; + } + + public void setDeletedState(Object[] deletedState) { + this.deletedState = deletedState; + } + + //the following methods are handling extraState contracts. + //they are not shared by a common superclass to avoid alignment padding + //we are trading off duplication for padding efficiency + @Override + public void addExtraState(EntityEntryExtraState extraState) { + if ( next == null ) { + next = extraState; + } + else { + next.addExtraState( extraState ); + } + } + + @Override + public T getExtraState(Class extraStateType) { + if ( next == null ) { + return null; + } + if ( extraStateType.isAssignableFrom( next.getClass() ) ) { + return (T) next; + } + else { + return next.getExtraState( extraStateType ); + } + } +} Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/internal/StatefulPersistenceContext.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/engine/internal/StatefulPersistenceContext.java (.../StatefulPersistenceContext.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/internal/StatefulPersistenceContext.java (.../StatefulPersistenceContext.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -680,6 +680,9 @@ @Override public Object proxyFor(Object impl) throws HibernateException { final EntityEntry e = getEntry( impl ); + if ( e == null ) { + return impl; + } return proxyFor( e.getPersister(), e.getEntityKey(), impl ); } @@ -1108,6 +1111,10 @@ collectionPersister, unmergedInstance ); + LOG.debugf( + "Detached object being merged (corresponding with a managed entity) has a collection that [%s] the detached child.", + ( found ? "contains" : "does not contain" ) + ); } } @@ -1134,6 +1141,10 @@ collectionPersister, mergeMap.get( proxy ) ); + LOG.debugf( + "Detached proxy being merged has a collection that [%s] the managed child.", + (found ? "contains" : "does not contain") + ); if ( !found ) { found = isFoundInParent( propertyName, @@ -1142,6 +1153,10 @@ collectionPersister, mergeMap.get( proxy ) ); + LOG.debugf( + "Detached proxy being merged has a collection that [%s] the detached child being merged..", + (found ? "contains" : "does not contain") + ); } if ( found ) { return proxy.getHibernateLazyInitializer().getIdentifier(); @@ -1184,6 +1199,10 @@ final Object unMergedChild = mergeMap.get( childEntity ); if ( unMergedInstance != null && unMergedChild != null ) { index = getIndexInParent( property, unMergedChild, persister, cp, unMergedInstance ); + LOG.debugf( + "A detached object being merged (corresponding to a parent in parentsByChild) has an indexed collection that [%s] the detached child being merged. ", + ( index != null ? "contains" : "does not contain" ) + ); } } if ( index != null ) { @@ -1208,6 +1227,10 @@ final Object unMergedChild = mergeMap.get( childEntity ); if ( unMergedInstance != null && unMergedChild!=null ) { index = getIndexInParent( property, unMergedChild, persister, cp, unMergedInstance ); + LOG.debugf( + "A detached object being merged (corresponding to a managed entity) has an indexed collection that [%s] the detached child being merged. ", + (index != null ? "contains" : "does not contain" ) + ); } } @@ -1739,7 +1762,7 @@ } } else { - naturalIdCacheAccessStrategy.remove( naturalIdCacheKey ); + naturalIdCacheAccessStrategy.evict( naturalIdCacheKey ); } } } Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/BlobProxy.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/BlobProxy.java (.../BlobProxy.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/BlobProxy.java (.../BlobProxy.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -32,7 +32,6 @@ import java.sql.SQLException; import org.hibernate.engine.jdbc.internal.BinaryStreamImpl; -import org.hibernate.internal.util.ClassLoaderHelper; import org.hibernate.type.descriptor.java.DataHelper; /** @@ -195,11 +194,7 @@ * @return The class loader appropriate for proxy construction. */ private static ClassLoader getProxyClassLoader() { - ClassLoader cl = ClassLoaderHelper.getContextClassLoader(); - if ( cl == null ) { - cl = BlobImplementer.class.getClassLoader(); - } - return cl; + return BlobImplementer.class.getClassLoader(); } private static class StreamBackedBinaryStream implements BinaryStream { Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/ClobProxy.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/ClobProxy.java (.../ClobProxy.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/ClobProxy.java (.../ClobProxy.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -33,7 +33,6 @@ import java.sql.SQLException; import org.hibernate.engine.jdbc.internal.CharacterStreamImpl; -import org.hibernate.internal.util.ClassLoaderHelper; import org.hibernate.type.descriptor.java.DataHelper; /** @@ -211,10 +210,6 @@ * @return The class loader appropriate for proxy construction. */ protected static ClassLoader getProxyClassLoader() { - ClassLoader cl = ClassLoaderHelper.getContextClassLoader(); - if ( cl == null ) { - cl = ClobImplementer.class.getClassLoader(); - } - return cl; + return ClobImplementer.class.getClassLoader(); } } Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/NClobProxy.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/NClobProxy.java (.../NClobProxy.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/NClobProxy.java (.../NClobProxy.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -27,8 +27,6 @@ import java.lang.reflect.Proxy; import java.sql.NClob; -import org.hibernate.internal.util.ClassLoaderHelper; - /** * Manages aspects of proxying java.sql.NClobs for non-contextual creation, including proxy creation and * handling proxy invocations. We use proxies here solely to avoid JDBC version incompatibilities. @@ -82,10 +80,6 @@ * @return The class loader appropriate for proxy construction. */ protected static ClassLoader getProxyClassLoader() { - ClassLoader cl = ClassLoaderHelper.getContextClassLoader(); - if ( cl == null ) { - cl = NClobImplementer.class.getClassLoader(); - } - return cl; + return NClobImplementer.class.getClassLoader(); } } Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/SerializableBlobProxy.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/SerializableBlobProxy.java (.../SerializableBlobProxy.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/SerializableBlobProxy.java (.../SerializableBlobProxy.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -31,7 +31,6 @@ import java.sql.Blob; import org.hibernate.HibernateException; -import org.hibernate.internal.util.ClassLoaderHelper; /** * Manages aspects of proxying {@link Blob Blobs} to add serializability. @@ -103,10 +102,6 @@ * @return The class loader appropriate for proxy construction. */ public static ClassLoader getProxyClassLoader() { - ClassLoader cl = ClassLoaderHelper.getContextClassLoader(); - if ( cl == null ) { - cl = WrappedBlob.class.getClassLoader(); - } - return cl; + return WrappedBlob.class.getClassLoader(); } } Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/SerializableClobProxy.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/SerializableClobProxy.java (.../SerializableClobProxy.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/SerializableClobProxy.java (.../SerializableClobProxy.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -31,7 +31,6 @@ import java.sql.Clob; import org.hibernate.HibernateException; -import org.hibernate.internal.util.ClassLoaderHelper; /** * Manages aspects of proxying {@link Clob Clobs} to add serializability. @@ -102,10 +101,6 @@ * @return The class loader appropriate for proxy construction. */ public static ClassLoader getProxyClassLoader() { - ClassLoader cl = ClassLoaderHelper.getContextClassLoader(); - if ( cl == null ) { - cl = WrappedClob.class.getClassLoader(); - } - return cl; + return WrappedClob.class.getClassLoader(); } } Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/dialect/internal/StandardDialectResolver.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/dialect/internal/StandardDialectResolver.java (.../StandardDialectResolver.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/dialect/internal/StandardDialectResolver.java (.../StandardDialectResolver.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -195,8 +195,10 @@ final int majorVersion = info.getDatabaseMajorVersion(); switch ( majorVersion ) { + case 12: + // fall through case 11: - return new Oracle10gDialect(); + // fall through case 10: return new Oracle10gDialect(); case 9: @@ -206,6 +208,7 @@ default: LOG.unknownOracleVersion( majorVersion ); } + return new Oracle8iDialect(); } if ( "HDB".equals( databaseName ) ) { Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java (.../JdbcCoordinatorImpl.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java (.../JdbcCoordinatorImpl.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -167,7 +167,7 @@ * @return The SqlExceptionHelper */ public SqlExceptionHelper sqlExceptionHelper() { - return transactionEnvironment().getJdbcServices().getSqlExceptionHelper(); + return exceptionHelper; } Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/internal/ResultSetReturnImpl.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/internal/ResultSetReturnImpl.java (.../ResultSetReturnImpl.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/internal/ResultSetReturnImpl.java (.../ResultSetReturnImpl.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -44,6 +44,8 @@ private final Dialect dialect; private final SqlStatementLogger sqlStatementLogger; private final SqlExceptionHelper sqlExceptionHelper; + + private boolean isJdbc4 = true; /** * Constructs a ResultSetReturnImpl @@ -65,7 +67,7 @@ @Override public ResultSet extract(PreparedStatement statement) { // IMPL NOTE : SQL logged by caller - if ( statement instanceof CallableStatement ) { + if (isTypeOf(statement, CallableStatement.class)) { // We actually need to extract from Callable statement. Although // this seems needless, Oracle can return an // OracleCallableStatementWrapper that finds its way to this method, @@ -90,6 +92,25 @@ } } + private boolean isTypeOf(final Statement statement, final Class type) { + if (isJdbc4) { + try { + // This is "more correct" than #isInstance, but not always supported. + return statement.isWrapperFor( type ); + } + catch (SQLException e) { + // No operation + } + catch (Throwable e) { + // No operation. Note that this catches more than just SQLException to + // cover edge cases where a driver might throw an UnsupportedOperationException, AbstractMethodError, + // etc. If so, skip permanently. + isJdbc4 = false; + } + } + return type.isInstance( statement ); + } + @Override public ResultSet extract(CallableStatement callableStatement) { // IMPL NOTE : SQL logged by caller Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/spi/SqlExceptionHelper.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/spi/SqlExceptionHelper.java (.../SqlExceptionHelper.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/jdbc/spi/SqlExceptionHelper.java (.../SqlExceptionHelper.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -313,20 +313,23 @@ public void handleAndClearWarnings( Statement statement, WarningHandler handler) { + // See HHH-9174. Statement#getWarnings can be an expensive call for many JDBC libs. Don't do it unless + // the log level would actually allow a warning to be logged. + if (LOG.isEnabled(Level.WARN)) { + try { + walkWarnings( statement.getWarnings(), handler ); + } + catch (SQLException sqlException) { + // workaround for WebLogic + LOG.debug( "could not log warnings", sqlException ); + } + } try { - walkWarnings( statement.getWarnings(), handler ); - } - catch (SQLException sqlException) { - // workaround for WebLogic - LOG.debug( "could not log warnings", sqlException ); - } - try { // Sybase fail if we don't do that, sigh... statement.clearWarnings(); } catch (SQLException sqle) { LOG.debug( "could not clear warnings", sqle ); } } - } Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/loading/internal/CollectionLoadContext.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/engine/loading/internal/CollectionLoadContext.java (.../CollectionLoadContext.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/loading/internal/CollectionLoadContext.java (.../CollectionLoadContext.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -45,6 +45,8 @@ import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.persister.collection.CollectionPersister; +import org.hibernate.persister.collection.QueryableCollection; +import org.hibernate.persister.entity.EntityPersister; import org.hibernate.pretty.MessageHelper; /** @@ -349,23 +351,37 @@ final CollectionCacheEntry entry = new CollectionCacheEntry( lce.getCollection(), persister ); final CacheKey cacheKey = session.generateCacheKey( lce.getKey(), persister.getKeyType(), persister.getRole() ); - try { - session.getEventListenerManager().cachePutStart(); - final boolean put = persister.getCacheAccessStrategy().putFromLoad( - cacheKey, - persister.getCacheEntryStructure().structure( entry ), - session.getTimestamp(), - version, - factory.getSettings().isMinimalPutsEnabled() && session.getCacheMode()!= CacheMode.REFRESH - ); + boolean isPutFromLoad = true; + if ( persister.getElementType().isAssociationType() ) { + for ( Serializable id : entry.getState() ) { + EntityPersister entityPersister = ( (QueryableCollection) persister ).getElementPersister(); + if ( session.getPersistenceContext().wasInsertedDuringTransaction( entityPersister, id ) ) { + isPutFromLoad = false; + break; + } + } + } - if ( put && factory.getStatistics().isStatisticsEnabled() ) { - factory.getStatisticsImplementor().secondLevelCachePut( persister.getCacheAccessStrategy().getRegion().getName() ); + // CollectionRegionAccessStrategy has no update, so avoid putting uncommitted data via putFromLoad + if (isPutFromLoad) { + try { + session.getEventListenerManager().cachePutStart(); + final boolean put = persister.getCacheAccessStrategy().putFromLoad( + cacheKey, + persister.getCacheEntryStructure().structure( entry ), + session.getTimestamp(), + version, + factory.getSettings().isMinimalPutsEnabled() && session.getCacheMode()!= CacheMode.REFRESH + ); + + if ( put && factory.getStatistics().isStatisticsEnabled() ) { + factory.getStatisticsImplementor().secondLevelCachePut( persister.getCacheAccessStrategy().getRegion().getName() ); + } } + finally { + session.getEventListenerManager().cachePutEnd(); + } } - finally { - session.getEventListenerManager().cachePutEnd(); - } } void cleanup() { Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/query/internal/NativeQueryInterpreterStandardImpl.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/engine/query/internal/NativeQueryInterpreterStandardImpl.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/query/internal/NativeQueryInterpreterStandardImpl.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,93 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.engine.query.internal; + +import java.util.HashMap; +import java.util.Map; + +import org.hibernate.engine.query.spi.NamedParameterDescriptor; +import org.hibernate.engine.query.spi.NativeQueryInterpreter; +import org.hibernate.engine.query.spi.NativeSQLQueryPlan; +import org.hibernate.engine.query.spi.OrdinalParameterDescriptor; +import org.hibernate.engine.query.spi.ParamLocationRecognizer; +import org.hibernate.engine.query.spi.ParameterMetadata; +import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.loader.custom.CustomQuery; +import org.hibernate.loader.custom.sql.SQLCustomQuery; + +/** + * @author Steve Ebersole + */ +public class NativeQueryInterpreterStandardImpl implements NativeQueryInterpreter { + /** + * Singleton access + */ + public static final NativeQueryInterpreterStandardImpl INSTANCE = new NativeQueryInterpreterStandardImpl(); + + @Override + public ParameterMetadata getParameterMetadata(String nativeQuery) { + final ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( nativeQuery ); + + final int size = recognizer.getOrdinalParameterLocationList().size(); + final OrdinalParameterDescriptor[] ordinalDescriptors = new OrdinalParameterDescriptor[ size ]; + for ( int i = 0; i < size; i++ ) { + final Integer position = recognizer.getOrdinalParameterLocationList().get( i ); + ordinalDescriptors[i] = new OrdinalParameterDescriptor( i, null, position ); + } + + final Map namedParamDescriptorMap = new HashMap(); + final Map map = recognizer.getNamedParameterDescriptionMap(); + + for ( final String name : map.keySet() ) { + final ParamLocationRecognizer.NamedParameterDescription description = map.get( name ); + namedParamDescriptorMap.put( + name, + new NamedParameterDescriptor( + name, + null, + description.buildPositionsArray(), + description.isJpaStyle() + ) + ); + } + + return new ParameterMetadata( ordinalDescriptors, namedParamDescriptorMap ); + } + + @Override + public NativeSQLQueryPlan createQueryPlan( + NativeSQLQuerySpecification specification, + SessionFactoryImplementor sessionFactory) { + + CustomQuery customQuery = new SQLCustomQuery( + specification.getQueryString(), + specification.getQueryReturns(), + specification.getQuerySpaces(), + sessionFactory + ); + + return new NativeSQLQueryPlan( specification.getQueryString(), customQuery ); + } +} Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/query/spi/HQLQueryPlan.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/engine/query/spi/HQLQueryPlan.java (.../HQLQueryPlan.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/query/spi/HQLQueryPlan.java (.../HQLQueryPlan.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -76,6 +76,11 @@ private final boolean shallow; /** + * We'll check the trace level only once per instance + */ + private final boolean TRACE_ENABLED = LOG.isTraceEnabled(); + + /** * Constructs a HQLQueryPlan * * @param hql The HQL query @@ -200,7 +205,7 @@ public List performList( QueryParameters queryParameters, SessionImplementor session) throws HibernateException { - if ( LOG.isTraceEnabled() ) { + if ( TRACE_ENABLED ) { LOG.tracev( "Find: {0}", getSourceQuery() ); queryParameters.traceParameters( session.getFactory() ); } @@ -298,7 +303,7 @@ public Iterator performIterate( QueryParameters queryParameters, EventSource session) throws HibernateException { - if ( LOG.isTraceEnabled() ) { + if ( TRACE_ENABLED ) { LOG.tracev( "Iterate: {0}", getSourceQuery() ); queryParameters.traceParameters( session.getFactory() ); } @@ -336,7 +341,7 @@ public ScrollableResults performScroll( QueryParameters queryParameters, SessionImplementor session) throws HibernateException { - if ( LOG.isTraceEnabled() ) { + if ( TRACE_ENABLED ) { LOG.tracev( "Iterate: {0}", getSourceQuery() ); queryParameters.traceParameters( session.getFactory() ); } @@ -362,7 +367,7 @@ */ public int performExecuteUpdate(QueryParameters queryParameters, SessionImplementor session) throws HibernateException { - if ( LOG.isTraceEnabled() ) { + if ( TRACE_ENABLED ) { LOG.tracev( "Execute update: {0}", getSourceQuery() ); queryParameters.traceParameters( session.getFactory() ); } @@ -377,12 +382,12 @@ } private ParameterMetadata buildParameterMetadata(ParameterTranslations parameterTranslations, String hql) { - final long start = System.currentTimeMillis(); + final long start = TRACE_ENABLED ? System.nanoTime() : 0; final ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( hql ); - final long end = System.currentTimeMillis(); - if ( LOG.isTraceEnabled() ) { - LOG.tracev( "HQL param location recognition took {0} mills ({1})", ( end - start ), hql ); + if ( TRACE_ENABLED ) { + final long end = System.nanoTime(); + LOG.tracev( "HQL param location recognition took {0} nanoseconds ({1})", ( end - start ), hql ); } int ordinalParamCount = parameterTranslations.getOrdinalParameterCount(); Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/query/spi/NativeQueryInterpreter.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/engine/query/spi/NativeQueryInterpreter.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/query/spi/NativeQueryInterpreter.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,57 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.engine.query.spi; + +import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.service.Service; + +/** + * Service contract for dealing with native queries. + * + * @author Steve Ebersole + * @author Gunnar Morling + */ +public interface NativeQueryInterpreter extends Service { + /** + * Returns a meta-data object with information about the named and ordinal + * parameters contained in the given native query. + * + * @param nativeQuery the native query to analyze. + * + * @return a meta-data object describing the parameters of the given query. + * Must not be {@code null}. + */ + ParameterMetadata getParameterMetadata(String nativeQuery); + + /** + * Creates a new query plan for the specified native query. + * + * @param specification Describes the query to create a plan for + * @param sessionFactory The current session factory + * + * @return A query plan for the specified native query. + */ + NativeSQLQueryPlan createQueryPlan(NativeSQLQuerySpecification specification, SessionFactoryImplementor sessionFactory); +} Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/query/spi/NativeQueryInterpreterInitiator.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/engine/query/spi/NativeQueryInterpreterInitiator.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/query/spi/NativeQueryInterpreterInitiator.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,62 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.engine.query.spi; + +import org.hibernate.cfg.Configuration; +import org.hibernate.engine.query.internal.NativeQueryInterpreterStandardImpl; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.metamodel.source.MetadataImplementor; +import org.hibernate.service.spi.ServiceRegistryImplementor; +import org.hibernate.service.spi.SessionFactoryServiceInitiator; + +/** + * @author Steve Ebersole + */ +public class NativeQueryInterpreterInitiator implements SessionFactoryServiceInitiator { + /** + * Singleton access + */ + public static final NativeQueryInterpreterInitiator INSTANCE = new NativeQueryInterpreterInitiator(); + + @Override + public NativeQueryInterpreter initiateService( + SessionFactoryImplementor sessionFactory, + Configuration configuration, + ServiceRegistryImplementor registry) { + return NativeQueryInterpreterStandardImpl.INSTANCE; + } + + @Override + public NativeQueryInterpreter initiateService( + SessionFactoryImplementor sessionFactory, + MetadataImplementor metadata, + ServiceRegistryImplementor registry) { + return NativeQueryInterpreterStandardImpl.INSTANCE; + } + + @Override + public Class getServiceInitiated() { + return NativeQueryInterpreter.class; + } +} Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/query/spi/NativeSQLQueryPlan.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/engine/query/spi/NativeSQLQueryPlan.java (.../NativeSQLQueryPlan.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/query/spi/NativeSQLQueryPlan.java (.../NativeSQLQueryPlan.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -33,16 +33,14 @@ import org.hibernate.HibernateException; import org.hibernate.QueryException; import org.hibernate.action.internal.BulkOperationCleanupAction; -import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification; import org.hibernate.engine.spi.QueryParameters; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.TypedValue; import org.hibernate.event.spi.EventSource; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.collections.ArrayHelper; -import org.hibernate.loader.custom.sql.SQLCustomQuery; +import org.hibernate.loader.custom.CustomQuery; import org.hibernate.type.Type; /** @@ -54,31 +52,24 @@ private static final CoreMessageLogger LOG = CoreLogging.messageLogger( NativeSQLQueryPlan.class ); private final String sourceQuery; - private final SQLCustomQuery customQuery; + private final CustomQuery customQuery; /** - * Constructs a NativeSQLQueryPlan - * - * @param specification The query spec - * @param factory The SessionFactory - */ - public NativeSQLQueryPlan( - NativeSQLQuerySpecification specification, - SessionFactoryImplementor factory) { - this.sourceQuery = specification.getQueryString(); - this.customQuery = new SQLCustomQuery( - specification.getQueryString(), - specification.getQueryReturns(), - specification.getQuerySpaces(), - factory - ); + * Constructs a NativeSQLQueryPlan. + * + * @param sourceQuery The original native query to create a plan for + * @param customQuery The query executed via this plan + */ + public NativeSQLQueryPlan(String sourceQuery, CustomQuery customQuery) { + this.sourceQuery = sourceQuery; + this.customQuery = customQuery; } public String getSourceQuery() { return sourceQuery; } - public SQLCustomQuery getCustomQuery() { + public CustomQuery getCustomQuery() { return customQuery; } Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/query/spi/QueryPlanCache.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/engine/query/spi/QueryPlanCache.java (.../QueryPlanCache.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/query/spi/QueryPlanCache.java (.../QueryPlanCache.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -81,6 +81,9 @@ */ private final BoundedConcurrentHashMap parameterMetadataCache; + + private NativeQueryInterpreter nativeQueryInterpreterService; + /** * Constructs the QueryPlanCache to be used by the given SessionFactory * @@ -120,6 +123,7 @@ BoundedConcurrentHashMap.Eviction.LIRS ); + nativeQueryInterpreterService = factory.getServiceRegistry().getService( NativeQueryInterpreter.class ); } /** @@ -135,39 +139,12 @@ public ParameterMetadata getSQLParameterMetadata(final String query) { ParameterMetadata value = parameterMetadataCache.get( query ); if ( value == null ) { - value = buildParameterMetadata( query ); + value = nativeQueryInterpreterService.getParameterMetadata( query ); parameterMetadataCache.putIfAbsent( query, value ); } return value; } - - private ParameterMetadata buildParameterMetadata(String query){ - final ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( query ); - final int size = recognizer.getOrdinalParameterLocationList().size(); - final OrdinalParameterDescriptor[] ordinalDescriptors = new OrdinalParameterDescriptor[ size ]; - for ( int i = 0; i < size; i++ ) { - final Integer position = recognizer.getOrdinalParameterLocationList().get( i ); - ordinalDescriptors[i] = new OrdinalParameterDescriptor( i, null, position ); - } - - final Map namedParamDescriptorMap = new HashMap(); - final Map map = recognizer.getNamedParameterDescriptionMap(); - for ( final String name : map.keySet() ) { - final ParamLocationRecognizer.NamedParameterDescription description = map.get( name ); - namedParamDescriptorMap.put( - name, - new NamedParameterDescriptor( - name, - null, - description.buildPositionsArray(), - description.isJpaStyle() - ) - ); - } - return new ParameterMetadata( ordinalDescriptors, namedParamDescriptorMap ); - } - /** * Get the query plan for the given HQL query, creating it and caching it if not already cached * @@ -246,7 +223,7 @@ NativeSQLQueryPlan value = (NativeSQLQueryPlan) queryPlanCache.get( spec ); if ( value == null ) { LOG.tracev( "Unable to locate native-sql query plan in cache; generating ({0})", spec.getQueryString() ); - value = new NativeSQLQueryPlan( spec, factory); + value = nativeQueryInterpreterService.createQueryPlan( spec, factory ); queryPlanCache.putIfAbsent( spec, value ); } else { Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/spi/BatchFetchQueue.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/engine/spi/BatchFetchQueue.java (.../BatchFetchQueue.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/spi/BatchFetchQueue.java (.../BatchFetchQueue.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -218,7 +218,7 @@ } private boolean isCached(EntityKey entityKey, EntityPersister persister) { - if ( persister.hasCache() ) { + if ( context.getSession().getCacheMode().isGetEnabled() && persister.hasCache() ) { final CacheKey key = context.getSession().generateCacheKey( entityKey.getIdentifier(), persister.getIdentifierType(), @@ -331,7 +331,7 @@ } private boolean isCached(Serializable collectionKey, CollectionPersister persister) { - if ( persister.hasCache() ) { + if ( context.getSession().getCacheMode().isGetEnabled() && persister.hasCache() ) { CacheKey cacheKey = context.getSession().generateCacheKey( collectionKey, persister.getKeyType(), Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/spi/EntityEntry.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/engine/spi/EntityEntry.java (.../EntityEntry.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/spi/EntityEntry.java (.../EntityEntry.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -1,7 +1,7 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * Copyright (c) 2010-2014, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Inc. @@ -28,41 +28,66 @@ import java.io.ObjectOutputStream; import java.io.Serializable; +import org.hibernate.AssertionFailure; import org.hibernate.CustomEntityDirtinessStrategy; import org.hibernate.EntityMode; import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.Session; import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor; +import org.hibernate.engine.internal.EntityEntryExtraStateHolder; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.UniqueKeyLoadable; import org.hibernate.pretty.MessageHelper; /** * We need an entry to tell us all about the current state of an object with respect to its persistent state - * + * + * Implementation Warning: Hibernate needs to instantiate a high amount of instances of this class, + * therefore we need to take care of its impact on memory consumption. + * * @author Gavin King + * @author Emmanuel Bernard + * @author Gunnar Morling + * @author Sanne Grinovero */ public final class EntityEntry implements Serializable { - private LockMode lockMode; - private Status status; - private Status previousStatus; private final Serializable id; private Object[] loadedState; - private Object[] deletedState; - private boolean existsInDatabase; private Object version; - private transient EntityPersister persister; - private final String entityName; - // cached EntityKey (lazy-initialized) - private transient EntityKey cachedEntityKey; - private boolean isBeingReplicated; - //NOTE: this is not updated when properties are fetched lazily! - private boolean loadedWithLazyPropertiesUnfetched; + private final EntityPersister persister; // permanent but we only need the entityName state in a non transient way + private transient EntityKey cachedEntityKey; // cached EntityKey (lazy-initialized) private final transient Object rowId; private final transient PersistenceContext persistenceContext; + private EntityEntryExtraState next; /** + * Holds several boolean and enum typed attributes in a very compact manner. Enum values are stored in 4 bits + * (where 0 represents {@code null}, and each enum value is represented by its ordinal value + 1), thus allowing + * for up to 15 values per enum. Boolean values are stored in one bit. + *

+ * The value is structured as follows: + * + *

+	 * 1 - Lock mode
+	 * 2 - Status
+	 * 3 - Previous Status
+	 * 4 - existsInDatabase
+	 * 5 - isBeingReplicated
+	 * 6 - loadedWithLazyPropertiesUnfetched; NOTE: this is not updated when properties are fetched lazily!
+	 *
+	 * 0000 0000 | 0000 0000 | 0654 3333 | 2222 1111
+	 * 
+ * Use {@link #setCompressedValue(org.hibernate.engine.spi.EntityEntry.EnumState, Enum)}, + * {@link #getCompressedValue(org.hibernate.engine.spi.EntityEntry.EnumState, Class)} etc + * to access the enums and booleans stored in this value. + *

+ * Representing enum values by their ordinal value is acceptable for our case as this value itself is never + * serialized or deserialized and thus is not affected should ordinal values change. + */ + private transient int compressedState; + + /** * @deprecated the tenantId and entityMode parameters where removed: this constructor accepts but ignores them. * Use the other constructor! */ @@ -97,21 +122,21 @@ final boolean disableVersionIncrement, final boolean lazyPropertiesAreUnfetched, final PersistenceContext persistenceContext) { - this.status = status; - this.previousStatus = null; + setCompressedValue( EnumState.STATUS, status ); + // not useful strictly speaking but more explicit + setCompressedValue( EnumState.PREVIOUS_STATUS, null ); // only retain loaded state if the status is not Status.READ_ONLY if ( status != Status.READ_ONLY ) { this.loadedState = loadedState; } this.id=id; this.rowId=rowId; - this.existsInDatabase=existsInDatabase; + setCompressedValue( BooleanState.EXISTS_IN_DATABASE, existsInDatabase ); this.version=version; - this.lockMode=lockMode; - this.isBeingReplicated=disableVersionIncrement; - this.loadedWithLazyPropertiesUnfetched = lazyPropertiesAreUnfetched; + setCompressedValue( EnumState.LOCK_MODE, lockMode ); + setCompressedValue( BooleanState.IS_BEING_REPLICATED, disableVersionIncrement ); + setCompressedValue( BooleanState.LOADED_WITH_LAZY_PROPERTIES_UNFETCHED, lazyPropertiesAreUnfetched ); this.persister=persister; - this.entityName = persister == null ? null : persister.getEntityName(); this.persistenceContext = persistenceContext; } @@ -133,43 +158,48 @@ final boolean isBeingReplicated, final boolean loadedWithLazyPropertiesUnfetched, final PersistenceContext persistenceContext) { - this.entityName = entityName; this.persister = ( factory == null ? null : factory.getEntityPersister( entityName ) ); this.id = id; - this.status = status; - this.previousStatus = previousStatus; + setCompressedValue( EnumState.STATUS, status ); + setCompressedValue( EnumState.PREVIOUS_STATUS, previousStatus ); this.loadedState = loadedState; - this.deletedState = deletedState; + setDeletedState( deletedState ); this.version = version; - this.lockMode = lockMode; - this.existsInDatabase = existsInDatabase; - this.isBeingReplicated = isBeingReplicated; - this.loadedWithLazyPropertiesUnfetched = loadedWithLazyPropertiesUnfetched; - // this is equivalent to the old behavior... - this.rowId = null; + setCompressedValue( EnumState.LOCK_MODE, lockMode ); + setCompressedValue( BooleanState.EXISTS_IN_DATABASE, existsInDatabase ); + setCompressedValue( BooleanState.IS_BEING_REPLICATED, isBeingReplicated ); + setCompressedValue( BooleanState.LOADED_WITH_LAZY_PROPERTIES_UNFETCHED, loadedWithLazyPropertiesUnfetched ); + this.rowId = null; // this is equivalent to the old behavior... this.persistenceContext = persistenceContext; } public LockMode getLockMode() { - return lockMode; + return getCompressedValue( EnumState.LOCK_MODE ); } public void setLockMode(LockMode lockMode) { - this.lockMode = lockMode; + setCompressedValue( EnumState.LOCK_MODE, lockMode ); } public Status getStatus() { - return status; + return getCompressedValue( EnumState.STATUS ); } + private Status getPreviousStatus() { + return getCompressedValue( EnumState.PREVIOUS_STATUS ); + } + public void setStatus(Status status) { if ( status == Status.READ_ONLY ) { //memory optimization loadedState = null; } - if ( this.status != status ) { - this.previousStatus = this.status; - this.status = status; + + Status currentStatus = this.getStatus(); + + if ( currentStatus != status ) { + setCompressedValue( EnumState.PREVIOUS_STATUS, currentStatus ); + setCompressedValue( EnumState.STATUS, status ); } } @@ -181,16 +211,28 @@ return loadedState; } + private static final Object[] DEFAULT_DELETED_STATE = null; + public Object[] getDeletedState() { - return deletedState; + EntityEntryExtraStateHolder extra = getExtraState( EntityEntryExtraStateHolder.class ); + return extra != null ? extra.getDeletedState() : DEFAULT_DELETED_STATE; } public void setDeletedState(Object[] deletedState) { - this.deletedState = deletedState; + EntityEntryExtraStateHolder extra = getExtraState( EntityEntryExtraStateHolder.class ); + if ( extra == null && deletedState == DEFAULT_DELETED_STATE ) { + //this is the default value and we do not store the extra state + return; + } + if ( extra == null ) { + extra = new EntityEntryExtraStateHolder(); + addExtraState( extra ); + } + extra.setDeletedState( deletedState ); } public boolean isExistsInDatabase() { - return existsInDatabase; + return getCompressedValue( BooleanState.EXISTS_IN_DATABASE ); } public Object getVersion() { @@ -217,11 +259,12 @@ } public String getEntityName() { - return entityName; + return persister == null ? null : persister.getEntityName(); + } public boolean isBeingReplicated() { - return isBeingReplicated; + return getCompressedValue( BooleanState.IS_BEING_REPLICATED ); } public Object getRowId() { @@ -269,17 +312,17 @@ * exists in the database */ public void postDelete() { - previousStatus = status; - status = Status.GONE; - existsInDatabase = false; + setCompressedValue( EnumState.PREVIOUS_STATUS, getStatus() ); + setCompressedValue( EnumState.STATUS, Status.GONE ); + setCompressedValue( BooleanState.EXISTS_IN_DATABASE, false ); } /** - * After actually inserting a row, record the fact that the instance exists on the + * After actually inserting a row, record the fact that the instance exists on the * database (needed for identity-column key generation) */ public void postInsert(Object[] insertedState) { - existsInDatabase = true; + setCompressedValue( BooleanState.EXISTS_IN_DATABASE, true ); } public boolean isNullifiable(boolean earlyInsert, SessionImplementor session) { @@ -357,6 +400,8 @@ * @return true, if the entity is modifiable; false, otherwise, */ public boolean isModifiableEntity() { + Status status = getStatus(); + Status previousStatus = getPreviousStatus(); return getPersister().isMutable() && status != Status.READ_ONLY && ! ( status == Status.DELETED && previousStatus == Status.READ_ONLY ); @@ -372,8 +417,9 @@ } public boolean isReadOnly() { - if ( status != Status.MANAGED && status != Status.READ_ONLY ) { - throw new HibernateException( "instance was not in a valid state" ); + Status status = getStatus(); + if (status != Status.MANAGED && status != Status.READ_ONLY) { + throw new HibernateException("instance was not in a valid state"); } return status == Status.READ_ONLY; } @@ -405,11 +451,13 @@ @Override public String toString() { - return "EntityEntry" + MessageHelper.infoString( entityName, id ) + '(' + status + ')'; + return "EntityEntry" + + MessageHelper.infoString( getPersister().getEntityName(), id ) + + '(' + getStatus() + ')'; } public boolean isLoadedWithLazyPropertiesUnfetched() { - return loadedWithLazyPropertiesUnfetched; + return getCompressedValue( BooleanState.LOADED_WITH_LAZY_PROPERTIES_UNFETCHED ); } /** @@ -418,21 +466,22 @@ * * @param oos The stream to which we should write the serial data. * - * @throws IOException If a stream error occurs + * @throws java.io.IOException If a stream error occurs */ public void serialize(ObjectOutputStream oos) throws IOException { - oos.writeObject( entityName ); + Status previousStatus = getPreviousStatus(); + oos.writeObject( getEntityName() ); oos.writeObject( id ); - oos.writeObject( status.name() ); + oos.writeObject( getStatus().name() ); oos.writeObject( (previousStatus == null ? "" : previousStatus.name()) ); // todo : potentially look at optimizing these two arrays oos.writeObject( loadedState ); - oos.writeObject( deletedState ); + oos.writeObject( getDeletedState() ); oos.writeObject( version ); - oos.writeObject( lockMode.toString() ); - oos.writeBoolean( existsInDatabase ); - oos.writeBoolean( isBeingReplicated ); - oos.writeBoolean( loadedWithLazyPropertiesUnfetched ); + oos.writeObject( getLockMode().toString() ); + oos.writeBoolean( isExistsInDatabase() ); + oos.writeBoolean( isBeingReplicated() ); + oos.writeBoolean( isLoadedWithLazyPropertiesUnfetched() ); } /** @@ -470,4 +519,199 @@ persistenceContext ); } + + //the following methods are handling extraState contracts. + //they are not shared by a common superclass to avoid alignment padding + //we are trading off duplication for padding efficiency + public void addExtraState(EntityEntryExtraState extraState) { + if ( next == null ) { + next = extraState; + } + else { + next.addExtraState( extraState ); + } + } + + public T getExtraState(Class extraStateType) { + if ( next == null ) { + return null; + } + if ( extraStateType.isAssignableFrom( next.getClass() ) ) { + return (T) next; + } + else { + return next.getExtraState( extraStateType ); + } + } + /** + * Saves the value for the given enum property. + * + * @param state + * identifies the value to store + * @param value + * the value to store; The caller must make sure that it matches + * the given identifier + */ + private > void setCompressedValue(EnumState state, E value) { + // reset the bits for the given property to 0 + compressedState &= state.getUnsetMask(); + // store the numeric representation of the enum value at the right offset + compressedState |= ( state.getValue( value ) << state.getOffset() ); + } + + /** + * Gets the current value of the given enum property. + * + * @param state + * identifies the value to store + * @return the current value of the specified property + */ + private > E getCompressedValue(EnumState state) { + // restore the numeric value from the bits at the right offset and return the corresponding enum constant + int index = ( ( compressedState & state.getMask() ) >> state.getOffset() ) - 1; + return index == - 1 ? null : state.getEnumConstants()[index]; + } + + /** + * Saves the value for the given boolean flag. + * + * @param state + * identifies the value to store + * @param value + * the value to store + */ + private void setCompressedValue(BooleanState state, boolean value) { + compressedState &= state.getUnsetMask(); + compressedState |= ( state.getValue( value ) << state.getOffset() ); + } + + /** + * Gets the current value of the given boolean flag. + * + * @param state + * identifies the value to store + * @return the current value of the specified flag + */ + private boolean getCompressedValue(BooleanState state) { + return ( ( compressedState & state.getMask() ) >> state.getOffset() ) == 1; + } + + /** + * Represents an enum value stored within a number value, using four bits starting at a specified offset. + * + * @author Gunnar Morling + */ + private static class EnumState> { + + private static final EnumState LOCK_MODE = new EnumState( 0, LockMode.class ); + private static final EnumState STATUS = new EnumState( 4, Status.class ); + private static final EnumState PREVIOUS_STATUS = new EnumState( 8, Status.class ); + + private final int offset; + private final E[] enumConstants; + private final int mask; + private final int unsetMask; + + private EnumState(int offset, Class enumType) { + E[] enumConstants = enumType.getEnumConstants(); + + // In case any of the enums cannot be stored in 4 bits anymore, we'd have to re-structure the compressed + // state int + if ( enumConstants.length > 15 ) { + throw new AssertionFailure( "Cannot store enum type " + enumType.getName() + " in compressed state as" + + " it has too many values." ); + } + + this.offset = offset; + this.enumConstants = enumConstants; + + // a mask for reading the four bits, starting at the right offset + this.mask = 0xF << offset; + + // a mask for setting the four bits at the right offset to 0 + this.unsetMask = 0xFFFF & ~mask; + } + + /** + * Returns the numeric value to be stored for the given enum value. + */ + private int getValue(E value) { + return value != null ? value.ordinal() + 1 : 0; + } + + /** + * Returns the offset within the number value at which this enum value is stored. + */ + private int getOffset() { + return offset; + } + + /** + * Returns the bit mask for reading this enum value from the number value storing it. + */ + private int getMask() { + return mask; + } + + /** + * Returns the bit mask for resetting this enum value from the number value storing it. + */ + private int getUnsetMask() { + return unsetMask; + } + + /** + * Returns the constants of the represented enum which is cached for performance reasons. + */ + private E[] getEnumConstants() { + return enumConstants; + } + } + + /** + * Represents a boolean flag stored within a number value, using one bit at a specified offset. + * + * @author Gunnar Morling + */ + private enum BooleanState { + + EXISTS_IN_DATABASE(13), + IS_BEING_REPLICATED(14), + LOADED_WITH_LAZY_PROPERTIES_UNFETCHED(15); + + private final int offset; + private final int mask; + private final int unsetMask; + + private BooleanState(int offset) { + this.offset = offset; + this.mask = 0x1 << offset; + this.unsetMask = 0xFFFF & ~mask; + } + + private int getValue(boolean value) { + return value ? 1 : 0; + } + + /** + * Returns the offset within the number value at which this boolean flag is stored. + */ + private int getOffset() { + return offset; + } + + /** + * Returns the bit mask for reading this flag from the number value storing it. + */ + private int getMask() { + return mask; + } + + /** + * Returns the bit mask for resetting this flag from the number value storing it. + */ + private int getUnsetMask() { + return unsetMask; + } + } } Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/spi/EntityEntryExtraState.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/engine/spi/EntityEntryExtraState.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/spi/EntityEntryExtraState.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,49 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ + +package org.hibernate.engine.spi; + +/** + * Navigation methods for extra state objects attached to {@link org.hibernate.engine.spi.EntityEntry}. + * + * @author Emmanuel Bernard + */ +public interface EntityEntryExtraState { + + /** + * Attach additional state to the core state of {@link org.hibernate.engine.spi.EntityEntry} + *

+ * Implementations must delegate to the next state or add it as next state if last in line. + */ + void addExtraState(EntityEntryExtraState extraState); + + /** + * Retrieve additional state by class type or null if no extra state of that type is present. + *

+ * Implementations must return self if they match or delegate discovery to the next state in line. + */ + T getExtraState(Class extraStateType); + + //a remove method is ugly to define and has not real use case that we found: left out +} Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/transaction/synchronization/internal/SynchronizationCallbackCoordinatorNonTrackingImpl.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/engine/transaction/synchronization/internal/SynchronizationCallbackCoordinatorNonTrackingImpl.java (.../SynchronizationCallbackCoordinatorNonTrackingImpl.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/transaction/synchronization/internal/SynchronizationCallbackCoordinatorNonTrackingImpl.java (.../SynchronizationCallbackCoordinatorNonTrackingImpl.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -63,6 +63,10 @@ afterCompletionAction = STANDARD_AFTER_COMPLETION_ACTION; } + protected final TransactionCoordinator transactionCoordinator() { + return transactionCoordinator; + } + private TransactionContext transactionContext() { return transactionCoordinator.getTransactionContext(); } Index: 3rdParty_sources/hibernate-core/org/hibernate/engine/transaction/synchronization/internal/SynchronizationCallbackCoordinatorTrackingImpl.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/engine/transaction/synchronization/internal/SynchronizationCallbackCoordinatorTrackingImpl.java (.../SynchronizationCallbackCoordinatorTrackingImpl.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/engine/transaction/synchronization/internal/SynchronizationCallbackCoordinatorTrackingImpl.java (.../SynchronizationCallbackCoordinatorTrackingImpl.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -78,6 +78,10 @@ // check for it in SessionImpl. See HHH-7910. delayedCompletionHandlingStatus = status; + // no matter what we need to release the Connection. Not releasing + // the Connection here can lead to leaked Connections. + transactionCoordinator().getJdbcCoordinator().getLogicalConnection().close(); + log.rollbackFromBackgroundThread( status ); return; } Index: 3rdParty_sources/hibernate-core/org/hibernate/event/internal/DefaultLoadEventListener.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/event/internal/DefaultLoadEventListener.java (.../DefaultLoadEventListener.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/event/internal/DefaultLoadEventListener.java (.../DefaultLoadEventListener.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -30,6 +30,7 @@ import org.hibernate.NonUniqueObjectException; import org.hibernate.PersistentObjectException; import org.hibernate.TypeMismatchException; +import org.hibernate.WrongClassException; import org.hibernate.cache.spi.CacheKey; import org.hibernate.cache.spi.access.SoftLock; import org.hibernate.cache.spi.entry.CacheEntry; @@ -591,7 +592,7 @@ final CacheKey ck = source.generateCacheKey( event.getEntityId(), persister.getIdentifierType(), - persister.getEntityName() + persister.getRootEntityName() ); final Object ce = CacheHelper.fromSharedCache( source, ck, persister.getCacheAccessStrategy() ); @@ -614,7 +615,17 @@ } CacheEntry entry = (CacheEntry) persister.getCacheEntryStructure().destructure( ce, factory ); - return convertCacheEntryToEntity( entry, event.getEntityId(), persister, event ); + Object entity = convertCacheEntryToEntity( entry, event.getEntityId(), persister, event ); + + if ( !persister.isInstance( entity ) ) { + throw new WrongClassException( + "loaded object was of wrong class " + entity.getClass(), + event.getEntityId(), + persister.getEntityName() + ); + } + + return entity; } private Object convertCacheEntryToEntity( @@ -625,7 +636,7 @@ final EventSource session = event.getSession(); final SessionFactoryImplementor factory = session.getFactory(); - final EntityPersister subclassPersister = factory.getEntityPersister( entry.getSubclass() ); + final EntityPersister subclassPersister; if ( LOG.isTraceEnabled() ) { LOG.tracef( @@ -648,7 +659,8 @@ ); } - entity = ( (ReferenceCacheEntryImpl) entry ).getReference(); + ReferenceCacheEntryImpl referenceCacheEntry = (ReferenceCacheEntryImpl) entry; + entity = referenceCacheEntry.getReference(); if ( entity == null ) { throw new IllegalStateException( "Reference cache entry contained null : " + MessageHelper.infoString( @@ -658,8 +670,10 @@ ) ); } + subclassPersister = referenceCacheEntry.getSubclassPersister(); } else { + subclassPersister = factory.getEntityPersister( entry.getSubclass() ); final Object optionalObject = event.getInstanceToLoad(); entity = optionalObject == null ? session.instantiate( subclassPersister, entityId ) Index: 3rdParty_sources/hibernate-core/org/hibernate/event/internal/DefaultMergeEventListener.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/event/internal/DefaultMergeEventListener.java (.../DefaultMergeEventListener.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/event/internal/DefaultMergeEventListener.java (.../DefaultMergeEventListener.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -1,7 +1,7 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as + * Copyright (c) 2008-2014, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Inc. @@ -31,14 +31,18 @@ import org.hibernate.ObjectDeletedException; import org.hibernate.StaleObjectStateException; import org.hibernate.WrongClassException; +import org.hibernate.boot.registry.selector.spi.StrategySelector; import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor; +import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.internal.Cascade; import org.hibernate.engine.internal.CascadePoint; import org.hibernate.engine.spi.CascadingAction; import org.hibernate.engine.spi.CascadingActions; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityKey; +import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.event.spi.EntityCopyObserver; import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.MergeEvent; import org.hibernate.event.spi.MergeEventListener; @@ -47,6 +51,7 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.LazyInitializer; +import org.hibernate.service.ServiceRegistry; import org.hibernate.type.ForeignKeyDirection; import org.hibernate.type.TypeHelper; @@ -59,9 +64,11 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener implements MergeEventListener { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( DefaultMergeEventListener.class ); + private String entityCopyObserverStrategy; + @Override protected Map getMergeMap(Object anything) { - return ( (EventCache) anything ).invertMap(); + return ( (MergeContext) anything ).invertMap(); } /** @@ -72,11 +79,39 @@ * @throws HibernateException */ public void onMerge(MergeEvent event) throws HibernateException { - EventCache copyCache = new EventCache( event.getSession() ); - onMerge( event, copyCache ); - copyCache.clear(); + final EntityCopyObserver entityCopyObserver = createEntityCopyObserver( event.getSession().getFactory() ); + final MergeContext mergeContext = new MergeContext( event.getSession(), entityCopyObserver ); + try { + onMerge( event, mergeContext ); + entityCopyObserver.topLevelMergeComplete( event.getSession() ); + } + finally { + entityCopyObserver.clear(); + mergeContext.clear(); + } } + private EntityCopyObserver createEntityCopyObserver(SessionFactoryImplementor sessionFactory) { + final ServiceRegistry serviceRegistry = sessionFactory.getServiceRegistry(); + if ( entityCopyObserverStrategy == null ) { + final ConfigurationService configurationService + = serviceRegistry.getService( ConfigurationService.class ); + entityCopyObserverStrategy = configurationService.getSetting( + "hibernate.event.merge.entity_copy_observer", + new ConfigurationService.Converter() { + @Override + public String convert(Object value) { + return value.toString(); + } + }, + EntityCopyNotAllowedObserver.SHORT_NAME + ); + LOG.debugf( "EntityCopyObserver strategy: %s", entityCopyObserverStrategy ); + } + final StrategySelector strategySelector = serviceRegistry.getService( StrategySelector.class ); + return strategySelector.resolveStrategy( EntityCopyObserver.class, entityCopyObserverStrategy ); + } + /** * Handle the given merge event. * @@ -86,7 +121,7 @@ */ public void onMerge(MergeEvent event, Map copiedAlready) throws HibernateException { - final EventCache copyCache = (EventCache) copiedAlready; + final MergeContext copyCache = (MergeContext) copiedAlready; final EventSource source = event.getSession(); final Object original = event.getOriginal(); @@ -178,7 +213,7 @@ final EventSource source = event.getSession(); final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity ); - ( (EventCache) copyCache ).put( entity, entity, true ); //before cascade! + ( (MergeContext) copyCache ).put( entity, entity, true ); //before cascade! cascadeOnMerge( source, persister, entity, copyCache ); copyValues( persister, entity, entity, source, copyCache ); @@ -203,7 +238,7 @@ persister.setIdentifier( copyCache.get( entity ), id, source ); } else { - ( (EventCache) copyCache ).put( entity, source.instantiate( persister, id ), true ); //before cascade! + ( (MergeContext) copyCache ).put( entity, source.instantiate( persister, id ), true ); //before cascade! } final Object copy = copyCache.get( entity ); @@ -282,7 +317,7 @@ entityIsTransient( event, copyCache ); } else { - ( (EventCache) copyCache ).put( entity, result, true ); //before cascade! + ( (MergeContext) copyCache ).put( entity, result, true ); //before cascade! final Object target = source.getPersistenceContext().unproxy( result ); if ( target == entity ) { Index: 3rdParty_sources/hibernate-core/org/hibernate/event/internal/DefaultResolveNaturalIdEventListener.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/event/internal/DefaultResolveNaturalIdEventListener.java (.../DefaultResolveNaturalIdEventListener.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/event/internal/DefaultResolveNaturalIdEventListener.java (.../DefaultResolveNaturalIdEventListener.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -24,6 +24,7 @@ package org.hibernate.event.internal; import java.io.Serializable; +import java.util.concurrent.TimeUnit; import org.hibernate.HibernateException; import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; @@ -117,7 +118,7 @@ final boolean stats = factory.getStatistics().isStatisticsEnabled(); long startTime = 0; if ( stats ) { - startTime = System.currentTimeMillis(); + startTime = System.nanoTime(); } final Serializable pk = event.getEntityPersister().loadEntityIdByNaturalId( @@ -129,10 +130,11 @@ if ( stats ) { final NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy = event.getEntityPersister().getNaturalIdCacheAccessStrategy(); final String regionName = naturalIdCacheAccessStrategy == null ? null : naturalIdCacheAccessStrategy.getRegion().getName(); - + final long endTime = System.nanoTime(); + final long milliseconds = TimeUnit.MILLISECONDS.convert( endTime - startTime, TimeUnit.NANOSECONDS ); factory.getStatisticsImplementor().naturalIdQueryExecuted( regionName, - System.currentTimeMillis() - startTime ); + milliseconds ); } //PK can be null if the entity doesn't exist Index: 3rdParty_sources/hibernate-core/org/hibernate/event/internal/EntityCopyAllowedLoggedObserver.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/event/internal/EntityCopyAllowedLoggedObserver.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/event/internal/EntityCopyAllowedLoggedObserver.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,190 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.event.internal; + +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import org.hibernate.event.spi.EventSource; +import org.hibernate.internal.CoreLogging; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.collections.IdentitySet; +import org.hibernate.pretty.MessageHelper; + +/** + * An {@link org.hibernate.event.spi.EntityCopyObserver} implementation that allows multiple representations of + * the same persistent entity to be merged and provides logging of the entity copies that + * that are detected. + * + * @author Gail Badner + */ +public class EntityCopyAllowedLoggedObserver extends EntityCopyAllowedObserver { + private static final CoreMessageLogger LOG = CoreLogging.messageLogger( EntityCopyAllowedLoggedObserver.class ); + + public static final String SHORT_NAME = "log"; + + // Tracks the number of entity copies per entity name. + private Map countsByEntityName; + + // managedToMergeEntitiesXref is only maintained for DEBUG logging so that a "nice" message + // about multiple representations can be logged at the completion of the top-level merge. + // If no entity copies have been detected, managedToMergeEntitiesXref will remain null; + private Map> managedToMergeEntitiesXref = null; + // key is the managed entity; + // value is the set of representations being merged corresponding to the same managed result. + + /** + * Indicates if DEBUG logging is enabled. + * + * @return true, if DEBUG logging is enabled. + */ + public static boolean isDebugLoggingEnabled() { + return LOG.isDebugEnabled(); + } + + @Override + public void entityCopyDetected( + Object managedEntity, + Object mergeEntity1, + Object mergeEntity2, + EventSource session) { + final String entityName = session.getEntityName( managedEntity ); + LOG.trace( + String.format( + "More than one representation of the same persistent entity being merged for: %s", + MessageHelper.infoString( + entityName, + session.getIdentifier( managedEntity ) + ) + ) + ); + Set detachedEntitiesForManaged = null; + if ( managedToMergeEntitiesXref == null ) { + // This is the first time multiple representations have been found; + // instantiate managedToMergeEntitiesXref. + managedToMergeEntitiesXref = new IdentityHashMap>(); + } + else { + // Get any existing representations that have already been found. + detachedEntitiesForManaged = managedToMergeEntitiesXref.get( managedEntity ); + } + if ( detachedEntitiesForManaged == null ) { + // There were no existing representations for this particular managed entity; + detachedEntitiesForManaged = new IdentitySet(); + managedToMergeEntitiesXref.put( managedEntity, detachedEntitiesForManaged ); + incrementEntityNameCount( entityName ); + } + // Now add the detached representation for the managed entity; + detachedEntitiesForManaged.add( mergeEntity1 ); + detachedEntitiesForManaged.add( mergeEntity2 ); + } + + private void incrementEntityNameCount(String entityName) { + Integer countBeforeIncrement = 0; + if ( countsByEntityName == null ) { + // Use a TreeMap so counts can be logged by entity name in alphabetic order. + countsByEntityName = new TreeMap(); + } + else { + countBeforeIncrement = countsByEntityName.get( entityName ); + if ( countBeforeIncrement == null ) { + // no entity copies for entityName detected previously. + countBeforeIncrement = 0; + } + } + countsByEntityName.put( entityName, countBeforeIncrement + 1 ); + } + + public void clear() { + if ( managedToMergeEntitiesXref != null ) { + managedToMergeEntitiesXref.clear(); + managedToMergeEntitiesXref = null; + } + if ( countsByEntityName != null ) { + countsByEntityName.clear(); + countsByEntityName = null; + } + } + + @Override + public void topLevelMergeComplete(EventSource session) { + // Log the summary. + if ( countsByEntityName != null ) { + for ( Map.Entry entry : countsByEntityName.entrySet() ) { + final String entityName = entry.getKey(); + final int count = entry.getValue(); + LOG.debug( + String.format( + "Summary: number of %s entities with multiple representations merged: %d", + entityName, + count + ) + ); + } + } + else { + LOG.debug( "No entity copies merged." ); + } + + if ( managedToMergeEntitiesXref != null ) { + for ( Map.Entry> entry : managedToMergeEntitiesXref.entrySet() ) { + Object managedEntity = entry.getKey(); + Set mergeEntities = entry.getValue(); + StringBuilder sb = new StringBuilder( "Details: merged ") + .append( mergeEntities.size() ) + .append( " representations of the same entity " ) + .append( + MessageHelper.infoString( + session.getEntityName( managedEntity ), + session.getIdentifier( managedEntity ) + ) + ) + .append( " being merged: " ); + boolean first = true; + for ( Object mergeEntity : mergeEntities ) { + if ( first ) { + first = false; + } + else { + sb.append( ", " ); + } + sb.append( getManagedOrDetachedEntityString( managedEntity, mergeEntity ) ); + } + sb.append( "; resulting managed entity: [" ).append( managedEntity ).append( ']' ); + LOG.debug( sb.toString()); + } + } + } + + private String getManagedOrDetachedEntityString(Object managedEntity, Object mergeEntity ) { + if ( mergeEntity == managedEntity) { + return "Managed: [" + mergeEntity + "]"; + } + else { + return "Detached: [" + mergeEntity + "]"; + } + } +} Index: 3rdParty_sources/hibernate-core/org/hibernate/event/internal/EntityCopyAllowedObserver.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/event/internal/EntityCopyAllowedObserver.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/event/internal/EntityCopyAllowedObserver.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,57 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.event.internal; + +import org.hibernate.event.spi.EntityCopyObserver; +import org.hibernate.event.spi.EventSource; + +/** + * An {@link org.hibernate.event.spi.EntityCopyObserver} implementation that allows multiple representations of + * the same persistent entity to be merged. + * + * @author Gail Badner + */ +public class EntityCopyAllowedObserver implements EntityCopyObserver { + + public static final String SHORT_NAME = "allow"; + + @Override + public void entityCopyDetected( + Object managedEntity, + Object mergeEntity1, + Object mergeEntity2, + EventSource session) { + // do nothing. + } + + public void clear() { + // do nothing. + } + + + @Override + public void topLevelMergeComplete(EventSource session) { + // do nothing. + } +} Index: 3rdParty_sources/hibernate-core/org/hibernate/event/internal/EntityCopyNotAllowedObserver.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/event/internal/EntityCopyNotAllowedObserver.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/event/internal/EntityCopyNotAllowedObserver.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,75 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.event.internal; + +import org.hibernate.AssertionFailure; +import org.hibernate.event.spi.EntityCopyObserver; +import org.hibernate.event.spi.EventSource; +import org.hibernate.pretty.MessageHelper; + +/** + * @author Gail Badner + */ +public class EntityCopyNotAllowedObserver implements EntityCopyObserver { + + public static final String SHORT_NAME = "disallow"; + + @Override + public void entityCopyDetected( + Object managedEntity, + Object mergeEntity1, + Object mergeEntity2, + EventSource session) { + if ( mergeEntity1 == managedEntity && mergeEntity2 == managedEntity) { + throw new AssertionFailure( "entity1 and entity2 are the same as managedEntity; must be different." ); + } + final String managedEntityString = MessageHelper.infoString( + session.getEntityName( managedEntity ), + session.getIdentifier( managedEntity ) + ); + throw new IllegalStateException( + "Multiple representations of the same entity " + managedEntityString + " are being merged. " + + getManagedOrDetachedEntityString( managedEntity, mergeEntity1 ) + "; " + + getManagedOrDetachedEntityString( managedEntity, mergeEntity2 ) + ); + } + + private String getManagedOrDetachedEntityString(Object managedEntity, Object entity ) { + if ( entity == managedEntity) { + return "Managed: [" + entity + "]"; + } + else { + return "Detached: [" + entity + "]"; + } + } + + public void clear() { + // Nothing to do + } + + @Override + public void topLevelMergeComplete(EventSource session) { + // Nothing to do + } +} Fisheye: Tag 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb refers to a dead (removed) revision in file `3rdParty_sources/hibernate-core/org/hibernate/event/internal/EventCache.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/hibernate-core/org/hibernate/event/internal/MergeContext.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/event/internal/MergeContext.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/event/internal/MergeContext.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,400 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2008-2014, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.event.internal; + +import java.util.Collection; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Set; + +import org.jboss.logging.Logger; + +import org.hibernate.event.spi.EntityCopyObserver; +import org.hibernate.event.spi.EventSource; +import org.hibernate.pretty.MessageHelper; + +/** + * MergeContext is a Map implementation that is intended to be used by a merge + * event listener to keep track of each entity being merged and their corresponding + * managed result. Entities to be merged may to be added to the MergeContext before + * the merge operation has cascaded to that entity. + * + * "Merge entity" and "mergeEntity" method parameter refer to an entity that is (or will be) + * merged via {@link org.hibernate.event.spi.EventSource#merge(Object mergeEntity)}. + * + * "Managed entity" and "managedEntity" method parameter refer to the managed entity that is + * the result of merging an entity. + * + * A merge entity can be transient, detached, or managed. If it is managed, then it must be + * the same as its associated entity result. + * + * If {@link #put(Object mergeEntity, Object managedEntity)} is called, and this + * MergeContext already contains an entry with a different entity as the key, but + * with the same (managedEntity) value, this means that multiple entity representations + * for the same persistent entity are being merged. If this happens, + * {@link org.hibernate.event.spi.EntityCopyObserver#entityCopyDetected( + * Object managedEntity, Object mergeEntity1, Object mergeEntity2, org.hibernate.event.spi.EventSource)} + * will be called. It is up to that method to determine the property course of + * action for this situation. + * + * There are several restrictions. + *
    + *
  • Methods that return collections (e.g., {@link #keySet()}, + * {@link #values()}, {@link #entrySet()}) return an + * unnmodifiable view of the collection;
  • + *
  • If {@link #put(Object mergeEntity, Object) managedEntity} or + * {@link #put(Object mergeEntity, Object managedEntity, boolean isOperatedOn)} + * is executed and this MergeMap already contains a cross-reference for + * mergeEntity, then managedEntity must be the + * same as what is already associated with mergeEntity in this + * MergeContext. + *
  • + *
  • If {@link #putAll(Map map)} is executed, the previous restriction + * applies to each entry in the Map;
  • + *
  • The {@link #remove(Object)} operation is not supported; + * The only way to remove data from a MergeContext is by calling + * {@link #clear()};
  • + *
  • the Map returned by {@link #invertMap()} will only contain the + * managed-to-merge entity cross-reference to its "newest" + * (most recently added) merge entity.
  • + *
+ *

+ * The following method is intended to be used by a merge event listener (and other + * classes) in the same package to add a merge entity and its corresponding + * managed entity to a MergeContext and indicate if the merge operation is + * being performed on the merge entity yet.

+ * {@link MergeContext#put(Object mergeEntity, Object managedEntity, boolean isOperatedOn)} + *

+ * The following method is intended to be used by a merge event listener (and other + * classes) in the same package to indicate whether the merge operation is being + * performed on a merge entity already in the MergeContext: + * {@link MergeContext#setOperatedOn(Object mergeEntity, boolean isOperatedOn) + * + * @author Gail Badner + */ +class MergeContext implements Map { + private static final Logger LOG = Logger.getLogger( MergeContext.class ); + + private final EventSource session; + private final EntityCopyObserver entityCopyObserver; + + private Map mergeToManagedEntityXref = new IdentityHashMap(10); + // key is an entity to be merged; + // value is the associated managed entity (result) in the persistence context. + + private Map managedToMergeEntityXref = new IdentityHashMap( 10 ); + // maintains the inverse of the mergeToManagedEntityXref for performance reasons. + // key is the managed entity result in the persistence context. + // value is the associated entity to be merged; if multiple + // representations of the same persistent entity are added to the MergeContext, + // value will be the most recently added merge entity that is + // associated with the managed entity. + + // TODO: merge mergeEntityToOperatedOnFlagMap into mergeToManagedEntityXref, since they have the same key. + // need to check if this would hurt performance. + private Map mergeEntityToOperatedOnFlagMap = new IdentityHashMap( 10 ); + // key is a merge entity; + // value is a flag indicating if the merge entity is currently in the merge process. + + MergeContext(EventSource session, EntityCopyObserver entityCopyObserver){ + this.session = session; + this.entityCopyObserver = entityCopyObserver; + } + + /** + * Clears the MergeContext. + */ + public void clear() { + mergeToManagedEntityXref.clear(); + managedToMergeEntityXref.clear(); + mergeEntityToOperatedOnFlagMap.clear(); + } + + /** + * Returns true if this MergeContext contains a cross-reference for the specified merge entity + * to a managed entity result. + * + * @param mergeEntity must be non-null + * @return true if this MergeContext contains a cross-reference for the specified merge entity + * @throws NullPointerException if mergeEntity is null + */ + public boolean containsKey(Object mergeEntity) { + if ( mergeEntity == null ) { + throw new NullPointerException( "null entities are not supported by " + getClass().getName() ); + } + return mergeToManagedEntityXref.containsKey( mergeEntity ); + } + + /** + * Returns true if this MergeContext contains a cross-reference from the specified managed entity + * to a merge entity. + * @param managedEntity must be non-null + * @return true if this MergeContext contains a cross-reference from the specified managed entity + * to a merge entity + * @throws NullPointerException if managedEntity is null + */ + public boolean containsValue(Object managedEntity) { + if ( managedEntity == null ) { + throw new NullPointerException( "null copies are not supported by " + getClass().getName() ); + } + return managedToMergeEntityXref.containsKey( managedEntity ); + } + + /** + * Returns an unmodifiable set view of the merge-to-managed entity cross-references contained in this MergeContext. + * @return an unmodifiable set view of the merge-to-managed entity cross-references contained in this MergeContext + * + * @see {@link Collections#unmodifiableSet(java.util.Set)} + */ + public Set entrySet() { + return Collections.unmodifiableSet( mergeToManagedEntityXref.entrySet() ); + } + + /** + * Returns the managed entity associated with the specified merge Entity. + * @param mergeEntity the merge entity; must be non-null + * @return the managed entity associated with the specified merge Entity + * @throws NullPointerException if mergeEntity is null + */ + public Object get(Object mergeEntity) { + if ( mergeEntity == null ) { + throw new NullPointerException( "null entities are not supported by " + getClass().getName() ); + } + return mergeToManagedEntityXref.get( mergeEntity ); + } + + /** + * Returns true if this MergeContext contains no merge-to-managed entity cross-references. + * @return true if this MergeContext contains no merge-to-managed entity cross-references. + */ + public boolean isEmpty() { + return mergeToManagedEntityXref.isEmpty(); + } + + /** + * Returns an unmodifiable set view of the merge entities contained in this MergeContext + * @return an unmodifiable set view of the merge entities contained in this MergeContext + * + * @see {@link Collections#unmodifiableSet(java.util.Set)} + */ + public Set keySet() { + return Collections.unmodifiableSet( mergeToManagedEntityXref.keySet() ); + } + + /** + * Associates the specified merge entity with the specified managed entity result in this MergeContext. + * If this MergeContext already contains a cross-reference for mergeEntity when this + * method is called, then managedEntity must be the same as what is already associated + * with mergeEntity. + *

+ * This method assumes that the merge process is not yet operating on mergeEntity. + * Later when mergeEntity enters the merge process, {@link #setOperatedOn(Object, boolean)} + * should be called. + *

+ * @param mergeEntity the merge entity; must be non-null + * @param managedEntity the managed entity result; must be non-null + * @return previous managed entity associated with specified merge entity, or null if + * there was no mapping for mergeEntity. + * @throws NullPointerException if mergeEntity or managedEntity is null + * @throws IllegalArgumentException if managedEntity is not the same as the previous + * managed entity associated with merge entity + * @throws IllegalStateException if internal cross-references are out of sync, + */ + public Object put(Object mergeEntity, Object managedEntity) { + return put( mergeEntity, managedEntity, Boolean.FALSE ); + } + + /** + * Associates the specified merge entity with the specified managed entity in this MergeContext. + * If this MergeContext already contains a cross-reference for mergeEntity when this + * method is called, then managedEntity must be the same as what is already associated + * with mergeEntity. + * + * @param mergeEntity the mergge entity; must be non-null + * @param managedEntity the managed entity; must be non-null + * @param isOperatedOn indicates if the merge operation is performed on the mergeEntity. + * + * @return previous managed entity associated with specified merge entity, or null if + * there was no mapping for mergeEntity. + * @throws NullPointerException if mergeEntity or managedEntity is null + * @throws IllegalArgumentException if managedEntity is not the same as the previous + * managed entity associated with mergeEntity + * @throws IllegalStateException if internal cross-references are out of sync, + */ + /* package-private */ Object put(Object mergeEntity, Object managedEntity, boolean isOperatedOn) { + if ( mergeEntity == null || managedEntity == null ) { + throw new NullPointerException( "null merge and managed entities are not supported by " + getClass().getName() ); + } + + Object oldManagedEntity = mergeToManagedEntityXref.put( mergeEntity, managedEntity ); + Boolean oldOperatedOn = mergeEntityToOperatedOnFlagMap.put( mergeEntity, isOperatedOn ); + // If managedEntity already corresponds with a different merge entity, that means + // that there are multiple entities being merged that correspond with managedEntity. + // In the following, oldMergeEntity will be replaced with mergeEntity in managedToMergeEntityXref. + Object oldMergeEntity = managedToMergeEntityXref.put( managedEntity, mergeEntity ); + + if ( oldManagedEntity == null ) { + // this is a new mapping for mergeEntity in mergeToManagedEntityXref + if ( oldMergeEntity != null ) { + // oldMergeEntity was a different merge entity with the same corresponding managed entity; + entityCopyObserver.entityCopyDetected( + managedEntity, + mergeEntity, + oldMergeEntity, + session + ); + } + if ( oldOperatedOn != null ) { + throw new IllegalStateException( + "MergeContext#mergeEntityToOperatedOnFlagMap contains an merge entity " + printEntity( mergeEntity ) + + ", but MergeContext#mergeToManagedEntityXref does not." + ); + } + } + else { + // mergeEntity was already mapped in mergeToManagedEntityXref + if ( oldManagedEntity != managedEntity ) { + throw new IllegalArgumentException( + "Error occurred while storing a merge Entity " + printEntity( mergeEntity ) + + ". It was previously associated with managed entity " + printEntity( oldManagedEntity ) + + ". Attempted to replace managed entity with " + printEntity( managedEntity ) + ); + } + if ( oldOperatedOn == null ) { + throw new IllegalStateException( + "MergeContext#mergeToManagedEntityXref contained an mergeEntity " + printEntity( mergeEntity ) + + ", but MergeContext#mergeEntityToOperatedOnFlagMap did not." + ); + } + } + + return oldManagedEntity; + } + + /** + * Copies all of the mappings from the specified Map to this MergeContext. + * The key and value for each entry in map is subject to the same + * restrictions as {@link #put(Object mergeEntity, Object managedEntity)}. + * + * This method assumes that the merge process is not yet operating on any merge entity + * + * @param map keys and values must be non-null + * @throws NullPointerException if any key or value is null + * @throws IllegalArgumentException if a key in map was already in this MergeContext + * but associated value in map is different from the previous value in this MergeContext. + * @throws IllegalStateException if internal cross-references are out of sync, + */ + public void putAll(Map map) { + for ( Object o : map.entrySet() ) { + Entry entry = (Entry) o; + put( entry.getKey(), entry.getValue() ); + } + } + + /** + * The remove operation is not supported. + * @param mergeEntity the merge entity. + * @throws UnsupportedOperationException if called. + */ + public Object remove(Object mergeEntity) { + throw new UnsupportedOperationException( + String.format( "Operation not supported: %s.remove()", getClass().getName() ) + ); + } + + /** + * Returns the number of merge-to-managed entity cross-references in this MergeContext + * @return the number of merge-to-managed entity cross-references in this MergeContext + */ + public int size() { + return mergeToManagedEntityXref.size(); + } + + /** + * Returns an unmodifiable Set view of managed entities contained in this MergeContext. + * @return an unmodifiable Set view of managed entities contained in this MergeContext + * + * @see {@link Collections#unmodifiableSet(java.util.Set)} + */ + public Collection values() { + return Collections.unmodifiableSet( managedToMergeEntityXref.keySet() ); + } + + /** + * Returns true if the listener is performing the merge operation on the specified merge entity. + * @param mergeEntity the merge entity; must be non-null + * @return true if the listener is performing the merge operation on the specified merge entity; + * false, if there is no mapping for mergeEntity. + * @throws NullPointerException if mergeEntity is null + */ + public boolean isOperatedOn(Object mergeEntity) { + if ( mergeEntity == null ) { + throw new NullPointerException( "null merge entities are not supported by " + getClass().getName() ); + } + final Boolean isOperatedOn = mergeEntityToOperatedOnFlagMap.get( mergeEntity ); + return isOperatedOn == null ? false : isOperatedOn; + } + + /** + * Set flag to indicate if the listener is performing the merge operation on the specified merge entity. + * @param mergeEntity must be non-null and this MergeContext must contain a cross-reference for mergeEntity + * to a managed entity + * @throws NullPointerException if mergeEntity is null + * @throws IllegalStateException if this MergeContext does not contain a a cross-reference for mergeEntity + */ + /* package-private */ void setOperatedOn(Object mergeEntity, boolean isOperatedOn) { + if ( mergeEntity == null ) { + throw new NullPointerException( "null entities are not supported by " + getClass().getName() ); + } + if ( ! mergeEntityToOperatedOnFlagMap.containsKey( mergeEntity ) || + ! mergeToManagedEntityXref.containsKey( mergeEntity ) ) { + throw new IllegalStateException( "called MergeContext#setOperatedOn() for mergeEntity not found in MergeContext" ); + } + mergeEntityToOperatedOnFlagMap.put( mergeEntity, isOperatedOn ); + } + + /** + * Returns an unmodifiable map view of the managed-to-merge entity + * cross-references. + * + * The returned Map will contain a cross-reference from each managed entity + * to the most recently associated merge entity that was most recently put in the MergeContext. + * + * @return an unmodifiable map view of the managed-to-merge entity cross-references. + * + * @see {@link Collections#unmodifiableMap(java.util.Map)} + */ + public Map invertMap() { + return Collections.unmodifiableMap( managedToMergeEntityXref ); + } + + private String printEntity(Object entity) { + if ( session.getPersistenceContext().getEntry( entity ) != null ) { + return MessageHelper.infoString( session.getEntityName( entity ), session.getIdentifier( entity ) ); + } + // Entity was not found in current persistence context. Use Object#toString() method. + return "[" + entity + "]"; + } +} Index: 3rdParty_sources/hibernate-core/org/hibernate/event/spi/EntityCopyObserver.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/event/spi/EntityCopyObserver.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/event/spi/EntityCopyObserver.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,56 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.event.spi; + +import org.hibernate.event.spi.EventSource; + +/** + * An observer for detection of multiple entity representations for a persistent entity being merged. + * + * @author Gail Badner + */ +public interface EntityCopyObserver { + + /** + * Called when more than one representation of the same persistent entity is being merged. + * + * @param managedEntity The managed entity in the persistence context (the merge result). + * @param mergeEntity1 A managed or detached entity being merged; must be non-null. + * @param mergeEntity2 A different managed or detached entity being merged; must be non-null. + * @param session The session. + */ + void entityCopyDetected(Object managedEntity, Object mergeEntity1, Object mergeEntity2, EventSource session); + + /** + * Called when the top-level merge operation is complete. + * + * @param session The session + */ + void topLevelMergeComplete(EventSource session); + + /** + * Called to clear any data stored in this EntityCopyObserver. + */ + void clear(); +} Index: 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/HqlParser.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/HqlParser.java (.../HqlParser.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/HqlParser.java (.../HqlParser.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -415,6 +415,25 @@ } @Override + public void expectNamedParameterName() throws TokenStreamException { + // we expect the token following a COLON (':') to be the name of a named parameter. + // if the following token is anything other than IDENT we convert its type if possible. + + // NOTE : the LT() call is more expensive than the LA() call; so we + // use LA() first to see if LT() is needed. + if ( LA( 1 ) != IDENT ) { + final HqlToken nextToken = (HqlToken) LT( 1 ); + if ( nextToken.isPossibleID() ) { + LOG.debugf( + "Converting keyword [%s] following COLON to IDENT as an expected parameter name", + nextToken.getText() + ); + nextToken.setType( IDENT ); + } + } + } + + @Override public void handleDotIdent() throws TokenStreamException { // This handles HHH-354, where there is a strange property name in a where clause. // If the lookahead contains a DOT then something that isn't an IDENT... Index: 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/HqlSqlWalker.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/HqlSqlWalker.java (.../HqlSqlWalker.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/HqlSqlWalker.java (.../HqlSqlWalker.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -47,6 +47,7 @@ import org.hibernate.hql.internal.antlr.SqlTokenTypes; import org.hibernate.hql.internal.ast.tree.AggregateNode; import org.hibernate.hql.internal.ast.tree.AssignmentSpecification; +import org.hibernate.hql.internal.ast.tree.CastFunctionNode; import org.hibernate.hql.internal.ast.tree.CollectionFunction; import org.hibernate.hql.internal.ast.tree.ConstructorNode; import org.hibernate.hql.internal.ast.tree.DeleteStatement; @@ -1077,6 +1078,12 @@ } @Override + protected void processCastFunction(AST castFunctionCall, boolean inSelect) throws SemanticException { + CastFunctionNode castFunctionNode = (CastFunctionNode) castFunctionCall; + castFunctionNode.resolve( inSelect ); + } + + @Override protected void processAggregation(AST node, boolean inSelect) throws SemanticException { AggregateNode aggregateNode = (AggregateNode) node; aggregateNode.resolve(); Index: 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/SqlASTFactory.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/SqlASTFactory.java (.../SqlASTFactory.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/SqlASTFactory.java (.../SqlASTFactory.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -32,8 +32,9 @@ import org.hibernate.hql.internal.ast.tree.BinaryArithmeticOperatorNode; import org.hibernate.hql.internal.ast.tree.BinaryLogicOperatorNode; import org.hibernate.hql.internal.ast.tree.BooleanLiteralNode; -import org.hibernate.hql.internal.ast.tree.Case2Node; -import org.hibernate.hql.internal.ast.tree.CaseNode; +import org.hibernate.hql.internal.ast.tree.CastFunctionNode; +import org.hibernate.hql.internal.ast.tree.SearchedCaseNode; +import org.hibernate.hql.internal.ast.tree.SimpleCaseNode; import org.hibernate.hql.internal.ast.tree.CollectionFunction; import org.hibernate.hql.internal.ast.tree.ConstructorNode; import org.hibernate.hql.internal.ast.tree.CountNode; @@ -133,6 +134,8 @@ return SqlFragment.class; case METHOD_CALL: return MethodNode.class; + case CAST: + return CastFunctionNode.class; case ELEMENTS: case INDICES: return CollectionFunction.class; @@ -171,9 +174,9 @@ case UNARY_PLUS: return UnaryArithmeticNode.class; case CASE2: - return Case2Node.class; + return SimpleCaseNode.class; case CASE: - return CaseNode.class; + return SearchedCaseNode.class; case PARAM: case NAMED_PARAM: return ParameterNode.class; Index: 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/SqlGenerator.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/SqlGenerator.java (.../SqlGenerator.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/SqlGenerator.java (.../SqlGenerator.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -44,6 +44,7 @@ import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; +import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.param.ParameterSpecification; import org.hibernate.type.Type; @@ -145,8 +146,8 @@ } @Override - protected void commaBetweenParameters(String comma) { - writer.commaBetweenParameters( comma ); + protected void betweenFunctionArguments() { + writer.betweenFunctionArguments(); } @Override @@ -208,7 +209,12 @@ else { // this function has a registered SQLFunction -> redirect output and catch the arguments outputStack.addFirst( writer ); - writer = new FunctionArguments(); + if ( node.getType() == CAST ) { + writer = new CastFunctionArguments(); + } + else { + writer = new StandardFunctionArguments(); + } } } @@ -222,7 +228,7 @@ else { final Type functionType = functionNode.getFirstArgumentType(); // this function has a registered SQLFunction -> redirect output and catch the arguments - FunctionArguments functionArguments = (FunctionArguments) writer; + FunctionArgumentsCollectingWriter functionArguments = (FunctionArgumentsCollectingWriter) writer; writer = outputStack.removeFirst(); out( sqlFunction.render( functionType, functionArguments.getArgs(), sessionFactory ) ); } @@ -236,21 +242,18 @@ interface SqlWriter { void clause(String clause); - /** - * todo remove this hack - * The parameter is either ", " or " , ". This is needed to pass sql generating tests as the old - * sql generator uses " , " in the WHERE and ", " in SELECT. - * - * @param comma either " , " or ", " - */ - void commaBetweenParameters(String comma); + void betweenFunctionArguments(); } + interface FunctionArgumentsCollectingWriter extends SqlWriter { + public List getArgs(); + } + /** * SQL function processing code redirects generated SQL output to an instance of this class * which catches function arguments. */ - class FunctionArguments implements SqlWriter { + class StandardFunctionArguments implements FunctionArgumentsCollectingWriter { private int argInd; private final List args = new ArrayList( 3 ); @@ -265,7 +268,7 @@ } @Override - public void commaBetweenParameters(String comma) { + public void betweenFunctionArguments() { ++argInd; } @@ -275,6 +278,52 @@ } /** + * SQL function processing code redirects generated SQL output to an instance of this class + * which catches function arguments. + */ + class CastFunctionArguments implements FunctionArgumentsCollectingWriter { + private String castExpression; + private String castTargetType; + + private boolean startedType; + + @Override + public void clause(String clause) { + if ( startedType ) { + if ( castTargetType == null ) { + castTargetType = clause; + } + else { + castTargetType += clause; + } + } + else { + if ( castExpression == null ) { + castExpression = clause; + } + else { + castExpression += clause; + } + } + } + + @Override + public void betweenFunctionArguments() { + if ( startedType ) { + throw new QueryException( "CAST function should only have 2 arguments" ); + } + startedType = true; + } + + public List getArgs() { + List rtn = CollectionHelper.arrayList( 2 ); + rtn.add( castExpression ); + rtn.add( castTargetType ); + return rtn; + } + } + + /** * The default SQL writer. */ class DefaultWriter implements SqlWriter { @@ -284,8 +333,8 @@ } @Override - public void commaBetweenParameters(String comma) { - getStringBuilder().append( comma ); + public void betweenFunctionArguments() { + getStringBuilder().append( ", " ); } } Fisheye: Tag 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb refers to a dead (removed) revision in file `3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/tree/Case2Node.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb refers to a dead (removed) revision in file `3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/tree/CaseNode.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/tree/CastFunctionNode.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/tree/CastFunctionNode.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/tree/CastFunctionNode.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,115 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.hql.internal.ast.tree; + +import org.hibernate.QueryException; +import org.hibernate.dialect.function.CastFunction; +import org.hibernate.dialect.function.SQLFunction; +import org.hibernate.hql.internal.ast.util.ColumnHelper; +import org.hibernate.type.Type; + +import antlr.SemanticException; + +/** + * Represents a cast function call. We handle this specially because its type + * argument has a semantic meaning to the HQL query (its not just pass through). + * + * @author Steve Ebersole + */ +public class CastFunctionNode extends AbstractSelectExpression implements FunctionNode { + private SQLFunction dialectCastFunction; + + private Node expressionNode; + + private IdentNode typeNode; + private Type castType; + + + /** + * Called from the hql-sql grammar after the children of the CAST have been resolved. + * + * @param inSelect Is this call part of the SELECT clause? + */ + public void resolve(boolean inSelect) { + this.dialectCastFunction = getSessionFactoryHelper().findSQLFunction( "cast" ); + if ( dialectCastFunction == null ) { + dialectCastFunction = CastFunction.INSTANCE; + } + + this.expressionNode = (Node) getFirstChild(); + if ( expressionNode == null ) { + throw new QueryException( "Could not resolve expression to CAST" ); + } + if ( SqlNode.class.isInstance( expressionNode ) ) { + final Type expressionType = ( (SqlNode) expressionNode ).getDataType(); + if ( expressionType != null ) { + if ( expressionType.isEntityType() ) { + throw new QueryException( "Expression to CAST cannot be an entity : " + expressionNode.getText() ); + } + if ( expressionType.isComponentType() ) { + throw new QueryException( "Expression to CAST cannot be a composite : " + expressionNode.getText() ); + } + if ( expressionType.isCollectionType() ) { + throw new QueryException( "Expression to CAST cannot be a collection : " + expressionNode.getText() ); + } + } + } + + this.typeNode = (IdentNode) expressionNode.getNextSibling(); + if ( typeNode == null ) { + throw new QueryException( "Could not resolve requested type for CAST" ); + } + + final String typeName = typeNode.getText(); + this.castType = getSessionFactoryHelper().getFactory().getTypeResolver().heuristicType( typeName ); + if ( castType == null ) { + throw new QueryException( "Could not resolve requested type for CAST : " + typeName ); + } + if ( castType.isEntityType() ) { + throw new QueryException( "CAST target type cannot be an entity : " + expressionNode.getText() ); + } + if ( castType.isComponentType() ) { + throw new QueryException( "CAST target type cannot be a composite : " + expressionNode.getText() ); + } + if ( castType.isCollectionType() ) { + throw new QueryException( "CAST target type cannot be a collection : " + expressionNode.getText() ); + } + setDataType( castType ); + } + + @Override + public SQLFunction getSQLFunction() { + return dialectCastFunction; + } + + @Override + public Type getFirstArgumentType() { + return castType; + } + + @Override + public void setScalarColumnText(int i) throws SemanticException { + ColumnHelper.generateSingleScalarColumn( this, i ); + } +} Index: 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/tree/DotNode.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/tree/DotNode.java (.../DotNode.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/tree/DotNode.java (.../DotNode.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -475,10 +475,8 @@ /////////////////////////////////////////////////////////////////////////////// boolean found = elem != null; - // even though we might find a pre-existing element by join path, for FromElements originating in a from-clause - // we should only ever use the found element if the aliases match (null != null here). Implied joins are - // always (?) ok to reuse. - boolean useFoundFromElement = found && ( elem.isImplied() || areSame( classAlias, elem.getClassAlias() ) ); + // even though we might find a pre-existing element by join path, we may not be able to reuse it... + boolean useFoundFromElement = found && canReuse( elem ); if ( !useFoundFromElement ) { // If this is an implied join in a from element, then use the impled join type which is part of the @@ -527,9 +525,14 @@ setFromElement( elem ); // This 'dot' expression now refers to the resulting from element. } - private boolean areSame(String alias1, String alias2) { - // again, null != null here - return !StringHelper.isEmpty( alias1 ) && !StringHelper.isEmpty( alias2 ) && alias1.equals( alias2 ); + private boolean canReuse(FromElement fromElement) { + // if the from-clauses are the same, we can be a little more aggressive in terms of what we reuse + if ( fromElement.getFromClause() == getWalker().getCurrentFromClause() ) { + return true; + } + + // otherwise (subquery case) dont reuse the fromElement if we are processing the from-clause of the subquery + return getWalker().getCurrentClauseType() != SqlTokenTypes.FROM; } private void setImpliedJoin(FromElement elem) { Index: 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/tree/MethodNode.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/tree/MethodNode.java (.../MethodNode.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/tree/MethodNode.java (.../MethodNode.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -133,13 +133,9 @@ if ( function != null ) { AST firstChild = exprList != null ? exprList.getFirstChild() : null; Type functionReturnType = getSessionFactoryHelper() - .findFunctionReturnType( methodName, firstChild ); + .findFunctionReturnType( methodName, function, firstChild ); setDataType( functionReturnType ); } - //TODO: - /*else { - methodName = (String) getWalker().getTokenReplacements().get( methodName ); - }*/ } public boolean isCollectionPropertyMethod() { Index: 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/tree/SearchedCaseNode.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/tree/SearchedCaseNode.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/tree/SearchedCaseNode.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,88 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + * + */ +package org.hibernate.hql.internal.ast.tree; + +import org.hibernate.QueryException; +import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes; +import org.hibernate.hql.internal.ast.util.ASTUtil; +import org.hibernate.hql.internal.ast.util.ColumnHelper; +import org.hibernate.type.Type; + +import antlr.SemanticException; +import antlr.collections.AST; + +/** + * Models what ANSI SQL terms a searched case expression. This is a CASE expression + * in the form

+ * CASE
+ *     WHEN [firstCondition] THEN [firstResult]
+ *     WHEN [secondCondition] THEN [secondResult]
+ *     ELSE [defaultResult]
+ * END
+ * 
+ * + * @author Gavin King + * @author Steve Ebersole + */ +public class SearchedCaseNode extends AbstractSelectExpression implements SelectExpression { + @Override + public Type getDataType() { + // option is used to hold each WHEN/ELSE in turn + AST option = getFirstChild(); + while ( option != null ) { + final AST result; + if ( option.getType() == HqlSqlTokenTypes.WHEN ) { + result = option.getFirstChild().getNextSibling(); + } + else if ( option.getType() == HqlSqlTokenTypes.ELSE ) { + result = option.getFirstChild(); + } + else { + throw new QueryException( + "Unexpected node type :" + + ASTUtil.getTokenTypeName( HqlSqlTokenTypes.class, option.getType() ) + + "; expecting WHEN or ELSE" + ); + } + + if ( SqlNode.class.isInstance( result ) ) { + final Type nodeDataType = ( (SqlNode) result ).getDataType(); + if ( nodeDataType != null ) { + return nodeDataType; + } + } + + option = option.getNextSibling(); + } + + throw new QueryException( "Could not determine data type for searched case statement" ); + } + + @Override + public void setScalarColumnText(int i) throws SemanticException { + ColumnHelper.generateSingleScalarColumn( this, i ); + } + +} Index: 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/tree/SimpleCaseNode.java =================================================================== diff -u --- 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/tree/SimpleCaseNode.java (revision 0) +++ 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/ast/tree/SimpleCaseNode.java (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -0,0 +1,87 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + * + */ +package org.hibernate.hql.internal.ast.tree; + +import org.hibernate.QueryException; +import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes; +import org.hibernate.hql.internal.ast.util.ASTUtil; +import org.hibernate.hql.internal.ast.util.ColumnHelper; +import org.hibernate.type.Type; + +import antlr.SemanticException; +import antlr.collections.AST; + +/** + * Models what ANSI SQL terms a simple case statement. This is a CASE expression in the form
+ * CASE [expression]
+ *     WHEN [firstCondition] THEN [firstResult]
+ *     WHEN [secondCondition] THEN [secondResult]
+ *     ELSE [defaultResult]
+ * END
+ * 
+ * + * @author Gavin King + * @author Steve Ebersole + */ +public class SimpleCaseNode extends AbstractSelectExpression implements SelectExpression { + + public Type getDataType() { + final AST expression = getFirstChild(); + // option is used to hold each WHEN/ELSE in turn + AST option = expression.getNextSibling(); + while ( option != null ) { + final AST result; + if ( option.getType() == HqlSqlTokenTypes.WHEN ) { + result = option.getFirstChild().getNextSibling(); + } + else if ( option.getType() == HqlSqlTokenTypes.ELSE ) { + result = option.getFirstChild(); + } + else { + throw new QueryException( + "Unexpected node type :" + + ASTUtil.getTokenTypeName( HqlSqlTokenTypes.class, option.getType() ) + + "; expecting WHEN or ELSE" + ); + } + + if ( SqlNode.class.isInstance( result ) ) { + final Type nodeDataType = ( (SqlNode) result ).getDataType(); + if ( nodeDataType != null ) { + return nodeDataType; + } + } + + option = option.getNextSibling(); + } + + throw new QueryException( "Could not determine data type for simple case statement" ); + } + + public void setScalarColumnText(int i) throws SemanticException { + ColumnHelper.generateSingleScalarColumn( this, i ); + } + +} Index: 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/classic/QueryTranslatorImpl.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/classic/QueryTranslatorImpl.java (.../QueryTranslatorImpl.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/hql/internal/classic/QueryTranslatorImpl.java (.../QueryTranslatorImpl.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -39,6 +39,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeUnit; import org.hibernate.HibernateException; import org.hibernate.LockMode; @@ -948,7 +949,7 @@ boolean stats = session.getFactory().getStatistics().isStatisticsEnabled(); long startTime = 0; - if ( stats ) startTime = System.currentTimeMillis(); + if ( stats ) startTime = System.nanoTime(); try { final List afterLoadActions = new ArrayList(); @@ -959,10 +960,12 @@ Iterator result = new IteratorImpl( rs, st, session, queryParameters.isReadOnly( session ), returnTypes, getColumnNames(), hi ); if ( stats ) { + final long endTime = System.nanoTime(); + final long milliseconds = TimeUnit.MILLISECONDS.convert( endTime - startTime, TimeUnit.NANOSECONDS ); session.getFactory().getStatisticsImplementor().queryExecuted( "HQL: " + queryString, 0, - System.currentTimeMillis() - startTime + milliseconds ); } Index: 3rdParty_sources/hibernate-core/org/hibernate/id/enhanced/NoopOptimizer.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/id/enhanced/NoopOptimizer.java (.../NoopOptimizer.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/id/enhanced/NoopOptimizer.java (.../NoopOptimizer.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -31,13 +31,10 @@ * An optimizer that performs no optimization. The database is hit for * every request. * - * @deprecated This is the fallback Optimizer chosen when we fail to instantiate one - * of the proper implementations. Using this implementation is probably a performance - * problem. + * Using this implementation is probably not the most efficient choice. */ -@Deprecated public final class NoopOptimizer extends AbstractOptimizer { - private volatile IntegralDataTypeHolder lastSourceValue; + private IntegralDataTypeHolder lastSourceValue; /** * Constructs a NoopOptimizer @@ -50,9 +47,13 @@ } @Override - public synchronized Serializable generate(AccessCallback callback) { - // IMPL NOTE : it is incredibly important that the method-local variable be used here to - // avoid concurrency issues. + public Serializable generate(AccessCallback callback) { + // IMPL NOTE : this method is called concurrently and is + // not synchronized. It is very important to work on the + // local variable: the field lastSourceValue is not + // reliable as it might be mutated by multipled threads. + // The lastSourceValue field is only accessed by tests, + // so this is not a concern. IntegralDataTypeHolder value = null; while ( value == null || value.lt( 1 ) ) { value = callback.getNextValue(); Index: 3rdParty_sources/hibernate-core/org/hibernate/loader/Loader.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/loader/Loader.java (.../Loader.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/loader/Loader.java (.../Loader.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -38,6 +38,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeUnit; import org.hibernate.AssertionFailure; import org.hibernate.HibernateException; @@ -1592,7 +1593,7 @@ ); // see if the entity defines reference caching, and if so use the cached reference (if one). - if ( persister.canUseReferenceCacheEntries() ) { + if ( session.getCacheMode().isGetEnabled() && persister.canUseReferenceCacheEntries() ) { final Object cachedEntry = CacheHelper.fromSharedCache( session, session.generateCacheKey( @@ -2546,7 +2547,7 @@ final boolean stats = getFactory().getStatistics().isStatisticsEnabled(); long startTime = 0; - if ( stats ) startTime = System.currentTimeMillis(); + if ( stats ) startTime = System.nanoTime(); List result; try { @@ -2561,10 +2562,12 @@ } if ( stats ) { + final long endTime = System.nanoTime(); + final long milliseconds = TimeUnit.MILLISECONDS.convert( endTime - startTime, TimeUnit.NANOSECONDS ); getFactory().getStatisticsImplementor().queryExecuted( getQueryIdentifier(), result.size(), - System.currentTimeMillis() - startTime + milliseconds ); } @@ -2616,7 +2619,7 @@ final boolean stats = getQueryIdentifier() != null && getFactory().getStatistics().isStatisticsEnabled(); long startTime = 0; - if ( stats ) startTime = System.currentTimeMillis(); + if ( stats ) startTime = System.nanoTime(); try { // Don't use Collections#emptyList() here -- follow on locking potentially adds AfterLoadActions, @@ -2626,10 +2629,12 @@ final PreparedStatement st = (PreparedStatement) wrapper.getStatement(); if ( stats ) { + final long endTime = System.nanoTime(); + final long milliseconds = TimeUnit.MILLISECONDS.convert( endTime - startTime, TimeUnit.NANOSECONDS ); getFactory().getStatisticsImplementor().queryExecuted( getQueryIdentifier(), 0, - System.currentTimeMillis() - startTime + milliseconds ); } Index: 3rdParty_sources/hibernate-core/org/hibernate/loader/hql/QueryLoader.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/loader/hql/QueryLoader.java (.../QueryLoader.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/loader/hql/QueryLoader.java (.../QueryLoader.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -32,6 +32,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.concurrent.TimeUnit; import org.hibernate.HibernateException; import org.hibernate.LockMode; @@ -509,7 +510,7 @@ final boolean stats = session.getFactory().getStatistics().isStatisticsEnabled(); long startTime = 0; if ( stats ) { - startTime = System.currentTimeMillis(); + startTime = System.nanoTime(); } try { @@ -530,11 +531,13 @@ ); if ( stats ) { + final long endTime = System.nanoTime(); + final long milliseconds = TimeUnit.MILLISECONDS.convert( endTime - startTime, TimeUnit.NANOSECONDS ); session.getFactory().getStatisticsImplementor().queryExecuted( // "HQL: " + queryTranslator.getQueryString(), getQueryIdentifier(), 0, - System.currentTimeMillis() - startTime + milliseconds ); } Index: 3rdParty_sources/hibernate-core/org/hibernate/loader/plan/build/internal/spaces/CollectionQuerySpaceImpl.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/loader/plan/build/internal/spaces/CollectionQuerySpaceImpl.java (.../CollectionQuerySpaceImpl.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/loader/plan/build/internal/spaces/CollectionQuerySpaceImpl.java (.../CollectionQuerySpaceImpl.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -26,6 +26,7 @@ import org.hibernate.loader.plan.build.spi.ExpandingCollectionQuerySpace; import org.hibernate.loader.plan.build.spi.ExpandingQuerySpaces; import org.hibernate.loader.plan.spi.Join; +import org.hibernate.loader.plan.spi.JoinDefinedByMetadata; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPropertyNames; import org.hibernate.persister.collection.QueryableCollection; @@ -36,6 +37,8 @@ */ public class CollectionQuerySpaceImpl extends AbstractQuerySpace implements ExpandingCollectionQuerySpace { private final CollectionPersister persister; + private JoinDefinedByMetadata elementJoin; + private JoinDefinedByMetadata indexJoin; public CollectionQuerySpaceImpl( CollectionPersister persister, @@ -78,6 +81,35 @@ @Override public void addJoin(Join join) { + if ( JoinDefinedByMetadata.class.isInstance( join ) ) { + final JoinDefinedByMetadata joinDefinedByMetadata = (JoinDefinedByMetadata) join; + if ( joinDefinedByMetadata.getJoinedPropertyName().equals( CollectionPropertyNames.COLLECTION_ELEMENTS ) ) { + if ( elementJoin == null ) { + elementJoin = joinDefinedByMetadata; + } + else { + throw new IllegalStateException( "Attempt to add an element join, but an element join already exists." ); + } + } + else if ( joinDefinedByMetadata.getJoinedPropertyName().equals( CollectionPropertyNames.COLLECTION_INDICES ) ) { + if ( indexJoin == null ) { + indexJoin = joinDefinedByMetadata; + } + else { + throw new IllegalStateException( "Attempt to add an index join, but an index join already exists." ); + } + } + else { + throw new IllegalArgumentException( + String.format( + "Collection propertyName must be either %s or %s; instead the joined property name was %s.", + CollectionPropertyNames.COLLECTION_ELEMENTS, + CollectionPropertyNames.COLLECTION_INDICES, + joinDefinedByMetadata.getJoinedPropertyName() + ) + ); + } + } internalGetJoins().add( join ); } @@ -86,4 +118,7 @@ return super.getExpandingQuerySpaces(); } + public void addJoin(JoinDefinedByMetadata join) { + addJoin( (Join) join ); + } } Index: 3rdParty_sources/hibernate-core/org/hibernate/loader/plan/build/internal/spaces/QuerySpacesImpl.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/loader/plan/build/internal/spaces/QuerySpacesImpl.java (.../QuerySpacesImpl.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/loader/plan/build/internal/spaces/QuerySpacesImpl.java (.../QuerySpacesImpl.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -38,6 +38,7 @@ import org.hibernate.loader.plan.spi.QuerySpaceUidNotRegisteredException; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.persister.entity.JoinedSubclassEntityPersister; import org.jboss.logging.Logger; @@ -101,11 +102,25 @@ checkQuerySpaceDoesNotExist( uid ); + // as a temporary fix for HHH-8980 and HHH-8830 we circumvent allowing + // inner joins (canJoinsBeRequired) when the persister is part of an + // entity inheritance. + // + // hasSubclasses() is the closest we can come to even knowing if the + // entity is part of a hierarchy. But its enough, since if there are no + // subclasses we cannot have the case where the attribute to join comes from + // a subclass :) + // + // a better long term fix is to expose whether a joined association attribute + // is defined on the class/superClass(es) or on the subClass(es). Attributes + // from the subClass(es) should not be inner joined; it is ok to inner join + // attributes from the class/superClass(es). + final EntityQuerySpaceImpl space = new EntityQuerySpaceImpl( entityPersister, uid, this, - canJoinsBeRequired + canJoinsBeRequired && !entityPersister.getEntityMetamodel().hasSubclasses() ); registerQuerySpace( space ); Index: 3rdParty_sources/hibernate-core/org/hibernate/loader/plan/build/spi/ExpandingCollectionQuerySpace.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/loader/plan/build/spi/ExpandingCollectionQuerySpace.java (.../ExpandingCollectionQuerySpace.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/loader/plan/build/spi/ExpandingCollectionQuerySpace.java (.../ExpandingCollectionQuerySpace.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -24,6 +24,9 @@ package org.hibernate.loader.plan.build.spi; import org.hibernate.loader.plan.spi.CollectionQuerySpace; +import org.hibernate.loader.plan.spi.Join; +import org.hibernate.loader.plan.spi.JoinDefinedByMetadata; +import org.hibernate.persister.collection.CollectionPropertyNames; /** * Describes a collection query space that allows adding joins with other @@ -34,4 +37,19 @@ * @author Gail Badner */ public interface ExpandingCollectionQuerySpace extends CollectionQuerySpace, ExpandingQuerySpace { + + /** + * Adds a join with another query space for either a collection element or index. If {@code join} + * is an instance of {@link JoinDefinedByMetadata}, then the only valid values returned by + * {@link JoinDefinedByMetadata#getJoinedPropertyName} are {@link CollectionPropertyNames#COLLECTION_ELEMENTS} + * and {@link CollectionPropertyNames#COLLECTION_INDICES}, for the collection element or index, respectively. + * + * @param join The element or index join to add. + * + * @throws java.lang.IllegalArgumentException if {@code join} is an instance of {@link JoinDefinedByMetadata} + * and {@code join.getJoinedPropertyName() is neither {@link CollectionPropertyNames#COLLECTION_ELEMENTS} + * nor {@link CollectionPropertyNames#COLLECTION_INDICES}}. + * @throws java.lang.IllegalStateException if there is already an existing join with the same joined property name. + */ + public void addJoin(Join join); } Index: 3rdParty_sources/hibernate-core/org/hibernate/loader/plan/exec/internal/LoadQueryJoinAndFetchProcessor.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/loader/plan/exec/internal/LoadQueryJoinAndFetchProcessor.java (.../LoadQueryJoinAndFetchProcessor.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/loader/plan/exec/internal/LoadQueryJoinAndFetchProcessor.java (.../LoadQueryJoinAndFetchProcessor.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -23,6 +23,7 @@ */ package org.hibernate.loader.plan.exec.internal; +import org.hibernate.AssertionFailure; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -284,28 +285,43 @@ // For many-to-many, the follow-on join will join to the associated entity element table. For one-to-many, // the collection table is the associated entity table, so the follow-on join will not be rendered.. + // currently we do not explicitly track the joins under the CollectionQuerySpace to know which is + // the element join and which is the index join (maybe we should?). + + JoinDefinedByMetadata collectionElementJoin = null; + JoinDefinedByMetadata collectionIndexJoin = null; + for ( Join collectionJoin : rightHandSide.getJoins() ) { + if ( JoinDefinedByMetadata.class.isInstance( collectionJoin ) ) { + final JoinDefinedByMetadata collectionJoinDefinedByMetadata = (JoinDefinedByMetadata) collectionJoin; + if ( CollectionPropertyNames.COLLECTION_ELEMENTS.equals( collectionJoinDefinedByMetadata.getJoinedPropertyName() ) ) { + if ( collectionElementJoin != null ) { + throw new AssertionFailure( + String.format( + "More than one element join defined for: %s", + rightHandSide.getCollectionPersister().getRole() + ) + ); + } + collectionElementJoin = collectionJoinDefinedByMetadata; + } + if ( CollectionPropertyNames.COLLECTION_INDICES.equals( collectionJoinDefinedByMetadata.getJoinedPropertyName() ) ) { + if ( collectionIndexJoin != null ) { + throw new AssertionFailure( + String.format( + "More than one index join defined for: %s", + rightHandSide.getCollectionPersister().getRole() + ) + ); + } + collectionIndexJoin = collectionJoinDefinedByMetadata; + } + } + } + if ( rightHandSide.getCollectionPersister().isOneToMany() || rightHandSide.getCollectionPersister().isManyToMany() ) { // relatedly, for collections with entity elements (one-to-many, many-to-many) we need to register the // sql aliases to use for the entity. - // - // currently we do not explicitly track the joins under the CollectionQuerySpace to know which is - // the element join and which is the index join (maybe we should?). Another option here is to have the - // "collection join" act as the entity element join in this case (much like I do with entity identifiers). - // The difficulty there is that collections can theoretically could be multiple joins in that case (one - // for element, one for index). However, that's a bit of future-planning as today Hibernate does not - // properly deal with the index anyway in terms of allowing dynamic fetching across a collection index... - // - // long story short, for now we'll use an assumption that the last join in the CollectionQuerySpace is the - // element join (that's how the joins are built as of now..) - // - // todo : remove this assumption ^^; maybe we make CollectionQuerySpace "special" and rather than have it - // hold a list of joins, we have it expose the 2 (index, element) separately. - - Join collectionElementJoin = null; - for ( Join collectionJoin : rightHandSide.getJoins() ) { - collectionElementJoin = collectionJoin; - } if ( collectionElementJoin == null ) { throw new IllegalStateException( String.format( @@ -329,6 +345,24 @@ ); } + if ( rightHandSide.getCollectionPersister().hasIndex() && + rightHandSide.getCollectionPersister().getIndexType().isEntityType() ) { + // for collections with entity index we need to register the + // sql aliases to use for the entity. + if ( collectionIndexJoin == null ) { + throw new IllegalStateException( + String.format( + "Could not locate collection index join within collection join [%s : %s]", + rightHandSide.getUid(), + rightHandSide.getCollectionPersister() + ) + ); + } + aliasResolutionContext.generateEntityReferenceAliases( + collectionIndexJoin.getRightHandSide().getUid(), + rightHandSide.getCollectionPersister().getIndexDefinition().toEntityDefinition().getEntityPersister() + ); + } addJoins( join, joinFragment, Index: 3rdParty_sources/hibernate-core/org/hibernate/mapping/SimpleValue.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/mapping/SimpleValue.java (.../SimpleValue.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/mapping/SimpleValue.java (.../SimpleValue.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -494,7 +494,10 @@ try { String[] columnsNames = new String[columns.size()]; for ( int i = 0; i < columns.size(); i++ ) { - columnsNames[i] = ( (Column) columns.get( i ) ).getName(); + Selectable column = columns.get(i); + if (column instanceof Column){ + columnsNames[i] = ((Column) column).getName(); + } } final XProperty xProperty = (XProperty) typeParameters.get( DynamicParameterizedType.XPROPERTY ); Index: 3rdParty_sources/hibernate-core/org/hibernate/metamodel/source/internal/IdentifierGeneratorResolver.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/metamodel/source/internal/IdentifierGeneratorResolver.java (.../IdentifierGeneratorResolver.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/metamodel/source/internal/IdentifierGeneratorResolver.java (.../IdentifierGeneratorResolver.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -30,6 +30,7 @@ import org.hibernate.cfg.NamingStrategy; import org.hibernate.cfg.ObjectNameNormalizer; import org.hibernate.engine.config.spi.ConfigurationService; +import org.hibernate.cfg.naming.NamingStrategyDelegator; import org.hibernate.id.PersistentIdentifierGenerator; import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.source.MetadataImplementor; @@ -93,5 +94,10 @@ protected NamingStrategy getNamingStrategy() { return namingStrategy; } + + @Override + protected NamingStrategyDelegator getNamingStrategyDelegator() { + return null; + } } } Index: 3rdParty_sources/hibernate-core/org/hibernate/persister/collection/AbstractCollectionPersister.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/persister/collection/AbstractCollectionPersister.java (.../AbstractCollectionPersister.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/persister/collection/AbstractCollectionPersister.java (.../AbstractCollectionPersister.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -1703,13 +1703,29 @@ public void processQueuedOps(PersistentCollection collection, Serializable key, SessionImplementor session) throws HibernateException { if ( collection.hasQueuedOperations() ) { - int nextIndex = getSize( key, session ); - doProcessQueuedOps( collection, key, nextIndex, session ); + doProcessQueuedOps( collection, key, session ); } } - protected abstract void doProcessQueuedOps(PersistentCollection collection, Serializable key, + /** + * Process queued operations within the PersistentCollection. + * + * @param collection The collection + * @param key The collection key + * @param nextIndex The next index to write + * @param session The session + * @throws HibernateException + * + * @deprecated Use {@link #doProcessQueuedOps(org.hibernate.collection.spi.PersistentCollection, java.io.Serializable, org.hibernate.engine.spi.SessionImplementor)} + */ + @Deprecated + protected void doProcessQueuedOps(PersistentCollection collection, Serializable key, int nextIndex, SessionImplementor session) + throws HibernateException { + doProcessQueuedOps( collection, key, session ); + } + + protected abstract void doProcessQueuedOps(PersistentCollection collection, Serializable key, SessionImplementor session) throws HibernateException; @Override Index: 3rdParty_sources/hibernate-core/org/hibernate/persister/collection/BasicCollectionPersister.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/persister/collection/BasicCollectionPersister.java (.../BasicCollectionPersister.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/persister/collection/BasicCollectionPersister.java (.../BasicCollectionPersister.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -155,8 +155,7 @@ } @Override - protected void doProcessQueuedOps(PersistentCollection collection, Serializable id, - int nextIndex, SessionImplementor session) + protected void doProcessQueuedOps(PersistentCollection collection, Serializable id, SessionImplementor session) throws HibernateException { // nothing to do } Index: 3rdParty_sources/hibernate-core/org/hibernate/persister/collection/OneToManyPersister.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/persister/collection/OneToManyPersister.java (.../OneToManyPersister.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/persister/collection/OneToManyPersister.java (.../OneToManyPersister.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -182,28 +182,33 @@ public void recreate(PersistentCollection collection, Serializable id, SessionImplementor session) throws HibernateException { super.recreate( collection, id, session ); - writeIndex( collection, collection.entries( this ), id, 0, session ); + writeIndex( collection, collection.entries( this ), id, true, session ); } @Override public void insertRows(PersistentCollection collection, Serializable id, SessionImplementor session) throws HibernateException { super.insertRows( collection, id, session ); - writeIndex( collection, collection.entries( this ), id, 0, session ); + writeIndex( collection, collection.entries( this ), id, true, session ); } @Override - protected void doProcessQueuedOps(PersistentCollection collection, Serializable id, - int nextIndex, SessionImplementor session) throws HibernateException { - writeIndex( collection, collection.queuedAdditionIterator(), id, nextIndex, session ); + protected void doProcessQueuedOps(PersistentCollection collection, Serializable id, SessionImplementor session) + throws HibernateException { + writeIndex( collection, collection.queuedAdditionIterator(), id, false, session ); } - - private void writeIndex(PersistentCollection collection, Iterator entries, Serializable id, - int nextIndex, SessionImplementor session) { + + private void writeIndex( + PersistentCollection collection, + Iterator entries, + Serializable id, + boolean resetIndex, + SessionImplementor session) { // If one-to-many and inverse, still need to create the index. See HHH-5732. if ( isInverse && hasIndex && !indexContainsFormula ) { try { if ( entries.hasNext() ) { + int nextIndex = resetIndex ? 0 : getSize( id, session ); Expectation expectation = Expectations.appropriateExpectation( getUpdateCheckStyle() ); while ( entries.hasNext() ) { Index: 3rdParty_sources/hibernate-core/org/hibernate/persister/entity/AbstractEntityPersister.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/persister/entity/AbstractEntityPersister.java (.../AbstractEntityPersister.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/persister/entity/AbstractEntityPersister.java (.../AbstractEntityPersister.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -1234,7 +1234,7 @@ LOG.tracev( "Initializing lazy properties of: {0}, field access: {1}", MessageHelper.infoString( this, id, getFactory() ), fieldName ); } - if ( hasCache() ) { + if ( session.getCacheMode().isGetEnabled() && hasCache() ) { final CacheKey cacheKey = session.generateCacheKey( id, getIdentifierType(), getEntityName() ); final Object ce = CacheHelper.fromSharedCache( session, cacheKey, getCacheAccessStrategy() ); if ( ce != null ) { @@ -4493,7 +4493,7 @@ } // check to see if it is in the second-level cache - if ( hasCache() ) { + if ( session.getCacheMode().isGetEnabled() && hasCache() ) { final CacheKey ck = session.generateCacheKey( id, getIdentifierType(), getRootEntityName() ); final Object ce = CacheHelper.fromSharedCache( session, ck, getCacheAccessStrategy() ); if ( ce != null ) { @@ -5267,7 +5267,7 @@ @Override public CacheEntry buildCacheEntry(Object entity, Object[] state, Object version, SessionImplementor session) { - return new ReferenceCacheEntryImpl( entity, persister.getEntityName() ); + return new ReferenceCacheEntryImpl( entity, persister ); } } Index: 3rdParty_sources/hibernate-core/org/hibernate/service/ServiceRegistryBuilder.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/service/ServiceRegistryBuilder.java (.../ServiceRegistryBuilder.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/service/ServiceRegistryBuilder.java (.../ServiceRegistryBuilder.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -86,4 +86,12 @@ public StandardServiceRegistry build() { return super.build(); } + + /** + * Don't remove yet: used by JBoss Tools + */ + public ServiceRegistry buildServiceRegistry() { + return build(); + } + } Index: 3rdParty_sources/hibernate-core/org/hibernate/service/internal/StandardSessionFactoryServiceInitiators.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/service/internal/StandardSessionFactoryServiceInitiators.java (.../StandardSessionFactoryServiceInitiators.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/service/internal/StandardSessionFactoryServiceInitiators.java (.../StandardSessionFactoryServiceInitiators.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.List; +import org.hibernate.engine.query.spi.NativeQueryInterpreterInitiator; import org.hibernate.engine.spi.CacheInitiator; import org.hibernate.event.service.internal.EventListenerServiceInitiator; import org.hibernate.service.spi.SessionFactoryServiceInitiator; @@ -48,6 +49,8 @@ serviceInitiators.add( StatisticsInitiator.INSTANCE ); serviceInitiators.add( CacheInitiator.INSTANCE ); + serviceInitiators.add( NativeQueryInterpreterInitiator.INSTANCE ); + return Collections.unmodifiableList( serviceInitiators ); } Index: 3rdParty_sources/hibernate-core/org/hibernate/stat/internal/ConcurrentNaturalIdCacheStatisticsImpl.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/stat/internal/ConcurrentNaturalIdCacheStatisticsImpl.java (.../ConcurrentNaturalIdCacheStatisticsImpl.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/stat/internal/ConcurrentNaturalIdCacheStatisticsImpl.java (.../ConcurrentNaturalIdCacheStatisticsImpl.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -31,7 +31,7 @@ import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; -import org.hibernate.cache.spi.CacheKey; +import org.hibernate.cache.spi.NaturalIdCacheKey; import org.hibernate.cache.spi.Region; import org.hibernate.stat.NaturalIdCacheStatistics; @@ -145,7 +145,7 @@ final Iterator iter = this.region.toMap().entrySet().iterator(); while ( iter.hasNext() ) { final Map.Entry me = (Map.Entry) iter.next(); - map.put( ( (CacheKey) me.getKey() ).getKey(), me.getValue() ); + map.put( ( (NaturalIdCacheKey) me.getKey() ).getNaturalIdValues(), me.getValue() ); } return map; } Index: 3rdParty_sources/hibernate-core/org/hibernate/stat/internal/ConcurrentStatisticsImpl.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/stat/internal/ConcurrentStatisticsImpl.java (.../ConcurrentStatisticsImpl.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/stat/internal/ConcurrentStatisticsImpl.java (.../ConcurrentStatisticsImpl.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -187,6 +187,7 @@ entityStatistics.clear(); collectionStatistics.clear(); queryStatistics.clear(); + naturalIdCacheStatistics.clear(); startTime = System.currentTimeMillis(); } Index: 3rdParty_sources/hibernate-core/org/hibernate/tool/hbm2ddl/DatabaseMetadata.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/tool/hbm2ddl/DatabaseMetadata.java (.../DatabaseMetadata.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/tool/hbm2ddl/DatabaseMetadata.java (.../DatabaseMetadata.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -54,7 +54,7 @@ */ public class DatabaseMetadata { - private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, DatabaseMetaData.class.getName()); + private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, DatabaseMetaData.class.getName()); private final Map tables = new HashMap(); private final Set sequences = new HashSet(); @@ -149,7 +149,9 @@ } finally { - rs.close(); + if ( rs != null ) { + rs.close(); + } } } catch (SQLException sqlException) { @@ -180,10 +182,13 @@ } } finally { - rs.close(); - statement.close(); + if ( rs != null ) { + rs.close(); + } + if ( statement != null ) { + statement.close(); + } } - } } } @@ -196,30 +201,30 @@ return false; } - public boolean isTable(Object key) throws HibernateException { - if(key instanceof String) { + public boolean isTable(Object key) throws HibernateException { + if(key instanceof String) { Table tbl = new Table((String)key); if ( getTableMetadata( tbl.getName(), tbl.getSchema(), tbl.getCatalog(), tbl.isQuoted() ) != null ) { - return true; - } else { - String[] strings = StringHelper.split(".", (String) key); - if(strings.length==3) { + return true; + } else { + String[] strings = StringHelper.split(".", (String) key); + if(strings.length==3) { tbl = new Table(strings[2]); tbl.setCatalog(strings[0]); tbl.setSchema(strings[1]); return getTableMetadata( tbl.getName(), tbl.getSchema(), tbl.getCatalog(), tbl.isQuoted() ) != null; - } else if (strings.length==2) { + } else if (strings.length==2) { tbl = new Table(strings[1]); tbl.setSchema(strings[0]); return getTableMetadata( tbl.getName(), tbl.getSchema(), tbl.getCatalog(), tbl.isQuoted() ) != null; - } - } - } - return false; - } + } + } + } + return false; + } @Override - public String toString() { + public String toString() { return "DatabaseMetadata" + tables.keySet().toString() + sequences.toString(); } } Index: 3rdParty_sources/hibernate-core/org/hibernate/type/descriptor/java/ByteArrayTypeDescriptor.java =================================================================== diff -u -r2b6774d5449fee3258575f0164adf4a2056aff5a -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/hibernate-core/org/hibernate/type/descriptor/java/ByteArrayTypeDescriptor.java (.../ByteArrayTypeDescriptor.java) (revision 2b6774d5449fee3258575f0164adf4a2056aff5a) +++ 3rdParty_sources/hibernate-core/org/hibernate/type/descriptor/java/ByteArrayTypeDescriptor.java (.../ByteArrayTypeDescriptor.java) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -27,6 +27,7 @@ import java.io.InputStream; import java.sql.Blob; import java.sql.SQLException; +import java.util.Arrays; import org.hibernate.HibernateException; import org.hibernate.engine.jdbc.BinaryStream; @@ -46,6 +47,20 @@ super( Byte[].class, ArrayMutabilityPlan.INSTANCE ); } @Override + public boolean areEqual(Byte[] one, Byte[] another) { + return one == another + || ( one != null && another != null && Arrays.equals(one, another) ); + } + @Override + public int extractHashCode(Byte[] bytes) { + int hashCode = 1; + for ( byte aByte : bytes ) { + hashCode = 31 * hashCode + aByte; + } + return hashCode; + } + + @Override public String toString(Byte[] bytes) { final StringBuilder buf = new StringBuilder(); for ( Byte aByte : bytes ) { Index: 3rdParty_sources/versions.txt =================================================================== diff -u -r588fe01186ff8c7c5b215e15f5ac4763137e0284 -r298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb --- 3rdParty_sources/versions.txt (.../versions.txt) (revision 588fe01186ff8c7c5b215e15f5ac4763137e0284) +++ 3rdParty_sources/versions.txt (.../versions.txt) (revision 298ae906ee8f2db8a1ee5dd195d1eefe81c3cdfb) @@ -19,7 +19,7 @@ gson 2.2.4 -Hibernate Core 3.6.10 +Hibernate Core 4.3.7 httpunit 1.7 @@ -48,9 +48,9 @@ Struts 1.2.9 -Undertow core 1.1.0 +Undertow core 1.1.8 -Undertow servlet 1.1.0 +Undertow servlet 1.1.8 xmltooling 1.4.0