Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.model.relational.ExportableProducer;
import org.hibernate.boot.model.relational.Namespace;
import org.hibernate.boot.model.relational.QualifiedTableName;
import org.hibernate.boot.model.source.internal.ImplicitColumnNamingSecondPass;
import org.hibernate.boot.model.source.spi.LocalMetadataBuildingContext;
import org.hibernate.boot.spi.AttributeConverterAutoApplyHandler;
Expand Down Expand Up @@ -1366,8 +1367,17 @@ public void addSecondaryTable(LocalMetadataBuildingContext buildingContext, Iden
}

@Override
public void addSecondaryTable(Identifier logicalName, Join secondaryTableJoin) {
if ( Identifier.areEqual( primaryTableLogicalName, logicalName ) ) {
public void addSecondaryTable(QualifiedTableName logicalQualifiedTableName, Join secondaryTableJoin) {
Identifier logicalName = logicalQualifiedTableName.getTableName();
if ( Identifier.areEqual(
Identifier.toIdentifier(
new QualifiedTableName(
Identifier.toIdentifier( primaryTable.getCatalog() ),
Identifier.toIdentifier( primaryTable.getSchema() ),
primaryTableLogicalName
).render()
),
Identifier.toIdentifier( logicalQualifiedTableName.render() ) ) ) {
throw new DuplicateSecondaryTableException( logicalName );
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.model.relational.QualifiedTableName;
import org.hibernate.boot.model.source.spi.LocalMetadataBuildingContext;
import org.hibernate.cfg.AnnotatedClassType;
import org.hibernate.cfg.AttributeConverterDefinition;
Expand Down Expand Up @@ -300,7 +301,7 @@ interface DelayedPropertyReferenceHandler extends Serializable {

interface EntityTableXref {
void addSecondaryTable(LocalMetadataBuildingContext buildingContext, Identifier logicalName, Join secondaryTableJoin);
void addSecondaryTable(Identifier logicalName, Join secondaryTableJoin);
void addSecondaryTable(QualifiedTableName logicalName, Join secondaryTableJoin);
Table resolveTable(Identifier tableName);
Table getPrimaryTable();
Join locateJoin(Identifier tableName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.ImplicitEntityNameSource;
import org.hibernate.boot.model.naming.NamingStrategyHelper;
import org.hibernate.boot.model.relational.QualifiedTableName;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MetadataBuildingContext;
Expand Down Expand Up @@ -935,26 +936,34 @@ private Join addJoin(
final Object joinColumns;
final List<UniqueConstraintHolder> uniqueConstraintHolders;

final Identifier logicalName;
final QualifiedTableName logicalName;
if ( secondaryTable != null ) {
schema = secondaryTable.schema();
catalog = secondaryTable.catalog();
logicalName = context.getMetadataCollector()
logicalName = new QualifiedTableName(
Identifier.toIdentifier( catalog ),
Identifier.toIdentifier( schema ),
context.getMetadataCollector()
.getDatabase()
.getJdbcEnvironment()
.getIdentifierHelper()
.toIdentifier( secondaryTable.name() );
.toIdentifier( secondaryTable.name() )
);
joinColumns = secondaryTable.pkJoinColumns();
uniqueConstraintHolders = TableBinder.buildUniqueConstraintHolders( secondaryTable.uniqueConstraints() );
}
else if ( joinTable != null ) {
schema = joinTable.schema();
catalog = joinTable.catalog();
logicalName = context.getMetadataCollector()
.getDatabase()
.getJdbcEnvironment()
.getIdentifierHelper()
.toIdentifier( joinTable.name() );
logicalName = new QualifiedTableName(
Identifier.toIdentifier( catalog ),
Identifier.toIdentifier( schema ),
context.getMetadataCollector()
.getDatabase()
.getJdbcEnvironment()
.getIdentifierHelper()
.toIdentifier( joinTable.name() )
);
joinColumns = joinTable.joinColumns();
uniqueConstraintHolders = TableBinder.buildUniqueConstraintHolders( joinTable.uniqueConstraints() );
}
Expand All @@ -965,7 +974,7 @@ else if ( joinTable != null ) {
final Table table = TableBinder.buildAndFillTable(
schema,
catalog,
logicalName,
logicalName.getTableName(),
false,
uniqueConstraintHolders,
null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,49 +28,52 @@ public class DefaultSchemaNameResolver implements SchemaNameResolver {

public static final DefaultSchemaNameResolver INSTANCE = new DefaultSchemaNameResolver();

private SchemaNameResolver delegate;

// NOTE: The actual delegate should not be cached in DefaultSchemaNameResolver because,
// in the case of multiple data sources, there may be a data source that
// requires a different delegate. See HHH-12392.
private DefaultSchemaNameResolver() {
}

private void determineAppropriateResolverDelegate(Connection connection) {
if ( delegate == null ) {
// unfortunately Connection#getSchema is only available in Java 1.7 and above
// and Hibernate still baselines on 1.6. So for now, use reflection and
// leverage the Connection#getSchema method if it is available.
try {
final Class<? extends Connection> jdbcConnectionClass = connection.getClass();
final Method getSchemaMethod = jdbcConnectionClass.getMethod( "getSchema" );
if ( getSchemaMethod != null && getSchemaMethod.getReturnType().equals( String.class ) ) {
try {
// If the JDBC driver does not implement the Java 7 spec, but the JRE is Java 7
// then the getSchemaMethod is not null but the call to getSchema() throws an java.lang.AbstractMethodError
delegate = new SchemaNameResolverJava17Delegate( getSchemaMethod );
// Connection#getSchema was introduced into jdk7.
// Since 5.1 is supposed to have jdk6 source, we can't call Connection#getSchema directly.
// Make sure it's possible to resolve the schema without taking dialect into account.
delegate.resolveSchemaName( connection, null );
}
catch (java.lang.AbstractMethodError e) {
log.debugf( "Unable to use Java 1.7 Connection#getSchema" );
delegate = SchemaNameResolverFallbackDelegate.INSTANCE;
}
private SchemaNameResolver determineAppropriateResolverDelegate(Connection connection) {
// unfortunately Connection#getSchema is only available in Java 1.7 and above
// and Hibernate still baselines on 1.6. So for now, use reflection and
// leverage the Connection#getSchema method if it is available.
try {
final Class<? extends Connection> jdbcConnectionClass = connection.getClass();
final Method getSchemaMethod = jdbcConnectionClass.getMethod( "getSchema" );
if ( getSchemaMethod != null && getSchemaMethod.getReturnType().equals( String.class ) ) {
try {
// If the JDBC driver does not implement the Java 7 spec, but the JRE is Java 7
// then the getSchemaMethod is not null but the call to getSchema() throws an java.lang.AbstractMethodError
final SchemaNameResolver delegate = new SchemaNameResolverJava17Delegate( getSchemaMethod );
// Connection#getSchema was introduced into jdk7.
// Since 5.1 is supposed to have jdk6 source, we can't call Connection#getSchema directly.
// Make sure it's possible to resolve the schema without taking dialect into account.
delegate.resolveSchemaName( connection, null );
return delegate;
}
else {
catch (java.lang.AbstractMethodError e) {
log.debugf( "Unable to use Java 1.7 Connection#getSchema" );
delegate = SchemaNameResolverFallbackDelegate.INSTANCE;
return SchemaNameResolverFallbackDelegate.INSTANCE;
}
}
catch (Exception ignore) {
delegate = SchemaNameResolverFallbackDelegate.INSTANCE;
log.debugf( "Unable to resolve connection default schema : " + ignore.getMessage() );
else {
log.debugf( "Unable to use Java 1.7 Connection#getSchema" );
return SchemaNameResolverFallbackDelegate.INSTANCE;
}
}
catch (Exception ignore) {
log.debugf( "Unable to resolve connection default schema : " + ignore.getMessage() );
return SchemaNameResolverFallbackDelegate.INSTANCE;
}
}

@Override
public String resolveSchemaName(Connection connection, Dialect dialect) throws SQLException {
determineAppropriateResolverDelegate( connection );
// NOTE: delegate should not be cached in DefaultSchemaNameResolver because,
// in the case of multiple data sources, there may be a data source that
// requires a different delegate. See HHH-12392.
final SchemaNameResolver delegate = determineAppropriateResolverDelegate( connection );
return delegate.resolveSchemaName( connection, dialect );
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* 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.annotations.secondarytable;

import java.io.Serializable;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.SecondaryTable;
import javax.persistence.Table;

import org.hibernate.Session;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.OptimisticLockType;
import org.hibernate.annotations.OptimisticLocking;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.dialect.H2Dialect;

import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;

import static org.junit.Assert.assertTrue;

/**
* @author Vlad Mihalcea
*/
@RequiresDialect(value = H2Dialect.class)
public class SecondaryTableSchemaTest
extends BaseCoreFunctionalTestCase {

@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Cluster.class,
};
}

@Override
protected void configure(Configuration configuration) {
configuration.setProperty(
AvailableSettings.URL,
configuration.getProperty( AvailableSettings.URL ) + ";INIT=CREATE SCHEMA IF NOT EXISTS schema1\\;CREATE SCHEMA IF NOT EXISTS schema2;"
);
}

@Test
public void test() {
Session session = openSession();
session.getTransaction().begin();
List clusters = session.createQuery( "select c from Cluster c" ).list();
assertTrue(clusters.isEmpty());
}

@Entity(name = "Cluster")
@Table(name = "cluster", schema = "schema1")
@SecondaryTable(name = "Cluster", schema="schema2", pkJoinColumns = { @PrimaryKeyJoinColumn(name = "clusterid") })
@org.hibernate.annotations.Table(appliesTo = "Cluster", optional = false)
@OptimisticLocking(type = OptimisticLockType.DIRTY)
@DynamicUpdate
public static class Cluster implements Serializable {
private static final long serialVersionUID = 3965099001305947412L;

@Id
@Column(name = "objid")
private Long id;

private String uuid;

private String resourceKey;

private String name;

@Column(name = "lastSync", table = "Cluster")
private Long lastSync;

@Column(name = "healthStatus", table = "Cluster")
private Integer healthStatus;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getResourceKey() {
return resourceKey;
}

public void setResourceKey(String resourceKey) {
this.resourceKey = resourceKey;
}

public String getUuid() {
return uuid;
}

public void setUuid(String uuid) {
this.uuid = uuid;
}

public Long getLastSync() {
return lastSync;
}

public void setLastSync(Long lastSync) {
this.lastSync = lastSync;
}

public Integer getHealthStatus() {
return healthStatus;
}

public void setHealthStatus(Integer healthStatus) {
this.healthStatus = healthStatus;
}

}
}
Loading