diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/Identifier.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/Identifier.java index 9cda8f66d6..b66ff016ef 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/Identifier.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/Identifier.java @@ -179,11 +179,11 @@ public class Identifier { Identifier that = (Identifier) o; return isQuoted == that.isQuoted - && text.equals( that.text ); + && isQuoted ? text.equals( that.text ) : text.equalsIgnoreCase( that.text ); } @Override public int hashCode() { - return text.hashCode(); + return isQuoted ? text.hashCode() : text.toUpperCase().hashCode(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/Table.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/Table.java index 1ca1f7af71..cbec4852ba 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/Table.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/Table.java @@ -31,8 +31,8 @@ import java.util.Set; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; -import org.hibernate.tool.schema.spi.ColumnInformation; -import org.hibernate.tool.schema.spi.TableInformation; +import org.hibernate.tool.schema.extract.spi.ColumnInformation; +import org.hibernate.tool.schema.extract.spi.TableInformation; /** * Models the concept of a relational TABLE (or VIEW). @@ -201,7 +201,7 @@ public class Table extends AbstractTableSpecification implements Exportable { } final Column column = (Column) value; - final ColumnInformation columnInformation = tableInformation.getColumnInformation( column.getColumnName() ); + final ColumnInformation columnInformation = tableInformation.getColumn( column.getColumnName() ); if ( columnInformation != null ) { continue; diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/ColumnInformationImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ColumnInformationImpl.java similarity index 93% rename from hibernate-core/src/main/java/org/hibernate/tool/schema/internal/ColumnInformationImpl.java rename to hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ColumnInformationImpl.java index d158672f1c..e4013a73f6 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/ColumnInformationImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ColumnInformationImpl.java @@ -21,12 +21,12 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.tool.schema.internal; +package org.hibernate.tool.schema.extract.internal; import org.hibernate.TruthValue; import org.hibernate.metamodel.spi.relational.Identifier; -import org.hibernate.tool.schema.spi.ColumnInformation; -import org.hibernate.tool.schema.spi.TableInformation; +import org.hibernate.tool.schema.extract.spi.ColumnInformation; +import org.hibernate.tool.schema.extract.spi.TableInformation; /** * JDBC column metadata diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java new file mode 100644 index 0000000000..b36c451260 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java @@ -0,0 +1,77 @@ +/* + * 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.tool.schema.extract.internal; + +import java.util.HashMap; +import java.util.Map; + +import org.hibernate.metamodel.spi.relational.ObjectName; +import org.hibernate.tool.schema.extract.spi.DatabaseInformation; +import org.hibernate.tool.schema.extract.spi.ExtractionContext; +import org.hibernate.tool.schema.extract.spi.SequenceInformation; +import org.hibernate.tool.schema.extract.spi.TableInformation; + +/** + * @author Steve Ebersole + */ +public class DatabaseInformationImpl implements DatabaseInformation, ExtractionContext.RegisteredObjectAccess { + private final Map tables = new HashMap(); + private final Map sequences = new HashMap(); + + public DatabaseInformationImpl() { + } + + // DatabaseInformation implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + @Override + public TableInformation getTableInformation(ObjectName tableName) { + return locateRegisteredTableInformation( tableName ); + } + + @Override + public SequenceInformation getSequenceInformation(ObjectName sequenceName) { + return locateRegisteredSequenceInformation( sequenceName ); + } + + + // RegisteredObjectAccess implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + @Override + public TableInformation locateRegisteredTableInformation(ObjectName tableName) { + return tables.get( tableName ); + } + + public void registerTableInformation(TableInformation tableInformation) { + tables.put( tableInformation.getName(), tableInformation ); + } + + @Override + public SequenceInformation locateRegisteredSequenceInformation(ObjectName sequenceName) { + return sequences.get( sequenceName ); + } + + public void registerSequenceInformation(SequenceInformation sequenceInformation) { + sequences.put( sequenceInformation.getSequenceName(), sequenceInformation ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ExtractionContextImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ExtractionContextImpl.java new file mode 100644 index 0000000000..a8f96851a9 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ExtractionContextImpl.java @@ -0,0 +1,103 @@ +/* + * 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.tool.schema.extract.internal; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; + +import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.tool.schema.extract.spi.ExtractionContext; + +/** + * @author Steve Ebersole + */ +public class ExtractionContextImpl implements ExtractionContext { + private final JdbcEnvironment jdbcEnvironment; + private final JdbcConnectionAccess jdbcConnectionAccess; + private final RegisteredObjectAccess registeredTableAccess; + + private Connection jdbcConnection; + private DatabaseMetaData jdbcDatabaseMetaData; + + public ExtractionContextImpl( + JdbcEnvironment jdbcEnvironment, + JdbcConnectionAccess jdbcConnectionAccess, + RegisteredObjectAccess registeredTableAccess) { + this.jdbcEnvironment = jdbcEnvironment; + this.jdbcConnectionAccess = jdbcConnectionAccess; + this.registeredTableAccess = registeredTableAccess; + } + + @Override + public JdbcEnvironment getJdbcEnvironment() { + return jdbcEnvironment; + } + + @Override + public Connection getJdbcConnection() { + if ( jdbcConnection == null ) { + try { + jdbcConnection = jdbcConnectionAccess.obtainConnection(); + } + catch (SQLException e) { + throw jdbcEnvironment.getSqlExceptionHelper().convert( e, "Unable to obtain JDBC Connection" ); + } + } + return jdbcConnection; + } + + @Override + public DatabaseMetaData getJdbcDatabaseMetaData() { + if ( jdbcDatabaseMetaData == null ) { + try { + jdbcDatabaseMetaData = getJdbcConnection().getMetaData(); + } + catch (SQLException e) { + throw jdbcEnvironment.getSqlExceptionHelper().convert( e, "Unable to obtain JDBC DatabaseMetaData" ); + } + } + return jdbcDatabaseMetaData; + } + + @Override + public RegisteredObjectAccess getRegisteredObjectAccess() { + return registeredTableAccess; + } + + public void cleanup() { + if ( jdbcDatabaseMetaData != null ) { + jdbcDatabaseMetaData = null; + } + + if ( jdbcConnection != null ) { + try { + jdbcConnectionAccess.releaseConnection( jdbcConnection ); + } + catch (SQLException ignore) { + } + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/ForeignKeyInformationImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ForeignKeyInformationImpl.java similarity index 62% rename from hibernate-core/src/main/java/org/hibernate/tool/schema/internal/ForeignKeyInformationImpl.java rename to hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ForeignKeyInformationImpl.java index 3f8a02c518..a07d53a2b0 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/ForeignKeyInformationImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ForeignKeyInformationImpl.java @@ -21,15 +21,13 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.tool.schema.internal; +package org.hibernate.tool.schema.extract.internal; -import java.util.ArrayList; import java.util.List; import org.hibernate.metamodel.spi.relational.Identifier; -import org.hibernate.tool.schema.spi.ColumnInformation; -import org.hibernate.tool.schema.spi.ForeignKeyInformation; -import org.hibernate.tool.schema.spi.SchemaManagementException; +import org.hibernate.tool.schema.extract.spi.ColumnInformation; +import org.hibernate.tool.schema.extract.spi.ForeignKeyInformation; /** * @author Steve Ebersole @@ -38,7 +36,7 @@ public class ForeignKeyInformationImpl implements ForeignKeyInformation { private final Identifier fkIdentifier; private final List columnMappingList; - private ForeignKeyInformationImpl( + public ForeignKeyInformationImpl( Identifier fkIdentifier, List columnMappingList) { this.fkIdentifier = fkIdentifier; @@ -51,37 +49,9 @@ public class ForeignKeyInformationImpl implements ForeignKeyInformation { } @Override - public List getColumnReferenceMappingList() { + public Iterable getColumnReferenceMappings() { return columnMappingList; } - - public static Builder builder(Identifier fkIdentifier) { - return new Builder( fkIdentifier ); - } - - public static class Builder { - private final Identifier fkIdentifier; - private final List columnMappingList = new ArrayList(); - - public Builder(Identifier fkIdentifier) { - this.fkIdentifier = fkIdentifier; - } - - public Builder addColumnMapping(ColumnInformation referencing, ColumnInformation referenced) { - columnMappingList.add( new ColumnReferenceMappingImpl( referencing, referenced ) ); - return this; - } - - public ForeignKeyInformationImpl build() { - if ( columnMappingList.isEmpty() ) { - throw new SchemaManagementException( - "Attempt to resolve foreign key metadata from JDBC metadata failed to find " + - "column mappings for foreign key named [" + fkIdentifier.getText() + "]" - ); - } - return new ForeignKeyInformationImpl( fkIdentifier, columnMappingList ); - } - } public static class ColumnReferenceMappingImpl implements ColumnReferenceMapping { private final ColumnInformation referencing; diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/IndexInformationImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/IndexInformationImpl.java similarity index 93% rename from hibernate-core/src/main/java/org/hibernate/tool/schema/internal/IndexInformationImpl.java rename to hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/IndexInformationImpl.java index 61bb31032d..b995cd0c43 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/IndexInformationImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/IndexInformationImpl.java @@ -21,15 +21,15 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.tool.schema.internal; +package org.hibernate.tool.schema.extract.internal; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.hibernate.metamodel.spi.relational.Identifier; -import org.hibernate.tool.schema.spi.ColumnInformation; -import org.hibernate.tool.schema.spi.IndexInformation; +import org.hibernate.tool.schema.extract.spi.ColumnInformation; +import org.hibernate.tool.schema.extract.spi.IndexInformation; import org.hibernate.tool.schema.spi.SchemaManagementException; /** diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SequenceInformationImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationImpl.java similarity index 93% rename from hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SequenceInformationImpl.java rename to hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationImpl.java index bd5713af34..254c12ffb7 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SequenceInformationImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationImpl.java @@ -21,10 +21,10 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.tool.schema.internal; +package org.hibernate.tool.schema.extract.internal; import org.hibernate.metamodel.spi.relational.ObjectName; -import org.hibernate.tool.schema.spi.SequenceInformation; +import org.hibernate.tool.schema.extract.spi.SequenceInformation; /** * For now we only collect sequence name. If all databases support it, would really like to see INCREMENT here as well. diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/StandardJdbcDatabaseMetaDataExtractor.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/StandardJdbcDatabaseMetaDataExtractor.java new file mode 100644 index 0000000000..683c84186f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/StandardJdbcDatabaseMetaDataExtractor.java @@ -0,0 +1,347 @@ +/* + * 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.tool.schema.extract.internal; + +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import org.hibernate.JDBCException; +import org.hibernate.TruthValue; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.metamodel.spi.relational.Identifier; +import org.hibernate.metamodel.spi.relational.ObjectName; +import org.hibernate.tool.schema.extract.spi.ColumnInformation; +import org.hibernate.tool.schema.extract.spi.ExtractionContext; +import org.hibernate.tool.schema.extract.spi.ForeignKeyInformation; +import org.hibernate.tool.schema.extract.spi.IndexInformation; +import org.hibernate.tool.schema.extract.spi.SchemaMetaDataExtractor; +import org.hibernate.tool.schema.extract.spi.TableInformation; +import org.hibernate.tool.schema.spi.SchemaManagementException; + +/** + * Implementation of the SchemaMetaDataExtractor contract which uses the standard JDBC {@link java.sql.DatabaseMetaData} + * API for extraction. + * + * @author Steve Ebersole + */ +public class StandardJdbcDatabaseMetaDataExtractor implements SchemaMetaDataExtractor { + private static final String[] TABLE_TYPES = new String[] { "TABLE", "VIEW" }; + + private final ExtractionContext extractionContext; + + public StandardJdbcDatabaseMetaDataExtractor(ExtractionContext extractionContext) { + this.extractionContext = extractionContext; + } + + protected IdentifierHelper identifierHelper() { + return extractionContext.getJdbcEnvironment().getIdentifierHelper(); + } + + protected JDBCException convertSQLException(SQLException sqlException, String message) { + return extractionContext.getJdbcEnvironment().getSqlExceptionHelper().convert( sqlException, message ); + } + + @Override + public Iterable getTables(String catalogFilter, String schemaFilter) { + try { + ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getTables( + catalogFilter, + schemaFilter, + null, + TABLE_TYPES + ); + + final List results = new ArrayList(); + + try { + while ( resultSet.next() ) { + final Identifier catalogIdentifier = identifierHelper().fromMetaDataCatalogName( + resultSet.getString( + "TABLE_CAT" + ) + ); + final Identifier schemaIdentifier = identifierHelper().fromMetaDataSchemaName( + resultSet.getString( + "TABLE_SCHEM" + ) + ); + final Identifier tableIdentifier = identifierHelper().fromMetaDataObjectName( + resultSet.getString( + "TABLE_NAME" + ) + ); + final ObjectName tableName = new ObjectName( catalogIdentifier, schemaIdentifier, tableIdentifier ); + TableInformation tableInformation = new TableInformationImpl( + this, + tableName, + isPhysicalTableType( resultSet.getString( "TABLE_TYPE" ) ), + resultSet.getString( "REMARKS" ) + ); + results.add( tableInformation ); + } + } + finally { + try { + resultSet.close(); + } + catch (SQLException ignore) { + } + } + + return results; + } + catch (SQLException sqlException) { + throw convertSQLException( sqlException, "Error accessing table metadata" ); + } + } + + protected boolean isPhysicalTableType(String tableType) { + return "TABLE".equalsIgnoreCase( tableType ); + } + + @Override + public Iterable getColumns(TableInformation tableInformation) { + final List results = new ArrayList(); + + try { + ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getColumns( + identifierHelper().toMetaDataCatalogName( tableInformation.getName().getCatalog() ), + identifierHelper().toMetaDataSchemaName( tableInformation.getName().getSchema() ), + identifierHelper().toMetaDataObjectName( tableInformation.getName().getName() ), + "%" + ); + + try { + while ( resultSet.next() ) { + final String columnName = resultSet.getString( "COLUMN_NAME" ); + if ( columnName == null ) { + continue; + } + + results.add( + new ColumnInformationImpl( + tableInformation, + Identifier.toIdentifier( columnName ), + resultSet.getInt( "DATA_TYPE" ), + new StringTokenizer( resultSet.getString( "TYPE_NAME" ), "() " ).nextToken(), + resultSet.getInt( "COLUMN_SIZE" ), + resultSet.getInt("DECIMAL_DIGITS"), + interpretTruthValue( resultSet.getString( "IS_NULLABLE" ) ) + ) + ); + } + } + finally { + resultSet.close(); + } + } + catch (SQLException e) { + throw convertSQLException( e, "Error accessing column metadata: " + tableInformation.getName().toString() ); + } + + return results; + } + + private TruthValue interpretTruthValue(String nullable) { + if ( "yes".equalsIgnoreCase( nullable ) ) { + return TruthValue.TRUE; + } + else if ( "no".equalsIgnoreCase( nullable ) ) { + return TruthValue.FALSE; + } + return TruthValue.UNKNOWN; + } + + @Override + public Iterable getIndexes(TableInformation tableInformation) { + final Map builders = new HashMap(); + + try { + ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getIndexInfo( + identifierHelper().toMetaDataCatalogName( tableInformation.getName().getCatalog() ), + identifierHelper().toMetaDataSchemaName( tableInformation.getName().getSchema() ), + identifierHelper().toMetaDataObjectName( tableInformation.getName().getName() ), + false, // DO NOT limit to just unique + true // DO require up-to-date results + ); + + try { + while ( resultSet.next() ) { + if ( resultSet.getShort("TYPE") == DatabaseMetaData.tableIndexStatistic ) { + continue; + } + + final Identifier indexIdentifier = Identifier.toIdentifier( resultSet.getString( "INDEX_NAME" ) ); + IndexInformationImpl.Builder builder = builders.get( indexIdentifier ); + if ( builder == null ) { + builder = IndexInformationImpl.builder( indexIdentifier ); + builders.put( indexIdentifier, builder ); + } + + final Identifier columnIdentifier = Identifier.toIdentifier( resultSet.getString( "COLUMN_NAME" ) ); + final ColumnInformation columnInformation = tableInformation.getColumn( columnIdentifier ); + if ( columnInformation == null ) { + throw new SchemaManagementException( + "Could not locate column information using identifier [" + columnIdentifier.getText() + "]" + ); + } + builder.addColumn( columnInformation ); + } + } + finally { + resultSet.close(); + } + } + catch (SQLException e) { + throw convertSQLException( + e, + "Error accessing index information: " + tableInformation.getName().toString() + ); + } + + final List indexes = new ArrayList(); + for ( IndexInformationImpl.Builder builder : builders.values() ) { + IndexInformationImpl index = builder.build(); + indexes.add( index ); + } + return indexes; + } + + @Override + public Iterable getForeignKeys(TableInformation tableInformation) { + final Map fkBuilders = new HashMap(); + + try { + ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getImportedKeys( + identifierHelper().toMetaDataCatalogName( tableInformation.getName().getCatalog() ), + identifierHelper().toMetaDataSchemaName( tableInformation.getName().getSchema() ), + identifierHelper().toMetaDataObjectName( tableInformation.getName().getName() ) + ); + + // todo : need to account for getCrossReference() as well... + + try { + while ( resultSet.next() ) { + // IMPL NOTE : The builder is mainly used to collect the column reference mappings + final Identifier fkIdentifier = Identifier.toIdentifier( resultSet.getString( "FK_NAME" ) ); + ForeignKeyBuilder fkBuilder = fkBuilders.get( fkIdentifier ); + if ( fkBuilder == null ) { + fkBuilder = generateForeignKeyBuilder( fkIdentifier ); + fkBuilders.put( fkIdentifier, fkBuilder ); + } + + final ObjectName incomingPkTableName = extractKeyTableName( resultSet, "PK" ); + + final TableInformation pkTableInformation = extractionContext.getRegisteredObjectAccess() + .locateRegisteredTableInformation( incomingPkTableName ); + + if ( pkTableInformation == null ) { + // the assumption here is that we have not seen this table already based on fully-qualified name + // during previous step of building all table metadata so most likely this is + // not a match based solely on schema/catalog and that another row in this result set + // should match. + continue; + } + + final Identifier fkColumnIdentifier = Identifier.toIdentifier( resultSet.getString( "FKCOLUMN_NAME" ) ); + final Identifier pkColumnIdentifier = Identifier.toIdentifier( resultSet.getString( "PKCOLUMN_NAME" ) ); + + fkBuilder.addColumnMapping( + tableInformation.getColumn( fkColumnIdentifier ), + pkTableInformation.getColumn( pkColumnIdentifier ) + ); + } + } + finally { + resultSet.close(); + } + } + catch (SQLException e) { + throw convertSQLException( + e, + "Error accessing column metadata: " + tableInformation.getName().toString() + ); + } + + final List fks = new ArrayList(); + for ( ForeignKeyBuilder fkBuilder : fkBuilders.values() ) { + ForeignKeyInformation fk = fkBuilder.build(); + fks.add( fk ); + } + return fks; + } + + private ForeignKeyBuilder generateForeignKeyBuilder(Identifier fkIdentifier) { + return new ForeignKeyBuilderImpl( fkIdentifier ); + } + + protected static interface ForeignKeyBuilder { + public ForeignKeyBuilder addColumnMapping(ColumnInformation referencing, ColumnInformation referenced); + + public ForeignKeyInformation build(); + } + + protected static class ForeignKeyBuilderImpl implements ForeignKeyBuilder { + private final Identifier fkIdentifier; + private final List columnMappingList = new ArrayList(); + + public ForeignKeyBuilderImpl(Identifier fkIdentifier) { + this.fkIdentifier = fkIdentifier; + } + + @Override + public ForeignKeyBuilder addColumnMapping(ColumnInformation referencing, ColumnInformation referenced) { + columnMappingList.add( new ForeignKeyInformationImpl.ColumnReferenceMappingImpl( referencing, referenced ) ); + return this; + } + + @Override + public ForeignKeyInformationImpl build() { + if ( columnMappingList.isEmpty() ) { + throw new SchemaManagementException( + "Attempt to resolve foreign key metadata from JDBC metadata failed to find " + + "column mappings for foreign key named [" + fkIdentifier.getText() + "]" + ); + } + return new ForeignKeyInformationImpl( fkIdentifier, columnMappingList ); + } + } + + private ObjectName extractKeyTableName(ResultSet resultSet, String prefix) throws SQLException { + final String incomingCatalogName = resultSet.getString( prefix + "TABLE_SCHEM" ); + final String incomingSchemaName = resultSet.getString( prefix + "TABLE_CATALOG" ); + final String incomingTableName = resultSet.getString( prefix + "TABLE_NAME" ); + + return new ObjectName( + Identifier.toIdentifier( incomingCatalogName ), Identifier.toIdentifier( incomingSchemaName ), + Identifier.toIdentifier( incomingTableName ) + ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/TableInformationImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/TableInformationImpl.java new file mode 100644 index 0000000000..08f57285cf --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/TableInformationImpl.java @@ -0,0 +1,150 @@ +/* + * 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.tool.schema.extract.internal; + +import java.util.HashMap; +import java.util.Map; + +import org.hibernate.metamodel.spi.relational.Identifier; +import org.hibernate.metamodel.spi.relational.ObjectName; +import org.hibernate.tool.schema.extract.spi.ColumnInformation; +import org.hibernate.tool.schema.extract.spi.ForeignKeyInformation; +import org.hibernate.tool.schema.extract.spi.IndexInformation; +import org.hibernate.tool.schema.extract.spi.SchemaMetaDataExtractor; +import org.hibernate.tool.schema.extract.spi.TableInformation; + +/** + * Provides access to information about existing schema objects (tables, sequences etc) of existing database. + * + * @author Christoph Sturm + * @author Max Rydahl Andersen + * @author Steve Ebersole + */ +public class TableInformationImpl implements TableInformation { + private final SchemaMetaDataExtractor metaDataExtractor; + private final ObjectName tableName; + private final boolean physicalTable; + private final String comment; + + private Map columns; + private Map foreignKeys; + private Map indexes; + + public TableInformationImpl( + SchemaMetaDataExtractor metaDataExtractor, + ObjectName tableName, + boolean physicalTable, + String comment) { + this.metaDataExtractor = metaDataExtractor; + this.tableName = tableName; + this.physicalTable = physicalTable; + this.comment = comment; + } + + @Override + public ObjectName getName() { + return tableName; + } + + @Override + public boolean isPhysicalTable() { + return physicalTable; + } + + @Override + public String getComment() { + return comment; + } + + @Override + public Iterable getColumns() { + return columns().values(); + } + + protected Map columns() { + if ( this.columns == null ) { + final Map columnMap = new HashMap(); + final Iterable columnInformationItr = metaDataExtractor.getColumns( this ); + for ( ColumnInformation columnInformation : columnInformationItr ) { + columnMap.put( columnInformation.getColumnIdentifier(), columnInformation ); + } + this.columns = columnMap; + } + return this.columns; + } + + @Override + public ColumnInformation getColumn(Identifier columnIdentifier) { + return columns().get( columnIdentifier ); + } + + @Override + public Iterable getForeignKeys() { + return foreignKeys().values(); + } + + protected Map foreignKeys() { + if ( foreignKeys == null ) { + final Map fkMap = new HashMap(); + final Iterable fks = metaDataExtractor.getForeignKeys( this ); + for ( ForeignKeyInformation fk : fks ) { + fkMap.put( fk.getForeignKeyIdentifier(), fk ); + } + this.foreignKeys = fkMap; + } + return foreignKeys; + } + + @Override + public ForeignKeyInformation getForeignKey(Identifier fkIdentifier) { + return foreignKeys().get( fkIdentifier ); + } + + @Override + public Iterable getIndexes() { + return indexes().values(); + } + + protected Map indexes() { + if ( indexes == null ) { + final Map indexMap = new HashMap(); + final Iterable indexes = metaDataExtractor.getIndexes( this ); + for ( IndexInformation index : indexes ) { + indexMap.put( index.getIndexIdentifier(), index ); + } + this.indexes = indexMap; + } + return indexes; + } + + @Override + public IndexInformation getIndex(Identifier indexName) { + return indexes().get( indexName ); + } + + @Override + public String toString() { + return "TableInformationImpl(" + tableName.toString() + ')'; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/TemporarySequenceInformationExtractor.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/TemporarySequenceInformationExtractor.java similarity index 66% rename from hibernate-core/src/main/java/org/hibernate/tool/schema/internal/TemporarySequenceInformationExtractor.java rename to hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/TemporarySequenceInformationExtractor.java index 0d4f638df1..2a6d5b3ed0 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/TemporarySequenceInformationExtractor.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/TemporarySequenceInformationExtractor.java @@ -21,19 +21,19 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.tool.schema.internal; +package org.hibernate.tool.schema.extract.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.engine.jdbc.env.spi.IdentifierHelper; import org.hibernate.metamodel.spi.relational.ObjectName; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; -import org.hibernate.tool.schema.spi.SequenceInformation; -import org.hibernate.tool.schema.spi.SequenceInformationExtractor; +import org.hibernate.tool.schema.extract.spi.ExtractionContext; +import org.hibernate.tool.schema.extract.spi.SequenceInformation; +import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; /** * Temporary implementation that works for H2. @@ -41,15 +41,10 @@ import org.hibernate.tool.schema.spi.SequenceInformationExtractor; * @author Steve Ebersole */ public class TemporarySequenceInformationExtractor implements SequenceInformationExtractor { - private final JdbcEnvironment jdbcEnvironment; - - public TemporarySequenceInformationExtractor(JdbcEnvironment jdbcEnvironment) { - this.jdbcEnvironment = jdbcEnvironment; - } - @Override - public Iterable extractMetadata(DatabaseMetaData databaseMetaData) throws SQLException { - Statement statement = databaseMetaData.getConnection().createStatement(); + public Iterable extractMetadata(ExtractionContext extractionContext) throws SQLException { + final IdentifierHelper identifierHelper = extractionContext.getJdbcEnvironment().getIdentifierHelper(); + final Statement statement = extractionContext.getJdbcConnection().createStatement(); try { ResultSet resultSet = statement.executeQuery( "select SEQUENCE_CATALOG, SEQUENCE_SCHEMA, SEQUENCE_NAME, INCREMENT " + @@ -61,20 +56,14 @@ public class TemporarySequenceInformationExtractor implements SequenceInformatio sequenceInformationList.add( new SequenceInformationImpl( new ObjectName( - jdbcEnvironment.getIdentifierHelper().fromMetaDataCatalogName( - resultSet.getString( - "SEQUENCE_CATALOG" - ) + identifierHelper.fromMetaDataCatalogName( + resultSet.getString( "SEQUENCE_CATALOG" ) ), - jdbcEnvironment.getIdentifierHelper().fromMetaDataSchemaName( - resultSet.getString( - "SEQUENCE_SCHEMA" - ) + identifierHelper.fromMetaDataSchemaName( + resultSet.getString( "SEQUENCE_SCHEMA" ) ), - jdbcEnvironment.getIdentifierHelper().fromMetaDataCatalogName( - resultSet.getString( - "SEQUENCE_NAME" - ) + identifierHelper.fromMetaDataCatalogName( + resultSet.getString( "SEQUENCE_NAME" ) ) ), resultSet.getInt( "INCREMENT" ) diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/package-info.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/package-info.java new file mode 100644 index 0000000000..cb7d093f23 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/package-info.java @@ -0,0 +1,28 @@ +/* + * 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.tool.schema.extract; + +/** + * Defines a model of schema information extracted from the database through JDBC. + */ diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/ColumnInformation.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ColumnInformation.java similarity index 98% rename from hibernate-core/src/main/java/org/hibernate/tool/schema/spi/ColumnInformation.java rename to hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ColumnInformation.java index df450dd5fd..a2cf37da0f 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/ColumnInformation.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ColumnInformation.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.tool.schema.spi; +package org.hibernate.tool.schema.extract.spi; import org.hibernate.TruthValue; import org.hibernate.metamodel.spi.relational.Identifier; diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/DatabaseInformation.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/DatabaseInformation.java similarity index 97% rename from hibernate-core/src/main/java/org/hibernate/tool/schema/spi/DatabaseInformation.java rename to hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/DatabaseInformation.java index 9ec824556c..0691964e55 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/DatabaseInformation.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/DatabaseInformation.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.tool.schema.spi; +package org.hibernate.tool.schema.extract.spi; import org.hibernate.metamodel.spi.relational.ObjectName; diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/DatabaseInformationBuilder.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/DatabaseInformationBuilder.java new file mode 100644 index 0000000000..4e924d39d5 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/DatabaseInformationBuilder.java @@ -0,0 +1,142 @@ +/* + * 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.tool.schema.extract.spi; + +import java.sql.Connection; +import java.sql.SQLException; + +import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.metamodel.spi.relational.Identifier; +import org.hibernate.metamodel.spi.relational.Schema; +import org.hibernate.tool.schema.extract.internal.DatabaseInformationImpl; +import org.hibernate.tool.schema.extract.internal.ExtractionContextImpl; +import org.hibernate.tool.schema.extract.internal.StandardJdbcDatabaseMetaDataExtractor; +import org.hibernate.tool.schema.extract.internal.TemporarySequenceInformationExtractor; + +/** + * Acts as the entry point into building {@link DatabaseInformation} instances. The correlation is 1-to-1 between + * DatabaseInformationBuilder and DatabaseInformation, meaning a given DatabaseInformationBuilder should only be used + * to build a single DatabaseInformation instance. + * + * @author Steve Ebersole + */ +public class DatabaseInformationBuilder { + private final DatabaseInformationImpl databaseInformation; + private final ExtractionContext extractionContext; + + private final SchemaMetaDataExtractor metaDataExtractor; + + public DatabaseInformationBuilder(JdbcEnvironment jdbcEnvironment, final Connection jdbcConnection) { + this( + jdbcEnvironment, + new JdbcConnectionAccess() { + @Override + public Connection obtainConnection() throws SQLException { + return jdbcConnection; + } + + @Override + public void releaseConnection(Connection connection) throws SQLException { + // nothing to do, we don't "own" the connection + } + + @Override + public boolean supportsAggressiveRelease() { + return false; + } + } + ); + } + + public DatabaseInformationBuilder(JdbcEnvironment jdbcEnvironment, JdbcConnectionAccess jdbcConnectionAccess) { + this.databaseInformation = new DatabaseInformationImpl(); + this.extractionContext = new ExtractionContextImpl( jdbcEnvironment, jdbcConnectionAccess, databaseInformation ); + + // todo : make this pluggable... + metaDataExtractor = new StandardJdbcDatabaseMetaDataExtractor( extractionContext ); + } + + public DatabaseInformationBuilder prepareAll() { + return prepare( SchemaMetaDataExtractor.ALL_CATALOGS_FILTER, SchemaMetaDataExtractor.ALL_SCHEMAS_FILTER ); + } + + public DatabaseInformationBuilder prepareCatalogAndSchema(Schema.Name schemaName) { + final IdentifierHelper identifierHelper = extractionContext.getJdbcEnvironment().getIdentifierHelper(); + return prepare( + identifierHelper.toMetaDataCatalogName( schemaName.getCatalog() ), + identifierHelper.toMetaDataSchemaName( schemaName.getSchema() ) + ); + } + + public DatabaseInformationBuilder prepareCatalog(Identifier catalog) { + final IdentifierHelper identifierHelper = extractionContext.getJdbcEnvironment().getIdentifierHelper(); + return prepare( + identifierHelper.toMetaDataCatalogName( catalog ), + SchemaMetaDataExtractor.ALL_SCHEMAS_FILTER + ); + } + + public DatabaseInformationBuilder prepareSchema(Identifier schema) { + final IdentifierHelper identifierHelper = extractionContext.getJdbcEnvironment().getIdentifierHelper(); + return prepare( + SchemaMetaDataExtractor.ALL_CATALOGS_FILTER, + identifierHelper.toMetaDataSchemaName( schema ) + ); + } + + private DatabaseInformationBuilder prepare(String catalog, String schema) { + // todo : apply filtering + + for ( TableInformation tableInformation : metaDataExtractor.getTables( catalog, schema ) ) { + databaseInformation.registerTableInformation( tableInformation ); + } + + final Iterable sequences = extractSequences(); + if ( sequences != null ) { + for ( SequenceInformation sequenceInformation : sequences ) { + databaseInformation.registerSequenceInformation( sequenceInformation ); + } + } + + return this; + } + + private Iterable extractSequences() { + // todo : temporary impl!!! + final TemporarySequenceInformationExtractor seqExtractor = new TemporarySequenceInformationExtractor(); + try { + return seqExtractor.extractMetadata( extractionContext ); + } + catch (SQLException e) { + throw extractionContext.getJdbcEnvironment().getSqlExceptionHelper().convert( e, "Unable to access sequence information" ); + } + } + + public DatabaseInformation build() { + return databaseInformation; + } +} + diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java new file mode 100644 index 0000000000..a339d239d4 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java @@ -0,0 +1,50 @@ +/* + * 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.tool.schema.extract.spi; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; + +import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.metamodel.spi.relational.ObjectName; + +/** + * Defines a context for performing extraction including providing access to information about ongoing extraction as + * well as to delegates needed in performing extraction. + * + * @author Steve Ebersole + */ +public interface ExtractionContext { + public JdbcEnvironment getJdbcEnvironment(); + public Connection getJdbcConnection(); + public DatabaseMetaData getJdbcDatabaseMetaData(); + + public static interface RegisteredObjectAccess { + public TableInformation locateRegisteredTableInformation(ObjectName tableName); + public SequenceInformation locateRegisteredSequenceInformation(ObjectName sequenceName); + } + + public RegisteredObjectAccess getRegisteredObjectAccess(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/ForeignKeyInformation.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ForeignKeyInformation.java similarity index 87% rename from hibernate-core/src/main/java/org/hibernate/tool/schema/spi/ForeignKeyInformation.java rename to hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ForeignKeyInformation.java index 706269fb1c..7c520489c6 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/ForeignKeyInformation.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ForeignKeyInformation.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.tool.schema.spi; +package org.hibernate.tool.schema.extract.spi; import java.util.List; @@ -39,11 +39,11 @@ public interface ForeignKeyInformation { public Identifier getForeignKeyIdentifier(); /** - * Get the list of column mappings that define the reference. + * Get the column mappings that define the reference. Returned in sequential order. * - * @return The mapping list + * @return The sequential column reference mappings. */ - public List getColumnReferenceMappingList(); + public Iterable getColumnReferenceMappings(); public static interface ColumnReferenceMapping { /** diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/IndexInformation.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/IndexInformation.java similarity index 97% rename from hibernate-core/src/main/java/org/hibernate/tool/schema/spi/IndexInformation.java rename to hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/IndexInformation.java index 19518e6a6d..6d6809bf01 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/IndexInformation.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/IndexInformation.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.tool.schema.spi; +package org.hibernate.tool.schema.extract.spi; import java.util.List; diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/PrimaryKeyInformation.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/PrimaryKeyInformation.java new file mode 100644 index 0000000000..4ece860e21 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/PrimaryKeyInformation.java @@ -0,0 +1,42 @@ +/* + * 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.tool.schema.extract.spi; + +import org.hibernate.metamodel.spi.relational.Identifier; + +/** + * Provides access to information about existing primary key for a table + * + * @author Steve Ebersole + */ +public interface PrimaryKeyInformation { + /** + * Obtain the identifier for this PK. + * + * @return The PK identifier. + */ + public Identifier getPrimaryKeyIdentifier(); + + public Iterable getColumns(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/SchemaMetaDataExtractor.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/SchemaMetaDataExtractor.java new file mode 100644 index 0000000000..dbe3b7395a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/SchemaMetaDataExtractor.java @@ -0,0 +1,107 @@ +/* + * 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.tool.schema.extract.spi; + +import java.util.Map; + +import org.hibernate.metamodel.spi.relational.Identifier; +import org.hibernate.tool.schema.extract.internal.ForeignKeyInformationImpl; +import org.hibernate.tool.schema.extract.internal.IndexInformationImpl; +import org.hibernate.tool.schema.extract.internal.TableInformationImpl; + +/** + * Contract for extracting information about objects in the database schema(s). To an extent, the contract largely + * mirrors parts of the JDBC {@link java.sql.DatabaseMetaData} contract. THe intention is to insulate callers + * from {@link java.sql.DatabaseMetaData} since on many databases there are better ways to get information from + * the meta schema. + * + * NOTE : Concepts here taken largely from the {@code MetaDataDialect} class Hibernate Tools. + * + * @author Steve Ebersole + */ +public interface SchemaMetaDataExtractor { + public static final String ALL_CATALOGS_FILTER = null; + public static final String SANS_CATALOG_FILTER = ""; + + public static final String ALL_SCHEMAS_FILTER = null; + public static final String SANS_SCHEMA_FILTER = ""; + + /** + * Return information about all matching tables + * + * @param catalogFilter Filter to be applied for the catalog to which tables belong. Can be either the + * name of the catalog to match or one of 2 special values:
    + *
  1. + * {@code null} ({@link #ALL_CATALOGS_FILTER}) - Indicates that tables from all catalogs should be returned + *
  2. + *
  3. + * {@code ""} (empty String) ({@link #SANS_CATALOG_FILTER}) - Indicates that only tables without a catalog + * should be returned + *
  4. + *
+ * @param schemaFilter Filter to be applied for the schema to which tables belong. Can be either the + * name of the schema to match or one of 2 special values:
    + *
  1. + * {@code null} ({@link #ALL_SCHEMAS_FILTER}) - Indicates that tables from all schemas should be returned + *
  2. + *
  3. + * {@code ""} (empty String) ({@link #SANS_SCHEMA_FILTER}) - Indicates that only tables without a schema + * should be returned + *
  4. + *
+ * + * @return iterator with map elements that has "TABLE_NAME", "TABLE_SCHEMA", "TABLE_CAT", "TABLE_TYPE" keys. + */ + public Iterable getTables(String catalogFilter, String schemaFilter); + + /** + * Return information about columns for the given table. Typically called from the TableInformation itself + * as part of on-demand initialization of its state. + * + * @param tableInformation The table for which to locate columns + * + * @return The extracted column information + */ + public Iterable getColumns(TableInformation tableInformation); + + /** + * Extract information about indexes defined against the given table. Typically called from the TableInformation + * itself as part of on-demand initialization of its state. + * + * @param tableInformation The table for which to locate indexes + * + * @return The extracted index information + */ + public Iterable getIndexes(TableInformation tableInformation); + + /** + * Extract information about foreign keys defined on the given table (targeting or point-at other tables). + * Typically called from the TableInformation itself as part of on-demand initialization of its state. + * + * @param tableInformation The table for which to locate foreign-keys + * + * @return The extracted foreign-key information + */ + public Iterable getForeignKeys(TableInformation tableInformation); +} diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SequenceInformation.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/SequenceInformation.java similarity index 97% rename from hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SequenceInformation.java rename to hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/SequenceInformation.java index 258fa32368..56b329aa45 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SequenceInformation.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/SequenceInformation.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.tool.schema.spi; +package org.hibernate.tool.schema.extract.spi; import org.hibernate.metamodel.spi.relational.ObjectName; diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SequenceInformationExtractor.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/SequenceInformationExtractor.java similarity index 86% rename from hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SequenceInformationExtractor.java rename to hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/SequenceInformationExtractor.java index fc33423f2a..f63edd1243 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SequenceInformationExtractor.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/SequenceInformationExtractor.java @@ -21,9 +21,8 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.tool.schema.spi; +package org.hibernate.tool.schema.extract.spi; -import java.sql.DatabaseMetaData; import java.sql.SQLException; /** @@ -36,12 +35,12 @@ public interface SequenceInformationExtractor { /** * Get the information about sequences. * - * @param databaseMetaData The JDBC DatabaseMetadata + * @param extractionContext Access to resources needed to perform the extraction * * @return The extracted information about existing sequences. * * @throws SQLException Don't bother handling SQLExceptions (unless you want to), we will deal with them in the * caller. */ - public Iterable extractMetadata(DatabaseMetaData databaseMetaData) throws SQLException; + public Iterable extractMetadata(ExtractionContext extractionContext) throws SQLException; } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/TableInformation.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/TableInformation.java similarity index 66% rename from hibernate-core/src/main/java/org/hibernate/tool/schema/spi/TableInformation.java rename to hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/TableInformation.java index 4ec2c806dd..f566082181 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/TableInformation.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/TableInformation.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.tool.schema.spi; +package org.hibernate.tool.schema.extract.spi; import org.hibernate.metamodel.spi.relational.Identifier; import org.hibernate.metamodel.spi.relational.ObjectName; @@ -41,6 +41,27 @@ public interface TableInformation { */ public ObjectName getName(); + /** + * Does this information describe a physical table as opposed to a view, etc? + * + * @return {@code true} if this is a physical table; {@code false} otherwise. + */ + public boolean isPhysicalTable(); + + /** + * Get the comments/remarks defined for the table. + * + * @return The table comments + */ + public String getComment(); + + /** + * Get an iterable over all of the table's columns. + * + * @return All of the table's columns + */ + public Iterable getColumns(); + /** * Retrieve the named ColumnInformation * @@ -48,7 +69,14 @@ public interface TableInformation { * * @return The matching column information. May return {@code null} */ - public ColumnInformation getColumnInformation(Identifier columnIdentifier); + public ColumnInformation getColumn(Identifier columnIdentifier); + + /** + * Obtain an iterable over all the table's defined foreign keys. + * + * @return The iterable. + */ + public Iterable getForeignKeys(); /** * Retrieve the named ForeignKeyInformation @@ -57,17 +85,17 @@ public interface TableInformation { * * @return The matching foreign key information. May return {@code null} */ - public ForeignKeyInformation getForeignKeyInformation(Identifier keyName); + public ForeignKeyInformation getForeignKey(Identifier keyName); /** - * Obtain an iterable over all the table's defined foreign keys. + * Obtain an iterable over all the table's defined indexes. * * @return The iterable. */ - public Iterable getForeignKeyInformations(); + public Iterable getIndexes(); /** - * todo : create an IndexInformation... + * Obtain an iterable over all the table's defined indexes */ - public IndexInformation getIndexInformation(Identifier indexName); + public IndexInformation getIndex(Identifier indexName); } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/DatabaseInformationImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/DatabaseInformationImpl.java deleted file mode 100644 index 3c7b00a311..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/DatabaseInformationImpl.java +++ /dev/null @@ -1,418 +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.tool.schema.internal; - -import java.sql.DatabaseMetaData; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.Map; -import java.util.StringTokenizer; - -import org.hibernate.TruthValue; -import org.hibernate.metamodel.spi.relational.Identifier; -import org.hibernate.metamodel.spi.relational.ObjectName; -import org.hibernate.metamodel.spi.relational.Schema; -import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; -import org.hibernate.tool.schema.spi.ColumnInformation; -import org.hibernate.tool.schema.spi.DatabaseInformation; -import org.hibernate.tool.schema.spi.SchemaManagementException; -import org.hibernate.tool.schema.spi.SequenceInformation; -import org.hibernate.tool.schema.spi.TableInformation; - -/** - * @author Steve Ebersole - */ -public class DatabaseInformationImpl implements DatabaseInformation { - private final JdbcEnvironment jdbcEnvironment; - private final DatabaseMetaData databaseMetaData; - - private final Map tables = new HashMap(); - private final Map sequences; - - public static Builder builder(JdbcEnvironment jdbcEnvironment, DatabaseMetaData databaseMetaData) { - try { - return new BuilderImpl( jdbcEnvironment, databaseMetaData ); - } - catch (SQLException e) { - throw jdbcEnvironment.getSqlExceptionHelper().convert( e, "Error accessing java.sql.DatabaseMetaData" ); - } - } - - private DatabaseInformationImpl(JdbcEnvironment jdbcEnvironment, DatabaseMetaData databaseMetaData) throws SQLException { - this.jdbcEnvironment = jdbcEnvironment; - this.databaseMetaData = databaseMetaData; - this.sequences = loadSequenceMetadataMap(); - } - - public IdentifierHelper identifierHelper() { - return jdbcEnvironment.getIdentifierHelper(); - } - - private static final String[] TABLE_TYPES = new String[] { "TABLE", "VIEW" }; - - private void loadTableMetadata(ResultSet resultSet) throws SQLException { - while ( resultSet.next() ) { - final Identifier catalogIdentifier = identifierHelper().fromMetaDataCatalogName( - resultSet.getString( - "TABLE_CAT" - ) - ); - final Identifier schemaIdentifier = identifierHelper().fromMetaDataSchemaName( - resultSet.getString( - "TABLE_SCHEM" - ) - ); - final Identifier tableIdentifier = identifierHelper().fromMetaDataObjectName( - resultSet.getString( - "TABLE_NAME" - ) - ); - final ObjectName tableName = new ObjectName( catalogIdentifier, schemaIdentifier, tableIdentifier ); - // make sure it does not already exist... - TableInformationImpl tableMetadata = tables.get( tableName ); - if ( tableMetadata != null ) { - throw new IllegalStateException( "Table already found on parsing database metadata [" + tableName + "]" ); - } - - tableMetadata = new TableInformationImpl( this, tableName ); - tables.put( toMapKey( tableName ), tableMetadata ); - } - } - - private Map loadSequenceMetadataMap() throws SQLException { - Map sequences = new HashMap(); - // todo : temporary impl! - final Iterable sequenceMetadatas = - new TemporarySequenceInformationExtractor( jdbcEnvironment ).extractMetadata( databaseMetaData ); - if ( sequenceMetadatas != null ) { - for ( SequenceInformation sequenceInformation :sequenceMetadatas ) { - sequences.put( toMapKey( sequenceInformation.getSequenceName() ), sequenceInformation ); - } - } - return sequences; - } - - @Override - public TableInformation getTableInformation(ObjectName 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 - public SequenceInformation getSequenceInformation(ObjectName sequenceName) { - return sequences.get( toMapKey( sequenceName ) ); - } - - public Map getColumnMetadata(TableInformation tableInformation) { - final Map results = new HashMap(); - - try { - ResultSet resultSet = databaseMetaData.getColumns( - identifierHelper().toMetaDataCatalogName( tableInformation.getName().getCatalog() ), - identifierHelper().toMetaDataSchemaName( tableInformation.getName().getSchema() ), - identifierHelper().toMetaDataObjectName( tableInformation.getName().getName() ), - "%" - ); - - try { - while ( resultSet.next() ) { - final String columnName = resultSet.getString( "COLUMN_NAME" ); - if ( columnName == null ) { - continue; - } - - final Identifier columnIdentifier = Identifier.toIdentifier( columnName ); - if ( results.containsKey( columnIdentifier ) ) { - continue; - } - - final ColumnInformationImpl meta = new ColumnInformationImpl( - tableInformation, - columnIdentifier, - resultSet.getInt( "DATA_TYPE" ), - new StringTokenizer( resultSet.getString( "TYPE_NAME" ), "() " ).nextToken(), - resultSet.getInt( "COLUMN_SIZE" ), - resultSet.getInt("DECIMAL_DIGITS"), - interpretTruthValue( resultSet.getString( "IS_NULLABLE" ) ) - ); - results.put( columnIdentifier, meta ); - } - } - finally { - resultSet.close(); - } - } - catch (SQLException e) { - throw jdbcEnvironment.getSqlExceptionHelper().convert( - e, - "Error accessing column metadata: " + tableInformation.getName().toString() - ); - } - - return results; - } - - public Map getIndexInformation(TableInformationImpl tableInformation) { - final Map builders = new HashMap(); - - try { - ResultSet resultSet = databaseMetaData.getIndexInfo( - identifierHelper().toMetaDataCatalogName( tableInformation.getName().getCatalog() ), - identifierHelper().toMetaDataSchemaName( tableInformation.getName().getSchema() ), - identifierHelper().toMetaDataObjectName( tableInformation.getName().getName() ), - false, // don't limit to just unique - true // do require up-to-date results - ); - - try { - while ( resultSet.next() ) { - if ( resultSet.getShort("TYPE") == DatabaseMetaData.tableIndexStatistic ) { - continue; - } - - final Identifier indexIdentifier = Identifier.toIdentifier( resultSet.getString( "INDEX_NAME" ) ); - IndexInformationImpl.Builder builder = builders.get( indexIdentifier ); - if ( builder == null ) { - builder = IndexInformationImpl.builder( indexIdentifier ); - builders.put( indexIdentifier, builder ); - } - - final Identifier columnIdentifier = Identifier.toIdentifier( resultSet.getString( "COLUMN_NAME" ) ); - final ColumnInformation columnInformation = tableInformation.getColumnInformation( columnIdentifier ); - if ( columnInformation == null ) { - throw new SchemaManagementException( - "Could not locate column information using identifier [" + columnIdentifier.getText() + "]" - ); - } - builder.addColumn( columnInformation ); - } - } - finally { - resultSet.close(); - } - } - catch (SQLException e) { - throw jdbcEnvironment.getSqlExceptionHelper().convert( - e, - "Error accessing index information: " + tableInformation.getName().toString() - ); - } - - final Map indexes = new HashMap(); - for ( IndexInformationImpl.Builder builder : builders.values() ) { - IndexInformationImpl index = builder.build(); - indexes.put( index.getIndexIdentifier(), index ); - } - return indexes; - } - - public Map getForeignKeyMetadata(TableInformationImpl tableMetadata) { - final Map fkBuilders - = new HashMap(); - - try { - ResultSet resultSet = databaseMetaData.getImportedKeys( - identifierHelper().toMetaDataCatalogName( tableMetadata.getName().getCatalog() ), - identifierHelper().toMetaDataSchemaName( tableMetadata.getName().getSchema() ), - identifierHelper().toMetaDataObjectName( tableMetadata.getName().getName() ) - ); - - // todo : need to account for getCrossReference() as well... - - try { - while ( resultSet.next() ) { - // IMPL NOTE : intentionally build the builder early! - final Identifier fkIdentifier = Identifier.toIdentifier( resultSet.getString( "FK_NAME" ) ); - ForeignKeyInformationImpl.Builder fkBuilder = fkBuilders.get( fkIdentifier ); - if ( fkBuilder == null ) { - fkBuilder = ForeignKeyInformationImpl.builder( fkIdentifier ); - fkBuilders.put( fkIdentifier, fkBuilder ); - } - - final ObjectName incomingPkTableName = extractKeyTableName( resultSet, "PK" ); - - final TableInformationImpl pkTableMetadata = tables.get( incomingPkTableName ); - if ( pkTableMetadata == null ) { - // the assumption here is that we have not seen this table already based on fully-qualified name - // during previous step of building all table metadata so most likely this is - // not a match based solely on schema/catalog and that another row in this result set - // should match. - continue; - } - - final Identifier fkColumnIdentifier = Identifier.toIdentifier( resultSet.getString( "FKCOLUMN_NAME" ) ); - final Identifier pkColumnIdentifier = Identifier.toIdentifier( resultSet.getString( "PKCOLUMN_NAME" ) ); - - fkBuilder.addColumnMapping( - tableMetadata.getColumnInformation( fkColumnIdentifier ), - pkTableMetadata.getColumnInformation( pkColumnIdentifier ) - ); - } - } - finally { - resultSet.close(); - } - } - catch (SQLException e) { - throw jdbcEnvironment.getSqlExceptionHelper().convert( - e, - "Error accessing column metadata: " + tableMetadata.getName().toString() - ); - } - - final Map fks = new HashMap(); - for ( ForeignKeyInformationImpl.Builder fkBuilder : fkBuilders.values() ) { - ForeignKeyInformationImpl fk = fkBuilder.build(); - fks.put( fk.getForeignKeyIdentifier(), fk ); - } - return fks; - } - - private ObjectName extractKeyTableName(ResultSet resultSet, String prefix) throws SQLException { - final String incomingCatalogName = resultSet.getString( prefix + "TABLE_SCHEM" ); - final String incomingSchemaName = resultSet.getString( prefix + "TABLE_CATALOG" ); - final String incomingTableName = resultSet.getString( prefix + "TABLE_NAME" ); - - return new ObjectName( - Identifier.toIdentifier( incomingCatalogName ), Identifier.toIdentifier( incomingSchemaName ), - Identifier.toIdentifier( incomingTableName ) - ); - } - - private TruthValue interpretTruthValue(String nullable) { - if ( "yes".equalsIgnoreCase( nullable ) ) { - return TruthValue.TRUE; - } - else if ( "no".equalsIgnoreCase( nullable ) ) { - return TruthValue.FALSE; - } - return TruthValue.UNKNOWN; - } - - public static interface Builder { - public Builder prepareAll(); - public Builder prepareCatalogAndSchema(Schema.Name schemaName); - public Builder prepareCatalog(Identifier catalog); - public Builder prepareSchema(Identifier schema); - public DatabaseInformation build(); - } - - private static class BuilderImpl implements Builder { - private final DatabaseInformationImpl it; - - public BuilderImpl(JdbcEnvironment jdbcEnvironment, DatabaseMetaData databaseMetaData) throws SQLException { - it = new DatabaseInformationImpl( jdbcEnvironment, databaseMetaData ); - } - - @Override - public Builder prepareAll() { - prepare( null, null ); - return this; - } - - private void prepare(String catalog, String schema) { - try { - ResultSet resultSet = it.databaseMetaData.getTables( - catalog, - schema, - null, - TABLE_TYPES - ); - - try { - it.loadTableMetadata( resultSet ); - } - finally { - try { - resultSet.close(); - } - catch (SQLException ignore) { - } - } - } - catch (SQLException sqlException) { - throw it.jdbcEnvironment.getSqlExceptionHelper().convert( sqlException, "Error accessing table metadata" ); - } - - } - - @Override - public Builder prepareCatalogAndSchema(Schema.Name schemaName) { - prepare( - it.identifierHelper().toMetaDataCatalogName( schemaName.getCatalog() ), - it.identifierHelper().toMetaDataSchemaName( schemaName.getSchema() ) - ); - return this; - } - - @Override - public Builder prepareCatalog(Identifier catalog) { - prepare( - it.identifierHelper().toMetaDataCatalogName( catalog ), - null - ); - return this; - } - - @Override - public Builder prepareSchema(Identifier schema) { - prepare( - null, - it.identifierHelper().toMetaDataSchemaName( schema ) - ); - return this; - } - - @Override - public DatabaseInformation build() { - return it; - } - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaMigratorImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaMigratorImpl.java index 60e8438ea0..7ec86579a1 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaMigratorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaMigratorImpl.java @@ -36,12 +36,12 @@ import org.hibernate.metamodel.spi.relational.Schema; import org.hibernate.metamodel.spi.relational.Sequence; import org.hibernate.metamodel.spi.relational.Table; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; -import org.hibernate.tool.schema.spi.DatabaseInformation; -import org.hibernate.tool.schema.spi.ForeignKeyInformation; +import org.hibernate.tool.schema.extract.spi.DatabaseInformation; +import org.hibernate.tool.schema.extract.spi.ForeignKeyInformation; import org.hibernate.tool.schema.spi.SchemaManagementException; import org.hibernate.tool.schema.spi.SchemaMigrator; -import org.hibernate.tool.schema.spi.SequenceInformation; -import org.hibernate.tool.schema.spi.TableInformation; +import org.hibernate.tool.schema.extract.spi.SequenceInformation; +import org.hibernate.tool.schema.extract.spi.TableInformation; import org.hibernate.tool.schema.spi.Target; diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaValidatorImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaValidatorImpl.java index 03f50367ad..93dd2121a2 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaValidatorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaValidatorImpl.java @@ -29,12 +29,12 @@ import org.hibernate.metamodel.spi.relational.Schema; import org.hibernate.metamodel.spi.relational.Sequence; import org.hibernate.metamodel.spi.relational.Table; import org.hibernate.metamodel.spi.relational.Value; -import org.hibernate.tool.schema.spi.ColumnInformation; -import org.hibernate.tool.schema.spi.DatabaseInformation; +import org.hibernate.tool.schema.extract.spi.ColumnInformation; +import org.hibernate.tool.schema.extract.spi.DatabaseInformation; import org.hibernate.tool.schema.spi.SchemaManagementException; import org.hibernate.tool.schema.spi.SchemaValidator; -import org.hibernate.tool.schema.spi.SequenceInformation; -import org.hibernate.tool.schema.spi.TableInformation; +import org.hibernate.tool.schema.extract.spi.SequenceInformation; +import org.hibernate.tool.schema.extract.spi.TableInformation; /** * @author Steve Ebersole @@ -74,7 +74,7 @@ public class SchemaValidatorImpl implements SchemaValidator { for ( Value value : table.values() ) { if ( Column.class.isInstance( value ) ) { final Column column = (Column) value; - final ColumnInformation columnInformation = tableInformation.getColumnInformation( column.getColumnName() ); + final ColumnInformation columnInformation = tableInformation.getColumn( column.getColumnName() ); if ( columnInformation == null ) { throw new SchemaManagementException( String.format( diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/TableInformationImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/TableInformationImpl.java deleted file mode 100644 index b8c3eb6091..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/TableInformationImpl.java +++ /dev/null @@ -1,100 +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.tool.schema.internal; - -import java.util.Map; - -import org.hibernate.metamodel.spi.relational.Identifier; -import org.hibernate.metamodel.spi.relational.ObjectName; -import org.hibernate.tool.schema.spi.ColumnInformation; -import org.hibernate.tool.schema.spi.ForeignKeyInformation; -import org.hibernate.tool.schema.spi.IndexInformation; -import org.hibernate.tool.schema.spi.TableInformation; - -/** - * Provides access to information about existing schema objects (tables, sequences etc) of existing database. - * - * @author Christoph Sturm - * @author Max Rydahl Andersen - * @author Steve Ebersole - */ -public class TableInformationImpl implements TableInformation { - private final DatabaseInformationImpl database; - private final ObjectName tableName; - private final Map columns; - - private Map foreignKeys; - private Map indexes; - - public TableInformationImpl(DatabaseInformationImpl database, ObjectName tableName) { - this.database = database; - this.tableName = tableName; - this.columns = database.getColumnMetadata( this ); - } - - @Override - public ObjectName getName() { - return tableName; - } - - @Override - public ColumnInformation getColumnInformation(Identifier columnIdentifier) { - return columns.get( columnIdentifier ); - } - - protected Map foreignKeys() { - if ( foreignKeys == null ) { - foreignKeys = database.getForeignKeyMetadata( this ); - } - return foreignKeys; - } - - @Override - public ForeignKeyInformation getForeignKeyInformation(Identifier fkIdentifier) { - return foreignKeys().get( fkIdentifier ); - } - - @Override - @SuppressWarnings("unchecked") - public Iterable getForeignKeyInformations() { - return foreignKeys().values(); - } - - @Override - public String toString() { - return "TableInformationImpl(" + tableName.toString() + ')'; - } - - protected Map indexes() { - if ( indexes == null ) { - indexes = database.getIndexInformation( this ); - } - return indexes; - } - - @Override - public IndexInformation getIndexInformation(Identifier indexName) { - return indexes().get( indexName ); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaMigrator.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaMigrator.java index 34c3988896..dc34db162d 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaMigrator.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaMigrator.java @@ -26,6 +26,7 @@ package org.hibernate.tool.schema.spi; import java.util.List; import org.hibernate.metamodel.spi.relational.Database; +import org.hibernate.tool.schema.extract.spi.DatabaseInformation; /** * Service delegate for handling schema migration. diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaValidator.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaValidator.java index d86de8b9dc..fb45ce754a 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaValidator.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaValidator.java @@ -24,6 +24,7 @@ package org.hibernate.tool.schema.spi; import org.hibernate.metamodel.spi.relational.Database; +import org.hibernate.tool.schema.extract.spi.DatabaseInformation; /** * Service delegate for handling schema validations diff --git a/hibernate-core/src/test/java/org/hibernate/test/service/schema/internal/ExistingDatabaseMetaDataImplTest.java b/hibernate-core/src/test/java/org/hibernate/test/service/schema/internal/ExistingDatabaseMetaDataImplTest.java index ed1d3db3bf..2bf92e4696 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/service/schema/internal/ExistingDatabaseMetaDataImplTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/service/schema/internal/ExistingDatabaseMetaDataImplTest.java @@ -28,19 +28,20 @@ import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.Environment; +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentImpl; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.metamodel.spi.relational.ObjectName; +import org.hibernate.service.spi.ServiceRegistryImplementor; +import org.hibernate.tool.schema.extract.spi.DatabaseInformation; +import org.hibernate.tool.schema.extract.spi.DatabaseInformationBuilder; + import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.hibernate.cfg.Environment; -import org.hibernate.dialect.Dialect; -import org.hibernate.metamodel.spi.relational.ObjectName; -import org.hibernate.service.ServiceRegistryBuilder; -import org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentImpl; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; -import org.hibernate.tool.schema.internal.DatabaseInformationImpl; -import org.hibernate.tool.schema.spi.DatabaseInformation; -import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.testing.junit4.BaseUnitTestCase; import static org.junit.Assert.assertNotNull; @@ -56,7 +57,7 @@ public class ExistingDatabaseMetaDataImplTest extends BaseUnitTestCase { @Before public void prepare() throws SQLException { Properties props = Environment.getProperties(); - serviceRegistry = (ServiceRegistryImplementor) new ServiceRegistryBuilder().applySettings( props ).build(); + serviceRegistry = (ServiceRegistryImplementor) new StandardServiceRegistryBuilder().applySettings( props ).build(); connection = DriverManager.getConnection( props.getProperty( Environment.URL ), props.getProperty( Environment.USER ), @@ -83,14 +84,15 @@ public class ExistingDatabaseMetaDataImplTest extends BaseUnitTestCase { } } if ( serviceRegistry != null ) { - ServiceRegistryBuilder.destroy( serviceRegistry ); + StandardServiceRegistryBuilder.destroy( serviceRegistry ); } } @Test public void testGetTableMetadata() throws Exception { - DatabaseInformation databaseMetaData = - DatabaseInformationImpl.builder( jdbcEnvironment, connection.getMetaData() ).prepareAll().build(); + DatabaseInformation databaseMetaData = new DatabaseInformationBuilder( jdbcEnvironment, connection ) + .prepareAll() + .build(); ObjectName name = new ObjectName( null, null, "t1" ); assertNotNull( databaseMetaData.getTableInformation( name ) );