HHH-10934 - Check ForeignKey on function instead of only the name

This commit is contained in:
MilovanderZee 2017-05-10 16:45:21 +02:00 committed by Chris Cranford
parent 736da3247c
commit 2867e070ea
1 changed files with 41 additions and 7 deletions

View File

@ -11,6 +11,9 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.model.naming.Identifier;
@ -35,6 +38,7 @@ import org.hibernate.resource.transaction.spi.DdlTransactionIsolator;
import org.hibernate.tool.hbm2ddl.UniqueConstraintSchemaUpdateStrategy;
import org.hibernate.tool.schema.extract.spi.DatabaseInformation;
import org.hibernate.tool.schema.extract.spi.ForeignKeyInformation;
import org.hibernate.tool.schema.extract.spi.ForeignKeyInformation.ColumnReferenceMapping;
import org.hibernate.tool.schema.extract.spi.IndexInformation;
import org.hibernate.tool.schema.extract.spi.NameSpaceTablesInformation;
import org.hibernate.tool.schema.extract.spi.SequenceInformation;
@ -414,14 +418,14 @@ public abstract class AbstractSchemaMigrator implements SchemaMigrator {
while ( fkItr.hasNext() ) {
final ForeignKey foreignKey = fkItr.next();
if ( foreignKey.isPhysicalConstraint() && foreignKey.isCreationEnabled() ) {
ForeignKeyInformation existingForeignKey = null;
boolean existingForeignKeyFound = false;
if ( tableInformation != null ) {
existingForeignKey = findMatchingForeignKey(
existingForeignKeyFound = checkForExistingForeignKey(
foreignKey,
tableInformation
);
}
if ( existingForeignKey == null ) {
if ( !existingForeignKeyFound ) {
// todo : shouldn't we just drop+recreate if FK exists?
// this follows the existing code from legacy SchemaUpdate which just skipped
@ -439,11 +443,41 @@ public abstract class AbstractSchemaMigrator implements SchemaMigrator {
}
}
private ForeignKeyInformation findMatchingForeignKey(ForeignKey foreignKey, TableInformation tableInformation) {
if ( foreignKey.getName() == null ) {
return null;
/**
* Check if the ForeignKey already exists. First check based on definition and if that is not matched check if a key
* with the exact same name exists. Keys with the same name are presumed to be functional equal.
*
* @param foreignKey - ForeignKey, new key to be created
* @param tableInformation - TableInformation, information of existing keys
* @return boolean, true if key already exists
*/
private boolean checkForExistingForeignKey(ForeignKey foreignKey, TableInformation tableInformation) {
if ( foreignKey.getName() == null || tableInformation == null ) {
return false;
}
return tableInformation.getForeignKey( Identifier.toIdentifier( foreignKey.getName() ) );
final String referencingColumn = foreignKey.getColumn( 0 ).getName();
final String referencedTable = foreignKey.getReferencedTable().getName();
/*
* Find existing keys based on referencing column and referencedTable. "referencedColumnName" is not checked
* because that always is the primary key of the "referencedTable".
*/
Predicate<ColumnReferenceMapping> mappingPredicate = m -> {
String existingReferencingColumn = m.getReferencingColumnMetadata().getColumnIdentifier().getText();
String existingReferencedTable = m.getReferencedColumnMetadata().getContainingTableInformation().getName().getTableName().getCanonicalName();
return referencingColumn.equals( existingReferencingColumn ) && referencedTable.equals( existingReferencedTable );
};
Stream<ForeignKeyInformation> keyStream = StreamSupport.stream( tableInformation.getForeignKeys().spliterator(), false );
Stream<ColumnReferenceMapping> mappingStream = keyStream.flatMap( k -> StreamSupport.stream( k.getColumnReferenceMappings().spliterator(), false ) );
boolean found = mappingStream.anyMatch( mappingPredicate );
if ( found ) {
return true;
}
// And at the end just compare the name of the key. If a key with the same name exists we assume the function is
// also the same...
return tableInformation.getForeignKey( Identifier.toIdentifier( foreignKey.getName() ) ) != null;
}
protected void checkExportIdentifier(Exportable exportable, Set<String> exportIdentifiers) {