diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/JdbcSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/JdbcSettings.java
index b60ee49560..9e15a64ddc 100644
--- a/hibernate-core/src/main/java/org/hibernate/cfg/JdbcSettings.java
+++ b/hibernate-core/src/main/java/org/hibernate/cfg/JdbcSettings.java
@@ -471,6 +471,25 @@ public interface JdbcSettings extends C3p0Settings, ProxoolSettings {
*/
String CONNECTION_HANDLING = "hibernate.connection.handling_mode";
+ /**
+ * Whether access to JDBC {@linkplain java.sql.DatabaseMetaData metadata} is allowed during bootstrap.
+ *
+ * Typically, Hibernate accesses this metadata to understand the capabilities of the underlying
+ * database to help minimize needed configuration. Disabling this access means that only explicit
+ * settings are used. At a minimum, the Dialect to use must be specified using either the {@value #DIALECT}
+ * or {@value JdbcSettings#JAKARTA_HBM2DDL_DB_NAME} setting. When the Dialect to use is specified in
+ * this manner it is generally a good idea to specify the
+ * {@linkplain JdbcSettings#JAKARTA_HBM2DDL_DB_VERSION database version} as well - Dialects use the version
+ * to configure themselves.
+ *
+ * @apiNote The specified Dialect may also provide defaults into the "explicit" settings.
+ *
+ * @settingDefault {@code true}
+ *
+ * @since 6.5
+ */
+ String ALLOW_METADATA_ON_BOOT = "hibernate.boot.allow_jdbc_metadata_access";
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Deprecated Hibernate settings
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 afe804a291..ac6d814599 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
@@ -14,6 +14,7 @@ import java.util.Map;
import java.util.StringTokenizer;
import org.hibernate.boot.registry.StandardServiceInitiator;
+import org.hibernate.cfg.JdbcSettings;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
@@ -55,6 +56,7 @@ import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_DB_MINOR_VERSI
import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_DB_NAME;
import static org.hibernate.cfg.AvailableSettings.JTA_TRACK_BY_THREAD;
import static org.hibernate.cfg.AvailableSettings.PREFER_USER_TRANSACTION;
+import static org.hibernate.cfg.JdbcSettings.ALLOW_METADATA_ON_BOOT;
import static org.hibernate.cfg.JdbcSettings.CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT;
import static org.hibernate.cfg.JdbcSettings.DIALECT;
import static org.hibernate.cfg.JdbcSettings.DIALECT_DB_VERSION;
@@ -65,6 +67,7 @@ import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER;
import static org.hibernate.internal.util.NullnessHelper.coalesceSuppliedValues;
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
import static org.hibernate.internal.util.config.ConfigurationHelper.getBoolean;
+import static org.hibernate.internal.util.config.ConfigurationHelper.getBooleanWrapper;
import static org.hibernate.internal.util.config.ConfigurationHelper.getInteger;
/**
@@ -115,7 +118,7 @@ public class JdbcEnvironmentInitiator implements StandardServiceInitiator configurationValues) {
- return getBoolean(USE_JDBC_METADATA_DEFAULTS, configurationValues, true );
+ /**
+ * Determine whether we can access JDBC {@linkplain DatabaseMetaData metadata} based on
+ * the {@value JdbcSettings#ALLOW_METADATA_ON_BOOT} setting. The default is to allow access.
+ *
+ * @implNote Currently also looks for the deprecated {@value JdbcEnvironmentInitiator#USE_JDBC_METADATA_DEFAULTS} setting as a fallback.
+ *
+ * @see JdbcSettings#ALLOW_METADATA_ON_BOOT
+ */
+ private static boolean allowJdbcMetadataAccess(Map configurationValues) {
+ final Boolean allow = getBooleanWrapper( ALLOW_METADATA_ON_BOOT, configurationValues, null );
+ if ( allow != null ) {
+ return allow;
+ }
+
+ final Boolean use = getBooleanWrapper( USE_JDBC_METADATA_DEFAULTS, configurationValues, null );
+ if ( use != null ) {
+ DEPRECATION_LOGGER.deprecatedSetting( USE_JDBC_METADATA_DEFAULTS, ALLOW_METADATA_ON_BOOT );
+ return use;
+ }
+
+ // allow by default
+ return true;
}
private static String getExplicitDatabaseVersion(
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/database/metadata/MetadataAccessTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/database/metadata/MetadataAccessTests.java
new file mode 100644
index 0000000000..11db3d4c04
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/database/metadata/MetadataAccessTests.java
@@ -0,0 +1,91 @@
+/*
+ * 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.orm.test.boot.database.metadata;
+
+import org.hibernate.HibernateException;
+import org.hibernate.boot.registry.StandardServiceRegistry;
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.cfg.JdbcSettings;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.H2Dialect;
+import org.hibernate.dialect.OracleDialect;
+import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
+import org.hibernate.service.spi.ServiceException;
+
+import org.hibernate.testing.env.TestingDatabaseInfo;
+import org.hibernate.testing.orm.junit.Jira;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.fail;
+
+/**
+ * @author Steve Ebersole
+ */
+@Jira( "https://hibernate.atlassian.net/browse/HHH-17269" )
+public class MetadataAccessTests {
+
+ @Test
+ void testAccessAllowed() {
+ final StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder();
+ registryBuilder.clearSettings();
+
+ // allow access to the jdbc metadata
+ registryBuilder.applySetting( JdbcSettings.ALLOW_METADATA_ON_BOOT, true );
+
+ // configure the values needed to connect to a H2 database
+ registryBuilder.applySetting( AvailableSettings.JAKARTA_JDBC_DRIVER, TestingDatabaseInfo.DRIVER );
+ registryBuilder.applySetting( AvailableSettings.JAKARTA_JDBC_URL, TestingDatabaseInfo.URL );
+ registryBuilder.applySetting( AvailableSettings.JAKARTA_JDBC_USER, TestingDatabaseInfo.USER );
+ registryBuilder.applySetting( AvailableSettings.JAKARTA_JDBC_PASSWORD, TestingDatabaseInfo.PASS );
+
+ // make certain there is no explicit dialect configured
+ assertThat( registryBuilder.getSettings() ).doesNotContainKey( JdbcSettings.DIALECT );
+
+ try (StandardServiceRegistry registry = registryBuilder.build()) {
+ final JdbcEnvironment jdbcEnvironment = registry.getService( JdbcEnvironment.class );
+ final Dialect dialect = jdbcEnvironment.getDialect();
+ assertThat( dialect ).isNotNull();
+ assertThat( dialect ).isInstanceOf( H2Dialect.class );
+ }
+ }
+
+ @Test
+ void testAccessDisabledExplicitDialect() {
+ final StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder();
+ registryBuilder.clearSettings();
+
+ registryBuilder.applySetting( JdbcSettings.ALLOW_METADATA_ON_BOOT, false );
+ registryBuilder.applySetting( JdbcSettings.DIALECT, "org.hibernate.dialect.OracleDialect" );
+
+ try (StandardServiceRegistry registry = registryBuilder.build()) {
+ final JdbcEnvironment jdbcEnvironment = registry.getService( JdbcEnvironment.class );
+ final Dialect dialect = jdbcEnvironment.getDialect();
+ assertThat( dialect ).isInstanceOf( OracleDialect.class );
+ }
+ }
+
+ @Test
+ void testAccessDisabledNoDialect() {
+ final StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder();
+ registryBuilder.clearSettings();
+ assertThat( registryBuilder.getSettings() ).doesNotContainKey( JdbcSettings.DIALECT );
+
+ registryBuilder.applySetting( JdbcSettings.ALLOW_METADATA_ON_BOOT, false );
+ try (StandardServiceRegistry registry = registryBuilder.build()) {
+ final JdbcEnvironment jdbcEnvironment = registry.getService( JdbcEnvironment.class );
+ final Dialect dialect = jdbcEnvironment.getDialect();
+ fail( "Should fail to boot - " + dialect );
+ }
+ catch (ServiceException expected) {
+ assertThat( expected.getCause() ).isInstanceOf( HibernateException.class );
+ final HibernateException cause = (HibernateException) expected.getCause();
+ assertThat( cause.getMessage() ).startsWith( "Unable to determine Dialect without JDBC metadata" );
+ }
+ }
+}