Skip to content

Commit 36ad460

Browse files
fix diff changelog generating undesired changes (#679)
* fix: how a unique constraint is not unique!? * fix: primary key backing index issues. * fix: advanced validation for sequence fields managed by liquibase * fix: allow allocation size of 50 to be the same as null
1 parent 2ef942f commit 36ad460

5 files changed

+110
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package liquibase.ext.hibernate.diff;
2+
3+
import liquibase.change.Change;
4+
import liquibase.database.Database;
5+
import liquibase.diff.ObjectDifferences;
6+
import liquibase.diff.output.DiffOutputControl;
7+
import liquibase.diff.output.changelog.ChangeGeneratorChain;
8+
import liquibase.ext.hibernate.database.HibernateDatabase;
9+
import liquibase.structure.DatabaseObject;
10+
import liquibase.structure.core.PrimaryKey;
11+
12+
/**
13+
* Hibernate doesn't know about all the variations that occur with primary keys, especially backing index stuff.
14+
* To prevent changing customized primary keys, we suppress this kind of changes from hibernate side.
15+
*/
16+
public class ChangedPrimaryKeyChangeGenerator extends liquibase.diff.output.changelog.core.ChangedPrimaryKeyChangeGenerator {
17+
18+
@Override
19+
public int getPriority(Class<? extends DatabaseObject> objectType, Database database) {
20+
if (PrimaryKey.class.isAssignableFrom(objectType)) {
21+
return PRIORITY_ADDITIONAL;
22+
}
23+
return PRIORITY_NONE;
24+
}
25+
26+
@Override
27+
public Change[] fixChanged(DatabaseObject changedObject, ObjectDifferences differences, DiffOutputControl control, Database referenceDatabase, Database comparisonDatabase, ChangeGeneratorChain chain) {
28+
if (referenceDatabase instanceof HibernateDatabase || comparisonDatabase instanceof HibernateDatabase) {
29+
differences.removeDifference("unique");
30+
if (!differences.hasDifferences()) {
31+
return null;
32+
}
33+
}
34+
35+
return super.fixChanged(changedObject, differences, control, referenceDatabase, comparisonDatabase, chain);
36+
}
37+
}

src/main/java/liquibase/ext/hibernate/diff/ChangedSequenceChangeGenerator.java

+32
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,39 @@ public Change[] fixChanged(DatabaseObject changedObject, ObjectDifferences diffe
5353
.filter(differenceField -> !HIBERNATE_SEQUENCE_FIELDS.contains(differenceField))
5454
.collect(Collectors.toCollection(LinkedHashSet::new));
5555
ignoredDifferenceFields.forEach(differences::removeDifference);
56+
this.advancedIgnoredDifferenceFields(differences, referenceDatabase, comparisonDatabase);
5657
return super.fixChanged(changedObject, differences, control, referenceDatabase, comparisonDatabase, chain);
5758
}
5859

60+
61+
/**
62+
* In some cases a value that was 1 can be null in the database, or the name field can be different only by case.
63+
* This method removes these differences from the list of differences so we don't generate a change for them.
64+
*/
65+
private void advancedIgnoredDifferenceFields(ObjectDifferences differences, Database referenceDatabase, Database comparisonDatabase) {
66+
Set<String> ignoredDifferenceFields = new HashSet<>();
67+
for (Difference difference : differences.getDifferences()) {
68+
String field = difference.getField();
69+
String refValue = difference.getReferenceValue() != null ? difference.getReferenceValue().toString() : null;
70+
String comparedValue = difference.getComparedValue() != null ? difference.getComparedValue().toString() : null;
71+
72+
// if the name field case is different and the databases are case-insensitive, we can ignore the difference
73+
boolean isNameField = field.equals("name");
74+
boolean isCaseInsensitive = !referenceDatabase.isCaseSensitive() || !comparisonDatabase.isCaseSensitive();
75+
76+
// if the startValue or incrementBy fields are 1 and the other is null, we can ignore the difference
77+
// Or 50, as it is the default value for hibernate for allocationSize:
78+
// https://github.com/hibernate/hibernate-orm/blob/bda95dfbe75c68f5c1b77a2f21c403cbe08548a2/hibernate-core/src/main/java/org/hibernate/boot/model/IdentifierGeneratorDefinition.java#L252
79+
boolean isStartOrIncrementField = field.equals("startValue") || field.equals("incrementBy");
80+
boolean isOneOrFiftyAndNull = "1".equals(refValue) && comparedValue == null || refValue == null && "1".equals(comparedValue) ||
81+
"50".equals(refValue) && comparedValue == null || refValue == null && "50".equals(comparedValue);
82+
83+
if ((isNameField && isCaseInsensitive && refValue != null && refValue.equalsIgnoreCase(comparedValue)) ||
84+
(isStartOrIncrementField && isOneOrFiftyAndNull)) {
85+
ignoredDifferenceFields.add(field);
86+
}
87+
}
88+
ignoredDifferenceFields.forEach(differences::removeDifference);
89+
}
90+
5991
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package liquibase.ext.hibernate.diff;
2+
3+
import liquibase.change.Change;
4+
import liquibase.database.Database;
5+
import liquibase.diff.ObjectDifferences;
6+
import liquibase.diff.output.DiffOutputControl;
7+
import liquibase.diff.output.changelog.ChangeGeneratorChain;
8+
import liquibase.ext.hibernate.database.HibernateDatabase;
9+
import liquibase.structure.DatabaseObject;
10+
import liquibase.structure.core.UniqueConstraint;
11+
12+
/**
13+
* Unique attribute for unique constraints backing index can have different values dependending on the database implementation,
14+
* so we suppress all unique constraint changes based on unique constraints.
15+
16+
*/
17+
public class ChangedUniqueConstraintChangeGenerator extends liquibase.diff.output.changelog.core.ChangedUniqueConstraintChangeGenerator {
18+
19+
@Override
20+
public int getPriority(Class<? extends DatabaseObject> objectType, Database database) {
21+
if (UniqueConstraint.class.isAssignableFrom(objectType)) {
22+
return PRIORITY_ADDITIONAL;
23+
}
24+
return PRIORITY_NONE;
25+
}
26+
27+
@Override
28+
public Change[] fixChanged(DatabaseObject changedObject, ObjectDifferences differences, DiffOutputControl control, Database referenceDatabase, Database comparisonDatabase, ChangeGeneratorChain chain) {
29+
if (referenceDatabase instanceof HibernateDatabase || comparisonDatabase instanceof HibernateDatabase) {
30+
differences.removeDifference("unique");
31+
if (!differences.hasDifferences()) {
32+
return null;
33+
}
34+
}
35+
return super.fixChanged(changedObject, differences, control, referenceDatabase, comparisonDatabase, chain);
36+
}
37+
}

src/main/java/liquibase/ext/hibernate/snapshot/UniqueConstraintSnapshotGenerator.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import java.math.BigInteger;
1616
import java.security.MessageDigest;
1717
import java.security.NoSuchAlgorithmException;
18-
import java.util.Iterator;
1918

2019
public class UniqueConstraintSnapshotGenerator extends HibernateSnapshotGenerator {
2120

@@ -54,7 +53,7 @@ protected void addTo(DatabaseObject foundObject, DatabaseSnapshot snapshot) thro
5453
Index index = getBackingIndex(uniqueConstraint, hibernateTable, snapshot);
5554
uniqueConstraint.setBackingIndex(index);
5655

57-
Scope.getCurrentScope().getLog(getClass()).info("Found unique constraint " + uniqueConstraint.toString());
56+
Scope.getCurrentScope().getLog(getClass()).info("Found unique constraint " + uniqueConstraint);
5857
table.getUniqueConstraints().add(uniqueConstraint);
5958
}
6059
for (var column : hibernateTable.getColumns()) {
@@ -68,7 +67,7 @@ protected void addTo(DatabaseObject foundObject, DatabaseSnapshot snapshot) thro
6867
}
6968
uniqueConstraint.addColumn(0, new Column(column.getName()).setRelation(table));
7069
uniqueConstraint.setName(name);
71-
Scope.getCurrentScope().getLog(getClass()).info("Found unique constraint " + uniqueConstraint.toString());
70+
Scope.getCurrentScope().getLog(getClass()).info("Found unique constraint " + uniqueConstraint);
7271
table.getUniqueConstraints().add(uniqueConstraint);
7372

7473
Index index = getBackingIndex(uniqueConstraint, hibernateTable, snapshot);
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
liquibase.ext.hibernate.diff.ChangedColumnChangeGenerator
22
liquibase.ext.hibernate.diff.ChangedForeignKeyChangeGenerator
3+
liquibase.ext.hibernate.diff.ChangedPrimaryKeyChangeGenerator
34
liquibase.ext.hibernate.diff.ChangedSequenceChangeGenerator
5+
liquibase.ext.hibernate.diff.ChangedUniqueConstraintChangeGenerator
46
liquibase.ext.hibernate.diff.MissingSequenceChangeGenerator
57
liquibase.ext.hibernate.diff.UnexpectedIndexChangeGenerator

0 commit comments

Comments
 (0)