@@ -103,7 +100,6 @@
org.apache.maven.plugin-tools
maven-plugin-annotations
- 3.5.2
provided
diff --git a/jOOQ/src/main/java/org/jooq/Configuration.java b/jOOQ/src/main/java/org/jooq/Configuration.java
index 3a0847faa7..e8a9015803 100644
--- a/jOOQ/src/main/java/org/jooq/Configuration.java
+++ b/jOOQ/src/main/java/org/jooq/Configuration.java
@@ -284,6 +284,11 @@ public interface Configuration extends Serializable {
*/
MetaProvider metaProvider();
+ /**
+ * Get this configuration's underlying meta provider.
+ */
+ VersionProvider versionProvider();
+
/**
* Get this configuration's underlying executor provider.
*
@@ -499,6 +504,18 @@ public interface Configuration extends Serializable {
*/
Configuration set(MetaProvider newMetaProvider);
+ /**
+ * Change this configuration to hold a new version provider.
+ *
+ * This method is not thread-safe and should not be used in globally
+ * available Configuration objects.
+ *
+ * @param newVersionProvider The new version provider to be contained in the
+ * changed configuration.
+ * @return The changed configuration.
+ */
+ Configuration set(VersionProvider newVersionProvider);
+
/**
* Change this configuration to hold a new executor provider.
*
@@ -877,6 +894,15 @@ public interface Configuration extends Serializable {
*/
Configuration derive(MetaProvider newMetaProvider);
+ /**
+ * Create a derived configuration from this one, with a new version provider.
+ *
+ * @param newVersionProvider The new version provider to be contained in the
+ * derived configuration.
+ * @return The derived configuration.
+ */
+ Configuration derive(VersionProvider newVersionProvider);
+
/**
* Create a derived configuration from this one, with a new executor.
*
diff --git a/jOOQ/src/main/java/org/jooq/DSLContext.java b/jOOQ/src/main/java/org/jooq/DSLContext.java
index 9dbfedc9a5..5839be0fc0 100644
--- a/jOOQ/src/main/java/org/jooq/DSLContext.java
+++ b/jOOQ/src/main/java/org/jooq/DSLContext.java
@@ -253,6 +253,11 @@ public interface DSLContext extends Scope , AutoCloseable {
*/
Version version(String id);
+ /**
+ * Create a migration to a new version.
+ */
+ Migration migration(Version to);
+
/**
* Access the database meta data.
*
diff --git a/jOOQ/src/main/java/org/jooq/Migration.java b/jOOQ/src/main/java/org/jooq/Migration.java
new file mode 100644
index 0000000000..19d3c00def
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/Migration.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Other licenses:
+ * -----------------------------------------------------------------------------
+ * Commercial licenses for this work are available. These replace the above
+ * ASL 2.0 and offer limited warranties, support, maintenance, and commercial
+ * database integrations.
+ *
+ * For more information, please visit: http://www.jooq.org/licenses
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+package org.jooq;
+
+import org.jooq.exception.DataDefinitionException;
+
+/**
+ * An executable migration between two {@link Version} instances.
+ *
+ * @author Lukas Eder
+ */
+public interface Migration extends Scope {
+
+ /**
+ * The version that is being migrated from.
+ */
+ Version from();
+
+ /**
+ * The version that is being migrated to.
+ */
+ Version to();
+
+ /**
+ * The queries that are executed by the migration.
+ */
+ Queries queries();
+
+ /**
+ * Apply the migration.
+ *
+ * @throws DataDefinitionException When something went wrong during the
+ * application of the migration.
+ */
+ MigrationResult migrate() throws DataDefinitionException;
+}
diff --git a/jOOQ/src/main/java/org/jooq/MigrationResult.java b/jOOQ/src/main/java/org/jooq/MigrationResult.java
new file mode 100644
index 0000000000..bda6d6797a
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/MigrationResult.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Other licenses:
+ * -----------------------------------------------------------------------------
+ * Commercial licenses for this work are available. These replace the above
+ * ASL 2.0 and offer limited warranties, support, maintenance, and commercial
+ * database integrations.
+ *
+ * For more information, please visit: http://www.jooq.org/licenses
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+package org.jooq;
+
+/**
+ * The result of a {@link Migration}.
+ *
+ * @author Lukas Eder
+ */
+public interface MigrationResult {
+
+}
diff --git a/jOOQ/src/main/java/org/jooq/VersionProvider.java b/jOOQ/src/main/java/org/jooq/VersionProvider.java
new file mode 100644
index 0000000000..7b55c4e807
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/VersionProvider.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Other licenses:
+ * -----------------------------------------------------------------------------
+ * Commercial licenses for this work are available. These replace the above
+ * ASL 2.0 and offer limited warranties, support, maintenance, and commercial
+ * database integrations.
+ *
+ * For more information, please visit: http://www.jooq.org/licenses
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+package org.jooq;
+
+import java.util.Set;
+
+/**
+ * An SPI that allows for providing a graph of versions.
+ *
+ * @author Lukas Eder
+ */
+@Internal // TODO This SPI is still being worked on and might change incompatibly
+public interface VersionProvider {
+
+ /**
+ * Provide a set of versions relevant to a migration.
+ *
+ * This can include the entire set of known versions, or a subset thereof.
+ * There is no requirement to provide a fully connected graph, although
+ * {@link Version#migrateFrom(Version)} and other operations are undefined
+ * if two versions do not have a common ancestor.
+ */
+ @Internal // TODO Produce a better type than Set. Possibly, #current() can be obtained from the new result type.
+ Set provide();
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java b/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java
index 83c5c1c1de..52020b14a9 100644
--- a/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java
@@ -77,6 +77,7 @@ import org.jooq.TransactionListenerProvider;
import org.jooq.TransactionProvider;
import org.jooq.Unwrapper;
import org.jooq.UnwrapperProvider;
+import org.jooq.VersionProvider;
import org.jooq.VisitListener;
import org.jooq.VisitListenerProvider;
import org.jooq.conf.Settings;
@@ -112,6 +113,7 @@ public class DefaultConfiguration implements Configuration {
private transient ConnectionProvider interpreterConnectionProvider;
private transient ConnectionProvider systemConnectionProvider;
private transient MetaProvider metaProvider;
+ private transient VersionProvider versionProvider;
private transient ExecutorProvider executorProvider;
private transient TransactionProvider transactionProvider;
private transient RecordMapperProvider recordMapperProvider;
@@ -174,6 +176,7 @@ public class DefaultConfiguration implements Configuration {
null,
null,
null,
+ null,
null,
@@ -197,6 +200,7 @@ public class DefaultConfiguration implements Configuration {
configuration.interpreterConnectionProvider,
configuration.systemConnectionProvider,
configuration.metaProvider,
+ configuration.versionProvider,
configuration.executorProvider,
configuration.transactionProvider,
configuration.recordMapperProvider,
@@ -230,6 +234,7 @@ public class DefaultConfiguration implements Configuration {
ConnectionProvider interpreterConnectionProvider,
ConnectionProvider systemConnectionProvider,
MetaProvider metaProvider,
+ VersionProvider versionProvider,
ExecutorProvider executorProvider,
TransactionProvider transactionProvider,
RecordMapperProvider recordMapperProvider,
@@ -252,6 +257,7 @@ public class DefaultConfiguration implements Configuration {
setInterpreterConnectionProvider(interpreterConnectionProvider);
setSystemConnectionProvider(systemConnectionProvider);
set(metaProvider);
+ set(versionProvider);
set(executorProvider);
set(transactionProvider);
set(recordMapperProvider);
@@ -309,6 +315,7 @@ public class DefaultConfiguration implements Configuration {
interpreterConnectionProvider,
systemConnectionProvider,
metaProvider,
+ versionProvider,
executorProvider,
transactionProvider,
recordMapperProvider,
@@ -336,6 +343,35 @@ public class DefaultConfiguration implements Configuration {
interpreterConnectionProvider,
systemConnectionProvider,
newMetaProvider,
+ versionProvider,
+ executorProvider,
+ transactionProvider,
+ recordMapperProvider,
+ recordUnmapperProvider,
+ recordListenerProviders,
+ executeListenerProviders,
+ visitListenerProviders,
+ transactionListenerProviders,
+ diagnosticsListenerProviders,
+ unwrapperProvider,
+ converterProvider,
+
+ clock,
+
+ dialect,
+ settings,
+ data
+ );
+ }
+
+ @Override
+ public final Configuration derive(VersionProvider newVersionProvider) {
+ return new DefaultConfiguration(
+ connectionProvider,
+ interpreterConnectionProvider,
+ systemConnectionProvider,
+ metaProvider,
+ newVersionProvider,
executorProvider,
transactionProvider,
recordMapperProvider,
@@ -368,6 +404,7 @@ public class DefaultConfiguration implements Configuration {
interpreterConnectionProvider,
systemConnectionProvider,
metaProvider,
+ versionProvider,
newExecutorProvider,
transactionProvider,
recordMapperProvider,
@@ -395,6 +432,7 @@ public class DefaultConfiguration implements Configuration {
interpreterConnectionProvider,
systemConnectionProvider,
metaProvider,
+ versionProvider,
executorProvider,
newTransactionProvider,
recordMapperProvider,
@@ -427,6 +465,7 @@ public class DefaultConfiguration implements Configuration {
interpreterConnectionProvider,
systemConnectionProvider,
metaProvider,
+ versionProvider,
executorProvider,
transactionProvider,
newRecordMapperProvider,
@@ -459,6 +498,7 @@ public class DefaultConfiguration implements Configuration {
interpreterConnectionProvider,
systemConnectionProvider,
metaProvider,
+ versionProvider,
executorProvider,
transactionProvider,
recordMapperProvider,
@@ -491,6 +531,7 @@ public class DefaultConfiguration implements Configuration {
interpreterConnectionProvider,
systemConnectionProvider,
metaProvider,
+ versionProvider,
executorProvider,
transactionProvider,
recordMapperProvider,
@@ -523,6 +564,7 @@ public class DefaultConfiguration implements Configuration {
interpreterConnectionProvider,
systemConnectionProvider,
metaProvider,
+ versionProvider,
executorProvider,
transactionProvider,
recordMapperProvider,
@@ -555,6 +597,7 @@ public class DefaultConfiguration implements Configuration {
interpreterConnectionProvider,
systemConnectionProvider,
metaProvider,
+ versionProvider,
executorProvider,
transactionProvider,
recordMapperProvider,
@@ -587,6 +630,7 @@ public class DefaultConfiguration implements Configuration {
interpreterConnectionProvider,
systemConnectionProvider,
metaProvider,
+ versionProvider,
executorProvider,
transactionProvider,
recordMapperProvider,
@@ -619,6 +663,7 @@ public class DefaultConfiguration implements Configuration {
interpreterConnectionProvider,
systemConnectionProvider,
metaProvider,
+ versionProvider,
executorProvider,
transactionProvider,
recordMapperProvider,
@@ -651,6 +696,7 @@ public class DefaultConfiguration implements Configuration {
interpreterConnectionProvider,
systemConnectionProvider,
metaProvider,
+ versionProvider,
executorProvider,
transactionProvider,
recordMapperProvider,
@@ -678,6 +724,7 @@ public class DefaultConfiguration implements Configuration {
interpreterConnectionProvider,
systemConnectionProvider,
metaProvider,
+ versionProvider,
executorProvider,
transactionProvider,
recordMapperProvider,
@@ -706,6 +753,7 @@ public class DefaultConfiguration implements Configuration {
interpreterConnectionProvider,
systemConnectionProvider,
metaProvider,
+ versionProvider,
executorProvider,
transactionProvider,
recordMapperProvider,
@@ -732,6 +780,7 @@ public class DefaultConfiguration implements Configuration {
interpreterConnectionProvider,
systemConnectionProvider,
metaProvider,
+ versionProvider,
executorProvider,
transactionProvider,
recordMapperProvider,
@@ -759,6 +808,7 @@ public class DefaultConfiguration implements Configuration {
interpreterConnectionProvider,
systemConnectionProvider,
metaProvider,
+ versionProvider,
executorProvider,
transactionProvider,
recordMapperProvider,
@@ -817,6 +867,12 @@ public class DefaultConfiguration implements Configuration {
return this;
}
+ @Override
+ public final Configuration set(VersionProvider newVersionProvider) {
+ this.versionProvider = newVersionProvider;
+ return this;
+ }
+
@Override
public final Configuration set(Executor newExecutor) {
return set(new ExecutorWrapper(newExecutor));
@@ -1035,6 +1091,13 @@ public class DefaultConfiguration implements Configuration {
set(newMetaProvider);
}
+ /**
+ * @see #set(MetaProvider)
+ */
+ public final void setVersionProvider(VersionProvider newVersionProvider) {
+ set(newVersionProvider);
+ }
+
/**
* @see #set(Executor)
*/
@@ -1229,6 +1292,13 @@ public class DefaultConfiguration implements Configuration {
: new DefaultMetaProvider(this);
}
+ @Override
+ public final VersionProvider versionProvider() {
+ return versionProvider != null
+ ? versionProvider
+ : new DefaultVersionProvider(this);
+ }
+
@Override
public final ExecutorProvider executorProvider() {
return executorProvider != null
@@ -1379,6 +1449,9 @@ public class DefaultConfiguration implements Configuration {
oos.writeObject(metaProvider instanceof Serializable
? metaProvider
: null);
+ oos.writeObject(versionProvider instanceof Serializable
+ ? versionProvider
+ : null);
oos.writeObject(transactionProvider instanceof Serializable
? transactionProvider
: null);
@@ -1437,6 +1510,7 @@ public class DefaultConfiguration implements Configuration {
interpreterConnectionProvider = (ConnectionProvider) ois.readObject();
systemConnectionProvider = (ConnectionProvider) ois.readObject();
metaProvider = (MetaProvider) ois.readObject();
+ versionProvider = (VersionProvider) ois.readObject();
transactionProvider = (TransactionProvider) ois.readObject();
recordMapperProvider = (RecordMapperProvider) ois.readObject();
recordUnmapperProvider = (RecordUnmapperProvider) ois.readObject();
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java
index 83a0d48f96..1f5868f0ae 100644
--- a/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java
@@ -191,6 +191,7 @@ import org.jooq.MergeKeyStep9;
import org.jooq.MergeKeyStepN;
import org.jooq.MergeUsingStep;
import org.jooq.Meta;
+import org.jooq.Migration;
import org.jooq.Name;
import org.jooq.Param;
import org.jooq.Parser;
@@ -415,6 +416,11 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri
return new VersionImpl(this, id, null, new Version[0]);
}
+ @Override
+ public Migration migration(Version to) {
+ return new MigrationImpl(configuration, to);
+ }
+
@Override
public Meta meta() {
return configuration().metaProvider().provide();
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultVersionProvider.java b/jOOQ/src/main/java/org/jooq/impl/DefaultVersionProvider.java
new file mode 100644
index 0000000000..4dcfc684a3
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultVersionProvider.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Other licenses:
+ * -----------------------------------------------------------------------------
+ * Commercial licenses for this work are available. These replace the above
+ * ASL 2.0 and offer limited warranties, support, maintenance, and commercial
+ * database integrations.
+ *
+ * For more information, please visit: http://www.jooq.org/licenses
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+package org.jooq.impl;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.jooq.Configuration;
+import org.jooq.DSLContext;
+import org.jooq.Parser;
+import org.jooq.Source;
+import org.jooq.Version;
+import org.jooq.VersionProvider;
+
+/**
+ * A default implementation of the {@link VersionProvider} SPI, which provides
+ * a materialisation of the currently available database version graph.
+ *
+ * It is based
+ *
+ * @author Lukas Eder
+ */
+@org.jooq.Internal // TODO This is work in progress. The current implementation is not useful yet.
+public class DefaultVersionProvider implements VersionProvider {
+
+ private final DSLContext ctx;
+ private final Source[] sources;
+
+ public DefaultVersionProvider(Configuration configuration, Source... sources) {
+ this.ctx = configuration.dsl();
+ this.sources = sources;
+ }
+
+ @Override
+ public Set provide() {
+ Set result = new LinkedHashSet<>();
+ Version parent;
+ result.add(parent = ctx.version("initial"));
+
+ Parser parser = ctx.parser();
+ for (int i = 0; i < sources.length; i++)
+ parent = parent.apply("version" + (i + 1), parser.parse(sources[i].readString()));
+
+ return result;
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/MigrationImpl.java b/jOOQ/src/main/java/org/jooq/impl/MigrationImpl.java
new file mode 100644
index 0000000000..f88691fea2
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/MigrationImpl.java
@@ -0,0 +1,439 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Other licenses:
+ * -----------------------------------------------------------------------------
+ * Commercial licenses for this work are available. These replace the above
+ * ASL 2.0 and offer limited warranties, support, maintenance, and commercial
+ * database integrations.
+ *
+ * For more information, please visit: http://www.jooq.org/licenses
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+package org.jooq.impl;
+
+import java.sql.Timestamp;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.jooq.Configuration;
+import org.jooq.Constants;
+import org.jooq.ContextTransactionalCallable;
+import org.jooq.Field;
+import org.jooq.Identity;
+import org.jooq.Migration;
+import org.jooq.MigrationResult;
+import org.jooq.Name;
+import org.jooq.Queries;
+import org.jooq.Query;
+import org.jooq.Record1;
+import org.jooq.Schema;
+import org.jooq.Table;
+import org.jooq.TableField;
+import org.jooq.UniqueKey;
+import org.jooq.Version;
+import org.jooq.exception.DataAccessException;
+import org.jooq.exception.DataDefinitionException;
+import org.jooq.tools.JooqLogger;
+import org.jooq.tools.StopWatch;
+
+/**
+ * @author Lukas Eder
+ */
+final class MigrationImpl extends AbstractScope implements Migration {
+
+ private static final JooqLogger log = JooqLogger.getLogger(Migration.class);
+
+ // TODO: Make this table and its schema configurable
+ private static final JooqMigrationsChangelog CHANGELOG = JooqMigrationsChangelog.JOOQ_MIGRATIONS_CHANGELOG;
+ private final Version to;
+ private Version from;
+ private Queries queries;
+ private Map versions;
+
+ MigrationImpl(Configuration configuration, Version to) {
+ super(configuration.derive(new ThreadLocalTransactionProvider(configuration.systemConnectionProvider())));
+
+ this.to = to;
+ }
+
+ @Override
+ public final Version from() {
+ if (from == null) {
+
+ // TODO: Use pessimistic locking so no one else can migrate in between
+ JooqMigrationsChangelogRecord currentRecord =
+ dsl().selectFrom(CHANGELOG)
+ .orderBy(CHANGELOG.MIGRATED_AT.desc(), CHANGELOG.ID.desc())
+ .limit(1)
+ .fetchOne();
+
+ from = currentRecord == null ? to().root() : versions().get(currentRecord.getMigratedTo());
+ }
+
+ return from;
+ }
+
+ @Override
+ public final Version to() {
+ return to;
+ }
+
+ @Override
+ public final Queries queries() {
+ if (queries == null)
+ queries = to().migrateFrom(from());
+
+ return queries;
+ }
+
+ private final Map versions() {
+ if (versions == null) {
+ versions = new HashMap<>();
+
+ for (Version version : configuration().versionProvider().provide())
+ versions.put(version.id(), version);
+ }
+
+ return versions;
+ }
+
+ private static final MigrationResult MIGRATION_RESULT = new MigrationResult() {};
+
+ @Override
+ public final MigrationResult migrate() throws DataDefinitionException {
+ return run(new ContextTransactionalCallable() {
+ @Override
+ public MigrationResult run() {
+ if (from().equals(to())) {
+ log.info("jOOQ Migrations", "Version " + to().id() + " is already installed as the current version.");
+ return MIGRATION_RESULT;
+ }
+
+ log.info("jOOQ Migrations", "Version " + from().id() + " is migrated to " + to().id());
+
+ StopWatch watch = new StopWatch();
+
+ // TODO: Make logging configurable
+ if (log.isDebugEnabled())
+ for (Query query : queries())
+ log.debug("jOOQ Migrations", dsl().renderInlined(query));
+
+ // TODO: Make batching an option
+ queries().executeBatch();
+
+ JooqMigrationsChangelogRecord newRecord = dsl().newRecord(CHANGELOG);
+ newRecord
+ .setJooqVersion(Constants.VERSION)
+ .setMigratedAt(new Timestamp(System.currentTimeMillis()))
+ .setMigratedFrom(from().id())
+ .setMigratedTo(to().id())
+ .setMigrationTime(watch.split() / 1000000L)
+ .store();
+
+ return MIGRATION_RESULT;
+ }
+ });
+ }
+
+ /**
+ * Initialise the underlying {@link Configuration} with the jOOQ Migrations
+ * Changelog.
+ */
+ public final void init() {
+
+ // TODO: What to do when initialising jOOQ-migrations on an existing database?
+ // - Should there be init() commands that can be run explicitl by the user?
+ // - Will we reverse engineer the production Meta snapshot first?
+ if (!existsChangelog())
+ dsl().meta(CHANGELOG).ddl().executeBatch();
+ }
+
+ private final boolean existsChangelog() {
+
+ // [#8301] Find a better way to test if our table already exists
+ try {
+ dsl().fetchExists(CHANGELOG);
+ return true;
+ }
+ catch (DataAccessException ignore) {}
+
+ return false;
+ }
+
+ private final T run(final ContextTransactionalCallable runnable) {
+ init();
+ return dsl().transactionResult(runnable);
+ }
+
+ // -------------------------------------------------------------------------
+ // XXX: Generated code
+ // -------------------------------------------------------------------------
+
+ // These classes have been generated and copied here. It would be desirable:
+ // - [#6948] To be able to generate package private classes directly inside of other classes
+ // - [#7444] Alternatively, have a simple public API replacing TableImpl
+
+ /**
+ * The migration log of jOOQ Migrations.
+ */
+ @SuppressWarnings({ "all", "unchecked", "rawtypes" })
+ static class JooqMigrationsChangelog extends TableImpl {
+
+ private static final long serialVersionUID = 1147896779;
+
+ /**
+ * The reference instance of JOOQ_MIGRATIONS_CHANGELOG
+ */
+ public static final JooqMigrationsChangelog JOOQ_MIGRATIONS_CHANGELOG = new JooqMigrationsChangelog();
+
+ /**
+ * The class holding records for this type
+ */
+ @Override
+ public Class getRecordType() {
+ return JooqMigrationsChangelogRecord.class;
+ }
+
+ /**
+ * The column JOOQ_MIGRATIONS_CHANGELOG.ID. The database version ID.
+ */
+ public final TableField ID = createField(DSL.name("ID"), org.jooq.impl.SQLDataType.BIGINT.nullable(false).identity(true), this, "The database version ID.");
+
+ /**
+ * The column JOOQ_MIGRATIONS_CHANGELOG.MIGRATED_FROM. The previous database version ID.
+ */
+ public final TableField MIGRATED_FROM = createField(DSL.name("MIGRATED_FROM"), org.jooq.impl.SQLDataType.VARCHAR(255).nullable(false), this, "The previous database version ID.");
+
+ /**
+ * The column JOOQ_MIGRATIONS_CHANGELOG.MIGRATED_TO.
+ */
+ public final TableField MIGRATED_TO = createField(DSL.name("MIGRATED_TO"), org.jooq.impl.SQLDataType.VARCHAR(255).nullable(false), this, "");
+
+ /**
+ * The column JOOQ_MIGRATIONS_CHANGELOG.MIGRATED_AT. The date/time when the database version was migrated to.
+ */
+ public final TableField MIGRATED_AT = createField(DSL.name("MIGRATED_AT"), org.jooq.impl.SQLDataType.TIMESTAMP.precision(6).nullable(false), this, "The date/time when the database version was migrated to.");
+
+ /**
+ * The column JOOQ_MIGRATIONS_CHANGELOG.MIGRATION_TIME. The time in milliseconds it took to migrate to this database version.
+ */
+ public final TableField MIGRATION_TIME = createField(DSL.name("MIGRATION_TIME"), org.jooq.impl.SQLDataType.BIGINT, this, "The time in milliseconds it took to migrate to this database version.");
+
+ /**
+ * The column JOOQ_MIGRATIONS_CHANGELOG.JOOQ_VERSION. The jOOQ version used to migrate to this database version.
+ */
+ public final TableField JOOQ_VERSION = createField(DSL.name("JOOQ_VERSION"), org.jooq.impl.SQLDataType.VARCHAR(50).nullable(false), this, "The jOOQ version used to migrate to this database version.");
+
+ /**
+ * Create a JOOQ_MIGRATIONS_CHANGELOG table reference
+ */
+ public JooqMigrationsChangelog() {
+ this(DSL.name("JOOQ_MIGRATIONS_CHANGELOG"), null);
+ }
+
+ /**
+ * Create an aliased JOOQ_MIGRATIONS_CHANGELOG table reference
+ */
+ public JooqMigrationsChangelog(String alias) {
+ this(DSL.name(alias), JOOQ_MIGRATIONS_CHANGELOG);
+ }
+
+ /**
+ * Create an aliased JOOQ_MIGRATIONS_CHANGELOG table reference
+ */
+ public JooqMigrationsChangelog(Name alias) {
+ this(alias, JOOQ_MIGRATIONS_CHANGELOG);
+ }
+
+ private JooqMigrationsChangelog(Name alias, Table aliased) {
+ this(alias, aliased, null);
+ }
+
+ private JooqMigrationsChangelog(Name alias, Table aliased, Field>[] parameters) {
+ super(alias, null, aliased, parameters, DSL.comment("The migration log of jOOQ Migrations."));
+ }
+
+ @Override
+ public Schema getSchema() {
+ return new SchemaImpl("");
+ }
+
+ @Override
+ public Identity getIdentity() {
+ return Internal.createIdentity(JOOQ_MIGRATIONS_CHANGELOG, JOOQ_MIGRATIONS_CHANGELOG.ID);
+ }
+
+ @Override
+ public UniqueKey getPrimaryKey() {
+ return Internal.createUniqueKey(JOOQ_MIGRATIONS_CHANGELOG, "JOOQ_MIGRATIONS_CHANGELOG_PK", JOOQ_MIGRATIONS_CHANGELOG.ID);
+ }
+
+ @Override
+ public List> getKeys() {
+ return Arrays.>asList(
+ Internal.createUniqueKey(JOOQ_MIGRATIONS_CHANGELOG, "JOOQ_MIGRATIONS_CHANGELOG_PK", JOOQ_MIGRATIONS_CHANGELOG.ID)
+ );
+ }
+ }
+
+ /**
+ * The migration log of jOOQ Migrations.
+ */
+ @SuppressWarnings({ "all", "unchecked", "rawtypes" })
+ static class JooqMigrationsChangelogRecord extends UpdatableRecordImpl {
+
+ private static final long serialVersionUID = 2016380678;
+
+ /**
+ * Setter for JOOQ_MIGRATIONS_CHANGELOG.ID. The database version ID.
+ */
+ public JooqMigrationsChangelogRecord setId(Long value) {
+ set(0, value);
+ return this;
+ }
+
+ /**
+ * Getter for JOOQ_MIGRATIONS_CHANGELOG.ID. The database version ID.
+ */
+ public Long getId() {
+ return (Long) get(0);
+ }
+
+ /**
+ * Setter for JOOQ_MIGRATIONS_CHANGELOG.MIGRATED_FROM. The previous database version ID.
+ */
+ public JooqMigrationsChangelogRecord setMigratedFrom(String value) {
+ set(1, value);
+ return this;
+ }
+
+ /**
+ * Getter for JOOQ_MIGRATIONS_CHANGELOG.MIGRATED_FROM. The previous database version ID.
+ */
+ public String getMigratedFrom() {
+ return (String) get(1);
+ }
+
+ /**
+ * Setter for JOOQ_MIGRATIONS_CHANGELOG.MIGRATED_TO.
+ */
+ public JooqMigrationsChangelogRecord setMigratedTo(String value) {
+ set(2, value);
+ return this;
+ }
+
+ /**
+ * Getter for JOOQ_MIGRATIONS_CHANGELOG.MIGRATED_TO.
+ */
+ public String getMigratedTo() {
+ return (String) get(2);
+ }
+
+ /**
+ * Setter for JOOQ_MIGRATIONS_CHANGELOG.MIGRATED_AT. The date/time when the database version was migrated to.
+ */
+ public JooqMigrationsChangelogRecord setMigratedAt(Timestamp value) {
+ set(3, value);
+ return this;
+ }
+
+ /**
+ * Getter for JOOQ_MIGRATIONS_CHANGELOG.MIGRATED_AT. The date/time when the database version was migrated to.
+ */
+ public Timestamp getMigratedAt() {
+ return (Timestamp) get(3);
+ }
+
+ /**
+ * Setter for JOOQ_MIGRATIONS_CHANGELOG.MIGRATION_TIME. The time in milliseconds it took to migrate to this database version.
+ */
+ public JooqMigrationsChangelogRecord setMigrationTime(Long value) {
+ set(4, value);
+ return this;
+ }
+
+ /**
+ * Getter for JOOQ_MIGRATIONS_CHANGELOG.MIGRATION_TIME. The time in milliseconds it took to migrate to this database version.
+ */
+ public Long getMigrationTime() {
+ return (Long) get(4);
+ }
+
+ /**
+ * Setter for JOOQ_MIGRATIONS_CHANGELOG.JOOQ_VERSION. The jOOQ version used to migrate to this database version.
+ */
+ public JooqMigrationsChangelogRecord setJooqVersion(String value) {
+ set(5, value);
+ return this;
+ }
+
+ /**
+ * Getter for JOOQ_MIGRATIONS_CHANGELOG.JOOQ_VERSION. The jOOQ version used to migrate to this database version.
+ */
+ public String getJooqVersion() {
+ return (String) get(5);
+ }
+
+ // -------------------------------------------------------------------------
+ // Primary key information
+ // -------------------------------------------------------------------------
+
+ @Override
+ public Record1 key() {
+ return (Record1) super.key();
+ }
+
+ // -------------------------------------------------------------------------
+ // Constructors
+ // -------------------------------------------------------------------------
+
+ /**
+ * Create a detached JooqMigrationsChangelogRecord
+ */
+ public JooqMigrationsChangelogRecord() {
+ super(JooqMigrationsChangelog.JOOQ_MIGRATIONS_CHANGELOG);
+ }
+
+ /**
+ * Create a detached, initialised JooqMigrationsChangelogRecord
+ */
+ public JooqMigrationsChangelogRecord(Long id, String migratedFrom, String migratedTo, Timestamp migratedAt, Long migrationTime, String jooqVersion) {
+ super(JooqMigrationsChangelog.JOOQ_MIGRATIONS_CHANGELOG);
+
+ set(0, id);
+ set(1, migratedFrom);
+ set(2, migratedTo);
+ set(3, migratedAt);
+ set(4, migrationTime);
+ set(5, jooqVersion);
+ }
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/VersionImpl.java b/jOOQ/src/main/java/org/jooq/impl/VersionImpl.java
index 4c48c543eb..93bc0b00c6 100644
--- a/jOOQ/src/main/java/org/jooq/impl/VersionImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/VersionImpl.java
@@ -142,6 +142,7 @@ final class VersionImpl implements Version {
+
return subgraph.migrateFrom((VersionImpl) version, ctx.queries());
}
diff --git a/jOOQ/src/main/java/org/jooq/tools/jdbc/MockConfiguration.java b/jOOQ/src/main/java/org/jooq/tools/jdbc/MockConfiguration.java
index 39fc112f21..86044f6630 100644
--- a/jOOQ/src/main/java/org/jooq/tools/jdbc/MockConfiguration.java
+++ b/jOOQ/src/main/java/org/jooq/tools/jdbc/MockConfiguration.java
@@ -66,6 +66,7 @@ import org.jooq.TransactionListenerProvider;
import org.jooq.TransactionProvider;
import org.jooq.Unwrapper;
import org.jooq.UnwrapperProvider;
+import org.jooq.VersionProvider;
import org.jooq.VisitListener;
import org.jooq.VisitListenerProvider;
import org.jooq.conf.Settings;
@@ -142,6 +143,11 @@ public class MockConfiguration implements Configuration {
return delegate.metaProvider();
}
+ @Override
+ public VersionProvider versionProvider() {
+ return delegate.versionProvider();
+ }
+
@Override
public ExecutorProvider executorProvider() {
return delegate.executorProvider();
@@ -234,6 +240,11 @@ public class MockConfiguration implements Configuration {
return delegate.set(newMetaProvider);
}
+ @Override
+ public Configuration set(VersionProvider newVersionProvider) {
+ return delegate.set(newVersionProvider);
+ }
+
@Override
public Configuration set(Connection newConnection) {
return delegate.set(newConnection);
@@ -386,6 +397,11 @@ public class MockConfiguration implements Configuration {
return delegate.derive(newMetaProvider);
}
+ @Override
+ public Configuration derive(VersionProvider newVersionProvider) {
+ return delegate.derive(newVersionProvider);
+ }
+
@Override
public Configuration derive(Executor newExecutor) {
return delegate.derive(newExecutor);
diff --git a/jOOQ/src/main/resources/migrations/jooq-migrations.sql b/jOOQ/src/main/resources/migrations/jooq-migrations.sql
new file mode 100644
index 0000000000..a6aa2362d4
--- /dev/null
+++ b/jOOQ/src/main/resources/migrations/jooq-migrations.sql
@@ -0,0 +1,19 @@
+CREATE TABLE jooq_migrations_changelog (
+ id BIGINT NOT NULL IDENTITY,
+ migrated_from VARCHAR(255) NOT NULL,
+ migrated_to VARCHAR(255) NOT NULL,
+ migrated_at TIMESTAMP NOT NULL,
+ migration_time BIGINT NULL,
+ jooq_version VARCHAR(50) NOT NULL,
+
+ CONSTRAINT jooq_migrations_changelog_pk PRIMARY KEY (id)
+);
+
+CREATE INDEX jooq_migrations_changelog_i1 ON jooq_migrations_changelog (migrated_at);
+
+COMMENT ON TABLE jooq_migrations_changelog IS 'The migration log of jOOQ Migrations.';
+COMMENT ON COLUMN jooq_migrations_changelog.id IS 'The database version ID.';
+COMMENT ON COLUMN jooq_migrations_changelog.migrated_from IS 'The previous database version ID.';
+COMMENT ON COLUMN jooq_migrations_changelog.migrated_at IS 'The date/time when the database version was migrated to.';
+COMMENT ON COLUMN jooq_migrations_changelog.migration_time IS 'The time in milliseconds it took to migrate to this database version.';
+COMMENT ON COLUMN jooq_migrations_changelog.jooq_version IS 'The jOOQ version used to migrate to this database version.'
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 6ff5a3595c..77338ae43e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -280,6 +280,31 @@
1.0-rc6
true