Skip to content

Commit

Permalink
HHH-12059 HHH-11440 HHH-11286 HHH-10333 - hbm2ddl.auto=validate and h…
Browse files Browse the repository at this point in the history
…bm2ddl.auto=update do not work with Oracle and SQLServer when Jdbc driver Connection implementation does not implement getSchema()
  • Loading branch information
dreab8 authored and vladmihalcea committed Feb 19, 2018
1 parent ca92a3f commit aaa8c65
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 68 deletions.
Expand Up @@ -743,6 +743,11 @@ public boolean canCreateSchema() {
return false;
}

@Override
public String getCurrentSchemaCommand() {
return "SELECT SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') FROM DUAL";
}

@Override
public boolean supportsPartitionBy() {
return true;
Expand Down
Expand Up @@ -120,6 +120,11 @@ public char closeQuote() {
return ']';
}

@Override
public String getCurrentSchemaCommand() {
return "SELECT SCHEMA_NAME()";
}

@Override
public char openQuote() {
return '[';
Expand Down
Expand Up @@ -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();
}
}

Expand All @@ -95,29 +96,11 @@ public String resolveSchemaName(Connection connection, Dialect dialect) throws S
);
}

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;
}
}
}
Expand Down
Expand Up @@ -298,7 +298,7 @@ private String determineCurrentSchemaName(
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;
}
}
Expand Down
Expand Up @@ -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;
}
Expand Up @@ -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
Expand All @@ -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.
*/
Expand All @@ -41,20 +44,34 @@ public String toString() {
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 );
}
}
}
}
Expand Up @@ -104,10 +104,7 @@ private SchemaFilterProvider getSchemaFilterProvider(Map options) {
}

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(
Expand Down

0 comments on commit aaa8c65

Please sign in to comment.