From d60dc9255d7abf4736bacddd6c8ac64f9641daea Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Wed, 9 Jun 2021 18:15:05 +0200 Subject: [PATCH 01/17] HHH-14660 Deprecate component mappings with different attributes for the same class --- .../internal/log/DeprecationLogger.java | 8 +++ .../metamodel/internal/AttributeFactory.java | 68 +++++++++++-------- .../metamodel/internal/MetadataContext.java | 38 +++++++++-- 3 files changed, 79 insertions(+), 35 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java index 2866a1a309..a3084bc76b 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java @@ -250,4 +250,12 @@ void connectionProviderClassDeprecated( "5.3 in upgrading. It will be removed in a later version." ) void logUseOfDeprecatedZeroBasedJdbcStyleParams(); + + @LogMessage(level = WARN) + @Message( + id = 90000025, + value = "Encountered multiple component mappings for the same java class [%s] with different property mappings. " + + "This is deprecated and will be removed in a future version. Every property mapping combination should have its own java class" + ) + void deprecatedComponentMapping(String name); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java index 4fe8d46283..f7b5629f33 100755 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java @@ -102,34 +102,40 @@ public PersistentAttributeDescriptor buildAttribute(ManagedTypeDesc if ( attributeContext.getPropertyMapping().getType().isComponentType() && jpaAttributeNature.equals( Attribute.PersistentAttributeType.BASIC ) ) { CompositeType compositeType = (CompositeType) attributeContext.getPropertyMapping().getType(); - EmbeddableTypeImpl embeddableType = new EmbeddableTypeImpl<>( - attributeMetadata.getJavaType(), - ownerType, - compositeType, - context.getSessionFactory() - ); - context.registerEmbeddedableType(embeddableType); - - String[] propertyNames = compositeType.getPropertyNames(); - org.hibernate.type.Type[] subtypes = compositeType.getSubtypes(); - InFlightAccess inFlightAccess = embeddableType.getInFlightAccess(); - - for ( int i = 0; i < propertyNames.length; i++ ) { - SingularAttributeImpl nestedAttribute = new SingularAttributeImpl( - embeddableType, - propertyNames[i], - Attribute.PersistentAttributeType.BASIC, - new BasicTypeImpl(subtypes[i].getReturnedClass(), Type.PersistenceType.BASIC), - null, - false, - false, - property.isOptional() - ); - inFlightAccess.addAttribute(nestedAttribute); - } - - metaModelType = embeddableType; + metaModelType = context.locateEmbeddable( attributeMetadata.getJavaType(), compositeType ); jpaAttributeNature = Attribute.PersistentAttributeType.EMBEDDED; + if ( metaModelType == null ) { + metaModelType = context.locateEmbeddable( attributeMetadata.getJavaType(), compositeType ); + if ( metaModelType == null ) { + EmbeddableTypeImpl embeddableType = new EmbeddableTypeImpl<>( + attributeMetadata.getJavaType(), + ownerType, + compositeType, + context.getSessionFactory() + ); + context.registerEmbeddableType( embeddableType, compositeType ); + + String[] propertyNames = compositeType.getPropertyNames(); + org.hibernate.type.Type[] subtypes = compositeType.getSubtypes(); + InFlightAccess inFlightAccess = embeddableType.getInFlightAccess(); + + for (int i = 0; i < propertyNames.length; i++) { + SingularAttributeImpl nestedAttribute = new SingularAttributeImpl( + embeddableType, + propertyNames[i], + Attribute.PersistentAttributeType.BASIC, + new BasicTypeImpl( subtypes[i].getReturnedClass(), Type.PersistenceType.BASIC ), + null, + false, + false, + property.isOptional() + ); + inFlightAccess.addAttribute( nestedAttribute ); + } + + metaModelType = embeddableType; + } + } } return new SingularAttributeImpl( @@ -249,13 +255,17 @@ private SimpleTypeDescriptor determineSimpleType(ValueContext typeContext } case EMBEDDABLE: { final Component component = (Component) typeContext.getHibernateValue(); - + final CompositeType compositeType = (CompositeType) component.getType(); Class javaType; if ( component.getComponentClassName() == null ) { javaType = typeContext.getJpaBindableType(); } else { javaType = component.getComponentClass(); + final EmbeddedTypeDescriptor cached = context.locateEmbeddable( javaType, compositeType ); + if ( cached != null ) { + return cached; + } } final EmbeddedTypeDescriptor embeddableType = new EmbeddableTypeImpl( @@ -264,7 +274,7 @@ private SimpleTypeDescriptor determineSimpleType(ValueContext typeContext (ComponentType) typeContext.getHibernateValue().getType(), context.getSessionFactory() ); - context.registerEmbeddedableType( embeddableType ); + context.registerEmbeddableType( embeddableType, compositeType ); final InFlightAccess inFlightAccess = embeddableType.getInFlightAccess(); final Iterator subProperties = component.getPropertyIterator(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java index 644cbff1e9..55e5025016 100755 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java @@ -8,6 +8,7 @@ import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -25,6 +26,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.EntityManagerMessageLogger; import org.hibernate.internal.HEMLogging; +import org.hibernate.internal.log.DeprecationLogger; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.mapping.Component; @@ -42,6 +44,7 @@ import org.hibernate.metamodel.model.domain.spi.ManagedTypeDescriptor; import org.hibernate.metamodel.model.domain.spi.MappedSuperclassTypeDescriptor; import org.hibernate.metamodel.model.domain.spi.SingularPersistentAttribute; +import org.hibernate.type.CompositeType; /** * Defines a context for storing information during the building of the {@link MetamodelImpl}. @@ -51,7 +54,7 @@ *

* At the end of the day, clients are interested in the {@link #getEntityTypeMap} and {@link #getEmbeddableTypeSet} * results, which represent all the registered {@linkplain #registerEntityType entities} and - * {@linkplain #registerEmbeddedableType embeddables} respectively. + * {@linkplain #registerEmbeddableType embeddables} respectively. * * @author Steve Ebersole * @author Emmanuel Bernard @@ -68,7 +71,8 @@ class MetadataContext { private Map> entityTypesByEntityName = new HashMap<>(); private Map> entityTypesByPersistentClass = new HashMap<>(); - private Set> embeddables = new HashSet<>(); + private Map>> embeddablesToProcess = new HashMap<>(); + private Map, CompositeType> componentByEmbeddable = new HashMap<>(); private Map> mappedSuperclassByMappedSuperclassMapping = new HashMap<>(); private Map, PersistentClass> mappedSuperClassTypeToPersistentClass = new HashMap<>(); @@ -108,7 +112,7 @@ public Map, EntityTypeDescriptor> getEntityTypeMap() { } public Set> getEmbeddableTypeSet() { - return Collections.unmodifiableSet( embeddables ); + return Collections.unmodifiableSet( componentByEmbeddable.keySet() ); } public Map, MappedSuperclassType> getMappedSuperclassTypeMap() { @@ -141,9 +145,13 @@ public Map, MappedSuperclassType> getMappedSuperclassTypeMap() { orderedMappings.add( persistentClass ); } - /*package*/ void registerEmbeddedableType(EmbeddedTypeDescriptor embeddableType) { + /*package*/ void registerEmbeddableType(EmbeddedTypeDescriptor embeddableType, CompositeType component) { + final List> existingEmbeddables = embeddablesToProcess.computeIfAbsent( + embeddableType.getJavaType(), k -> new ArrayList<>( 1 ) + ); + existingEmbeddables.add( embeddableType ); if ( !( ignoreUnsupported && embeddableType.getParent().getJavaType() == null ) ) { - embeddables.add( embeddableType ); + componentByEmbeddable.put( embeddableType, component ); } } @@ -198,6 +206,24 @@ public Map> getEntityTypesByEntityName() { return Collections.unmodifiableMap( entityTypesByEntityName ); } + public EmbeddedTypeDescriptor locateEmbeddable(Class embeddableClass, CompositeType component) { + final List> embeddableDomainTypes = embeddablesToProcess.get( embeddableClass ); + if ( embeddableDomainTypes != null ) { + for ( EmbeddedTypeDescriptor embeddableDomainType : embeddableDomainTypes ) { + final CompositeType cachedComponent = componentByEmbeddable.get( embeddableDomainType ); + if ( Arrays.equals( cachedComponent.getPropertyNames(), component.getPropertyNames() ) ) { + //noinspection unchecked + return (EmbeddedTypeDescriptor) embeddableDomainType; + } + else { + // See HHH-14660 + DeprecationLogger.DEPRECATION_LOGGER.deprecatedComponentMapping(embeddableClass.getName() ); + } + } + } + return null; + } + @SuppressWarnings({"unchecked"}) public void wrapUp() { if ( LOG.isTraceEnabled() ) { @@ -294,7 +320,7 @@ else if ( MappedSuperclass.class.isAssignableFrom( mapping.getClass() ) ) { } if ( staticMetamodelScanEnabled ) { - for ( EmbeddedTypeDescriptor embeddable : embeddables ) { + for ( EmbeddedTypeDescriptor embeddable : componentByEmbeddable.keySet() ) { populateStaticMetamodel( embeddable ); } } From bbc2ecb4840fcdcb6e2003ab2be5faf7d33b73db Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 3 Jun 2021 11:51:50 +0200 Subject: [PATCH 02/17] HHH-14649 Add test for issue --- .../dialect/Oracle12LimitHandlerTest.java | 67 +++++++++++++++++++ .../OraclePaginationWithLocksTest.java | 24 +++++++ 2 files changed, 91 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/dialect/Oracle12LimitHandlerTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/dialect/Oracle12LimitHandlerTest.java b/hibernate-core/src/test/java/org/hibernate/dialect/Oracle12LimitHandlerTest.java new file mode 100644 index 0000000000..96e35caebd --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/dialect/Oracle12LimitHandlerTest.java @@ -0,0 +1,67 @@ +package org.hibernate.dialect; + +import org.hibernate.dialect.pagination.Oracle12LimitHandler; +import org.hibernate.engine.spi.QueryParameters; +import org.hibernate.engine.spi.RowSelection; + +import org.hibernate.testing.TestForIssue; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +@TestForIssue( jiraKey = "HHH-14649") +public class Oracle12LimitHandlerTest { + + @Test + public void testSqlWithSpace() { + final String sql = "select p.name from Person p where p.id = 1 for update"; + final String expected = "select * from ( select p.name from Person p where p.id = 1 ) where rownum <= ? for update"; + + final QueryParameters queryParameters = getQueryParameters( 0, 5 ); + final String processedSql = Oracle12LimitHandler.INSTANCE.processSql( sql, queryParameters ); + + assertEquals( expected, processedSql ); + } + + @Test + public void testSqlWithSpaceInsideQuotedString() { + final String sql = "select p.name from Person p where p.name = ' this is a string with spaces ' for update"; + final String expected = "select * from ( select p.name from Person p where p.name = ' this is a string with spaces ' ) where rownum <= ? for update"; + + final QueryParameters queryParameters = getQueryParameters( 0, 5 ); + final String processedSql = Oracle12LimitHandler.INSTANCE.processSql( sql, queryParameters ); + + assertEquals( expected, processedSql ); + } + + @Test + public void testSqlWithForUpdateInsideQuotedString() { + final String sql = "select a.prop from A a where a.name = 'this is for update '"; + final String expected = "select a.prop from A a where a.name = 'this is for update ' fetch first ? rows only"; + + final QueryParameters queryParameters = getQueryParameters( 0, 5 ); + final String processedSql = Oracle12LimitHandler.INSTANCE.processSql( sql, queryParameters ); + + assertEquals( expected, processedSql ); + } + + @Test + public void testSqlWithForUpdateInsideAndOutsideQuotedStringA() { + final String sql = "select a.prop from A a where a.name = 'this is for update ' for update"; + final String expected = "select * from ( select a.prop from A a where a.name = 'this is for update ' ) where rownum <= ? for update"; + + final QueryParameters queryParameters = getQueryParameters( 0, 5 ); + final String processedSql = Oracle12LimitHandler.INSTANCE.processSql( sql, queryParameters ); + + assertEquals( expected, processedSql ); + } + + private QueryParameters getQueryParameters(int firstRow, int maxRow) { + final QueryParameters queryParameters = new QueryParameters(); + RowSelection rowSelection = new RowSelection(); + rowSelection.setFirstRow( firstRow ); + rowSelection.setMaxRows( maxRow ); + queryParameters.setRowSelection( rowSelection ); + return queryParameters; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/pagination/OraclePaginationWithLocksTest.java b/hibernate-core/src/test/java/org/hibernate/test/pagination/OraclePaginationWithLocksTest.java index 8aa64636ea..2280fcebd4 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/pagination/OraclePaginationWithLocksTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/pagination/OraclePaginationWithLocksTest.java @@ -96,6 +96,30 @@ public void testNativeQuery() { ); } + @Test + public void testNativeQueryWithSpaces() { + inTransaction( session -> { + final List people = session.createNativeQuery( + "select p.name from Person p where p.id = 1 for update" ) + .setMaxResults( 10 ) + .list(); + } ); + + inTransaction( session -> { + Person p = new Person(); + p.setName( " this is a string with spaces " ); + session.persist( p ); + } ); + + inTransaction( session -> { + final List people = session.createNativeQuery( + "select p.name from Person p where p.name = ' this is a string with spaces ' for update" ) + .setMaxResults( 10 ) + .list(); + assertEquals( 1, people.size() ); + } ); + } + @Test public void testCriteriaQuery() { inTransaction( From 8002b188bbb7f4c799ba1172db833827bb39c259 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 3 Jun 2021 11:52:18 +0200 Subject: [PATCH 03/17] HHH-14649 Oracle limit handler create wrong sql query when multiple spaces are present in the query --- .../hibernate/dialect/pagination/Oracle12LimitHandler.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Oracle12LimitHandler.java b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Oracle12LimitHandler.java index 3067a01a81..c4d7f23f15 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Oracle12LimitHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Oracle12LimitHandler.java @@ -52,6 +52,7 @@ public String processSql(String sql, QueryParameters queryParameters) { if ( !hasMaxRows ) { return sql; } + sql = sql.trim(); final LockOptions lockOptions = queryParameters.getLockOptions(); if ( lockOptions != null ) { @@ -83,7 +84,6 @@ private String processSqlOffsetFetch(String sql, boolean hasFirstRow) { bindLimitParametersInReverseOrder = false; useMaxForLimit = false; - sql = normalizeStatement( sql ); final int offsetFetchLength; final String offsetFetchString; if ( hasFirstRow ) { @@ -100,7 +100,6 @@ private String processSqlOffsetFetch(String sql, boolean hasFirstRow) { private String processSql(String sql, int forUpdateIndex, boolean hasFirstRow) { bindLimitParametersInReverseOrder = true; useMaxForLimit = true; - sql = normalizeStatement( sql ); String forUpdateClause = null; boolean isForUpdate = false; @@ -142,10 +141,6 @@ private String processSql(String sql, int forUpdateIndex, boolean hasFirstRow) { return pagingSelect.toString(); } - private String normalizeStatement(String sql) { - return sql.trim().replaceAll( "\\s+", " " ); - } - private int getForUpdateIndex(String sql) { final int forUpdateLastIndex = sql.toLowerCase( Locale.ROOT ).lastIndexOf( "for update" ); // We need to recognize cases like : select a from t where b = 'for update'; From f8da005f3a465799f60acb238be41d209f7e81bf Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 9 Jun 2021 14:40:02 +0100 Subject: [PATCH 04/17] HHH-14667 Remove extraction of TypeInfo from the Database JDBC metadata as it's unused --- .../ExtractedDatabaseMetaDataImpl.java | 36 ------------------- .../env/internal/JdbcEnvironmentImpl.java | 12 ++----- .../env/spi/ExtractedDatabaseMetaData.java | 9 ----- .../engine/jdbc/env/spi/JdbcEnvironment.java | 9 ----- 4 files changed, 2 insertions(+), 64 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java index 36a74edeb4..80d4f18717 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java @@ -9,10 +9,8 @@ import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.Arrays; import java.util.Collections; import java.util.HashSet; -import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -21,8 +19,6 @@ import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.env.spi.SQLStateType; -import org.hibernate.engine.jdbc.spi.TypeInfo; -import org.hibernate.internal.util.StringHelper; import org.hibernate.tool.schema.extract.spi.SequenceInformation; /** @@ -47,7 +43,6 @@ public class ExtractedDatabaseMetaDataImpl implements ExtractedDatabaseMetaData private final boolean lobLocatorUpdateCopy; private final Set extraKeywords; - private final LinkedHashSet typeInfoSet; private final List sequenceInformationList; private ExtractedDatabaseMetaDataImpl( @@ -55,7 +50,6 @@ private ExtractedDatabaseMetaDataImpl( String connectionCatalogName, String connectionSchemaName, Set extraKeywords, - LinkedHashSet typeInfoSet, boolean supportsRefCursors, boolean supportsNamedParameters, boolean supportsScrollableResults, @@ -74,9 +68,6 @@ private ExtractedDatabaseMetaDataImpl( this.extraKeywords = extraKeywords != null ? extraKeywords : Collections.emptySet(); - this.typeInfoSet = typeInfoSet != null - ? typeInfoSet - : new LinkedHashSet(); this.supportsRefCursors = supportsRefCursors; this.supportsNamedParameters = supportsNamedParameters; @@ -155,11 +146,6 @@ public String getConnectionSchemaName() { return connectionSchemaName; } - @Override - public LinkedHashSet getTypeInfoSet() { - return typeInfoSet; - } - @Override public List getSequenceInformationList() { return sequenceInformationList; @@ -172,7 +158,6 @@ public static class Builder { private String connectionCatalogName; private Set extraKeywords; - private LinkedHashSet typeInfoSet; private boolean supportsRefCursors; private boolean supportsNamedParameters; @@ -202,8 +187,6 @@ public Builder apply(DatabaseMetaData databaseMetaData) throws SQLException { extraKeywords = parseKeywords( databaseMetaData.getSQLKeywords() ); sqlStateType = SQLStateType.interpretReportedSQLStateType( databaseMetaData.getSQLStateType() ); lobLocatorUpdateCopy = databaseMetaData.locatorsUpdateCopy(); - typeInfoSet = new LinkedHashSet(); - typeInfoSet.addAll( TypeInfo.extractTypeInfo( databaseMetaData ) ); return this; } @@ -239,24 +222,6 @@ public Builder addExtraKeyword(String keyword) { return this; } - public Builder setTypeInfoSet(LinkedHashSet typeInfoSet) { - if ( this.typeInfoSet == null ) { - this.typeInfoSet = typeInfoSet; - } - else { - this.typeInfoSet.addAll( typeInfoSet ); - } - return this; - } - - public Builder addTypeInfo(TypeInfo typeInfo) { - if ( this.typeInfoSet == null ) { - this.typeInfoSet = new LinkedHashSet(); - } - typeInfoSet.add( typeInfo ); - return this; - } - public Builder setSupportsRefCursors(boolean supportsRefCursors) { this.supportsRefCursors = supportsRefCursors; return this; @@ -313,7 +278,6 @@ public ExtractedDatabaseMetaDataImpl build() { connectionCatalogName, connectionSchemaName, extraKeywords, - typeInfoSet, supportsRefCursors, supportsNamedParameters, supportsScrollableResults, diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java index b236dd6da1..420e8c0a49 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java @@ -60,7 +60,6 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment { private final QualifiedObjectNameFormatter qualifiedObjectNameFormatter; private final LobCreatorBuilderImpl lobCreatorBuilder; - private final LinkedHashSet typeInfoSet = new LinkedHashSet(); private final NameQualifierSupport nameQualifierSupport; /** @@ -277,8 +276,6 @@ public JdbcEnvironmentImpl( databaseMetaData ); - this.typeInfoSet.addAll( TypeInfo.extractTypeInfo( databaseMetaData ) ); - this.lobCreatorBuilder = LobCreatorBuilderImpl.makeLobCreatorBuilder( dialect, cfgService.getSettings(), @@ -379,14 +376,9 @@ public LobCreatorBuilder getLobCreatorBuilder() { return lobCreatorBuilder; } - @Override public TypeInfo getTypeInfoForJdbcCode(int jdbcTypeCode) { - for ( TypeInfo typeInfo : typeInfoSet ) { - if ( typeInfo.getJdbcTypeCode() == jdbcTypeCode ) { - return typeInfo; - } - } - return null; + throw new UnsupportedOperationException( "Support for getting TypeInfo from jdbcTypeCode has been disabled as it wasn't used." + + " Use org.hibernate.engine.jdbc.spi.TypeInfo.extractTypeInfo as alternative, or report an issue and explain." ); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java index 7410cdbf32..cf98795e52 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java @@ -45,15 +45,6 @@ public interface ExtractedDatabaseMetaData { */ String getConnectionSchemaName(); - /** - * Set of type info reported by the driver. - * - * @return The type information obtained from the driver. - * - * @see java.sql.DatabaseMetaData#getTypeInfo() - */ - LinkedHashSet getTypeInfoSet(); - /** * Get the list of extra keywords (beyond standard SQL92 keywords) reported by the driver. * diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java index ec94471af1..3d4f79a1c8 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java @@ -9,7 +9,6 @@ import org.hibernate.boot.model.naming.Identifier; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; -import org.hibernate.engine.jdbc.spi.TypeInfo; import org.hibernate.service.Service; /** @@ -89,12 +88,4 @@ public interface JdbcEnvironment extends Service { */ LobCreatorBuilder getLobCreatorBuilder(); - /** - * Find type information for the type identified by the given "JDBC type code". - * - * @param jdbcTypeCode The JDBC type code. - * - * @return The corresponding type info. - */ - TypeInfo getTypeInfoForJdbcCode(int jdbcTypeCode); } From fd3585728456e17e5482802bee1ad9a053519f8c Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 9 Jun 2021 14:48:21 +0100 Subject: [PATCH 05/17] HHH-14667 Remove some dead code --- .../jdbc/env/internal/JdbcEnvironmentImpl.java | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java index 420e8c0a49..e6fdf2d4a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java @@ -9,12 +9,8 @@ import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; -import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashSet; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -288,7 +284,7 @@ public JdbcEnvironmentImpl( private String determineCurrentSchemaName( DatabaseMetaData databaseMetaData, ServiceRegistry serviceRegistry, - Dialect dialect) throws SQLException { + Dialect dialect) { final SchemaNameResolver schemaNameResolver; final Object setting = serviceRegistry.getService( ConfigurationService.class ).getSettings().get( @@ -323,14 +319,6 @@ private SqlExceptionHelper buildSqlExceptionHelper(Dialect dialect, boolean logW return new SqlExceptionHelper( sqlExceptionConverter, logWarnings ); } - private Set buildMergedReservedWords(Dialect dialect, DatabaseMetaData dbmd) throws SQLException { - Set reservedWords = new HashSet(); - reservedWords.addAll( dialect.getKeywords() ); - // todo : do we need to explicitly handle SQL:2003 keywords? - reservedWords.addAll( Arrays.asList( dbmd.getSQLKeywords().split( "," ) ) ); - return reservedWords; - } - @Override public Dialect getDialect() { return dialect; From c10493435ef924d867d679a96607ce2bb3864767 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 9 Jun 2021 15:05:19 +0100 Subject: [PATCH 06/17] HHH-14667 Skip loading all keywords from the DB when keyword auto-quoting is disabled --- .../engine/jdbc/env/spi/IdentifierHelperBuilder.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/IdentifierHelperBuilder.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/IdentifierHelperBuilder.java index 0f74afd8f3..74de34f772 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/IdentifierHelperBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/IdentifierHelperBuilder.java @@ -61,6 +61,10 @@ public void applyReservedWords(DatabaseMetaData metaData) throws SQLException { return; } + //Important optimisation: skip loading all keywords from the DB when autoQuoteKeywords is disabled + if ( autoQuoteKeywords == false ) { + return; + } this.reservedWords.addAll( parseKeywords( metaData.getSQLKeywords() ) ); } @@ -176,6 +180,10 @@ public void clearReservedWords() { } public void applyReservedWords(Set words) { + //No use when autoQuoteKeywords is disabled + if ( autoQuoteKeywords == false ) { + return; + } this.reservedWords.addAll( words ); } From 8f765eeff82f60de42a2acad7b14e1306626a166 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 9 Jun 2021 15:53:01 +0100 Subject: [PATCH 07/17] HHH-14667 Remove also unused: ExtractedDatabaseMetaData#getTypeInfoSet() and doesLobLocatorUpdateCopy() --- .../internal/ExtractedDatabaseMetaDataImpl.java | 16 ---------------- .../jdbc/env/spi/ExtractedDatabaseMetaData.java | 9 --------- .../test/jdbc/env/NoDatabaseMetaDataTest.java | 4 ---- 3 files changed, 29 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java index 80d4f18717..d16643cebf 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java @@ -40,7 +40,6 @@ public class ExtractedDatabaseMetaDataImpl implements ExtractedDatabaseMetaData private final boolean supportsDataDefinitionInTransaction; private final boolean doesDataDefinitionCauseTransactionCommit; private final SQLStateType sqlStateType; - private final boolean lobLocatorUpdateCopy; private final Set extraKeywords; private final List sequenceInformationList; @@ -58,7 +57,6 @@ private ExtractedDatabaseMetaDataImpl( boolean supportsDataDefinitionInTransaction, boolean doesDataDefinitionCauseTransactionCommit, SQLStateType sqlStateType, - boolean lobLocatorUpdateCopy, List sequenceInformationList) { this.jdbcEnvironment = jdbcEnvironment; @@ -77,7 +75,6 @@ private ExtractedDatabaseMetaDataImpl( this.supportsDataDefinitionInTransaction = supportsDataDefinitionInTransaction; this.doesDataDefinitionCauseTransactionCommit = doesDataDefinitionCauseTransactionCommit; this.sqlStateType = sqlStateType; - this.lobLocatorUpdateCopy = lobLocatorUpdateCopy; this.sequenceInformationList = sequenceInformationList; } @@ -131,11 +128,6 @@ public SQLStateType getSqlStateType() { return sqlStateType; } - @Override - public boolean doesLobLocatorUpdateCopy() { - return lobLocatorUpdateCopy; - } - @Override public String getConnectionCatalogName() { return connectionCatalogName; @@ -167,7 +159,6 @@ public static class Builder { private boolean supportsDataDefinitionInTransaction; private boolean doesDataDefinitionCauseTransactionCommit; private SQLStateType sqlStateType; - private boolean lobLocatorUpdateCopy; private List sequenceInformationList = Collections.emptyList(); public Builder(JdbcEnvironment jdbcEnvironment) { @@ -186,7 +177,6 @@ public Builder apply(DatabaseMetaData databaseMetaData) throws SQLException { doesDataDefinitionCauseTransactionCommit = databaseMetaData.dataDefinitionCausesTransactionCommit(); extraKeywords = parseKeywords( databaseMetaData.getSQLKeywords() ); sqlStateType = SQLStateType.interpretReportedSQLStateType( databaseMetaData.getSQLStateType() ); - lobLocatorUpdateCopy = databaseMetaData.locatorsUpdateCopy(); return this; } @@ -262,11 +252,6 @@ public Builder setSqlStateType(SQLStateType sqlStateType) { return this; } - public Builder setLobLocatorUpdateCopy(boolean lobLocatorUpdateCopy) { - this.lobLocatorUpdateCopy = lobLocatorUpdateCopy; - return this; - } - public Builder setSequenceInformationList(List sequenceInformationList) { this.sequenceInformationList = sequenceInformationList; return this; @@ -286,7 +271,6 @@ public ExtractedDatabaseMetaDataImpl build() { supportsDataDefinitionInTransaction, doesDataDefinitionCauseTransactionCommit, sqlStateType, - lobLocatorUpdateCopy, sequenceInformationList ); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java index cf98795e52..a87ac93420 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java @@ -127,15 +127,6 @@ public interface ExtractedDatabaseMetaData { */ SQLStateType getSqlStateType(); - /** - * Did the driver report that updates to a LOB locator affect a copy of the LOB? - * - * @return True if updates to the state of a LOB locator update only a copy. - * - * @see java.sql.DatabaseMetaData#locatorsUpdateCopy() - */ - boolean doesLobLocatorUpdateCopy(); - /** * Retrieve the list of {@code SequenceInformation} objects which describe the underlying database sequences. * diff --git a/hibernate-core/src/test/java/org/hibernate/test/jdbc/env/NoDatabaseMetaDataTest.java b/hibernate-core/src/test/java/org/hibernate/test/jdbc/env/NoDatabaseMetaDataTest.java index 017bc52570..ef92e999a4 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/jdbc/env/NoDatabaseMetaDataTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/jdbc/env/NoDatabaseMetaDataTest.java @@ -38,7 +38,6 @@ public void testNoJdbcMetadataDefaultDialect() { assertNull( extractedDatabaseMetaData.getConnectionCatalogName() ); assertNull( extractedDatabaseMetaData.getConnectionSchemaName() ); - assertTrue( extractedDatabaseMetaData.getTypeInfoSet().isEmpty() ); assertTrue( extractedDatabaseMetaData.getExtraKeywords().isEmpty() ); assertFalse( extractedDatabaseMetaData.supportsNamedParameters() ); assertFalse( extractedDatabaseMetaData.supportsRefCursors() ); @@ -48,7 +47,6 @@ public void testNoJdbcMetadataDefaultDialect() { assertFalse( extractedDatabaseMetaData.supportsDataDefinitionInTransaction() ); assertFalse( extractedDatabaseMetaData.doesDataDefinitionCauseTransactionCommit() ); assertNull( extractedDatabaseMetaData.getSqlStateType() ); - assertFalse( extractedDatabaseMetaData.doesLobLocatorUpdateCopy() ); StandardServiceRegistryBuilder.destroy( serviceRegistry ); } @@ -65,7 +63,6 @@ public void testNoJdbcMetadataDialectOverride() { assertNull( extractedDatabaseMetaData.getConnectionCatalogName() ); assertNull( extractedDatabaseMetaData.getConnectionSchemaName() ); - assertTrue( extractedDatabaseMetaData.getTypeInfoSet().isEmpty() ); assertTrue( extractedDatabaseMetaData.getExtraKeywords().isEmpty() ); assertTrue( extractedDatabaseMetaData.supportsNamedParameters() ); assertFalse( extractedDatabaseMetaData.supportsRefCursors() ); @@ -75,7 +72,6 @@ public void testNoJdbcMetadataDialectOverride() { assertFalse( extractedDatabaseMetaData.supportsDataDefinitionInTransaction() ); assertFalse( extractedDatabaseMetaData.doesDataDefinitionCauseTransactionCommit() ); assertNull( extractedDatabaseMetaData.getSqlStateType() ); - assertFalse( extractedDatabaseMetaData.doesLobLocatorUpdateCopy() ); StandardServiceRegistryBuilder.destroy( serviceRegistry ); } From ab8c81482c7d7d0f65a8f7e9a584dacef965bbf5 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 9 Jun 2021 22:56:29 +0100 Subject: [PATCH 08/17] HHH-14667 Remove also ExtractedDatabaseMetaData#getExtraKeywords() as it's unused as well --- .../ExtractedDatabaseMetaDataImpl.java | 36 ------------------- .../env/spi/ExtractedDatabaseMetaData.java | 9 ----- .../test/jdbc/env/NoDatabaseMetaDataTest.java | 2 -- 3 files changed, 47 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java index d16643cebf..18a40d684c 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java @@ -10,7 +10,6 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Set; @@ -41,14 +40,12 @@ public class ExtractedDatabaseMetaDataImpl implements ExtractedDatabaseMetaData private final boolean doesDataDefinitionCauseTransactionCommit; private final SQLStateType sqlStateType; - private final Set extraKeywords; private final List sequenceInformationList; private ExtractedDatabaseMetaDataImpl( JdbcEnvironment jdbcEnvironment, String connectionCatalogName, String connectionSchemaName, - Set extraKeywords, boolean supportsRefCursors, boolean supportsNamedParameters, boolean supportsScrollableResults, @@ -59,14 +56,8 @@ private ExtractedDatabaseMetaDataImpl( SQLStateType sqlStateType, List sequenceInformationList) { this.jdbcEnvironment = jdbcEnvironment; - this.connectionCatalogName = connectionCatalogName; this.connectionSchemaName = connectionSchemaName; - - this.extraKeywords = extraKeywords != null - ? extraKeywords - : Collections.emptySet(); - this.supportsRefCursors = supportsRefCursors; this.supportsNamedParameters = supportsNamedParameters; this.supportsScrollableResults = supportsScrollableResults; @@ -118,11 +109,6 @@ public boolean doesDataDefinitionCauseTransactionCommit() { return doesDataDefinitionCauseTransactionCommit; } - @Override - public Set getExtraKeywords() { - return extraKeywords; - } - @Override public SQLStateType getSqlStateType() { return sqlStateType; @@ -149,8 +135,6 @@ public static class Builder { private String connectionSchemaName; private String connectionCatalogName; - private Set extraKeywords; - private boolean supportsRefCursors; private boolean supportsNamedParameters; private boolean supportsScrollableResults; @@ -175,7 +159,6 @@ public Builder apply(DatabaseMetaData databaseMetaData) throws SQLException { supportsBatchUpdates = databaseMetaData.supportsBatchUpdates(); supportsDataDefinitionInTransaction = !databaseMetaData.dataDefinitionIgnoredInTransactions(); doesDataDefinitionCauseTransactionCommit = databaseMetaData.dataDefinitionCausesTransactionCommit(); - extraKeywords = parseKeywords( databaseMetaData.getSQLKeywords() ); sqlStateType = SQLStateType.interpretReportedSQLStateType( databaseMetaData.getSQLStateType() ); return this; } @@ -194,24 +177,6 @@ public Builder setConnectionCatalogName(String connectionCatalogName) { return this; } - public Builder setExtraKeywords(Set extraKeywords) { - if ( this.extraKeywords == null ) { - this.extraKeywords = extraKeywords; - } - else { - this.extraKeywords.addAll( extraKeywords ); - } - return this; - } - - public Builder addExtraKeyword(String keyword) { - if ( this.extraKeywords == null ) { - this.extraKeywords = new HashSet(); - } - this.extraKeywords.add( keyword ); - return this; - } - public Builder setSupportsRefCursors(boolean supportsRefCursors) { this.supportsRefCursors = supportsRefCursors; return this; @@ -262,7 +227,6 @@ public ExtractedDatabaseMetaDataImpl build() { jdbcEnvironment, connectionCatalogName, connectionSchemaName, - extraKeywords, supportsRefCursors, supportsNamedParameters, supportsScrollableResults, diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java index a87ac93420..33f5a4c57d 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java @@ -45,15 +45,6 @@ public interface ExtractedDatabaseMetaData { */ String getConnectionSchemaName(); - /** - * Get the list of extra keywords (beyond standard SQL92 keywords) reported by the driver. - * - * @return The extra keywords used by this database. - * - * @see java.sql.DatabaseMetaData#getSQLKeywords() - */ - Set getExtraKeywords(); - /** * Does the driver report supporting named parameters? * diff --git a/hibernate-core/src/test/java/org/hibernate/test/jdbc/env/NoDatabaseMetaDataTest.java b/hibernate-core/src/test/java/org/hibernate/test/jdbc/env/NoDatabaseMetaDataTest.java index ef92e999a4..dbe88a7c4e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/jdbc/env/NoDatabaseMetaDataTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/jdbc/env/NoDatabaseMetaDataTest.java @@ -38,7 +38,6 @@ public void testNoJdbcMetadataDefaultDialect() { assertNull( extractedDatabaseMetaData.getConnectionCatalogName() ); assertNull( extractedDatabaseMetaData.getConnectionSchemaName() ); - assertTrue( extractedDatabaseMetaData.getExtraKeywords().isEmpty() ); assertFalse( extractedDatabaseMetaData.supportsNamedParameters() ); assertFalse( extractedDatabaseMetaData.supportsRefCursors() ); assertFalse( extractedDatabaseMetaData.supportsScrollableResults() ); @@ -63,7 +62,6 @@ public void testNoJdbcMetadataDialectOverride() { assertNull( extractedDatabaseMetaData.getConnectionCatalogName() ); assertNull( extractedDatabaseMetaData.getConnectionSchemaName() ); - assertTrue( extractedDatabaseMetaData.getExtraKeywords().isEmpty() ); assertTrue( extractedDatabaseMetaData.supportsNamedParameters() ); assertFalse( extractedDatabaseMetaData.supportsRefCursors() ); assertFalse( extractedDatabaseMetaData.supportsScrollableResults() ); From 5b2289e883fb022beaf1c0dcb6097cd69463e399 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Thu, 10 Jun 2021 12:05:32 +0100 Subject: [PATCH 09/17] HHH-14667 Avoid triggering the load of sequence metadata when not required Also introduce SequenceMismatchStrategy#NONE, which allows to fully disable the checks performed by SequenceMismatchStrategy on initialization; combining these two changes, users have the option to fully skip loading the details about existing sequences from the DB. --- .../userguide/appendices/Configurations.adoc | 2 +- .../org/hibernate/cfg/AvailableSettings.java | 5 +- .../ExtractedDatabaseMetaDataImpl.java | 98 ++++++++++++++++--- .../env/internal/JdbcEnvironmentImpl.java | 60 +++--------- .../internal/JdbcEnvironmentInitiator.java | 3 +- .../id/SequenceMismatchStrategy.java | 8 +- .../id/enhanced/SequenceStyleGenerator.java | 16 +-- .../SkipLoadingSequenceInformationTest.java | 71 ++++++++++++++ ...LServerDialectSequenceInformationTest.java | 10 +- .../test/schemafilter/SequenceFilterTest.java | 1 + .../boot/BasicTestingJdbcServiceImpl.java | 4 +- 11 files changed, 199 insertions(+), 79 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/engine/jdbc/env/internal/SkipLoadingSequenceInformationTest.java diff --git a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc index 333409606e..3f608e0b55 100644 --- a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc +++ b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc @@ -275,7 +275,7 @@ Please report your mapping that causes the problem to us so we can examine the d + The default value is `false` which means Hibernate will use an algorithm to determine if the insert can be delayed or if the insert should be performed immediately. -`*hibernate.id.sequence.increment_size_mismatch_strategy*` (e.g. `LOG`, `FIX` or `EXCEPTION` (default value)):: +`*hibernate.id.sequence.increment_size_mismatch_strategy*` (e.g. `LOG`, `FIX`, `NONE` or `EXCEPTION` (default value)):: This setting defines the `org.hibernate.id.SequenceMismatchStrategy` used when Hibernate detects a mismatch between a sequence configuration in an entity mapping and its database sequence object counterpart. diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index b7efa75376..51e765ebd0 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -2423,8 +2423,9 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { * and its database sequence object counterpart. *

* Possible values are {@link org.hibernate.id.SequenceMismatchStrategy#EXCEPTION}, - * {@link org.hibernate.id.SequenceMismatchStrategy#LOG}, and - * {@link org.hibernate.id.SequenceMismatchStrategy#FIX}. + * {@link org.hibernate.id.SequenceMismatchStrategy#LOG}, + * {@link org.hibernate.id.SequenceMismatchStrategy#FIX} + * and {@link org.hibernate.id.SequenceMismatchStrategy#NONE}. *

* The default value is given by the {@link org.hibernate.id.SequenceMismatchStrategy#EXCEPTION}, * meaning that an Exception is thrown when detecting such a conflict. diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java index 18a40d684c..1ac0389086 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java @@ -6,18 +6,25 @@ */ package org.hibernate.engine.jdbc.env.internal; +import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collections; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; +import org.hibernate.HibernateException; import org.hibernate.boot.model.source.internal.hbm.CommaSeparatedStringHelper; +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; import org.hibernate.engine.jdbc.cursor.internal.StandardRefCursorSupport; import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.env.spi.SQLStateType; +import org.hibernate.tool.schema.extract.spi.ExtractionContext; import org.hibernate.tool.schema.extract.spi.SequenceInformation; /** @@ -26,7 +33,9 @@ * @author Steve Ebersole */ public class ExtractedDatabaseMetaDataImpl implements ExtractedDatabaseMetaData { + private final JdbcEnvironment jdbcEnvironment; + private final JdbcConnectionAccess connectionAccess; private final String connectionCatalogName; private final String connectionSchemaName; @@ -39,11 +48,16 @@ public class ExtractedDatabaseMetaDataImpl implements ExtractedDatabaseMetaData private final boolean supportsDataDefinitionInTransaction; private final boolean doesDataDefinitionCauseTransactionCommit; private final SQLStateType sqlStateType; + private final boolean jdbcMetadataAccessible; - private final List sequenceInformationList; + //Lazily initialized: loading all sequence information upfront has been + //shown to be too slow in some cases. In this way we only load it + //when there is actual need for these details. + private List sequenceInformationList; private ExtractedDatabaseMetaDataImpl( JdbcEnvironment jdbcEnvironment, + JdbcConnectionAccess connectionAccess, String connectionCatalogName, String connectionSchemaName, boolean supportsRefCursors, @@ -54,8 +68,9 @@ private ExtractedDatabaseMetaDataImpl( boolean supportsDataDefinitionInTransaction, boolean doesDataDefinitionCauseTransactionCommit, SQLStateType sqlStateType, - List sequenceInformationList) { + boolean jdbcMetadataIsAccessible) { this.jdbcEnvironment = jdbcEnvironment; + this.connectionAccess = connectionAccess; this.connectionCatalogName = connectionCatalogName; this.connectionSchemaName = connectionSchemaName; this.supportsRefCursors = supportsRefCursors; @@ -66,7 +81,7 @@ private ExtractedDatabaseMetaDataImpl( this.supportsDataDefinitionInTransaction = supportsDataDefinitionInTransaction; this.doesDataDefinitionCauseTransactionCommit = doesDataDefinitionCauseTransactionCommit; this.sqlStateType = sqlStateType; - this.sequenceInformationList = sequenceInformationList; + this.jdbcMetadataAccessible = jdbcMetadataIsAccessible; } @Override @@ -125,12 +140,26 @@ public String getConnectionSchemaName() { } @Override - public List getSequenceInformationList() { - return sequenceInformationList; + public synchronized List getSequenceInformationList() { + if ( jdbcMetadataAccessible ) { + //Loading the sequence information can take a while on large databases, + //even minutes in some cases. + //We trigger this lazily as only certain combinations of configurations, + //mappings and used features actually trigger any use of such details. + if ( sequenceInformationList == null ) { + sequenceInformationList = sequenceInformationList(); + } + return sequenceInformationList; + } + else { + return Collections.emptyList(); + } } public static class Builder { private final JdbcEnvironment jdbcEnvironment; + private final boolean jdbcMetadataIsAccessible; + private final JdbcConnectionAccess connectionAccess; private String connectionSchemaName; private String connectionCatalogName; @@ -143,10 +172,11 @@ public static class Builder { private boolean supportsDataDefinitionInTransaction; private boolean doesDataDefinitionCauseTransactionCommit; private SQLStateType sqlStateType; - private List sequenceInformationList = Collections.emptyList(); - public Builder(JdbcEnvironment jdbcEnvironment) { + public Builder(JdbcEnvironment jdbcEnvironment, boolean jdbcMetadataIsAccessible, JdbcConnectionAccess connectionAccess) { this.jdbcEnvironment = jdbcEnvironment; + this.jdbcMetadataIsAccessible = jdbcMetadataIsAccessible; + this.connectionAccess = connectionAccess; } public Builder apply(DatabaseMetaData databaseMetaData) throws SQLException { @@ -217,14 +247,10 @@ public Builder setSqlStateType(SQLStateType sqlStateType) { return this; } - public Builder setSequenceInformationList(List sequenceInformationList) { - this.sequenceInformationList = sequenceInformationList; - return this; - } - public ExtractedDatabaseMetaDataImpl build() { return new ExtractedDatabaseMetaDataImpl( jdbcEnvironment, + connectionAccess, connectionCatalogName, connectionSchemaName, supportsRefCursors, @@ -235,8 +261,54 @@ public ExtractedDatabaseMetaDataImpl build() { supportsDataDefinitionInTransaction, doesDataDefinitionCauseTransactionCommit, sqlStateType, - sequenceInformationList + jdbcMetadataIsAccessible ); } } + + /** + * Get the sequence information List from the database. + * + * @return sequence information List + */ + private List sequenceInformationList() { + final JdbcEnvironment jdbcEnvironment = this.jdbcEnvironment; + final Dialect dialect = this.jdbcEnvironment.getDialect(); + + Connection connection = null; + try { + connection = connectionAccess.obtainConnection(); + final Connection c = connection; + Iterable sequenceInformationIterable = dialect + .getSequenceInformationExtractor() + .extractMetadata( new ExtractionContext.EmptyExtractionContext() { + @Override + public Connection getJdbcConnection() { + return c; + } + + @Override + public JdbcEnvironment getJdbcEnvironment() { + return jdbcEnvironment; + } + } + ); + return StreamSupport.stream( sequenceInformationIterable.spliterator(), false ) + .collect( Collectors.toList() ); + } + catch (SQLException e) { + throw new HibernateException( "Could not fetch the SequenceInformation from the database", e ); + } + finally { + if ( connection != null ) { + try { + connectionAccess.releaseConnection( connection ); + } + catch (SQLException throwables) { + //ignored + } + } + } + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java index e6fdf2d4a0..ab55ef3d46 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java @@ -6,13 +6,8 @@ */ package org.hibernate.engine.jdbc.env.internal; -import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.registry.selector.spi.StrategySelector; @@ -20,6 +15,7 @@ import org.hibernate.dialect.Dialect; import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.config.spi.StandardConverters; +import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData; import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; @@ -35,8 +31,6 @@ import org.hibernate.exception.internal.StandardSQLExceptionConverter; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.spi.ServiceRegistryImplementor; -import org.hibernate.tool.schema.extract.spi.ExtractionContext; -import org.hibernate.tool.schema.extract.spi.SequenceInformation; import org.jboss.logging.Logger; @@ -64,7 +58,7 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment { * @param serviceRegistry The service registry * @param dialect The resolved dialect. */ - public JdbcEnvironmentImpl(final ServiceRegistryImplementor serviceRegistry, Dialect dialect) { + public JdbcEnvironmentImpl(final ServiceRegistryImplementor serviceRegistry, final Dialect dialect) { this.dialect = dialect; final ConfigurationService cfgService = serviceRegistry.getService( ConfigurationService.class ); @@ -86,7 +80,7 @@ public JdbcEnvironmentImpl(final ServiceRegistryImplementor serviceRegistry, Dia identifierHelperBuilder.setNameQualifierSupport( nameQualifierSupport ); IdentifierHelper identifierHelper = null; - ExtractedDatabaseMetaDataImpl.Builder dbMetaDataBuilder = new ExtractedDatabaseMetaDataImpl.Builder( this ); + ExtractedDatabaseMetaDataImpl.Builder dbMetaDataBuilder = new ExtractedDatabaseMetaDataImpl.Builder( this, false, null ); try { identifierHelper = dialect.buildIdentifierHelper( identifierHelperBuilder, null ); dbMetaDataBuilder.setSupportsNamedParameters( dialect.supportsNamedParameters( null ) ); @@ -150,8 +144,12 @@ private static boolean autoKeywordQuoting(ConfigurationService cfgService) { * Constructor form used from testing * * @param dialect The dialect + * @param jdbcConnectionAccess */ - public JdbcEnvironmentImpl(DatabaseMetaData databaseMetaData, Dialect dialect) throws SQLException { + public JdbcEnvironmentImpl( + DatabaseMetaData databaseMetaData, + Dialect dialect, + JdbcConnectionAccess jdbcConnectionAccess) throws SQLException { this.dialect = dialect; this.sqlExceptionHelper = buildSqlExceptionHelper( dialect, false ); @@ -177,10 +175,9 @@ public JdbcEnvironmentImpl(DatabaseMetaData databaseMetaData, Dialect dialect) t } this.identifierHelper = identifierHelper; - this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl.Builder( this ) + this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl.Builder( this, true, jdbcConnectionAccess ) .apply( databaseMetaData ) .setSupportsNamedParameters( databaseMetaData.supportsNamedParameters() ) - .setSequenceInformationList( sequenceInformationList( databaseMetaData.getConnection() ) ) .build(); this.currentCatalog = null; @@ -224,7 +221,8 @@ else if ( supportsSchemas ) { public JdbcEnvironmentImpl( ServiceRegistryImplementor serviceRegistry, Dialect dialect, - DatabaseMetaData databaseMetaData) throws SQLException { + DatabaseMetaData databaseMetaData, + JdbcConnectionAccess jdbcConnectionAccess) throws SQLException { this.dialect = dialect; final ConfigurationService cfgService = serviceRegistry.getService( ConfigurationService.class ); @@ -256,11 +254,10 @@ public JdbcEnvironmentImpl( } this.identifierHelper = identifierHelper; - this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl.Builder( this ) + this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl.Builder( this, true, jdbcConnectionAccess ) .apply( databaseMetaData ) .setConnectionSchemaName( determineCurrentSchemaName( databaseMetaData, serviceRegistry, dialect ) ) .setSupportsNamedParameters( dialect.supportsNamedParameters( databaseMetaData ) ) - .setSequenceInformationList( sequenceInformationList( databaseMetaData.getConnection() ) ) .build(); // and that current-catalog and current-schema happen after it @@ -369,37 +366,4 @@ public TypeInfo getTypeInfoForJdbcCode(int jdbcTypeCode) { " Use org.hibernate.engine.jdbc.spi.TypeInfo.extractTypeInfo as alternative, or report an issue and explain." ); } - /** - * Get the sequence information List from the database. - * - * @param connection database connection - * @return sequence information List - */ - private List sequenceInformationList(final Connection connection) { - try { - - Iterable sequenceInformationIterable = dialect - .getSequenceInformationExtractor() - .extractMetadata( new ExtractionContext.EmptyExtractionContext() { - @Override - public Connection getJdbcConnection() { - return connection; - } - - @Override - public JdbcEnvironment getJdbcEnvironment() { - return JdbcEnvironmentImpl.this; - } - } - ); - - return StreamSupport.stream( sequenceInformationIterable.spliterator(), false ) - .collect( Collectors.toList() ); - } - catch (SQLException e) { - log.error( "Could not fetch the SequenceInformation from the database", e ); - } - - return Collections.emptyList(); - } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentInitiator.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentInitiator.java index d2563e4251..edf0f769d9 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentInitiator.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentInitiator.java @@ -114,7 +114,8 @@ public DialectResolutionInfo getDialectResolutionInfo() { return new JdbcEnvironmentImpl( registry, dialect, - dbmd + dbmd, + jdbcConnectionAccess ); } catch (SQLException e) { diff --git a/hibernate-core/src/main/java/org/hibernate/id/SequenceMismatchStrategy.java b/hibernate-core/src/main/java/org/hibernate/id/SequenceMismatchStrategy.java index cd90cdf0b9..b9ece879fe 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/SequenceMismatchStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/id/SequenceMismatchStrategy.java @@ -32,7 +32,13 @@ public enum SequenceMismatchStrategy { * When detecting a mismatch, Hibernate tries to fix it by overriding the entity sequence mapping using the one * found in the database. */ - FIX; + FIX, + + /** + * Don't perform any check. This is useful to speedup bootstrap as it won't query the sequences on the DB, + * at cost of not validating the sequences. + */ + NONE; /** * Interpret the configured SequenceMismatchStrategy value. diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java index 2996ad104e..d3d7de7e5c 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java @@ -12,6 +12,7 @@ import org.hibernate.HibernateException; import org.hibernate.MappingException; +import org.hibernate.boot.SchemaAutoTooling; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.model.relational.QualifiedName; @@ -242,19 +243,20 @@ public void configure(Type type, Properties params, ServiceRegistry serviceRegis final boolean isPooledOptimizer = OptimizerFactory.isPooledOptimizer( optimizationStrategy ); - if ( isPooledOptimizer && isPhysicalSequence( jdbcEnvironment, forceTableUse ) ) { + + SequenceMismatchStrategy sequenceMismatchStrategy = configurationService.getSetting( + AvailableSettings.SEQUENCE_INCREMENT_SIZE_MISMATCH_STRATEGY, + SequenceMismatchStrategy::interpret, + SequenceMismatchStrategy.EXCEPTION + ); + + if ( sequenceMismatchStrategy != SequenceMismatchStrategy.NONE && isPooledOptimizer && isPhysicalSequence( jdbcEnvironment, forceTableUse ) ) { String databaseSequenceName = sequenceName.getObjectName().getText(); Long databaseIncrementValue = getSequenceIncrementValue( jdbcEnvironment, databaseSequenceName ); if ( databaseIncrementValue != null && !databaseIncrementValue.equals( (long) incrementSize ) ) { int dbIncrementValue = databaseIncrementValue.intValue(); - SequenceMismatchStrategy sequenceMismatchStrategy = configurationService.getSetting( - AvailableSettings.SEQUENCE_INCREMENT_SIZE_MISMATCH_STRATEGY, - SequenceMismatchStrategy::interpret, - SequenceMismatchStrategy.EXCEPTION - ); - switch ( sequenceMismatchStrategy ) { case EXCEPTION: throw new MappingException( diff --git a/hibernate-core/src/test/java/org/hibernate/engine/jdbc/env/internal/SkipLoadingSequenceInformationTest.java b/hibernate-core/src/test/java/org/hibernate/engine/jdbc/env/internal/SkipLoadingSequenceInformationTest.java new file mode 100644 index 0000000000..8d49430855 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/engine/jdbc/env/internal/SkipLoadingSequenceInformationTest.java @@ -0,0 +1,71 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.engine.jdbc.env.internal; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +import org.hibernate.annotations.GenericGenerator; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.id.SequenceMismatchStrategy; +import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +/** + * Verifies that setting {@code AvailableSettings.SEQUENCE_INCREMENT_SIZE_MISMATCH_STRATEGY} to {@code none} + * is going to skip loading the sequence information from the database. + */ +@TestForIssue( jiraKey = "HHH-14667") +public class SkipLoadingSequenceInformationTest extends BaseCoreFunctionalTestCase { + + @Override + protected void configure(Configuration configuration) { + configuration.setProperty( AvailableSettings.SEQUENCE_INCREMENT_SIZE_MISMATCH_STRATEGY, SequenceMismatchStrategy.NONE.name() ); + configuration.setProperty( Environment.DIALECT, VetoingDialect.class.getName() ); + } + + @Entity(name="seqentity") + static class SequencingEntity { + @Id + @GenericGenerator(name = "pooledoptimizer", strategy = "enhanced-sequence", + parameters = { + @org.hibernate.annotations.Parameter(name = "optimizer", value = "pooled"), + @org.hibernate.annotations.Parameter(name = "initial_value", value = "1"), + @org.hibernate.annotations.Parameter(name = "increment_size", value = "2") + } + ) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "pooledoptimizer") + Integer id; + String name; + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[]{SequencingEntity.class}; + } + + @Test + public void test() { + // If it's able to boot, we're good. + } + + public static class VetoingDialect extends H2Dialect { + @Override + public SequenceInformationExtractor getSequenceInformationExtractor() { + throw new IllegalStateException("Should really not invoke this method in this setup"); + } + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectSequenceInformationTest.java b/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectSequenceInformationTest.java index 5352df7fb9..1193cf8d68 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectSequenceInformationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectSequenceInformationTest.java @@ -22,6 +22,7 @@ import org.hibernate.cfg.Environment; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.SQLServer2012Dialect; +import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; import org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentImpl; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.spi.JdbcServices; @@ -82,15 +83,16 @@ public void testExtractSequenceInformationForSqlServerWithCaseSensitiveCollation ssrb.applySettings( Collections.singletonMap( AvailableSettings.URL, newUrl ) ); StandardServiceRegistry ssr = ssrb.build(); - try ( Connection connection = ssr.getService( JdbcServices.class ) - .getBootstrapJdbcConnectionAccess() - .obtainConnection() ) { + final JdbcConnectionAccess bootstrapJdbcConnectionAccess = ssr.getService( JdbcServices.class ) + .getBootstrapJdbcConnectionAccess(); + + try ( Connection connection = bootstrapJdbcConnectionAccess.obtainConnection() ) { try (Statement statement = connection.createStatement()) { statement.execute( "CREATE SEQUENCE ITEM_SEQ START WITH 100 INCREMENT BY 10" ); } - JdbcEnvironment jdbcEnvironment = new JdbcEnvironmentImpl( connection.getMetaData(), dialect ); + JdbcEnvironment jdbcEnvironment = new JdbcEnvironmentImpl( connection.getMetaData(), dialect, bootstrapJdbcConnectionAccess ); Iterable sequenceInformations = SequenceInformationExtractorLegacyImpl.INSTANCE.extractMetadata( new ExtractionContext.EmptyExtractionContext() { @Override diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemafilter/SequenceFilterTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemafilter/SequenceFilterTest.java index e794cd28b3..fd80567369 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemafilter/SequenceFilterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemafilter/SequenceFilterTest.java @@ -62,6 +62,7 @@ public void setUp() { Map settings = new HashMap(); settings.putAll( Environment.getProperties() ); settings.put( AvailableSettings.DIALECT, H2Dialect.class.getName() ); + settings.put( "hibernate.temp.use_jdbc_metadata_defaults", "false" ); settings.put( AvailableSettings.FORMAT_SQL, false ); this.serviceRegistry = ServiceRegistryBuilder.buildServiceRegistry( settings ); diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/boot/BasicTestingJdbcServiceImpl.java b/hibernate-testing/src/main/java/org/hibernate/testing/boot/BasicTestingJdbcServiceImpl.java index 836c3f50c8..c3ade8b0a1 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/boot/BasicTestingJdbcServiceImpl.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/boot/BasicTestingJdbcServiceImpl.java @@ -58,10 +58,11 @@ public void prepare(boolean allowAggressiveRelease) throws SQLException { dialect = ConnectionProviderBuilder.getCorrespondingDialect(); connectionProvider = ConnectionProviderBuilder.buildConnectionProvider( allowAggressiveRelease ); sqlStatementLogger = new SqlStatementLogger( true, false, false ); + this.jdbcConnectionAccess = new JdbcConnectionAccessImpl( connectionProvider ); Connection jdbcConnection = connectionProvider.getConnection(); try { - jdbcEnvironment = new JdbcEnvironmentImpl( jdbcConnection.getMetaData(), dialect ); + jdbcEnvironment = new JdbcEnvironmentImpl( jdbcConnection.getMetaData(), dialect, jdbcConnectionAccess ); } finally { try { @@ -71,7 +72,6 @@ public void prepare(boolean allowAggressiveRelease) throws SQLException { } } - this.jdbcConnectionAccess = new JdbcConnectionAccessImpl( connectionProvider ); } public void release() { From ee55768587abc2893d26fca1915ac32e86242fa2 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Fri, 11 Jun 2021 10:05:28 +0100 Subject: [PATCH 10/17] HHH-14667 SequenceFilterTest only needs to be run on H2 --- .../test/schemafilter/SequenceFilterTest.java | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemafilter/SequenceFilterTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemafilter/SequenceFilterTest.java index fd80567369..f64b90feb1 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemafilter/SequenceFilterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemafilter/SequenceFilterTest.java @@ -6,19 +6,16 @@ */ package org.hibernate.test.schemafilter; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.SequenceGenerator; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; - -import org.hamcrest.BaseMatcher; -import org.hamcrest.Description; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.SequenceGenerator; import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; @@ -34,16 +31,17 @@ import org.hibernate.tool.schema.internal.SchemaDropperImpl; import org.hibernate.tool.schema.spi.SchemaFilter; +import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.ServiceRegistryBuilder; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseUnitTestCase; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.hibernate.testing.DialectChecks; -import org.hibernate.testing.RequiresDialectFeature; -import org.hibernate.testing.ServiceRegistryBuilder; -import org.hibernate.testing.TestForIssue; -import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; import static org.hibernate.test.schemafilter.RecordingTarget.Category.SEQUENCE_CREATE; import static org.hibernate.test.schemafilter.RecordingTarget.Category.SEQUENCE_DROP; @@ -52,7 +50,7 @@ * @author Andrea Boriero */ @TestForIssue(jiraKey = "HHH-10937") -@RequiresDialectFeature(value = {DialectChecks.SupportSchemaCreation.class}) +@RequiresDialect(H2Dialect.class) public class SequenceFilterTest extends BaseUnitTestCase { private StandardServiceRegistryImpl serviceRegistry; private Metadata metadata; From e2f24c5436316fc09792fe9801151e189269af48 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 14 Jun 2021 15:31:48 +0100 Subject: [PATCH 11/17] HHH-14667 Maintain backwards compatibility for Hibernate Reactive --- .../env/internal/JdbcEnvironmentImpl.java | 19 ++++++++++++++----- .../engine/jdbc/env/spi/JdbcEnvironment.java | 10 ++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java index ab55ef3d46..e19585abbc 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java @@ -209,6 +209,20 @@ else if ( supportsSchemas ) { } } + /** + * @deprecated currently used by Hibernate Reactive + * This version of the constructor should handle the case in which we do actually have the option to access the DatabaseMetaData, + * but since Hibernate Reactive is currently not making use of it we take a shortcut. + */ + @Deprecated + public JdbcEnvironmentImpl( + ServiceRegistryImplementor serviceRegistry, + Dialect dialect, + DatabaseMetaData databaseMetaData + /*JdbcConnectionAccess jdbcConnectionAccess*/) throws SQLException { + this(serviceRegistry, dialect); + } + /** * The main constructor form. Builds a JdbcEnvironment using the available DatabaseMetaData * @@ -361,9 +375,4 @@ public LobCreatorBuilder getLobCreatorBuilder() { return lobCreatorBuilder; } - public TypeInfo getTypeInfoForJdbcCode(int jdbcTypeCode) { - throw new UnsupportedOperationException( "Support for getting TypeInfo from jdbcTypeCode has been disabled as it wasn't used." + - " Use org.hibernate.engine.jdbc.spi.TypeInfo.extractTypeInfo as alternative, or report an issue and explain." ); - } - } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java index 3d4f79a1c8..2a9fa57f0b 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java @@ -9,6 +9,7 @@ import org.hibernate.boot.model.naming.Identifier; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; +import org.hibernate.engine.jdbc.spi.TypeInfo; import org.hibernate.service.Service; /** @@ -88,4 +89,13 @@ public interface JdbcEnvironment extends Service { */ LobCreatorBuilder getLobCreatorBuilder(); + /** + * @deprecated This is currently not implemented an will likely be removed + * (A default method is provided to facilitate removal from implementors) + */ + @Deprecated + default TypeInfo getTypeInfoForJdbcCode(int jdbcTypeCode) { + throw new UnsupportedOperationException( "Support for getting TypeInfo from jdbcTypeCode has been disabled as it wasn't used. Use org.hibernate.engine.jdbc.spi.TypeInfo.extractTypeInfo as alternative, or report an issue and explain." ); + } + } From f91fe0335276896cafcdf841f1ec9d8cbbfb1417 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Fri, 11 Jun 2021 11:52:01 -0500 Subject: [PATCH 12/17] HHH-14679 - Deprecate ResultSetWrapper and friends --- .../hibernate/boot/internal/SessionFactoryOptionsBuilder.java | 1 + .../java/org/hibernate/boot/spi/SessionFactoryOptions.java | 4 ++++ .../src/main/java/org/hibernate/cfg/AvailableSettings.java | 3 +++ .../main/java/org/hibernate/engine/jdbc/ColumnNameCache.java | 3 +++ .../java/org/hibernate/engine/jdbc/ResultSetWrapperProxy.java | 3 +++ .../hibernate/engine/jdbc/internal/ResultSetWrapperImpl.java | 4 +++- .../java/org/hibernate/engine/jdbc/spi/ResultSetWrapper.java | 3 +++ 7 files changed, 20 insertions(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java index 7ddff3bf79..2f8bf765a9 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java @@ -1273,6 +1273,7 @@ public void enableScrollableResultSupport(boolean enabled) { this.scrollableResultSetsEnabled = enabled; } + @Deprecated public void enableResultSetWrappingSupport(boolean enabled) { this.wrapResultSetsEnabled = enabled; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java index df6e62f99c..632abf1cb9 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java @@ -219,6 +219,10 @@ default boolean isStrictJpaQueryLanguageCompliance() { boolean isScrollableResultSetsEnabled(); + /** + * @deprecated (since 5.5) Scheduled for removal in 6.0 as ResultSet wrapping is no longer needed + */ + @Deprecated boolean isWrapResultSetsEnabled(); boolean isGetGeneratedKeysEnabled(); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index 51e765ebd0..a40320d3b7 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -1114,7 +1114,10 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { /** * Enable wrapping of JDBC result sets in order to speed up column name lookups for * broken JDBC drivers + * + * @deprecated (since 5.5) Scheduled for removal in 6.0 as ResultSet wrapping is no longer needed */ + @Deprecated String WRAP_RESULT_SETS = "hibernate.jdbc.wrap_result_sets"; /** diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/ColumnNameCache.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/ColumnNameCache.java index b231a00e0a..52897f8b18 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/ColumnNameCache.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/ColumnNameCache.java @@ -13,8 +13,11 @@ /** * Cache of column-name -> column-index resolutions * + * @deprecated (since 5.5) Scheduled for removal in 6.0 as ResultSet wrapping is no longer needed + * * @author Steve Ebersole */ +@Deprecated public final class ColumnNameCache { private static final float LOAD_FACTOR = .75f; diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/ResultSetWrapperProxy.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/ResultSetWrapperProxy.java index d179c0af9c..6db6cc63a3 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/ResultSetWrapperProxy.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/ResultSetWrapperProxy.java @@ -27,9 +27,12 @@ * A proxy for a ResultSet delegate, responsible for locally caching the columnName-to-columnIndex resolution that * has been found to be inefficient in a few vendor's drivers (i.e., Oracle and Postgres). * + * @deprecated (since 5.5) Scheduled for removal in 6.0 as ResultSet wrapping is no longer needed + * * @author Steve Ebersole * @author Gail Badner */ +@Deprecated public class ResultSetWrapperProxy implements InvocationHandler { private static final CoreMessageLogger LOG = messageLogger( ResultSetWrapperProxy.class ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/ResultSetWrapperImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/ResultSetWrapperImpl.java index 46eacc8810..4f267c9a00 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/ResultSetWrapperImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/ResultSetWrapperImpl.java @@ -8,7 +8,6 @@ import java.sql.ResultSet; -import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.engine.jdbc.ColumnNameCache; import org.hibernate.engine.jdbc.ResultSetWrapperProxy; import org.hibernate.engine.jdbc.spi.ResultSetWrapper; @@ -18,9 +17,12 @@ * Standard Hibernate implementation for wrapping a {@link ResultSet} in a " column name cache" wrapper. * + * @deprecated (since 5.5) Scheduled for removal in 6.0 as ResultSet wrapping is no longer needed + * * @author Steve Ebersole * @author Gail Badner */ +@Deprecated public class ResultSetWrapperImpl implements ResultSetWrapper { private final ServiceRegistry serviceRegistry; diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/ResultSetWrapper.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/ResultSetWrapper.java index 355bbc7857..59e99686a9 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/ResultSetWrapper.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/ResultSetWrapper.java @@ -13,8 +13,11 @@ /** * Contract for wrapping a {@link ResultSet} in a "column name cache" wrapper. * + * @deprecated (since 5.5) Scheduled for removal in 6.0 as ResultSet wrapping is no longer needed + * * @author Gail Badner */ +@Deprecated public interface ResultSetWrapper { /** * Wrap a result set in a "column name cache" wrapper. From 423b13b50ae7940c11807a4b8c545d16a12e8059 Mon Sep 17 00:00:00 2001 From: Markus Heiden Date: Tue, 8 Jun 2021 01:01:06 +0200 Subject: [PATCH 13/17] HHH-14657 Use the compile instead of runtime classpath The runtime classpath contains the dependencies as jars that are not yet built when the plugin needs them. So use the compile classpath plus the compiled classes of the current project. --- .../orm/tooling/gradle/EnhancementHelper.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tooling/hibernate-gradle-plugin/src/main/groovy/org/hibernate/orm/tooling/gradle/EnhancementHelper.java b/tooling/hibernate-gradle-plugin/src/main/groovy/org/hibernate/orm/tooling/gradle/EnhancementHelper.java index 927fa254e5..85982c8c5b 100644 --- a/tooling/hibernate-gradle-plugin/src/main/groovy/org/hibernate/orm/tooling/gradle/EnhancementHelper.java +++ b/tooling/hibernate-gradle-plugin/src/main/groovy/org/hibernate/orm/tooling/gradle/EnhancementHelper.java @@ -37,7 +37,7 @@ */ public class EnhancementHelper { static void enhance(SourceSet sourceSet, EnhanceExtension options, Project project) { - final ClassLoader classLoader = toClassLoader( sourceSet.getRuntimeClasspath() ); + final ClassLoader classLoader = toClassLoader( sourceSet.getCompileClasspath(), sourceSet.getOutput().getClassesDirs() ); final EnhancementContext enhancementContext = new DefaultEnhancementContext() { @Override @@ -96,14 +96,16 @@ public boolean doExtendedEnhancement(UnloadedClass classDescriptor) { } } - public static ClassLoader toClassLoader(FileCollection runtimeClasspath) { + public static ClassLoader toClassLoader(FileCollection... classpaths) { List urls = new ArrayList<>(); - for ( File file : runtimeClasspath ) { - try { - urls.add( file.toURI().toURL() ); - } - catch (MalformedURLException e) { - throw new GradleException( "Unable to resolve classpath entry to URL : " + file.getAbsolutePath(), e ); + for ( FileCollection classpath : classpaths ) { + for ( File file : classpath ) { + try { + urls.add( file.toURI().toURL() ); + } + catch (MalformedURLException e) { + throw new GradleException( "Unable to resolve classpath entry to URL : " + file.getAbsolutePath(), e ); + } } } return new URLClassLoader( urls.toArray( new URL[0] ), Enhancer.class.getClassLoader() ); From 26038d1b002ed02692a37a6c6156fea243f870eb Mon Sep 17 00:00:00 2001 From: Markus Heiden Date: Tue, 8 Jun 2021 01:01:06 +0200 Subject: [PATCH 14/17] HHH-14657 Use the compile instead of runtime classpath The runtime classpath contains the dependencies as jars that are not yet built when the plugin needs them. So use the compile classpath plus the compiled classes of the current project. --- .../org/hibernate/orm/tooling/gradle/EnhancementHelper.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tooling/hibernate-gradle-plugin/src/main/groovy/org/hibernate/orm/tooling/gradle/EnhancementHelper.java b/tooling/hibernate-gradle-plugin/src/main/groovy/org/hibernate/orm/tooling/gradle/EnhancementHelper.java index 85982c8c5b..2afc97d04f 100644 --- a/tooling/hibernate-gradle-plugin/src/main/groovy/org/hibernate/orm/tooling/gradle/EnhancementHelper.java +++ b/tooling/hibernate-gradle-plugin/src/main/groovy/org/hibernate/orm/tooling/gradle/EnhancementHelper.java @@ -37,6 +37,11 @@ */ public class EnhancementHelper { static void enhance(SourceSet sourceSet, EnhanceExtension options, Project project) { + // The compile classpath contains the jar dependencies and + // the output directories with the compiled classes of project dependencies in a multi-project build. + // The classes directories contain the compiled classes of this project. + // The runtime classpath cannot be used for this purpose + // because it contains the jars of project dependencies which are not yet built. final ClassLoader classLoader = toClassLoader( sourceSet.getCompileClasspath(), sourceSet.getOutput().getClassesDirs() ); final EnhancementContext enhancementContext = new DefaultEnhancementContext() { From 1b1a6e7c1c782ef521278f89f62639c314ee9d6a Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Mon, 14 Jun 2021 15:40:24 +0000 Subject: [PATCH 15/17] 5.5.2.Final --- changelog.txt | 13 +++++++++++++ gradle/version.properties | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 7032ce85a2..c1070194e0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,19 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.5.2.Final (June 14, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/31957 + +** Bug + * [HHH-14609] - Fetch join association within fetched element collection fails + * [HHH-14608] - Merge causes StackOverflow when JPA proxy compliance is enabled + +** Task + * [HHH-14599] - Upgrade to Gradle 7 in support of Java 17 + + Changes in 5.5.0.Final (June 01, 2021) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index d5d6d7f95f..cf08f61f7d 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.1-SNAPSHOT \ No newline at end of file +hibernateVersion=5.5.2.Final \ No newline at end of file From d345516ab8cc11d6d43b80586efadba0caa766fa Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Mon, 14 Jun 2021 15:45:29 +0000 Subject: [PATCH 16/17] 5.5.2-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index cf08f61f7d..cf7403230f 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.2.Final \ No newline at end of file +hibernateVersion=5.5.2-SNAPSHOT \ No newline at end of file From 9630ca9a7f7272f923745d282c816d7eddb89df3 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 14 Jun 2021 20:26:08 +0100 Subject: [PATCH 17/17] Actually next will be 5.5.3-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index cf7403230f..df60010858 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.2-SNAPSHOT \ No newline at end of file +hibernateVersion=5.5.3-SNAPSHOT