[jOOQ/jOOQ#9506] More work on Migrations API:

- Handling of default schema in MigrationImpl::revertUntrackedQueries
- Use Settings.migrationHistorySchema in revertUntrackedQueries
- Improve logic to filter out history table from revertUntrackedQueries
- Set migration default schema as interpreter search path in History
- Suppress exceptions caused by history record re-insertion in case of
DataMigrationRedoLogException
- VersionImpl should apply CREATE SCHEMA IF NOT EXISTS to on init
- Remove weird initialisation of VersionImpl.meta with interpreter
search path
- Implement DefaultMigrationContext::toString
- Automatically set interpreter search path in Maven plugin
- GitCommitProvider should use same content type subdirs (in plural)
- Add commitProvider property to Maven plugin
- Upgrade jgit
- Allow for configuring a basedir within the GitConfiguration#repository
This commit is contained in:
Lukas Eder 2024-11-21 15:21:54 +01:00
parent f086212738
commit 1dd1205673
14 changed files with 236 additions and 92 deletions

View File

@ -37,9 +37,6 @@
*/
package org.jooq.migrations.maven;
import static org.apache.maven.plugins.annotations.LifecyclePhase.GENERATE_SOURCES;
import static org.apache.maven.plugins.annotations.ResolutionScope.TEST;
import java.io.File;
import org.jooq.CommitProvider;
@ -47,9 +44,9 @@ import org.jooq.Commits;
import org.jooq.Configuration;
import org.jooq.Migration;
import org.jooq.Migrations;
import org.jooq.impl.DefaultCommitProvider;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
/**
* A base class for {@link MigrateMojo},
@ -63,21 +60,18 @@ public abstract class AbstractMigrateMojo extends AbstractMigrationsMojo {
if (directory == null)
throw new MojoExecutionException("Directory was not provided");
Migrations migrations = configuration.dsl().migrations();
Commits commits = migrations.commits();
CommitProvider cp = configuration.commitProvider();
if (cp instanceof DefaultCommitProvider) {
Migrations migrations = configuration.dsl().migrations();
Commits commits = migrations.commits();
commits.load(file(directory));
}
// [#9506] TODO: Support loading directories recursively
// [#9506] TODO: Support loading **/*.sql style paths
// [#9506] TODO: Support relative paths, absolute paths, etc.
commits.load(file(directory));
// [#9506] TODO: Having to use this CommitsProvider "trick" isn't really
// user friendly. There must be a better way
Migration migration = configuration
.derive((CommitProvider) () -> commits)
.derive(cp)
.dsl()
.migrations()
.migrateTo(commits.latest());
.migrateTo(cp.provide().latest());
if (getLog().isInfoEnabled())
getLog().info(

View File

@ -46,9 +46,12 @@ import java.net.URLClassLoader;
import java.util.List;
import org.jooq.CloseableDSLContext;
import org.jooq.CommitProvider;
import org.jooq.Configuration;
import org.jooq.conf.InterpreterSearchSchema;
import org.jooq.conf.MigrationSchema;
import org.jooq.impl.DSL;
import org.jooq.impl.DefaultCommitProvider;
import org.jooq.tools.ClassUtils;
import org.jooq.tools.jdbc.JDBCUtils;
@ -146,6 +149,12 @@ abstract class AbstractMigrationsMojo extends AbstractMojo {
@Parameter(property = "jooq.migrate.historySchemaCreateSchemaIfNotExists")
boolean historySchemaCreateSchemaIfNotExists;
/**
* The {@link CommitProvider} implementation, defaulting to {@link DefaultCommitProvider}.
*/
@Parameter(property = "jooq.migrate.commitProvider")
String commitProvider;
@Override
public final void execute() throws MojoExecutionException {
if (skip) {
@ -174,13 +183,29 @@ abstract class AbstractMigrationsMojo extends AbstractMojo {
// Initialise Settings
// ---------------------------------------------------------------------
// TODO [#9506]: What are accepted constructor signatures?
if (commitProvider != null)
ctx.configuration().set((CommitProvider) ClassUtils
.loadClass(commitProvider)
.getConstructor(Configuration.class)
.newInstance(ctx.configuration())
);
ctx.settings().getMigrationSchemata().addAll(schemata);
if (defaultCatalog != null || defaultSchema != null)
ctx.settings().setMigrationDefaultSchema(new MigrationSchema()
.withCatalog(defaultIfNull(defaultCatalog, ""))
.withSchema(defaultIfNull(defaultSchema, ""))
);
if (defaultCatalog != null || defaultSchema != null) {
ctx.settings()
.withMigrationDefaultSchema(new MigrationSchema()
.withCatalog(defaultIfNull(defaultCatalog, ""))
.withSchema(defaultIfNull(defaultSchema, ""))
)
// [#9506] TODO: This should be automatic, even for programmatic usage
.withInterpreterSearchPath(new InterpreterSearchSchema()
.withCatalog(defaultIfNull(defaultCatalog, ""))
.withSchema(defaultIfNull(defaultSchema, ""))
);
}
if (historyCatalog != null || historySchema != null)
ctx.settings().setMigrationHistorySchema(new MigrationSchema()

View File

@ -83,7 +83,7 @@
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>6.6.1.202309021850-r</version>
<version>7.0.0.202409031743-r</version>
</dependency>
</dependencies>
</project>

View File

@ -65,6 +65,7 @@ import org.jooq.File;
import org.jooq.FilePattern;
import org.jooq.Migrations;
import org.jooq.tools.JooqLogger;
import org.jooq.tools.StringUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.Status;
@ -81,7 +82,6 @@ import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.util.io.DisabledOutputStream;
import org.jetbrains.annotations.NotNull;
/**
* A {@link CommitProvider} that produces versions from a git repository.
@ -98,12 +98,25 @@ public final class GitCommitProvider implements CommitProvider {
private final FilePattern incrementFilePattern;
private final FilePattern schemaFilePattern;
public GitCommitProvider(Configuration configuration) {
this(configuration, new GitConfiguration());
}
public GitCommitProvider(Configuration configuration, GitConfiguration git) {
this.dsl = configuration.dsl();
this.migrations = dsl.migrations();
this.git = git;
this.incrementFilePattern = new FilePattern().pattern(git.incrementFilePattern());
this.schemaFilePattern = new FilePattern().pattern(git.schemaFilePattern());
this.incrementFilePattern = new FilePattern().pattern(combine(git.basedir(), git.incrementFilePattern()));
this.schemaFilePattern = new FilePattern().pattern(combine(git.basedir(), git.schemaFilePattern()));
}
private static final String combine(String basedir, String pattern) {
if (StringUtils.isEmpty(basedir))
return pattern;
else if (basedir.endsWith("/"))
return basedir + pattern;
else
return basedir + "/" + pattern;
}
@Override
@ -115,6 +128,9 @@ public final class GitCommitProvider implements CommitProvider {
Repository r = g.getRepository();
ObjectReader reader = r.newObjectReader()
) {
// Prevent a "close() called when useCnt is already zero" warning
r.incrementOpen();
List<RevCommit> revCommits = new ArrayList<>();
Map<String, List<RevTag>> tags = new HashMap<>();
RevCommit last = null;
@ -311,24 +327,34 @@ public final class GitCommitProvider implements CommitProvider {
treeWalk.setRecursive(false);
while (treeWalk.next()) {
if (treeWalk.isSubtree()) {
String path = treeWalk.getPathString();
if (treeWalk.isSubtree() && include(path)) {
treeWalk.enterSubtree();
}
else {
ContentType contentType = contentType(treeWalk.getPathString());
ContentType contentType = contentType(path);
if (contentType != null)
if (contentType != null) {
files.add(migrations.file(
treeWalk.getPathString(),
read(repository, revCommit, treeWalk.getPathString()),
path,
read(repository, revCommit, path),
contentType
));
}
}
}
return files;
}
private final boolean include(String path) {
// [#9506] TODO: resolve . and ..
return git.basedir().startsWith(path)
|| path.startsWith(git.basedir());
}
private final String read(Repository repository, RevCommit commit, String path) throws IOException {
try (TreeWalk treeWalk = TreeWalk.forPath(repository, path, commit.getTree())) {
ObjectId blobId = treeWalk.getObjectId(0);

View File

@ -40,11 +40,6 @@ package org.jooq.migrations.jgit;
import static org.jooq.tools.StringUtils.defaultIfNull;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.jooq.Commit;
import org.jooq.tools.StringUtils;
@ -58,6 +53,7 @@ import org.jetbrains.annotations.NotNull;
public class GitConfiguration {
private final File repository;
private final String basedir;
private final String schemaFilePattern;
private final String incrementFilePattern;
private final String scriptFilePattern;
@ -71,12 +67,14 @@ public class GitConfiguration {
null,
null,
null,
null,
true
);
}
private GitConfiguration(
File repository,
String basedir,
String schemaFilePattern,
String incrementFilePattern,
String scriptFilePattern,
@ -84,10 +82,11 @@ public class GitConfiguration {
boolean includeUncommitted
) {
this.repository = repository != null ? repository : new File(".");
this.schemaFilePattern = defaultIfNull(schemaFilePattern, "migrations/schema/**");
this.incrementFilePattern = defaultIfNull(incrementFilePattern, "migrations/increment/**");
this.scriptFilePattern = defaultIfNull(scriptFilePattern, "migrations/script/**");
this.snapshotFilePattern = defaultIfNull(snapshotFilePattern, "migrations/snapshot/**");
this.basedir = basedir != null ? basedir : "src/main/resources";
this.schemaFilePattern = defaultIfNull(schemaFilePattern, "migrations/schemas/**");
this.incrementFilePattern = defaultIfNull(incrementFilePattern, "migrations/increments/**");
this.scriptFilePattern = defaultIfNull(scriptFilePattern, "migrations/scripts/**");
this.snapshotFilePattern = defaultIfNull(snapshotFilePattern, "migrations/snapshots/**");
this.includeUncommitted = includeUncommitted;
}
@ -98,6 +97,7 @@ public class GitConfiguration {
public final GitConfiguration repository(File newRepository) {
return new GitConfiguration(
newRepository,
basedir,
schemaFilePattern,
incrementFilePattern,
scriptFilePattern,
@ -114,6 +114,30 @@ public class GitConfiguration {
return repository;
}
/**
* The base directory of the migration scripts within the {@link #repository()}.
*/
@NotNull
public final GitConfiguration basedir(String newBasedir) {
return new GitConfiguration(
repository,
newBasedir,
schemaFilePattern,
incrementFilePattern,
scriptFilePattern,
snapshotFilePattern,
includeUncommitted
);
}
/**
* The base directory of the migration scripts within the {@link #repository()}.
*/
@NotNull
public final String basedir() {
return basedir;
}
/**
* The patterns of files in the repository to be searched for schema
* definition files.
@ -122,6 +146,7 @@ public class GitConfiguration {
public final GitConfiguration schemaFilePattern(String newSchemaFilePattern) {
return new GitConfiguration(
repository,
basedir,
newSchemaFilePattern,
incrementFilePattern,
scriptFilePattern,
@ -147,6 +172,7 @@ public class GitConfiguration {
public final GitConfiguration incrementFilePattern(String newIncrementFilePattern) {
return new GitConfiguration(
repository,
basedir,
schemaFilePattern,
newIncrementFilePattern,
scriptFilePattern,
@ -172,6 +198,7 @@ public class GitConfiguration {
public final GitConfiguration includeUncommitted(boolean newIncludeUncommitted) {
return new GitConfiguration(
repository,
basedir,
schemaFilePattern,
incrementFilePattern,
scriptFilePattern,

View File

@ -122,4 +122,17 @@ final class DefaultMigrationContext extends AbstractScope implements MigrationCo
final void query(Query q) {
this.query = q;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(
"MigrationContext for migration from: " + migrationFrom + " to " + migrationTo + "\n"
+ "Migration queries:\n" + migrationQueries
+ "Revert untracked queries:\n" + revertUntrackedQueries
);
return sb.toString();
}
}

View File

@ -22,7 +22,7 @@ import org.jooq.UniqueKey;
/**
* The migration history of jOOQ Migrations.
*/
@SuppressWarnings({ "all", "unchecked", "rawtypes" })
@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
class History extends TableImpl<HistoryRecord> {
private static final long serialVersionUID = 1L;
@ -64,6 +64,11 @@ class History extends TableImpl<HistoryRecord> {
*/
final TableField<HistoryRecord, String> MIGRATED_TO = createField(DSL.name("MIGRATED_TO"), SQLDataType.VARCHAR(255).nullable(false), this, "The current database version ID.");
/**
* The column <code>JOOQ_MIGRATION_HISTORY.MIGRATED_TO_MESSAGE</code>.
*/
final TableField<HistoryRecord, String> MIGRATED_TO_MESSAGE = createField(DSL.name("MIGRATED_TO_MESSAGE"), SQLDataType.CLOB.nullable(false), this, "");
/**
* The column <code>JOOQ_MIGRATION_HISTORY.MIGRATED_TO_TAGS</code>. The
* current database version tags, if any, in JSON array format.

View File

@ -139,7 +139,7 @@ class HistoryImpl extends AbstractScope implements History {
private final void addSchema(Set<Schema> set, MigrationSchema schema) {
if (schema != null)
set.addAll(lookup(asList(schema(name(schema.getCatalog(), schema.getSchema())))));
set.addAll(lookup(asList(MigrationImpl.schema(schema))));
}
final Collection<Schema> lookup(List<Schema> schemas) {
@ -187,6 +187,11 @@ class HistoryImpl extends AbstractScope implements History {
);
}
result.settings().withInterpreterSearchPath(new InterpreterSearchSchema()
.withCatalog(defaultSchema.getCatalog())
.withSchema(defaultSchema.getSchema())
);
return result;
}
else

View File

@ -12,7 +12,7 @@ import org.jooq.Record1;
/**
* The migration history of jOOQ Migrations.
*/
@SuppressWarnings({ "all", "unchecked", "rawtypes" })
@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
private static final long serialVersionUID = 1L;
@ -85,12 +85,27 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
return (String) get(3);
}
/**
* Setter for <code>JOOQ_MIGRATION_HISTORY.MIGRATED_TO_MESSAGE</code>.
*/
HistoryRecord setMigratedToMessage(String value) {
set(4, value);
return this;
}
/**
* Getter for <code>JOOQ_MIGRATION_HISTORY.MIGRATED_TO_MESSAGE</code>.
*/
String getMigratedToMessage() {
return (String) get(4);
}
/**
* Setter for <code>JOOQ_MIGRATION_HISTORY.MIGRATED_TO_TAGS</code>. The
* current database version tags, if any, in JSON array format.
*/
HistoryRecord setMigratedToTags(String value) {
set(4, value);
set(5, value);
return this;
}
@ -99,7 +114,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* current database version tags, if any, in JSON array format.
*/
String getMigratedToTags() {
return (String) get(4);
return (String) get(5);
}
/**
@ -107,7 +122,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* in milliseconds it took to migrate to this database version.
*/
HistoryRecord setMigrationTime(Long value) {
set(5, value);
set(6, value);
return this;
}
@ -116,7 +131,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* in milliseconds it took to migrate to this database version.
*/
Long getMigrationTime() {
return (Long) get(5);
return (Long) get(6);
}
/**
@ -124,7 +139,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* version used to migrate to this database version.
*/
HistoryRecord setJooqVersion(String value) {
set(6, value);
set(7, value);
return this;
}
@ -133,7 +148,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* version used to migrate to this database version.
*/
String getJooqVersion() {
return (String) get(6);
return (String) get(7);
}
/**
@ -141,7 +156,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* that were run to install this database version.
*/
HistoryRecord setSql(String value) {
set(7, value);
set(8, value);
return this;
}
@ -150,7 +165,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* that were run to install this database version.
*/
String getSql() {
return (String) get(7);
return (String) get(8);
}
/**
@ -158,7 +173,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* SQL statements that were run to install this database version.
*/
HistoryRecord setSqlCount(Integer value) {
set(8, value);
set(9, value);
return this;
}
@ -167,7 +182,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* SQL statements that were run to install this database version.
*/
Integer getSqlCount() {
return (Integer) get(8);
return (Integer) get(9);
}
/**
@ -175,7 +190,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* version installation status.
*/
HistoryRecord setStatus(HistoryStatus value) {
set(9, value);
set(10, value);
return this;
}
@ -184,7 +199,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* version installation status.
*/
HistoryStatus getStatus() {
return (HistoryStatus) get(9);
return (HistoryStatus) get(10);
}
/**
@ -192,7 +207,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* or error message explaining the status.
*/
HistoryRecord setStatusMessage(String value) {
set(10, value);
set(11, value);
return this;
}
@ -201,7 +216,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* or error message explaining the status.
*/
String getStatusMessage() {
return (String) get(10);
return (String) get(11);
}
/**
@ -209,7 +224,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* resolution, if any.
*/
HistoryRecord setResolution(HistoryResolution value) {
set(11, value);
set(12, value);
return this;
}
@ -218,7 +233,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* resolution, if any.
*/
HistoryResolution getResolution() {
return (HistoryResolution) get(11);
return (HistoryResolution) get(12);
}
/**
@ -226,7 +241,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* info or error message explaining the resolution.
*/
HistoryRecord setResolutionMessage(String value) {
set(12, value);
set(13, value);
return this;
}
@ -235,7 +250,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* info or error message explaining the resolution.
*/
String getResolutionMessage() {
return (String) get(12);
return (String) get(13);
}
// -------------------------------------------------------------------------
@ -261,13 +276,14 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
/**
* Create a detached, initialised HistoryRecord
*/
HistoryRecord(Integer id, Timestamp migratedAt, String migratedFrom, String migratedTo, String migratedToTags, Long migrationTime, String jooqVersion, String sql, Integer sqlCount, HistoryStatus status, String statusMessage, HistoryResolution resolution, String resolutionMessage) {
HistoryRecord(Integer id, Timestamp migratedAt, String migratedFrom, String migratedTo, String migratedToMessage, String migratedToTags, Long migrationTime, String jooqVersion, String sql, Integer sqlCount, HistoryStatus status, String statusMessage, HistoryResolution resolution, String resolutionMessage) {
super(History.HISTORY);
setId(id);
setMigratedAt(migratedAt);
setMigratedFrom(migratedFrom);
setMigratedTo(migratedTo);
setMigratedToMessage(migratedToMessage);
setMigratedToTags(migratedToTags);
setMigrationTime(migrationTime);
setJooqVersion(jooqVersion);

View File

@ -12,7 +12,7 @@ import org.jooq.Schema;
/**
* This class is generated by jOOQ.
*/
@SuppressWarnings({ "all", "unchecked", "rawtypes" })
@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
public enum HistoryResolution implements EnumType {
OPEN("OPEN"),

View File

@ -12,7 +12,7 @@ import org.jooq.Schema;
/**
* This class is generated by jOOQ.
*/
@SuppressWarnings({ "all", "unchecked", "rawtypes" })
@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
public enum HistoryStatus implements EnumType {
STARTING("STARTING"),

View File

@ -39,9 +39,12 @@ package org.jooq.impl;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import static java.util.function.Predicate.not;
import static org.jooq.impl.DSL.createSchemaIfNotExists;
import static org.jooq.impl.DSL.dropSchemaIfExists;
import static org.jooq.impl.DSL.dropTableIfExists;
import static org.jooq.impl.DSL.name;
import static org.jooq.impl.DSL.table;
import static org.jooq.impl.History.HISTORY;
import static org.jooq.impl.HistoryImpl.initCtx;
import static org.jooq.impl.HistoryResolution.OPEN;
@ -50,6 +53,7 @@ import static org.jooq.impl.HistoryStatus.MIGRATING;
import static org.jooq.impl.HistoryStatus.REVERTING;
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 java.io.PrintWriter;
@ -57,6 +61,7 @@ import java.io.StringWriter;
import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
import org.jooq.Commit;
import org.jooq.Commits;
@ -71,7 +76,11 @@ import org.jooq.MigrationListener;
import org.jooq.Queries;
import org.jooq.Query;
import org.jooq.Schema;
import org.jooq.Table;
import org.jooq.Tag;
import org.jooq.conf.InterpreterSearchSchema;
import org.jooq.conf.MigrationSchema;
import org.jooq.exception.DataAccessException;
import org.jooq.exception.DataMigrationException;
import org.jooq.exception.DataMigrationVerificationException;
import org.jooq.tools.JooqLogger;
@ -101,6 +110,10 @@ final class MigrationImpl extends AbstractScope implements Migration {
this.history = new HistoryImpl(configuration());
}
static final Schema schema(MigrationSchema schema) {
return new SchemaImpl(name(schema.getCatalog(), schema.getSchema()));
}
@Override
public final Commit from() {
if (from == null)
@ -184,23 +197,39 @@ final class MigrationImpl extends AbstractScope implements Migration {
}
private final Queries revertUntrackedQueries(Set<Schema> includedSchemas) {
MigrationSchema hs = settings().getMigrationHistorySchema();
MigrationSchema ds = settings().getMigrationDefaultSchema();
Set<Table<?>> historyTables = new HashSet<>();
if (hs != null || ds != null)
historyTables.add(table(schema(hs != null ? hs : ds).getQualifiedName().append(HISTORY.getUnqualifiedName())));
else
historyTables.addAll(map(includedSchemas, s -> table(s.getQualifiedName().append(HISTORY.getUnqualifiedName()))));
Commit currentCommit = currentCommit();
Meta currentMeta = currentCommit.meta();
Meta existingMeta = dsl().meta().filterSchemas(includedSchemas::contains);
Meta existingMeta = dsl().meta()
.filterSchemas(includedSchemas::contains)
.filterTables(not(historyTables::contains));
Set<Schema> expectedSchemas = new HashSet<>();
expectedSchemas.addAll(history.lookup(from().meta().getSchemas()));
expectedSchemas.addAll(history.lookup(to().meta().getSchemas()));
expectedSchemas.retainAll(includedSchemas);
if (ds != null) {
Schema d = DEFAULT_SCHEMA.get();
if (expectedSchemas.contains(d) && includedSchemas.contains(d))
expectedSchemas.add(schema(ds));
}
schemaLoop:
for (Schema schema : existingMeta.getSchemas()) {
if (!includedSchemas.contains(schema))
continue schemaLoop;
// TODO Why is this qualification necessary?
existingMeta = existingMeta.apply(dropTableIfExists(schema.getQualifiedName().append(HISTORY.getUnqualifiedName())).cascade());
if (!expectedSchemas.contains(schema))
existingMeta = existingMeta.apply(dropSchemaIfExists(schema).cascade());
else
@ -347,6 +376,7 @@ final class MigrationImpl extends AbstractScope implements Migration {
.setMigratedAt(new Timestamp(dsl().configuration().clock().instant().toEpochMilli()))
.setMigratedFrom(from().id())
.setMigratedTo(to().id())
.setMigratedToMessage(to().message())
.setMigratedToTags(new JSONArray(map(to().tags(), Tag::id)).toString())
.setMigrationTime(0L)
.setSql(queries().toString())
@ -426,13 +456,18 @@ final class MigrationImpl extends AbstractScope implements Migration {
dsl().transaction(runnable);
}
catch (DataMigrationRedoLogException e) {
try {
// [#9506] Make sure history record is re-created in case it was rolled back.
HistoryRecord record = history.currentHistoryRecord(false);
// [#9506] Make sure history record is re-created in case it was rolled back.
HistoryRecord record = history.currentHistoryRecord(false);
if (record == null || !StringUtils.equals(e.record.getId(), record.getId())) {
e.record.touched(true);
e.record.insert();
if (record == null || !StringUtils.equals(e.record.getId(), record.getId())) {
e.record.touched(true);
e.record.insert();
}
}
catch (DataAccessException s) {
e.addSuppressed(s);
}
if (e.getCause() instanceof DataMigrationException r)

View File

@ -41,8 +41,7 @@ import static java.lang.Boolean.TRUE;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static org.jooq.impl.DSL.createSchema;
import static org.jooq.impl.DSL.name;
import static org.jooq.impl.DSL.schema;
import static org.jooq.impl.DSL.createSchemaIfNotExists;
import static org.jooq.impl.Tools.anyMatch;
import static org.jooq.impl.Tools.map;
@ -60,6 +59,7 @@ import org.jooq.Query;
import org.jooq.Source;
import org.jooq.Version;
import org.jooq.conf.InterpreterSearchSchema;
import org.jooq.conf.MigrationSchema;
import org.jooq.exception.DataDefinitionException;
/**
@ -82,12 +82,9 @@ final class VersionImpl extends AbstractNode<Version> implements Version {
private static final Meta init(DSLContext ctx) {
Meta result = ctx.meta("");
// TODO: Instead of reusing interpreter search path, we should have some dedicated
// configuration for this.
// TODO: Should this be moved in DSLContext.meta()?
List<InterpreterSearchSchema> searchPath = ctx.settings().getInterpreterSearchPath();
for (InterpreterSearchSchema schema : searchPath)
result = result.apply(createSchema(schema(name(schema.getCatalog(), schema.getSchema()))));
MigrationSchema ds = ctx.settings().getMigrationDefaultSchema();
if (ds != null)
result = result.apply(createSchemaIfNotExists(MigrationImpl.schema(ds)));
return result;
}

View File

@ -1,17 +1,18 @@
CREATE TABLE jooq_migration_history (
id BIGINT NOT NULL IDENTITY,
migrated_at TIMESTAMP NOT NULL,
migrated_from VARCHAR(255) NOT NULL,
migrated_to VARCHAR(255) NOT NULL,
migrated_to_tags CLOB NOT NULL,
migration_time BIGINT NULL,
jooq_version VARCHAR(50) NOT NULL,
sql CLOB NULL,
sql_count INT NOT NULL,
status VARCHAR(10) NOT NULL,
status_message CLOB NULL,
resolution VARCHAR(10) NULL,
resolution_message CLOB NULL,
id BIGINT NOT NULL IDENTITY,
migrated_at TIMESTAMP NOT NULL,
migrated_from VARCHAR(255) NOT NULL,
migrated_to VARCHAR(255) NOT NULL,
migrated_to_message CLOB NOT NULL,
migrated_to_tags CLOB NOT NULL,
migration_time BIGINT NULL,
jooq_version VARCHAR(50) NOT NULL,
sql CLOB NULL,
sql_count INT NOT NULL,
status VARCHAR(10) NOT NULL,
status_message CLOB NULL,
resolution VARCHAR(10) NULL,
resolution_message CLOB NULL,
CONSTRAINT jooq_migr_hist_pk PRIMARY KEY (id),
CONSTRAINT jooq_migr_hist_chk1 CHECK (status IN ('STARTING', 'REVERTING', 'MIGRATING', 'SUCCESS', 'FAILURE')),