UpOperation.java

  1. /*
  2.  *    Copyright 2010-2023 the original author or authors.
  3.  *
  4.  *    Licensed under the Apache License, Version 2.0 (the "License");
  5.  *    you may not use this file except in compliance with the License.
  6.  *    You may obtain a copy of the License at
  7.  *
  8.  *       https://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  *    Unless required by applicable law or agreed to in writing, software
  11.  *    distributed under the License is distributed on an "AS IS" BASIS,
  12.  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  *    See the License for the specific language governing permissions and
  14.  *    limitations under the License.
  15.  */
  16. package org.apache.ibatis.migration.operations;

  17. import java.io.PrintStream;
  18. import java.io.Reader;
  19. import java.sql.Connection;
  20. import java.util.Collections;
  21. import java.util.HashMap;
  22. import java.util.List;
  23. import java.util.Map;

  24. import org.apache.ibatis.migration.Change;
  25. import org.apache.ibatis.migration.ConnectionProvider;
  26. import org.apache.ibatis.migration.MigrationException;
  27. import org.apache.ibatis.migration.MigrationLoader;
  28. import org.apache.ibatis.migration.hook.HookContext;
  29. import org.apache.ibatis.migration.hook.MigrationHook;
  30. import org.apache.ibatis.migration.options.DatabaseOperationOption;
  31. import org.apache.ibatis.migration.utils.Util;

  32. public final class UpOperation extends DatabaseOperation {
  33.   private final Integer steps;

  34.   public UpOperation() {
  35.     this.steps = null;
  36.   }

  37.   public UpOperation(Integer steps) {
  38.     this.steps = steps;
  39.     if (steps != null && steps.intValue() < 1) {
  40.       throw new IllegalArgumentException("step must be positive number or null.");
  41.     }
  42.   }

  43.   public UpOperation operate(ConnectionProvider connectionProvider, MigrationLoader migrationsLoader,
  44.       DatabaseOperationOption option, PrintStream printStream) {
  45.     return operate(connectionProvider, migrationsLoader, option, printStream, null);
  46.   }

  47.   public UpOperation operate(ConnectionProvider connectionProvider, MigrationLoader migrationsLoader,
  48.       DatabaseOperationOption option, PrintStream printStream, MigrationHook hook) {
  49.     try (Connection con = connectionProvider.getConnection()) {
  50.       if (option == null) {
  51.         option = new DatabaseOperationOption();
  52.       }

  53.       List<Change> changesInDb = Collections.emptyList();
  54.       if (changelogExists(con, option)) {
  55.         changesInDb = getChangelog(con, option);
  56.       }

  57.       List<Change> migrations = migrationsLoader.getMigrations();
  58.       Collections.sort(migrations);
  59.       String skippedOrMissing = checkSkippedOrMissing(changesInDb, migrations);
  60.       int stepCount = 0;

  61.       Map<String, Object> hookBindings = new HashMap<>();
  62.       ScriptRunner runner = getScriptRunner(con, option, printStream);
  63.       try {
  64.         for (Change change : migrations) {
  65.           if (changesInDb.isEmpty() || change.compareTo(changesInDb.get(changesInDb.size() - 1)) > 0) {
  66.             if (stepCount == 0 && hook != null) {
  67.               hookBindings.put(MigrationHook.HOOK_CONTEXT, new HookContext(connectionProvider, runner, null));
  68.               hook.before(hookBindings);
  69.             }
  70.             if (hook != null) {
  71.               hookBindings.put(MigrationHook.HOOK_CONTEXT,
  72.                   new HookContext(connectionProvider, runner, new Change(change)));
  73.               hook.beforeEach(hookBindings);
  74.             }
  75.             println(printStream, Util.horizontalLine("Applying: " + change.getFilename(), 80));
  76.             try (Reader scriptReader = migrationsLoader.getScriptReader(change, false)) {
  77.               runner.runScript(scriptReader);
  78.             }
  79.             insertChangelog(change, con, option);
  80.             println(printStream);
  81.             if (hook != null) {
  82.               hookBindings.put(MigrationHook.HOOK_CONTEXT,
  83.                   new HookContext(connectionProvider, runner, new Change(change)));
  84.               hook.afterEach(hookBindings);
  85.             }
  86.             stepCount++;
  87.             if (steps != null && stepCount >= steps) {
  88.               break;
  89.             }
  90.           }
  91.         }
  92.         if (stepCount > 0 && hook != null) {
  93.           hookBindings.put(MigrationHook.HOOK_CONTEXT, new HookContext(connectionProvider, runner, null));
  94.           hook.after(hookBindings);
  95.         }
  96.         println(printStream, skippedOrMissing);
  97.         return this;
  98.       } catch (Exception e) {
  99.         try (Reader onAbortScriptReader = migrationsLoader.getOnAbortReader()) {
  100.           if (onAbortScriptReader != null) {
  101.             println(printStream);
  102.             println(printStream, Util.horizontalLine("Executing onabort.sql script.", 80));
  103.             runner.runScript(onAbortScriptReader);
  104.             println(printStream);
  105.           }
  106.         }
  107.         throw e;
  108.       }
  109.     } catch (Throwable e) {
  110.       while (e instanceof MigrationException && e.getCause() != null) {
  111.         e = e.getCause();
  112.       }
  113.       throw new MigrationException("Error executing command.  Cause: " + e, e);
  114.     }
  115.   }
  116. }