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

mybatis / migrations / #436

pending completion
#436

push

github

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

Run overall code cleanup using Eclipse

91 of 91 new or added lines in 19 files covered. (100.0%)

1777 of 2212 relevant lines covered (80.33%)

0.8 hits per line

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

71.17
/src/main/java/org/apache/ibatis/migration/operations/ScriptRunner.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

18
import java.io.BufferedReader;
19
import java.io.PrintWriter;
20
import java.io.Reader;
21
import java.sql.Connection;
22
import java.sql.ResultSet;
23
import java.sql.ResultSetMetaData;
24
import java.sql.SQLException;
25
import java.sql.SQLWarning;
26
import java.sql.Statement;
27
import java.util.regex.Matcher;
28
import java.util.regex.Pattern;
29

30
/**
31
 * @author Clinton Begin
32
 */
33
public class ScriptRunner {
34

35
  private static final String LINE_SEPARATOR = System.lineSeparator();
1✔
36

37
  private static final String DEFAULT_DELIMITER = ";";
38

39
  private static final Pattern DELIMITER_PATTERN = Pattern
1✔
40
      .compile("^\\s*((--)|(//))?\\s*(//)?\\s*@DELIMITER\\s+([^\\s]+)", Pattern.CASE_INSENSITIVE);
1✔
41

42
  private final Connection connection;
43

44
  private boolean stopOnError;
45
  private boolean throwWarning;
46
  private boolean autoCommit;
47
  private boolean sendFullScript;
48
  private boolean removeCRs;
49
  private boolean escapeProcessing = true;
1✔
50

51
  private PrintWriter logWriter = new PrintWriter(System.out);
1✔
52
  private PrintWriter errorLogWriter = new PrintWriter(System.err);
1✔
53

54
  private String delimiter = DEFAULT_DELIMITER;
1✔
55
  private boolean fullLineDelimiter;
56

57
  public ScriptRunner(Connection connection) {
1✔
58
    this.connection = connection;
1✔
59
  }
1✔
60

61
  public void setStopOnError(boolean stopOnError) {
62
    this.stopOnError = stopOnError;
1✔
63
  }
1✔
64

65
  public void setThrowWarning(boolean throwWarning) {
66
    this.throwWarning = throwWarning;
1✔
67
  }
1✔
68

69
  public void setAutoCommit(boolean autoCommit) {
70
    this.autoCommit = autoCommit;
1✔
71
  }
1✔
72

73
  public void setSendFullScript(boolean sendFullScript) {
74
    this.sendFullScript = sendFullScript;
1✔
75
  }
1✔
76

77
  public void setRemoveCRs(boolean removeCRs) {
78
    this.removeCRs = removeCRs;
1✔
79
  }
1✔
80

81
  /**
82
   * Sets the escape processing.
83
   *
84
   * @param escapeProcessing
85
   *          the new escape processing
86
   *
87
   * @since 3.1.1
88
   */
89
  public void setEscapeProcessing(boolean escapeProcessing) {
90
    this.escapeProcessing = escapeProcessing;
1✔
91
  }
1✔
92

93
  public void setLogWriter(PrintWriter logWriter) {
94
    this.logWriter = logWriter;
1✔
95
  }
1✔
96

97
  public void setErrorLogWriter(PrintWriter errorLogWriter) {
98
    this.errorLogWriter = errorLogWriter;
1✔
99
  }
1✔
100

101
  public void setDelimiter(String delimiter) {
102
    this.delimiter = delimiter;
1✔
103
  }
1✔
104

105
  public void setFullLineDelimiter(boolean fullLineDelimiter) {
106
    this.fullLineDelimiter = fullLineDelimiter;
1✔
107
  }
1✔
108

109
  public void runScript(Reader reader) {
110
    setAutoCommit();
1✔
111

112
    try {
113
      if (sendFullScript) {
1✔
114
        executeFullScript(reader);
×
115
      } else {
116
        executeLineByLine(reader);
1✔
117
      }
118
    } finally {
119
      rollbackConnection();
1✔
120
    }
121
  }
1✔
122

123
  private void executeFullScript(Reader reader) {
124
    StringBuilder script = new StringBuilder();
×
125
    try {
126
      BufferedReader lineReader = new BufferedReader(reader);
×
127
      String line;
128
      while ((line = lineReader.readLine()) != null) {
×
129
        script.append(line);
×
130
        script.append(LINE_SEPARATOR);
×
131
      }
132
      String command = script.toString();
×
133
      println(command);
×
134
      executeStatement(command);
×
135
      commitConnection();
×
136
    } catch (Exception e) {
×
137
      String message = "Error executing: " + script + ".  Cause: " + e;
×
138
      printlnError(message);
×
139
      throw new RuntimeException(message, e);
×
140
    }
×
141
  }
×
142

143
  private void executeLineByLine(Reader reader) {
144
    StringBuilder command = new StringBuilder();
1✔
145
    try {
146
      BufferedReader lineReader = new BufferedReader(reader);
1✔
147
      String line;
148
      while ((line = lineReader.readLine()) != null) {
1✔
149
        handleLine(command, line);
1✔
150
      }
151
      commitConnection();
1✔
152
      checkForMissingLineTerminator(command);
1✔
153
    } catch (Exception e) {
×
154
      String message = "Error executing: " + command + ".  Cause: " + e;
×
155
      printlnError(message);
×
156
      throw new RuntimeException(message, e);
×
157
    }
1✔
158
  }
1✔
159

160
  /**
161
   * @deprecated Since 3.5.4, this method is deprecated. Please close the {@link Connection} outside of this class.
162
   */
163
  @Deprecated
164
  public void closeConnection() {
165
    try {
166
      connection.close();
×
167
    } catch (Exception e) {
×
168
      // ignore
169
    }
×
170
  }
×
171

172
  private void setAutoCommit() {
173
    try {
174
      if (autoCommit != connection.getAutoCommit()) {
1✔
175
        connection.setAutoCommit(autoCommit);
1✔
176
      }
177
    } catch (Throwable t) {
×
178
      throw new RuntimeException("Could not set AutoCommit to " + autoCommit + ". Cause: " + t, t);
×
179
    }
1✔
180
  }
1✔
181

182
  private void commitConnection() {
183
    try {
184
      if (!connection.getAutoCommit()) {
1✔
185
        connection.commit();
1✔
186
      }
187
    } catch (Throwable t) {
×
188
      throw new RuntimeException("Could not commit transaction. Cause: " + t, t);
×
189
    }
1✔
190
  }
1✔
191

192
  private void rollbackConnection() {
193
    try {
194
      if (!connection.getAutoCommit()) {
1✔
195
        connection.rollback();
1✔
196
      }
197
    } catch (Throwable t) {
×
198
      // ignore
199
    }
1✔
200
  }
1✔
201

202
  private void checkForMissingLineTerminator(StringBuilder command) {
203
    if (command != null && command.toString().trim().length() > 0) {
1✔
204
      throw new RuntimeException("Line missing end-of-line terminator (" + delimiter + ") => " + command);
×
205
    }
206
  }
1✔
207

208
  private void handleLine(StringBuilder command, String line) throws SQLException {
209
    String trimmedLine = line.trim();
1✔
210
    if (lineIsComment(trimmedLine)) {
1✔
211
      Matcher matcher = DELIMITER_PATTERN.matcher(trimmedLine);
1✔
212
      if (matcher.find()) {
1✔
213
        delimiter = matcher.group(5);
×
214
      }
215
      println(trimmedLine);
1✔
216
    } else if (commandReadyToExecute(trimmedLine)) {
1✔
217
      command.append(line, 0, line.lastIndexOf(delimiter));
1✔
218
      command.append(LINE_SEPARATOR);
1✔
219
      println(command);
1✔
220
      executeStatement(command.toString());
1✔
221
      command.setLength(0);
1✔
222
    } else if (trimmedLine.length() > 0) {
1✔
223
      command.append(line);
1✔
224
      command.append(LINE_SEPARATOR);
1✔
225
    }
226
  }
1✔
227

228
  private boolean lineIsComment(String trimmedLine) {
229
    return trimmedLine.startsWith("//") || trimmedLine.startsWith("--");
1✔
230
  }
231

232
  private boolean commandReadyToExecute(String trimmedLine) {
233
    // issue #561 remove anything after the delimiter
234
    return !fullLineDelimiter && trimmedLine.contains(delimiter) || fullLineDelimiter && trimmedLine.equals(delimiter);
1✔
235
  }
236

237
  private void executeStatement(String command) throws SQLException {
238
    Statement statement = connection.createStatement();
1✔
239
    try {
240
      statement.setEscapeProcessing(escapeProcessing);
1✔
241
      String sql = command;
1✔
242
      if (removeCRs) {
1✔
243
        sql = sql.replace("\r\n", "\n");
×
244
      }
245
      try {
246
        boolean hasResults = statement.execute(sql);
1✔
247
        while (hasResults || statement.getUpdateCount() != -1) {
1✔
248
          checkWarnings(statement);
1✔
249
          printResults(statement, hasResults);
1✔
250
          hasResults = statement.getMoreResults();
1✔
251
        }
252
      } catch (SQLWarning e) {
×
253
        throw e;
×
254
      } catch (SQLException e) {
×
255
        if (stopOnError) {
×
256
          throw e;
×
257
        }
258
        String message = "Error executing: " + command + ".  Cause: " + e;
×
259
        printlnError(message);
×
260
      }
1✔
261
    } finally {
262
      try {
263
        statement.close();
1✔
264
      } catch (Exception ignored) {
×
265
        // Ignore to workaround a bug in some connection pools
266
        // (Does anyone know the details of the bug?)
267
      }
1✔
268
    }
269
  }
1✔
270

271
  private void checkWarnings(Statement statement) throws SQLException {
272
    if (!throwWarning) {
1✔
273
      return;
1✔
274
    }
275
    // In Oracle, CREATE PROCEDURE, FUNCTION, etc. returns warning
276
    // instead of throwing exception if there is compilation error.
277
    SQLWarning warning = statement.getWarnings();
1✔
278
    if (warning != null) {
1✔
279
      throw warning;
×
280
    }
281
  }
1✔
282

283
  private void printResults(Statement statement, boolean hasResults) {
284
    if (!hasResults) {
1✔
285
      return;
1✔
286
    }
287
    try (ResultSet rs = statement.getResultSet()) {
1✔
288
      ResultSetMetaData md = rs.getMetaData();
1✔
289
      int cols = md.getColumnCount();
1✔
290
      for (int i = 0; i < cols; i++) {
1✔
291
        String name = md.getColumnLabel(i + 1);
1✔
292
        print(name + "\t");
1✔
293
      }
294
      println("");
1✔
295
      while (rs.next()) {
1✔
296
        for (int i = 0; i < cols; i++) {
1✔
297
          String value = rs.getString(i + 1);
1✔
298
          print(value + "\t");
1✔
299
        }
300
        println("");
1✔
301
      }
302
    } catch (SQLException e) {
×
303
      printlnError("Error printing results: " + e.getMessage());
×
304
    }
1✔
305
  }
1✔
306

307
  private void print(Object o) {
308
    if (logWriter != null) {
1✔
309
      logWriter.print(o);
1✔
310
      logWriter.flush();
1✔
311
    }
312
  }
1✔
313

314
  private void println(Object o) {
315
    if (logWriter != null) {
1✔
316
      logWriter.println(o);
1✔
317
      logWriter.flush();
1✔
318
    }
319
  }
1✔
320

321
  private void printlnError(Object o) {
322
    if (errorLogWriter != null) {
×
323
      errorLogWriter.println(o);
×
324
      errorLogWriter.flush();
×
325
    }
326
  }
×
327

328
}
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