From 1dd1205673a29b2d3bc1e14155aaccbc06586ca8 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Thu, 21 Nov 2024 15:21:54 +0100 Subject: [PATCH] [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 --- .../migrations/maven/AbstractMigrateMojo.java | 24 +++----- .../maven/AbstractMigrationsMojo.java | 35 ++++++++++-- jOOQ-migrations/pom.xml | 2 +- .../migrations/jgit/GitCommitProvider.java | 42 +++++++++++--- .../migrations/jgit/GitConfiguration.java | 45 ++++++++++++--- .../jooq/impl/DefaultMigrationContext.java | 13 +++++ jOOQ/src/main/java/org/jooq/impl/History.java | 7 ++- .../main/java/org/jooq/impl/HistoryImpl.java | 7 ++- .../java/org/jooq/impl/HistoryRecord.java | 56 ++++++++++++------- .../java/org/jooq/impl/HistoryResolution.java | 2 +- .../java/org/jooq/impl/HistoryStatus.java | 2 +- .../java/org/jooq/impl/MigrationImpl.java | 53 +++++++++++++++--- .../main/java/org/jooq/impl/VersionImpl.java | 13 ++--- .../resources/org/jooq/migrations/v1-init.sql | 27 ++++----- 14 files changed, 236 insertions(+), 92 deletions(-) diff --git a/jOOQ-migrations-maven/src/main/java/org/jooq/migrations/maven/AbstractMigrateMojo.java b/jOOQ-migrations-maven/src/main/java/org/jooq/migrations/maven/AbstractMigrateMojo.java index 38f975e3e1..5be5352eb8 100644 --- a/jOOQ-migrations-maven/src/main/java/org/jooq/migrations/maven/AbstractMigrateMojo.java +++ b/jOOQ-migrations-maven/src/main/java/org/jooq/migrations/maven/AbstractMigrateMojo.java @@ -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( diff --git a/jOOQ-migrations-maven/src/main/java/org/jooq/migrations/maven/AbstractMigrationsMojo.java b/jOOQ-migrations-maven/src/main/java/org/jooq/migrations/maven/AbstractMigrationsMojo.java index aeea98a49e..0257944ad7 100644 --- a/jOOQ-migrations-maven/src/main/java/org/jooq/migrations/maven/AbstractMigrationsMojo.java +++ b/jOOQ-migrations-maven/src/main/java/org/jooq/migrations/maven/AbstractMigrationsMojo.java @@ -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() diff --git a/jOOQ-migrations/pom.xml b/jOOQ-migrations/pom.xml index 0debf7c4a4..587719b2dd 100644 --- a/jOOQ-migrations/pom.xml +++ b/jOOQ-migrations/pom.xml @@ -83,7 +83,7 @@ org.eclipse.jgit org.eclipse.jgit - 6.6.1.202309021850-r + 7.0.0.202409031743-r \ No newline at end of file diff --git a/jOOQ-migrations/src/main/java/org/jooq/migrations/jgit/GitCommitProvider.java b/jOOQ-migrations/src/main/java/org/jooq/migrations/jgit/GitCommitProvider.java index 5d8add5930..91f2e8d092 100644 --- a/jOOQ-migrations/src/main/java/org/jooq/migrations/jgit/GitCommitProvider.java +++ b/jOOQ-migrations/src/main/java/org/jooq/migrations/jgit/GitCommitProvider.java @@ -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 revCommits = new ArrayList<>(); Map> 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); diff --git a/jOOQ-migrations/src/main/java/org/jooq/migrations/jgit/GitConfiguration.java b/jOOQ-migrations/src/main/java/org/jooq/migrations/jgit/GitConfiguration.java index c4e8cc02cf..d2ed6e16f5 100644 --- a/jOOQ-migrations/src/main/java/org/jooq/migrations/jgit/GitConfiguration.java +++ b/jOOQ-migrations/src/main/java/org/jooq/migrations/jgit/GitConfiguration.java @@ -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, diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultMigrationContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultMigrationContext.java index 9e61dd0c5c..b8848266ae 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultMigrationContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultMigrationContext.java @@ -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(); + } } diff --git a/jOOQ/src/main/java/org/jooq/impl/History.java b/jOOQ/src/main/java/org/jooq/impl/History.java index 33c01d1580..b5cbd7d1d1 100644 --- a/jOOQ/src/main/java/org/jooq/impl/History.java +++ b/jOOQ/src/main/java/org/jooq/impl/History.java @@ -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 { private static final long serialVersionUID = 1L; @@ -64,6 +64,11 @@ class History extends TableImpl { */ final TableField MIGRATED_TO = createField(DSL.name("MIGRATED_TO"), SQLDataType.VARCHAR(255).nullable(false), this, "The current database version ID."); + /** + * The column JOOQ_MIGRATION_HISTORY.MIGRATED_TO_MESSAGE. + */ + final TableField MIGRATED_TO_MESSAGE = createField(DSL.name("MIGRATED_TO_MESSAGE"), SQLDataType.CLOB.nullable(false), this, ""); + /** * The column JOOQ_MIGRATION_HISTORY.MIGRATED_TO_TAGS. The * current database version tags, if any, in JSON array format. diff --git a/jOOQ/src/main/java/org/jooq/impl/HistoryImpl.java b/jOOQ/src/main/java/org/jooq/impl/HistoryImpl.java index a862451fc6..826ba186c3 100644 --- a/jOOQ/src/main/java/org/jooq/impl/HistoryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/HistoryImpl.java @@ -139,7 +139,7 @@ class HistoryImpl extends AbstractScope implements History { private final void addSchema(Set 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 lookup(List 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 diff --git a/jOOQ/src/main/java/org/jooq/impl/HistoryRecord.java b/jOOQ/src/main/java/org/jooq/impl/HistoryRecord.java index 7dab0c90e4..a1d13b45e8 100644 --- a/jOOQ/src/main/java/org/jooq/impl/HistoryRecord.java +++ b/jOOQ/src/main/java/org/jooq/impl/HistoryRecord.java @@ -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 { private static final long serialVersionUID = 1L; @@ -85,12 +85,27 @@ class HistoryRecord extends UpdatableRecordImpl { return (String) get(3); } + /** + * Setter for JOOQ_MIGRATION_HISTORY.MIGRATED_TO_MESSAGE. + */ + HistoryRecord setMigratedToMessage(String value) { + set(4, value); + return this; + } + + /** + * Getter for JOOQ_MIGRATION_HISTORY.MIGRATED_TO_MESSAGE. + */ + String getMigratedToMessage() { + return (String) get(4); + } + /** * Setter for JOOQ_MIGRATION_HISTORY.MIGRATED_TO_TAGS. 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 { * 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 { * 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 { * 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 { * 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 { * 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 { * 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 { * 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 { * 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 { * 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 { * version installation status. */ HistoryRecord setStatus(HistoryStatus value) { - set(9, value); + set(10, value); return this; } @@ -184,7 +199,7 @@ class HistoryRecord extends UpdatableRecordImpl { * version installation status. */ HistoryStatus getStatus() { - return (HistoryStatus) get(9); + return (HistoryStatus) get(10); } /** @@ -192,7 +207,7 @@ class HistoryRecord extends UpdatableRecordImpl { * 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 { * or error message explaining the status. */ String getStatusMessage() { - return (String) get(10); + return (String) get(11); } /** @@ -209,7 +224,7 @@ class HistoryRecord extends UpdatableRecordImpl { * resolution, if any. */ HistoryRecord setResolution(HistoryResolution value) { - set(11, value); + set(12, value); return this; } @@ -218,7 +233,7 @@ class HistoryRecord extends UpdatableRecordImpl { * resolution, if any. */ HistoryResolution getResolution() { - return (HistoryResolution) get(11); + return (HistoryResolution) get(12); } /** @@ -226,7 +241,7 @@ class HistoryRecord extends UpdatableRecordImpl { * 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 { * 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 { /** * 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); diff --git a/jOOQ/src/main/java/org/jooq/impl/HistoryResolution.java b/jOOQ/src/main/java/org/jooq/impl/HistoryResolution.java index 15cbcfdd95..eb938d9bd9 100644 --- a/jOOQ/src/main/java/org/jooq/impl/HistoryResolution.java +++ b/jOOQ/src/main/java/org/jooq/impl/HistoryResolution.java @@ -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"), diff --git a/jOOQ/src/main/java/org/jooq/impl/HistoryStatus.java b/jOOQ/src/main/java/org/jooq/impl/HistoryStatus.java index 08eb70a13f..e8147ab10d 100644 --- a/jOOQ/src/main/java/org/jooq/impl/HistoryStatus.java +++ b/jOOQ/src/main/java/org/jooq/impl/HistoryStatus.java @@ -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"), diff --git a/jOOQ/src/main/java/org/jooq/impl/MigrationImpl.java b/jOOQ/src/main/java/org/jooq/impl/MigrationImpl.java index 83703f9cdc..b5ac99d7d7 100644 --- a/jOOQ/src/main/java/org/jooq/impl/MigrationImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/MigrationImpl.java @@ -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 includedSchemas) { + MigrationSchema hs = settings().getMigrationHistorySchema(); + MigrationSchema ds = settings().getMigrationDefaultSchema(); + + Set> 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 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) diff --git a/jOOQ/src/main/java/org/jooq/impl/VersionImpl.java b/jOOQ/src/main/java/org/jooq/impl/VersionImpl.java index 1e36ff6571..b6ec3d227a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/VersionImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/VersionImpl.java @@ -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 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 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; } diff --git a/jOOQ/src/main/resources/org/jooq/migrations/v1-init.sql b/jOOQ/src/main/resources/org/jooq/migrations/v1-init.sql index 032827fd3d..c5a756b0e0 100644 --- a/jOOQ/src/main/resources/org/jooq/migrations/v1-init.sql +++ b/jOOQ/src/main/resources/org/jooq/migrations/v1-init.sql @@ -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')),