HHH-18286 Add Setting to fail Bootstrapping on Metadata Access Failure
A failure to access the JDBC connection metadata while bootstrapping Hibernate can lead to ClassCastExceptions during runtime when the Oracle JDBC driver is used and a BLOB is created by the NonContextualLobCreator. To avoid this issue, a new JDBC setting is introduced, which lets the bootstrapping fail when the connection metadata cannot be obtained.
This commit is contained in:
parent
d0ddbb5d47
commit
bcdc9fc1c7
|
@ -490,6 +490,21 @@ public interface JdbcSettings extends C3p0Settings, ProxoolSettings, AgroalSetti
|
|||
*/
|
||||
String ALLOW_METADATA_ON_BOOT = "hibernate.boot.allow_jdbc_metadata_access";
|
||||
|
||||
/**
|
||||
* Whether failures to access the JDBC {@linkplain java.sql.DatabaseMetaData metadata} should be ignored and the
|
||||
* bootstrapping process should continue. Hibernate then uses a default JDBC
|
||||
* {@linkplain org.hibernate.engine.jdbc.env.spi.JdbcEnvironment environment}.
|
||||
* <p/>
|
||||
* Failures to access the metadata can result in unexpected runtime errors when accessing the database, since the
|
||||
* default JDBC environment might not correctly represent the capabilities of the underlying database.
|
||||
* <p/>
|
||||
* This setting only takes effect when the {@link #ALLOW_METADATA_ON_BOOT} setting is activated.
|
||||
*
|
||||
* @settingDefault {@code true}
|
||||
* @see #ALLOW_METADATA_ON_BOOT
|
||||
* @since 6.6
|
||||
*/
|
||||
String IGNORE_METADATA_ACCESS_FAILURE_ON_BOOT = "hibernate.boot.ignore_jdbc_metadata_access_failure";
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Deprecated Hibernate settings
|
||||
|
|
|
@ -13,13 +13,13 @@ import java.util.Collections;
|
|||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.boot.registry.StandardServiceInitiator;
|
||||
import org.hibernate.cfg.JdbcSettings;
|
||||
import org.hibernate.dialect.DatabaseVersion;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
|
||||
import org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator;
|
||||
import org.hibernate.engine.jdbc.connections.internal.DatabaseConnectionInfoImpl;
|
||||
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
|
||||
import org.hibernate.engine.jdbc.connections.spi.DatabaseConnectionInfo;
|
||||
|
@ -321,7 +321,7 @@ public class JdbcEnvironmentInitiator implements StandardServiceInitiator<JdbcEn
|
|||
return temporaryJdbcSessionOwner.transactionCoordinator.createIsolationDelegate().delegateWork(
|
||||
new AbstractReturningWork<>() {
|
||||
@Override
|
||||
public JdbcEnvironmentImpl execute(Connection connection) {
|
||||
public JdbcEnvironmentImpl execute(Connection connection) throws SQLException {
|
||||
try {
|
||||
final DatabaseMetaData metadata = connection.getMetaData();
|
||||
logDatabaseAndDriver( metadata );
|
||||
|
@ -357,7 +357,12 @@ public class JdbcEnvironmentInitiator implements StandardServiceInitiator<JdbcEn
|
|||
);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.unableToObtainConnectionMetadata( e );
|
||||
if ( shouldIgnoreMetadataAccessFailure( configurationValues ) ) {
|
||||
log.unableToObtainConnectionMetadata( e );
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// accessing the JDBC metadata failed
|
||||
|
@ -387,12 +392,25 @@ public class JdbcEnvironmentInitiator implements StandardServiceInitiator<JdbcEn
|
|||
);
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
log.unableToObtainConnectionToQueryMetadata( e );
|
||||
if ( shouldIgnoreMetadataAccessFailure( configurationValues ) ) {
|
||||
log.unableToObtainConnectionToQueryMetadata( e );
|
||||
}
|
||||
else {
|
||||
throw new HibernateException( "Unable to access JDBC metadata", e );
|
||||
}
|
||||
}
|
||||
// accessing the JDBC metadata failed
|
||||
return getJdbcEnvironmentWithDefaults( configurationValues, registry, dialectFactory );
|
||||
}
|
||||
|
||||
private static boolean shouldIgnoreMetadataAccessFailure(Map<String, Object> configurationValues) {
|
||||
return getBoolean(
|
||||
JdbcSettings.IGNORE_METADATA_ACCESS_FAILURE_ON_BOOT,
|
||||
configurationValues,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
private static void logDatabaseAndDriver(DatabaseMetaData dbmd) throws SQLException {
|
||||
if ( log.isDebugEnabled() ) {
|
||||
log.debugf(
|
||||
|
|
|
@ -6,10 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.orm.test.boot.database.metadata;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hibernate.dialect.SimpleDatabaseVersion.ZERO_VERSION;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
@ -50,6 +46,11 @@ import org.junit.jupiter.params.provider.MethodSource;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.hibernate.dialect.SimpleDatabaseVersion.ZERO_VERSION;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -203,6 +204,23 @@ public class MetadataAccessTests {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Jira("https://hibernate.atlassian.net/browse/HHH-18286")
|
||||
void testDontIgnoreMetadataAccessFailureWhenConnectionCantBeObtained() {
|
||||
StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder();
|
||||
registryBuilder.clearSettings();
|
||||
|
||||
registryBuilder.applySetting( JdbcSettings.IGNORE_METADATA_ACCESS_FAILURE_ON_BOOT, false );
|
||||
|
||||
try (StandardServiceRegistry registry = registryBuilder.build()) {
|
||||
assertThatExceptionOfType( ServiceException.class )
|
||||
.isThrownBy( () -> registry.getService( JdbcEnvironment.class ) )
|
||||
.havingCause()
|
||||
.isInstanceOf( HibernateException.class )
|
||||
.withMessage( "Unable to access JDBC metadata" );
|
||||
}
|
||||
}
|
||||
|
||||
// Ugly hack because neither MINIMUM_VERSION nor getMinimumSupportedVersion()
|
||||
// can be accessed from this test.
|
||||
private static DatabaseVersion getVersionConstant(Class<? extends Dialect> dialectClass, String versionConstantName) {
|
||||
|
|
Loading…
Reference in New Issue