• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mybatis / migrations / #438

pending completion
#438

push

github

web-flow
Merge pull request #296 from hazendaz/develop

Code cleanup, fix a few leaks, better test charset handling, use modern nio in tests

11 of 11 new or added lines in 5 files covered. (100.0%)

1778 of 2213 relevant lines covered (80.34%)

0.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.44
/src/main/java/org/apache/ibatis/migration/commands/ScriptCommand.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.commands;
17

18
import java.io.IOException;
19
import java.io.Reader;
20
import java.math.BigDecimal;
21
import java.util.Arrays;
22
import java.util.Collections;
23
import java.util.HashMap;
24
import java.util.List;
25
import java.util.Map;
26
import java.util.StringTokenizer;
27

28
import org.apache.ibatis.migration.Change;
29
import org.apache.ibatis.migration.MigrationException;
30
import org.apache.ibatis.migration.hook.MigrationHook;
31
import org.apache.ibatis.migration.hook.ScriptHookContext;
32
import org.apache.ibatis.migration.operations.DatabaseOperation;
33
import org.apache.ibatis.migration.operations.StatusOperation;
34
import org.apache.ibatis.migration.options.SelectedOptions;
35

36
public final class ScriptCommand extends BaseCommand {
37

38
  public ScriptCommand(SelectedOptions options) {
39
    super(options);
1✔
40
  }
1✔
41

42
  @Override
43
  public void execute(String... sparams) {
44
    try {
45
      if (sparams == null || sparams.length < 1 || sparams[0] == null) {
1✔
46
        throw new MigrationException("The script command requires a range of versions from v1 - v2.");
×
47
      }
48
      StringTokenizer parser = new StringTokenizer(sparams[0]);
1✔
49
      int tokenCount = parser.countTokens();
1✔
50
      boolean scriptPending = false;
1✔
51
      boolean scriptPendingUndo = false;
1✔
52

53
      String firstToken = parser.nextToken();
1✔
54

55
      if (tokenCount == 1 && firstToken.equals("pending")) {
1✔
56
        scriptPending = true;
1✔
57
      } else if (tokenCount == 1 && firstToken.equals("pending_undo")) {
1✔
58
        scriptPendingUndo = true;
1✔
59
      } else if (!scriptPending && !scriptPendingUndo && tokenCount != 2) {
1✔
60
        throw new MigrationException("The script command requires a range of versions from v1 - v2.");
×
61
      }
62

63
      BigDecimal v1 = scriptPending || scriptPendingUndo ? null : new BigDecimal(firstToken);
1✔
64
      BigDecimal v2 = scriptPending || scriptPendingUndo ? null : new BigDecimal(parser.nextToken());
1✔
65

66
      boolean undo;
67
      undo = scriptPendingUndo;
1✔
68
      if (!scriptPending && !scriptPendingUndo) {
1✔
69
        int comparison = v1.compareTo(v2);
1✔
70
        if (comparison == 0) {
1✔
71
          throw new MigrationException(
1✔
72
              "The script command requires two different versions. Use 0 to include the first version.");
73
        }
74
        undo = comparison > 0;
1✔
75
      }
76

77
      Map<String, Object> hookBindings = new HashMap<>();
1✔
78
      MigrationHook hook = createScriptHook();
1✔
79
      List<Change> migrations = scriptPending || scriptPendingUndo ? new StatusOperation()
1✔
80
          .operate(getConnectionProvider(), getMigrationLoader(), getDatabaseOperationOption(), null).getCurrentStatus()
1✔
81
          : getMigrationLoader().getMigrations();
1✔
82
      Collections.sort(migrations);
1✔
83
      if (undo) {
1✔
84
        Collections.reverse(migrations);
1✔
85
      }
86
      int count = 0;
1✔
87
      for (int i = 0; i < migrations.size(); i++) {
1✔
88
        Change change = migrations.get(i);
1✔
89
        if (shouldRun(change, v1, v2, scriptPending || scriptPendingUndo)) {
1✔
90
          if (count == 0 && hook != null) {
1✔
91
            hookBindings.put(MigrationHook.HOOK_CONTEXT, new ScriptHookContext(null, undo));
1✔
92
            hook.before(hookBindings);
1✔
93
            printStream.println();
1✔
94
          }
95
          if (hook != null) {
1✔
96
            hookBindings.put(MigrationHook.HOOK_CONTEXT, new ScriptHookContext(new Change(change), undo));
1✔
97
            hook.beforeEach(hookBindings);
1✔
98
            printStream.println();
1✔
99
          }
100
          printStream.println("-- " + change.getFilename());
1✔
101
          Reader migrationReader = getMigrationLoader().getScriptReader(change, undo);
1✔
102
          char[] cbuf = new char[1024];
1✔
103
          int l;
104
          while ((l = migrationReader.read(cbuf)) > -1) {
1✔
105
            printStream.print(l == cbuf.length ? cbuf : Arrays.copyOf(cbuf, l));
1✔
106
          }
107
          count++;
1✔
108
          printStream.println();
1✔
109
          printStream.println();
1✔
110
          if (!undo) {
1✔
111
            printStream.println(generateVersionInsert(change));
1✔
112
          } else if (i + 1 < migrations.size() || !DESC_CREATE_CHANGELOG.equals(change.getDescription())) {
1✔
113
            printStream.println(generateVersionDelete(change));
1✔
114
          }
115
          printStream.println();
1✔
116
          if (hook != null) {
1✔
117
            hookBindings.put(MigrationHook.HOOK_CONTEXT, new ScriptHookContext(new Change(change), undo));
1✔
118
            hook.afterEach(hookBindings);
1✔
119
            printStream.println();
1✔
120
          }
121
        }
122
      }
123
      if (count > 0 && hook != null) {
1✔
124
        hookBindings.put(MigrationHook.HOOK_CONTEXT, new ScriptHookContext(null, undo));
1✔
125
        hook.after(hookBindings);
1✔
126
        printStream.println();
1✔
127
      }
128
    } catch (IOException e) {
×
129
      throw new MigrationException("Error generating script. Cause: " + e, e);
×
130
    }
1✔
131
  }
1✔
132

133
  private String generateVersionInsert(Change change) {
134
    return "INSERT INTO " + changelogTable() + " (ID, APPLIED_AT, DESCRIPTION) " + "VALUES (" + change.getId() + ", '"
1✔
135
        + DatabaseOperation.generateAppliedTimeStampAsString() + "', '" + change.getDescription().replace('\'', ' ')
1✔
136
        + "')" + getDelimiter();
1✔
137
  }
138

139
  private String generateVersionDelete(Change change) {
140
    return "DELETE FROM " + changelogTable() + " WHERE ID = " + change.getId() + getDelimiter();
1✔
141
  }
142

143
  private boolean shouldRun(Change change, BigDecimal v1, BigDecimal v2, boolean pendingOnly) {
144
    if (pendingOnly) {
1✔
145
      return change.getAppliedTimestamp() == null;
1✔
146
    }
147
    BigDecimal id = change.getId();
1✔
148
    if (v1.compareTo(v2) > 0) {
1✔
149
      return id.compareTo(v2) > 0 && id.compareTo(v1) <= 0;
1✔
150
    }
151
    return id.compareTo(v1) > 0 && id.compareTo(v2) <= 0;
1✔
152
  }
153

154
  // Issue 699
155
  private String getDelimiter() {
156
    StringBuilder delimiter = new StringBuilder();
1✔
157
    if (environment().isFullLineDelimiter()) {
1✔
158
      delimiter.append('\n');
×
159
    }
160
    delimiter.append(environment().getDelimiter());
1✔
161
    return delimiter.toString();
1✔
162
  }
163

164
  private MigrationHook createScriptHook() {
165
    String before = environment().getHookBeforeScript();
1✔
166
    String beforeEach = environment().getHookBeforeEachScript();
1✔
167
    String afterEach = environment().getHookAfterEachScript();
1✔
168
    String after = environment().getHookAfterScript();
1✔
169
    if (before == null && beforeEach == null && afterEach == null && after == null) {
1✔
170
      return null;
1✔
171
    }
172
    return createFileMigrationHook(before, beforeEach, afterEach, after);
1✔
173
  }
174
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc