HHH-7472 - Introduce a "schema management" service

This commit is contained in:
Steve Ebersole 2012-07-28 00:04:20 -05:00
parent f43c8bab1b
commit 47f6360225
12 changed files with 564 additions and 405 deletions

View File

@ -23,17 +23,25 @@
*/ */
package org.hibernate.engine.jdbc.env.internal; package org.hibernate.engine.jdbc.env.internal;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set; import java.util.Set;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.env.spi.SchemaCatalogSupport; import org.hibernate.engine.jdbc.env.spi.SchemaCatalogSupport;
import org.hibernate.engine.jdbc.spi.SchemaNameResolver; import org.hibernate.engine.jdbc.env.spi.StandardSchemaCatalogSupportImpl;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.exception.internal.SQLExceptionTypeDelegate; import org.hibernate.exception.internal.SQLExceptionTypeDelegate;
import org.hibernate.exception.internal.SQLStateConversionDelegate; import org.hibernate.exception.internal.SQLStateConversionDelegate;
import org.hibernate.exception.internal.StandardSQLExceptionConverter; import org.hibernate.exception.internal.StandardSQLExceptionConverter;
import org.hibernate.exception.spi.SQLExceptionConverter; import org.hibernate.exception.spi.SQLExceptionConverter;
import org.hibernate.metamodel.spi.relational.Identifier;
import org.hibernate.service.schema.spi.ExistingSequenceMetadataExtractor; import org.hibernate.service.schema.spi.ExistingSequenceMetadataExtractor;
/** /**
@ -41,24 +49,58 @@ import org.hibernate.service.schema.spi.ExistingSequenceMetadataExtractor;
*/ */
public class JdbcEnvironmentImpl implements JdbcEnvironment { public class JdbcEnvironmentImpl implements JdbcEnvironment {
private final Dialect dialect; private final Dialect dialect;
private final IdentifierHelper identifierHelper;
private final Identifier currentCatalog;
private final Identifier currentSchema;
private final SchemaCatalogSupport schemaCatalogSupport; private final SchemaCatalogSupport schemaCatalogSupport;
private final SchemaNameResolver schemaNameResolver;
private ExistingSequenceMetadataExtractor sequenceMetadataExtractor; private ExistingSequenceMetadataExtractor sequenceMetadataExtractor;
private final Set<String> reservedWords; private final Set<String> reservedWords;
private final SqlExceptionHelper sqlExceptionHelper; private final SqlExceptionHelper sqlExceptionHelper;
public JdbcEnvironmentImpl( public JdbcEnvironmentImpl(DatabaseMetaData dbmd, Dialect dialect, Map properties) throws SQLException {
Dialect dialect,
SchemaCatalogSupport schemaCatalogSupport,
SchemaNameResolver schemaNameResolver,
ExistingSequenceMetadataExtractor sequenceMetadataExtractor,
Set<String> reservedWords) {
this.dialect = dialect; this.dialect = dialect;
this.schemaCatalogSupport = schemaCatalogSupport;
this.schemaNameResolver = schemaNameResolver; Set<String> reservedWords = new HashSet<String>();
this.sequenceMetadataExtractor = sequenceMetadataExtractor; reservedWords.addAll( dialect.getKeywords() );
// todo : do we need to explicitly handle SQL:2003 keywords?
reservedWords.addAll( Arrays.asList( dbmd.getSQLKeywords().split( "," ) ) );
this.reservedWords = reservedWords; this.reservedWords = reservedWords;
this.identifierHelper = new NormalizingIdentifierHelperImpl(
this,
dbmd.storesMixedCaseQuotedIdentifiers(),
dbmd.storesLowerCaseQuotedIdentifiers(),
dbmd.storesUpperCaseQuotedIdentifiers(),
dbmd.storesUpperCaseIdentifiers(),
dbmd.storesLowerCaseIdentifiers()
);
String currentCatalogName = dbmd.getConnection().getCatalog();
if ( currentCatalogName != null ) {
// intentionally using fromMetaDataObjectName rather than fromMetaDataCatalogName !!!
currentCatalog = identifierHelper.fromMetaDataObjectName( currentCatalogName );
}
else {
currentCatalogName = (String) properties.get( AvailableSettings.DEFAULT_CATALOG );
currentCatalog = Identifier.toIdentifier( currentCatalogName );
}
String currentSchemaName = TemporarySchemaNameResolver.INSTANCE.resolveSchemaName( dbmd.getConnection() );
if ( currentSchemaName != null ) {
// intentionally using fromMetaDataObjectName rather than fromMetaDataSchemaName !!!
currentSchema = identifierHelper.fromMetaDataObjectName( currentSchemaName );
}
else {
currentSchemaName = (String) properties.get( AvailableSettings.DEFAULT_SCHEMA );
currentSchema = Identifier.toIdentifier( currentSchemaName );
}
schemaCatalogSupport = new StandardSchemaCatalogSupportImpl(
dbmd.getCatalogSeparator(),
dbmd.isCatalogAtStart(),
dialect.openQuote(),
dialect.closeQuote()
);
SQLExceptionConverter sqlExceptionConverter = dialect.buildSQLExceptionConverter(); SQLExceptionConverter sqlExceptionConverter = dialect.buildSQLExceptionConverter();
if ( sqlExceptionConverter == null ) { if ( sqlExceptionConverter == null ) {
@ -66,11 +108,56 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
sqlExceptionConverter = converter; sqlExceptionConverter = converter;
converter.addDelegate( dialect.buildSQLExceptionConversionDelegate() ); converter.addDelegate( dialect.buildSQLExceptionConversionDelegate() );
converter.addDelegate( new SQLExceptionTypeDelegate( dialect ) ); converter.addDelegate( new SQLExceptionTypeDelegate( dialect ) );
// todo : vary this based on extractedMetaDataSupport.getSqlStateType()
converter.addDelegate( new SQLStateConversionDelegate( dialect ) ); converter.addDelegate( new SQLStateConversionDelegate( dialect ) );
} }
this.sqlExceptionHelper = new SqlExceptionHelper( sqlExceptionConverter ); this.sqlExceptionHelper = new SqlExceptionHelper( sqlExceptionConverter );
this.sequenceMetadataExtractor = new TemporaryExistingSequenceMetadataExtractor( this );
}
public JdbcEnvironmentImpl(Dialect dialect, Map properties) {
this.dialect = dialect;
Set<String> reservedWords = new HashSet<String>();
reservedWords.addAll( dialect.getKeywords() );
// todo : do we need to explicitly handle SQL:2003 keywords?
this.reservedWords = reservedWords;
// again, a simple temporary impl that works on H2
this.identifierHelper = new NormalizingIdentifierHelperImpl(
this,
true, // storesMixedCaseQuotedIdentifiers
false, // storesLowerCaseQuotedIdentifiers
false, // storesUpperCaseQuotedIdentifiers
true, // storesUpperCaseIdentifiers
false // storesLowerCaseIdentifiers
);
String currentCatalogName = (String) properties.get( AvailableSettings.DEFAULT_CATALOG );
currentCatalog = Identifier.toIdentifier( currentCatalogName );
String currentSchemaName = (String) properties.get( AvailableSettings.DEFAULT_SCHEMA );
currentSchema = Identifier.toIdentifier( currentSchemaName );
// again, a simple temporary impl that works on H2
schemaCatalogSupport = new StandardSchemaCatalogSupportImpl(
".",
true,
dialect.openQuote(),
dialect.closeQuote()
);
SQLExceptionConverter sqlExceptionConverter = dialect.buildSQLExceptionConverter();
if ( sqlExceptionConverter == null ) {
final StandardSQLExceptionConverter converter = new StandardSQLExceptionConverter();
sqlExceptionConverter = converter;
converter.addDelegate( dialect.buildSQLExceptionConversionDelegate() );
converter.addDelegate( new SQLExceptionTypeDelegate( dialect ) );
converter.addDelegate( new SQLStateConversionDelegate( dialect ) );
}
this.sqlExceptionHelper = new SqlExceptionHelper( sqlExceptionConverter );
this.sequenceMetadataExtractor = new TemporaryExistingSequenceMetadataExtractor( this );
} }
@Override @Override
@ -78,14 +165,24 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
return dialect; return dialect;
} }
@Override
public Identifier getCurrentCatalog() {
return currentCatalog;
}
@Override
public Identifier getCurrentSchema() {
return currentSchema;
}
@Override @Override
public SchemaCatalogSupport getSchemaCatalogSupport() { public SchemaCatalogSupport getSchemaCatalogSupport() {
return schemaCatalogSupport; return schemaCatalogSupport;
} }
@Override @Override
public SchemaNameResolver getSchemaNameResolver() { public IdentifierHelper getIdentifierHelper() {
return schemaNameResolver; return identifierHelper;
} }
@Override @Override

View File

@ -0,0 +1,199 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.engine.jdbc.env.internal;
import org.jboss.logging.Logger;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.spi.relational.Identifier;
/**
* @author Steve Ebersole
*/
public class NormalizingIdentifierHelperImpl implements IdentifierHelper {
private static final Logger log = Logger.getLogger( NormalizingIdentifierHelperImpl.class );
private final JdbcEnvironment jdbcEnvironment;
private final boolean storesMixedCaseQuotedIdentifiers;
private final boolean storesLowerCaseQuotedIdentifiers;
private final boolean storesUpperCaseQuotedIdentifiers;
private final boolean storesUpperCaseIdentifiers;
private final boolean storesLowerCaseIdentifiers;
public NormalizingIdentifierHelperImpl(
JdbcEnvironment jdbcEnvironment, boolean storesMixedCaseQuotedIdentifiers,
boolean storesLowerCaseQuotedIdentifiers,
boolean storesUpperCaseQuotedIdentifiers,
boolean storesUpperCaseIdentifiers,
boolean storesLowerCaseIdentifiers) {
this.jdbcEnvironment = jdbcEnvironment;
this.storesMixedCaseQuotedIdentifiers = storesMixedCaseQuotedIdentifiers;
this.storesLowerCaseQuotedIdentifiers = storesLowerCaseQuotedIdentifiers;
this.storesUpperCaseQuotedIdentifiers = storesUpperCaseQuotedIdentifiers;
this.storesUpperCaseIdentifiers = storesUpperCaseIdentifiers;
this.storesLowerCaseIdentifiers = storesLowerCaseIdentifiers;
if ( storesMixedCaseQuotedIdentifiers && storesLowerCaseQuotedIdentifiers && storesUpperCaseQuotedIdentifiers ) {
log.warn( "JDBC Driver reports it stores quoted identifiers in mixed, upper and lower case" );
}
else if ( storesMixedCaseQuotedIdentifiers && storesUpperCaseQuotedIdentifiers ) {
log.warn( "JDBC Driver reports it stores quoted identifiers in both mixed and upper case" );
}
else if ( storesMixedCaseQuotedIdentifiers && storesLowerCaseQuotedIdentifiers ) {
log.warn( "JDBC Driver reports it stores quoted identifiers in both mixed and lower case" );
}
if ( storesUpperCaseIdentifiers && storesLowerCaseIdentifiers ) {
log.warn( "JDBC Driver reports it stores non-quoted identifiers in both upper and lower case" );
}
if ( storesUpperCaseIdentifiers && storesUpperCaseQuotedIdentifiers ) {
log.warn( "JDBC Driver reports it stores both quoted and non-quoted identifiers in upper case" );
}
if ( storesLowerCaseIdentifiers && storesLowerCaseQuotedIdentifiers ) {
log.warn( "JDBC Driver reports it stores both quoted and non-quoted identifiers in lower case" );
}
}
// In the DatabaseMetaData method params for catalog and schema name have the following meaning:
// 1) <""> means to match things "without a catalog/schema"
// 2) <null> means to not limit results based on this field
//
// todo : not sure how "without a catalog/schema" is interpreted. Current?
@Override
public String toMetaDataCatalogName(Identifier identifier) {
if ( identifier == null ) {
// todo : not sure if this is interpreted as <""> or <currentCatalog>
return jdbcEnvironment.getCurrentCatalog().getText();
}
return toText( identifier );
}
private String toText(Identifier identifier) {
if ( identifier == null ) {
throw new IllegalArgumentException( "Identifier cannot be null; bad usage" );
}
if ( identifier.isQuoted() && storesMixedCaseQuotedIdentifiers ) {
return identifier.getText();
}
else if ( ( identifier.isQuoted() && storesUpperCaseQuotedIdentifiers )
|| ( !identifier.isQuoted() && storesUpperCaseIdentifiers ) ) {
return StringHelper.toUpperCase( identifier.getText() );
}
else if ( ( identifier.isQuoted() && storesLowerCaseQuotedIdentifiers )
|| ( !identifier.isQuoted() && storesLowerCaseIdentifiers ) ) {
return StringHelper.toLowerCase( identifier.getText() );
}
return identifier.getText();
}
@Override
public String toMetaDataSchemaName(Identifier identifier) {
if ( identifier == null ) {
// todo : not sure if this is interpreted as <""> or <currentSchema>
return jdbcEnvironment.getCurrentSchema().getText();
}
return toText( identifier );
}
@Override
public String toMetaDataObjectName(Identifier identifier) {
if ( identifier == null ) {
// if this method was called, the value is needed
throw new IllegalArgumentException( );
}
return toText( identifier );
}
@Override
public Identifier fromMetaDataCatalogName(String catalogName) {
if ( catalogName == null ) {
return null;
}
if ( catalogName.equals( jdbcEnvironment.getCurrentCatalog().getText() ) ) {
return null;
}
return toIdentifier( catalogName );
// note really sure the best way to know (can you?) whether the identifier is quoted
}
private Identifier toIdentifier(String incomingName) {
// lovely decipher of whether the incoming value represents a quoted identifier...
final boolean isUpperCase = incomingName.toUpperCase().equals( incomingName );
final boolean isLowerCase = incomingName.toLowerCase().equals( incomingName );
final boolean isMixedCase = ! isLowerCase && ! isUpperCase;
if ( jdbcEnvironment.getReservedWords().contains( incomingName ) ) {
// unequivocally it needs to be quoted...
return Identifier.toIdentifier( incomingName, true );
}
if ( storesMixedCaseQuotedIdentifiers && isMixedCase ) {
return Identifier.toIdentifier( incomingName, true );
}
if ( storesLowerCaseQuotedIdentifiers && isLowerCase ) {
return Identifier.toIdentifier( incomingName, true );
}
if ( storesUpperCaseQuotedIdentifiers && isUpperCase ) {
return Identifier.toIdentifier( incomingName, true );
}
return Identifier.toIdentifier( incomingName );
}
@Override
public Identifier fromMetaDataSchemaName(String schemaName) {
if ( schemaName == null ) {
return null;
}
if ( schemaName.equals( jdbcEnvironment.getCurrentSchema().getText() ) ) {
return null;
}
return toIdentifier( schemaName );
}
@Override
public Identifier fromMetaDataObjectName(String objectName) {
if ( objectName == null ) {
return null;
}
return toIdentifier( objectName );
}
}

View File

@ -0,0 +1,101 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.engine.jdbc.env.internal;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.metamodel.spi.relational.ObjectName;
import org.hibernate.service.schema.internal.ExistingSequenceMetadataImpl;
import org.hibernate.service.schema.spi.ExistingSequenceMetadata;
import org.hibernate.service.schema.spi.ExistingSequenceMetadataExtractor;
/**
* Temporary implementation that works for H2.
*
* @author Steve Ebersole
*/
public class TemporaryExistingSequenceMetadataExtractor implements ExistingSequenceMetadataExtractor {
private final JdbcEnvironmentImpl jdbcEnvironment;
public TemporaryExistingSequenceMetadataExtractor(JdbcEnvironmentImpl jdbcEnvironment) {
this.jdbcEnvironment = jdbcEnvironment;
}
@Override
public Iterable<ExistingSequenceMetadata> extractMetadata(DatabaseMetaData databaseMetaData) throws SQLException {
Statement statement = databaseMetaData.getConnection().createStatement();
try {
ResultSet resultSet = statement.executeQuery(
"select SEQUENCE_CATALOG, SEQUENCE_SCHEMA, SEQUENCE_NAME " +
"from information_schema.sequences"
);
try {
final List<ExistingSequenceMetadata> sequenceMetadataList = new ArrayList<ExistingSequenceMetadata>();
while ( resultSet.next() ) {
sequenceMetadataList.add(
new ExistingSequenceMetadataImpl(
new ObjectName(
jdbcEnvironment.getIdentifierHelper().fromMetaDataCatalogName(
resultSet.getString(
"SEQUENCE_CATALOG"
)
),
jdbcEnvironment.getIdentifierHelper().fromMetaDataSchemaName(
resultSet.getString(
"SEQUENCE_SCHEMA"
)
),
jdbcEnvironment.getIdentifierHelper().fromMetaDataCatalogName(
resultSet.getString(
"SEQUENCE_NAME"
)
)
)
)
);
}
return sequenceMetadataList;
}
finally {
try {
resultSet.close();
}
catch (SQLException ignore) {
}
}
}
finally {
try {
statement.close();
}
catch (SQLException ignore) {
}
}
}
}

View File

@ -0,0 +1,69 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.engine.jdbc.env.internal;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.hibernate.engine.jdbc.env.spi.SchemaNameResolver;
/**
* Temporary implementation that works for H2.
*
* @author Steve Ebersole
*/
public class TemporarySchemaNameResolver implements SchemaNameResolver {
public static final TemporarySchemaNameResolver INSTANCE = new TemporarySchemaNameResolver();
@Override
public String resolveSchemaName(Connection connection) throws SQLException {
// the H2 variant...
Statement statement = connection.createStatement();
try {
ResultSet resultSet = statement.executeQuery( "call schema()" );
try {
if ( ! resultSet.next() ) {
return null;
}
return resultSet.getString( 1 );
}
finally {
try {
resultSet.close();
}
catch (SQLException ignore) {
}
}
}
finally {
try {
statement.close();
}
catch (SQLException ignore) {
}
}
}
}

View File

@ -21,7 +21,7 @@
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.service.schema.spi; package org.hibernate.engine.jdbc.env.spi;
import org.hibernate.metamodel.spi.relational.Identifier; import org.hibernate.metamodel.spi.relational.Identifier;

View File

@ -26,8 +26,8 @@ package org.hibernate.engine.jdbc.env.spi;
import java.util.Set; import java.util.Set;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.spi.SchemaNameResolver;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.metamodel.spi.relational.Identifier;
import org.hibernate.service.schema.spi.ExistingSequenceMetadataExtractor; import org.hibernate.service.schema.spi.ExistingSequenceMetadataExtractor;
/** /**
@ -39,9 +39,13 @@ import org.hibernate.service.schema.spi.ExistingSequenceMetadataExtractor;
public interface JdbcEnvironment { public interface JdbcEnvironment {
public Dialect getDialect(); public Dialect getDialect();
public Identifier getCurrentCatalog();
public Identifier getCurrentSchema();
public SchemaCatalogSupport getSchemaCatalogSupport(); public SchemaCatalogSupport getSchemaCatalogSupport();
public SchemaNameResolver getSchemaNameResolver(); public IdentifierHelper getIdentifierHelper();
public Set<String> getReservedWords(); public Set<String> getReservedWords();

View File

@ -21,7 +21,7 @@
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.engine.jdbc.spi; package org.hibernate.engine.jdbc.env.spi;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;

View File

@ -1,168 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.engine.jdbc.env.spi;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentImpl;
import org.hibernate.engine.jdbc.spi.SchemaNameResolver;
import org.hibernate.metamodel.spi.relational.ObjectName;
import org.hibernate.service.schema.internal.ExistingSequenceMetadataImpl;
import org.hibernate.service.schema.spi.ExistingSequenceMetadata;
import org.hibernate.service.schema.spi.ExistingSequenceMetadataExtractor;
import org.hibernate.service.schema.spi.IdentifierHelper;
/**
* @author Steve Ebersole
*/
public class StandardJdbcEnvironmentBuilder {
public static final StandardJdbcEnvironmentBuilder INSTANCE = new StandardJdbcEnvironmentBuilder();
private static final SchemaNameResolver FOR_NOW_SCHEMA_NAME_RESOLVER = new SchemaNameResolver() {
@Override
public String resolveSchemaName(Connection connection) throws SQLException {
// the H2 variant...
Statement statement = connection.createStatement();
try {
ResultSet resultSet = statement.executeQuery( "call schema()" );
try {
if ( ! resultSet.next() ) {
return null;
}
return resultSet.getString( 1 );
}
finally {
try {
resultSet.close();
}
catch (SQLException ignore) {
}
}
}
finally {
try {
statement.close();
}
catch (SQLException ignore) {
}
}
}
};
private static final ExistingSequenceMetadataExtractor FOR_NOW_SEQ_META_EXTRACTOR = new ExistingSequenceMetadataExtractor() {
@Override
public Iterable<ExistingSequenceMetadata> extractMetadata(
DatabaseMetaData databaseMetaData,
IdentifierHelper identifierHelper) throws SQLException {
// again, the H2 variant...
Statement statement = databaseMetaData.getConnection().createStatement();
try {
ResultSet resultSet = statement.executeQuery(
"select SEQUENCE_CATALOG, SEQUENCE_SCHEMA, SEQUENCE_NAME " +
"from information_schema.sequences"
);
try {
final List<ExistingSequenceMetadata> sequenceMetadataList = new ArrayList<ExistingSequenceMetadata>();
while ( resultSet.next() ) {
sequenceMetadataList.add(
new ExistingSequenceMetadataImpl(
new ObjectName(
identifierHelper.fromMetaDataCatalogName(
resultSet.getString(
"SEQUENCE_CATALOG"
)
),
identifierHelper.fromMetaDataSchemaName( resultSet.getString( "SEQUENCE_SCHEMA" ) ),
identifierHelper.fromMetaDataCatalogName( resultSet.getString( "SEQUENCE_NAME" ) )
)
)
);
}
return sequenceMetadataList;
}
finally {
try {
resultSet.close();
}
catch (SQLException ignore) {
}
}
}
finally {
try {
statement.close();
}
catch (SQLException ignore) {
}
}
}
};
public JdbcEnvironment buildJdbcEnvironment(DatabaseMetaData dbmd, Dialect dialect) throws SQLException {
SchemaCatalogSupport schemaCatalogSupport = new StandardSchemaCatalogSupportImpl(
dbmd.getCatalogSeparator(),
dbmd.isCatalogAtStart(),
dialect.openQuote(),
dialect.closeQuote()
);
Set<String> reservedWords = new HashSet<String>();
reservedWords.addAll( dialect.getKeywords() );
// todo : do we need to explicitly handle SQL:2003 keywords?
reservedWords.addAll( Arrays.asList( dbmd.getSQLKeywords().split( "," ) ) );
return new JdbcEnvironmentImpl(
dialect,
schemaCatalogSupport,
FOR_NOW_SCHEMA_NAME_RESOLVER,
FOR_NOW_SEQ_META_EXTRACTOR,
reservedWords
);
}
public JdbcEnvironment buildJdbcEnvironment(Dialect dialect) throws SQLException {
SchemaCatalogSupport schemaCatalogSupport = new StandardSchemaCatalogSupportImpl( dialect );
Set<String> reservedWords = new HashSet<String>();
reservedWords.addAll( dialect.getKeywords() );
return new JdbcEnvironmentImpl(
dialect,
schemaCatalogSupport,
FOR_NOW_SCHEMA_NAME_RESOLVER,
FOR_NOW_SEQ_META_EXTRACTOR,
reservedWords
);
}
}

View File

@ -46,7 +46,7 @@ import org.hibernate.engine.jdbc.spi.ExtractedDatabaseMetaData;
import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess; import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.ResultSetWrapper; import org.hibernate.engine.jdbc.spi.ResultSetWrapper;
import org.hibernate.engine.jdbc.spi.SchemaNameResolver; import org.hibernate.engine.jdbc.env.spi.SchemaNameResolver;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.SqlStatementLogger; import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
import org.hibernate.exception.internal.SQLExceptionTypeDelegate; import org.hibernate.exception.internal.SQLExceptionTypeDelegate;

View File

@ -30,11 +30,9 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import org.jboss.logging.Logger;
import org.hibernate.TruthValue; import org.hibernate.TruthValue;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.spi.relational.Identifier; import org.hibernate.metamodel.spi.relational.Identifier;
import org.hibernate.metamodel.spi.relational.ObjectName; import org.hibernate.metamodel.spi.relational.ObjectName;
import org.hibernate.metamodel.spi.relational.Schema; import org.hibernate.metamodel.spi.relational.Schema;
@ -42,19 +40,14 @@ import org.hibernate.service.schema.spi.ExistingColumnMetadata;
import org.hibernate.service.schema.spi.ExistingDatabaseMetaData; import org.hibernate.service.schema.spi.ExistingDatabaseMetaData;
import org.hibernate.service.schema.spi.ExistingSequenceMetadata; import org.hibernate.service.schema.spi.ExistingSequenceMetadata;
import org.hibernate.service.schema.spi.ExistingTableMetadata; import org.hibernate.service.schema.spi.ExistingTableMetadata;
import org.hibernate.service.schema.spi.IdentifierHelper;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class ExistingDatabaseMetaDataImpl implements ExistingDatabaseMetaData { public class ExistingDatabaseMetaDataImpl implements ExistingDatabaseMetaData {
private static final Logger log = Logger.getLogger( ExistingDatabaseMetaDataImpl.class );
private final JdbcEnvironment jdbcEnvironment; private final JdbcEnvironment jdbcEnvironment;
private final DatabaseMetaData databaseMetaData; private final DatabaseMetaData databaseMetaData;
private final IdentifierHelperImpl identifierHelper;
private final Map<ObjectName,ExistingTableMetadataImpl> tables = new HashMap<ObjectName, ExistingTableMetadataImpl>(); private final Map<ObjectName,ExistingTableMetadataImpl> tables = new HashMap<ObjectName, ExistingTableMetadataImpl>();
private final Map<ObjectName,ExistingSequenceMetadata> sequences; private final Map<ObjectName,ExistingSequenceMetadata> sequences;
@ -70,34 +63,28 @@ public class ExistingDatabaseMetaDataImpl implements ExistingDatabaseMetaData {
private ExistingDatabaseMetaDataImpl(JdbcEnvironment jdbcEnvironment, DatabaseMetaData databaseMetaData) throws SQLException { private ExistingDatabaseMetaDataImpl(JdbcEnvironment jdbcEnvironment, DatabaseMetaData databaseMetaData) throws SQLException {
this.jdbcEnvironment = jdbcEnvironment; this.jdbcEnvironment = jdbcEnvironment;
this.databaseMetaData = databaseMetaData; this.databaseMetaData = databaseMetaData;
this.identifierHelper = new IdentifierHelperImpl( this.sequences = loadSequenceMetadataMap();
databaseMetaData.getConnection().getCatalog(), }
jdbcEnvironment.getSchemaNameResolver().resolveSchemaName( databaseMetaData.getConnection() ),
databaseMetaData.storesMixedCaseQuotedIdentifiers(),
databaseMetaData.storesLowerCaseQuotedIdentifiers(),
databaseMetaData.storesUpperCaseQuotedIdentifiers(),
databaseMetaData.storesUpperCaseIdentifiers(),
databaseMetaData.storesLowerCaseIdentifiers()
);
sequences = loadSequenceMetadataMap(); public IdentifierHelper identifierHelper() {
return jdbcEnvironment.getIdentifierHelper();
} }
private static final String[] TABLE_TYPES = new String[] { "TABLE", "VIEW" }; private static final String[] TABLE_TYPES = new String[] { "TABLE", "VIEW" };
private void loadTableMetadata(ResultSet resultSet) throws SQLException { private void loadTableMetadata(ResultSet resultSet) throws SQLException {
while ( resultSet.next() ) { while ( resultSet.next() ) {
final Identifier catalogIdentifier = identifierHelper.fromMetaDataCatalogName( final Identifier catalogIdentifier = identifierHelper().fromMetaDataCatalogName(
resultSet.getString( resultSet.getString(
"TABLE_CAT" "TABLE_CAT"
) )
); );
final Identifier schemaIdentifier = identifierHelper.fromMetaDataSchemaName( final Identifier schemaIdentifier = identifierHelper().fromMetaDataSchemaName(
resultSet.getString( resultSet.getString(
"TABLE_SCHEM" "TABLE_SCHEM"
) )
); );
final Identifier tableIdentifier = identifierHelper.fromMetaDataObjectName( final Identifier tableIdentifier = identifierHelper().fromMetaDataObjectName(
resultSet.getString( resultSet.getString(
"TABLE_NAME" "TABLE_NAME"
) )
@ -110,20 +97,17 @@ public class ExistingDatabaseMetaDataImpl implements ExistingDatabaseMetaData {
} }
tableMetadata = new ExistingTableMetadataImpl( this, tableName ); tableMetadata = new ExistingTableMetadataImpl( this, tableName );
tables.put( tableName, tableMetadata ); tables.put( toMapKey( tableName ), tableMetadata );
} }
} }
private Map<ObjectName,ExistingSequenceMetadata> loadSequenceMetadataMap() throws SQLException { private Map<ObjectName,ExistingSequenceMetadata> loadSequenceMetadataMap() throws SQLException {
Map<ObjectName,ExistingSequenceMetadata> sequences = new HashMap<ObjectName, ExistingSequenceMetadata>(); Map<ObjectName,ExistingSequenceMetadata> sequences = new HashMap<ObjectName, ExistingSequenceMetadata>();
final Iterable<ExistingSequenceMetadata> sequenceMetadatas = final Iterable<ExistingSequenceMetadata> sequenceMetadatas =
jdbcEnvironment.getExistingSequenceMetadataExtractor().extractMetadata( jdbcEnvironment.getExistingSequenceMetadataExtractor().extractMetadata( databaseMetaData );
databaseMetaData,
identifierHelper
);
if ( sequenceMetadatas != null ) { if ( sequenceMetadatas != null ) {
for ( ExistingSequenceMetadata sequenceMetadata :sequenceMetadatas ) { for ( ExistingSequenceMetadata sequenceMetadata :sequenceMetadatas ) {
sequences.put( sequenceMetadata.getSequenceName(), sequenceMetadata ); sequences.put( toMapKey( sequenceMetadata.getSequenceName() ), sequenceMetadata );
} }
} }
return sequences; return sequences;
@ -131,12 +115,37 @@ public class ExistingDatabaseMetaDataImpl implements ExistingDatabaseMetaData {
@Override @Override
public ExistingTableMetadata getTableMetadata(ObjectName tableName) { public ExistingTableMetadata getTableMetadata(ObjectName tableName) {
return tables.get( tableName ); return tables.get( toMapKey( tableName ) );
}
public static ObjectName toMapKey(ObjectName qualifiedName) {
Identifier catalog = qualifiedName.getCatalog();
if ( catalog != null ) {
if ( ! catalog.isQuoted() ) {
catalog = Identifier.toIdentifier( catalog.getText().toUpperCase() );
}
}
Identifier schema = qualifiedName.getSchema();
if ( schema != null ) {
if ( ! schema.isQuoted() ) {
schema = Identifier.toIdentifier( schema.getText().toUpperCase() );
}
}
Identifier name = qualifiedName.getName();
if ( name != null ) {
if ( ! name.isQuoted() ) {
name = Identifier.toIdentifier( name.getText().toUpperCase() );
}
}
return new ObjectName( catalog, schema, name );
} }
@Override @Override
public ExistingSequenceMetadata getSequenceMetadata(ObjectName sequenceName) { public ExistingSequenceMetadata getSequenceMetadata(ObjectName sequenceName) {
return sequences.get( sequenceName ); return sequences.get( toMapKey( sequenceName ) );
} }
public Map<Identifier, ExistingColumnMetadata> getColumnMetadata(ExistingTableMetadata tableMetadata) { public Map<Identifier, ExistingColumnMetadata> getColumnMetadata(ExistingTableMetadata tableMetadata) {
@ -144,9 +153,9 @@ public class ExistingDatabaseMetaDataImpl implements ExistingDatabaseMetaData {
try { try {
ResultSet resultSet = databaseMetaData.getColumns( ResultSet resultSet = databaseMetaData.getColumns(
identifierHelper.toMetaDataCatalogName( tableMetadata.getName().getCatalog() ), identifierHelper().toMetaDataCatalogName( tableMetadata.getName().getCatalog() ),
identifierHelper.toMetaDataSchemaName( tableMetadata.getName().getSchema() ), identifierHelper().toMetaDataSchemaName( tableMetadata.getName().getSchema() ),
identifierHelper.toMetaDataObjectName( tableMetadata.getName().getName() ), identifierHelper().toMetaDataObjectName( tableMetadata.getName().getName() ),
"%" "%"
); );
@ -194,9 +203,9 @@ public class ExistingDatabaseMetaDataImpl implements ExistingDatabaseMetaData {
try { try {
ResultSet resultSet = databaseMetaData.getImportedKeys( ResultSet resultSet = databaseMetaData.getImportedKeys(
identifierHelper.toMetaDataCatalogName( tableMetadata.getName().getCatalog() ), identifierHelper().toMetaDataCatalogName( tableMetadata.getName().getCatalog() ),
identifierHelper.toMetaDataSchemaName( tableMetadata.getName().getSchema() ), identifierHelper().toMetaDataSchemaName( tableMetadata.getName().getSchema() ),
identifierHelper.toMetaDataObjectName( tableMetadata.getName().getName() ) identifierHelper().toMetaDataObjectName( tableMetadata.getName().getName() )
); );
// todo : need to account for getCrossReference() as well... // todo : need to account for getCrossReference() as well...
@ -271,172 +280,6 @@ public class ExistingDatabaseMetaDataImpl implements ExistingDatabaseMetaData {
return TruthValue.UNKNOWN; return TruthValue.UNKNOWN;
} }
public class IdentifierHelperImpl implements IdentifierHelper {
private final String currentCatalog;
private final String currentSchema;
private final boolean storesMixedCaseQuotedIdentifiers;
private final boolean storesLowerCaseQuotedIdentifiers;
private final boolean storesUpperCaseQuotedIdentifiers;
private final boolean storesUpperCaseIdentifiers;
private final boolean storesLowerCaseIdentifiers;
public IdentifierHelperImpl(
String currentCatalog,
String currentSchema,
boolean storesMixedCaseQuotedIdentifiers,
boolean storesLowerCaseQuotedIdentifiers,
boolean storesUpperCaseQuotedIdentifiers,
boolean storesUpperCaseIdentifiers,
boolean storesLowerCaseIdentifiers) {
this.currentCatalog = currentCatalog;
this.currentSchema = currentSchema;
this.storesMixedCaseQuotedIdentifiers = storesMixedCaseQuotedIdentifiers;
this.storesLowerCaseQuotedIdentifiers = storesLowerCaseQuotedIdentifiers;
this.storesUpperCaseQuotedIdentifiers = storesUpperCaseQuotedIdentifiers;
this.storesUpperCaseIdentifiers = storesUpperCaseIdentifiers;
this.storesLowerCaseIdentifiers = storesLowerCaseIdentifiers;
if ( storesMixedCaseQuotedIdentifiers && storesLowerCaseQuotedIdentifiers && storesUpperCaseQuotedIdentifiers ) {
log.warn( "JDBC Driver reports it stores quoted identifiers in mixed, upper and lower case" );
}
else if ( storesMixedCaseQuotedIdentifiers && storesUpperCaseQuotedIdentifiers ) {
log.warn( "JDBC Driver reports it stores quoted identifiers in both mixed and upper case" );
}
else if ( storesMixedCaseQuotedIdentifiers && storesLowerCaseQuotedIdentifiers ) {
log.warn( "JDBC Driver reports it stores quoted identifiers in both mixed and lower case" );
}
if ( storesUpperCaseIdentifiers && storesLowerCaseIdentifiers ) {
log.warn( "JDBC Driver reports it stores non-quoted identifiers in both upper and lower case" );
}
if ( storesUpperCaseIdentifiers && storesUpperCaseQuotedIdentifiers ) {
log.warn( "JDBC Driver reports it stores both quoted and non-quoted identifiers in upper case" );
}
if ( storesLowerCaseIdentifiers && storesLowerCaseQuotedIdentifiers ) {
log.warn( "JDBC Driver reports it stores both quoted and non-quoted identifiers in lower case" );
}
}
// In the DatabaseMetaData method params for catalog and schema name have the following meaning:
// 1) <""> means to match things "without a catalog/schema"
// 2) <null> means to not limit results based on this field
//
// todo : not sure how "without a catalog/schema" is interpreted. Current?
@Override
public String toMetaDataCatalogName(Identifier identifier) {
if ( identifier == null ) {
// todo : not sure if this is interpreted as <""> or <currentCatalog>
return currentCatalog;
}
return toText( identifier );
}
private String toText(Identifier identifier) {
if ( identifier == null ) {
throw new IllegalArgumentException( "Identifier cannot be null; bad usage" );
}
if ( identifier.isQuoted() && storesMixedCaseQuotedIdentifiers ) {
return identifier.getText();
}
else if ( ( identifier.isQuoted() && storesUpperCaseQuotedIdentifiers )
|| ( !identifier.isQuoted() && storesUpperCaseIdentifiers ) ) {
return StringHelper.toUpperCase( identifier.getText() );
}
else if ( ( identifier.isQuoted() && storesLowerCaseQuotedIdentifiers )
|| ( !identifier.isQuoted() && storesLowerCaseIdentifiers ) ) {
return StringHelper.toLowerCase( identifier.getText() );
}
return identifier.getText();
}
@Override
public String toMetaDataSchemaName(Identifier identifier) {
if ( identifier == null ) {
// todo : not sure if this is interpreted as <""> or <currentSchema>
return currentSchema;
}
return toText( identifier );
}
@Override
public String toMetaDataObjectName(Identifier identifier) {
if ( identifier == null ) {
// if this method was called, the value is needed
throw new IllegalArgumentException( );
}
return toText( identifier );
}
@Override
public Identifier fromMetaDataCatalogName(String catalogName) {
if ( catalogName == null ) {
return null;
}
if ( catalogName.equals( currentCatalog ) ) {
return null;
}
return toIdentifier( catalogName );
// note really sure the best way to know (can you?) whether the identifier is quoted
}
private Identifier toIdentifier(String incomingName) {
// lovely decipher of whether the incoming value represents a quoted identifier...
final boolean isUpperCase = incomingName.toUpperCase().equals( incomingName );
final boolean isLowerCase = incomingName.toLowerCase().equals( incomingName );
final boolean isMixedCase = ! isLowerCase && ! isUpperCase;
if ( jdbcEnvironment.getReservedWords().contains( incomingName ) ) {
// unequivocally it needs to be quoted...
return Identifier.toIdentifier( incomingName, true );
}
if ( storesMixedCaseQuotedIdentifiers && isMixedCase ) {
return Identifier.toIdentifier( incomingName, true );
}
if ( storesLowerCaseQuotedIdentifiers && isLowerCase ) {
return Identifier.toIdentifier( incomingName, true );
}
if ( storesUpperCaseQuotedIdentifiers && isUpperCase ) {
return Identifier.toIdentifier( incomingName, true );
}
return Identifier.toIdentifier( incomingName );
}
@Override
public Identifier fromMetaDataSchemaName(String schemaName) {
if ( schemaName == null ) {
return null;
}
if ( schemaName.equals( currentSchema ) ) {
return null;
}
return toIdentifier( schemaName );
}
@Override
public Identifier fromMetaDataObjectName(String objectName) {
if ( objectName == null ) {
return null;
}
return toIdentifier( objectName );
}
}
public static interface Builder { public static interface Builder {
public Builder prepareAll(); public Builder prepareAll();
public Builder prepareCatalogAndSchema(Schema.Name schemaName); public Builder prepareCatalogAndSchema(Schema.Name schemaName);
@ -487,8 +330,8 @@ public class ExistingDatabaseMetaDataImpl implements ExistingDatabaseMetaData {
@Override @Override
public Builder prepareCatalogAndSchema(Schema.Name schemaName) { public Builder prepareCatalogAndSchema(Schema.Name schemaName) {
prepare( prepare(
it.identifierHelper.toMetaDataCatalogName( schemaName.getCatalog() ), it.identifierHelper().toMetaDataCatalogName( schemaName.getCatalog() ),
it.identifierHelper.toMetaDataSchemaName( schemaName.getSchema() ) it.identifierHelper().toMetaDataSchemaName( schemaName.getSchema() )
); );
return this; return this;
} }
@ -496,7 +339,7 @@ public class ExistingDatabaseMetaDataImpl implements ExistingDatabaseMetaData {
@Override @Override
public Builder prepareCatalog(Identifier catalog) { public Builder prepareCatalog(Identifier catalog) {
prepare( prepare(
it.identifierHelper.toMetaDataCatalogName( catalog ), it.identifierHelper().toMetaDataCatalogName( catalog ),
null null
); );
return this; return this;
@ -506,7 +349,7 @@ public class ExistingDatabaseMetaDataImpl implements ExistingDatabaseMetaData {
public Builder prepareSchema(Identifier schema) { public Builder prepareSchema(Identifier schema) {
prepare( prepare(
null, null,
it.identifierHelper.toMetaDataSchemaName( schema ) it.identifierHelper().toMetaDataSchemaName( schema )
); );
return this; return this;
} }

View File

@ -31,7 +31,5 @@ import java.sql.SQLException;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface ExistingSequenceMetadataExtractor { public interface ExistingSequenceMetadataExtractor {
public Iterable<ExistingSequenceMetadata> extractMetadata( public Iterable<ExistingSequenceMetadata> extractMetadata(DatabaseMetaData databaseMetaData) throws SQLException;
DatabaseMetaData databaseMetaData,
IdentifierHelper identifierHelper) throws SQLException;
} }

View File

@ -30,8 +30,9 @@ import java.util.Properties;
import org.hibernate.cfg.Environment; import org.hibernate.cfg.Environment;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentImpl;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.env.spi.StandardJdbcEnvironmentBuilder; import org.hibernate.metamodel.spi.relational.ObjectName;
import org.hibernate.service.schema.internal.ExistingDatabaseMetaDataImpl; import org.hibernate.service.schema.internal.ExistingDatabaseMetaDataImpl;
import org.hibernate.service.schema.spi.ExistingDatabaseMetaData; import org.hibernate.service.schema.spi.ExistingDatabaseMetaData;
@ -41,6 +42,8 @@ import org.junit.Test;
import org.hibernate.testing.junit4.BaseUnitTestCase; import org.hibernate.testing.junit4.BaseUnitTestCase;
import static org.junit.Assert.assertNotNull;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@ -56,18 +59,15 @@ public class ExistingDatabaseMetaDataImplTest extends BaseUnitTestCase {
props.getProperty( Environment.USER ), props.getProperty( Environment.USER ),
props.getProperty( Environment.PASS ) props.getProperty( Environment.PASS )
); );
connection.createStatement().execute( "CREATE SCHEMA \"another_schema\"" ); connection.createStatement().execute( "CREATE SCHEMA another_schema" );
connection.createStatement().execute( "CREATE TABLE t1 (name varchar)" ); connection.createStatement().execute( "CREATE TABLE t1 (name varchar)" );
connection.createStatement().execute( "CREATE TABLE db1.\"another_schema\".t2 (name varchar)" ); connection.createStatement().execute( "CREATE TABLE another_schema.t2 (name varchar)" );
connection.createStatement().execute( "CREATE SEQUENCE seq1" ); connection.createStatement().execute( "CREATE SEQUENCE seq1" );
connection.createStatement().execute( "CREATE SEQUENCE db1.\"another_schema\".seq1" ); connection.createStatement().execute( "CREATE SEQUENCE db1.another_schema.seq2" );
jdbcEnvironment = StandardJdbcEnvironmentBuilder.INSTANCE.buildJdbcEnvironment( jdbcEnvironment = new JdbcEnvironmentImpl( connection.getMetaData(), Dialect.getDialect( props ), props );
connection.getMetaData(),
Dialect.getDialect( props )
);
} }
@After @After
@ -81,10 +81,26 @@ public class ExistingDatabaseMetaDataImplTest extends BaseUnitTestCase {
} }
} }
// @Test @Test
public void testGetTableMetadata() throws Exception { public void testGetTableMetadata() throws Exception {
ExistingDatabaseMetaData databaseMetaData = ExistingDatabaseMetaData databaseMetaData =
ExistingDatabaseMetaDataImpl.builder( jdbcEnvironment, connection.getMetaData() ).prepareAll().build(); ExistingDatabaseMetaDataImpl.builder( jdbcEnvironment, connection.getMetaData() ).prepareAll().build();
databaseMetaData.toString();
ObjectName name = new ObjectName( null, null, "t1" );
assertNotNull( databaseMetaData.getTableMetadata( name ) );
name = new ObjectName( null, "another_schema", "t2" );
assertNotNull( databaseMetaData.getTableMetadata( name ) );
name = new ObjectName( null, null, "seq1" );
assertNotNull( databaseMetaData.getSequenceMetadata( name ) );
name = new ObjectName( null, "another_schema", "seq2" );
assertNotNull( databaseMetaData.getSequenceMetadata( name ) );
// knowing if identifiers coming back from the database are quoted is all dicked up...
// see org.hibernate.engine.jdbc.env.internal.NormalizingIdentifierHelperImpl
//
// surely JDBC has a better way to determine this right?
} }
} }