From e91901946a9388368e962a0418b797271a8ba436 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 21 Jun 2021 11:37:19 +0100 Subject: [PATCH 1/7] HHH-14690 Avoid fully resetting StatisticsImpl just after its constructor --- .../java/org/hibernate/stat/internal/StatisticsImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java index 70a1fe847a..8663465fce 100644 --- a/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java @@ -122,7 +122,7 @@ public class StatisticsImpl implements StatisticsImplementor, Service, Manageabl Statistics.DEFAULT_QUERY_STATISTICS_MAX_SIZE, 20 ); - clear(); + resetStartTime(); metamodel = sessionFactory.getMetamodel(); cache = sessionFactory.getCache(); cacheRegionPrefix = sessionFactoryOptions.getCacheRegionPrefix(); @@ -192,6 +192,10 @@ public class StatisticsImpl implements StatisticsImplementor, Service, Manageabl queryPlanCacheHitCount.reset(); queryPlanCacheMissCount.reset(); + resetStartTime(); + } + + private void resetStartTime() { startTime = System.currentTimeMillis(); } From 916849a8af149b8239c423182b756dcf8ea74cec Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 22 Jun 2021 11:16:22 +0100 Subject: [PATCH 2/7] HHH-14691 Small optimisation for updating Query Cache Statistics --- .../stat/internal/StatisticsImpl.java | 29 +++++----- .../stat/internal/StatsNamedContainer.java | 27 ++++++---- ...tsNamedContainerNullComputedValueTest.java | 53 ++++++++++++++++++- 3 files changed, 82 insertions(+), 27 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java index 8663465fce..e02f7ecde9 100644 --- a/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java @@ -563,24 +563,21 @@ public class StatisticsImpl implements StatisticsImplementor, Service, Manageabl } @Override - public CacheRegionStatisticsImpl getQueryRegionStatistics(String regionName) { - final CacheRegionStatisticsImpl existing = l2CacheStatsMap.get( regionName ); - if ( existing != null ) { - return existing; - } - - final QueryResultsCache regionAccess = cache - .getQueryResultsCacheStrictly( regionName ); - if ( regionAccess == null ) { - return null; - } - - return l2CacheStatsMap.getOrCompute( - regionName, - s -> new CacheRegionStatisticsImpl( regionAccess.getRegion() ) - ); + public CacheRegionStatisticsImpl getQueryRegionStatistics(final String regionName) { + return l2CacheStatsMap.getOrCompute( regionName, this::computeQueryRegionStatistics ); } + private CacheRegionStatisticsImpl computeQueryRegionStatistics(final String regionName) { + final QueryResultsCache regionAccess = cache.getQueryResultsCacheStrictly( regionName ); + if ( regionAccess == null ) { + return null; //this null value will be cached + } + else { + return new CacheRegionStatisticsImpl( regionAccess.getRegion() ); + } + } + + @Override public CacheRegionStatisticsImpl getCacheRegionStatistics(String regionName) { if ( ! secondLevelCacheEnabled ) { diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/StatsNamedContainer.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatsNamedContainer.java index dcf195a056..8e85c4aecb 100644 --- a/hibernate-core/src/main/java/org/hibernate/stat/internal/StatsNamedContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatsNamedContainer.java @@ -25,7 +25,8 @@ import org.hibernate.internal.util.collections.BoundedConcurrentHashMap; */ final class StatsNamedContainer { - private final ConcurrentMap map; + private final ConcurrentMap map; + private final static Object NULL_TOKEN = new Object(); /** * Creates a bounded container - based on BoundedConcurrentHashMap @@ -63,33 +64,39 @@ final class StatsNamedContainer { * sure the function is invoked at most once: we don't need this guarantee, and prefer to reduce risk of blocking. */ public V getOrCompute(final String key, final Function function) { - final V v1 = map.get( key ); + final Object v1 = map.get( key ); if ( v1 != null ) { - return v1; + if ( v1 == NULL_TOKEN ) { + return null; + } + return (V) v1; } else { final V v2 = function.apply( key ); - //Occasionally a function might return null. We can't store a null in the CHM, - // so a placeholder would be required to implement that, but we prefer to just keep this - // situation as slightly sub-optimal so to not make the code more complex just to handle the exceptional case: - // null values are assumed to be rare enough for this not being worth it. if ( v2 == null ) { + map.put( key, NULL_TOKEN ); return null; } else { - final V v3 = map.putIfAbsent( key, v2 ); + final Object v3 = map.putIfAbsent( key, v2 ); if ( v3 == null ) { return v2; } else { - return v3; + return (V) v3; } } } } public V get(final String key) { - return map.get( key ); + final Object o = map.get( key ); + if ( o == NULL_TOKEN) { + return null; + } + else { + return (V) o; + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/stat/internal/StatsNamedContainerNullComputedValueTest.java b/hibernate-core/src/test/java/org/hibernate/stat/internal/StatsNamedContainerNullComputedValueTest.java index afd5b1088d..307ba75034 100644 --- a/hibernate-core/src/test/java/org/hibernate/stat/internal/StatsNamedContainerNullComputedValueTest.java +++ b/hibernate-core/src/test/java/org/hibernate/stat/internal/StatsNamedContainerNullComputedValueTest.java @@ -6,14 +6,21 @@ */ package org.hibernate.stat.internal; +import java.util.concurrent.atomic.AtomicInteger; + import org.hibernate.testing.TestForIssue; +import org.junit.Assert; import org.junit.Test; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertNull; @TestForIssue(jiraKey = "HHH-13645") public class StatsNamedContainerNullComputedValueTest { + private final static AtomicInteger invocationCounterNullProducer = new AtomicInteger(); + private final static AtomicInteger invocationCounterValueProducer = new AtomicInteger(); + @Test public void testNullComputedValue() { final StatsNamedContainer statsNamedContainer = new StatsNamedContainer(); @@ -27,4 +34,48 @@ public class StatsNamedContainerNullComputedValueTest { ); } -} \ No newline at end of file + @Test + public void abletoStoreNullValues() { + final StatsNamedContainer statsNamedContainer = new StatsNamedContainer(); + Assert.assertEquals( 0, invocationCounterNullProducer.get() ); + assertNull( getCacheWithNullValue( statsNamedContainer ) ); + Assert.assertEquals( 1, invocationCounterNullProducer.get() ); + assertNull( getCacheWithNullValue( statsNamedContainer ) ); + Assert.assertEquals( 1, invocationCounterNullProducer.get() ); + } + + @Test + public void abletoStoreActualValues() { + final StatsNamedContainer statsNamedContainer = new StatsNamedContainer(); + Assert.assertEquals( 0, invocationCounterValueProducer.get() ); + Assert.assertEquals( 5, getCacheWithActualValue( statsNamedContainer ) ); + Assert.assertEquals( 1, invocationCounterValueProducer.get() ); + Assert.assertEquals( 5, getCacheWithActualValue( statsNamedContainer ) ); + Assert.assertEquals( 1, invocationCounterValueProducer.get() ); + } + + private Object getCacheWithActualValue(StatsNamedContainer statsNamedContainer) { + return statsNamedContainer.getOrCompute( + "key", + StatsNamedContainerNullComputedValueTest::produceValue + ); + } + + private Object getCacheWithNullValue(StatsNamedContainer statsNamedContainer) { + return statsNamedContainer.getOrCompute( + "key", + StatsNamedContainerNullComputedValueTest::produceNull + ); + } + + private static Integer produceValue(Object o) { + invocationCounterValueProducer.getAndIncrement(); + return Integer.valueOf( 5 ); + } + + private static Integer produceNull(Object v) { + invocationCounterNullProducer.getAndIncrement(); + return null; + } + +} From dfdc439f662d656117bc0018ec0d2627f62935bc Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Tue, 17 Dec 2019 13:49:40 +0000 Subject: [PATCH 3/7] HHH-13788 Add test for issue --- ...faultsSettingToFalseAndQuotedNameTest.java | 147 ++++++++++++++++++ ...dbcMetadataDefaultsSettingToFalseTest.java | 141 +++++++++++++++++ 2 files changed, 288 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseAndQuotedNameTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseAndQuotedNameTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseAndQuotedNameTest.java new file mode 100644 index 0000000000..a41cf20036 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseAndQuotedNameTest.java @@ -0,0 +1,147 @@ +/* + * 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 http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.schemaupdate; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.EnumSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.dialect.Dialect; +import org.hibernate.tool.hbm2ddl.SchemaExport; +import org.hibernate.tool.hbm2ddl.SchemaUpdate; +import org.hibernate.tool.hbm2ddl.SchemaValidator; +import org.hibernate.tool.schema.JdbcMetadaAccessStrategy; +import org.hibernate.tool.schema.TargetType; + +import org.hibernate.testing.TestForIssue; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +@TestForIssue(jiraKey = "HHH-13788") +@RunWith(Parameterized.class) +public class SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseAndQuotedNameTest { + @Parameterized.Parameters + public static String[] parameters() { + return new String[] { + JdbcMetadaAccessStrategy.GROUPED.toString(), + JdbcMetadaAccessStrategy.INDIVIDUALLY.toString() + }; + } + + @Parameterized.Parameter + public String jdbcMetadataExtractorStrategy; + + private File updateOutputFile; + private File createOutputFile; + private StandardServiceRegistry ssr; + private MetadataImplementor metadata; + + @Before + public void setUp() throws IOException { + createOutputFile = File.createTempFile( "create_script", ".sql" ); + createOutputFile.deleteOnExit(); + updateOutputFile = File.createTempFile( "update_script", ".sql" ); + updateOutputFile.deleteOnExit(); + ssr = new StandardServiceRegistryBuilder() + .applySetting( "hibernate.temp.use_jdbc_metadata_defaults", "false" ) + .applySetting( AvailableSettings.SHOW_SQL, "true" ) + .applySetting( + AvailableSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY, + jdbcMetadataExtractorStrategy + ) + .build(); + + final MetadataSources metadataSources = new MetadataSources( ssr ); + metadataSources.addAnnotatedClass( AnotherTestEntity.class ); + + metadata = (MetadataImplementor) metadataSources.buildMetadata(); + metadata.validate(); + } + + @After + public void tearDown() { + new SchemaExport().setHaltOnError( true ) + .setFormat( false ) + .drop( EnumSet.of( TargetType.DATABASE ), metadata ); + StandardServiceRegistryBuilder.destroy( ssr ); + } + + @Test + public void testSchemaUpdateDoesNotTryToRecreateExistingTables() + throws Exception { + createSchema(); + + new SchemaUpdate().setHaltOnError( true ) + .setOutputFile( updateOutputFile.getAbsolutePath() ) + .setFormat( false ) + .execute( EnumSet.of( TargetType.DATABASE, TargetType.SCRIPT ), metadata ); + + checkNoUpdateStatementHasBeenGenerated(); + } + + private void checkNoUpdateStatementHasBeenGenerated() throws IOException { + final String fileContent = new String( Files.readAllBytes( updateOutputFile.toPath() ) ); + assertThat( + "The update output file should be empty because the db schema had already been generated and the domain model was not modified", + fileContent, + is( "" ) + ); + } + + private void createSchema() throws Exception { + new SchemaUpdate().setHaltOnError( true ) + .setOutputFile( createOutputFile.getAbsolutePath() ) + .execute( EnumSet.of( TargetType.DATABASE, TargetType.SCRIPT ), metadata ); + new SchemaValidator().validate( metadata ); + checkSchemaHasBeenGenerated(); + } + + private void checkSchemaHasBeenGenerated() throws Exception { + String fileContent = new String( Files.readAllBytes( createOutputFile.toPath() ) ); + final Dialect dialect = metadata.getDatabase().getDialect(); + Pattern fileContentPattern; + if ( dialect.openQuote() == '[' ) { + fileContentPattern = Pattern.compile( "create( (column|row))? table " + "\\[" + "another_test_entity" + "\\]" ); + } + else { + fileContentPattern = Pattern.compile( "create( (column|row))? table " + dialect.openQuote() + "another_test_entity" + dialect + .closeQuote() ); + } + Matcher fileContentMatcher = fileContentPattern.matcher( fileContent.toLowerCase() ); + assertThat( + "The schema has not been correctly generated, Script file : " + fileContent.toLowerCase(), + fileContentMatcher.find(), + is( true ) + ); + } + + @Entity(name = "`Another_Test_Entity`") + public static class AnotherTestEntity { + @Id + private Long id; + + @Column(name = "`another_NAME`") + private String name; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseTest.java new file mode 100644 index 0000000000..3d3eedf777 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseTest.java @@ -0,0 +1,141 @@ +/* + * 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 http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.schemaupdate; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.EnumSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.tool.hbm2ddl.SchemaExport; +import org.hibernate.tool.hbm2ddl.SchemaUpdate; +import org.hibernate.tool.hbm2ddl.SchemaValidator; +import org.hibernate.tool.schema.JdbcMetadaAccessStrategy; +import org.hibernate.tool.schema.TargetType; + +import org.hibernate.testing.TestForIssue; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +/** + * @author Andrea Boriero + */ +@TestForIssue(jiraKey = "HHH-13788") +@RunWith(Parameterized.class) +public class SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseTest { + + @Parameterized.Parameters + public static String[] parameters() { + return new String[] { + JdbcMetadaAccessStrategy.GROUPED.toString(), + JdbcMetadaAccessStrategy.INDIVIDUALLY.toString() + }; + } + + @Parameterized.Parameter + public String jdbcMetadataExtractorStrategy; + + private File updateOutputFile; + private File createOutputFile; + private StandardServiceRegistry ssr; + private MetadataImplementor metadata; + + @Before + public void setUp() throws IOException { + createOutputFile = File.createTempFile( "create_script", ".sql" ); + createOutputFile.deleteOnExit(); + updateOutputFile = File.createTempFile( "update_script", ".sql" ); + updateOutputFile.deleteOnExit(); + ssr = new StandardServiceRegistryBuilder() + .applySetting( "hibernate.temp.use_jdbc_metadata_defaults", "false" ) + .applySetting( AvailableSettings.SHOW_SQL, "true" ) + .applySetting( + AvailableSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY, + jdbcMetadataExtractorStrategy + ) + .build(); + + final MetadataSources metadataSources = new MetadataSources( ssr ); + metadataSources.addAnnotatedClass( TestEntity.class ); + + metadata = (MetadataImplementor) metadataSources.buildMetadata(); + metadata.validate(); + } + + @After + public void tearDown() { + new SchemaExport().setHaltOnError( true ) + .setFormat( false ) + .drop( EnumSet.of( TargetType.DATABASE ), metadata ); + StandardServiceRegistryBuilder.destroy( ssr ); + } + + @Test + public void testSchemaUpdateDoesNotTryToRecreateExistingTables() + throws Exception { + createSchema(); + + new SchemaUpdate().setHaltOnError( true ) + .setOutputFile( updateOutputFile.getAbsolutePath() ) + .setFormat( false ) + .execute( EnumSet.of( TargetType.DATABASE, TargetType.SCRIPT ), metadata ); + + checkNoUpdateStatementHasBeenGenerated(); + } + + private void checkNoUpdateStatementHasBeenGenerated() throws IOException { + final String fileContent = new String( Files.readAllBytes( updateOutputFile.toPath() ) ); + assertThat( + "The update output file should be empty because the db schema had already been generated and the domain model was not modified", + fileContent, + is( "" ) + ); + } + + private void createSchema() throws Exception { + new SchemaUpdate().setHaltOnError( true ) + .setOutputFile( createOutputFile.getAbsolutePath() ) + .execute( EnumSet.of( TargetType.DATABASE, TargetType.SCRIPT ), metadata ); + new SchemaValidator().validate( metadata ); + checkSchemaHasBeenGenerated(); + } + + private void checkSchemaHasBeenGenerated() throws Exception { + String fileContent = new String( Files.readAllBytes( createOutputFile.toPath() ) ); + Pattern fileContentPattern = Pattern.compile( "create( (column|row))? table my_test_entity" ); + Matcher fileContentMatcher = fileContentPattern.matcher( fileContent.toLowerCase() ); + assertThat( + "The schema has not been correctly generated, Script file : " + fileContent.toLowerCase(), + fileContentMatcher.find(), + is( true ) + ); + } + + @Entity(name = "My_Test_Entity") + public static class TestEntity { + @Id + private Long id; + + private String name; + } +} From b17e17cdb63cfec3bb8360b80fccec9b4bbba579 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Tue, 17 Dec 2019 13:51:02 +0000 Subject: [PATCH 4/7] HHH-13788 Schema update try to recreate existing tables --- ...tionExtractorJdbcDatabaseMetaDataImpl.java | 154 +++++++++++++++--- 1 file changed, 128 insertions(+), 26 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java index 8ff9abb13b..4a67ba2d3c 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java @@ -29,6 +29,8 @@ import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.config.spi.StandardConverters; import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; @@ -59,12 +61,26 @@ public class InformationExtractorJdbcDatabaseMetaDataImpl implements Information private final ExtractionContext extractionContext; + private final boolean useJdbcMetadataDefaultsSetting; + + private Identifier currentCatalog; + private Identifier currentSchema; + + private String currentCatalogFilter; + private String currentSchemaFilter; + public InformationExtractorJdbcDatabaseMetaDataImpl(ExtractionContext extractionContext) { this.extractionContext = extractionContext; ConfigurationService configService = extractionContext.getServiceRegistry() .getService( ConfigurationService.class ); + useJdbcMetadataDefaultsSetting = configService.getSetting( + "hibernate.temp.use_jdbc_metadata_defaults", + StandardConverters.BOOLEAN, + Boolean.TRUE + ); + final String extraPhysycalTableTypesConfig = configService.getSetting( AvailableSettings.EXTRA_PHYSICAL_TABLE_TYPES, StandardConverters.STRING, @@ -229,11 +245,14 @@ public class InformationExtractorJdbcDatabaseMetaDataImpl implements Information TableInformation tableInfo = null; // 1) look in current namespace - if ( extractionContext.getJdbcEnvironment().getCurrentCatalog() != null - || extractionContext.getJdbcEnvironment().getCurrentSchema() != null ) { + final JdbcEnvironment jdbcEnvironment = extractionContext.getJdbcEnvironment(); + final Identifier currentSchema = getCurrentSchema( jdbcEnvironment ); + final Identifier currentCatalog = getCurrentCatalog( jdbcEnvironment ); + if ( currentCatalog != null + || currentSchema != null ) { tableInfo = locateTableInNamespace( - extractionContext.getJdbcEnvironment().getCurrentCatalog(), - extractionContext.getJdbcEnvironment().getCurrentSchema(), + currentCatalog, + currentSchema, tableName ); @@ -288,23 +307,106 @@ public class InformationExtractorJdbcDatabaseMetaDataImpl implements Information } } + private Identifier getCurrentSchema(JdbcEnvironment jdbcEnvironment) { + if ( currentSchema != null ) { + return currentSchema; + } + final Identifier schema = jdbcEnvironment.getCurrentSchema(); + if ( schema != null ) { + currentSchema = schema; + } + if ( !useJdbcMetadataDefaultsSetting ) { + try { + currentSchema = extractionContext.getJdbcEnvironment() + .getIdentifierHelper() + .toIdentifier( extractionContext.getJdbcConnection().getSchema() ); + } + catch (SQLException ignore) { + log.sqlWarning( ignore.getErrorCode(), ignore.getSQLState() ); + } + } + return currentCatalog; + } + + private Identifier getCurrentCatalog(JdbcEnvironment jdbcEnvironment) { + if ( currentCatalog != null ) { + return currentCatalog; + } + final Identifier catalog = jdbcEnvironment.getCurrentCatalog(); + if ( catalog != null ) { + currentCatalog = catalog; + } + if ( !useJdbcMetadataDefaultsSetting ) { + try { + currentCatalog = extractionContext.getJdbcEnvironment() + .getIdentifierHelper() + .toIdentifier( extractionContext.getJdbcConnection().getCatalog() ); + } + catch (SQLException ignore) { + log.sqlWarning( ignore.getErrorCode(), ignore.getSQLState() ); + } + } + return currentCatalog; + } + + private String getCurrentCatalogFilter(JdbcEnvironment jdbcEnvironment) { + if ( currentCatalogFilter != null ) { + return currentCatalogFilter; + } + final Identifier currentCatalog = jdbcEnvironment.getCurrentCatalog(); + if ( currentCatalog != null ) { + currentCatalogFilter = toMetaDataObjectName( currentCatalog ); + } + if ( !useJdbcMetadataDefaultsSetting ) { + try { + currentCatalogFilter = extractionContext.getJdbcConnection().getCatalog(); + } + catch (SQLException ignore) { + log.sqlWarning( ignore.getErrorCode(), ignore.getSQLState() ); + } + } + return currentCatalogFilter; + } + + private String getCurrentSchemaFilter(JdbcEnvironment jdbcEnvironment) { + if ( currentSchemaFilter != null ) { + return currentSchemaFilter; + } + final Identifier currentSchema = jdbcEnvironment.getCurrentSchema(); + if ( currentSchema != null ) { + currentSchemaFilter = toMetaDataObjectName( currentSchema ); + } + + if ( !useJdbcMetadataDefaultsSetting ) { + try { + currentSchemaFilter = extractionContext.getJdbcConnection().getSchema(); + } + catch (SQLException ignore) { + log.sqlWarning( ignore.getErrorCode(), ignore.getSQLState() ); + } + } + return currentSchemaFilter; + } + public NameSpaceTablesInformation getTables(Identifier catalog, Identifier schema) { String catalogFilter = null; String schemaFilter = null; - if ( extractionContext.getJdbcEnvironment().getNameQualifierSupport().supportsCatalogs() ) { + final JdbcEnvironment jdbcEnvironment = extractionContext.getJdbcEnvironment(); + final NameQualifierSupport nameQualifierSupport = jdbcEnvironment.getNameQualifierSupport(); + if ( nameQualifierSupport.supportsCatalogs() ) { if ( catalog == null ) { - if ( extractionContext.getJdbcEnvironment().getCurrentCatalog() != null ) { - // 1) look in current namespace - catalogFilter = toMetaDataObjectName( extractionContext.getJdbcEnvironment().getCurrentCatalog() ); - } - else if ( extractionContext.getDefaultCatalog() != null ) { - // 2) look in default namespace - catalogFilter = toMetaDataObjectName( extractionContext.getDefaultCatalog() ); - } - else { - catalogFilter = ""; + // look in the current namespace + catalogFilter = getCurrentCatalogFilter(jdbcEnvironment); + if ( catalogFilter == null ) { + if ( extractionContext.getDefaultCatalog() != null ) { + // 2) look in default namespace + catalogFilter = toMetaDataObjectName( extractionContext.getDefaultCatalog() ); + } + else { + catalogFilter = ""; + } } } else { @@ -312,18 +414,18 @@ public class InformationExtractorJdbcDatabaseMetaDataImpl implements Information } } - if ( extractionContext.getJdbcEnvironment().getNameQualifierSupport().supportsSchemas() ) { + if ( nameQualifierSupport.supportsSchemas() ) { if ( schema == null ) { - if ( extractionContext.getJdbcEnvironment().getCurrentSchema() != null ) { - // 1) look in current namespace - schemaFilter = toMetaDataObjectName( extractionContext.getJdbcEnvironment().getCurrentSchema() ); - } - else if ( extractionContext.getDefaultSchema() != null ) { - // 2) look in default namespace - schemaFilter = toMetaDataObjectName( extractionContext.getDefaultSchema() ); - } - else { - schemaFilter = ""; + // 1) look in current namespace + schemaFilter = getCurrentSchemaFilter( jdbcEnvironment ); + if ( schemaFilter == null ) { + if ( extractionContext.getDefaultSchema() != null ) { + // 2) look in default namespace + schemaFilter = toMetaDataObjectName( extractionContext.getDefaultSchema() ); + } + else { + schemaFilter = ""; + } } } else { From f1a5b2cbca159747cca517d61430241915251dbd Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Tue, 22 Jun 2021 16:29:09 +0200 Subject: [PATCH 5/7] HHH-13788 Fix default IdentifierHelper case strategy --- .../org/hibernate/dialect/MariaDBDialect.java | 19 +++++++++++++++++++ .../org/hibernate/dialect/MySQLDialect.java | 16 ++++++++++++++++ .../dialect/PostgreSQL81Dialect.java | 15 +++++++++++++++ .../hibernate/dialect/SQLServerDialect.java | 17 +++++++++++++++++ .../jdbc/env/spi/IdentifierHelperBuilder.java | 2 +- 5 files changed, 68 insertions(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java index db6b858134..158cadebc5 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java @@ -6,6 +6,14 @@ */ package org.hibernate.dialect; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; + +import org.hibernate.engine.jdbc.env.spi.AnsiSqlKeywords; +import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; + /** * @author Vlad Mihalcea */ @@ -22,4 +30,15 @@ public class MariaDBDialect extends MySQL5Dialect { protected MySQLStorageEngine getDefaultMySQLStorageEngine() { return InnoDBStorageEngine.INSTANCE; } + + @Override + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + throws SQLException { + + // some MariaDB drivers does not return case strategy info + builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.MIXED ); + builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); + + return super.buildIdentifierHelper( builder, dbMetaData ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java index 75b7d66f62..945b443206 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java @@ -7,6 +7,7 @@ package org.hibernate.dialect; import java.sql.CallableStatement; +import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; @@ -27,6 +28,9 @@ import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.LimitHelper; import org.hibernate.dialect.unique.MySQLUniqueDelegate; import org.hibernate.dialect.unique.UniqueDelegate; +import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; import org.hibernate.engine.spi.RowSelection; import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.LockTimeoutException; @@ -562,6 +566,18 @@ public class MySQLDialect extends Dialect { }; } + @Override + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + throws SQLException { + + if ( dbMetaData == null ) { + builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.MIXED ); + builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); + } + + return super.buildIdentifierHelper( builder, dbMetaData ); + } + @Override public String getNotExpression(String expression) { return "not (" + expression + ")"; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java index 220cfb976a..95ea786bf3 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java @@ -29,6 +29,9 @@ import org.hibernate.dialect.identity.PostgreSQL81IdentityColumnSupport; import org.hibernate.dialect.pagination.AbstractLimitHandler; import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.LimitHelper; +import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; import org.hibernate.engine.spi.RowSelection; import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; @@ -76,6 +79,18 @@ public class PostgreSQL81Dialect extends Dialect { } }; + @Override + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + throws SQLException { + + if ( dbMetaData == null ) { + builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.LOWER ); + builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); + } + + return super.buildIdentifierHelper( builder, dbMetaData ); + } + /** * Constructs a PostgreSQL81Dialect */ diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java index 2c9542a003..96bf1aa0a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java @@ -6,6 +6,8 @@ */ package org.hibernate.dialect; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; import java.sql.Types; import java.util.Locale; @@ -19,6 +21,9 @@ import org.hibernate.dialect.identity.SQLServerIdentityColumnSupport; import org.hibernate.dialect.pagination.LegacyLimitHandler; import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.TopLimitHandler; +import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StringType; import org.hibernate.type.Type; @@ -107,6 +112,18 @@ public class SQLServerDialect extends AbstractTransactSQLDialect { return true; } + @Override + public IdentifierHelper buildIdentifierHelper( + IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) throws SQLException { + + if ( dbMetaData == null ) { + builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.MIXED ); + builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); + } + + return super.buildIdentifierHelper( builder, dbMetaData ); + } + @Override public boolean supportsLimitOffset() { return false; 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 74de34f772..97fe15a2c6 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 @@ -38,7 +38,7 @@ public class IdentifierHelperBuilder { private boolean globallyQuoteIdentifiers = false; private boolean skipGlobalQuotingForColumnDefinitions = false; private boolean autoQuoteKeywords = true; - private IdentifierCaseStrategy unquotedCaseStrategy = IdentifierCaseStrategy.MIXED; + private IdentifierCaseStrategy unquotedCaseStrategy = IdentifierCaseStrategy.UPPER; private IdentifierCaseStrategy quotedCaseStrategy = IdentifierCaseStrategy.MIXED; public static IdentifierHelperBuilder from(JdbcEnvironment jdbcEnvironment) { From ce514fe69ec2c22020f300fac6a463d804eb99a5 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Tue, 22 Jun 2021 15:38:32 +0000 Subject: [PATCH 6/7] 5.5.3.Final --- changelog.txt | 19 +++++++++++++++++++ gradle/version.properties | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index c1070194e0..12ad9644f3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,25 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.5.3.Final (June 22, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/31957 + +** Bug + * [HHH-14654] - geolatte-geom Geometry types no longer works with geography column types + * [HHH-14597] - Regression bug: could not resolve property: null of: + * [HHH-13788] - Schema update try to recreate existing tables + * [HHH-4808] - SessionImpl.initializeCollection() does not release JDBC connection (if outside of a transaction) + +** Improvement + * [HHH-14691] - Small optimisation for updating Query Cache Statistics + * [HHH-14690] - Avoid fully resetting StatisticsImpl just after its constructor + +** New Feature + * [HHH-11817] - Allow schema-export commands written to file to truncate in addition to current appending + + Changes in 5.5.2.Final (June 14, 2021) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index df60010858..7f621f1105 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.3-SNAPSHOT +hibernateVersion=5.5.3.Final \ No newline at end of file From c3f8e56f28886918c2f41e9eea80f0f311ca9173 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Tue, 22 Jun 2021 15:43:31 +0000 Subject: [PATCH 7/7] 5.5.4-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 7f621f1105..73d49076c2 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.3.Final \ No newline at end of file +hibernateVersion=5.5.4-SNAPSHOT \ No newline at end of file