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

mybatis / migrations / 848

01 Jan 2026 09:03PM UTC coverage: 79.903% (-1.0%) from 80.917%
848

push

github

web-flow
Merge pull request #490 from hazendaz/master

[mvn] Add hsqldb method class names back to maven.config

679 of 986 branches covered (68.86%)

1813 of 2269 relevant lines covered (79.9%)

0.8 hits per line

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

93.33
/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(
×
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
          try (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
          }
108
          count++;
1✔
109
          printStream.println();
1✔
110
          printStream.println();
1✔
111
          if (!undo) {
1✔
112
            printStream.println(generateVersionInsert(change));
1✔
113
          } else if (i + 1 < migrations.size() || !DESC_CREATE_CHANGELOG.equals(change.getDescription())) {
1!
114
            printStream.println(generateVersionDelete(change));
1✔
115
          }
116
          printStream.println();
1✔
117
          if (hook != null) {
1✔
118
            hookBindings.put(MigrationHook.HOOK_CONTEXT, new ScriptHookContext(new Change(change), undo));
1✔
119
            hook.afterEach(hookBindings);
1✔
120
            printStream.println();
1✔
121
          }
122
        }
123
      }
124
      if (count > 0 && hook != null) {
1!
125
        hookBindings.put(MigrationHook.HOOK_CONTEXT, new ScriptHookContext(null, undo));
1✔
126
        hook.after(hookBindings);
1✔
127
        printStream.println();
1✔
128
      }
129
    } catch (IOException e) {
×
130
      throw new MigrationException("Error generating script. Cause: " + e, e);
×
131
    }
1✔
132
  }
1✔
133

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

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

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

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

165
  private MigrationHook createScriptHook() {
166
    String before = environment().getHookBeforeScript();
1✔
167
    String beforeEach = environment().getHookBeforeEachScript();
1✔
168
    String afterEach = environment().getHookAfterEachScript();
1✔
169
    String after = environment().getHookAfterScript();
1✔
170
    if (before == null && beforeEach == null && afterEach == null && after == null) {
1!
171
      return null;
1✔
172
    }
173
    return createFileMigrationHook(before, beforeEach, afterEach, after);
1✔
174
  }
175
}
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