1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.migration.operations;
17
18 import java.io.PrintStream;
19 import java.io.Reader;
20 import java.sql.Connection;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24
25 import org.apache.ibatis.migration.Change;
26 import org.apache.ibatis.migration.ConnectionProvider;
27 import org.apache.ibatis.migration.MigrationException;
28 import org.apache.ibatis.migration.MigrationLoader;
29 import org.apache.ibatis.migration.hook.HookContext;
30 import org.apache.ibatis.migration.hook.MigrationHook;
31 import org.apache.ibatis.migration.options.DatabaseOperationOption;
32 import org.apache.ibatis.migration.utils.Util;
33
34 public final class UpOperation extends DatabaseOperation {
35 private final Integer steps;
36
37 public UpOperation() {
38 this.steps = null;
39 }
40
41 public UpOperation(Integer steps) {
42 this.steps = steps;
43 if (steps != null && steps.intValue() < 1) {
44 throw new IllegalArgumentException("step must be positive number or null.");
45 }
46 }
47
48 public UpOperation operate(ConnectionProvider connectionProvider, MigrationLoader migrationsLoader,
49 DatabaseOperationOption option, PrintStream printStream) {
50 return operate(connectionProvider, migrationsLoader, option, printStream, null);
51 }
52
53 public UpOperation operate(ConnectionProvider connectionProvider, MigrationLoader migrationsLoader,
54 DatabaseOperationOption option, PrintStream printStream, MigrationHook hook) {
55 try (Connection con = connectionProvider.getConnection()) {
56 if (option == null) {
57 option = new DatabaseOperationOption();
58 }
59
60 List<Change> changesInDb = List.of();
61 if (changelogExists(con, option)) {
62 changesInDb = getChangelog(con, option);
63 }
64
65 List<Change> migrations = migrationsLoader.getMigrations();
66 migrations.sort(null);
67 String skippedOrMissing = checkSkippedOrMissing(changesInDb, migrations);
68 int stepCount = 0;
69
70 Map<String, Object> hookBindings = new HashMap<>();
71 ScriptRunner runner = getScriptRunner(con, option, printStream);
72 try {
73 for (Change change : migrations) {
74 if (changesInDb.isEmpty() || change.compareTo(changesInDb.get(changesInDb.size() - 1)) > 0) {
75 if (stepCount == 0 && hook != null) {
76 hookBindings.put(MigrationHook.HOOK_CONTEXT, new HookContext(connectionProvider, runner, null));
77 hook.before(hookBindings);
78 }
79 if (hook != null) {
80 hookBindings.put(MigrationHook.HOOK_CONTEXT,
81 new HookContext(connectionProvider, runner, new Change(change)));
82 hook.beforeEach(hookBindings);
83 }
84 println(printStream, Util.horizontalLine("Applying: " + change.getFilename(), 80));
85 try (Reader scriptReader = migrationsLoader.getScriptReader(change, false)) {
86 runner.runScript(scriptReader);
87 }
88 insertChangelog(change, con, option);
89 println(printStream);
90 if (hook != null) {
91 hookBindings.put(MigrationHook.HOOK_CONTEXT,
92 new HookContext(connectionProvider, runner, new Change(change)));
93 hook.afterEach(hookBindings);
94 }
95 stepCount++;
96 if (steps != null && stepCount >= steps) {
97 break;
98 }
99 }
100 }
101 if (stepCount > 0 && hook != null) {
102 hookBindings.put(MigrationHook.HOOK_CONTEXT, new HookContext(connectionProvider, runner, null));
103 hook.after(hookBindings);
104 }
105 println(printStream, skippedOrMissing);
106 return this;
107 } catch (Exception e) {
108 try (Reader onAbortScriptReader = migrationsLoader.getOnAbortReader()) {
109 if (onAbortScriptReader != null) {
110 println(printStream);
111 println(printStream, Util.horizontalLine("Executing onabort.sql script.", 80));
112 runner.runScript(onAbortScriptReader);
113 println(printStream);
114 }
115 }
116 throw e;
117 }
118 } catch (Throwable e) {
119 while (e instanceof MigrationException && e.getCause() != null) {
120 e = e.getCause();
121 }
122 throw new MigrationException("Error executing command. Cause: " + e, e);
123 }
124 }
125 }