HHH-12059 HHH-11440 HHH-11286 HHH-10333 - hbm2ddl.auto=validate and hbm2ddl.auto=update do not work with Oracle and SQLServer when Jdbc driver Connection implementation does not implement getSchema()

This commit is contained in:
Andrea Boriero 2018-02-15 10:15:37 +00:00 committed by Vlad Mihalcea
parent ca92a3fe5b
commit aaa8c65938
7 changed files with 75 additions and 68 deletions

View File

@ -743,6 +743,11 @@ public class Oracle8iDialect extends Dialect {
return false;
}
@Override
public String getCurrentSchemaCommand() {
return "SELECT SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') FROM DUAL";
}
@Override
public boolean supportsPartitionBy() {
return true;

View File

@ -120,6 +120,11 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
return ']';
}
@Override
public String getCurrentSchemaCommand() {
return "SELECT SCHEMA_NAME()";
}
@Override
public char openQuote() {
return '[';

View File

@ -28,52 +28,53 @@ public class DefaultSchemaNameResolver implements SchemaNameResolver {
public static final DefaultSchemaNameResolver INSTANCE = new DefaultSchemaNameResolver();
private final SchemaNameResolver delegate;
private SchemaNameResolver delegate;
public DefaultSchemaNameResolver() {
this.delegate = determineAppropriateResolverDelegate();
private DefaultSchemaNameResolver() {
}
private static SchemaNameResolver determineAppropriateResolverDelegate() {
// unfortunately Connection#getSchema is only available in Java 1.7 and above
// and Hibernate still baselines on 1.6. So for now, use reflection and
// leverage the Connection#getSchema method if it is available.
final Class<Connection> jdbcConnectionClass = Connection.class;
try {
final Method getSchemaMethod = jdbcConnectionClass.getMethod( "getSchema" );
if ( getSchemaMethod != null ) {
if ( getSchemaMethod.getReturnType().equals( String.class ) ) {
return new SchemaNameResolverJava17Delegate( getSchemaMethod );
private void determineAppropriateResolverDelegate(Connection connection) {
if ( delegate == null ) {
// unfortunately Connection#getSchema is only available in Java 1.7 and above
// and Hibernate still baselines on 1.6. So for now, use reflection and
// leverage the Connection#getSchema method if it is available.
try {
final Class<? extends Connection> jdbcConnectionClass = connection.getClass();
final Method getSchemaMethod = jdbcConnectionClass.getMethod( "getSchema" );
if ( getSchemaMethod != null && getSchemaMethod.getReturnType().equals( String.class ) ) {
try {
// If the JDBC driver does not implement the Java 7 spec, but the JRE is Java 7
// then the getSchemaMethod is not null but the call to getSchema() throws an java.lang.AbstractMethodError
connection.getSchema();
delegate = new SchemaNameResolverJava17Delegate( );
}
catch (java.lang.AbstractMethodError e) {
log.debugf( "Unable to use Java 1.7 Connection#getSchema" );
delegate = SchemaNameResolverFallbackDelegate.INSTANCE;
}
}
else {
log.debugf( "Unable to use Java 1.7 Connection#getSchema" );
delegate = SchemaNameResolverFallbackDelegate.INSTANCE;
}
}
catch (Exception ignore) {
log.debugf( "Unable to resolve connection default schema : " + ignore.getMessage() );
}
}
catch (Exception ignore) {
}
log.debugf( "Unable to use Java 1.7 Connection#getSchema" );
return SchemaNameResolverFallbackDelegate.INSTANCE;
}
@Override
public String resolveSchemaName(Connection connection, Dialect dialect) throws SQLException {
determineAppropriateResolverDelegate( connection );
return delegate.resolveSchemaName( connection, dialect );
}
public static class SchemaNameResolverJava17Delegate implements SchemaNameResolver {
private final Method getSchemaMethod;
public SchemaNameResolverJava17Delegate(Method getSchemaMethod) {
this.getSchemaMethod = getSchemaMethod;
}
@Override
public String resolveSchemaName(Connection connection, Dialect dialect) throws SQLException {
try {
return (String) getSchemaMethod.invoke( connection );
}
catch (Exception e) {
throw new HibernateException( "Unable to invoke Connection#getSchema method via reflection", e );
}
return connection.getSchema();
}
}
@ -95,29 +96,11 @@ public class DefaultSchemaNameResolver implements SchemaNameResolver {
);
}
final Statement statement = connection.createStatement();
try {
final ResultSet resultSet = statement.executeQuery( dialect.getCurrentSchemaCommand() );
try {
if ( !resultSet.next() ) {
return null;
}
return resultSet.getString( 1 );
}
finally {
try {
resultSet.close();
}
catch (SQLException ignore) {
}
}
}
finally {
try {
statement.close();
}
catch (SQLException ignore) {
}
try (
final Statement statement = connection.createStatement();
final ResultSet resultSet = statement.executeQuery( dialect.getCurrentSchemaCommand() )
) {
return resultSet.next() ? resultSet.getString( 1 ) : null;
}
}
}

View File

@ -298,7 +298,7 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
return schemaNameResolver.resolveSchemaName( databaseMetaData.getConnection(), dialect );
}
catch (Exception e) {
// for now, just ignore the exception.
log.debug( "Unable to resolve connection default schema", e );
return null;
}
}

View File

@ -25,5 +25,5 @@ public interface SchemaNameResolver {
*
* @return The name of the schema (may be null).
*/
public String resolveSchemaName(Connection connection, Dialect dialect) throws SQLException;
String resolveSchemaName(Connection connection, Dialect dialect) throws SQLException;
}

View File

@ -6,8 +6,11 @@
*/
package org.hibernate.tool.schema;
import java.util.Map;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
/**
* @author Andrea Boriero
@ -24,7 +27,7 @@ public enum JdbcMetadaAccessStrategy {
* The {@link org.hibernate.tool.schema.spi.SchemaMigrator} and {@link org.hibernate.tool.schema.spi.SchemaValidator}
* execute a single {@link java.sql.DatabaseMetaData#getTables(String, String, String, String[])} call
* to retrieve all the database table in order to determine all the {@link javax.persistence.Entity} have a mapped database tables.
*
* <p>
* This strategy is the default one and it may require {@link AvailableSettings#DEFAULT_CATALOG} and/or
* {@link AvailableSettings#DEFAULT_SCHEMA} values to be provided.
*/
@ -41,20 +44,34 @@ public enum JdbcMetadaAccessStrategy {
return strategy;
}
public static JdbcMetadaAccessStrategy interpretHbm2ddlSetting(Object value) {
if(value == null){
return GROUPED;
public static JdbcMetadaAccessStrategy interpretSetting(Map options) {
if ( options == null ) {
return interpretHbm2ddlSetting( null );
}
String name = value.toString();
if ( StringHelper.isEmpty( name ) || GROUPED.strategy.equals( name ) ) {
return GROUPED;
}
else if ( INDIVIDUALLY.strategy.equals( name ) ) {
else if ( ConfigurationHelper.getBoolean( AvailableSettings.ENABLE_SYNONYMS, options, false ) ) {
// Use of synonyms can cause issues during schema validation or schema update when GROUPED strategy is used (especially in Oracle)
return INDIVIDUALLY;
}
else {
throw new IllegalArgumentException( "Unrecognized `" + AvailableSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY + "` value : " + name );
return interpretHbm2ddlSetting( options.get( AvailableSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY ) );
}
}
public static JdbcMetadaAccessStrategy interpretHbm2ddlSetting(Object value) {
if ( value == null ) {
return GROUPED;
}
else {
final String name = value.toString();
if ( StringHelper.isEmpty( name ) || GROUPED.strategy.equals( name ) ) {
return GROUPED;
}
else if ( INDIVIDUALLY.strategy.equals( name ) ) {
return INDIVIDUALLY;
}
else {
throw new IllegalArgumentException( "Unrecognized `" + AvailableSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY + "` value : " + name );
}
}
}
}

View File

@ -104,10 +104,7 @@ public class HibernateSchemaManagementTool implements SchemaManagementTool, Serv
}
private JdbcMetadaAccessStrategy determineJdbcMetadaAccessStrategy(Map options) {
if ( options == null ) {
return JdbcMetadaAccessStrategy.interpretHbm2ddlSetting( null );
}
return JdbcMetadaAccessStrategy.interpretHbm2ddlSetting( options.get( AvailableSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY ) );
return JdbcMetadaAccessStrategy.interpretSetting( options );
}
GenerationTarget[] buildGenerationTargets(