+ * Note that a configured Flyway object is immutable. If you change the configuration you will end up creating a new Flyway
+ * object.
+ *
+ */
+public class Flyway {
+ private static final Log LOG = LogFactory.getLog(Flyway.class);
+
+ private final ClassicConfiguration configuration;
+
+ /**
+ * Whether the database connection info has already been printed in the logs.
+ */
+ private boolean dbConnectionInfoPrinted;
+
+ /**
+ * Designed so we can fail fast if the configuration is invalid
+ */
+ private ConfigurationValidator configurationValidator = new ConfigurationValidator();
+
+ /**
+ * Designed so we can fail fast if the SQL file resources are invalid
+ */
+ private ResourceNameValidator resourceNameValidator = new ResourceNameValidator();
+
+ /**
+ * This is your starting point. This creates a configuration which can be customized to your needs before being
+ * loaded into a new Flyway instance using the load() method.
+ *
In its simplest form, this is how you configure Flyway with all defaults to get started:
After that you have a fully-configured Flyway instance at your disposal which can be used to invoke Flyway
+ * functionality such as migrate() or clean().
+ *
+ * @return A new configuration from which Flyway can be loaded.
+ */
+ public static FluentConfiguration configure() {
+ return new FluentConfiguration();
+ }
+
+ /**
+ * This is your starting point. This creates a configuration which can be customized to your needs before being
+ * loaded into a new Flyway instance using the load() method.
+ *
In its simplest form, this is how you configure Flyway with all defaults to get started:
After that you have a fully-configured Flyway instance at your disposal which can be used to invoke Flyway
+ * functionality such as migrate() or clean().
+ *
+ * @param classLoader The class loader to use when loading classes and resources.
+ * @return A new configuration from which Flyway can be loaded.
+ */
+ public static FluentConfiguration configure(ClassLoader classLoader) {
+ return new FluentConfiguration(classLoader);
+ }
+
+ /**
+ * Creates a new instance of Flyway with this configuration. In general the Flyway.configure() factory method should
+ * be preferred over this constructor, unless you need to create or reuse separate Configuration objects.
+ *
+ * @param configuration The configuration to use.
+ */
+ public Flyway(Configuration configuration) {
+ this.configuration = new ClassicConfiguration(configuration);
+ }
+
+ /**
+ * @return The configuration that Flyway is using.
+ */
+ public Configuration getConfiguration() {
+ return new ClassicConfiguration(configuration);
+ }
+
+ /**
+ * Used to cache resource names for classpath scanning between commands
+ */
+ private ResourceNameCache resourceNameCache = new ResourceNameCache();
+
+ /**
+ * Used to cache LocationScanners between commands
+ */
+ private final LocationScannerCache locationScannerCache = new LocationScannerCache();
+
+ /**
+ *
Starts the database migration. All pending migrations will be applied in order.
+ * Calling migrate on an up-to-date database has no effect.
+ *
+ *
+ * @return The number of successfully applied migrations.
+ * @throws FlywayException when the migration failed.
+ */
+ public int migrate() throws FlywayException {
+ return execute(new Command() {
+ public Integer execute(MigrationResolver migrationResolver,
+ SchemaHistory schemaHistory, Database database, Schema[] schemas, CallbackExecutor callbackExecutor
+
+
+
+ ) {
+ if (configuration.isValidateOnMigrate()) {
+ doValidate(database, migrationResolver, schemaHistory, schemas, callbackExecutor,
+ true // Always ignore pending migrations when validating before migrating
+ );
+ }
+
+ if (!schemaHistory.exists()) {
+ List nonEmptySchemas = new ArrayList<>();
+ for (Schema schema : schemas) {
+ if (schema.exists() && !schema.empty()) {
+ nonEmptySchemas.add(schema);
+ }
+ }
+
+ if (!nonEmptySchemas.isEmpty()) {
+ if (configuration.isBaselineOnMigrate()) {
+ doBaseline(schemaHistory, callbackExecutor);
+ } else {
+ // Second check for MySQL which is sometimes flaky otherwise
+ if (!schemaHistory.exists()) {
+ throw new FlywayException("Found non-empty schema(s) "
+ + StringUtils.collectionToCommaDelimitedString(nonEmptySchemas)
+ + " but no schema history table. Use baseline()"
+ + " or set baselineOnMigrate to true to initialize the schema history table.");
+ }
+ }
+ } else {
+ new DbSchemas(database, schemas, schemaHistory).create(false);
+ schemaHistory.create(false);
+ }
+ }
+
+ return new DbMigrate(database, schemaHistory, schemas[0], migrationResolver, configuration,
+ callbackExecutor).migrate();
+ }
+ }, true);
+ }
+
+ private void doBaseline(SchemaHistory schemaHistory, CallbackExecutor callbackExecutor) {
+ new DbBaseline(schemaHistory, configuration.getBaselineVersion(), configuration.getBaselineDescription(),
+ callbackExecutor).baseline();
+ }
+
+ /**
+ *
Undoes the most recently applied versioned migration. If target is specified, Flyway will attempt to undo
+ * versioned migrations in the order they were applied until it hits one with a version below the target. If there
+ * is no versioned migration to undo, calling undo has no effect.
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ *
+ * @return The number of successfully undone migrations.
+ * @throws FlywayException when the undo failed.
+ */
+ public int undo() throws FlywayException {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("undo");
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+ /**
+ *
Validate applied migrations against resolved ones (on the filesystem or classpath)
+ * to detect accidental changes that may prevent the schema(s) from being recreated exactly.
+ *
Validation fails if
+ *
+ *
differences in migration names, types or checksums are found
+ *
versions have been applied that aren't resolved locally anymore
+ *
versions have been resolved that haven't been applied yet
+ *
+ *
+ *
+ *
+ * @throws FlywayException when the validation failed.
+ */
+ public void validate() throws FlywayException {
+ execute(new Command() {
+ public Void execute(MigrationResolver migrationResolver, SchemaHistory schemaHistory, Database database,
+ Schema[] schemas, CallbackExecutor callbackExecutor
+
+
+
+ ) {
+ doValidate(database, migrationResolver, schemaHistory, schemas, callbackExecutor,
+ configuration.isIgnorePendingMigrations());
+ return null;
+ }
+ }, true);
+ }
+
+ /**
+ * Performs the actual validation. All set up must have taken place beforehand.
+ *
+ * @param database The database-specific support.
+ * @param migrationResolver The migration resolver;
+ * @param schemaHistory The schema history table.
+ * @param schemas The schemas managed by Flyway.
+ * @param callbackExecutor The callback executor.
+ * @param ignorePending Whether to ignore pending migrations.
+ */
+ private void doValidate(Database database, MigrationResolver migrationResolver, SchemaHistory schemaHistory,
+ Schema[] schemas, CallbackExecutor callbackExecutor, boolean ignorePending) {
+ String validationError =
+ new DbValidate(database, schemaHistory, schemas[0], migrationResolver,
+ configuration, ignorePending, callbackExecutor).validate();
+
+ if (validationError != null) {
+ if (configuration.isCleanOnValidationError()) {
+ doClean(database, schemaHistory, schemas, callbackExecutor);
+ } else {
+ throw new FlywayException("Validate failed: " + validationError);
+ }
+ }
+ }
+
+ private void doClean(Database database, SchemaHistory schemaHistory, Schema[] schemas, CallbackExecutor callbackExecutor) {
+ new DbClean(database, schemaHistory, schemas, callbackExecutor, configuration.isCleanDisabled()).clean();
+ }
+
+ /**
+ *
Drops all objects (tables, views, procedures, triggers, ...) in the configured schemas.
+ * The schemas are cleaned in the order specified by the {@code schemas} property.
Retrieves the complete information about all the migrations including applied, pending and current migrations with
+ * details and status.
+ *
+ *
+ * @return All migrations sorted by version, oldest first.
+ * @throws FlywayException when the info retrieval failed.
+ */
+ public MigrationInfoService info() {
+ return execute(new Command() {
+ public MigrationInfoService execute(MigrationResolver migrationResolver, SchemaHistory schemaHistory,
+ final Database database, final Schema[] schemas, CallbackExecutor callbackExecutor
+
+
+
+ ) {
+ return new DbInfo(migrationResolver, schemaHistory, configuration, callbackExecutor).info();
+ }
+ }, true);
+ }
+
+ /**
+ *
Baselines an existing database, excluding all migrations up to and including baselineVersion.
+ *
+ *
+ *
+ * @throws FlywayException when the schema baselining failed.
+ */
+ public void baseline() throws FlywayException {
+ execute(new Command() {
+ public Void execute(MigrationResolver migrationResolver,
+ SchemaHistory schemaHistory, Database database, Schema[] schemas, CallbackExecutor callbackExecutor
+
+
+
+ ) {
+ new DbSchemas(database, schemas, schemaHistory).create(true);
+ doBaseline(schemaHistory, callbackExecutor);
+ return null;
+ }
+ }, false);
+ }
+
+ /**
+ * Repairs the Flyway schema history table. This will perform the following actions:
+ *
+ *
Remove any failed migrations on databases without DDL transactions (User objects left behind must still be cleaned up manually)
+ *
Realign the checksums, descriptions and types of the applied migrations with the ones of the available migrations
+ *
+ *
+ *
+ * @throws FlywayException when the schema history table repair failed.
+ */
+ public void repair() throws FlywayException {
+ execute(new Command() {
+ public Void execute(MigrationResolver migrationResolver,
+ SchemaHistory schemaHistory, Database database, Schema[] schemas, CallbackExecutor callbackExecutor
+
+
+
+ ) {
+ new DbRepair(database, migrationResolver, schemaHistory, callbackExecutor, configuration).repair();
+ return null;
+ }
+ }, true);
+ }
+
+ /**
+ * Creates the MigrationResolver.
+ *
+ * @param resourceProvider The resource provider.
+ * @param classProvider The class provider.
+ * @param sqlScriptFactory The SQL statement builder factory.
+ * @param parsingContext The parsing context.
+ * @return A new, fully configured, MigrationResolver instance.
+ */
+ private MigrationResolver createMigrationResolver(ResourceProvider resourceProvider,
+ ClassProvider classProvider,
+ SqlScriptExecutorFactory sqlScriptExecutorFactory,
+ SqlScriptFactory sqlScriptFactory,
+ ParsingContext parsingContext) {
+ return new CompositeMigrationResolver(resourceProvider, classProvider, configuration,
+ sqlScriptExecutorFactory, sqlScriptFactory, parsingContext, configuration.getResolvers());
+ }
+
+ /**
+ * Executes this command with proper resource handling and cleanup.
+ *
+ * @param command The command to execute.
+ * @param The type of the result.
+ * @return The result of the command.
+ */
+ /*private -> testing*/ T execute(Command command, boolean scannerRequired) {
+ T result;
+
+ VersionPrinter.printVersion(
+
+
+
+ );
+
+ configurationValidator.validate(configuration);
+
+
+
+
+
+
+
+
+
+
+
+
+ final ResourceProvider resourceProvider;
+ ClassProvider classProvider;
+ if (!scannerRequired && configuration.isSkipDefaultResolvers() && configuration.isSkipDefaultCallbacks()) {
+ resourceProvider = NoopResourceProvider.INSTANCE;
+ //noinspection unchecked
+ classProvider = NoopClassProvider.INSTANCE;
+ } else {
+ Scanner scanner = new Scanner<>(
+ JavaMigration.class,
+ Arrays.asList(configuration.getLocations()),
+ configuration.getClassLoader(),
+ configuration.getEncoding()
+
+
+
+ , resourceNameCache
+ , locationScannerCache
+ );
+ resourceProvider = scanner;
+ classProvider = scanner;
+ }
+
+ if (configuration.isValidateMigrationNaming()) {
+ resourceNameValidator.validateSQLMigrationNaming(resourceProvider, configuration);
+ }
+
+ JdbcConnectionFactory jdbcConnectionFactory = new JdbcConnectionFactory(configuration.getDataSource(),
+ configuration.getConnectRetries()
+
+
+
+
+ );
+
+ final ParsingContext parsingContext = new ParsingContext();
+ final SqlScriptFactory sqlScriptFactory =
+ DatabaseFactory.createSqlScriptFactory(jdbcConnectionFactory, configuration, parsingContext);
+
+ final SqlScriptExecutorFactory noCallbackSqlScriptExecutorFactory = DatabaseFactory.createSqlScriptExecutorFactory(
+ jdbcConnectionFactory
+
+
+
+
+ );
+
+ jdbcConnectionFactory.setConnectionInitializer(new JdbcConnectionFactory.ConnectionInitializer() {
+ @Override
+ public void initialize(JdbcConnectionFactory jdbcConnectionFactory, Connection connection) {
+ if (configuration.getInitSql() == null) {
+ return;
+ }
+ StringResource resource = new StringResource(configuration.getInitSql());
+
+ SqlScript sqlScript = sqlScriptFactory.createSqlScript(resource, true, resourceProvider);
+ noCallbackSqlScriptExecutorFactory.createSqlScriptExecutor(connection
+
+
+
+ ).execute(sqlScript);
+ }
+ });
+
+ Database database = null;
+ try {
+ database = DatabaseFactory.createDatabase(configuration, !dbConnectionInfoPrinted, jdbcConnectionFactory
+
+
+
+ );
+
+ dbConnectionInfoPrinted = true;
+ LOG.debug("DDL Transactions Supported: " + database.supportsDdlTransactions());
+
+ Pair> schemas = prepareSchemas(database);
+ Schema defaultSchema = schemas.getLeft();
+
+
+
+
+
+
+
+ parsingContext.populate(database, configuration);
+
+ database.ensureSupported();
+
+ DefaultCallbackExecutor callbackExecutor = new DefaultCallbackExecutor(configuration, database, defaultSchema,
+ prepareCallbacks(database, resourceProvider, jdbcConnectionFactory, sqlScriptFactory
+
+
+
+ ));
+
+ SqlScriptExecutorFactory sqlScriptExecutorFactory = DatabaseFactory.createSqlScriptExecutorFactory(jdbcConnectionFactory
+
+
+
+
+ );
+
+ result = command.execute(
+ createMigrationResolver(resourceProvider, classProvider, sqlScriptExecutorFactory, sqlScriptFactory, parsingContext),
+ SchemaHistoryFactory.getSchemaHistory(configuration, noCallbackSqlScriptExecutorFactory, sqlScriptFactory,
+ database, defaultSchema
+
+
+
+ ),
+ database,
+ schemas.getRight().toArray(new Schema[0]),
+ callbackExecutor
+
+
+
+ );
+ } finally {
+ IOUtils.close(database);
+
+
+
+ showMemoryUsage();
+ }
+ return result;
+ }
+
+ private void showMemoryUsage() {
+ Runtime runtime = Runtime.getRuntime();
+ long free = runtime.freeMemory();
+ long total = runtime.totalMemory();
+ long used = total - free;
+
+ long totalMB = total / (1024 * 1024);
+ long usedMB = used / (1024 * 1024);
+ LOG.debug("Memory usage: " + usedMB + " of " + totalMB + "M");
+ }
+
+ private Pair> prepareSchemas(Database database) {
+ String defaultSchemaName = configuration.getDefaultSchema();
+ String[] schemaNames = configuration.getSchemas();
+
+ if (!isDefaultSchemaValid(defaultSchemaName, schemaNames)) {
+ throw new FlywayException("The defaultSchema property is specified but is not a member of the schemas property");
+ }
+
+ LOG.debug("Schemas: " + StringUtils.arrayToCommaDelimitedString(schemaNames));
+ LOG.debug("Default schema: " + defaultSchemaName);
+
+ List schemas = new ArrayList<>();
+
+ if (schemaNames.length == 0) {
+ Schema currentSchema = database.getMainConnection().getCurrentSchema();
+ if (currentSchema == null) {
+ throw new FlywayException("Unable to determine schema for the schema history table." +
+ " Set a default schema for the connection or specify one using the defaultSchema property!");
+ }
+ schemas.add(currentSchema);
+ } else {
+ for (String schemaName : schemaNames) {
+ schemas.add(database.getMainConnection().getSchema(schemaName));
+ }
+ }
+
+ if (defaultSchemaName == null && schemaNames.length > 0) {
+ defaultSchemaName = schemaNames[0];
+ }
+
+ Schema defaultSchema = (defaultSchemaName != null)
+ ? database.getMainConnection().getSchema(defaultSchemaName)
+ : database.getMainConnection().getCurrentSchema();
+
+ return Pair.of(defaultSchema, schemas);
+ }
+
+ private boolean isDefaultSchemaValid(String defaultSchema, String[] schemas) {
+ // No default schema specified
+ if (defaultSchema == null) {
+ return true;
+ }
+ // Default schema is one of those Flyway is managing
+ for (String schema : schemas) {
+ if (defaultSchema.equals(schema)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private List prepareCallbacks(Database database, ResourceProvider resourceProvider,
+ JdbcConnectionFactory jdbcConnectionFactory,
+ SqlScriptFactory sqlScriptFactory
+
+
+
+
+ ) {
+ List effectiveCallbacks = new ArrayList<>();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ effectiveCallbacks.addAll(Arrays.asList(configuration.getCallbacks()));
+
+ if (!configuration.isSkipDefaultCallbacks()) {
+ SqlScriptExecutorFactory sqlScriptExecutorFactory =
+ DatabaseFactory.createSqlScriptExecutorFactory(jdbcConnectionFactory
+
+
+
+
+ );
+
+ effectiveCallbacks.addAll(
+ new SqlScriptCallbackFactory(
+ resourceProvider,
+ sqlScriptExecutorFactory,
+ sqlScriptFactory,
+ configuration
+ ).getCallbacks());
+ }
+
+
+
+
+
+ return effectiveCallbacks;
+ }
+
+ /**
+ * A Flyway command that can be executed.
+ *
+ * @param The result type of the command.
+ */
+ /*private -> testing*/ interface Command {
+ /**
+ * Execute the operation.
+ *
+ * @param migrationResolver The migration resolver to use.
+ * @param schemaHistory The schema history table.
+ * @param database The database-specific support for these connections.
+ * @param schemas The schemas managed by Flyway.
+ * @param callbackExecutor The callback executor.
+ * @return The result of the operation.
+ */
+ T execute(MigrationResolver migrationResolver, SchemaHistory schemaHistory,
+ Database database, Schema[] schemas, CallbackExecutor callbackExecutor
+
+
+
+ );
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/ErrorCode.java b/flyway-core/src/main/java/org/flywaydb/core/api/ErrorCode.java
new file mode 100644
index 00000000..035396c3
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/ErrorCode.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api;
+
+public enum ErrorCode {
+ FAULT,
+ ERROR,
+ JDBC_DRIVER,
+ DB_CONNECTION,
+ DUPLICATE_VERSIONED_MIGRATION,
+ DUPLICATE_REPEATABLE_MIGRATION,
+ DUPLICATE_UNDO_MIGRATION,
+ CONFIGURATION;
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/FlywayException.java b/flyway-core/src/main/java/org/flywaydb/core/api/FlywayException.java
new file mode 100644
index 00000000..1d53a8b1
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/FlywayException.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api;
+
+/**
+ * Exception thrown when Flyway encounters a problem.
+ */
+public class FlywayException extends RuntimeException {
+
+ private ErrorCode errorCode = ErrorCode.ERROR;
+
+ /**
+ * Creates a new FlywayException with this message, cause, and error code.
+ *
+ * @param message The exception message.
+ * @param cause The exception cause.
+ * @param errorCode The error code.
+ */
+ public FlywayException(String message, Throwable cause, ErrorCode errorCode) {
+ super(message, cause);
+ this.errorCode = errorCode;
+ }
+
+ /**
+ * Creates a new FlywayException with this message and error code
+ *
+ * @param message The exception message.
+ * @param errorCode The error code.
+ */
+ public FlywayException(String message, ErrorCode errorCode) {
+ super(message);
+ this.errorCode = errorCode;
+ }
+
+ /**
+ * Creates a new FlywayException with this message and this cause.
+ *
+ * @param message The exception message.
+ * @param cause The exception cause.
+ */
+ public FlywayException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Creates a new FlywayException with this cause. For use in subclasses that override getMessage().
+ *
+ * @param cause The exception cause.
+ */
+ public FlywayException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Creates a new FlywayException with this message.
+ *
+ * @param message The exception message.
+ */
+ public FlywayException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new FlywayException. For use in subclasses that override getMessage().
+ */
+ public FlywayException() {
+ super();
+ }
+
+ public ErrorCode getErrorCode() {
+ return errorCode;
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/InfoOutputProvider.java b/flyway-core/src/main/java/org/flywaydb/core/api/InfoOutputProvider.java
new file mode 100644
index 00000000..2b7016d0
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/InfoOutputProvider.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api;
+
+import org.flywaydb.core.internal.output.InfoOutput;
+
+interface InfoOutputProvider {
+ InfoOutput getInfoOutput();
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/Location.java b/flyway-core/src/main/java/org/flywaydb/core/api/Location.java
new file mode 100644
index 00000000..d800c08b
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/Location.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api;
+
+import org.flywaydb.core.api.logging.Log;
+import org.flywaydb.core.api.logging.LogFactory;
+
+import java.io.File;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A location to load migrations from.
+ */
+public final class Location implements Comparable {
+ private static final Log LOG = LogFactory.getLog(Location.class);
+
+ /**
+ * The prefix for classpath locations.
+ */
+ private static final String CLASSPATH_PREFIX = "classpath:";
+
+ /**
+ * The prefix for filesystem locations.
+ */
+ public static final String FILESYSTEM_PREFIX = "filesystem:";
+
+ /**
+ * The prefix part of the location. Can be either classpath: or filesystem:.
+ */
+ private final String prefix;
+
+ /**
+ * The path part of the location.
+ */
+ private String rawPath;
+
+ /**
+ * The first folder in the path. This will equal rawPath if the path does not contain any wildcards
+ */
+ private String rootPath;
+
+ private Pattern pathRegex = null;
+
+ /**
+ * Creates a new location.
+ *
+ * @param descriptor The location descriptor.
+ */
+ public Location(String descriptor) {
+ String normalizedDescriptor = descriptor.trim();
+
+ if (normalizedDescriptor.contains(":")) {
+ prefix = normalizedDescriptor.substring(0, normalizedDescriptor.indexOf(":") + 1);
+ rawPath = normalizedDescriptor.substring(normalizedDescriptor.indexOf(":") + 1);
+ } else {
+ prefix = CLASSPATH_PREFIX;
+ rawPath = normalizedDescriptor;
+ }
+
+ if (isClassPath()) {
+ if (rawPath.contains(".")) {
+ LOG.warn("Use of dots (.) as path separators will be deprecated in Flyway 7. Path: " + rawPath);
+ }
+ rawPath = rawPath.replace(".", "/");
+ if (rawPath.startsWith("/")) {
+ rawPath = rawPath.substring(1);
+ }
+ if (rawPath.endsWith("/")) {
+ rawPath = rawPath.substring(0, rawPath.length() - 1);
+ }
+ processRawPath();
+ } else if (isFileSystem()) {
+ processRawPath();
+ rootPath = new File(rootPath).getPath();
+
+ if (pathRegex == null) {
+ // if the original path contained no wildcards, also normalise it
+ rawPath = new File(rawPath).getPath();
+ }
+ } else {
+ throw new FlywayException("Unknown prefix for location (should be either filesystem: or classpath:): "
+ + normalizedDescriptor);
+ }
+
+ if (rawPath.endsWith(File.separator)) {
+ rawPath = rawPath.substring(0, rawPath.length() - 1);
+ }
+ }
+
+ /**
+ * Process the rawPath into a rootPath and a regex.
+ * Supported wildcards:
+ * **: Match any 0 or more directories
+ * *: Match any sequence of non-seperator characters
+ * ?: Match any single character
+ */
+ private void processRawPath() {
+ if (rawPath.contains("*") || rawPath.contains("?")) {
+ // we need to figure out the root, and create the regex
+
+ String seperator = isFileSystem() ? File.separator : "/";
+ String escapedSeperator = seperator.replace("\\", "\\\\").replace("/", "\\/");
+
+ // split on either of the path seperators
+ String[] pathSplit = rawPath.split("[\\\\/]");
+
+ StringBuilder rootPart = new StringBuilder();
+ StringBuilder patternPart = new StringBuilder();
+
+ boolean endsInFile = false;
+ boolean skipSeperator = false;
+ boolean inPattern = false;
+ for (String pathPart : pathSplit) {
+ endsInFile = false;
+
+ if (pathPart.contains("*") || pathPart.contains("?")) {
+ inPattern = true;
+ }
+
+ if (inPattern) {
+ if (skipSeperator) {
+ skipSeperator = false;
+ } else {
+ patternPart.append("/");
+ }
+
+ String regex;
+ if ("**".equals(pathPart)) {
+ regex = "([^/]+/)*?";
+
+ // this pattern contains the ending seperator, so make sure we skip appending it after
+ skipSeperator = true;
+ } else {
+ endsInFile = pathPart.contains(".");
+
+ regex = pathPart;
+ regex = regex.replace(".", "\\.");
+ regex = regex.replace("?", "[^/]");
+ regex = regex.replace("*", "[^/]+?");
+ }
+
+ patternPart.append(regex);
+ } else {
+ rootPart.append(seperator).append(pathPart);
+ }
+ }
+
+ // We always append a seperator before each part, so ensure we skip it when setting the final rootPath
+ rootPath = rootPart.length() > 0 ? rootPart.toString().substring(1) : "";
+
+ // Again, skip first seperator
+ String pattern = patternPart.toString().substring(1);
+
+ // Replace the temporary / with the actual escaped seperator
+ pattern = pattern.replace("/", escapedSeperator);
+
+ // Append the rootpath if it is non-empty
+ if (rootPart.length() > 0) {
+ pattern = rootPath.replace(seperator, escapedSeperator) + escapedSeperator + pattern;
+ }
+
+ // if the path did not end in a file, then append the file match pattern
+ if (!endsInFile) {
+ pattern = pattern + escapedSeperator + "(?.*)";
+ }
+
+ pathRegex = Pattern.compile(pattern);
+ } else {
+ rootPath = rawPath;
+ }
+ }
+
+ /**
+ * @return Whether the given path matches this locations regex. Will always return true when the location did not contain any wildcards.
+ */
+ public boolean matchesPath(String path) {
+ if (pathRegex == null) {
+ return true;
+ }
+
+ return pathRegex.matcher(path).matches();
+ }
+
+ /**
+ * Returns the path relative to this location. If the location path contains wildcards, the returned path will be relative
+ * to the last non-wildcard folder in the path.
+ * @return the path relative to this location
+ */
+ public String getPathRelativeToThis(String path) {
+ if (pathRegex != null && pathRegex.pattern().contains("?")) {
+ Matcher matcher = pathRegex.matcher(path);
+ if (matcher.matches()) {
+ String relPath = matcher.group("relpath");
+ if (relPath != null && relPath.length() > 0) {
+ return relPath;
+ }
+ }
+ }
+
+ return rootPath.length() > 0 ? path.substring(rootPath.length() + 1) : path;
+ }
+
+ /**
+ * Checks whether this denotes a location on the classpath.
+ *
+ * @return {@code true} if it does, {@code false} if it doesn't.
+ */
+ public boolean isClassPath() {
+ return CLASSPATH_PREFIX.equals(prefix);
+ }
+
+ /**
+ * Checks whether this denotes a location on the filesystem.
+ *
+ * @return {@code true} if it does, {@code false} if it doesn't.
+ */
+ public boolean isFileSystem() {
+ return FILESYSTEM_PREFIX.equals(prefix);
+ }
+
+ /**
+ * Checks whether this location is a parent of this other location.
+ *
+ * @param other The other location.
+ * @return {@code true} if it is, {@code false} if it isn't.
+ */
+ @SuppressWarnings("SimplifiableIfStatement")
+ public boolean isParentOf(Location other) {
+ if (pathRegex != null || other.pathRegex != null) {
+ return false;
+ }
+
+ if (isClassPath() && other.isClassPath()) {
+ return (other.getDescriptor() + "/").startsWith(getDescriptor() + "/");
+ }
+ if (isFileSystem() && other.isFileSystem()) {
+ return (other.getDescriptor() + File.separator).startsWith(getDescriptor() + File.separator);
+ }
+ return false;
+ }
+
+ /**
+ * @return The prefix part of the location. Can be either classpath: or filesystem:.
+ */
+ public String getPrefix() {
+ return prefix;
+ }
+
+ /**
+ * @return The root part of the path part of the location.
+ */
+ public String getRootPath() {
+ return rootPath;
+ }
+
+ /**
+ * @return The path part of the location.
+ */
+ public String getPath() {
+ return rawPath;
+ }
+
+ /**
+ * @return The the regex that matches in original path. Null if the original path did not contain any wildcards.
+ */
+ public Pattern getPathRegex() {
+ return pathRegex;
+ }
+
+ /**
+ * @return The complete location descriptor.
+ */
+ public String getDescriptor() {
+ return prefix + rawPath;
+ }
+
+ @SuppressWarnings("NullableProblems")
+ public int compareTo(Location o) {
+ return getDescriptor().compareTo(o.getDescriptor());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Location location = (Location) o;
+
+ return getDescriptor().equals(location.getDescriptor());
+ }
+
+ @Override
+ public int hashCode() {
+ return getDescriptor().hashCode();
+ }
+
+ /**
+ * @return The complete location descriptor.
+ */
+ @Override
+ public String toString() {
+ return getDescriptor();
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/MigrationInfo.java b/flyway-core/src/main/java/org/flywaydb/core/api/MigrationInfo.java
new file mode 100644
index 00000000..a7895aeb
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/MigrationInfo.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api;
+
+import java.util.Date;
+
+/**
+ * Info about a migration.
+ */
+public interface MigrationInfo extends Comparable {
+ /**
+ * @return The type of migration (BASELINE, SQL, JDBC, ...)
+ */
+ MigrationType getType();
+
+ /**
+ * @return The target version of this migration.
+ */
+ Integer getChecksum();
+
+ /**
+ * @return The schema version after the migration is complete.
+ */
+ MigrationVersion getVersion();
+
+ /**
+ * @return The description of the migration.
+ */
+ String getDescription();
+
+ /**
+ * @return The name of the script to execute for this migration, relative to its classpath or filesystem location.
+ */
+ String getScript();
+
+ /**
+ * @return The state of the migration (PENDING, SUCCESS, ...)
+ */
+ MigrationState getState();
+
+ /**
+ * @return The timestamp when this migration was installed. (Only for applied migrations)
+ */
+ Date getInstalledOn();
+
+ /**
+ * @return The user that installed this migration. (Only for applied migrations)
+ */
+ String getInstalledBy();
+
+ /**
+ * @return The rank of this installed migration. This is the most precise way to sort applied migrations by installation order.
+ * Migrations that were applied later have a higher rank. (Only for applied migrations)
+ */
+ Integer getInstalledRank();
+
+ /**
+ * @return The execution time (in millis) of this migration. (Only for applied migrations)
+ */
+ Integer getExecutionTime();
+
+ /**
+ * @return The physical location of the migration on disk.
+ */
+ String getPhysicalLocation();
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/MigrationInfoService.java b/flyway-core/src/main/java/org/flywaydb/core/api/MigrationInfoService.java
new file mode 100644
index 00000000..78884618
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/MigrationInfoService.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api;
+
+/**
+ * Info about all migrations, including applied, current and pending with details and status.
+ */
+public interface MigrationInfoService extends InfoOutputProvider {
+ /**
+ * Retrieves the full set of infos about applied, current and future migrations.
+ *
+ * @return The full set of infos. An empty array if none.
+ */
+ MigrationInfo[] all();
+
+ /**
+ * Retrieves the information of the current applied migration, if any.
+ *
+ * @return The info. {@code null} if no migrations have been applied yet.
+ */
+ MigrationInfo current();
+
+ /**
+ * Retrieves the full set of infos about pending migrations, available locally, but not yet applied to the DB.
+ *
+ * @return The pending migrations. An empty array if none.
+ */
+ MigrationInfo[] pending();
+
+ /**
+ * Retrieves the full set of infos about the migrations applied to the DB.
+ *
+ * @return The applied migrations. An empty array if none.
+ */
+ MigrationInfo[] applied();
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/MigrationState.java b/flyway-core/src/main/java/org/flywaydb/core/api/MigrationState.java
new file mode 100644
index 00000000..1e279762
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/MigrationState.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api;
+
+/**
+ * The state of a migration.
+ */
+public enum MigrationState {
+ /**
+ * This migration has not been applied yet.
+ */
+ PENDING("Pending", true, false, false),
+
+ /**
+ * This migration has not been applied yet, and won't be applied because target is set to a lower version.
+ */
+ ABOVE_TARGET("Above Target", true, false, false),
+
+ /**
+ * This migration was not applied against this DB, because the schema history table was baselined with a higher version.
+ */
+ BELOW_BASELINE("Below Baseline", true, false, false),
+
+ /**
+ * This migration has baselined this DB.
+ */
+ BASELINE("Baseline", true, true, false),
+
+ /**
+ *
This usually indicates a problem.
+ *
+ * This migration was not applied against this DB, because a migration with a higher version has already been
+ * applied. This probably means some checkins happened out of order.
+ *
+ *
Fix by increasing the version number, run clean and migrate again or rerun migration with outOfOrder enabled.
+ * This migration was applied against this DB, but it is not available locally.
+ * This usually results from multiple older migration files being consolidated into a single one.
+ *
+ * This migration was applied against this DB, but it is not available locally.
+ * This usually results from multiple older migration files being consolidated into a single one.
+ *
+ *
This should rarely, if ever, occur in practice.
+ */
+ MISSING_FAILED("Failed (Missing)", false, true, true),
+
+ /**
+ * This migration succeeded.
+ */
+ SUCCESS("Success", true, true, false),
+
+ /**
+ * This versioned migration succeeded, but has since been undone.
+ */
+ UNDONE("Undone", true, true, false),
+
+ /**
+ * This undo migration is ready to be applied if desired.
+ */
+ AVAILABLE("Available", true, false, false),
+
+ /**
+ * This migration failed.
+ */
+ FAILED("Failed", true, true, true),
+
+ /**
+ *
This migration succeeded.
+ *
+ * This migration succeeded, but it was applied out of order.
+ * Rerunning the entire migration history might produce different results!
+ *
+ * This migration has been applied against the DB, but it is not available locally.
+ * Its version is higher than the highest version available locally.
+ * It was most likely successfully installed by a future version of this deployable.
+ *
+ * This migration has been applied against the DB, but it is not available locally.
+ * Its version is higher than the highest version available locally.
+ * It most likely failed during the installation of a future version of this deployable.
+ *
+ */
+ FUTURE_FAILED("Failed (Future)", false, true, true),
+
+ /**
+ * This is a repeatable migration that is outdated and should be re-applied.
+ */
+ OUTDATED("Outdated", true, true, false),
+
+ /**
+ * This is a repeatable migration that is outdated and has already been superseded by a newer run.
+ */
+ SUPERSEDED("Superseded", true, true, false);
+
+ /**
+ * The name suitable for display to the end-user.
+ */
+ private final String displayName;
+
+ /**
+ * Flag indicating if this migration is available on the classpath or not.
+ */
+ private final boolean resolved;
+
+ /**
+ * Flag indicating if this migration has been applied or not.
+ */
+ private final boolean applied;
+
+ /**
+ * Flag indicating if this migration has failed when it was applied or not.
+ */
+ private final boolean failed;
+
+ /**
+ * Creates a new MigrationState.
+ *
+ * @param displayName The name suitable for display to the end-user.
+ * @param resolved Flag indicating if this migration is available on the classpath or not.
+ * @param applied Flag indicating if this migration has been applied or not.
+ * @param failed Flag indicating if this migration has failed when it was applied or not.
+ */
+ MigrationState(String displayName, boolean resolved, boolean applied, boolean failed) {
+ this.displayName = displayName;
+ this.resolved = resolved;
+ this.applied = applied;
+ this.failed = failed;
+ }
+
+ /**
+ * @return The name suitable for display to the end-user.
+ */
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ /**
+ * @return Flag indicating if this migration has been applied or not.
+ */
+ public boolean isApplied() {
+ return applied;
+ }
+
+ /**
+ * @return Flag indicating if this migration has been resolved or not.
+ */
+ public boolean isResolved() {
+ return resolved;
+ }
+
+ /**
+ * @return Flag indicating if this migration has failed or not.
+ */
+ public boolean isFailed() {
+ return failed;
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/MigrationType.java b/flyway-core/src/main/java/org/flywaydb/core/api/MigrationType.java
new file mode 100644
index 00000000..02e03fa7
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/MigrationType.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api;
+
+/**
+ * Type of migration.
+ */
+public enum MigrationType {
+ /**
+ * Schema creation migration.
+ */
+ SCHEMA(true, false),
+
+ /**
+ * Baseline migration.
+ */
+ BASELINE(true, false),
+
+ /**
+ * SQL migrations.
+ */
+ SQL(false, false),
+
+ /**
+ * Undo SQL migrations.
+ */
+ UNDO_SQL(false, true),
+
+ /**
+ * JDBC Java-based migrations.
+ */
+ JDBC(false, false),
+
+ /**
+ * Undo JDBC java-based migrations.
+ */
+ UNDO_JDBC(false, true),
+
+ /**
+ * Spring JDBC Java-based migrations.
+ *
+ * @deprecated Will be removed in Flyway 7.0. Use JDBC instead.
+ */
+ @Deprecated
+ SPRING_JDBC(false, false),
+
+ /**
+ * Undo Spring JDBC java-based migrations.
+ *
+ * @deprecated Will be removed in Flyway 7.0. Use UNDO_JDBC instead.
+ */
+ @Deprecated
+ UNDO_SPRING_JDBC(false, true),
+
+ /**
+ * Migrations using custom MigrationResolvers.
+ */
+ CUSTOM(false, false),
+
+ /**
+ * Undo migrations using custom MigrationResolvers.
+ */
+ UNDO_CUSTOM(false, true);
+
+ private final boolean synthetic;
+ private final boolean undo;
+
+ MigrationType(boolean synthetic, boolean undo) {
+ this.synthetic = synthetic;
+ this.undo = undo;
+ }
+
+ /**
+ * @return Whether this is a synthetic migration type, which is only ever present in the schema history table,
+ * but never discovered by migration resolvers.
+ */
+ public boolean isSynthetic() {
+ return synthetic;
+ }
+
+ /**
+ * @return Whether this is an undo migration, which has undone an earlier migration present in the schema history table.
+ */
+ public boolean isUndo() {
+ return undo;
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/MigrationVersion.java b/flyway-core/src/main/java/org/flywaydb/core/api/MigrationVersion.java
new file mode 100644
index 00000000..2f08f0ff
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/MigrationVersion.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * A version of a migration.
+ *
+ * @author Axel Fontaine
+ */
+public final class MigrationVersion implements Comparable {
+ /**
+ * Version for an empty schema.
+ */
+ public static final MigrationVersion EMPTY = new MigrationVersion(null, "<< Empty Schema >>");
+
+ /**
+ * Latest version.
+ */
+ public static final MigrationVersion LATEST = new MigrationVersion(BigInteger.valueOf(-1), "<< Latest Version >>");
+
+ /**
+ * Current version. Only a marker. For the real version use Flyway.info().current() instead.
+ */
+ public static final MigrationVersion CURRENT = new MigrationVersion(BigInteger.valueOf(-2), "<< Current Version >>");
+
+ /**
+ * Regex for matching proper version format
+ */
+ private static final Pattern SPLIT_REGEX = Pattern.compile("\\.(?=\\d)");
+
+ /**
+ * The individual parts this version string is composed of. Ex. 1.2.3.4.0 -> [1, 2, 3, 4, 0]
+ */
+ private final List versionParts;
+
+ /**
+ * The printable text to represent the version.
+ */
+ private final String displayText;
+
+ /**
+ * Create a MigrationVersion from a version String.
+ *
+ * @param version The version String. The value {@code current} will be interpreted as MigrationVersion.CURRENT,
+ * a marker for the latest version that has been applied to the database.
+ * @return The MigrationVersion
+ */
+ @SuppressWarnings("ConstantConditions")
+ public static MigrationVersion fromVersion(String version) {
+ if ("current".equalsIgnoreCase(version)) return CURRENT;
+ if ("latest".equalsIgnoreCase(version) || LATEST.getVersion().equals(version)) return LATEST;
+ if (version == null) return EMPTY;
+ return new MigrationVersion(version);
+ }
+
+ /**
+ * Creates a Version using this version string.
+ *
+ * @param version The version in one of the following formats: 6, 6.0, 005, 1.2.3.4, 201004200021. {@code null}
+ * means that this version refers to an empty schema.
+ */
+ private MigrationVersion(String version) {
+ String normalizedVersion = version.replace('_', '.');
+ this.versionParts = tokenize(normalizedVersion);
+ this.displayText = normalizedVersion;
+ }
+
+ /**
+ * Creates a Version using this version string.
+ *
+ * @param version The version in one of the following formats: 6, 6.0, 005, 1.2.3.4, 201004200021. {@code null}
+ * means that this version refers to an empty schema.
+ * @param displayText The alternative text to display instead of the version number.
+ */
+ private MigrationVersion(BigInteger version, String displayText) {
+ this.versionParts = new ArrayList<>();
+ this.versionParts.add(version);
+ this.displayText = displayText;
+ }
+
+ /**
+ * @return The textual representation of the version.
+ */
+ @Override
+ public String toString() {
+ return displayText;
+ }
+
+ /**
+ * @return Numeric version as String
+ */
+ public String getVersion() {
+ if (this.equals(EMPTY)) return null;
+ if (this.equals(LATEST)) return Long.toString(Long.MAX_VALUE);
+ return displayText;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ MigrationVersion version1 = (MigrationVersion) o;
+
+ return compareTo(version1) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ return versionParts == null ? 0 : versionParts.hashCode();
+ }
+
+ /**
+ * Convenience method for quickly checking whether this version is at least as new as this other version.
+ *
+ * @param otherVersion The other version.
+ * @return {@code true} if this version is equal or newer, {@code false} if it is older.
+ */
+ public boolean isAtLeast(String otherVersion) {
+ return compareTo(MigrationVersion.fromVersion(otherVersion)) >= 0;
+ }
+
+ /**
+ * Convenience method for quickly checking whether this version is newer than this other version.
+ *
+ * @param otherVersion The other version.
+ * @return {@code true} if this version is newer, {@code false} if it is not.
+ */
+ public boolean isNewerThan(String otherVersion) {
+ return compareTo(MigrationVersion.fromVersion(otherVersion)) > 0;
+ }
+
+ /**
+ * Convenience method for quickly checking whether this major version is newer than this other major version.
+ *
+ * @param otherVersion The other version.
+ * @return {@code true} if this major version is newer, {@code false} if it is not.
+ */
+ public boolean isMajorNewerThan(String otherVersion) {
+ return getMajor().compareTo(MigrationVersion.fromVersion(otherVersion).getMajor()) > 0;
+ }
+
+ /**
+ * @return The major version.
+ */
+ public BigInteger getMajor() {
+ return versionParts.get(0);
+ }
+
+ /**
+ * @return The major version as a string.
+ */
+ public String getMajorAsString() {
+ return versionParts.get(0).toString();
+ }
+
+ /**
+ * @return The minor version as a string.
+ */
+ public String getMinorAsString() {
+ if (versionParts.size() == 1) {
+ return "0";
+ }
+ return versionParts.get(1).toString();
+ }
+
+ @Override
+ public int compareTo(MigrationVersion o) {
+ if (o == null) {
+ return 1;
+ }
+
+ if (this == EMPTY) {
+ if (o == EMPTY) return 0;
+ else return -1;
+ }
+
+ if (this == CURRENT) {
+ return o == CURRENT ? 0 : -1;
+ }
+
+ if (this == LATEST) {
+ if (o == LATEST) return 0;
+ else return 1;
+ }
+
+ if (o == EMPTY) {
+ return 1;
+ }
+
+ if (o == CURRENT) {
+ return 1;
+ }
+
+ if (o == LATEST) {
+ return -1;
+ }
+ final List parts1 = versionParts;
+ final List parts2 = o.versionParts;
+ int largestNumberOfParts = Math.max(parts1.size(), parts2.size());
+ for (int i = 0; i < largestNumberOfParts; i++) {
+ final int compared = getOrZero(parts1, i).compareTo(getOrZero(parts2, i));
+ if (compared != 0) {
+ return compared;
+ }
+ }
+ return 0;
+ }
+
+ private BigInteger getOrZero(List elements, int i) {
+ return i < elements.size() ? elements.get(i) : BigInteger.ZERO;
+ }
+
+ /**
+ * Splits this string into list of Long
+ *
+ * @param versionStr The string to split.
+ * @return The resulting array.
+ */
+ private List tokenize(String versionStr) {
+ List parts = new ArrayList<>();
+ for (String part : SPLIT_REGEX.split(versionStr)) {
+ parts.add(toBigInteger(versionStr, part));
+ }
+
+ for (int i = parts.size() - 1; i > 0; i--) {
+ if (!parts.get(i).equals(BigInteger.ZERO)) {
+ break;
+ }
+ parts.remove(i);
+ }
+
+ return parts;
+ }
+
+ private BigInteger toBigInteger(String versionStr, String part) {
+ try {
+ return new BigInteger(part);
+ } catch (NumberFormatException e) {
+ throw new FlywayException("Version may only contain 0..9 and . (dot). Invalid version: " + versionStr);
+ }
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/android/ContextHolder.java b/flyway-core/src/main/java/org/flywaydb/core/api/android/ContextHolder.java
new file mode 100644
index 00000000..b10abcdd
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/android/ContextHolder.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.android;
+
+import android.content.Context;
+
+/**
+ * Holds an Android context. The context must be set for Flyway to be able to scan assets and classes for migrations.
+ *
+ *
+ * You can set this within an activity using ContextHolder.setContext(this);
+ *
+ */
+public class ContextHolder {
+ private ContextHolder() {}
+
+ /**
+ * The Android context to use.
+ */
+ private static Context context;
+
+ /**
+ * @return The Android context to use to be able to scan assets and classes for migrations.
+ */
+ public static Context getContext() {
+ return context;
+ }
+
+ /**
+ * @param context The Android context to use to be able to scan assets and classes for migrations.
+ */
+ public static void setContext(Context context) {
+ ContextHolder.context = context;
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/android/package-info.java b/flyway-core/src/main/java/org/flywaydb/core/api/android/package-info.java
new file mode 100644
index 00000000..694c4076
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/android/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+/**
+ * Android-specific helper classes.
+ */
+package org.flywaydb.core.api.android;
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/callback/BaseCallback.java b/flyway-core/src/main/java/org/flywaydb/core/api/callback/BaseCallback.java
new file mode 100644
index 00000000..07fdf009
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/callback/BaseCallback.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.callback;
+
+/**
+ * Base implementation of Callback from which one can inherit. This is a convenience class that assumes by default that
+ * all events are handled and all handlers can run within a transaction.
+ */
+public abstract class BaseCallback implements Callback {
+ @Override
+ public boolean supports(Event event, Context context) {
+ return true;
+ }
+
+ @Override
+ public boolean canHandleInTransaction(Event event, Context context) {
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/callback/Callback.java b/flyway-core/src/main/java/org/flywaydb/core/api/callback/Callback.java
new file mode 100644
index 00000000..eae83cf7
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/callback/Callback.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.callback;
+
+/**
+ * This is the main callback interface that should be implemented to handle Flyway lifecycle events.
+ */
+public interface Callback {
+ /**
+ * Whether this callback supports this event or not. This is primarily meant as a way to optimize event handling
+ * by avoiding unnecessary connection state setups for events that will not be handled anyway.
+ *
+ * @param event The event to check.
+ * @param context The context for this event.
+ * @return {@code true} if it can be handled, {@code false} if not.
+ */
+ boolean supports(Event event, Context context);
+
+ /**
+ * Whether this event can be handled in a transaction or whether it must be handled outside a transaction instead.
+ * In the vast majority of the cases the answer will be
+ * {@code true}. Only in the rare cases where non-transactional statements are executed should this return {@code false}.
+ * This method is called before {@link #handle(Event, Context)} in order to determine in advance whether a transaction
+ * can be used or not.
+ *
+ * @param event The event to check.
+ * @param context The context for this event.
+ * @return {@code true} if it can be handled within a transaction (almost all cases). {@code false} if it must be
+ * handled outside a transaction instead (very rare).
+ */
+ boolean canHandleInTransaction(Event event, Context context);
+
+ /**
+ * Handles this Flyway lifecycle event.
+ *
+ * @param event The event to handle.
+ * @param context The context for this event.
+ */
+ void handle(Event event, Context context);
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/callback/Context.java b/flyway-core/src/main/java/org/flywaydb/core/api/callback/Context.java
new file mode 100644
index 00000000..0c9acb96
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/callback/Context.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.callback;
+
+import org.flywaydb.core.api.MigrationInfo;
+import org.flywaydb.core.api.configuration.Configuration;
+
+import java.sql.Connection;
+
+/**
+ * The context relevant to an event.
+ */
+public interface Context {
+ /**
+ * @return The configuration currently in use.
+ */
+ Configuration getConfiguration();
+
+ /**
+ * @return The JDBC connection being used. Transaction are managed by Flyway.
+ * When the context is passed to the {@link Callback#handle(Event, Context)} method, a transaction will already have
+ * been started if required and will be automatically committed or rolled back afterwards.
+ */
+ Connection getConnection();
+
+ /**
+ * @return The info about the migration being handled. Only relevant for the BEFORE_EACH_* and AFTER_EACH_* events.
+ * {@code null} in all other cases.
+ */
+ MigrationInfo getMigrationInfo();
+
+ /**
+ * @return The info about the statement being handled. Only relevant for the statement-level events.
+ * {@code null} in all other cases.
+ *
Flyway Pro and Flyway Enterprise only
+ */
+ Statement getStatement();
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/callback/Error.java b/flyway-core/src/main/java/org/flywaydb/core/api/callback/Error.java
new file mode 100644
index 00000000..14d96c55
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/callback/Error.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.callback;
+
+/**
+ * An error that occurred while executing a statement.
+ *
Flyway Pro and Flyway Enterprise only
+ */
+public interface Error {
+ /**
+ * @return The error code.
+ */
+ int getCode();
+
+ /**
+ * @return The error state.
+ */
+ String getState();
+
+ /**
+ * @return The error message.
+ */
+ String getMessage();
+
+ /**
+ * Checks whether this error has already been handled.
+ *
+ * @return {@code true} {@code true} if this error has already be handled or {@code false} if it should flow
+ * via the default error handler.
+ */
+ boolean isHandled();
+
+ /**
+ * Sets whether this error has already been handled.
+ *
+ * @param handled {@code true} if this error has already be handled or {@code false} if it should flow via the
+ * default error handler.
+ */
+ void setHandled(boolean handled);
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/callback/Event.java b/flyway-core/src/main/java/org/flywaydb/core/api/callback/Event.java
new file mode 100644
index 00000000..7cc501d7
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/callback/Event.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.callback;
+
+/**
+ * The Flyway lifecycle events that can be handled in callbacks.
+ */
+public enum Event {
+ /**
+ * Fired before clean is executed. This event will be fired in a separate transaction from the actual clean operation.
+ */
+ BEFORE_CLEAN("beforeClean"),
+ /**
+ * Fired after clean has succeeded. This event will be fired in a separate transaction from the actual clean operation.
+ */
+ AFTER_CLEAN("afterClean"),
+ /**
+ * Fired after clean has failed. This event will be fired in a separate transaction from the actual clean operation.
+ */
+ AFTER_CLEAN_ERROR("afterCleanError"),
+
+ /**
+ * Fired before migrate is executed. This event will be fired in a separate transaction from the actual migrate operation.
+ */
+ BEFORE_MIGRATE("beforeMigrate"),
+ /**
+ * Fired before each individual migration is executed. This event will be fired within the same transaction (if any)
+ * as the migration and can be used for things like setting up connection parameters that are required by migrations.
+ */
+ BEFORE_EACH_MIGRATE("beforeEachMigrate"),
+ /**
+ * Fired before each individual statement in a migration is executed. This event will be fired within the same transaction (if any)
+ * as the migration and can be used for things like asserting a statement complies with policy (for example: no grant statements allowed).
+ *
Flyway Pro and Enterprise Edition only
+ */
+ BEFORE_EACH_MIGRATE_STATEMENT("beforeEachMigrateStatement"),
+ /**
+ * Fired after each individual statement in a migration that succeeded. This event will be fired within the same transaction (if any)
+ * as the migration.
+ *
Flyway Pro and Enterprise Edition only
+ */
+ AFTER_EACH_MIGRATE_STATEMENT("afterEachMigrateStatement"),
+ /**
+ * Fired after each individual statement in a migration that failed. This event will be fired within the same transaction (if any)
+ * as the migration.
+ *
Flyway Pro and Enterprise Edition only
+ */
+ AFTER_EACH_MIGRATE_STATEMENT_ERROR("afterEachMigrateStatementError"),
+ /**
+ * Fired after each individual migration that succeeded. This event will be fired within the same transaction (if any)
+ * as the migration.
+ */
+ AFTER_EACH_MIGRATE("afterEachMigrate"),
+ /**
+ * Fired after each individual migration that failed. This event will be fired within the same transaction (if any)
+ * as the migration.
+ */
+ AFTER_EACH_MIGRATE_ERROR("afterEachMigrateError"),
+ /**
+ * Fired after migrate has succeeded. This event will be fired in a separate transaction from the actual migrate operation.
+ */
+ AFTER_MIGRATE("afterMigrate"),
+ /**
+ * Fired after migrate has failed. This event will be fired in a separate transaction from the actual migrate operation.
+ */
+ AFTER_MIGRATE_ERROR("afterMigrateError"),
+
+ /**
+ * Fired before undo is executed. This event will be fired in a separate transaction from the actual undo operation.
+ *
Flyway Pro and Enterprise Edition only
+ */
+ BEFORE_UNDO("beforeUndo"),
+ /**
+ * Fired before each individual undo is executed. This event will be fired within the same transaction (if any)
+ * as the undo and can be used for things like setting up connection parameters that are required by undo.
+ *
Flyway Pro and Enterprise Edition only
+ */
+ BEFORE_EACH_UNDO("beforeEachUndo"),
+ /**
+ * Fired before each individual statement in an undo migration is executed. This event will be fired within the same transaction (if any)
+ * as the migration and can be used for things like asserting a statement complies with policy (for example: no grant statements allowed).
+ *
Flyway Pro and Enterprise Edition only
+ */
+ BEFORE_EACH_UNDO_STATEMENT("beforeEachUndoStatement"),
+ /**
+ * Fired after each individual statement in an undo migration that succeeded. This event will be fired within the same transaction (if any)
+ * as the migration.
+ *
Flyway Pro and Enterprise Edition only
+ */
+ AFTER_EACH_UNDO_STATEMENT("afterEachUndoStatement"),
+ /**
+ * Fired after each individual statement in an undo migration that failed. This event will be fired within the same transaction (if any)
+ * as the migration.
+ *
Flyway Pro and Enterprise Edition only
+ */
+ AFTER_EACH_UNDO_STATEMENT_ERROR("afterEachUndoStatementError"),
+ /**
+ * Fired after each individual undo that succeeded. This event will be fired within the same transaction (if any)
+ * as the undo.
+ *
Flyway Pro and Enterprise Edition only
+ */
+ AFTER_EACH_UNDO("afterEachUndo"),
+ /**
+ * Fired after each individual undo that failed. This event will be fired within the same transaction (if any)
+ * as the undo.
+ *
Flyway Pro and Enterprise Edition only
+ */
+ AFTER_EACH_UNDO_ERROR("afterEachUndoError"),
+ /**
+ * Fired after undo has succeeded. This event will be fired in a separate transaction from the actual undo operation.
+ *
Flyway Pro and Enterprise Edition only
+ */
+ AFTER_UNDO("afterUndo"),
+ /**
+ * Fired after undo has failed. This event will be fired in a separate transaction from the actual undo operation.
+ *
Flyway Pro and Enterprise Edition only
+ */
+ AFTER_UNDO_ERROR("afterUndoError"),
+
+ /**
+ * Fired before validate is executed. This event will be fired in a separate transaction from the actual validate operation.
+ */
+ BEFORE_VALIDATE("beforeValidate"),
+ /**
+ * Fired after validate has succeeded. This event will be fired in a separate transaction from the actual validate operation.
+ */
+ AFTER_VALIDATE("afterValidate"),
+ /**
+ * Fired after validate has failed. This event will be fired in a separate transaction from the actual validate operation.
+ */
+ AFTER_VALIDATE_ERROR("afterValidateError"),
+
+ /**
+ * Fired before baseline is executed. This event will be fired in a separate transaction from the actual baseline operation.
+ */
+ BEFORE_BASELINE("beforeBaseline"),
+ /**
+ * Fired after baseline has succeeded. This event will be fired in a separate transaction from the actual baseline operation.
+ */
+ AFTER_BASELINE("afterBaseline"),
+ /**
+ * Fired after baseline has failed. This event will be fired in a separate transaction from the actual baseline operation.
+ */
+ AFTER_BASELINE_ERROR("afterBaselineError"),
+
+ /**
+ * Fired before repair is executed. This event will be fired in a separate transaction from the actual repair operation.
+ */
+ BEFORE_REPAIR("beforeRepair"),
+ /**
+ * Fired after repair has succeeded. This event will be fired in a separate transaction from the actual repair operation.
+ */
+ AFTER_REPAIR("afterRepair"),
+ /**
+ * Fired after repair has failed. This event will be fired in a separate transaction from the actual repair operation.
+ */
+ AFTER_REPAIR_ERROR("afterRepairError"),
+
+ /**
+ * Fired before info is executed. This event will be fired in a separate transaction from the actual info operation.
+ */
+ BEFORE_INFO("beforeInfo"),
+ /**
+ * Fired after info has succeeded. This event will be fired in a separate transaction from the actual info operation.
+ */
+ AFTER_INFO("afterInfo"),
+ /**
+ * Fired after info has failed. This event will be fired in a separate transaction from the actual info operation.
+ */
+ AFTER_INFO_ERROR("afterInfoError");
+
+ private final String id;
+
+ Event(String id) {
+ this.id = id;
+ }
+
+ /**
+ * @return The id of an event. Examples: {@code beforeClean}, {@code afterEachMigrate}, ...
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Retrieves the event with this id.
+ * @param id The id.
+ * @return The event. {@code null} if not found.
+ */
+ public static Event fromId(String id) {
+ for (Event event : values()) {
+ if (event.id.equals(id)) {
+ return event;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return id;
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/callback/Statement.java b/flyway-core/src/main/java/org/flywaydb/core/api/callback/Statement.java
new file mode 100644
index 00000000..891b02b9
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/callback/Statement.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.callback;
+
+import java.util.List;
+
+/**
+ * The statement relevant to an event.
+ *
Flyway Pro and Flyway Enterprise only
+ */
+public interface Statement {
+ /**
+ * @return The SQL statement.
+ */
+ String getSql();
+
+ /**
+ * @return The warnings that were raised during the execution of the statement.
+ * {@code null} if the statement hasn't been executed yet.
+ */
+ List getWarnings();
+
+ /**
+ * @return The errors that were thrown during the execution of the statement.
+ * {@code null} if the statement hasn't been executed yet.
+ */
+ List getErrors();
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/callback/Warning.java b/flyway-core/src/main/java/org/flywaydb/core/api/callback/Warning.java
new file mode 100644
index 00000000..eaec7071
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/callback/Warning.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.callback;
+
+/**
+ * A warning that occurred while executing a statement.
+ *
Flyway Pro and Flyway Enterprise only
+ */
+public interface Warning {
+ /**
+ * @return The warning code.
+ */
+ int getCode();
+
+ /**
+ * @return The warning state.
+ */
+ String getState();
+
+ /**
+ * @return The warning message.
+ */
+ String getMessage();
+
+ /**
+ * Checks whether this warning has already been handled.
+ *
+ * @return {@code true} {@code true} if this warning has already be handled or {@code false} if it should flow
+ * via the default warning handler.
+ */
+ boolean isHandled();
+
+ /**
+ * Sets whether this warning has already been handled.
+ *
+ * @param handled {@code true} if this warning has already be handled or {@code false} if it should flow via the
+ * default warning handler.
+ */
+ void setHandled(boolean handled);
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/callback/package-info.java b/flyway-core/src/main/java/org/flywaydb/core/api/callback/package-info.java
new file mode 100644
index 00000000..b92cd6f5
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/callback/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+/**
+ * Interfaces for Flyway lifecycle callbacks.
+ */
+package org.flywaydb.core.api.callback;
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/configuration/ClassicConfiguration.java b/flyway-core/src/main/java/org/flywaydb/core/api/configuration/ClassicConfiguration.java
new file mode 100644
index 00000000..a5765c3e
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/configuration/ClassicConfiguration.java
@@ -0,0 +1,1924 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.configuration;
+
+import org.flywaydb.core.api.ErrorCode;
+import org.flywaydb.core.api.FlywayException;
+import org.flywaydb.core.api.Location;
+import org.flywaydb.core.api.MigrationVersion;
+import org.flywaydb.core.api.callback.Callback;
+import org.flywaydb.core.api.logging.Log;
+import org.flywaydb.core.api.logging.LogFactory;
+import org.flywaydb.core.api.migration.JavaMigration;
+import org.flywaydb.core.api.resolver.MigrationResolver;
+import org.flywaydb.core.internal.configuration.ConfigUtils;
+import org.flywaydb.core.internal.jdbc.DriverDataSource;
+import org.flywaydb.core.internal.license.Edition;
+import org.flywaydb.core.internal.util.ClassUtils;
+import org.flywaydb.core.internal.util.Locations;
+import org.flywaydb.core.internal.util.StringUtils;
+
+import javax.sql.DataSource;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import static org.flywaydb.core.internal.configuration.ConfigUtils.removeBoolean;
+import static org.flywaydb.core.internal.configuration.ConfigUtils.removeInteger;
+
+/**
+ * JavaBean-style configuration for Flyway. This is primarily meant for compatibility with scenarios where the
+ * new FluentConfiguration isn't an easy fit, such as Spring XML bean configuration.
+ *
+ * This configuration can then be passed to Flyway using the new Flyway(Configuration) constructor.
+ *
+ */
+public class ClassicConfiguration implements Configuration {
+ private static final Log LOG = LogFactory.getLog(ClassicConfiguration.class);
+
+ private String driver;
+ private String url;
+ private String user;
+ private String password;
+
+ /**
+ * The dataSource to use to access the database. Must have the necessary privileges to execute ddl.
+ */
+ private DataSource dataSource;
+
+ /**
+ * The maximum number of retries when attempting to connect to the database. After each failed attempt, Flyway will
+ * wait 1 second before attempting to connect again, up to the maximum number of times specified by connectRetries.
+ * (default: 0)
+ */
+ private int connectRetries;
+
+ /**
+ * The SQL statements to run to initialize a new database connection immediately after opening it.
+ * (default: {@code null})
+ */
+ private String initSql;
+
+ /**
+ * The ClassLoader to use for resolving migrations on the classpath. (default: Thread.currentThread().getContextClassLoader() )
+ */
+ private ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+
+ /**
+ * The locations to scan recursively for migrations.
+ *
The location type is determined by its prefix.
+ * Unprefixed locations or locations starting with {@code classpath:} point to a package on the classpath and may
+ * contain both sql and java-based migrations.
+ * Locations starting with {@code filesystem:} point to a directory on the filesystem and may only contain sql
+ * migrations.
+ *
+ * (default: db/migration)
+ */
+ private Locations locations = new Locations("db/migration");
+
+ /**
+ * The encoding of Sql migrations. (default: UTF-8)
+ */
+ private Charset encoding = StandardCharsets.UTF_8;
+
+ /**
+ * The default schema managed by Flyway. This schema name is case-sensitive. If not specified, but
+ * schemaNames is, Flyway uses the first schema in that list. If that is also not specified, Flyway uses
+ * the default schema for the database connection.
+ *
Consequences:
+ *
+ *
This schema will be the one containing the schema history table.
+ *
This schema will be the default for the database connection (provided the database supports this concept).
+ *
+ */
+ private String defaultSchemaName = null;
+
+ /**
+ * The schemas managed by Flyway. These schema names are case-sensitive. If not specified, Flyway uses
+ * the default schema for the database connection. If defaultSchemaName is not specified, then the first of
+ * this list also acts as default schema.
+ *
Consequences:
+ *
+ *
Flyway will automatically attempt to create all these schemas, unless they already exist.
+ *
The schemas will be cleaned in the order of this list.
+ *
If Flyway created them, the schemas themselves will be dropped when cleaning.
The tablespace where to create the schema history table that will be used by Flyway.
+ *
If not specified, Flyway uses the default tablespace for the database connection.
+ * This setting is only relevant for databases that do support the notion of tablespaces. Its value is simply
+ * ignored for all others.
+ */
+ private String tablespace;
+
+ /**
+ * The target version up to which Flyway should consider migrations.
+ * Migrations with a higher version number will be ignored.
+ * Special values:
+ *
+ *
{@code current}: designates the current version of the schema
+ *
{@code latest}: the latest version of the schema, as defined by the migration with the highest version
+ *
+ * Defaults to {@code latest}.
+ */
+ private MigrationVersion target;
+
+ /**
+ * Whether placeholders should be replaced. (default: true)
+ */
+ private boolean placeholderReplacement = true;
+
+ /**
+ * The map of <placeholder, replacementValue> to apply to sql migration scripts.
+ */
+ private Map placeholders = new HashMap<>();
+
+ /**
+ * The prefix of every placeholder. (default: ${ )
+ */
+ private String placeholderPrefix = "${";
+
+ /**
+ * The suffix of every placeholder. (default: } )
+ */
+ private String placeholderSuffix = "}";
+
+ /**
+ * The file name prefix for versioned SQL migrations. (default: V)
+ *
+ *
Versioned SQL migrations have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to V1_1__My_description.sql
Repeatable sql migrations have the following file name structure: prefixSeparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to R__My_description.sql
+ */
+ private String repeatableSqlMigrationPrefix = "R";
+
+ /**
+ * The file name separator for sql migrations. (default: __)
+ *
+ *
Sql migrations have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to V1_1__My_description.sql
+ */
+ private String sqlMigrationSeparator = "__";
+
+ /**
+ * The file name suffixes for SQL migrations. (default: .sql)
+ *
SQL migrations have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to V1_1__My_description.sql
+ *
Multiple suffixes (like .sql,.pkg,.pkb) can be specified for easier compatibility with other tools such as
+ * editors with specific file associations.
+ */
+ private String[] sqlMigrationSuffixes = {".sql"};
+
+ /**
+ * The manually added Java-based migrations. These are not Java-based migrations discovered through classpath
+ * scanning and instantiated by Flyway. Instead these are manually added instances of JavaMigration.
+ * This is particularly useful when working with a dependency injection container, where you may want the DI
+ * container to instantiate the class and wire up its dependencies for you. (default: none)
+ */
+ private JavaMigration[] javaMigrations = {};
+
+ /**
+ * Ignore missing migrations when reading the schema history table. These are migrations that were performed by an
+ * older deployment of the application that are no longer available in this version. For example: we have migrations
+ * available on the classpath with versions 1.0 and 3.0. The schema history table indicates that a migration with version 2.0
+ * (unknown to us) has also been applied. Instead of bombing out (fail fast) with an exception, a
+ * warning is logged and Flyway continues normally. This is useful for situations where one must be able to deploy
+ * a newer version of the application even though it doesn't contain migrations included with an older one anymore.
+ * Note that if the most recently applied migration is removed, Flyway has no way to know it is missing and will
+ * mark it as future instead.
+ *
+ * {@code true} to continue normally and log a warning, {@code false} to fail fast with an exception.
+ * (default: {@code false})
+ */
+ private boolean ignoreMissingMigrations;
+
+ /**
+ * Ignore ignored migrations when reading the schema history table. These are migrations that were added in between
+ * already migrated migrations in this version. For example: we have migrations available on the classpath with
+ * versions from 1.0 to 3.0. The schema history table indicates that version 1 was finished on 1.0.15, and the next
+ * one was 2.0.0. But with the next release a new migration was added to version 1: 1.0.16. Such scenario is ignored
+ * by migrate command, but by default is rejected by validate. When ignoreIgnoredMigrations is enabled, such case
+ * will not be reported by validate command. This is useful for situations where one must be able to deliver
+ * complete set of migrations in a delivery package for multiple versions of the product, and allows for further
+ * development of older versions.
+ *
+ * {@code true} to continue normally, {@code false} to fail fast with an exception.
+ * (default: {@code false})
+ */
+ private boolean ignoreIgnoredMigrations;
+
+ /**
+ * Ignore pending migrations when reading the schema history table. These are migrations that are available on the
+ * classpath but have not yet been performed by an application deployment.
+ * This can be useful for verifying that in-development migration changes don't contain any validation-breaking changes
+ * of migrations that have already been applied to a production environment, e.g. as part of a CI/CD process, without
+ * failing because of the existence of new migration versions.
+ *
+ * {@code true} to continue normally, {@code false} to fail fast with an exception.
+ * (default: {@code false})
+ */
+ private boolean ignorePendingMigrations;
+
+ /**
+ * Ignore future migrations when reading the schema history table. These are migrations that were performed by a
+ * newer deployment of the application that are not yet available in this version. For example: we have migrations
+ * available on the classpath up to version 3.0. The schema history table indicates that a migration to version 4.0
+ * (unknown to us) has already been applied. Instead of bombing out (fail fast) with an exception, a
+ * warning is logged and Flyway continues normally. This is useful for situations where one must be able to redeploy
+ * an older version of the application after the database has been migrated by a newer one. (default: {@code true})
+ */
+ private boolean ignoreFutureMigrations = true;
+
+ /**
+ * Whether to validate migrations and callbacks whose scripts do not obey the correct naming convention. A failure can be
+ * useful to check that errors such as case sensitivity in migration prefixes have been corrected.
+ * {@code false} to continue normally, {@code true} to fail fast with an exception. (default: {@code false})
+ */
+ private boolean validateMigrationNaming = false;
+
+ /**
+ * Whether to automatically call validate or not when running migrate. (default: {@code true})
+ */
+ private boolean validateOnMigrate = true;
+
+ /**
+ * Whether to automatically call clean or not when a validation error occurs. (default: {@code false})
+ *
This is exclusively intended as a convenience for development. even though we
+ * strongly recommend not to change migration scripts once they have been checked into SCM and run, this provides a
+ * way of dealing with this case in a smooth manner. The database will be wiped clean automatically, ensuring that
+ * the next migration will bring you back to the state checked into SCM.
This is especially useful for production environments where running clean can be quite a career limiting move.
+ */
+ private boolean cleanDisabled;
+
+ /**
+ * The version to tag an existing schema with when executing baseline. (default: 1)
+ */
+ private MigrationVersion baselineVersion = MigrationVersion.fromVersion("1");
+
+ /**
+ * The description to tag an existing schema with when executing baseline. (default: << Flyway Baseline >>)
+ */
+ private String baselineDescription = "<< Flyway Baseline >>";
+
+ /**
+ *
+ * Whether to automatically call baseline when migrate is executed against a non-empty schema with no schema history table.
+ * This schema will then be initialized with the {@code baselineVersion} before executing the migrations.
+ * Only migrations above {@code baselineVersion} will then be applied.
+ *
+ *
+ * This is useful for initial Flyway production deployments on projects with an existing DB.
+ *
+ *
+ * Be careful when enabling this as it removes the safety net that ensures
+ * Flyway does not migrate the wrong database in case of a configuration mistake! (default: {@code false})
+ *
+ */
+ private boolean baselineOnMigrate;
+
+ /**
+ * Allows migrations to be run "out of order".
+ *
If you already have versions 1 and 3 applied, and now a version 2 is found,
+ * it will be applied too instead of being ignored.
+ *
(default: {@code false})
+ */
+ private boolean outOfOrder;
+
+ /**
+ * This is a list of custom callbacks that fire before and after tasks are executed. You can
+ * add as many custom callbacks as you want. (default: none)
+ */
+ private final List callbacks = new ArrayList<>();
+
+ /**
+ * Whether Flyway should skip the default callbacks. If true, only custom callbacks are used.
+ *
(default: false)
+ */
+ private boolean skipDefaultCallbacks;
+
+ /**
+ * The custom MigrationResolvers to be used in addition to the built-in ones for resolving Migrations to apply.
+ *
(default: none)
+ */
+ private MigrationResolver[] resolvers = new MigrationResolver[0];
+
+ /**
+ * Whether Flyway should skip the default resolvers. If true, only custom resolvers are used.
+ *
(default: false)
+ */
+ private boolean skipDefaultResolvers;
+
+ /**
+ * Whether to allow mixing transactional and non-transactional statements within the same migration.
+ *
+ * {@code true} if mixed migrations should be allowed. {@code false} if an error should be thrown instead. (default: {@code false})
+ */
+ private boolean mixed;
+
+ /**
+ * Whether to group all pending migrations together in the same transaction when applying them (only recommended for databases with support for DDL transactions).
+ *
+ * {@code true} if migrations should be grouped. {@code false} if they should be applied individually instead. (default: {@code false})
+ */
+ private boolean group;
+
+ /**
+ * The username that will be recorded in the schema history table as having applied the migration.
+ *
+ * {@code null} for the current database user of the connection. (default: {@code null}).
+ */
+ private String installedBy;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /**
+ * Creates a new default configuration.
+ */
+ public ClassicConfiguration() {
+ // Nothing to do.
+ }
+
+ /**
+ * Creates a new default configuration with this classloader.
+ *
+ * @param classLoader The ClassLoader to use for loading migrations, resolvers, etc from the classpath. (default: Thread.currentThread().getContextClassLoader() )
+ */
+ public ClassicConfiguration(ClassLoader classLoader) {
+ if (classLoader != null) {
+ this.classLoader = classLoader;
+ }
+ }
+
+ /**
+ * Creates a new configuration with the same values as this existing one.
+ *
+ * @param configuration The configuration to use.
+ */
+ public ClassicConfiguration(Configuration configuration) {
+ this(configuration.getClassLoader());
+ configure(configuration);
+ }
+
+ @Override
+ public Location[] getLocations() {
+ return locations.getLocations().toArray(new Location[0]);
+ }
+
+ @Override
+ public Charset getEncoding() {
+ return encoding;
+ }
+
+ @Override
+ public String getDefaultSchema() { return defaultSchemaName; }
+
+ @Override
+ public String[] getSchemas() { return schemaNames; }
+
+ @Override
+ public String getTable() {
+ return table;
+ }
+
+ @Override
+ public String getTablespace() {
+ return tablespace;
+ }
+
+ @Override
+ public MigrationVersion getTarget() {
+ return target;
+ }
+
+ @Override
+ public boolean isPlaceholderReplacement() {
+ return placeholderReplacement;
+ }
+
+ @Override
+ public Map getPlaceholders() {
+ return placeholders;
+ }
+
+ @Override
+ public String getPlaceholderPrefix() {
+ return placeholderPrefix;
+ }
+
+ @Override
+ public String getPlaceholderSuffix() {
+ return placeholderSuffix;
+ }
+
+ @Override
+ public String getSqlMigrationPrefix() {
+ return sqlMigrationPrefix;
+ }
+
+ @Override
+ public String getRepeatableSqlMigrationPrefix() {
+ return repeatableSqlMigrationPrefix;
+ }
+
+ @Override
+ public String getSqlMigrationSeparator() {
+ return sqlMigrationSeparator;
+ }
+
+ @Override
+ public String[] getSqlMigrationSuffixes() {
+ return sqlMigrationSuffixes;
+ }
+
+ @Override
+ public JavaMigration[] getJavaMigrations() {
+ return javaMigrations;
+ }
+
+ @Override
+ public boolean isIgnoreMissingMigrations() {
+ return ignoreMissingMigrations;
+ }
+
+ @Override
+ public boolean isIgnoreIgnoredMigrations() {
+ return ignoreIgnoredMigrations;
+ }
+
+ @Override
+ public boolean isIgnorePendingMigrations() {
+ return ignorePendingMigrations;
+ }
+
+ @Override
+ public boolean isIgnoreFutureMigrations() {
+ return ignoreFutureMigrations;
+ }
+
+ @Override
+ public boolean isValidateMigrationNaming() {
+ return validateMigrationNaming;
+ }
+
+ @Override
+ public boolean isValidateOnMigrate() {
+ return validateOnMigrate;
+ }
+
+ @Override
+ public boolean isCleanOnValidationError() {
+ return cleanOnValidationError;
+ }
+
+ @Override
+ public boolean isCleanDisabled() {
+ return cleanDisabled;
+ }
+
+ @Override
+ public MigrationVersion getBaselineVersion() {
+ return baselineVersion;
+ }
+
+ @Override
+ public String getBaselineDescription() {
+ return baselineDescription;
+ }
+
+ @Override
+ public boolean isBaselineOnMigrate() {
+ return baselineOnMigrate;
+ }
+
+ @Override
+ public boolean isOutOfOrder() {
+ return outOfOrder;
+ }
+
+ @Override
+ public MigrationResolver[] getResolvers() {
+ return resolvers;
+ }
+
+ @Override
+ public boolean isSkipDefaultResolvers() {
+ return skipDefaultResolvers;
+ }
+
+ @Override
+ public DataSource getDataSource() {
+ if (dataSource == null &&
+ (StringUtils.hasLength(driver) || StringUtils.hasLength(user) || StringUtils.hasLength(password))) {
+ LOG.warn("Discarding INCOMPLETE dataSource configuration! " + ConfigUtils.URL + " must be set.");
+ }
+ return dataSource;
+ }
+
+ @Override
+ public int getConnectRetries() {
+ return connectRetries;
+ }
+
+ @Override
+ public String getInitSql() {
+ return initSql;
+ }
+
+ @Override
+ public ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ @Override
+ public boolean isMixed() {
+ return mixed;
+ }
+
+ @Override
+ public String getInstalledBy() {
+ return installedBy;
+ }
+
+ @Override
+ public boolean isGroup() {
+ return group;
+ }
+
+ @Override
+ public String[] getErrorOverrides() {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("errorOverrides");
+
+
+
+
+ }
+
+ @Override
+ public OutputStream getDryRunOutput() {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("dryRunOutput");
+
+
+
+
+ }
+
+ @Override
+ public String getLicenseKey() {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("licenseKey");
+
+
+
+
+ }
+
+ /**
+ * Whether Flyway should output a table with the results of queries when executing migrations.
+ *
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @return {@code true} to output the results table (default: {@code true})
+ */
+ @Override
+ public boolean outputQueryResults() {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("outputQueryResults");
+
+
+
+
+ }
+
+ /**
+ * Sets the stream where to output the SQL statements of a migration dry run. {@code null} to execute the SQL statements
+ * directly against the database. The stream when be closing when Flyway finishes writing the output.
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param dryRunOutput The output file or {@code null} to execute the SQL statements directly against the database.
+ */
+ public void setDryRunOutput(OutputStream dryRunOutput) {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("dryRunOutput");
+
+
+
+
+ }
+
+ /**
+ * Sets the file where to output the SQL statements of a migration dry run. {@code null} to execute the SQL statements
+ * directly against the database. If the file specified is in a non-existent directory, Flyway will create all
+ * directories and parent directories as needed.
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param dryRunOutput The output file or {@code null} to execute the SQL statements directly against the database.
+ */
+ public void setDryRunOutputAsFile(File dryRunOutput) {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("dryRunOutput");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+ /**
+ * Sets the file where to output the SQL statements of a migration dry run. {@code null} to execute the SQL statements
+ * directly against the database. If the file specified is in a non-existent directory, Flyway will create all
+ * directories and parent directories as needed.
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param dryRunOutputFileName The name of the output file or {@code null} to execute the SQL statements directly
+ * against the database.
+ */
+ public void setDryRunOutputAsFileName(String dryRunOutputFileName) {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("dryRunOutput");
+
+
+
+
+ }
+
+ /**
+ * Rules for the built-in error handler that let you override specific SQL states and errors codes in order to force
+ * specific errors or warnings to be treated as debug messages, info messages, warnings or errors.
+ *
Each error override has the following format: {@code STATE:12345:W}.
+ * It is a 5 character SQL state (or * to match all SQL states), a colon,
+ * the SQL error code (or * to match all SQL error codes), a colon and finally
+ * the desired behavior that should override the initial one.
+ *
The following behaviors are accepted:
+ *
+ *
{@code D} to force a debug message
+ *
{@code D-} to force a debug message, but do not show the original sql state and error code
+ *
{@code I} to force an info message
+ *
{@code I-} to force an info message, but do not show the original sql state and error code
+ *
{@code W} to force a warning
+ *
{@code W-} to force a warning, but do not show the original sql state and error code
+ *
{@code E} to force an error
+ *
{@code E-} to force an error, but do not show the original sql state and error code
+ *
+ *
Example 1: to force Oracle stored procedure compilation issues to produce
+ * errors instead of warnings, the following errorOverride can be used: {@code 99999:17110:E}
+ *
Example 2: to force SQL Server PRINT messages to be displayed as info messages (without SQL state and error
+ * code details) instead of warnings, the following errorOverride can be used: {@code S0001:0:I-}
+ *
Example 3: to force all errors with SQL error code 123 to be treated as warnings instead,
+ * the following errorOverride can be used: {@code *:123:W}
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param errorOverrides The ErrorOverrides or an empty array if none are defined. (default: none)
+ */
+ public void setErrorOverrides(String... errorOverrides) {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("errorOverrides");
+
+
+
+
+ }
+
+ /**
+ * Whether to group all pending migrations together in the same transaction when applying them (only recommended for databases with support for DDL transactions).
+ *
+ * @param group {@code true} if migrations should be grouped. {@code false} if they should be applied individually instead. (default: {@code false})
+ */
+ public void setGroup(boolean group) {
+ this.group = group;
+ }
+
+ /**
+ * The username that will be recorded in the schema history table as having applied the migration.
+ *
+ * @param installedBy The username or {@code null} for the current database user of the connection. (default: {@code null}).
+ */
+ public void setInstalledBy(String installedBy) {
+ if ("".equals(installedBy)) {
+ installedBy = null;
+ }
+ this.installedBy = installedBy;
+ }
+
+ /**
+ * Whether to allow mixing transactional and non-transactional statements within the same migration. Enabling this
+ * automatically causes the entire affected migration to be run without a transaction.
+ *
+ *
Note that this is only applicable for PostgreSQL, Aurora PostgreSQL, SQL Server and SQLite which all have
+ * statements that do not run at all within a transaction.
+ *
This is not to be confused with implicit transaction, as they occur in MySQL or Oracle, where even though a
+ * DDL statement was run within a transaction, the database will issue an implicit commit before and after
+ * its execution.
+ *
+ * @param mixed {@code true} if mixed migrations should be allowed. {@code false} if an error should be thrown instead. (default: {@code false})
+ */
+ public void setMixed(boolean mixed) {
+ this.mixed = mixed;
+ }
+
+ /**
+ * Ignore missing migrations when reading the schema history table. These are migrations that were performed by an
+ * older deployment of the application that are no longer available in this version. For example: we have migrations
+ * available on the classpath with versions 1.0 and 3.0. The schema history table indicates that a migration with version 2.0
+ * (unknown to us) has also been applied. Instead of bombing out (fail fast) with an exception, a
+ * warning is logged and Flyway continues normally. This is useful for situations where one must be able to deploy
+ * a newer version of the application even though it doesn't contain migrations included with an older one anymore.
+ * Note that if the most recently applied migration is removed, Flyway has no way to know it is missing and will
+ * mark it as future instead.
+ *
+ * @param ignoreMissingMigrations {@code true} to continue normally and log a warning, {@code false} to fail fast with an exception.
+ * (default: {@code false})
+ */
+ public void setIgnoreMissingMigrations(boolean ignoreMissingMigrations) {
+ this.ignoreMissingMigrations = ignoreMissingMigrations;
+ }
+
+ /**
+ * Ignore ignored migrations when reading the schema history table. These are migrations that were added in between
+ * already migrated migrations in this version. For example: we have migrations available on the classpath with
+ * versions from 1.0 to 3.0. The schema history table indicates that version 1 was finished on 1.0.15, and the next
+ * one was 2.0.0. But with the next release a new migration was added to version 1: 1.0.16. Such scenario is ignored
+ * by migrate command, but by default is rejected by validate. When ignoreIgnoredMigrations is enabled, such case
+ * will not be reported by validate command. This is useful for situations where one must be able to deliver
+ * complete set of migrations in a delivery package for multiple versions of the product, and allows for further
+ * development of older versions.
+ *
+ * @param ignoreIgnoredMigrations {@code true} to continue normally, {@code false} to fail fast with an exception.
+ * (default: {@code false})
+ */
+ public void setIgnoreIgnoredMigrations(boolean ignoreIgnoredMigrations) {
+ this.ignoreIgnoredMigrations = ignoreIgnoredMigrations;
+ }
+
+ /**
+ * Ignore pending migrations when reading the schema history table. These are migrations that are available
+ * but have not yet been applied. This can be useful for verifying that in-development migration changes
+ * don't contain any validation-breaking changes of migrations that have already been applied to a production
+ * environment, e.g. as part of a CI/CD process, without failing because of the existence of new migration versions.
+ *
+ * @param ignorePendingMigrations {@code true} to continue normally, {@code false} to fail fast with an exception.
+ * (default: {@code false})
+ */
+ public void setIgnorePendingMigrations(boolean ignorePendingMigrations) {
+ this.ignorePendingMigrations = ignorePendingMigrations;
+ }
+
+ /**
+ * Whether to ignore future migrations when reading the schema history table. These are migrations that were performed by a
+ * newer deployment of the application that are not yet available in this version. For example: we have migrations
+ * available on the classpath up to version 3.0. The schema history table indicates that a migration to version 4.0
+ * (unknown to us) has already been applied. Instead of bombing out (fail fast) with an exception, a
+ * warning is logged and Flyway continues normally. This is useful for situations where one must be able to redeploy
+ * an older version of the application after the database has been migrated by a newer one.
+ *
+ * @param ignoreFutureMigrations {@code true} to continue normally and log a warning, {@code false} to fail
+ * fast with an exception. (default: {@code true})
+ */
+ public void setIgnoreFutureMigrations(boolean ignoreFutureMigrations) {
+ this.ignoreFutureMigrations = ignoreFutureMigrations;
+ }
+
+ /**
+ * Whether to validate migrations and callbacks whose scripts do not obey the correct naming convention. A failure can be
+ * useful to check that errors such as case sensitivity in migration prefixes have been corrected.
+ *
+ * @param validateMigrationNaming {@code false} to continue normally, {@code true} to fail
+ * fast with an exception. (default: {@code false})
+ */
+ public void setValidateMigrationNaming(boolean validateMigrationNaming) {
+ this.validateMigrationNaming = validateMigrationNaming;
+ }
+
+ /**
+ * Whether to automatically call validate or not when running migrate.
+ *
+ * @param validateOnMigrate {@code true} if validate should be called. {@code false} if not. (default: {@code true})
+ */
+ public void setValidateOnMigrate(boolean validateOnMigrate) {
+ this.validateOnMigrate = validateOnMigrate;
+ }
+
+ /**
+ * Whether to automatically call clean or not when a validation error occurs.
+ *
This is exclusively intended as a convenience for development. even though we
+ * strongly recommend not to change migration scripts once they have been checked into SCM and run, this provides a
+ * way of dealing with this case in a smooth manner. The database will be wiped clean automatically, ensuring that
+ * the next migration will bring you back to the state checked into SCM.
+ *
Warning ! Do not enable in production !
+ *
+ * @param cleanOnValidationError {@code true} if clean should be called. {@code false} if not. (default: {@code false})
+ */
+ public void setCleanOnValidationError(boolean cleanOnValidationError) {
+ this.cleanOnValidationError = cleanOnValidationError;
+ }
+
+ /**
+ * Whether to disable clean.
+ *
This is especially useful for production environments where running clean can be quite a career limiting move.
+ *
+ * @param cleanDisabled {@code true} to disable clean. {@code false} to leave it enabled. (default: {@code false})
+ */
+ public void setCleanDisabled(boolean cleanDisabled) {
+ this.cleanDisabled = cleanDisabled;
+ }
+
+ /**
+ * Sets the locations to scan recursively for migrations.
+ *
The location type is determined by its prefix.
+ * Unprefixed locations or locations starting with {@code classpath:} point to a package on the classpath and may
+ * contain both SQL and Java-based migrations.
+ * Locations starting with {@code filesystem:} point to a directory on the filesystem, may only
+ * contain SQL migrations and are only scanned recursively down non-hidden directories.
+ *
+ * @param locations Locations to scan recursively for migrations. (default: db/migration)
+ */
+ public void setLocationsAsStrings(String... locations) {
+ this.locations = new Locations(locations);
+ }
+
+ /**
+ * Sets the locations to scan recursively for migrations.
+ *
The location type is determined by its prefix.
+ * Unprefixed locations or locations starting with {@code classpath:} point to a package on the classpath and may
+ * contain both SQL and Java-based migrations.
+ * Locations starting with {@code filesystem:} point to a directory on the filesystem, may only
+ * contain SQL migrations and are only scanned recursively down non-hidden directories.
+ *
+ * @param locations Locations to scan recursively for migrations. (default: db/migration)
+ */
+ public void setLocations(Location... locations) {
+ this.locations = new Locations(Arrays.asList(locations));
+ }
+
+ /**
+ * Sets the encoding of Sql migrations.
+ *
+ * @param encoding The encoding of Sql migrations. (default: UTF-8)
+ */
+ public void setEncoding(Charset encoding) {
+ this.encoding = encoding;
+ }
+
+ /**
+ * Sets the encoding of Sql migrations.
+ *
+ * @param encoding The encoding of Sql migrations. (default: UTF-8)
+ */
+ public void setEncodingAsString(String encoding) {
+ this.encoding = Charset.forName(encoding);
+ }
+
+ /**
+ * Sets the default schema managed by Flyway. This schema name is case-sensitive. If not specified, but
+ * Schemas is, Flyway uses the first schema in that list. If that is also not specified, Flyway uses the default
+ * schema for the database connection.
+ *
Consequences:
+ *
+ *
This schema will be the one containing the schema history table.
+ *
This schema will be the default for the database connection (provided the database supports this concept).
+ *
+ *
+ * @param schema The default schema managed by Flyway.
+ */
+ public void setDefaultSchema(String schema) {
+ this.defaultSchemaName = schema;
+ }
+
+ /**
+ * Sets the schemas managed by Flyway. These schema names are case-sensitive. If not specified, Flyway uses
+ * the default schema for the database connection. If defaultSchema is not specified, then the first of
+ * this list also acts as default schema.
+ *
Consequences:
+ *
+ *
Flyway will automatically attempt to create all these schemas, unless they already exist.
+ *
The schemas will be cleaned in the order of this list.
+ *
If Flyway created them, the schemas themselves will be dropped when cleaning.
+ *
+ *
+ * @param schemas The schemas managed by Flyway. May not be {@code null}. Must contain at least one element.
+ */
+ public void setSchemas(String... schemas) {
+ this.schemaNames = schemas;
+ }
+
+ /**
+ *
Sets the name of the schema history table that will be used by Flyway.
By default (single-schema mode)
+ * the schema history table is placed in the default schema for the connection provided by the datasource.
When
+ * the flyway.schemas property is set (multi-schema mode), the schema history table is placed in the first schema
+ * of the list.
+ *
+ * @param table The name of the schema history table that will be used by Flyway. (default: flyway_schema_history)
+ */
+ public void setTable(String table) {
+ this.table = table;
+ }
+
+ /**
+ *
Sets the tablespace where to create the schema history table that will be used by Flyway.
+ *
If not specified, Flyway uses the default tablespace for the database connection.This setting is only relevant
+ * for databases that do support the notion of tablespaces. Its value is simply
+ * ignored for all others.
+ *
+ * @param tablespace The tablespace where to create the schema history table that will be used by Flyway.
+ */
+ public void setTablespace(String tablespace) {
+ this.tablespace = tablespace;
+ }
+
+ /**
+ * Sets the target version up to which Flyway should consider migrations.
+ * Migrations with a higher version number will be ignored.
+ * Special values:
+ *
+ *
{@code current}: designates the current version of the schema
+ *
{@code latest}: the latest version of the schema, as defined by the migration with the highest version
+ *
+ * Defaults to {@code latest}.
+ */
+ public void setTarget(MigrationVersion target) {
+ this.target = target;
+ }
+
+ /**
+ * Sets the target version up to which Flyway should consider migrations.
+ * Migrations with a higher version number will be ignored.
+ * Special values:
+ *
+ *
{@code current}: designates the current version of the schema
+ *
{@code latest}: the latest version of the schema, as defined by the migration with the highest version
+ *
+ * Defaults to {@code latest}.
+ */
+ public void setTargetAsString(String target) {
+ this.target = MigrationVersion.fromVersion(target);
+ }
+
+ /**
+ * Sets whether placeholders should be replaced.
+ *
+ * @param placeholderReplacement Whether placeholders should be replaced. (default: true)
+ */
+ public void setPlaceholderReplacement(boolean placeholderReplacement) {
+ this.placeholderReplacement = placeholderReplacement;
+ }
+
+ /**
+ * Sets the placeholders to replace in sql migration scripts.
+ *
+ * @param placeholders The map of <placeholder, replacementValue> to apply to sql migration scripts.
+ */
+ public void setPlaceholders(Map placeholders) {
+ this.placeholders = placeholders;
+ }
+
+ /**
+ * Sets the prefix of every placeholder.
+ *
+ * @param placeholderPrefix The prefix of every placeholder. (default: ${ )
+ */
+ public void setPlaceholderPrefix(String placeholderPrefix) {
+ if (!StringUtils.hasLength(placeholderPrefix)) {
+ throw new FlywayException("placeholderPrefix cannot be empty!", ErrorCode.CONFIGURATION);
+ }
+ this.placeholderPrefix = placeholderPrefix;
+ }
+
+ /**
+ * Sets the suffix of every placeholder.
+ *
+ * @param placeholderSuffix The suffix of every placeholder. (default: } )
+ */
+ public void setPlaceholderSuffix(String placeholderSuffix) {
+ if (!StringUtils.hasLength(placeholderSuffix)) {
+ throw new FlywayException("placeholderSuffix cannot be empty!", ErrorCode.CONFIGURATION);
+ }
+ this.placeholderSuffix = placeholderSuffix;
+ }
+
+ /**
+ * Sets the file name prefix for sql migrations.
+ *
Sql migrations have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to V1_1__My_description.sql
+ *
+ * @param sqlMigrationPrefix The file name prefix for sql migrations (default: V)
+ */
+ public void setSqlMigrationPrefix(String sqlMigrationPrefix) {
+ this.sqlMigrationPrefix = sqlMigrationPrefix;
+ }
+
+ @Override
+ public String getUndoSqlMigrationPrefix() {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("undoSqlMigrationPrefix");
+
+
+
+
+ }
+
+ /**
+ * Sets the file name prefix for undo SQL migrations. (default: U)
+ *
Undo SQL migrations are responsible for undoing the effects of the versioned migration with the same version.
+ *
They have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to U1.1__My_description.sql
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param undoSqlMigrationPrefix The file name prefix for undo SQL migrations. (default: U)
+ */
+ public void setUndoSqlMigrationPrefix(String undoSqlMigrationPrefix) {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("undoSqlMigrationPrefix");
+
+
+
+
+ }
+
+ /**
+ * The manually added Java-based migrations. These are not Java-based migrations discovered through classpath
+ * scanning and instantiated by Flyway. Instead these are manually added instances of JavaMigration.
+ * This is particularly useful when working with a dependency injection container, where you may want the DI
+ * container to instantiate the class and wire up its dependencies for you.
+ *
+ * @param javaMigrations The manually added Java-based migrations. An empty array if none. (default: none)
+ */
+ public void setJavaMigrations(JavaMigration... javaMigrations) {
+ if (javaMigrations == null) {
+ throw new FlywayException("javaMigrations cannot be null", ErrorCode.CONFIGURATION);
+ }
+ this.javaMigrations = javaMigrations;
+ }
+
+ @Override
+ public boolean isStream() {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("stream");
+
+
+
+
+ }
+
+ /**
+ * Whether to stream SQL migrations when executing them. Streaming doesn't load the entire migration in memory at
+ * once. Instead each statement is loaded individually. This is particularly useful for very large SQL migrations
+ * composed of multiple MB or even GB of reference data, as this dramatically reduces Flyway's memory consumption.
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param stream {@code true} to stream SQL migrations. {@code false} to fully loaded them in memory instead. (default: {@code false})
+ */
+ public void setStream(boolean stream) {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("stream");
+
+
+
+
+ }
+
+ @Override
+ public boolean isBatch() {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("batch");
+
+
+
+
+ }
+
+ /**
+ * Whether to batch SQL statements when executing them. Batching can save up to 99 percent of network roundtrips by
+ * sending up to 100 statements at once over the network to the database, instead of sending each statement
+ * individually. This is particularly useful for very large SQL migrations composed of multiple MB or even GB of
+ * reference data, as this can dramatically reduce the network overhead. This is supported for INSERT, UPDATE,
+ * DELETE, MERGE and UPSERT statements. All other statements are automatically executed without batching.
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param batch {@code true} to batch SQL statements. {@code false} to execute them individually instead. (default: {@code false})
+ */
+ public void setBatch(boolean batch) {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("batch");
+
+
+
+
+ }
+
+ /**
+ * Sets the file name prefix for repeatable sql migrations.
+ *
Repeatable sql migrations have the following file name structure: prefixSeparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to R__My_description.sql
+ *
+ * @param repeatableSqlMigrationPrefix The file name prefix for repeatable sql migrations (default: R)
+ */
+ public void setRepeatableSqlMigrationPrefix(String repeatableSqlMigrationPrefix) {
+ this.repeatableSqlMigrationPrefix = repeatableSqlMigrationPrefix;
+ }
+
+ /**
+ * Sets the file name separator for sql migrations.
+ *
Sql migrations have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to V1_1__My_description.sql
+ *
+ * @param sqlMigrationSeparator The file name separator for sql migrations (default: __)
+ */
+ public void setSqlMigrationSeparator(String sqlMigrationSeparator) {
+ if (!StringUtils.hasLength(sqlMigrationSeparator)) {
+ throw new FlywayException("sqlMigrationSeparator cannot be empty!", ErrorCode.CONFIGURATION);
+ }
+
+ this.sqlMigrationSeparator = sqlMigrationSeparator;
+ }
+
+ /**
+ * The file name suffixes for SQL migrations. (default: .sql)
+ *
SQL migrations have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to V1_1__My_description.sql
+ *
Multiple suffixes (like .sql,.pkg,.pkb) can be specified for easier compatibility with other tools such as
+ * editors with specific file associations.
+ *
+ * @param sqlMigrationSuffixes The file name suffixes for SQL migrations.
+ */
+ public void setSqlMigrationSuffixes(String... sqlMigrationSuffixes) {
+ this.sqlMigrationSuffixes = sqlMigrationSuffixes;
+ }
+
+ /**
+ * Sets the datasource to use. Must have the necessary privileges to execute ddl.
+ *
+ * @param dataSource The datasource to use. Must have the necessary privileges to execute ddl.
+ */
+ public void setDataSource(DataSource dataSource) {
+ driver = null;
+ url = null;
+ user = null;
+ password = null;
+ this.dataSource = dataSource;
+ }
+
+ /**
+ * Sets the datasource to use. Must have the necessary privileges to execute ddl.
+ *
To use a custom ClassLoader, setClassLoader() must be called prior to calling this method.
+ *
+ * @param url The JDBC URL of the database.
+ * @param user The user of the database.
+ * @param password The password of the database.
+ */
+ public void setDataSource(String url, String user, String password) {
+ this.dataSource = new DriverDataSource(classLoader, null, url, user, password);
+ }
+
+ /**
+ * The maximum number of retries when attempting to connect to the database. After each failed attempt, Flyway will
+ * wait 1 second before attempting to connect again, up to the maximum number of times specified by connectRetries.
+ *
+ * @param connectRetries The maximum number of retries (default: 0).
+ */
+ public void setConnectRetries(int connectRetries) {
+ if (connectRetries < 0) {
+ throw new FlywayException("Invalid number of connectRetries (must be 0 or greater): " + connectRetries, ErrorCode.CONFIGURATION);
+ }
+ this.connectRetries = connectRetries;
+ }
+
+ /**
+ * The SQL statements to run to initialize a new database connection immediately after opening it.
+ *
+ * @param initSql The SQL statements. (default: {@code null})
+ */
+ public void setInitSql(String initSql) {
+ this.initSql = initSql;
+ }
+
+ /**
+ * Sets the version to tag an existing schema with when executing baseline.
+ *
+ * @param baselineVersion The version to tag an existing schema with when executing baseline. (default: 1)
+ */
+ public void setBaselineVersion(MigrationVersion baselineVersion) {
+ this.baselineVersion = baselineVersion;
+ }
+
+ /**
+ * Sets the version to tag an existing schema with when executing baseline.
+ *
+ * @param baselineVersion The version to tag an existing schema with when executing baseline. (default: 1)
+ */
+ public void setBaselineVersionAsString(String baselineVersion) {
+ this.baselineVersion = MigrationVersion.fromVersion(baselineVersion);
+ }
+
+ /**
+ * Sets the description to tag an existing schema with when executing baseline.
+ *
+ * @param baselineDescription The description to tag an existing schema with when executing baseline. (default: << Flyway Baseline >>)
+ */
+ public void setBaselineDescription(String baselineDescription) {
+ this.baselineDescription = baselineDescription;
+ }
+
+ /**
+ *
+ * Whether to automatically call baseline when migrate is executed against a non-empty schema with no schema history table.
+ * This schema will then be baselined with the {@code baselineVersion} before executing the migrations.
+ * Only migrations above {@code baselineVersion} will then be applied.
+ *
+ *
+ * This is useful for initial Flyway production deployments on projects with an existing DB.
+ *
+ *
+ * Be careful when enabling this as it removes the safety net that ensures
+ * Flyway does not migrate the wrong database in case of a configuration mistake!
+ *
+ *
+ * @param baselineOnMigrate {@code true} if baseline should be called on migrate for non-empty schemas, {@code false} if not. (default: {@code false})
+ */
+ public void setBaselineOnMigrate(boolean baselineOnMigrate) {
+ this.baselineOnMigrate = baselineOnMigrate;
+ }
+
+ /**
+ * Allows migrations to be run "out of order".
+ *
If you already have versions 1 and 3 applied, and now a version 2 is found,
+ * it will be applied too instead of being ignored.
+ *
+ * @param outOfOrder {@code true} if outOfOrder migrations should be applied, {@code false} if not. (default: {@code false})
+ */
+ public void setOutOfOrder(boolean outOfOrder) {
+ this.outOfOrder = outOfOrder;
+ }
+
+ /**
+ * Gets the callbacks for lifecycle notifications.
+ *
+ * @return The callbacks for lifecycle notifications. An empty array if none. (default: none)
+ */
+ @Override
+ public Callback[] getCallbacks() {
+ return callbacks.toArray(new Callback[0]);
+ }
+
+ @Override
+ public boolean isSkipDefaultCallbacks() {
+ return skipDefaultCallbacks;
+ }
+
+ /**
+ * Set the callbacks for lifecycle notifications.
+ *
+ * @param callbacks The callbacks for lifecycle notifications. (default: none)
+ */
+ public void setCallbacks(Callback... callbacks) {
+ this.callbacks.clear();
+ this.callbacks.addAll(Arrays.asList(callbacks));
+ }
+
+ /**
+ * Set the callbacks for lifecycle notifications.
+ *
+ * @param callbacks The fully qualified class names of the callbacks for lifecycle notifications. (default: none)
+ */
+ public void setCallbacksAsClassNames(String... callbacks) {
+ this.callbacks.clear();
+ for (String callback : callbacks) {
+ Object o = ClassUtils.instantiate(callback, classLoader);
+ if (o instanceof Callback) {
+ this.callbacks.add((Callback) o);
+ } else {
+ throw new FlywayException("Invalid callback: " + callback + " (must implement org.flywaydb.core.api.callback.Callback)", ErrorCode.CONFIGURATION);
+ }
+ }
+ }
+
+ /**
+ * Whether Flyway should skip the default callbacks. If true, only custom callbacks are used.
+ *
+ * @param skipDefaultCallbacks Whether default built-in callbacks should be skipped.
(default: false)
+ */
+ public void setSkipDefaultCallbacks(boolean skipDefaultCallbacks) {
+ this.skipDefaultCallbacks = skipDefaultCallbacks;
+ }
+
+ /**
+ * Sets custom MigrationResolvers to be used in addition to the built-in ones for resolving Migrations to apply.
+ *
+ * @param resolvers The custom MigrationResolvers to be used in addition to the built-in ones for resolving Migrations to apply. (default: empty list)
+ */
+ public void setResolvers(MigrationResolver... resolvers) {
+ this.resolvers = resolvers;
+ }
+
+ /**
+ * Sets custom MigrationResolvers to be used in addition to the built-in ones for resolving Migrations to apply.
+ *
+ * @param resolvers The fully qualified class names of the custom MigrationResolvers to be used in addition to the built-in ones for resolving Migrations to apply. (default: empty list)
+ */
+ public void setResolversAsClassNames(String... resolvers) {
+ List resolverList = ClassUtils.instantiateAll(resolvers, classLoader);
+ setResolvers(resolverList.toArray(new MigrationResolver[resolvers.length]));
+ }
+
+ /**
+ * Whether Flyway should skip the default resolvers. If true, only custom resolvers are used.
+ *
+ * @param skipDefaultResolvers Whether default built-in resolvers should be skipped.
(default: false)
+ */
+ public void setSkipDefaultResolvers(boolean skipDefaultResolvers) {
+ this.skipDefaultResolvers = skipDefaultResolvers;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Override
+ public boolean isOracleSqlplus() {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("oracle.sqlplus");
+
+
+
+
+ }
+
+ /**
+ * Whether to Flyway's support for Oracle SQL*Plus commands should be activated.
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param oracleSqlplus {@code true} to active SQL*Plus support. {@code false} to fail fast instead. (default: {@code false})
+ */
+ public void setOracleSqlplus(boolean oracleSqlplus) {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("oracle.sqlplus");
+
+
+
+
+ }
+
+ @Override
+ public boolean isOracleSqlplusWarn() {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("oracle.sqlplusWarn");
+
+
+
+
+ }
+
+ /**
+ * Whether Flyway should issue a warning instead of an error whenever it encounters an Oracle SQL*Plus statement
+ * it doesn't yet support.
+ *
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param oracleSqlplusWarn {@code true} to issue a warning. {@code false} to fail fast instead. (default: {@code false})
+ */
+ public void setOracleSqlplusWarn(boolean oracleSqlplusWarn) {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("oracle.sqlplusWarn");
+
+
+
+
+ }
+
+ /**
+ * Your Flyway license key (FL01...). Not yet a Flyway Pro or Enterprise Edition customer?
+ * Request your Flyway trial license key
+ * to try out Flyway Pro and Enterprise Edition features free for 30 days.
+ *
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param licenseKey Your Flyway license key.
+ */
+ public void setLicenseKey(String licenseKey) {
+
+ LOG.warn(Edition.PRO + " or " + Edition.ENTERPRISE + " upgrade required: " + licenseKey
+ + " is not supported by " + Edition.COMMUNITY + ".");
+
+
+
+
+ }
+
+ /**
+ * Configure with the same values as this existing configuration.
+ *
+ * @param configuration The configuration to use.
+ */
+ public void configure(Configuration configuration) {
+ setBaselineDescription(configuration.getBaselineDescription());
+ setBaselineOnMigrate(configuration.isBaselineOnMigrate());
+ setBaselineVersion(configuration.getBaselineVersion());
+ setCallbacks(configuration.getCallbacks());
+ setCleanDisabled(configuration.isCleanDisabled());
+ setCleanOnValidationError(configuration.isCleanOnValidationError());
+ setDataSource(configuration.getDataSource());
+ setConnectRetries(configuration.getConnectRetries());
+ setInitSql(configuration.getInitSql());
+
+
+
+
+
+
+
+
+
+
+
+ setEncoding(configuration.getEncoding());
+ setGroup(configuration.isGroup());
+ setValidateMigrationNaming(configuration.isValidateMigrationNaming());
+ setIgnoreFutureMigrations(configuration.isIgnoreFutureMigrations());
+ setIgnoreMissingMigrations(configuration.isIgnoreMissingMigrations());
+ setIgnoreIgnoredMigrations(configuration.isIgnoreIgnoredMigrations());
+ setIgnorePendingMigrations(configuration.isIgnorePendingMigrations());
+ setInstalledBy(configuration.getInstalledBy());
+ setJavaMigrations(configuration.getJavaMigrations());
+ setLocations(configuration.getLocations());
+ setMixed(configuration.isMixed());
+ setOutOfOrder(configuration.isOutOfOrder());
+ setPlaceholderPrefix(configuration.getPlaceholderPrefix());
+ setPlaceholderReplacement(configuration.isPlaceholderReplacement());
+ setPlaceholders(configuration.getPlaceholders());
+ setPlaceholderSuffix(configuration.getPlaceholderSuffix());
+ setRepeatableSqlMigrationPrefix(configuration.getRepeatableSqlMigrationPrefix());
+ setResolvers(configuration.getResolvers());
+ setDefaultSchema(configuration.getDefaultSchema());
+ setSchemas(configuration.getSchemas());
+ setSkipDefaultCallbacks(configuration.isSkipDefaultCallbacks());
+ setSkipDefaultResolvers(configuration.isSkipDefaultResolvers());
+ setSqlMigrationPrefix(configuration.getSqlMigrationPrefix());
+ setSqlMigrationSeparator(configuration.getSqlMigrationSeparator());
+ setSqlMigrationSuffixes(configuration.getSqlMigrationSuffixes());
+ setTable(configuration.getTable());
+ setTablespace(configuration.getTablespace());
+ setTarget(configuration.getTarget());
+ setValidateOnMigrate(configuration.isValidateOnMigrate());
+ }
+
+ /**
+ * Whether Flyway should output a table with the results of queries when executing migrations.
+ *
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @return {@code true} to output the results table (default: {@code true})
+ */
+ private void setOutputQueryResults(boolean outputQueryResults) {
+
+ throw new org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException("outputQueryResults");
+
+
+
+
+ }
+
+ /**
+ * Configures Flyway with these properties. This overwrites any existing configuration. Property names are
+ * documented in the flyway maven plugin.
+ *
To use a custom ClassLoader, setClassLoader() must be called prior to calling this method.
+ *
+ * @param properties Properties used for configuration.
+ * @throws FlywayException when the configuration failed.
+ */
+ public void configure(Properties properties) {
+ configure(ConfigUtils.propertiesToMap(properties));
+ }
+
+ /**
+ * Configures Flyway with these properties. This overwrites any existing configuration. Property names are
+ * documented in the flyway maven plugin.
+ *
To use a custom ClassLoader, it must be passed to the Flyway constructor prior to calling this method.
+ *
+ * @param props Properties used for configuration.
+ * @throws FlywayException when the configuration failed.
+ */
+ public void configure(Map props) {
+ // Make copy to prevent removing elements from the original.
+ props = new HashMap<>(props);
+
+ String driverProp = props.remove(ConfigUtils.DRIVER);
+ if (driverProp != null) {
+ dataSource = null;
+ driver = driverProp;
+ }
+ String urlProp = props.remove(ConfigUtils.URL);
+ if (urlProp != null) {
+ dataSource = null;
+ url = urlProp;
+ }
+ String userProp = props.remove(ConfigUtils.USER);
+ if (userProp != null) {
+ dataSource = null;
+ user = userProp;
+ }
+ String passwordProp = props.remove(ConfigUtils.PASSWORD);
+ if (passwordProp != null) {
+ dataSource = null;
+ password = passwordProp;
+ }
+ if (StringUtils.hasText(url) && (StringUtils.hasText(urlProp) ||
+ StringUtils.hasText(driverProp) || StringUtils.hasText(userProp) || StringUtils.hasText(passwordProp))) {
+ setDataSource(new DriverDataSource(classLoader, driver, url, user, password));
+ }
+ Integer connectRetriesProp = removeInteger(props, ConfigUtils.CONNECT_RETRIES);
+ if (connectRetriesProp != null) {
+ setConnectRetries(connectRetriesProp);
+ }
+ String initSqlProp = props.remove(ConfigUtils.INIT_SQL);
+ if (initSqlProp != null) {
+ setInitSql(initSqlProp);
+ }
+ String locationsProp = props.remove(ConfigUtils.LOCATIONS);
+ if (locationsProp != null) {
+ setLocationsAsStrings(StringUtils.tokenizeToStringArray(locationsProp, ","));
+ }
+ Boolean placeholderReplacementProp = removeBoolean(props, ConfigUtils.PLACEHOLDER_REPLACEMENT);
+ if (placeholderReplacementProp != null) {
+ setPlaceholderReplacement(placeholderReplacementProp);
+ }
+ String placeholderPrefixProp = props.remove(ConfigUtils.PLACEHOLDER_PREFIX);
+ if (placeholderPrefixProp != null) {
+ setPlaceholderPrefix(placeholderPrefixProp);
+ }
+ String placeholderSuffixProp = props.remove(ConfigUtils.PLACEHOLDER_SUFFIX);
+ if (placeholderSuffixProp != null) {
+ setPlaceholderSuffix(placeholderSuffixProp);
+ }
+ String sqlMigrationPrefixProp = props.remove(ConfigUtils.SQL_MIGRATION_PREFIX);
+ if (sqlMigrationPrefixProp != null) {
+ setSqlMigrationPrefix(sqlMigrationPrefixProp);
+ }
+ String undoSqlMigrationPrefixProp = props.remove(ConfigUtils.UNDO_SQL_MIGRATION_PREFIX);
+ if (undoSqlMigrationPrefixProp != null) {
+ setUndoSqlMigrationPrefix(undoSqlMigrationPrefixProp);
+ }
+ String repeatableSqlMigrationPrefixProp = props.remove(ConfigUtils.REPEATABLE_SQL_MIGRATION_PREFIX);
+ if (repeatableSqlMigrationPrefixProp != null) {
+ setRepeatableSqlMigrationPrefix(repeatableSqlMigrationPrefixProp);
+ }
+ String sqlMigrationSeparatorProp = props.remove(ConfigUtils.SQL_MIGRATION_SEPARATOR);
+ if (sqlMigrationSeparatorProp != null) {
+ setSqlMigrationSeparator(sqlMigrationSeparatorProp);
+ }
+ String sqlMigrationSuffixesProp = props.remove(ConfigUtils.SQL_MIGRATION_SUFFIXES);
+ if (sqlMigrationSuffixesProp != null) {
+ setSqlMigrationSuffixes(StringUtils.tokenizeToStringArray(sqlMigrationSuffixesProp, ","));
+ }
+ String encodingProp = props.remove(ConfigUtils.ENCODING);
+ if (encodingProp != null) {
+ setEncodingAsString(encodingProp);
+ }
+ String defaultSchemaProp = props.remove(ConfigUtils.DEFAULT_SCHEMA);
+ if (defaultSchemaProp != null) {
+ setDefaultSchema(defaultSchemaProp);
+ }
+ String schemasProp = props.remove(ConfigUtils.SCHEMAS);
+ if (schemasProp != null) {
+ setSchemas(StringUtils.tokenizeToStringArray(schemasProp, ","));
+ }
+ String tableProp = props.remove(ConfigUtils.TABLE);
+ if (tableProp != null) {
+ setTable(tableProp);
+ }
+ String tablespaceProp = props.remove(ConfigUtils.TABLESPACE);
+ if (tablespaceProp != null) {
+ setTablespace(tablespaceProp);
+ }
+ Boolean cleanOnValidationErrorProp = removeBoolean(props, ConfigUtils.CLEAN_ON_VALIDATION_ERROR);
+ if (cleanOnValidationErrorProp != null) {
+ setCleanOnValidationError(cleanOnValidationErrorProp);
+ }
+ Boolean cleanDisabledProp = removeBoolean(props, ConfigUtils.CLEAN_DISABLED);
+ if (cleanDisabledProp != null) {
+ setCleanDisabled(cleanDisabledProp);
+ }
+ Boolean validateOnMigrateProp = removeBoolean(props, ConfigUtils.VALIDATE_ON_MIGRATE);
+ if (validateOnMigrateProp != null) {
+ setValidateOnMigrate(validateOnMigrateProp);
+ }
+ String baselineVersionProp = props.remove(ConfigUtils.BASELINE_VERSION);
+ if (baselineVersionProp != null) {
+ setBaselineVersion(MigrationVersion.fromVersion(baselineVersionProp));
+ }
+ String baselineDescriptionProp = props.remove(ConfigUtils.BASELINE_DESCRIPTION);
+ if (baselineDescriptionProp != null) {
+ setBaselineDescription(baselineDescriptionProp);
+ }
+ Boolean baselineOnMigrateProp = removeBoolean(props, ConfigUtils.BASELINE_ON_MIGRATE);
+ if (baselineOnMigrateProp != null) {
+ setBaselineOnMigrate(baselineOnMigrateProp);
+ }
+ Boolean ignoreMissingMigrationsProp = removeBoolean(props, ConfigUtils.IGNORE_MISSING_MIGRATIONS);
+ if (ignoreMissingMigrationsProp != null) {
+ setIgnoreMissingMigrations(ignoreMissingMigrationsProp);
+ }
+ Boolean ignoreIgnoredMigrationsProp = removeBoolean(props, ConfigUtils.IGNORE_IGNORED_MIGRATIONS);
+ if (ignoreIgnoredMigrationsProp != null) {
+ setIgnoreIgnoredMigrations(ignoreIgnoredMigrationsProp);
+ }
+ Boolean ignorePendingMigrationsProp = removeBoolean(props, ConfigUtils.IGNORE_PENDING_MIGRATIONS);
+ if (ignorePendingMigrationsProp != null) {
+ setIgnorePendingMigrations(ignorePendingMigrationsProp);
+ }
+ Boolean ignoreFutureMigrationsProp = removeBoolean(props, ConfigUtils.IGNORE_FUTURE_MIGRATIONS);
+ if (ignoreFutureMigrationsProp != null) {
+ setIgnoreFutureMigrations(ignoreFutureMigrationsProp);
+ }
+ Boolean validateMigrationNamingProp = removeBoolean(props, ConfigUtils.VALIDATE_MIGRATION_NAMING);
+ if (validateMigrationNamingProp != null) {
+ setValidateMigrationNaming(validateMigrationNamingProp);
+ }
+ String targetProp = props.remove(ConfigUtils.TARGET);
+ if (targetProp != null) {
+ setTarget(MigrationVersion.fromVersion(targetProp));
+ }
+ Boolean outOfOrderProp = removeBoolean(props, ConfigUtils.OUT_OF_ORDER);
+ if (outOfOrderProp != null) {
+ setOutOfOrder(outOfOrderProp);
+ }
+ Boolean outputQueryResultsProp = removeBoolean(props, ConfigUtils.OUTPUT_QUERY_RESULTS);
+ if (outputQueryResultsProp != null) {
+ setOutputQueryResults(outputQueryResultsProp);
+ }
+ String resolversProp = props.remove(ConfigUtils.RESOLVERS);
+ if (StringUtils.hasLength(resolversProp)) {
+ setResolversAsClassNames(StringUtils.tokenizeToStringArray(resolversProp, ","));
+ }
+ Boolean skipDefaultResolversProp = removeBoolean(props, ConfigUtils.SKIP_DEFAULT_RESOLVERS);
+ if (skipDefaultResolversProp != null) {
+ setSkipDefaultResolvers(skipDefaultResolversProp);
+ }
+ String callbacksProp = props.remove(ConfigUtils.CALLBACKS);
+ if (StringUtils.hasLength(callbacksProp)) {
+ setCallbacksAsClassNames(StringUtils.tokenizeToStringArray(callbacksProp, ","));
+ }
+ Boolean skipDefaultCallbacksProp = removeBoolean(props, ConfigUtils.SKIP_DEFAULT_CALLBACKS);
+ if (skipDefaultCallbacksProp != null) {
+ setSkipDefaultCallbacks(skipDefaultCallbacksProp);
+ }
+
+ Map placeholdersFromProps = new HashMap<>(getPlaceholders());
+ Iterator> iterator = props.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry entry = iterator.next();
+ String propertyName = entry.getKey();
+
+ if (propertyName.startsWith(ConfigUtils.PLACEHOLDERS_PROPERTY_PREFIX)
+ && propertyName.length() > ConfigUtils.PLACEHOLDERS_PROPERTY_PREFIX.length()) {
+ String placeholderName = propertyName.substring(ConfigUtils.PLACEHOLDERS_PROPERTY_PREFIX.length());
+ String placeholderValue = entry.getValue();
+ placeholdersFromProps.put(placeholderName, placeholderValue);
+ iterator.remove();
+ }
+ }
+ setPlaceholders(placeholdersFromProps);
+
+ Boolean mixedProp = removeBoolean(props, ConfigUtils.MIXED);
+ if (mixedProp != null) {
+ setMixed(mixedProp);
+ }
+
+ Boolean groupProp = removeBoolean(props, ConfigUtils.GROUP);
+ if (groupProp != null) {
+ setGroup(groupProp);
+ }
+
+ String installedByProp = props.remove(ConfigUtils.INSTALLED_BY);
+ if (installedByProp != null) {
+ setInstalledBy(installedByProp);
+ }
+
+ String dryRunOutputProp = props.remove(ConfigUtils.DRYRUN_OUTPUT);
+ if (dryRunOutputProp != null) {
+ setDryRunOutputAsFileName(dryRunOutputProp);
+ }
+
+ String errorOverridesProp = props.remove(ConfigUtils.ERROR_OVERRIDES);
+ if (errorOverridesProp != null) {
+ setErrorOverrides(StringUtils.tokenizeToStringArray(errorOverridesProp, ","));
+ }
+
+ Boolean streamProp = removeBoolean(props, ConfigUtils.STREAM);
+ if (streamProp != null) {
+ setStream(streamProp);
+ }
+
+ Boolean batchProp = removeBoolean(props, ConfigUtils.BATCH);
+ if (batchProp != null) {
+ setBatch(batchProp);
+ }
+
+ Boolean oracleSqlplusProp = removeBoolean(props, ConfigUtils.ORACLE_SQLPLUS);
+ if (oracleSqlplusProp != null) {
+ setOracleSqlplus(oracleSqlplusProp);
+ }
+
+ Boolean oracleSqlplusWarnProp = removeBoolean(props, ConfigUtils.ORACLE_SQLPLUS_WARN);
+ if (oracleSqlplusWarnProp != null) {
+ setOracleSqlplusWarn(oracleSqlplusWarnProp);
+ }
+
+ String licenseKeyProp = props.remove(ConfigUtils.LICENSE_KEY);
+ if (licenseKeyProp != null) {
+ setLicenseKey(licenseKeyProp);
+ }
+
+ ConfigUtils.checkConfigurationForUnrecognisedProperties(props, "flyway.");
+ }
+
+ /**
+ * Configures Flyway using FLYWAY_* environment variables.
+ */
+ public void configureUsingEnvVars() {
+ configure(ConfigUtils.environmentVariablesToPropertyMap());
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/configuration/Configuration.java b/flyway-core/src/main/java/org/flywaydb/core/api/configuration/Configuration.java
new file mode 100644
index 00000000..4869c684
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/configuration/Configuration.java
@@ -0,0 +1,518 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.configuration;
+
+import org.flywaydb.core.api.Location;
+import org.flywaydb.core.api.MigrationVersion;
+import org.flywaydb.core.api.callback.Callback;
+import org.flywaydb.core.api.migration.JavaMigration;
+import org.flywaydb.core.api.resolver.MigrationResolver;
+
+import javax.sql.DataSource;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.util.Map;
+
+/**
+ * Flyway configuration.
+ */
+public interface Configuration {
+ /**
+ * Retrieves the ClassLoader to use for loading migrations, resolvers, etc from the classpath.
+ *
+ * @return The ClassLoader to use for loading migrations, resolvers, etc from the classpath.
+ * (default: Thread.currentThread().getContextClassLoader() )
+ */
+ ClassLoader getClassLoader();
+
+ /**
+ * Retrieves the dataSource to use to access the database. Must have the necessary privileges to execute ddl.
+ *
+ * @return The dataSource to use to access the database. Must have the necessary privileges to execute ddl.
+ */
+ DataSource getDataSource();
+
+ /**
+ * The maximum number of retries when attempting to connect to the database. After each failed attempt, Flyway will
+ * wait 1 second before attempting to connect again, up to the maximum number of times specified by connectRetries.
+ *
+ * @return The maximum number of retries when attempting to connect to the database. (default: 0)
+ */
+ int getConnectRetries();
+
+ /**
+ * The SQL statements to run to initialize a new database connection immediately after opening it.
+ *
+ * @return The SQL statements. (default: {@code null})
+ */
+ String getInitSql();
+
+ /**
+ * Retrieves the version to tag an existing schema with when executing baseline.
+ *
+ * @return The version to tag an existing schema with when executing baseline. (default: 1)
+ */
+ MigrationVersion getBaselineVersion();
+
+ /**
+ * Retrieves the description to tag an existing schema with when executing baseline.
+ *
+ * @return The description to tag an existing schema with when executing baseline. (default: << Flyway Baseline >>)
+ */
+ String getBaselineDescription();
+
+ /**
+ * Retrieves the custom MigrationResolvers to be used in addition to the built-in ones for resolving Migrations to apply.
+ *
+ * @return The custom MigrationResolvers to be used in addition to the built-in ones for resolving Migrations to apply. An empty array if none.
+ * (default: none)
+ */
+ MigrationResolver[] getResolvers();
+
+ /**
+ * Whether Flyway should skip the default resolvers. If true, only custom resolvers are used.
+ *
+ * @return Whether default built-in resolvers should be skipped. (default: false)
+ */
+ boolean isSkipDefaultResolvers();
+
+ /**
+ * Gets the callbacks for lifecycle notifications.
+ *
+ * @return The callbacks for lifecycle notifications. An empty array if none. (default: none)
+ */
+ Callback[] getCallbacks();
+
+ /**
+ * Whether Flyway should skip the default callbacks. If true, only custom callbacks are used.
+ *
+ * @return Whether default built-in callbacks should be skipped. (default: false)
+ */
+ boolean isSkipDefaultCallbacks();
+
+ /**
+ * The file name prefix for versioned SQL migrations.
+ *
Versioned SQL migrations have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to V1.1__My_description.sql
+ *
+ * @return The file name prefix for sql migrations. (default: V)
+ */
+ String getSqlMigrationPrefix();
+
+ /**
+ * The file name prefix for undo SQL migrations.
+ *
Undo SQL migrations are responsible for undoing the effects of the versioned migration with the same version.
+ *
They have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to U1.1__My_description.sql
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @return The file name prefix for undo sql migrations. (default: U)
+ */
+ String getUndoSqlMigrationPrefix();
+
+ /**
+ * Retrieves the file name prefix for repeatable SQL migrations.
+ *
Repeatable SQL migrations have the following file name structure: prefixSeparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to R__My_description.sql
+ *
+ * @return The file name prefix for repeatable sql migrations. (default: R)
+ */
+ String getRepeatableSqlMigrationPrefix();
+
+ /**
+ * Retrieves the file name separator for sql migrations.
+ *
Sql migrations have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to V1_1__My_description.sql
+ *
+ * @return The file name separator for sql migrations. (default: __)
+ */
+ String getSqlMigrationSeparator();
+
+ /**
+ * The file name suffixes for SQL migrations. (default: .sql)
+ *
SQL migrations have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to V1_1__My_description.sql
+ *
Multiple suffixes (like .sql,.pkg,.pkb) can be specified for easier compatibility with other tools such as
+ * editors with specific file associations.
+ *
+ * @return The file name suffixes for SQL migrations.
+ */
+ String[] getSqlMigrationSuffixes();
+
+ /**
+ * The manually added Java-based migrations. These are not Java-based migrations discovered through classpath
+ * scanning and instantiated by Flyway. Instead these are manually added instances of JavaMigration.
+ * This is particularly useful when working with a dependency injection container, where you may want the DI
+ * container to instantiate the class and wire up its dependencies for you.
+ *
+ * @return The manually added Java-based migrations. An empty array if none. (default: none)
+ */
+ JavaMigration[] getJavaMigrations();
+
+ /**
+ * Checks whether placeholders should be replaced.
+ *
+ * @return Whether placeholders should be replaced. (default: true)
+ */
+ boolean isPlaceholderReplacement();
+
+ /**
+ * Retrieves the suffix of every placeholder.
+ *
+ * @return The suffix of every placeholder. (default: } )
+ */
+ String getPlaceholderSuffix();
+
+ /**
+ * Retrieves the prefix of every placeholder.
+ *
+ * @return The prefix of every placeholder. (default: ${ )
+ */
+ String getPlaceholderPrefix();
+
+ /**
+ * Retrieves the map of <placeholder, replacementValue> to apply to sql migration scripts.
+ *
+ * @return The map of <placeholder, replacementValue> to apply to sql migration scripts.
+ */
+ Map getPlaceholders();
+
+ /**
+ * Gets the target version up to which Flyway should consider migrations.
+ * Migrations with a higher version number will be ignored.
+ * Special values:
+ *
+ *
{@code current}: designates the current version of the schema
+ *
{@code latest}: the latest version of the schema, as defined by the migration with the highest version
+ *
+ * Defaults to {@code latest}.
+ * @return The target version up to which Flyway should consider migrations. Defaults to {@code latest}
+ */
+ MigrationVersion getTarget();
+
+ /**
+ *
Retrieves the name of the schema history table that will be used by Flyway.
By default (single-schema
+ * mode) the schema history table is placed in the default schema for the connection provided by the datasource.
+ * When the flyway.schemas property is set (multi-schema mode), the schema history table is placed in the first
+ * schema of the list.
+ *
+ * @return The name of the schema history table that will be used by Flyway. (default: flyway_schema_history)
+ */
+ String getTable();
+
+ /**
+ *
The tablespace where to create the schema history table that will be used by Flyway.
+ *
If not specified, Flyway uses the default tablespace for the database connection.
+ * This setting is only relevant for databases that do support the notion of tablespaces. Its value is simply
+ * ignored for all others.
+ *
+ * @return The tablespace where to create the schema history table that will be used by Flyway.
+ */
+ String getTablespace();
+
+ /**
+ * The default schema managed by Flyway. This schema name is case-sensitive. If not specified, but schemas
+ * is, Flyway uses the first schema in that list. If that is also not specified, Flyway uses the default schema for the
+ * database connection.
+ *
Consequences:
+ *
+ *
This schema will be the one containing the schema history table.
+ *
This schema will be the default for the database connection (provided the database supports this concept).
+ *
+ *
+ * @return The schemas managed by Flyway. (default: The first schema specified in getSchemas(), and failing that
+ * the default schema for the database connection)
+ */
+ String getDefaultSchema();
+
+ /**
+ * The schemas managed by Flyway. These schema names are case-sensitive. If not specified, Flyway uses
+ * the default schema for the database connection. If defaultSchemaName is not specified, then the first of
+ * this list also acts as default schema.
+ *
Consequences:
+ *
+ *
Flyway will automatically attempt to create all these schemas, unless they already exist.
+ *
The schemas will be cleaned in the order of this list.
+ *
If Flyway created them, the schemas themselves will be dropped when cleaning.
+ *
+ *
+ * @return The schemas managed by Flyway. (default: The default schema for the database connection)
+ */
+ String[] getSchemas();
+
+ /**
+ * Retrieves the encoding of Sql migrations.
+ *
+ * @return The encoding of Sql migrations. (default: UTF-8)
+ */
+ Charset getEncoding();
+
+ /**
+ * Retrieves the locations to scan recursively for migrations.
+ *
The location type is determined by its prefix.
+ * Unprefixed locations or locations starting with {@code classpath:} point to a package on the classpath and may
+ * contain both SQL and Java-based migrations.
+ * Locations starting with {@code filesystem:} point to a directory on the filesystem, may only
+ * contain SQL migrations and are only scanned recursively down non-hidden directories.
+ * Whether to automatically call baseline when migrate is executed against a non-empty schema with no schema history table.
+ * This schema will then be initialized with the {@code baselineVersion} before executing the migrations.
+ * Only migrations above {@code baselineVersion} will then be applied.
+ *
+ *
+ * This is useful for initial Flyway production deployments on projects with an existing DB.
+ *
+ *
+ * Be careful when enabling this as it removes the safety net that ensures
+ * Flyway does not migrate the wrong database in case of a configuration mistake!
+ *
+ *
+ * @return {@code true} if baseline should be called on migrate for non-empty schemas, {@code false} if not. (default: {@code false})
+ */
+ boolean isBaselineOnMigrate();
+
+ /**
+ * Allows migrations to be run "out of order".
+ *
If you already have versions 1 and 3 applied, and now a version 2 is found,
+ * it will be applied too instead of being ignored.
+ *
+ * @return {@code true} if outOfOrder migrations should be applied, {@code false} if not. (default: {@code false})
+ */
+ boolean isOutOfOrder();
+
+ /**
+ * Ignore missing migrations when reading the schema history table. These are migrations that were performed by an
+ * older deployment of the application that are no longer available in this version. For example: we have migrations
+ * available on the classpath with versions 1.0 and 3.0. The schema history table indicates that a migration with version 2.0
+ * (unknown to us) has also been applied. Instead of bombing out (fail fast) with an exception, a
+ * warning is logged and Flyway continues normally. This is useful for situations where one must be able to deploy
+ * a newer version of the application even though it doesn't contain migrations included with an older one anymore.
+ * Note that if the most recently applied migration is removed, Flyway has no way to know it is missing and will
+ * mark it as future instead.
+ *
+ * @return {@code true} to continue normally and log a warning, {@code false} to fail fast with an exception.
+ * (default: {@code false})
+ */
+ boolean isIgnoreMissingMigrations();
+
+ /**
+ * Ignore ignored migrations when reading the schema history table. These are migrations that were added in between
+ * already migrated migrations in this version. For example: we have migrations available on the classpath with
+ * versions from 1.0 to 3.0. The schema history table indicates that version 1 was finished on 1.0.15, and the next
+ * one was 2.0.0. But with the next release a new migration was added to version 1: 1.0.16. Such scenario is ignored
+ * by migrate command, but by default is rejected by validate. When ignoreIgnoredMigrations is enabled, such case
+ * will not be reported by validate command. This is useful for situations where one must be able to deliver
+ * complete set of migrations in a delivery package for multiple versions of the product, and allows for further
+ * development of older versions.
+ *
+ * @return {@code true} to continue normally, {@code false} to fail fast with an exception.
+ * (default: {@code false})
+ */
+ boolean isIgnoreIgnoredMigrations();
+
+ /**
+ * Ignore pending migrations when reading the schema history table. These are migrations that are available
+ * but have not yet been applied. This can be useful for verifying that in-development migration changes
+ * don't contain any validation-breaking changes of migrations that have already been applied to a production
+ * environment, e.g. as part of a CI/CD process, without failing because of the existence of new migration versions.
+ *
+ * @return {@code true} to continue normally, {@code false} to fail fast with an exception.
+ * (default: {@code false})
+ */
+ boolean isIgnorePendingMigrations();
+
+ /**
+ * Ignore future migrations when reading the schema history table. These are migrations that were performed by a
+ * newer deployment of the application that are not yet available in this version. For example: we have migrations
+ * available on the classpath up to version 3.0. The schema history table indicates that a migration to version 4.0
+ * (unknown to us) has already been applied. Instead of bombing out (fail fast) with an exception, a
+ * warning is logged and Flyway continues normally. This is useful for situations where one must be able to redeploy
+ * an older version of the application after the database has been migrated by a newer one.
+ *
+ * @return {@code true} to continue normally and log a warning, {@code false} to fail fast with an exception.
+ * (default: {@code true})
+ */
+ boolean isIgnoreFutureMigrations();
+
+ /**
+ * Whether to validate migrations and callbacks whose scripts do not obey the correct naming convention. A failure can be
+ * useful to check that errors such as case sensitivity in migration prefixes have been corrected.
+ *
+ * @return {@code false} to continue normally, {@code true} to fail fast with an exception. (default: {@code false})
+ */
+ boolean isValidateMigrationNaming();
+
+ /**
+ * Whether to automatically call validate or not when running migrate.
+ *
+ * @return {@code true} if validate should be called. {@code false} if not. (default: {@code true})
+ */
+ boolean isValidateOnMigrate();
+
+ /**
+ * Whether to automatically call clean or not when a validation error occurs.
+ *
This is exclusively intended as a convenience for development. even though we
+ * strongly recommend not to change migration scripts once they have been checked into SCM and run, this provides a
+ * way of dealing with this case in a smooth manner. The database will be wiped clean automatically, ensuring that
+ * the next migration will bring you back to the state checked into SCM.
+ *
Warning ! Do not enable in production !
+ *
+ * @return {@code true} if clean should be called. {@code false} if not. (default: {@code false})
+ */
+ boolean isCleanOnValidationError();
+
+ /**
+ * Whether to disable clean.
+ *
This is especially useful for production environments where running clean can be quite a career limiting move.
+ *
+ * @return {@code true} to disable clean. {@code false} to leave it enabled. (default: {@code false})
+ */
+ boolean isCleanDisabled();
+
+ /**
+ * Whether to allow mixing transactional and non-transactional statements within the same migration. Enabling this
+ * automatically causes the entire affected migration to be run without a transaction.
+ *
+ *
Note that this is only applicable for PostgreSQL, Aurora PostgreSQL, SQL Server and SQLite which all have
+ * statements that do not run at all within a transaction.
+ *
This is not to be confused with implicit transaction, as they occur in MySQL or Oracle, where even though a
+ * DDL statement was run within a transaction, the database will issue an implicit commit before and after
+ * its execution.
+ *
+ * @return {@code true} if mixed migrations should be allowed. {@code false} if an error should be thrown instead. (default: {@code false})
+ */
+ boolean isMixed();
+
+ /**
+ * Whether to group all pending migrations together in the same transaction when applying them (only recommended for databases with support for DDL transactions).
+ *
+ * @return {@code true} if migrations should be grouped. {@code false} if they should be applied individually instead. (default: {@code false})
+ */
+ boolean isGroup();
+
+ /**
+ * The username that will be recorded in the schema history table as having applied the migration.
+ *
+ * @return The username or {@code null} for the current database user of the connection. (default: {@code null}).
+ */
+ String getInstalledBy();
+
+ /**
+ * Rules for the built-in error handler that let you override specific SQL states and errors codes in order to force
+ * specific errors or warnings to be treated as debug messages, info messages, warnings or errors.
+ *
Each error override has the following format: {@code STATE:12345:W}.
+ * It is a 5 character SQL state (or * to match all SQL states), a colon,
+ * the SQL error code (or * to match all SQL error codes), a colon and finally
+ * the desired behavior that should override the initial one.
+ *
The following behaviors are accepted:
+ *
+ *
{@code D} to force a debug message
+ *
{@code D-} to force a debug message, but do not show the original sql state and error code
+ *
{@code I} to force an info message
+ *
{@code I-} to force an info message, but do not show the original sql state and error code
+ *
{@code W} to force a warning
+ *
{@code W-} to force a warning, but do not show the original sql state and error code
+ *
{@code E} to force an error
+ *
{@code E-} to force an error, but do not show the original sql state and error code
+ *
+ *
Example 1: to force Oracle stored procedure compilation issues to produce
+ * errors instead of warnings, the following errorOverride can be used: {@code 99999:17110:E}
+ *
Example 2: to force SQL Server PRINT messages to be displayed as info messages (without SQL state and error
+ * code details) instead of warnings, the following errorOverride can be used: {@code S0001:0:I-}
+ *
Example 3: to force all errors with SQL error code 123 to be treated as warnings instead,
+ * the following errorOverride can be used: {@code *:123:W}
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @return The ErrorOverrides or an empty array if none are defined. (default: none)
+ */
+ String[] getErrorOverrides();
+
+ /**
+ * The stream where to output the SQL statements of a migration dry run. {@code null} if the SQL statements
+ * are executed against the database directly.
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @return The stream or {@code null} if the SQL statements are executed against the database directly.
+ */
+ OutputStream getDryRunOutput();
+
+ /**
+ * Whether to stream SQL migrations when executing them. Streaming doesn't load the entire migration in memory at
+ * once. Instead each statement is loaded individually. This is particularly useful for very large SQL migrations
+ * composed of multiple MB or even GB of reference data, as this dramatically reduces Flyway's memory consumption.
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @return {@code true} to stream SQL migrations. {@code false} to fully loaded them in memory instead. (default: {@code false})
+ */
+ boolean isStream();
+
+ /**
+ * Whether to batch SQL statements when executing them. Batching can save up to 99 percent of network roundtrips by
+ * sending up to 100 statements at once over the network to the database, instead of sending each statement
+ * individually. This is particularly useful for very large SQL migrations composed of multiple MB or even GB of
+ * reference data, as this can dramatically reduce the network overhead. This is supported for INSERT, UPDATE,
+ * DELETE, MERGE and UPSERT statements. All other statements are automatically executed without batching.
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @return {@code true} to batch SQL statements. {@code false} to execute them individually instead. (default: {@code false})
+ */
+ boolean isBatch();
+
+ /**
+ * Whether to Flyway's support for Oracle SQL*Plus commands should be activated.
+ *
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @return {@code true} to active SQL*Plus support. {@code false} to fail fast instead. (default: {@code false})
+ */
+ boolean isOracleSqlplus();
+
+ /**
+ * Whether Flyway should issue a warning instead of an error whenever it encounters an Oracle SQL*Plus statement
+ * it doesn't yet support.
+ *
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @return {@code true} to issue a warning. {@code false} to fail fast instead. (default: {@code false})
+ */
+ boolean isOracleSqlplusWarn();
+
+ /**
+ * Your Flyway license key (FL01...). Not yet a Flyway Pro or Enterprise Edition customer?
+ * Request your Flyway trial license key
+ * to try out Flyway Pro and Enterprise Edition features free for 30 days.
+ *
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @return Your Flyway license key.
+ */
+ String getLicenseKey();
+
+ /**
+ * Whether Flyway should output a table with the results of queries when executing migrations.
+ *
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @return {@code true} to output the results table (default: {@code true})
+ */
+ boolean outputQueryResults();
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/configuration/FluentConfiguration.java b/flyway-core/src/main/java/org/flywaydb/core/api/configuration/FluentConfiguration.java
new file mode 100644
index 00000000..97fcaaf4
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/configuration/FluentConfiguration.java
@@ -0,0 +1,1100 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.configuration;
+
+import org.flywaydb.core.Flyway;
+import org.flywaydb.core.api.FlywayException;
+import org.flywaydb.core.api.Location;
+import org.flywaydb.core.api.MigrationVersion;
+import org.flywaydb.core.api.callback.Callback;
+import org.flywaydb.core.api.migration.JavaMigration;
+import org.flywaydb.core.api.resolver.MigrationResolver;
+import org.flywaydb.core.internal.configuration.ConfigUtils;
+import org.flywaydb.core.internal.util.ClassUtils;
+
+import javax.sql.DataSource;
+import java.io.File;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Fluent configuration for Flyway. This is the preferred means of configuring the Flyway API.
+ *
+ * This configuration can be passed to Flyway using the new Flyway(Configuration) constructor.
+ *
+ */
+public class FluentConfiguration implements Configuration {
+ private final ClassicConfiguration config;
+
+ /**
+ * Creates a new default configuration.
+ */
+ public FluentConfiguration() {
+ config = new ClassicConfiguration();
+ }
+
+ /**
+ * Creates a new default configuration with this class loader.
+ *
+ * @param classLoader The ClassLoader to use for loading migrations, resolvers, etc from the classpath. (default: Thread.currentThread().getContextClassLoader() )
+ */
+ public FluentConfiguration(ClassLoader classLoader) {
+ config = new ClassicConfiguration(classLoader);
+ }
+
+ /**
+ * Loads this configuration into a new Flyway instance.
+ *
+ * @return The new fully-configured Flyway instance.
+ */
+ public Flyway load() {
+ return new Flyway(this);
+ }
+
+ /**
+ * Configure with the same values as this existing configuration.
+ *
+ * @param configuration The configuration to use.
+ */
+ public FluentConfiguration configuration(Configuration configuration) {
+ config.configure(configuration);
+ return this;
+ }
+
+ @Override
+ public Location[] getLocations() {
+ return config.getLocations();
+ }
+
+ @Override
+ public Charset getEncoding() {
+ return config.getEncoding();
+ }
+
+ @Override
+ public String getDefaultSchema() { return config.getDefaultSchema(); }
+
+ @Override
+ public String[] getSchemas() { return config.getSchemas(); }
+
+ @Override
+ public String getTable() {
+ return config.getTable();
+ }
+
+ @Override
+ public String getTablespace() {
+ return config.getTablespace();
+ }
+
+ @Override
+ public MigrationVersion getTarget() {
+ return config.getTarget();
+ }
+
+ @Override
+ public boolean isPlaceholderReplacement() {
+ return config.isPlaceholderReplacement();
+ }
+
+ @Override
+ public Map getPlaceholders() {
+ return config.getPlaceholders();
+ }
+
+ @Override
+ public String getPlaceholderPrefix() {
+ return config.getPlaceholderPrefix();
+ }
+
+ @Override
+ public String getPlaceholderSuffix() {
+ return config.getPlaceholderSuffix();
+ }
+
+ @Override
+ public String getSqlMigrationPrefix() {
+ return config.getSqlMigrationPrefix();
+ }
+
+ @Override
+ public String getRepeatableSqlMigrationPrefix() {
+ return config.getRepeatableSqlMigrationPrefix();
+ }
+
+ @Override
+ public String getSqlMigrationSeparator() {
+ return config.getSqlMigrationSeparator();
+ }
+
+ @Override
+ public String[] getSqlMigrationSuffixes() {
+ return config.getSqlMigrationSuffixes();
+ }
+
+ @Override
+ public JavaMigration[] getJavaMigrations() {
+ return config.getJavaMigrations();
+ }
+
+ @Override
+ public boolean isIgnoreMissingMigrations() {
+ return config.isIgnoreMissingMigrations();
+ }
+
+ @Override
+ public boolean isIgnoreIgnoredMigrations() {
+ return config.isIgnoreIgnoredMigrations();
+ }
+
+ @Override
+ public boolean isIgnorePendingMigrations() {
+ return config.isIgnorePendingMigrations();
+ }
+
+ @Override
+ public boolean isIgnoreFutureMigrations() {
+ return config.isIgnoreFutureMigrations();
+ }
+
+ @Override
+ public boolean isValidateMigrationNaming() { return config.isValidateMigrationNaming(); }
+
+ @Override
+ public boolean isValidateOnMigrate() {
+ return config.isValidateOnMigrate();
+ }
+
+ @Override
+ public boolean isCleanOnValidationError() {
+ return config.isCleanOnValidationError();
+ }
+
+ @Override
+ public boolean isCleanDisabled() {
+ return config.isCleanDisabled();
+ }
+
+ @Override
+ public MigrationVersion getBaselineVersion() {
+ return config.getBaselineVersion();
+ }
+
+ @Override
+ public String getBaselineDescription() {
+ return config.getBaselineDescription();
+ }
+
+ @Override
+ public boolean isBaselineOnMigrate() {
+ return config.isBaselineOnMigrate();
+ }
+
+ @Override
+ public boolean isOutOfOrder() {
+ return config.isOutOfOrder();
+ }
+
+ @Override
+ public MigrationResolver[] getResolvers() {
+ return config.getResolvers();
+ }
+
+ @Override
+ public boolean isSkipDefaultResolvers() {
+ return config.isSkipDefaultResolvers();
+ }
+
+ @Override
+ public DataSource getDataSource() {
+ return config.getDataSource();
+ }
+
+ @Override
+ public int getConnectRetries() {
+ return config.getConnectRetries();
+ }
+
+ @Override
+ public String getInitSql() {
+ return config.getInitSql();
+ }
+
+ @Override
+ public ClassLoader getClassLoader() {
+ return config.getClassLoader();
+ }
+
+ @Override
+ public boolean isMixed() {
+ return config.isMixed();
+ }
+
+ @Override
+ public String getInstalledBy() {
+ return config.getInstalledBy();
+ }
+
+ @Override
+ public boolean isGroup() {
+ return config.isGroup();
+ }
+
+ @Override
+ public String[] getErrorOverrides() {
+ return config.getErrorOverrides();
+ }
+
+ @Override
+ public OutputStream getDryRunOutput() {
+ return config.getDryRunOutput();
+ }
+
+ @Override
+ public boolean isStream() {
+ return config.isStream();
+ }
+
+ @Override
+ public boolean isBatch() {
+ return config.isBatch();
+ }
+
+ @Override
+ public boolean isOracleSqlplus() {
+ return config.isOracleSqlplus();
+ }
+
+ @Override
+ public boolean isOracleSqlplusWarn() {
+ return config.isOracleSqlplusWarn();
+ }
+
+ @Override
+ public String getLicenseKey() {
+ return config.getLicenseKey();
+ }
+
+ @Override
+ public boolean outputQueryResults() {
+ return config.outputQueryResults();
+ }
+
+ /**
+ * Sets the stream where to output the SQL statements of a migration dry run. {@code null} to execute the SQL statements
+ * directly against the database. The stream when be closing when Flyway finishes writing the output.
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param dryRunOutput The output file or {@code null} to execute the SQL statements directly against the database.
+ */
+ public FluentConfiguration dryRunOutput(OutputStream dryRunOutput) {
+ config.setDryRunOutput(dryRunOutput);
+ return this;
+ }
+
+ /**
+ * Sets the file where to output the SQL statements of a migration dry run. {@code null} to execute the SQL statements
+ * directly against the database. If the file specified is in a non-existent directory, Flyway will create all
+ * directories and parent directories as needed.
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param dryRunOutput The output file or {@code null} to execute the SQL statements directly against the database.
+ */
+ public FluentConfiguration dryRunOutput(File dryRunOutput) {
+ config.setDryRunOutputAsFile(dryRunOutput);
+ return this;
+ }
+
+ /**
+ * Sets the file where to output the SQL statements of a migration dry run. {@code null} to execute the SQL statements
+ * directly against the database. If the file specified is in a non-existent directory, Flyway will create all
+ * directories and parent directories as needed.
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param dryRunOutputFileName The name of the output file or {@code null} to execute the SQL statements directly
+ * against the database.
+ */
+ public FluentConfiguration dryRunOutput(String dryRunOutputFileName) {
+ config.setDryRunOutputAsFileName(dryRunOutputFileName);
+ return this;
+ }
+
+ /**
+ * Rules for the built-in error handler that let you override specific SQL states and errors codes in order to force
+ * specific errors or warnings to be treated as debug messages, info messages, warnings or errors.
+ *
Each error override has the following format: {@code STATE:12345:W}.
+ * It is a 5 character SQL state (or * to match all SQL states), a colon,
+ * the SQL error code (or * to match all SQL error codes), a colon and finally
+ * the desired behavior that should override the initial one.
+ *
The following behaviors are accepted:
+ *
+ *
{@code D} to force a debug message
+ *
{@code D-} to force a debug message, but do not show the original sql state and error code
+ *
{@code I} to force an info message
+ *
{@code I-} to force an info message, but do not show the original sql state and error code
+ *
{@code W} to force a warning
+ *
{@code W-} to force a warning, but do not show the original sql state and error code
+ *
{@code E} to force an error
+ *
{@code E-} to force an error, but do not show the original sql state and error code
+ *
+ *
Example 1: to force Oracle stored procedure compilation issues to produce
+ * errors instead of warnings, the following errorOverride can be used: {@code 99999:17110:E}
+ *
Example 2: to force SQL Server PRINT messages to be displayed as info messages (without SQL state and error
+ * code details) instead of warnings, the following errorOverride can be used: {@code S0001:0:I-}
+ *
Example 3: to force all errors with SQL error code 123 to be treated as warnings instead,
+ * the following errorOverride can be used: {@code *:123:W}
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param errorOverrides The ErrorOverrides or an empty array if none are defined. (default: none)
+ */
+ public FluentConfiguration errorOverrides(String... errorOverrides) {
+ config.setErrorOverrides(errorOverrides);
+ return this;
+ }
+
+ /**
+ * Whether to group all pending migrations together in the same transaction when applying them (only recommended for databases with support for DDL transactions).
+ *
+ * @param group {@code true} if migrations should be grouped. {@code false} if they should be applied individually instead. (default: {@code false})
+ */
+ public FluentConfiguration group(boolean group) {
+ config.setGroup(group);
+ return this;
+ }
+
+ /**
+ * The username that will be recorded in the schema history table as having applied the migration.
+ *
+ * @param installedBy The username or {@code null} for the current database user of the connection. (default: {@code null}).
+ */
+ public FluentConfiguration installedBy(String installedBy) {
+ config.setInstalledBy(installedBy);
+ return this;
+ }
+
+ /**
+ * Whether to allow mixing transactional and non-transactional statements within the same migration. Enabling this
+ * automatically causes the entire affected migration to be run without a transaction.
+ *
+ *
Note that this is only applicable for PostgreSQL, Aurora PostgreSQL, SQL Server and SQLite which all have
+ * statements that do not run at all within a transaction.
+ *
This is not to be confused with implicit transaction, as they occur in MySQL or Oracle, where even though a
+ * DDL statement was run within a transaction, the database will issue an implicit commit before and after
+ * its execution.
+ *
+ * @param mixed {@code true} if mixed migrations should be allowed. {@code false} if an error should be thrown instead. (default: {@code false})
+ */
+ public FluentConfiguration mixed(boolean mixed) {
+ config.setMixed(mixed);
+ return this;
+ }
+
+ /**
+ * Ignore missing migrations when reading the schema history table. These are migrations that were performed by an
+ * older deployment of the application that are no longer available in this version. For example: we have migrations
+ * available on the classpath with versions 1.0 and 3.0. The schema history table indicates that a migration with version 2.0
+ * (unknown to us) has also been applied. Instead of bombing out (fail fast) with an exception, a
+ * warning is logged and Flyway continues normally. This is useful for situations where one must be able to deploy
+ * a newer version of the application even though it doesn't contain migrations included with an older one anymore.
+ * Note that if the most recently applied migration is removed, Flyway has no way to know it is missing and will
+ * mark it as future instead.
+ *
+ * @param ignoreMissingMigrations {@code true} to continue normally and log a warning, {@code false} to fail fast with an exception.
+ * (default: {@code false})
+ */
+ public FluentConfiguration ignoreMissingMigrations(boolean ignoreMissingMigrations) {
+ config.setIgnoreMissingMigrations(ignoreMissingMigrations);
+ return this;
+ }
+
+ /**
+ * Ignore ignored migrations when reading the schema history table. These are migrations that were added in between
+ * already migrated migrations in this version. For example: we have migrations available on the classpath with
+ * versions from 1.0 to 3.0. The schema history table indicates that version 1 was finished on 1.0.15, and the next
+ * one was 2.0.0. But with the next release a new migration was added to version 1: 1.0.16. Such scenario is ignored
+ * by migrate command, but by default is rejected by validate. When ignoreIgnoredMigrations is enabled, such case
+ * will not be reported by validate command. This is useful for situations where one must be able to deliver
+ * complete set of migrations in a delivery package for multiple versions of the product, and allows for further
+ * development of older versions.
+ *
+ * @param ignoreIgnoredMigrations {@code true} to continue normally, {@code false} to fail fast with an exception.
+ * (default: {@code false})
+ */
+ public FluentConfiguration ignoreIgnoredMigrations(boolean ignoreIgnoredMigrations) {
+ config.setIgnoreIgnoredMigrations(ignoreIgnoredMigrations);
+ return this;
+ }
+
+ /**
+ * Ignore pending migrations when reading the schema history table. These are migrations that are available
+ * but have not yet been applied. This can be useful for verifying that in-development migration changes
+ * don't contain any validation-breaking changes of migrations that have already been applied to a production
+ * environment, e.g. as part of a CI/CD process, without failing because of the existence of new migration versions.
+ *
+ * @param ignorePendingMigrations {@code true} to continue normally, {@code false} to fail fast with an exception.
+ * (default: {@code false})
+ */
+ public FluentConfiguration ignorePendingMigrations(boolean ignorePendingMigrations) {
+ config.setIgnorePendingMigrations(ignorePendingMigrations);
+ return this;
+ }
+
+ /**
+ * Whether to ignore future migrations when reading the schema history table. These are migrations that were performed by a
+ * newer deployment of the application that are not yet available in this version. For example: we have migrations
+ * available on the classpath up to version 3.0. The schema history table indicates that a migration to version 4.0
+ * (unknown to us) has already been applied. Instead of bombing out (fail fast) with an exception, a
+ * warning is logged and Flyway continues normally. This is useful for situations where one must be able to redeploy
+ * an older version of the application after the database has been migrated by a newer one.
+ *
+ * @param ignoreFutureMigrations {@code true} to continue normally and log a warning, {@code false} to fail
+ * fast with an exception. (default: {@code true})
+ */
+ public FluentConfiguration ignoreFutureMigrations(boolean ignoreFutureMigrations) {
+ config.setIgnoreFutureMigrations(ignoreFutureMigrations);
+ return this;
+ }
+
+ /**
+ * Whether to validate migrations and callbacks whose scripts do not obey the correct naming convention. A failure can be
+ * useful to check that errors such as case sensitivity in migration prefixes have been corrected.
+ *
+ * @param validateMigrationNaming {@code false} to continue normally, {@code true} to fail
+ * fast with an exception. (default: {@code false})
+ */
+ public FluentConfiguration validateMigrationNaming(boolean validateMigrationNaming){
+ config.setValidateMigrationNaming(validateMigrationNaming);
+ return this;
+ }
+
+ /**
+ * Whether to automatically call validate or not when running migrate.
+ *
+ * @param validateOnMigrate {@code true} if validate should be called. {@code false} if not. (default: {@code true})
+ */
+ public FluentConfiguration validateOnMigrate(boolean validateOnMigrate) {
+ config.setValidateOnMigrate(validateOnMigrate);
+ return this;
+ }
+
+ /**
+ * Whether to automatically call clean or not when a validation error occurs.
+ *
This is exclusively intended as a convenience for development. even though we
+ * strongly recommend not to change migration scripts once they have been checked into SCM and run, this provides a
+ * way of dealing with this case in a smooth manner. The database will be wiped clean automatically, ensuring that
+ * the next migration will bring you back to the state checked into SCM.
+ *
Warning ! Do not enable in production !
+ *
+ * @param cleanOnValidationError {@code true} if clean should be called. {@code false} if not. (default: {@code false})
+ */
+ public FluentConfiguration cleanOnValidationError(boolean cleanOnValidationError) {
+ config.setCleanOnValidationError(cleanOnValidationError);
+ return this;
+ }
+
+ /**
+ * Whether to disable clean.
+ *
This is especially useful for production environments where running clean can be quite a career limiting move.
+ *
+ * @param cleanDisabled {@code true} to disable clean. {@code false} to leave it enabled. (default: {@code false})
+ */
+ public FluentConfiguration cleanDisabled(boolean cleanDisabled) {
+ config.setCleanDisabled(cleanDisabled);
+ return this;
+ }
+
+ /**
+ * Sets the locations to scan recursively for migrations.
+ *
The location type is determined by its prefix.
+ * Unprefixed locations or locations starting with {@code classpath:} point to a package on the classpath and may
+ * contain both SQL and Java-based migrations.
+ * Locations starting with {@code filesystem:} point to a directory on the filesystem, may only
+ * contain SQL migrations and are only scanned recursively down non-hidden directories.
+ *
+ * @param locations Locations to scan recursively for migrations. (default: db/migration)
+ */
+ public FluentConfiguration locations(String... locations) {
+ config.setLocationsAsStrings(locations);
+ return this;
+ }
+
+ /**
+ * Sets the locations to scan recursively for migrations.
+ *
The location type is determined by its prefix.
+ * Unprefixed locations or locations starting with {@code classpath:} point to a package on the classpath and may
+ * contain both SQL and Java-based migrations.
+ * Locations starting with {@code filesystem:} point to a directory on the filesystem, may only
+ * contain SQL migrations and are only scanned recursively down non-hidden directories.
+ *
+ * @param locations Locations to scan recursively for migrations. (default: db/migration)
+ */
+ public FluentConfiguration locations(Location... locations) {
+ config.setLocations(locations);
+ return this;
+ }
+
+ /**
+ * Sets the encoding of Sql migrations.
+ *
+ * @param encoding The encoding of Sql migrations. (default: UTF-8)
+ */
+ public FluentConfiguration encoding(String encoding) {
+ config.setEncodingAsString(encoding);
+ return this;
+ }
+
+ /**
+ * Sets the encoding of Sql migrations.
+ *
+ * @param encoding The encoding of Sql migrations. (default: UTF-8)
+ */
+ public FluentConfiguration encoding(Charset encoding) {
+ config.setEncoding(encoding);
+ return this;
+ }
+
+ /**
+ * Sets the default schema managed by Flyway. This schema name is case-sensitive. If not specified, but
+ * schemas is, Flyway uses the first schema in that list. If that is also not specified, Flyway uses the default
+ * schema for the database connection.
+ *
Consequences:
+ *
+ *
This schema will be the one containing the schema history table.
+ *
This schema will be the default for the database connection (provided the database supports this concept).
+ *
+ *
+ * @param schema The default schema managed by Flyway.
+ */
+ public FluentConfiguration defaultSchema(String schema) {
+ config.setDefaultSchema(schema);
+ return this;
+ }
+
+ /**
+ * Sets the schemas managed by Flyway. These schema names are case-sensitive. If not specified, Flyway uses
+ * the default schema for the database connection. If defaultSchemaName is not specified, then the first of
+ * this list also acts as default schema.
+ *
Consequences:
+ *
+ *
Flyway will automatically attempt to create all these schemas, unless they already exist.
+ *
The schemas will be cleaned in the order of this list.
+ *
If Flyway created them, the schemas themselves will be dropped when cleaning.
+ *
+ *
+ * @param schemas The schemas managed by Flyway. May not be {@code null}. Must contain at least one element.
+ */
+ public FluentConfiguration schemas(String... schemas) {
+ config.setSchemas(schemas);
+ return this;
+ }
+
+ /**
+ *
Sets the name of the schema history table that will be used by Flyway.
By default (single-schema mode)
+ * the schema history table is placed in the default schema for the connection provided by the datasource.
When
+ * the flyway.schemas property is set (multi-schema mode), the schema history table is placed in the first schema
+ * of the list.
+ *
+ * @param table The name of the schema history table that will be used by Flyway. (default: flyway_schema_history)
+ */
+ public FluentConfiguration table(String table) {
+ config.setTable(table);
+ return this;
+ }
+
+ /**
+ *
Sets the tablespace where to create the schema history table that will be used by Flyway.
+ *
If not specified, Flyway uses the default tablespace for the database connection.
+ * This setting is only relevant for databases that do support the notion of tablespaces. Its value is simply
+ * ignored for all others.
+ *
+ * @param tablespace The tablespace where to create the schema history table that will be used by Flyway.
+ */
+ public FluentConfiguration tablespace(String tablespace) {
+ config.setTablespace(tablespace);
+ return this;
+ }
+
+ /**
+ * Sets the target version up to which Flyway should consider migrations.
+ * Migrations with a higher version number will be ignored.
+ * Special values:
+ *
+ *
{@code current}: designates the current version of the schema
+ *
{@code latest}: the latest version of the schema, as defined by the migration with the highest version
+ *
+ * Defaults to {@code latest}.
+ */
+ public FluentConfiguration target(MigrationVersion target) {
+ config.setTarget(target);
+ return this;
+ }
+
+ /**
+ * Sets the target version up to which Flyway should consider migrations.
+ * Migrations with a higher version number will be ignored.
+ * Special values:
+ *
+ *
{@code current}: designates the current version of the schema
+ *
{@code latest}: the latest version of the schema, as defined by the migration with the highest version
+ *
+ * Defaults to {@code latest}.
+ */
+ public FluentConfiguration target(String target) {
+ config.setTargetAsString(target);
+ return this;
+ }
+
+ /**
+ * Sets whether placeholders should be replaced.
+ *
+ * @param placeholderReplacement Whether placeholders should be replaced. (default: true)
+ */
+ public FluentConfiguration placeholderReplacement(boolean placeholderReplacement) {
+ config.setPlaceholderReplacement(placeholderReplacement);
+ return this;
+ }
+
+ /**
+ * Sets the placeholders to replace in sql migration scripts.
+ *
+ * @param placeholders The map of <placeholder, replacementValue> to apply to sql migration scripts.
+ */
+ public FluentConfiguration placeholders(Map placeholders) {
+ config.setPlaceholders(placeholders);
+ return this;
+ }
+
+ /**
+ * Sets the prefix of every placeholder.
+ *
+ * @param placeholderPrefix The prefix of every placeholder. (default: ${ )
+ */
+ public FluentConfiguration placeholderPrefix(String placeholderPrefix) {
+ config.setPlaceholderPrefix(placeholderPrefix);
+ return this;
+ }
+
+ /**
+ * Sets the suffix of every placeholder.
+ *
+ * @param placeholderSuffix The suffix of every placeholder. (default: } )
+ */
+ public FluentConfiguration placeholderSuffix(String placeholderSuffix) {
+ config.setPlaceholderSuffix(placeholderSuffix);
+ return this;
+ }
+
+ /**
+ * Sets the file name prefix for sql migrations.
+ *
Sql migrations have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to V1_1__My_description.sql
+ *
+ * @param sqlMigrationPrefix The file name prefix for sql migrations (default: V)
+ */
+ public FluentConfiguration sqlMigrationPrefix(String sqlMigrationPrefix) {
+ config.setSqlMigrationPrefix(sqlMigrationPrefix);
+ return this;
+ }
+
+ @Override
+ public String getUndoSqlMigrationPrefix() {
+ return config.getUndoSqlMigrationPrefix();
+ }
+
+ /**
+ * Sets the file name prefix for undo SQL migrations. (default: U)
+ *
Undo SQL migrations are responsible for undoing the effects of the versioned migration with the same version.
+ *
They have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to U1.1__My_description.sql
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param undoSqlMigrationPrefix The file name prefix for undo SQL migrations. (default: U)
+ */
+ public FluentConfiguration undoSqlMigrationPrefix(String undoSqlMigrationPrefix) {
+ config.setUndoSqlMigrationPrefix(undoSqlMigrationPrefix);
+ return this;
+ }
+
+ /**
+ * Sets the file name prefix for repeatable sql migrations.
+ *
Repeatable sql migrations have the following file name structure: prefixSeparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to R__My_description.sql
+ *
+ * @param repeatableSqlMigrationPrefix The file name prefix for repeatable sql migrations (default: R)
+ */
+ public FluentConfiguration repeatableSqlMigrationPrefix(String repeatableSqlMigrationPrefix) {
+ config.setRepeatableSqlMigrationPrefix(repeatableSqlMigrationPrefix);
+ return this;
+ }
+
+ /**
+ * Sets the file name separator for sql migrations.
+ *
Sql migrations have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to V1_1__My_description.sql
+ *
+ * @param sqlMigrationSeparator The file name separator for sql migrations (default: __)
+ */
+ public FluentConfiguration sqlMigrationSeparator(String sqlMigrationSeparator) {
+ config.setSqlMigrationSeparator(sqlMigrationSeparator);
+ return this;
+ }
+
+ /**
+ * The file name suffixes for SQL migrations. (default: .sql)
+ *
SQL migrations have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix ,
+ * which using the defaults translates to V1_1__My_description.sql
+ *
Multiple suffixes (like .sql,.pkg,.pkb) can be specified for easier compatibility with other tools such as
+ * editors with specific file associations.
+ *
+ * @param sqlMigrationSuffixes The file name suffixes for SQL migrations.
+ */
+ public FluentConfiguration sqlMigrationSuffixes(String... sqlMigrationSuffixes) {
+ config.setSqlMigrationSuffixes(sqlMigrationSuffixes);
+ return this;
+ }
+
+ /**
+ * The manually added Java-based migrations. These are not Java-based migrations discovered through classpath
+ * scanning and instantiated by Flyway. Instead these are manually added instances of JavaMigration.
+ * This is particularly useful when working with a dependency injection container, where you may want the DI
+ * container to instantiate the class and wire up its dependencies for you.
+ *
+ * @param javaMigrations The manually added Java-based migrations. An empty array if none. (default: none)
+ */
+ public FluentConfiguration javaMigrations(JavaMigration... javaMigrations) {
+ config.setJavaMigrations(javaMigrations);
+ return this;
+ }
+
+ /**
+ * Sets the datasource to use. Must have the necessary privileges to execute ddl.
+ *
+ * @param dataSource The datasource to use. Must have the necessary privileges to execute ddl.
+ */
+ public FluentConfiguration dataSource(DataSource dataSource) {
+ config.setDataSource(dataSource);
+ return this;
+ }
+
+ /**
+ * Sets the datasource to use. Must have the necessary privileges to execute ddl.
+ *
+ * @param url The JDBC URL of the database.
+ * @param user The user of the database.
+ * @param password The password of the database.
+ */
+ public FluentConfiguration dataSource(String url, String user, String password) {
+ config.setDataSource(url, user, password);
+ return this;
+ }
+
+ /**
+ * The maximum number of retries when attempting to connect to the database. After each failed attempt, Flyway will
+ * wait 1 second before attempting to connect again, up to the maximum number of times specified by connectRetries.
+ *
+ * @param connectRetries The maximum number of retries (default: 0).
+ */
+ public FluentConfiguration connectRetries(int connectRetries) {
+ config.setConnectRetries(connectRetries);
+ return this;
+ }
+
+ /**
+ * The SQL statements to run to initialize a new database connection immediately after opening it.
+ *
+ * @param initSql The SQL statements. (default: {@code null})
+ */
+ public FluentConfiguration initSql(String initSql) {
+ config.setInitSql(initSql);
+ return this;
+ }
+
+ /**
+ * Sets the version to tag an existing schema with when executing baseline.
+ *
+ * @param baselineVersion The version to tag an existing schema with when executing baseline. (default: 1)
+ */
+ public FluentConfiguration baselineVersion(MigrationVersion baselineVersion) {
+ config.setBaselineVersion(baselineVersion);
+ return this;
+ }
+
+ /**
+ * Sets the version to tag an existing schema with when executing baseline.
+ *
+ * @param baselineVersion The version to tag an existing schema with when executing baseline. (default: 1)
+ */
+ public FluentConfiguration baselineVersion(String baselineVersion) {
+ config.setBaselineVersion(MigrationVersion.fromVersion(baselineVersion));
+ return this;
+ }
+
+ /**
+ * Sets the description to tag an existing schema with when executing baseline.
+ *
+ * @param baselineDescription The description to tag an existing schema with when executing baseline. (default: << Flyway Baseline >>)
+ */
+ public FluentConfiguration baselineDescription(String baselineDescription) {
+ config.setBaselineDescription(baselineDescription);
+ return this;
+ }
+
+ /**
+ *
+ * Whether to automatically call baseline when migrate is executed against a non-empty schema with no schema history table.
+ * This schema will then be baselined with the {@code baselineVersion} before executing the migrations.
+ * Only migrations above {@code baselineVersion} will then be applied.
+ *
+ *
+ * This is useful for initial Flyway production deployments on projects with an existing DB.
+ *
+ *
+ * Be careful when enabling this as it removes the safety net that ensures
+ * Flyway does not migrate the wrong database in case of a configuration mistake!
+ *
+ *
+ * @param baselineOnMigrate {@code true} if baseline should be called on migrate for non-empty schemas, {@code false} if not. (default: {@code false})
+ */
+ public FluentConfiguration baselineOnMigrate(boolean baselineOnMigrate) {
+ config.setBaselineOnMigrate(baselineOnMigrate);
+ return this;
+ }
+
+ /**
+ * Allows migrations to be run "out of order".
+ *
If you already have versions 1 and 3 applied, and now a version 2 is found,
+ * it will be applied too instead of being ignored.
+ *
+ * @param outOfOrder {@code true} if outOfOrder migrations should be applied, {@code false} if not. (default: {@code false})
+ */
+ public FluentConfiguration outOfOrder(boolean outOfOrder) {
+ config.setOutOfOrder(outOfOrder);
+ return this;
+ }
+
+ /**
+ * Gets the callbacks for lifecycle notifications.
+ *
+ * @return The callbacks for lifecycle notifications. An empty array if none. (default: none)
+ */
+ @Override
+ public Callback[] getCallbacks() {
+ return config.getCallbacks();
+ }
+
+ @Override
+ public boolean isSkipDefaultCallbacks() {
+ return config.isSkipDefaultCallbacks();
+ }
+
+ /**
+ * Set the callbacks for lifecycle notifications.
+ *
+ * @param callbacks The callbacks for lifecycle notifications. (default: none)
+ */
+ public FluentConfiguration callbacks(Callback... callbacks) {
+ config.setCallbacks(callbacks);
+ return this;
+ }
+
+ /**
+ * Set the callbacks for lifecycle notifications.
+ *
+ * @param callbacks The fully qualified class names of the callbacks for lifecycle notifications. (default: none)
+ */
+ public FluentConfiguration callbacks(String... callbacks) {
+ config.setCallbacksAsClassNames(callbacks);
+ return this;
+ }
+
+ /**
+ * Whether Flyway should skip the default callbacks. If true, only custom callbacks are used.
+ *
+ * @param skipDefaultCallbacks Whether default built-in callbacks should be skipped.
(default: false)
+ */
+ public FluentConfiguration skipDefaultCallbacks(boolean skipDefaultCallbacks) {
+ config.setSkipDefaultCallbacks(skipDefaultCallbacks);
+ return this;
+ }
+
+ /**
+ * Sets custom MigrationResolvers to be used in addition to the built-in ones for resolving Migrations to apply.
+ *
+ * @param resolvers The custom MigrationResolvers to be used in addition to the built-in ones for resolving Migrations to apply. (default: empty list)
+ */
+ public FluentConfiguration resolvers(MigrationResolver... resolvers) {
+ config.setResolvers(resolvers);
+ return this;
+ }
+
+ /**
+ * Sets custom MigrationResolvers to be used in addition to the built-in ones for resolving Migrations to apply.
+ *
+ * @param resolvers The fully qualified class names of the custom MigrationResolvers to be used in addition to the built-in ones for resolving Migrations to apply. (default: empty list)
+ */
+ public FluentConfiguration resolvers(String... resolvers) {
+ config.setResolversAsClassNames(resolvers);
+ return this;
+ }
+
+ /**
+ * Whether Flyway should skip the default resolvers. If true, only custom resolvers are used.
+ *
+ * @param skipDefaultResolvers Whether default built-in resolvers should be skipped.
(default: false)
+ */
+ public FluentConfiguration skipDefaultResolvers(boolean skipDefaultResolvers) {
+ config.setSkipDefaultResolvers(skipDefaultResolvers);
+ return this;
+ }
+
+ /**
+ * Whether to stream SQL migrations when executing them. Streaming doesn't load the entire migration in memory at
+ * once. Instead each statement is loaded individually. This is particularly useful for very large SQL migrations
+ * composed of multiple MB or even GB of reference data, as this dramatically reduces Flyway's memory consumption.
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param stream {@code true} to stream SQL migrations. {@code false} to fully loaded them in memory instead. (default: {@code false})
+ */
+ public FluentConfiguration stream(boolean stream) {
+ config.setStream(stream);
+ return this;
+ }
+
+ /**
+ * Whether to batch SQL statements when executing them. Batching can save up to 99 percent of network roundtrips by
+ * sending up to 100 statements at once over the network to the database, instead of sending each statement
+ * individually. This is particularly useful for very large SQL migrations composed of multiple MB or even GB of
+ * reference data, as this can dramatically reduce the network overhead. This is supported for INSERT, UPDATE,
+ * DELETE, MERGE and UPSERT statements. All other statements are automatically executed without batching.
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param batch {@code true} to batch SQL statements. {@code false} to execute them individually instead. (default: {@code false})
+ */
+ public FluentConfiguration batch(boolean batch) {
+ config.setBatch(batch);
+ return this;
+ }
+
+ /**
+ * Whether to Flyway's support for Oracle SQL*Plus commands should be activated.
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param oracleSqlplus {@code true} to active SQL*Plus support. {@code false} to fail fast instead. (default: {@code false})
+ */
+ public FluentConfiguration oracleSqlplus(boolean oracleSqlplus) {
+ config.setOracleSqlplus(oracleSqlplus);
+ return this;
+ }
+
+ /**
+ * Whether Flyway should issue a warning instead of an error whenever it encounters an Oracle SQL*Plus statement
+ * it doesn't yet support.
+ *
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param oracleSqlplusWarn {@code true} to issue a warning. {@code false} to fail fast instead. (default: {@code false})
+ */
+ public FluentConfiguration oracleSqlplusWarn(boolean oracleSqlplusWarn) {
+ config.setOracleSqlplusWarn(oracleSqlplusWarn);
+ return this;
+ }
+
+ /**
+ * Your Flyway license key (FL01...). Not yet a Flyway Pro or Enterprise Edition customer?
+ * Request your Flyway trial license key
+ * to try out Flyway Pro and Enterprise Edition features free for 30 days.
+ *
+ *
Flyway Pro and Flyway Enterprise only
+ *
+ * @param licenseKey Your Flyway license key.
+ */
+ public FluentConfiguration licenseKey(String licenseKey) {
+ config.setLicenseKey(licenseKey);
+ return this;
+ }
+
+ /**
+ * Configures Flyway with these properties. This overwrites any existing configuration. Property names are
+ * documented in the flyway maven plugin.
+ *
To use a custom ClassLoader, setClassLoader() must be called prior to calling this method.
+ *
+ * @param properties Properties used for configuration.
+ * @throws FlywayException when the configuration failed.
+ */
+ public FluentConfiguration configuration(Properties properties) {
+ config.configure(properties);
+ return this;
+ }
+
+ /**
+ * Configures Flyway with these properties. This overwrites any existing configuration. Property names are
+ * documented in the flyway maven plugin.
+ *
To use a custom ClassLoader, it must be passed to the Flyway constructor prior to calling this method.
+ *
+ * @param props Properties used for configuration.
+ * @throws FlywayException when the configuration failed.
+ */
+ public FluentConfiguration configuration(Map props) {
+ config.configure(props);
+ return this;
+ }
+
+ /**
+ * Load configuration files from the default locations:
+ * $installationDir$/conf/flyway.conf
+ * $user.home$/flyway.conf
+ * $workingDirectory$/flyway.conf
+ *
+ * The configuration files must be encoded with UTF-8.
+ *
+ * @throws FlywayException when the configuration failed.
+ */
+ public FluentConfiguration loadDefaultConfigurationFiles() {
+ return loadDefaultConfigurationFiles("UTF-8");
+ }
+
+ /**
+ * Load configuration files from the default locations:
+ * $installationDir$/conf/flyway.conf
+ * $user.home$/flyway.conf
+ * $workingDirectory$/flyway.conf
+ *
+ * @param encoding the conf file encoding.
+ * @throws FlywayException when the configuration failed.
+ */
+ public FluentConfiguration loadDefaultConfigurationFiles(String encoding) {
+ String installationPath = ClassUtils.getLocationOnDisk(FluentConfiguration.class);
+ File installationDir = new File(installationPath).getParentFile();
+
+ Map configMap = ConfigUtils.loadDefaultConfigurationFiles(installationDir, encoding);
+
+ config.configure(configMap);
+ return this;
+ }
+
+ /**
+ * Configures Flyway using FLYWAY_* environment variables.
+ *
+ * @throws FlywayException when the configuration failed.
+ */
+ public FluentConfiguration envVars() {
+ config.configureUsingEnvVars();
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/configuration/package-info.java b/flyway-core/src/main/java/org/flywaydb/core/api/configuration/package-info.java
new file mode 100644
index 00000000..e360e7d9
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/configuration/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+/**
+ * Interfaces for Flyway configuration injection.
+ */
+package org.flywaydb.core.api.configuration;
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/executor/Context.java b/flyway-core/src/main/java/org/flywaydb/core/api/executor/Context.java
new file mode 100644
index 00000000..c682487f
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/executor/Context.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.executor;
+
+import org.flywaydb.core.api.configuration.Configuration;
+
+import java.sql.Connection;
+
+/**
+ * The context relevant to a migration executor.
+ */
+public interface Context {
+ /**
+ * @return The configuration currently in use.
+ */
+ Configuration getConfiguration();
+
+ /**
+ * @return The JDBC connection being used. Transaction are managed by Flyway.
+ * When the context is passed to the migrate method, a transaction will already have
+ * been started if required and will be automatically committed or rolled back afterwards, unless the
+ * canExecuteInTransaction method has been implemented to return false.
+ */
+ Connection getConnection();
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/executor/MigrationExecutor.java b/flyway-core/src/main/java/org/flywaydb/core/api/executor/MigrationExecutor.java
new file mode 100644
index 00000000..a200c0ea
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/executor/MigrationExecutor.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.executor;
+
+import java.sql.SQLException;
+
+/**
+ * Executes a migration.
+ */
+public interface MigrationExecutor {
+ /**
+ * Executes the migration this executor is associated with.
+ *
+ * @param context The context to use to execute the migration against the DB.
+ * @throws SQLException when the execution of a statement failed.
+ */
+ void execute(Context context) throws SQLException;
+
+ /**
+ * Whether the execution can take place inside a transaction. Almost all implementation should return {@code true}.
+ * This however makes it possible to execute certain migrations outside a transaction. This is useful for databases
+ * like PostgreSQL and SQL Server where certain statement can only execute outside a transaction.
+ *
+ * @return {@code true} if a transaction should be used (highly recommended), or {@code false} if not.
+ */
+ boolean canExecuteInTransaction();
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/executor/package-info.java b/flyway-core/src/main/java/org/flywaydb/core/api/executor/package-info.java
new file mode 100644
index 00000000..d25f38f7
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/executor/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+/**
+ * Interfaces for Migration executors.
+ */
+package org.flywaydb.core.api.executor;
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/logging/Log.java b/flyway-core/src/main/java/org/flywaydb/core/api/logging/Log.java
new file mode 100644
index 00000000..83326562
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/logging/Log.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.logging;
+
+/**
+ * A logger.
+ */
+public interface Log {
+ /**
+ * @return Whether debug logging is enabled.
+ */
+ boolean isDebugEnabled();
+
+ /**
+ * Logs a debug message.
+ *
+ * @param message The message to log.
+ */
+ void debug(String message);
+
+ /**
+ * Logs an info message.
+ *
+ * @param message The message to log.
+ */
+ void info(String message);
+
+ /**
+ * Logs a warning message.
+ *
+ * @param message The message to log.
+ */
+ void warn(String message);
+
+ /**
+ * Logs an error message.
+ *
+ * @param message The message to log.
+ */
+ void error(String message);
+
+ /**
+ * Logs an error message and the exception that caused it.
+ *
+ * @param message The message to log.
+ * @param e The exception that caused the error.
+ */
+ void error(String message, Exception e);
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/logging/LogCreator.java b/flyway-core/src/main/java/org/flywaydb/core/api/logging/LogCreator.java
new file mode 100644
index 00000000..8e04e2ae
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/logging/LogCreator.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.logging;
+
+/**
+ * Factory for implementation-specific loggers.
+ */
+public interface LogCreator {
+ /**
+ * Creates an implementation-specific logger for this class.
+ *
+ * @param clazz The class to create the logger for.
+ * @return The logger.
+ */
+ Log createLogger(Class> clazz);
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/logging/LogFactory.java b/flyway-core/src/main/java/org/flywaydb/core/api/logging/LogFactory.java
new file mode 100644
index 00000000..2671d431
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/logging/LogFactory.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.logging;
+
+import org.flywaydb.core.internal.logging.LogCreatorFactory;
+
+/**
+ * Factory for loggers. Custom MigrationResolver, MigrationExecutor, Callback and JavaMigration
+ * implementations should use this to obtain a logger that will work with any logging framework across all environments
+ * (API, Maven, Gradle, CLI, etc).
+ */
+public class LogFactory {
+ /**
+ * Factory for implementation-specific loggers.
+ */
+ private static LogCreator logCreator;
+
+ /**
+ * The factory for implementation-specific loggers to be used as a fallback when no other suitable loggers were found.
+ */
+ private static LogCreator fallbackLogCreator;
+
+ /**
+ * Prevent instantiation.
+ */
+ private LogFactory() {
+ // Do nothing
+ }
+
+ /**
+ * Sets the LogCreator that will be used. This will effectively override Flyway's default LogCreator auto-detection
+ * logic and force Flyway to always use this LogCreator regardless of which log libraries are present on the
+ * classpath.
+ *
+ *
This is primarily meant for integrating Flyway into environments with their own logging system (like Ant,
+ * Gradle, Maven, ...). This ensures Flyway is a good citizen in those environments and sends its logs through the
+ * expected pipeline.
+ *
+ * @param logCreator The factory for implementation-specific loggers.
+ */
+ public static void setLogCreator(LogCreator logCreator) {
+ LogFactory.logCreator = logCreator;
+ }
+
+ /**
+ * Sets the fallback LogCreator. This LogCreator will be used as a fallback solution when the default LogCreator
+ * auto-detection logic fails to detect a suitable LogCreator based on the log libraries present on the classpath.
+ *
+ * @param fallbackLogCreator The factory for implementation-specific loggers to be used as a fallback when no other
+ * suitable loggers were found.
+ */
+ public static void setFallbackLogCreator(LogCreator fallbackLogCreator) {
+ LogFactory.fallbackLogCreator = fallbackLogCreator;
+ }
+
+ /**
+ * Retrieves the matching logger for this class.
+ *
+ * @param clazz The class to get the logger for.
+ * @return The logger.
+ */
+ public static Log getLog(Class> clazz) {
+ if (logCreator == null) {
+ logCreator = LogCreatorFactory.getLogCreator(LogFactory.class.getClassLoader(), fallbackLogCreator);
+ }
+
+ return logCreator.createLogger(clazz);
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/logging/package-info.java b/flyway-core/src/main/java/org/flywaydb/core/api/logging/package-info.java
new file mode 100644
index 00000000..1555fa80
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/logging/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+/**
+ * Interfaces for Flyway's log abstraction. Custom MigrationResolver, MigrationExecutor, FlywayCallback, ErrorHandler and JdbcMigration
+ * implementations should use this to obtain a logger that will work with any logging framework across all environments
+ * (API, Maven, Gradle, CLI, etc).
+ */
+package org.flywaydb.core.api.logging;
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/migration/BaseJavaMigration.java b/flyway-core/src/main/java/org/flywaydb/core/api/migration/BaseJavaMigration.java
new file mode 100644
index 00000000..9eb31a13
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/migration/BaseJavaMigration.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.migration;
+
+import org.flywaydb.core.api.FlywayException;
+import org.flywaydb.core.api.MigrationVersion;
+import org.flywaydb.core.internal.resolver.MigrationInfoHelper;
+import org.flywaydb.core.internal.util.Pair;
+
+/**
+ *
This is the recommended class to extend for implementing Java-based Migrations.
+ *
Subclasses should follow the default Flyway naming convention of having a class name with the following structure:
+ *
+ *
Versioned Migrations: V2__Add_new_table
+ *
Undo Migrations: U2__Add_new_table
+ *
Repeatable Migrations: R__Add_new_table
+ *
+ *
+ *
The file name consists of the following parts:
+ *
+ *
Prefix: V for versioned migrations, U for undo migrations, R for repeatable migrations
+ *
Version: Underscores (automatically replaced by dots at runtime) separate as many parts as you like (Not for repeatable migrations)
+ *
Separator: __ (two underscores)
+ *
Description: Underscores (automatically replaced by spaces at runtime) separate the words
+ *
+ *
If you need more control over the class name, you can override the default convention by implementing the
+ * JavaMigration interface directly. This will allow you to name your class as you wish. Version, description and
+ * migration category are provided by implementing the respective methods.
+ */
+public abstract class BaseJavaMigration implements JavaMigration {
+ private final MigrationVersion version;
+ private final String description;
+
+
+
+
+ /**
+ * Creates a new instance of a Java-based migration following Flyway's default naming convention.
+ */
+ public BaseJavaMigration() {
+ String shortName = getClass().getSimpleName();
+ String prefix;
+
+
+
+ boolean repeatable = shortName.startsWith("R");
+ if (shortName.startsWith("V") || repeatable
+
+
+
+ ) {
+ prefix = shortName.substring(0, 1);
+ } else {
+ throw new FlywayException("Invalid Java-based migration class name: " + getClass().getName()
+ + " => ensure it starts with V" +
+
+
+
+ " or R," +
+ " or implement org.flywaydb.core.api.migration.JavaMigration directly for non-default naming");
+ }
+ Pair info =
+ MigrationInfoHelper.extractVersionAndDescription(shortName, prefix, "__", new String[]{""}, repeatable);
+ version = info.getLeft();
+ description = info.getRight();
+ }
+
+ @Override
+ public MigrationVersion getVersion() {
+ return version;
+ }
+
+ @Override
+ public String getDescription() {
+ return description;
+ }
+
+ @Override
+ public Integer getChecksum() {
+ return null;
+ }
+
+ @Override
+ public boolean isUndo() {
+
+
+
+
+ return false;
+
+ }
+
+ @Override
+ public boolean canExecuteInTransaction() {
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/migration/Context.java b/flyway-core/src/main/java/org/flywaydb/core/api/migration/Context.java
new file mode 100644
index 00000000..6dd9666f
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/migration/Context.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.migration;
+
+import org.flywaydb.core.api.configuration.Configuration;
+
+import java.sql.Connection;
+
+/**
+ * The context relevant to a Java-based migration.
+ */
+public interface Context {
+ /**
+ * @return The configuration currently in use.
+ */
+ Configuration getConfiguration();
+
+ /**
+ * @return The JDBC connection being used. Transaction are managed by Flyway.
+ * When the context is passed to the migrate method, a transaction will already have
+ * been started if required and will be automatically committed or rolled back afterwards, unless the
+ * canExecuteInTransaction method has been implemented to return false.
+ */
+ Connection getConnection();
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/migration/JavaMigration.java b/flyway-core/src/main/java/org/flywaydb/core/api/migration/JavaMigration.java
new file mode 100644
index 00000000..d2c699cf
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/migration/JavaMigration.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.migration;
+
+import org.flywaydb.core.api.MigrationVersion;
+
+/**
+ * Interface to be implemented by Java-based Migrations.
+ *
+ *
Java-based migrations are a great fit for all changes that can not easily be expressed using SQL.
+ *
+ *
These would typically be things like
+ *
+ *
BLOB & CLOB changes
+ *
Advanced bulk data changes (Recalculations, advanced format changes, …)
+ *
+ *
+ *
Migration classes implementing this interface will be
+ * automatically discovered when placed in a location on the classpath.
+ *
+ *
Most users will be better served by subclassing subclass {@link BaseJavaMigration} instead of implementing this
+ * interface directly, as {@link BaseJavaMigration} encourages the use of Flyway's default naming convention and
+ * comes with sensible default implementations of all methods (except migrate of course) while at the same time also
+ * providing better isolation against future additions to this interface.
+ */
+public interface JavaMigration {
+ /**
+ * @return The version of the schema after the migration is complete. {@code null} for repeatable migrations.
+ */
+ MigrationVersion getVersion();
+
+ /**
+ * @return The description of this migration for the migration history. Never {@code null}.
+ */
+ String getDescription();
+
+ /**
+ * Computes the checksum of the migration.
+ *
+ * @return The checksum of the migration.
+ */
+ Integer getChecksum();
+
+ /**
+ * Whether this is an undo migration for a previously applied versioned migration.
+ *
+ * @return {@code true} if it is, {@code false} if not. Always {@code false} for repeatable migrations.
+ */
+ boolean isUndo();
+
+ /**
+ * Whether the execution should take place inside a transaction. Almost all implementation should return {@code true}.
+ * This however makes it possible to execute certain migrations outside a transaction. This is useful for databases
+ * like PostgreSQL and SQL Server where certain statement can only execute outside a transaction.
+ *
+ * @return {@code true} if a transaction should be used (highly recommended), or {@code false} if not.
+ */
+ boolean canExecuteInTransaction();
+
+ /**
+ * Executes this migration. The execution will automatically take place within a transaction, when the underlying
+ * database supports it and the canExecuteInTransaction returns {@code true}.
+ *
+ * @param context The context relevant for this migration, containing things like the JDBC connection to use and the
+ * current Flyway configuration.
+ * @throws Exception when the migration failed.
+ */
+ void migrate(Context context) throws Exception;
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/migration/package-info.java b/flyway-core/src/main/java/org/flywaydb/core/api/migration/package-info.java
new file mode 100644
index 00000000..d6d590ee
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/migration/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+/**
+ * Interfaces for Migration implementors.
+ */
+package org.flywaydb.core.api.migration;
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/package-info.java b/flyway-core/src/main/java/org/flywaydb/core/api/package-info.java
new file mode 100644
index 00000000..f7ea4c0a
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+/**
+ * FlywayException, MigrationInfo and related classes.
+ */
+package org.flywaydb.core.api;
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/resolver/ChecksumMatcher.java b/flyway-core/src/main/java/org/flywaydb/core/api/resolver/ChecksumMatcher.java
new file mode 100644
index 00000000..2986649a
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/resolver/ChecksumMatcher.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.resolver;
+
+interface ChecksumMatcher {
+ boolean checksumMatches(Integer checksum);
+
+ boolean checksumMatchesWithoutBeingIdentical(Integer checksum);
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/resolver/Context.java b/flyway-core/src/main/java/org/flywaydb/core/api/resolver/Context.java
new file mode 100644
index 00000000..62b46df1
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/resolver/Context.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.resolver;
+
+import org.flywaydb.core.api.configuration.Configuration;
+
+import java.sql.Connection;
+
+/**
+ * The context relevant to a migration resolver.
+ */
+public interface Context {
+ /**
+ * @return The configuration currently in use.
+ */
+ Configuration getConfiguration();
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/resolver/MigrationResolver.java b/flyway-core/src/main/java/org/flywaydb/core/api/resolver/MigrationResolver.java
new file mode 100644
index 00000000..1c6b9bfb
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/resolver/MigrationResolver.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.resolver;
+
+import java.util.Collection;
+
+/**
+ * Resolves available migrations. This interface can be implemented to create custom resolvers. A custom resolver
+ * can be used to create additional types of migrations not covered by the standard resolvers (jdbc, sql, spring-jdbc).
+ * Using the skipDefaultResolvers configuration property, the built-in resolvers can also be completely replaced.
+ */
+public interface MigrationResolver {
+ /**
+ * Resolves the available migrations.
+ *
+ * @return The available migrations.
+ */
+ Collection resolveMigrations(Context context);
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/resolver/ResolvedMigration.java b/flyway-core/src/main/java/org/flywaydb/core/api/resolver/ResolvedMigration.java
new file mode 100644
index 00000000..b5bf08fd
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/resolver/ResolvedMigration.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.api.resolver;
+
+import org.flywaydb.core.api.MigrationType;
+import org.flywaydb.core.api.MigrationVersion;
+import org.flywaydb.core.api.executor.MigrationExecutor;
+
+/**
+ * Migration resolved through a MigrationResolver. Can be applied against a database.
+ */
+public interface ResolvedMigration extends ChecksumMatcher {
+ /**
+ * @return The version of the database after applying this migration. {@code null} for repeatable migrations.
+ */
+ MigrationVersion getVersion();
+
+ /**
+ * @return The description of the migration.
+ */
+ String getDescription();
+
+ /**
+ * @return The name of the script to execute for this migration, relative to its base (classpath/filesystem) location.
+ */
+ String getScript();
+
+ /**
+ * @return The checksum of the migration. Optional. Can be {@code null} if not unique checksum is computable.
+ */
+ Integer getChecksum();
+
+ /**
+ * @return The type of migration (INIT, SQL, ...)
+ */
+ MigrationType getType();
+
+ /**
+ * @return The physical location of the migration on disk. Used for more precise error reporting in case of conflict.
+ */
+ String getPhysicalLocation();
+
+ /**
+ * @return The executor to run this migration.
+ */
+ MigrationExecutor getExecutor();
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/api/resolver/package-info.java b/flyway-core/src/main/java/org/flywaydb/core/api/resolver/package-info.java
new file mode 100644
index 00000000..13fd55ac
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/api/resolver/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+/**
+ * Interfaces for Migration resolvers.
+ */
+package org.flywaydb.core.api.resolver;
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/internal/callback/CallbackExecutor.java b/flyway-core/src/main/java/org/flywaydb/core/internal/callback/CallbackExecutor.java
new file mode 100644
index 00000000..1bf6b07f
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/internal/callback/CallbackExecutor.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.internal.callback;
+
+import org.flywaydb.core.api.MigrationInfo;
+import org.flywaydb.core.api.callback.Event;
+import org.flywaydb.core.api.callback.Warning;
+import org.flywaydb.core.api.callback.Error;
+
+import java.util.List;
+
+/**
+ * Executes the callbacks for a specific event.
+ */
+public interface CallbackExecutor {
+ /**
+ * Executes the callbacks for this event on the main connection, within a separate transaction per callback if possible.
+ *
+ * @param event The vent to handle.
+ */
+ void onEvent(Event event);
+
+ /**
+ * Executes the callbacks for this event on the migration connection, within a separate transaction per callback if possible.
+ *
+ * @param event The vent to handle.
+ */
+ void onMigrateOrUndoEvent(Event event);
+
+ /**
+ * Sets the current migration info.
+ *
+ * @param migrationInfo The current migration.
+ */
+ void setMigrationInfo(MigrationInfo migrationInfo);
+
+ /**
+ * Executes the callbacks for an "each" event within the same transaction (if any) as the main operation.
+ *
+ * @param event The event to handle.
+ */
+ void onEachMigrateOrUndoEvent(Event event);
+
+
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/internal/callback/DefaultCallbackExecutor.java b/flyway-core/src/main/java/org/flywaydb/core/internal/callback/DefaultCallbackExecutor.java
new file mode 100644
index 00000000..00849fbf
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/internal/callback/DefaultCallbackExecutor.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.internal.callback;
+
+import org.flywaydb.core.api.FlywayException;
+import org.flywaydb.core.api.MigrationInfo;
+import org.flywaydb.core.api.callback.Callback;
+import org.flywaydb.core.api.callback.Context;
+import org.flywaydb.core.api.callback.Error;
+import org.flywaydb.core.api.callback.Event;
+import org.flywaydb.core.api.callback.Warning;
+import org.flywaydb.core.api.configuration.Configuration;
+import org.flywaydb.core.internal.database.base.Connection;
+import org.flywaydb.core.internal.database.base.Database;
+import org.flywaydb.core.internal.database.base.Schema;
+import org.flywaydb.core.internal.jdbc.ExecutionTemplateFactory;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+ * Executes the callbacks for a specific event.
+ */
+public class DefaultCallbackExecutor implements CallbackExecutor {
+ private final Configuration configuration;
+ private final Database database;
+ private final Schema schema;
+ private final Collection callbacks;
+ private MigrationInfo migrationInfo;
+
+ /**
+ * Creates a new callback executor.
+ *
+ * @param configuration The configuration.
+ * @param database The database.
+ * @param schema The current schema to use for the connection.
+ * @param callbacks The callbacks to execute.
+ */
+ public DefaultCallbackExecutor(Configuration configuration, Database database, Schema schema, Collection callbacks) {
+ this.configuration = configuration;
+ this.database = database;
+ this.schema = schema;
+ this.callbacks = callbacks;
+ }
+
+ @Override
+ public void onEvent(final Event event) {
+ execute(event, database.getMainConnection());
+ }
+
+ @Override
+ public void onMigrateOrUndoEvent(final Event event) {
+ execute(event, database.getMigrationConnection());
+ }
+
+ @Override
+ public void setMigrationInfo(MigrationInfo migrationInfo) {
+ this.migrationInfo = migrationInfo;
+ }
+
+ @Override
+ public void onEachMigrateOrUndoEvent(Event event) {
+ final Context context = new SimpleContext(configuration, database.getMigrationConnection(), migrationInfo);
+ for (Callback callback : callbacks) {
+ if (callback.supports(event, context)) {
+ callback.handle(event, context);
+ }
+ }
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ private void execute(final Event event, final Connection connection) {
+ final Context context = new SimpleContext(configuration, connection, null);
+
+ for (final Callback callback : callbacks) {
+ if (callback.supports(event, context)) {
+ if (callback.canHandleInTransaction(event, context)) {
+ ExecutionTemplateFactory.createExecutionTemplate(connection.getJdbcConnection(),
+ database).execute(new Callable() {
+ @Override
+ public Void call() {
+ DefaultCallbackExecutor.this.execute(connection, callback, event, context);
+ return null;
+ }
+ });
+ } else {
+ execute(connection, callback, event, context);
+ }
+ }
+ }
+ }
+
+ private void execute(Connection connection, Callback callback, Event event, Context context) {
+ connection.restoreOriginalState();
+ connection.changeCurrentSchemaTo(schema);
+ handleEvent(callback, event, context);
+ }
+
+ private void handleEvent(Callback callback, Event event, Context context) {
+ try {
+ callback.handle(event, context);
+ } catch (RuntimeException e) {
+ throw new FlywayException("Error while executing " + event.getId() + " callback: " + e.getMessage(), e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/internal/callback/NoopCallback.java b/flyway-core/src/main/java/org/flywaydb/core/internal/callback/NoopCallback.java
new file mode 100644
index 00000000..99ac6a4c
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/internal/callback/NoopCallback.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.internal.callback;
+
+import org.flywaydb.core.api.callback.Callback;
+import org.flywaydb.core.api.callback.Context;
+import org.flywaydb.core.api.callback.Event;
+
+/**
+ * Callback that does nothing.
+ */
+public enum NoopCallback implements Callback {
+ INSTANCE;
+
+ @Override
+ public boolean supports(Event event, Context context) {
+ return false;
+ }
+
+ @Override
+ public boolean canHandleInTransaction(Event event, Context context) {
+ return true;
+ }
+
+ @Override
+ public void handle(Event event, Context context) {
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/internal/callback/NoopCallbackExecutor.java b/flyway-core/src/main/java/org/flywaydb/core/internal/callback/NoopCallbackExecutor.java
new file mode 100644
index 00000000..90b2f2d1
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/internal/callback/NoopCallbackExecutor.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.internal.callback;
+
+import org.flywaydb.core.api.MigrationInfo;
+import org.flywaydb.core.api.callback.Error;
+import org.flywaydb.core.api.callback.Event;
+import org.flywaydb.core.api.callback.Warning;
+
+import java.util.List;
+
+/**
+ * A callback executor that does nothing.
+ */
+public enum NoopCallbackExecutor implements CallbackExecutor {
+ INSTANCE;
+
+ @Override
+ public void onEvent(Event event) {
+ }
+
+ @Override
+ public void onMigrateOrUndoEvent(Event event) {
+ }
+
+ @Override
+ public void setMigrationInfo(MigrationInfo migrationInfo) {
+ }
+
+ @Override
+ public void onEachMigrateOrUndoEvent(Event event) {
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/internal/callback/SimpleContext.java b/flyway-core/src/main/java/org/flywaydb/core/internal/callback/SimpleContext.java
new file mode 100644
index 00000000..004e4bda
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/internal/callback/SimpleContext.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.internal.callback;
+
+import org.flywaydb.core.api.MigrationInfo;
+import org.flywaydb.core.api.callback.Context;
+import org.flywaydb.core.api.callback.Error;
+import org.flywaydb.core.api.callback.Statement;
+import org.flywaydb.core.api.callback.Warning;
+import org.flywaydb.core.api.configuration.Configuration;
+import org.flywaydb.core.internal.database.base.Connection;
+
+import java.util.List;
+
+public class SimpleContext implements Context {
+ private final Configuration configuration;
+ private final Connection connection;
+ private final MigrationInfo migrationInfo;
+ private final Statement statement;
+
+ SimpleContext(Configuration configuration, Connection connection, MigrationInfo migrationInfo) {
+ this.configuration = configuration;
+ this.connection = connection;
+ this.migrationInfo = migrationInfo;
+ this.statement = null;
+ }
+
+ public SimpleContext(Configuration configuration, Connection connection, MigrationInfo migrationInfo,
+ String sql, List warnings, List errors) {
+ this.configuration = configuration;
+ this.connection = connection;
+ this.migrationInfo = migrationInfo;
+ this.statement = new SimpleStatement(sql, warnings, errors);
+ }
+
+ @Override
+ public Configuration getConfiguration() {
+ return configuration;
+ }
+
+ @Override
+ public java.sql.Connection getConnection() {
+ return connection.getJdbcConnection();
+ }
+
+ @Override
+ public MigrationInfo getMigrationInfo() {
+ return migrationInfo;
+ }
+
+ @Override
+ public Statement getStatement() {
+ return statement;
+ }
+
+
+ private static class SimpleStatement implements Statement {
+ private final String sql;
+ private final List warnings;
+ private final List errors;
+
+ private SimpleStatement(String sql, List warnings, List errors) {
+ this.sql = sql;
+ this.warnings = warnings;
+ this.errors = errors;
+ }
+
+ @Override
+ public String getSql() {
+ return sql;
+ }
+
+ @Override
+ public List getWarnings() {
+ return warnings;
+ }
+
+ @Override
+ public List getErrors() {
+ return errors;
+ }
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/internal/callback/SqlScriptCallbackFactory.java b/flyway-core/src/main/java/org/flywaydb/core/internal/callback/SqlScriptCallbackFactory.java
new file mode 100644
index 00000000..018d82b6
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/internal/callback/SqlScriptCallbackFactory.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.internal.callback;
+
+import org.flywaydb.core.api.FlywayException;
+import org.flywaydb.core.api.callback.Callback;
+import org.flywaydb.core.api.callback.Context;
+import org.flywaydb.core.api.callback.Event;
+import org.flywaydb.core.api.configuration.Configuration;
+import org.flywaydb.core.api.logging.Log;
+import org.flywaydb.core.api.logging.LogFactory;
+import org.flywaydb.core.internal.resource.LoadableResource;
+import org.flywaydb.core.internal.resource.ResourceName;
+import org.flywaydb.core.internal.resource.ResourceNameParser;
+import org.flywaydb.core.internal.resource.ResourceProvider;
+import org.flywaydb.core.internal.sqlscript.SqlScript;
+import org.flywaydb.core.internal.sqlscript.SqlScriptExecutorFactory;
+import org.flywaydb.core.internal.sqlscript.SqlScriptFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Callback factory, looking for SQL scripts (named like on the callback methods) inside the configured locations.
+ */
+public class SqlScriptCallbackFactory {
+ private static final Log LOG = LogFactory.getLog(SqlScriptCallbackFactory.class);
+
+ private final List callbacks = new ArrayList<>();
+
+ /**
+ * Creates a new instance.
+ *
+ * @param resourceProvider The resource provider.
+ * @param sqlScriptFactory The SQL statement factory.
+ * @param configuration The Flyway configuration.
+ */
+ public SqlScriptCallbackFactory(ResourceProvider resourceProvider,
+ SqlScriptExecutorFactory sqlScriptExecutorFactory,
+ SqlScriptFactory sqlScriptFactory,
+ Configuration configuration) {
+ Map callbacksFound = new HashMap<>();
+
+ LOG.debug("Scanning for SQL callbacks ...");
+ Collection resources = resourceProvider.getResources("", configuration.getSqlMigrationSuffixes());
+ ResourceNameParser resourceNameParser = new ResourceNameParser(configuration);
+
+ for (LoadableResource resource : resources) {
+ ResourceName parsedName = resourceNameParser.parse(resource.getFilename());
+ if (!parsedName.isValid()) {
+ continue;
+ }
+
+ String name = parsedName.getFilenameWithoutSuffix();
+ Event event = Event.fromId(parsedName.getPrefix());
+ if (event != null) {
+ SqlScript existing = callbacksFound.get(name);
+ if (existing != null) {
+ throw new FlywayException("Found more than 1 SQL callback script called " + name + "!\n" +
+ "Offenders:\n" +
+ "-> " + existing.getResource().getAbsolutePathOnDisk() + "\n" +
+ "-> " + resource.getAbsolutePathOnDisk());
+ }
+ SqlScript sqlScript = sqlScriptFactory.createSqlScript(resource, configuration.isMixed(), resourceProvider);
+ callbacksFound.put(name, sqlScript);
+ callbacks.add(new SqlScriptCallback(event, parsedName.getDescription(), sqlScriptExecutorFactory, sqlScript
+
+
+
+ ));
+ }
+ }
+ Collections.sort(callbacks);
+ }
+
+ public List getCallbacks() {
+ return new ArrayList<>(callbacks);
+ }
+
+ private static class SqlScriptCallback implements Callback, Comparable {
+ private final Event event;
+ private final String description;
+ private final SqlScriptExecutorFactory sqlScriptExecutorFactory;
+ private final SqlScript sqlScript;
+
+
+
+
+ private SqlScriptCallback(Event event, String description, SqlScriptExecutorFactory sqlScriptExecutorFactory, SqlScript sqlScript
+
+
+
+ ) {
+ this.event = event;
+ this.description = description;
+ this.sqlScriptExecutorFactory = sqlScriptExecutorFactory;
+ this.sqlScript = sqlScript;
+
+
+
+ }
+
+ @Override
+ public boolean supports(Event event, Context context) {
+ return this.event == event;
+ }
+
+ @Override
+ public boolean canHandleInTransaction(Event event, Context context) {
+ return sqlScript.executeInTransaction();
+ }
+
+ @Override
+ public void handle(Event event, Context context) {
+ LOG.info("Executing SQL callback: " + event.getId()
+ + (description == null ? "" : " - " + description)
+ + (sqlScript.executeInTransaction() ? "" : " [non-transactional]"));
+ sqlScriptExecutorFactory.createSqlScriptExecutor(context.getConnection()
+
+
+
+ ).execute(sqlScript);
+ }
+
+ @Override
+ public int compareTo(SqlScriptCallback o) {
+ int result = event.compareTo(o.event);
+ if (result == 0) {
+ if (description == null) {
+ return -1;
+ }
+ if (o.description == null) {
+ return 1;
+ }
+ result = description.compareTo(o.description);
+ }
+ return result;
+ }
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/internal/callback/package-info.java b/flyway-core/src/main/java/org/flywaydb/core/internal/callback/package-info.java
new file mode 100644
index 00000000..b189d1e8
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/internal/callback/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+/**
+ * FlywayException, MigrationInfo and related classes.
+ */
+package org.flywaydb.core.internal.callback;
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/internal/clazz/ClassProvider.java b/flyway-core/src/main/java/org/flywaydb/core/internal/clazz/ClassProvider.java
new file mode 100644
index 00000000..a6078c0e
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/internal/clazz/ClassProvider.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.internal.clazz;
+
+import java.util.Collection;
+
+/**
+ * A facility to obtain classes.
+ */
+public interface ClassProvider {
+ /**
+ * Retrieve all classes which implement the specified interface.
+ *
+ * @return The non-abstract classes that were found.
+ */
+ Collection> getClasses();
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/internal/clazz/NoopClassProvider.java b/flyway-core/src/main/java/org/flywaydb/core/internal/clazz/NoopClassProvider.java
new file mode 100644
index 00000000..fa7f710e
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/internal/clazz/NoopClassProvider.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.internal.clazz;
+
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * ClassProvider that does nothing.
+ */
+public enum NoopClassProvider implements ClassProvider {
+ INSTANCE;
+
+ @Override
+ public Collection> getClasses() {
+ return Collections.emptyList();
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/internal/clazz/package-info.java b/flyway-core/src/main/java/org/flywaydb/core/internal/clazz/package-info.java
new file mode 100644
index 00000000..85d24975
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/internal/clazz/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+/**
+ * Private API. No compatibility guarantees provided.
+ */
+package org.flywaydb.core.internal.clazz;
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/internal/command/DbBaseline.java b/flyway-core/src/main/java/org/flywaydb/core/internal/command/DbBaseline.java
new file mode 100644
index 00000000..8993977b
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/internal/command/DbBaseline.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.internal.command;
+
+import org.flywaydb.core.api.FlywayException;
+import org.flywaydb.core.api.MigrationVersion;
+import org.flywaydb.core.api.callback.Event;
+import org.flywaydb.core.api.logging.Log;
+import org.flywaydb.core.api.logging.LogFactory;
+import org.flywaydb.core.internal.callback.CallbackExecutor;
+import org.flywaydb.core.internal.schemahistory.AppliedMigration;
+import org.flywaydb.core.internal.schemahistory.SchemaHistory;
+
+/**
+ * Handles Flyway's baseline command.
+ */
+public class DbBaseline {
+ private static final Log LOG = LogFactory.getLog(DbBaseline.class);
+
+ /**
+ * The schema history table.
+ */
+ private final SchemaHistory schemaHistory;
+
+ /**
+ * The version to tag an existing schema with when executing baseline.
+ */
+ private final MigrationVersion baselineVersion;
+
+ /**
+ * The description to tag an existing schema with when executing baseline.
+ */
+ private final String baselineDescription;
+
+ /**
+ * The callback executor.
+ */
+ private final CallbackExecutor callbackExecutor;
+
+ /**
+ * Creates a new DbBaseline.
+ *
+ * @param schemaHistory The database schema history table.
+ * @param baselineVersion The version to tag an existing schema with when executing baseline.
+ * @param baselineDescription The description to tag an existing schema with when executing baseline.
+ * @param callbackExecutor The callback executor.
+ */
+ public DbBaseline(SchemaHistory schemaHistory, MigrationVersion baselineVersion,
+ String baselineDescription, CallbackExecutor callbackExecutor) {
+ this.schemaHistory = schemaHistory;
+ this.baselineVersion = baselineVersion;
+ this.baselineDescription = baselineDescription;
+ this.callbackExecutor = callbackExecutor;
+ }
+
+ /**
+ * Baselines the database.
+ */
+ public void baseline() {
+ callbackExecutor.onEvent(Event.BEFORE_BASELINE);
+
+ try {
+ if (!schemaHistory.exists()) {
+ schemaHistory.create(true);
+ LOG.info("Successfully baselined schema with version: " + baselineVersion);
+ } else {
+ AppliedMigration baselineMarker = schemaHistory.getBaselineMarker();
+ if (baselineMarker != null) {
+ if (baselineVersion.equals(baselineMarker.getVersion())
+ && baselineDescription.equals(baselineMarker.getDescription())) {
+ LOG.info("Schema history table " + schemaHistory + " already initialized with ("
+ + baselineVersion + "," + baselineDescription + "). Skipping.");
+ } else {
+ throw new FlywayException("Unable to baseline schema history table " + schemaHistory + " with ("
+ + baselineVersion + "," + baselineDescription
+ + ") as it has already been baselined with ("
+ + baselineMarker.getVersion() + "," + baselineMarker.getDescription() + ")");
+ }
+ } else {
+ if (schemaHistory.hasSchemasMarker() && baselineVersion.equals(MigrationVersion.fromVersion("0"))) {
+ throw new FlywayException("Unable to baseline schema history table " + schemaHistory + " with version 0 as this version was used for schema creation");
+ }
+
+ if (schemaHistory.hasNonSyntheticAppliedMigrations()) {
+ throw new FlywayException("Unable to baseline schema history table " + schemaHistory + " as it already contains migrations");
+ }
+
+ if (schemaHistory.allAppliedMigrations().isEmpty()) {
+ throw new FlywayException("Unable to baseline schema history table " + schemaHistory + " as it already exists, and is empty.\n" +
+ "Delete the schema history table with the clean command, and run baseline again.");
+ }
+
+ throw new FlywayException("Unable to baseline schema history table " + schemaHistory + " as it already contains migrations.\n" +
+ "Delete the schema history table with the clean command, and run baseline again.");
+ }
+ }
+ } catch (FlywayException e) {
+ callbackExecutor.onEvent(Event.AFTER_BASELINE_ERROR);
+ throw e;
+ }
+
+ callbackExecutor.onEvent(Event.AFTER_BASELINE);
+ }
+}
\ No newline at end of file
diff --git a/flyway-core/src/main/java/org/flywaydb/core/internal/command/DbClean.java b/flyway-core/src/main/java/org/flywaydb/core/internal/command/DbClean.java
new file mode 100644
index 00000000..4e39fb7f
--- /dev/null
+++ b/flyway-core/src/main/java/org/flywaydb/core/internal/command/DbClean.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2010-2020 Redgate Software Ltd
+ *
+ * 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.
+ */
+package org.flywaydb.core.internal.command;
+
+import org.flywaydb.core.api.FlywayException;
+import org.flywaydb.core.api.callback.Event;
+import org.flywaydb.core.api.logging.Log;
+import org.flywaydb.core.api.logging.LogFactory;
+import org.flywaydb.core.internal.callback.CallbackExecutor;
+import org.flywaydb.core.internal.database.base.Connection;
+import org.flywaydb.core.internal.database.base.Database;
+import org.flywaydb.core.internal.database.base.Schema;
+import org.flywaydb.core.internal.exception.FlywaySqlException;
+import org.flywaydb.core.internal.jdbc.ExecutionTemplateFactory;
+import org.flywaydb.core.internal.schemahistory.SchemaHistory;
+import org.flywaydb.core.internal.util.StopWatch;
+import org.flywaydb.core.internal.util.TimeFormat;
+
+import java.util.concurrent.Callable;
+
+/**
+ * Main workflow for cleaning the database.
+ */
+public class DbClean {
+ private static final Log LOG = LogFactory.getLog(DbClean.class);
+
+ /**
+ * The connection to use.
+ */
+ private final Connection connection;
+
+ /**
+ * The schema history table.
+ */
+ private final SchemaHistory schemaHistory;
+
+ /**
+ * The schemas to clean.
+ */
+ private final Schema[] schemas;
+
+ /**
+ * The callback executor.
+ */
+ private final CallbackExecutor callbackExecutor;
+
+ /**
+ * Whether to disable clean.
+ *
This is especially useful for production environments where running clean can be quite a career limiting move.
+ */
+ private boolean cleanDisabled;
+
+ /**
+ * The database
+ */
+ private Database database;
+
+ /**
+ * Creates a new database cleaner.
+ *
+ * @param database The DB support for the connection.
+ * @param schemaHistory The schema history table.
+ * @param schemas The schemas to clean.
+ * @param callbackExecutor The callback executor.
+ * @param cleanDisabled Whether to disable clean.
+ */
+ public DbClean(Database database, SchemaHistory schemaHistory, Schema[] schemas,
+ CallbackExecutor callbackExecutor, boolean cleanDisabled) {
+ this.database = database;
+ this.connection = database.getMainConnection();
+ this.schemaHistory = schemaHistory;
+ this.schemas = schemas;
+ this.callbackExecutor = callbackExecutor;
+ this.cleanDisabled = cleanDisabled;
+ }
+
+ /**
+ * Cleans the schemas of all objects.
+ *
+ * @throws FlywayException when clean failed.
+ */
+ public void clean() throws FlywayException {
+ if (cleanDisabled) {
+ throw new FlywayException("Unable to execute clean as it has been disabled with the \"flyway.cleanDisabled\" property.");
+ }
+ callbackExecutor.onEvent(Event.BEFORE_CLEAN);
+
+ try {
+ connection.changeCurrentSchemaTo(schemas[0]);
+ boolean dropSchemas = false;
+ try {
+ dropSchemas = schemaHistory.hasSchemasMarker();
+ } catch (Exception e) {
+ LOG.error("Error while checking whether the schemas should be dropped", e);
+ }
+
+ dropDatabaseObjectsPreSchemas();
+
+ for (Schema schema : schemas) {
+ if (!schema.exists()) {
+ LOG.warn("Unable to clean unknown schema: " + schema);
+ continue;
+ }
+
+ if (dropSchemas) {
+ dropSchema(schema);
+ } else {
+ cleanSchema(schema);
+ }
+ }
+
+ dropDatabaseObjectsPostSchemas();
+
+ } catch (FlywayException e) {
+ callbackExecutor.onEvent(Event.AFTER_CLEAN_ERROR);
+ throw e;
+ }
+
+ callbackExecutor.onEvent(Event.AFTER_CLEAN);
+ schemaHistory.clearCache();
+ }
+
+ /**
+ * Drops database-level objects that need to be cleaned prior to schema-level objects
+ *
+ * @throws FlywayException when the drop failed.
+ */
+ private void dropDatabaseObjectsPreSchemas() {
+ LOG.debug("Dropping pre-schema database level objects...");
+ StopWatch stopWatch = new StopWatch();
+ stopWatch.start();
+ try {
+ ExecutionTemplateFactory.createExecutionTemplate(connection.getJdbcConnection(),
+ database).execute(new Callable