HHH-10133 - CatalogSeparator of dialect metadata not used in runtime, just in schema tool

This commit is contained in:
Steve Ebersole 2015-09-25 17:46:19 -05:00
parent 7354c7bfc3
commit 3571218183
9 changed files with 470 additions and 113 deletions

View File

@ -14,6 +14,11 @@ import org.hibernate.boot.model.naming.Identifier;
* <li>{@link java.sql.DatabaseMetaData#isCatalogAtStart}</li>
* <li>{@link java.sql.DatabaseMetaData#getCatalogSeparator()}</li>
* </ol>
* <p/>
* Also, be careful about the usage of {@link #render}. If the intention is get get the name
* as used in the database, the {@link org.hibernate.engine.jdbc.env.spi.JdbcEnvironment} ->
* {@link org.hibernate.engine.jdbc.env.spi.QualifiedObjectNameFormatter#format} should be
* used instead.
*
* @author Steve Ebersole
*/
@ -22,5 +27,14 @@ public interface QualifiedName {
Identifier getSchemaName();
Identifier getObjectName();
/**
* Returns a String-form of the qualified name.
* <p/>
* Depending on intention, may not be appropriate. May want
* {@link org.hibernate.engine.jdbc.env.spi.QualifiedObjectNameFormatter#format}
* instead. See {@link org.hibernate.engine.jdbc.env.spi.JdbcEnvironment#getQualifiedObjectNameFormatter}
*
* @return The string form
*/
String render();
}

View File

@ -23,6 +23,7 @@ import org.hibernate.boot.model.relational.InitCommand;
import org.hibernate.boot.model.relational.Namespace;
import org.hibernate.boot.model.relational.QualifiedTableName;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.env.spi.QualifiedObjectNameFormatter;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.tool.hbm2ddl.ColumnMetadata;
@ -106,6 +107,11 @@ public class Table implements RelationalModel, Serializable, Exportable {
this.isAbstract = isAbstract;
}
/**
* @deprecated Should use {@link QualifiedObjectNameFormatter#format} on QualifiedObjectNameFormatter
* obtained from {@link org.hibernate.engine.jdbc.env.spi.JdbcEnvironment}
*/
@Deprecated
public String getQualifiedName(Dialect dialect, String defaultCatalog, String defaultSchema) {
if ( subselect != null ) {
return "( " + subselect + " )";
@ -120,6 +126,11 @@ public class Table implements RelationalModel, Serializable, Exportable {
return qualify( usedCatalog, usedSchema, quotedName );
}
/**
* @deprecated Should use {@link QualifiedObjectNameFormatter#format} on QualifiedObjectNameFormatter
* obtained from {@link org.hibernate.engine.jdbc.env.spi.JdbcEnvironment}
*/
@Deprecated
public static String qualify(String catalog, String schema, String table) {
StringBuilder qualifiedName = new StringBuilder();
if ( catalog != null ) {

View File

@ -22,6 +22,7 @@ import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.QueryException;
import org.hibernate.TransientObjectException;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
import org.hibernate.cache.spi.entry.CacheEntryStructure;
@ -31,6 +32,7 @@ import org.hibernate.cache.spi.entry.UnstructuredCacheEntry;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
@ -230,9 +232,12 @@ public abstract class AbstractCollectionPersister
CollectionRegionAccessStrategy cacheAccessStrategy,
PersisterCreationContext creationContext) throws MappingException, CacheException {
final Database database = creationContext.getMetadata().getDatabase();
final JdbcEnvironment jdbcEnvironment = database.getJdbcEnvironment();
this.factory = creationContext.getSessionFactory();
this.cacheAccessStrategy = cacheAccessStrategy;
if ( factory.getSettings().isStructuredCacheEntriesEnabled() ) {
if ( factory.getSessionFactoryOptions().isStructuredCacheEntriesEnabled() ) {
cacheEntryStructure = collectionBinding.isMap()
? StructuredMapCacheEntry.INSTANCE
: StructuredCollectionCacheEntry.INSTANCE;
@ -260,11 +265,7 @@ public abstract class AbstractCollectionPersister
isArray = collectionBinding.isArray();
subselectLoadable = collectionBinding.isSubselectLoadable();
qualifiedTableName = table.getQualifiedName(
dialect,
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
);
qualifiedTableName = determineTableName( table, jdbcEnvironment );
int spacesSize = 1 + collectionBinding.getSynchronizedTables().size();
spaces = new String[spacesSize];
@ -284,7 +285,7 @@ public abstract class AbstractCollectionPersister
int batch = collectionBinding.getBatchSize();
if ( batch == -1 ) {
batch = factory.getSettings().getDefaultBatchFetchSize();
batch = factory.getSessionFactoryOptions().getDefaultBatchFetchSize();
}
batchSize = batch;
@ -585,6 +586,17 @@ public abstract class AbstractCollectionPersister
initCollectionPropertyMap();
}
protected String determineTableName(Table table, JdbcEnvironment jdbcEnvironment) {
if ( table.getSubselect() != null ) {
return "( " + table.getSubselect() + " )";
}
return jdbcEnvironment.getQualifiedObjectNameFormatter().format(
table.getQualifiedTableName(),
jdbcEnvironment.getDialect()
);
}
private class ColumnMapperImpl implements ColumnMapper {
@Override
public SqlValueReference[] map(String reference) {

View File

@ -54,6 +54,7 @@ import org.hibernate.engine.internal.MutableEntityEntryFactory;
import org.hibernate.engine.internal.StatefulPersistenceContext;
import org.hibernate.engine.internal.Versioning;
import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.spi.CachedNaturalIdValueSource;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.CascadingActions;
@ -92,6 +93,7 @@ import org.hibernate.mapping.Component;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.Table;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.spi.PersisterCreationContext;
@ -5112,6 +5114,17 @@ public abstract class AbstractEntityPersister
return 0;
}
protected String determineTableName(Table table, JdbcEnvironment jdbcEnvironment) {
if ( table.getSubselect() != null ) {
return "( " + table.getSubselect() + " )";
}
return jdbcEnvironment.getQualifiedObjectNameFormatter().format(
table.getQualifiedTableName(),
jdbcEnvironment.getDialect()
);
}
@Override
public EntityEntryFactory getEntityEntryFactory() {
return this.entityEntryFactory;

View File

@ -18,9 +18,11 @@ import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.QueryException;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.DynamicFilterAliasGenerator;
@ -133,6 +135,8 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
super( persistentClass, cacheAccessStrategy, naturalIdRegionAccessStrategy, creationContext );
final SessionFactoryImplementor factory = creationContext.getSessionFactory();
final Database database = creationContext.getMetadata().getDatabase();
final JdbcEnvironment jdbcEnvironment = database.getJdbcEnvironment();
// DISCRIMINATOR
@ -201,28 +205,24 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
final int idColumnSpan = getIdentifierColumnSpan();
ArrayList tables = new ArrayList();
ArrayList keyColumns = new ArrayList();
ArrayList keyColumnReaders = new ArrayList();
ArrayList keyColumnReaderTemplates = new ArrayList();
ArrayList cascadeDeletes = new ArrayList();
Iterator titer = persistentClass.getTableClosureIterator();
Iterator kiter = persistentClass.getKeyClosureIterator();
while ( titer.hasNext() ) {
Table tab = (Table) titer.next();
KeyValue key = (KeyValue) kiter.next();
String tabname = tab.getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
);
tables.add( tabname );
ArrayList<String> tableNames = new ArrayList<String>();
ArrayList<String[]> keyColumns = new ArrayList<String[]>();
ArrayList<String[]> keyColumnReaders = new ArrayList<String[]>();
ArrayList<String[]> keyColumnReaderTemplates = new ArrayList<String[]>();
ArrayList<Boolean> cascadeDeletes = new ArrayList<Boolean>();
Iterator tItr = persistentClass.getTableClosureIterator();
Iterator kItr = persistentClass.getKeyClosureIterator();
while ( tItr.hasNext() ) {
final Table table = (Table) tItr.next();
final KeyValue key = (KeyValue) kItr.next();
final String tableName = determineTableName( table, jdbcEnvironment );
tableNames.add( tableName );
String[] keyCols = new String[idColumnSpan];
String[] keyColReaders = new String[idColumnSpan];
String[] keyColReaderTemplates = new String[idColumnSpan];
Iterator citer = key.getColumnIterator();
Iterator cItr = key.getColumnIterator();
for ( int k = 0; k < idColumnSpan; k++ ) {
Column column = (Column) citer.next();
Column column = (Column) cItr.next();
keyCols[k] = column.getQuotedName( factory.getDialect() );
keyColReaders[k] = column.getReadExpr( factory.getDialect() );
keyColReaderTemplates[k] = column.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
@ -233,26 +233,21 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
cascadeDeletes.add( key.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete() );
}
//Span of the tables directly mapped by this entity and super-classes, if any
coreTableSpan = tables.size();
//Span of the tableNames directly mapped by this entity and super-classes, if any
coreTableSpan = tableNames.size();
isNullableTable = new boolean[persistentClass.getJoinClosureSpan()];
int tableIndex = 0;
Iterator joinIter = persistentClass.getJoinClosureIterator();
while ( joinIter.hasNext() ) {
Join join = (Join) joinIter.next();
Iterator joinItr = persistentClass.getJoinClosureIterator();
while ( joinItr.hasNext() ) {
Join join = (Join) joinItr.next();
isNullableTable[tableIndex++] = join.isOptional();
Table table = join.getTable();
String tableName = table.getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
);
tables.add( tableName );
final String tableName = determineTableName( table, jdbcEnvironment );
tableNames.add( tableName );
KeyValue key = join.getKey();
int joinIdColumnSpan = key.getColumnSpan();
@ -261,10 +256,10 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
String[] keyColReaders = new String[joinIdColumnSpan];
String[] keyColReaderTemplates = new String[joinIdColumnSpan];
Iterator citer = key.getColumnIterator();
Iterator cItr = key.getColumnIterator();
for ( int k = 0; k < joinIdColumnSpan; k++ ) {
Column column = (Column) citer.next();
Column column = (Column) cItr.next();
keyCols[k] = column.getQuotedName( factory.getDialect() );
keyColReaders[k] = column.getReadExpr( factory.getDialect() );
keyColReaderTemplates[k] = column.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
@ -275,64 +270,55 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
cascadeDeletes.add( key.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete() );
}
naturalOrderTableNames = ArrayHelper.toStringArray( tables );
naturalOrderTableNames = ArrayHelper.toStringArray( tableNames );
naturalOrderTableKeyColumns = ArrayHelper.to2DStringArray( keyColumns );
naturalOrderTableKeyColumnReaders = ArrayHelper.to2DStringArray( keyColumnReaders );
naturalOrderTableKeyColumnReaderTemplates = ArrayHelper.to2DStringArray( keyColumnReaderTemplates );
naturalOrderCascadeDeleteEnabled = ArrayHelper.toBooleanArray( cascadeDeletes );
ArrayList subtables = new ArrayList();
ArrayList isConcretes = new ArrayList();
ArrayList isDeferreds = new ArrayList();
ArrayList isLazies = new ArrayList();
ArrayList<String> subclassTableNames = new ArrayList<String>();
ArrayList<Boolean> isConcretes = new ArrayList<Boolean>();
ArrayList<Boolean> isDeferreds = new ArrayList<Boolean>();
ArrayList<Boolean> isLazies = new ArrayList<Boolean>();
keyColumns = new ArrayList();
titer = persistentClass.getSubclassTableClosureIterator();
while ( titer.hasNext() ) {
Table tab = (Table) titer.next();
keyColumns = new ArrayList<String[]>();
tItr = persistentClass.getSubclassTableClosureIterator();
while ( tItr.hasNext() ) {
Table tab = (Table) tItr.next();
isConcretes.add( persistentClass.isClassOrSuperclassTable( tab ) );
isDeferreds.add( Boolean.FALSE );
isLazies.add( Boolean.FALSE );
String tabname = tab.getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
);
subtables.add( tabname );
final String tableName = determineTableName( tab, jdbcEnvironment );
subclassTableNames.add( tableName );
String[] key = new String[idColumnSpan];
Iterator citer = tab.getPrimaryKey().getColumnIterator();
Iterator cItr = tab.getPrimaryKey().getColumnIterator();
for ( int k = 0; k < idColumnSpan; k++ ) {
key[k] = ( (Column) citer.next() ).getQuotedName( factory.getDialect() );
key[k] = ( (Column) cItr.next() ).getQuotedName( factory.getDialect() );
}
keyColumns.add( key );
}
//Add joins
joinIter = persistentClass.getSubclassJoinClosureIterator();
while ( joinIter.hasNext() ) {
Join join = (Join) joinIter.next();
joinItr = persistentClass.getSubclassJoinClosureIterator();
while ( joinItr.hasNext() ) {
final Join join = (Join) joinItr.next();
final Table joinTable = join.getTable();
Table tab = join.getTable();
isConcretes.add( persistentClass.isClassOrSuperclassTable( tab ) );
isConcretes.add( persistentClass.isClassOrSuperclassTable( joinTable ) );
isDeferreds.add( join.isSequentialSelect() );
isLazies.add( join.isLazy() );
String tabname = tab.getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
);
subtables.add( tabname );
String joinTableName = determineTableName( joinTable, jdbcEnvironment );
subclassTableNames.add( joinTableName );
String[] key = new String[idColumnSpan];
Iterator citer = tab.getPrimaryKey().getColumnIterator();
Iterator citer = joinTable.getPrimaryKey().getColumnIterator();
for ( int k = 0; k < idColumnSpan; k++ ) {
key[k] = ( (Column) citer.next() ).getQuotedName( factory.getDialect() );
}
keyColumns.add( key );
}
String[] naturalOrderSubclassTableNameClosure = ArrayHelper.toStringArray( subtables );
String[] naturalOrderSubclassTableNameClosure = ArrayHelper.toStringArray( subclassTableNames );
String[][] naturalOrderSubclassTableKeyColumnClosure = ArrayHelper.to2DStringArray( keyColumns );
isClassOrSuperclassTable = ArrayHelper.toBooleanArray( isConcretes );
subclassTableSequentialSelect = ArrayHelper.toBooleanArray( isDeferreds );
@ -347,9 +333,9 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
}
/**
* Suppose an entity Client extends Person, mapped to the tables CLIENT and PERSON respectively.
* Suppose an entity Client extends Person, mapped to the tableNames CLIENT and PERSON respectively.
* For the Client entity:
* naturalOrderTableNames -> PERSON, CLIENT; this reflects the sequence in which the tables are
* naturalOrderTableNames -> PERSON, CLIENT; this reflects the sequence in which the tableNames are
* added to the meta-data when the annotated entities are processed.
* However, in some instances, for example when generating joins, the CLIENT table needs to be
* the first table as it will the driving table.
@ -357,7 +343,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
*/
tableSpan = naturalOrderTableNames.length;
tableNames = reverse( naturalOrderTableNames, coreTableSpan );
this.tableNames = reverse( naturalOrderTableNames, coreTableSpan );
tableKeyColumns = reverse( naturalOrderTableKeyColumns, coreTableSpan );
tableKeyColumnReaders = reverse( naturalOrderTableKeyColumnReaders, coreTableSpan );
tableKeyColumnReaderTemplates = reverse( naturalOrderTableKeyColumnReaderTemplates, coreTableSpan );
@ -365,7 +351,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
subclassTableKeyColumnClosure = reverse( naturalOrderSubclassTableKeyColumnClosure, coreTableSpan );
spaces = ArrayHelper.join(
tableNames,
this.tableNames,
ArrayHelper.toStringArray( persistentClass.getSynchronizedTables() )
);
@ -408,10 +394,10 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
throw new AssertionFailure( "Tablespan does not match height of joined-subclass hiearchy." );
}
joinIter = persistentClass.getJoinClosureIterator();
joinItr = persistentClass.getJoinClosureIterator();
int j = coreTableSpan;
while ( joinIter.hasNext() ) {
Join join = (Join) joinIter.next();
while ( joinItr.hasNext() ) {
Join join = (Join) joinItr.next();
customSQLInsert[j] = join.getCustomSQLInsert();
insertCallable[j] = customSQLInsert[j] != null && join.isCustomInsertCallable();
@ -444,7 +430,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
);
propertyTableNumbers[i] = getTableId( tabname, tableNames );
propertyTableNumbers[i] = getTableId( tabname, this.tableNames );
naturalOrderPropertyTableNumbers[i] = getTableId( tabname, naturalOrderTableNames );
i++;
}

View File

@ -17,8 +17,10 @@ import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.DynamicFilterAliasGenerator;
@ -123,6 +125,9 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
final SessionFactoryImplementor factory = creationContext.getSessionFactory();
final Database database = creationContext.getMetadata().getDatabase();
final JdbcEnvironment jdbcEnvironment = database.getJdbcEnvironment();
// CLASS + TABLE
joinSpan = persistentClass.getJoinClosureSpan() + 1;
@ -131,11 +136,8 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
isNullableTable = new boolean[joinSpan];
keyColumnNames = new String[joinSpan][];
final Table table = persistentClass.getRootTable();
qualifiedTableNames[0] = table.getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
);
qualifiedTableNames[0] = determineTableName( table, jdbcEnvironment );
isInverseTable[0] = false;
isNullableTable[0] = false;
keyColumnNames[0] = getIdentifierColumnNames();
@ -174,11 +176,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
int j = 1;
while ( joinIter.hasNext() ) {
Join join = (Join) joinIter.next();
qualifiedTableNames[j] = join.getTable().getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
);
qualifiedTableNames[j] = determineTableName( join.getTable(), jdbcEnvironment );
isInverseTable[j] = join.isInverse();
isNullableTable[j] = join.isOptional();
cascadeDeleteEnabled[j] = join.getKey().isCascadeDeleteEnabled() &&

View File

@ -19,10 +19,12 @@ import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.cfg.Settings;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.SessionFactoryImplementor;
@ -74,8 +76,6 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
super( persistentClass, cacheAccessStrategy, naturalIdRegionAccessStrategy, creationContext );
final SessionFactoryImplementor factory = creationContext.getSessionFactory();
if ( getIdentifierGenerator() instanceof IdentityGenerator ) {
throw new MappingException(
"Cannot use identity column key generation with <union-subclass> mapping for: " +
@ -83,18 +83,13 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
);
}
final SessionFactoryImplementor factory = creationContext.getSessionFactory();
final Database database = creationContext.getMetadata().getDatabase();
final JdbcEnvironment jdbcEnvironment = database.getJdbcEnvironment();
// TABLE
tableName = persistentClass.getTable().getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
);
/*rootTableName = persistentClass.getRootTable().getQualifiedName(
factory.getDialect(),
factory.getDefaultCatalog(),
factory.getDefaultSchema()
);*/
tableName = determineTableName( persistentClass.getTable(), jdbcEnvironment );
//Custom SQL
@ -173,14 +168,8 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
HashSet subclassTables = new HashSet();
iter = persistentClass.getSubclassTableClosureIterator();
while ( iter.hasNext() ) {
Table table = (Table) iter.next();
subclassTables.add(
table.getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
)
);
final Table table = (Table) iter.next();
subclassTables.add( determineTableName( table, jdbcEnvironment ) );
}
subclassSpaces = ArrayHelper.toStringArray( subclassTables );
@ -198,11 +187,7 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
while ( iter.hasNext() ) {
Table tab = (Table) iter.next();
if ( !tab.isAbstractUnionTable() ) {
String tableName = tab.getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
);
final String tableName = determineTableName( tab, jdbcEnvironment );
tableNames.add( tableName );
String[] key = new String[idColumnSpan];
Iterator citer = tab.getPrimaryKey().getColumnIterator();

View File

@ -0,0 +1,209 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.boot.database.qualfiedTableNaming;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
/**
* @author Steve Ebersole
*/
public class JdbcMocks {
public static Connection createConnection(String databaseName, int majorVersion) {
return createConnection( databaseName, majorVersion, -9999 );
}
public static Connection createConnection(String databaseName, int majorVersion, int minorVersion) {
DatabaseMetaDataHandler metadataHandler = new DatabaseMetaDataHandler( databaseName, majorVersion, minorVersion );
ConnectionHandler connectionHandler = new ConnectionHandler();
DatabaseMetaData metadataProxy = ( DatabaseMetaData ) Proxy.newProxyInstance(
ClassLoader.getSystemClassLoader(),
new Class[] {DatabaseMetaData.class},
metadataHandler
);
Connection connectionProxy = ( Connection ) Proxy.newProxyInstance(
ClassLoader.getSystemClassLoader(),
new Class[] { Connection.class },
connectionHandler
);
metadataHandler.setConnectionProxy( connectionProxy );
connectionHandler.setMetadataProxy( metadataProxy );
return connectionProxy;
}
private static class ConnectionHandler implements InvocationHandler {
private DatabaseMetaData metadataProxy;
public void setMetadataProxy(DatabaseMetaData metadataProxy) {
this.metadataProxy = metadataProxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final String methodName = method.getName();
if ( "getMetaData".equals( methodName ) ) {
return metadataProxy;
}
if ( "toString".equals( methodName ) ) {
return "Connection proxy [@" + hashCode() + "]";
}
if ( "hashCode".equals( methodName ) ) {
return Integer.valueOf( this.hashCode() );
}
if ( "getCatalog".equals( methodName ) ) {
return "DB1";
}
if ( "supportsRefCursors".equals( methodName ) ) {
return false;
}
if ( canThrowSQLException( method ) ) {
throw new SQLException();
}
else {
throw new UnsupportedOperationException();
}
}
}
private static class DatabaseMetaDataHandler implements InvocationHandler {
private final String databaseName;
private final int majorVersion;
private final int minorVersion;
private Connection connectionProxy;
public void setConnectionProxy(Connection connectionProxy) {
this.connectionProxy = connectionProxy;
}
private DatabaseMetaDataHandler(String databaseName, int majorVersion) {
this( databaseName, majorVersion, -9999 );
}
private DatabaseMetaDataHandler(String databaseName, int majorVersion, int minorVersion) {
this.databaseName = databaseName;
this.majorVersion = majorVersion;
this.minorVersion = minorVersion;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final String methodName = method.getName();
if ( "getDatabaseProductName".equals( methodName ) ) {
return databaseName;
}
if ( "getDatabaseMajorVersion".equals( methodName ) ) {
return Integer.valueOf( majorVersion );
}
if ( "getDatabaseMinorVersion".equals( methodName ) ) {
return Integer.valueOf( minorVersion );
}
if ( "getConnection".equals( methodName ) ) {
return connectionProxy;
}
if ( "toString".equals( methodName ) ) {
return "DatabaseMetaData proxy [db-name=" + databaseName + ", version=" + majorVersion + "]";
}
if ( "hashCode".equals( methodName ) ) {
return Integer.valueOf( this.hashCode() );
}
if ( "supportsNamedParameters".equals( methodName ) ) {
return true ;
}
if ( "supportsResultSetType".equals( methodName ) ) {
return true ;
}
if ( "supportsGetGeneratedKeys".equals( methodName ) ) {
return true ;
}
if ( "supportsBatchUpdates".equals( methodName ) ) {
return true ;
}
if ( "dataDefinitionIgnoredInTransactions".equals( methodName ) ) {
return false ;
}
if ( "dataDefinitionCausesTransactionCommit".equals( methodName ) ) {
return false ;
}
if ( "getSQLKeywords".equals( methodName ) ) {
return "after,ansi,append,attach,audit,before,bitmap,boolean,buffered,byte,cache,call,cluster,clustersize,codeset,database,datafiles,dataskip,datetime,dba,dbdate,dbmoney,debug,define,delimiter,deluxe,detach,dirty,distributions,document,each,elif,exclusive,exit,explain,express,expression,extend,extent,file,fillfactor,foreach,format,fraction,fragment,gk,hash,high,hold,hybrid,if,index,init,labeleq,labelge,labelgt,labelle,labellt,let,listing,lock,log,low,matches,maxerrors,medium,mode,modify,money,mounting,new,nvarchar,off,old,operational,optical,optimization,page,pdqpriority,pload,private,raise,range,raw,recordend,recover,referencing,rejectfile,release,remainder,rename,reserve,resolution,resource,resume,return,returning,returns,ridlist,robin,rollforward,round,row,rowids,sameas,samples,schedule,scratch,serial,share,skall,skinhibit,skshow,smallfloat,stability,standard,start,static,statistics,stdev,step,sync,synonym,system,temp,text,timeout,trace,trigger,units,unlock,variance,wait,while,xload,xunload" ;
}
if ( "getSQLStateType".equals( methodName ) ) {
return DatabaseMetaData.sqlStateXOpen ;
}
if ( "locatorsUpdateCopy".equals( methodName ) ) {
return false ;
}
if ( "getTypeInfo".equals( methodName ) ) {
com.sun.rowset.CachedRowSetImpl rowSet = new com.sun.rowset.CachedRowSetImpl();
return rowSet ;
}
if ( "storesLowerCaseIdentifiers".equals( methodName ) ) {
return true ;
}
if ( "storesUpperCaseIdentifiers".equals( methodName ) ) {
return false ;
}
if ( "getCatalogSeparator".equals( methodName ) ) {
return ":" ;
}
if ( "isCatalogAtStart".equals( methodName ) ) {
return true ;
}
if ( canThrowSQLException( method ) ) {
throw new SQLException();
}
else {
throw new UnsupportedOperationException();
}
}
}
private static boolean canThrowSQLException(Method method) {
final Class[] exceptions = method.getExceptionTypes();
for ( Class exceptionType : exceptions ) {
if ( SQLException.class.isAssignableFrom( exceptionType ) ) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,129 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.boot.database.qualfiedTableNaming;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.relational.Namespace;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport;
import org.hibernate.mapping.Table;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.SingleTableEntityPersister;
import org.hibernate.tool.schema.internal.StandardTableExporter;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
/**
* @author Steve Ebersole
*/
public class QualifiedTableNamingTest extends BaseNonConfigCoreFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { Box.class };
}
@Override
protected boolean createSchema() {
return false;
}
@Override
protected void addSettings(Map settings) {
super.addSettings( settings );
settings.put( AvailableSettings.DIALECT, TestDialect.class );
settings.put( AvailableSettings.CONNECTION_PROVIDER, MockedConnectionProvider.class.getName() );
}
@Test
public void testQualifiedNameSeparator() throws Exception {
Namespace.Name namespaceName = new Namespace.Name(
Identifier.toIdentifier( "DB1" ),
Identifier.toIdentifier( "PUBLIC" )
);
String expectedName = null;
for ( Namespace namespace : metadata().getDatabase().getNamespaces() ) {
if ( !namespace.getName().equals( namespaceName ) ) {
continue;
}
assertEquals( 1, namespace.getTables().size() );
expectedName = metadata().getDatabase().getJdbcEnvironment().getQualifiedObjectNameFormatter().format(
namespace.getTables().iterator().next().getQualifiedTableName(),
getDialect()
);
}
assertNotNull( expectedName );
SingleTableEntityPersister persister = (SingleTableEntityPersister) sessionFactory().getEntityPersister( Box.class.getName() );
assertEquals( expectedName, persister.getTableName() );
}
@Entity(name = "Box")
@javax.persistence.Table(name = "Box", schema = "PUBLIC", catalog = "DB1")
public static class Box {
@Id
public Integer id;
public String value;
}
public static class TestDialect extends Dialect {
@Override
public NameQualifierSupport getNameQualifierSupport() {
return NameQualifierSupport.BOTH;
}
}
public static class MockedConnectionProvider implements ConnectionProvider {
private Connection connection;
@Override
public Connection getConnection() throws SQLException {
if (connection == null) {
connection = JdbcMocks.createConnection( "db1", 0 );
}
return connection;
}
@Override
public void closeConnection(Connection conn) throws SQLException {
}
@Override
public boolean supportsAggressiveRelease() {
return false;
}
@Override
public boolean isUnwrappableAs(Class unwrapType) {
return false;
}
@Override
public <T> T unwrap(Class<T> unwrapType) {
return null;
}
}
}