HHH-9910 - Schema migration (update) problems with catalog/schema restrictions

yes, in oracle
This commit is contained in:
Steve Ebersole 2015-07-21 18:31:09 -05:00
parent 6af89449f2
commit ce54660cdb
4 changed files with 228 additions and 30 deletions

View File

@ -53,6 +53,7 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
private final LobCreatorBuilderImpl lobCreatorBuilder;
private final LinkedHashSet<TypeInfo> typeInfoSet = new LinkedHashSet<TypeInfo>();
private final NameQualifierSupport nameQualifierSupport;
/**
* Constructor form used when the JDBC {@link java.sql.DatabaseMetaData} is not available.
@ -70,6 +71,7 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
// assume both catalogs and schemas are supported
nameQualifierSupport = NameQualifierSupport.BOTH;
}
this.nameQualifierSupport = nameQualifierSupport;
this.sqlExceptionHelper = buildSqlExceptionHelper( dialect );
this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl.Builder( this ).build();
@ -138,6 +140,7 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
if ( nameQualifierSupport == null ) {
nameQualifierSupport = determineNameQualifierSupport( databaseMetaData );
}
this.nameQualifierSupport = nameQualifierSupport;
final IdentifierHelperBuilder identifierHelperBuilder = IdentifierHelperBuilder.from( this );
identifierHelperBuilder.setNameQualifierSupport( nameQualifierSupport );
@ -211,6 +214,7 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
if ( nameQualifierSupport == null ) {
nameQualifierSupport = determineNameQualifierSupport( databaseMetaData );
}
this.nameQualifierSupport = nameQualifierSupport;
final IdentifierHelperBuilder identifierHelperBuilder = IdentifierHelperBuilder.from( this );
identifierHelperBuilder.setGloballyQuoteIdentifiers( globalQuoting( cfgService ) );
@ -323,6 +327,11 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
return identifierHelper;
}
@Override
public NameQualifierSupport getNameQualifierSupport() {
return nameQualifierSupport;
}
@Override
public SqlExceptionHelper getSqlExceptionHelper() {
return sqlExceptionHelper;

View File

@ -68,6 +68,13 @@ public interface JdbcEnvironment extends Service {
*/
IdentifierHelper getIdentifierHelper();
/**
* Obtain the level of support for qualified names.
*
* @return
*/
NameQualifierSupport getNameQualifierSupport();
/**
* Obtain the helper for dealing with JDBC {@link java.sql.SQLException} faults.
*

View File

@ -12,6 +12,7 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
@ -70,6 +71,42 @@ public class InformationExtractorJdbcDatabaseMetaDataImpl implements Information
return extractionContext.getJdbcEnvironment().getSqlExceptionHelper().convert( sqlException, message );
}
protected String toMetaDataObjectName(Identifier identifier) {
return extractionContext.getJdbcEnvironment().getIdentifierHelper().toMetaDataObjectName( identifier );
}
@Override
public boolean catalogExists(Identifier catalog) {
try {
final ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getCatalogs();
try {
while ( resultSet.next() ) {
final String existingCatalogName = resultSet.getString( "TABLE_CAT" );
// todo : hmm.. case sensitive or insensitive match...
// for now, match any case...
if ( catalog.getText().equalsIgnoreCase( existingCatalogName ) ) {
return true;
}
}
return false;
}
finally {
try {
resultSet.close();
}
catch (SQLException ignore) {
}
}
}
catch (SQLException sqlException) {
throw convertSQLException( sqlException, "Unable to query DatabaseMetaData for existing catalogs" );
}
}
@Override
public boolean schemaExists(Identifier catalog, Identifier schema) {
try {
@ -150,17 +187,140 @@ public class InformationExtractorJdbcDatabaseMetaDataImpl implements Information
@Override
public TableInformation getTable(Identifier catalog, Identifier schema, Identifier tableName) {
try {
final String catalogFilter = determineCatalogFilter( catalog );
final String schemaFilter = determineSchemaFilter( schema );
if ( catalog != null || schema != null ) {
// The table defined an explicit namespace. In such cases we only ever want to look
// in the identified namespace
ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getTables(
catalogFilter,
schemaFilter,
extractionContext.getJdbcEnvironment().getIdentifierHelper().toMetaDataObjectName( tableName ),
return locateTableInNamespace( catalog, schema, tableName );
}
else {
// The table did not define an explicit namespace:
// 1) look in current namespace
// 2) look in default namespace
// 3) look in all namespaces - multiple hits is considered an error
TableInformation tableInfo = null;
// 1) look in current namespace
if ( extractionContext.getJdbcEnvironment().getCurrentCatalog() != null
|| extractionContext.getJdbcEnvironment().getCurrentSchema() != null ) {
tableInfo = locateTableInNamespace(
extractionContext.getJdbcEnvironment().getCurrentCatalog(),
extractionContext.getJdbcEnvironment().getCurrentSchema(),
tableName
);
if ( tableInfo != null ) {
return tableInfo;
}
}
// 2) look in default namespace
if ( extractionContext.getDefaultCatalog() != null || extractionContext.getDefaultSchema() != null ) {
tableInfo = locateTableInNamespace(
extractionContext.getJdbcEnvironment().getCurrentCatalog(),
extractionContext.getJdbcEnvironment().getCurrentSchema(),
tableName
);
if ( tableInfo != null ) {
return tableInfo;
}
}
// 3) look in all namespaces
try {
final String tableNameFilter = toMetaDataObjectName( tableName );
final ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getTables(
null,
null,
tableNameFilter,
tableTypes
);
try {
return processGetTableResults(
null,
null,
tableName,
resultSet
);
}
finally {
try {
resultSet.close();
}
catch (SQLException ignore) {
}
}
}
catch (SQLException sqlException) {
throw convertSQLException( sqlException, "Error accessing table metadata" );
}
}
}
private TableInformation locateTableInNamespace(
Identifier catalog,
Identifier schema,
Identifier tableName) {
final String catalogFilter;
final String schemaFilter;
if ( extractionContext.getJdbcEnvironment().getNameQualifierSupport().supportsCatalogs() ) {
if ( catalog == null ) {
catalogFilter = "";
}
else {
catalogFilter = toMetaDataObjectName( catalog );
}
}
else {
catalogFilter = null;
}
if ( extractionContext.getJdbcEnvironment().getNameQualifierSupport().supportsSchemas() ) {
if ( schema == null ) {
schemaFilter = "";
}
else {
schemaFilter = toMetaDataObjectName( schema );
}
}
else {
schemaFilter = null;
}
final String tableNameFilter = toMetaDataObjectName( tableName );
try {
ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getTables(
catalogFilter,
schemaFilter,
tableNameFilter,
tableTypes
);
return processGetTableResults(
catalog,
schema,
tableName,
resultSet
);
}
catch (SQLException sqlException) {
throw convertSQLException( sqlException, "Error accessing table metadata" );
}
}
private TableInformation processGetTableResults(
Identifier catalog,
Identifier schema,
Identifier tableName,
ResultSet resultSet) throws SQLException {
try {
if ( !resultSet.next() ) {
log.tableNotFound( tableName.render() );
@ -176,6 +336,15 @@ public class InformationExtractorJdbcDatabaseMetaDataImpl implements Information
if ( resultSet.next() ) {
log.multipleTablesFound( tableName.render() );
throw new SchemaExtractionException(
String.format(
Locale.ENGLISH,
"More than one table found in namespace (%s, %s) : %s",
catalog.render(),
schema.render(),
tableName.render()
)
);
}
return tableInformation;
@ -188,10 +357,6 @@ public class InformationExtractorJdbcDatabaseMetaDataImpl implements Information
}
}
}
catch (SQLException sqlException) {
throw convertSQLException( sqlException, "Error accessing table metadata" );
}
}
protected boolean isPhysicalTableType(String tableType) {
return "TABLE".equalsIgnoreCase( tableType );

View File

@ -23,6 +23,23 @@ import org.hibernate.tool.schema.extract.internal.TableInformationImpl;
*/
public interface InformationExtractor {
/**
* Does the given catalog exist yet?
*
* @param catalog The name of the catalog to look for.
*
* @return {@code true} if the catalog does exist; {@code false} otherwise
*/
boolean catalogExists(Identifier catalog);
/**
* The the given schema exist yet?
*
* @param catalog The name of the catalog to look in.
* @param schema The name of the schema to look for.
*
* @return {@code true} if the schema does exist; {@code false} otherwise
*/
boolean schemaExists(Identifier catalog, Identifier schema);
/**