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