[jOOQ/jOOQ#9506] [jOOQ/jOOQ#17646] Diff should ignore constraint changes where (synthetically) named constraint is replaced by an equivalent unnamed constraint.

Users may use unnamed constraints in migration scripts. When comparing the schema with the existing schema in the database, we must ignore the database's synthetic constraint names.
This commit is contained in:
Lukas Eder 2024-11-21 16:30:45 +01:00
parent 6c957454fd
commit 2406f7ec50
5 changed files with 70 additions and 7 deletions

View File

@ -214,8 +214,14 @@ abstract class AbstractMigrationsMojo extends AbstractMojo {
);
ctx.settings().setMigrationSchemataCreateSchemaIfNotExists(schemataCreateSchemaIfNotExists);
ctx.settings().setMigrationHistorySchemaCreateSchemaIfNotExists(historySchemaCreateSchemaIfNotExists);
ctx.settings()
.withMigrationSchemataCreateSchemaIfNotExists(schemataCreateSchemaIfNotExists)
.withMigrationHistorySchemaCreateSchemaIfNotExists(historySchemaCreateSchemaIfNotExists)
// [#9506] [#17646] Users may use unnamed constraints in migration scripts.
// When comparing the schema with the existing schema in the database,
// we must ignore the database's synthetic constraint names.
.withMigrationIgnoreUnnamedConstraintDiffs(true);
// Initialise connection
// ---------------------------------------------------------------------

View File

@ -491,6 +491,8 @@ public class Settings
protected Boolean migrationAutoVerification = true;
@XmlElement(defaultValue = "true")
protected Boolean migrationIgnoreDefaultTimestampPrecisionDiffs = true;
@XmlElement(defaultValue = "false")
protected Boolean migrationIgnoreUnnamedConstraintDiffs = false;
@XmlElement(type = String.class)
@XmlJavaTypeAdapter(LocaleAdapter.class)
protected Locale locale;
@ -6312,6 +6314,30 @@ public class Settings
this.migrationIgnoreDefaultTimestampPrecisionDiffs = value;
}
/**
* Various <code>migrateTo()</code> methods (e.g. {@link org.jooq.Meta#migrateTo(org.jooq.Meta)}) ignore the difference between (possibly synthetically) name constraints and unnamed constraints, if the structure of the constraint is the same.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isMigrationIgnoreUnnamedConstraintDiffs() {
return migrationIgnoreUnnamedConstraintDiffs;
}
/**
* Various <code>migrateTo()</code> methods (e.g. {@link org.jooq.Meta#migrateTo(org.jooq.Meta)}) ignore the difference between (possibly synthetically) name constraints and unnamed constraints, if the structure of the constraint is the same.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setMigrationIgnoreUnnamedConstraintDiffs(Boolean value) {
this.migrationIgnoreUnnamedConstraintDiffs = value;
}
/**
* The Locale to be used with any locale dependent logic if there is not a more specific locale available. More specific locales include e.g. {@link #getRenderLocale()}, {@link #getParseLocale()}, or {@link #getInterpreterLocale()}.
*
@ -9376,6 +9402,15 @@ public class Settings
return this;
}
/**
* Various <code>migrateTo()</code> methods (e.g. {@link org.jooq.Meta#migrateTo(org.jooq.Meta)}) ignore the difference between (possibly synthetically) name constraints and unnamed constraints, if the structure of the constraint is the same.
*
*/
public Settings withMigrationIgnoreUnnamedConstraintDiffs(Boolean value) {
setMigrationIgnoreUnnamedConstraintDiffs(value);
return this;
}
/**
* The Locale to be used with any locale dependent logic if there is not a more specific locale available. More specific locales include e.g. {@link #getRenderLocale()}, {@link #getParseLocale()}, or {@link #getInterpreterLocale()}.
*
@ -9891,6 +9926,7 @@ public class Settings
builder.append("migrationAutoBaseline", migrationAutoBaseline);
builder.append("migrationAutoVerification", migrationAutoVerification);
builder.append("migrationIgnoreDefaultTimestampPrecisionDiffs", migrationIgnoreDefaultTimestampPrecisionDiffs);
builder.append("migrationIgnoreUnnamedConstraintDiffs", migrationIgnoreUnnamedConstraintDiffs);
builder.append("locale", locale);
builder.append("parseDialect", parseDialect);
builder.append("parseLocale", parseLocale);
@ -11776,6 +11812,15 @@ public class Settings
return false;
}
}
if (migrationIgnoreUnnamedConstraintDiffs == null) {
if (other.migrationIgnoreUnnamedConstraintDiffs!= null) {
return false;
}
} else {
if (!migrationIgnoreUnnamedConstraintDiffs.equals(other.migrationIgnoreUnnamedConstraintDiffs)) {
return false;
}
}
if (locale == null) {
if (other.locale!= null) {
return false;
@ -12239,6 +12284,7 @@ public class Settings
result = ((prime*result)+((migrationAutoBaseline == null)? 0 :migrationAutoBaseline.hashCode()));
result = ((prime*result)+((migrationAutoVerification == null)? 0 :migrationAutoVerification.hashCode()));
result = ((prime*result)+((migrationIgnoreDefaultTimestampPrecisionDiffs == null)? 0 :migrationIgnoreDefaultTimestampPrecisionDiffs.hashCode()));
result = ((prime*result)+((migrationIgnoreUnnamedConstraintDiffs == null)? 0 :migrationIgnoreUnnamedConstraintDiffs.hashCode()));
result = ((prime*result)+((locale == null)? 0 :locale.hashCode()));
result = ((prime*result)+((parseDialect == null)? 0 :parseDialect.hashCode()));
result = ((prime*result)+((parseLocale == null)? 0 :parseLocale.hashCode()));

View File

@ -38,6 +38,7 @@
package org.jooq.impl;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import static java.util.Arrays.asList;
// ...
import static org.jooq.SQLDialect.IGNITE;
@ -533,15 +534,20 @@ final class Diff {
return (r, k1, k2) -> {
Name n1 = k1.getUnqualifiedName();
Name n2 = k2.getUnqualifiedName();
boolean allowRenames = true;
if (n1.empty() ^ n2.empty()) {
drop.drop(r, k1);
create.create(r, k2);
if (n1.empty() || !TRUE.equals(ctx.settings().isMigrationIgnoreUnnamedConstraintDiffs())) {
drop.drop(r, k1);
create.create(r, k2);
return;
return;
}
else
allowRenames = false;
}
if (NAMED_COMP.compare(k1, k2) != 0)
if (allowRenames && NAMED_COMP.compare(k1, k2) != 0)
// [#10813] Don't rename constraints in MySQL
if (type != PRIMARY_KEY || !NO_SUPPORT_PK_NAMES.contains(ctx.dialect()))

View File

@ -55,6 +55,7 @@ import static org.jooq.impl.HistoryStatus.STARTING;
import static org.jooq.impl.HistoryStatus.SUCCESS;
import static org.jooq.impl.SchemaImpl.DEFAULT_SCHEMA;
import static org.jooq.impl.Tools.map;
import static org.jooq.tools.StringUtils.isEmpty;
import java.io.PrintWriter;
import java.io.StringWriter;
@ -181,7 +182,7 @@ final class MigrationImpl extends AbstractScope implements Migration {
throw new DataMigrationVerificationException("Commit is not available from CommitProvider: " + commit.id());
for (Schema schema : history.lookup(commit.meta().getSchemas()))
if (!ctx.migratedSchemas().contains(schema))
if (!isEmpty(schema.getName()) && !ctx.migratedSchemas().contains(schema))
throw new DataMigrationVerificationException(
"""
Schema is referenced from commit, but not configured for migration: {schema}.

View File

@ -1563,6 +1563,10 @@ deployed on an RDBMS that does not.]]></jxb:javadoc></jxb:property></appinfo></a
<element name="migrationIgnoreDefaultTimestampPrecisionDiffs" type="boolean" minOccurs="0" maxOccurs="1" default="true">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Various <code>migrateTo()</code> methods (e.g. {@link org.jooq.Meta#migrateTo(org.jooq.Meta)}) ignore the difference between <code>TIMESTAMP</code> and <code>TIMESTAMP(6)</code>, if 6 is the default precision for timestamps on the configured dialect.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="migrationIgnoreUnnamedConstraintDiffs" type="boolean" minOccurs="0" maxOccurs="1" default="false">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Various <code>migrateTo()</code> methods (e.g. {@link org.jooq.Meta#migrateTo(org.jooq.Meta)}) ignore the difference between (possibly synthetically) name constraints and unnamed constraints, if the structure of the constraint is the same.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="locale" type="string" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The Locale to be used with any locale dependent logic if there is not a more specific locale available. More specific locales include e.g. {@link #getRenderLocale()}, {@link #getParseLocale()}, or {@link #getInterpreterLocale()}.]]></jxb:javadoc></jxb:property></appinfo></annotation>