HHH-17424 - Have Dialect manage more of ExtractedDatabaseMetadata

https://hibernate.atlassian.net/browse/HHH-17424
This commit is contained in:
Steve Ebersole 2023-11-14 14:48:01 -06:00
parent fa5f0f75c2
commit 501b57a978
6 changed files with 159 additions and 77 deletions

View File

@ -275,8 +275,13 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
final ConfigurationService configurationService = serviceRegistry.getService( ConfigurationService.class ); final ConfigurationService configurationService = serviceRegistry.getService( ConfigurationService.class );
final JdbcServices jdbcServices = serviceRegistry.getService( JdbcServices.class ); final JdbcServices jdbcServices = serviceRegistry.getService( JdbcServices.class );
assert jdbcServices != null;
assert configurationService != null;
final Dialect dialect = jdbcServices.getJdbcEnvironment().getDialect();
final Map<String,Object> configurationSettings = new HashMap<>(); final Map<String,Object> configurationSettings = new HashMap<>();
configurationSettings.putAll( map( jdbcServices.getJdbcEnvironment().getDialect().getDefaultProperties() ) ); configurationSettings.putAll( map( dialect.getDefaultProperties() ) );
configurationSettings.putAll( configurationService.getSettings() ); configurationSettings.putAll( configurationService.getSettings() );
this.beanManagerReference = NullnessHelper.coalesceSuppliedValues( this.beanManagerReference = NullnessHelper.coalesceSuppliedValues(
@ -488,7 +493,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
} }
this.jdbcBatchSize = getInt( STATEMENT_BATCH_SIZE, configurationSettings, 1 ); this.jdbcBatchSize = getInt( STATEMENT_BATCH_SIZE, configurationSettings, 1 );
if ( !meta.supportsBatchUpdates() ) { if ( disallowBatchUpdates( dialect, meta ) ) {
this.jdbcBatchSize = 0; this.jdbcBatchSize = 0;
} }
@ -585,6 +590,14 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
); );
} }
private boolean disallowBatchUpdates(Dialect dialect, ExtractedDatabaseMetaData meta) {
final Boolean dialectAnswer = dialect.supportsBatchUpdates();
if ( dialectAnswer != null ) {
return dialectAnswer;
}
return !meta.supportsBatchUpdates();
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private SqmMultiTableMutationStrategy resolveSqmMutationStrategy( private SqmMultiTableMutationStrategy resolveSqmMutationStrategy(
String strategyName, String strategyName,

View File

@ -4952,6 +4952,30 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
return null; return null;
} }
/**
* Does this Dialect support {@linkplain PreparedStatement#addBatch() batch updates}.
*
* @return {@code true} indicates it does; {@code false} indicates it does not; {@code null} indicates
* it might and that database-metadata should be consulted.
*
* @see org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData#supportsBatchUpdates
*/
public Boolean supportsBatchUpdates() {
return null;
}
/**
* Does this Dialect support {@linkplain PreparedStatement#addBatch() batch updates}.
*
* @return {@code true} indicates it does; {@code false} indicates it does not; {@code null} indicates
* it might and that database-metadata should be consulted
*
* @see org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData#supportsRefCursors
*/
public Boolean supportsRefCursors() {
return null;
}
/** /**
* Pluggable strategy for determining the {@link Size} to use for * Pluggable strategy for determining the {@link Size} to use for
* columns of a given SQL type. * columns of a given SQL type.

View File

@ -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 http://www.gnu.org/licenses/lgpl-2.1.html.
*/
package org.hibernate.engine.jdbc.cursor.internal;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.engine.jdbc.cursor.spi.RefCursorSupport;
import org.hibernate.engine.jdbc.spi.JdbcServices;
/**
* @author Steve Ebersole
*/
public class FallbackRefCursorSupport implements RefCursorSupport {
private final JdbcServices jdbcServices;
public FallbackRefCursorSupport(JdbcServices jdbcServices) {
this.jdbcServices = jdbcServices;
}
@Override
public void registerRefCursorParameter(CallableStatement statement, int position) {
try {
jdbcServices.getDialect().registerResultSetOutParameter( statement, position );
}
catch (SQLException e) {
throw jdbcServices.getSqlExceptionHelper().convert( e, "Error asking dialect to register ref cursor parameter [" + position + "]" );
}
}
@Override
public void registerRefCursorParameter(CallableStatement statement, String name) {
try {
jdbcServices.getDialect().registerResultSetOutParameter( statement, name );
}
catch (SQLException e) {
throw jdbcServices.getSqlExceptionHelper().convert( e, "Error asking dialect to register ref cursor parameter [" + name + "]" );
}
}
@Override
public ResultSet getResultSet(CallableStatement statement, int position) {
try {
return jdbcServices.getDialect().getResultSet( statement, position );
}
catch (SQLException e) {
throw jdbcServices.getSqlExceptionHelper().convert(
e,
"Error asking dialect to extract ResultSet from CallableStatement parameter [" + position + "]"
);
}
}
@Override
public ResultSet getResultSet(CallableStatement statement, String name) {
try {
return jdbcServices.getDialect().getResultSet( statement, name );
}
catch (SQLException e) {
throw jdbcServices.getSqlExceptionHelper().convert(
e,
"Error asking dialect to extract ResultSet from CallableStatement parameter [" + name + "]"
);
}
}
}

View File

@ -10,6 +10,7 @@ import java.util.Map;
import org.hibernate.boot.registry.StandardServiceInitiator; import org.hibernate.boot.registry.StandardServiceInitiator;
import org.hibernate.engine.jdbc.cursor.spi.RefCursorSupport; import org.hibernate.engine.jdbc.cursor.spi.RefCursorSupport;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.ServiceRegistryImplementor;
/** /**
@ -25,7 +26,23 @@ public class RefCursorSupportInitiator implements StandardServiceInitiator<RefCu
@Override @Override
public RefCursorSupport initiateService(Map<String, Object> configurationValues, ServiceRegistryImplementor registry) { public RefCursorSupport initiateService(Map<String, Object> configurationValues, ServiceRegistryImplementor registry) {
return new StandardRefCursorSupport(); final JdbcServices jdbcServices = registry.getService( JdbcServices.class );
assert jdbcServices != null;
final boolean supportsRefCursors = useRefCursorSupport( jdbcServices );
if ( supportsRefCursors ) {
return new StandardRefCursorSupport( jdbcServices );
}
else {
return new FallbackRefCursorSupport( jdbcServices );
}
}
private boolean useRefCursorSupport(JdbcServices jdbcServices) {
final Boolean dialectAnswer = jdbcServices.getDialect().supportsRefCursors();
if ( dialectAnswer != null ) {
return dialectAnswer;
}
return jdbcServices.getJdbcEnvironment().getExtractedDatabaseMetaData().supportsRefCursors();
} }
@Override @Override

View File

@ -15,7 +15,6 @@ import java.sql.Types;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.engine.jdbc.cursor.spi.RefCursorSupport; import org.hibernate.engine.jdbc.cursor.spi.RefCursorSupport;
import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.service.spi.InjectService;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
@ -27,102 +26,49 @@ import org.jboss.logging.Logger;
public class StandardRefCursorSupport implements RefCursorSupport { public class StandardRefCursorSupport implements RefCursorSupport {
private static final Logger log = Logger.getLogger( StandardRefCursorSupport.class ); private static final Logger log = Logger.getLogger( StandardRefCursorSupport.class );
private JdbcServices jdbcServices; private final JdbcServices jdbcServices;
/** public StandardRefCursorSupport(JdbcServices jdbcServices) {
* Hook for service registry to be able to inject JdbcServices
*
* @param jdbcServices The JdbcServices service
*/
@InjectService
@SuppressWarnings("UnusedDeclaration")
public void injectJdbcServices(JdbcServices jdbcServices) {
this.jdbcServices = jdbcServices; this.jdbcServices = jdbcServices;
} }
@Override @Override
public void registerRefCursorParameter(CallableStatement statement, int position) { public void registerRefCursorParameter(CallableStatement statement, int position) {
if ( jdbcServices.getExtractedMetaDataSupport().supportsRefCursors() ) { try {
try { statement.registerOutParameter( position, refCursorTypeCode() );
statement.registerOutParameter( position, refCursorTypeCode() );
}
catch (SQLException e) {
throw jdbcServices.getSqlExceptionHelper().convert( e, "Error registering REF_CURSOR parameter [" + position + "]" );
}
} }
else { catch (SQLException e) {
try { throw jdbcServices.getSqlExceptionHelper().convert( e, "Error registering REF_CURSOR parameter [" + position + "]" );
jdbcServices.getDialect().registerResultSetOutParameter( statement, position );
}
catch (SQLException e) {
throw jdbcServices.getSqlExceptionHelper().convert( e, "Error asking dialect to register ref cursor parameter [" + position + "]" );
}
} }
} }
@Override @Override
public void registerRefCursorParameter(CallableStatement statement, String name) { public void registerRefCursorParameter(CallableStatement statement, String name) {
if ( jdbcServices.getExtractedMetaDataSupport().supportsRefCursors() ) { try {
try { statement.registerOutParameter( name, refCursorTypeCode() );
statement.registerOutParameter( name, refCursorTypeCode() );
}
catch (SQLException e) {
throw jdbcServices.getSqlExceptionHelper().convert( e, "Error registering REF_CURSOR parameter [" + name + "]" );
}
} }
else { catch (SQLException e) {
try { throw jdbcServices.getSqlExceptionHelper().convert( e, "Error registering REF_CURSOR parameter [" + name + "]" );
jdbcServices.getDialect().registerResultSetOutParameter( statement, name );
}
catch (SQLException e) {
throw jdbcServices.getSqlExceptionHelper().convert( e, "Error asking dialect to register ref cursor parameter [" + name + "]" );
}
} }
} }
@Override @Override
public ResultSet getResultSet(CallableStatement statement, int position) { public ResultSet getResultSet(CallableStatement statement, int position) {
if ( jdbcServices.getExtractedMetaDataSupport().supportsRefCursors() ) { try {
try { return statement.getObject( position, ResultSet.class );
return statement.getObject( position, ResultSet.class );
}
catch (Exception e) {
throw new HibernateException( "Unexpected error extracting REF_CURSOR parameter [" + position + "]", e );
}
} }
else { catch (Exception e) {
try { throw new HibernateException( "Unexpected error extracting REF_CURSOR parameter [" + position + "]", e );
return jdbcServices.getDialect().getResultSet( statement, position );
}
catch (SQLException e) {
throw jdbcServices.getSqlExceptionHelper().convert(
e,
"Error asking dialect to extract ResultSet from CallableStatement parameter [" + position + "]"
);
}
} }
} }
@Override @Override
public ResultSet getResultSet(CallableStatement statement, String name) { public ResultSet getResultSet(CallableStatement statement, String name) {
if ( jdbcServices.getExtractedMetaDataSupport().supportsRefCursors() ) { try {
try { return statement.getObject( name, ResultSet.class );
return statement.getObject( name, ResultSet.class );
}
catch (Exception e) {
throw new HibernateException( "Unexpected error extracting REF_CURSOR parameter [" + name + "]", e );
}
} }
else { catch (Exception e) {
try { throw new HibernateException( "Unexpected error extracting REF_CURSOR parameter [" + name + "]", e );
return jdbcServices.getDialect().getResultSet( statement, name );
}
catch (SQLException e) {
throw jdbcServices.getSqlExceptionHelper().convert(
e,
"Error asking dialect to extract ResultSet from CallableStatement parameter [" + name + "]"
);
}
} }
} }

View File

@ -9,6 +9,7 @@ package org.hibernate.engine.jdbc.env.spi;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.tool.schema.extract.spi.SequenceInformation; import org.hibernate.tool.schema.extract.spi.SequenceInformation;
/** /**
@ -30,6 +31,8 @@ public interface ExtractedDatabaseMetaData {
* Retrieve the name of the catalog in effect when we connected to the database. * Retrieve the name of the catalog in effect when we connected to the database.
* *
* @return The catalog name * @return The catalog name
*
* @see AvailableSettings#DEFAULT_SCHEMA
*/ */
String getConnectionCatalogName(); String getConnectionCatalogName();
@ -45,14 +48,19 @@ public interface ExtractedDatabaseMetaData {
* *
* @return {@code true} indicates the driver reported true; {@code false} indicates the driver reported false * @return {@code true} indicates the driver reported true; {@code false} indicates the driver reported false
* or that the driver could not be asked. * or that the driver could not be asked.
*
* @see AvailableSettings#CALLABLE_NAMED_PARAMS_ENABLED
*/ */
boolean supportsNamedParameters(); boolean supportsNamedParameters();
/** /**
* Does the driver report supporting REF_CURSORs? * Does the driver report supporting {@link java.sql.Types#REF_CURSOR}?
* *
* @return {@code true} indicates the driver reported true; {@code false} indicates the driver reported false * @return {@code true} indicates the driver reported true; {@code false} indicates the driver reported false
* or that the driver could not be asked. * or that the driver could not be asked.
*
* @see java.sql.DatabaseMetaData#supportsRefCursors()
* @see org.hibernate.dialect.Dialect#supportsRefCursors
*/ */
boolean supportsRefCursors(); boolean supportsRefCursors();
@ -62,15 +70,17 @@ public interface ExtractedDatabaseMetaData {
* @return True if the driver reported to support {@link java.sql.ResultSet#TYPE_SCROLL_INSENSITIVE}. * @return True if the driver reported to support {@link java.sql.ResultSet#TYPE_SCROLL_INSENSITIVE}.
* *
* @see java.sql.DatabaseMetaData#supportsResultSetType * @see java.sql.DatabaseMetaData#supportsResultSetType
* @see AvailableSettings#USE_SCROLLABLE_RESULTSET
*/ */
boolean supportsScrollableResults(); boolean supportsScrollableResults();
/** /**
* Did the driver report to supporting retrieval of generated keys? * Did the driver report to supporting retrieval of generated keys?
* *
* @return True if the if the driver reported to support calls to {@link java.sql.Statement#getGeneratedKeys} * @return True if the driver reported to support calls to {@link java.sql.Statement#getGeneratedKeys}
* *
* @see java.sql.DatabaseMetaData#supportsGetGeneratedKeys * @see java.sql.DatabaseMetaData#supportsGetGeneratedKeys
* @see AvailableSettings#USE_GET_GENERATED_KEYS
*/ */
boolean supportsGetGeneratedKeys(); boolean supportsGetGeneratedKeys();
@ -80,6 +90,7 @@ public interface ExtractedDatabaseMetaData {
* @return True if the driver supports batched updates * @return True if the driver supports batched updates
* *
* @see java.sql.DatabaseMetaData#supportsBatchUpdates * @see java.sql.DatabaseMetaData#supportsBatchUpdates
* @see org.hibernate.dialect.Dialect#supportsBatchUpdates
*/ */
boolean supportsBatchUpdates(); boolean supportsBatchUpdates();