001/* 002 * Slightly modified version of the com.ibatis.common.jdbc.ScriptRunner class 003 * from the iBATIS Apache project. Only removed dependency on Resource class 004 * and a constructor 005 */ 006/** 007 * Copyright 2004-2020 the original author or authors. 008 * 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 */ 021package gu.sql2java; 022 023import java.io.IOException; 024import java.io.InputStream; 025import java.io.InputStreamReader; 026import java.io.LineNumberReader; 027import java.io.PrintWriter; 028import java.io.Reader; 029import java.io.StringReader; 030import java.sql.Connection; 031import java.sql.ResultSet; 032import java.sql.ResultSetMetaData; 033import java.sql.SQLException; 034import java.sql.Statement; 035 036import com.google.common.base.Throwables; 037 038import gu.sql2java.exception.DaoException; 039 040import static com.google.common.base.Preconditions.checkNotNull; 041/** 042 * Tool to run database scripts. 043 */ 044public class ScriptRunner { 045 046 /** The Constant DEFAULT_DELIMITER. */ 047 private static final String DEFAULT_DELIMITER = ";"; 048 049 /** The stop on error. */ 050 private boolean stopOnError; 051 052 /** The auto commit. */ 053 private boolean autoCommit; 054 055 /** The log writer. */ 056 private PrintWriter logWriter = new PrintWriter(System.out); 057 058 /** The error log writer. */ 059 private PrintWriter errorLogWriter = new PrintWriter(System.err); 060 061 /** The delimiter. */ 062 private String delimiter = DEFAULT_DELIMITER; 063 064 /** The full line delimiter. */ 065 private boolean fullLineDelimiter = false; 066 067 /** 068 * Default constructor. 069 * @param autoCommit 070 * the auto commit 071 * @param stopOnError 072 * stop on error 073 */ 074 public ScriptRunner(boolean autoCommit, boolean stopOnError) { 075 this.autoCommit = autoCommit; 076 this.stopOnError = stopOnError; 077 } 078 079 /** 080 * Sets the delimiter. 081 * 082 * @param delimiter 083 * the delimiter 084 * @param fullLineDelimiter 085 * the full line delimiter 086 * @return 087 */ 088 public ScriptRunner setDelimiter(String delimiter, boolean fullLineDelimiter) { 089 this.delimiter = delimiter; 090 this.fullLineDelimiter = fullLineDelimiter; 091 return this; 092 } 093 094 /** 095 * Setter for logWriter property. 096 * 097 * @param logWriter 098 * - the new value of the logWriter property 099 * @return 100 */ 101 public ScriptRunner setLogWriter(PrintWriter logWriter) { 102 this.logWriter = logWriter; 103 return this; 104 } 105 106 /** 107 * Setter for errorLogWriter property. 108 * 109 * @param errorLogWriter 110 * - the new value of the errorLogWriter property 111 * @return 112 */ 113 public ScriptRunner setErrorLogWriter(PrintWriter errorLogWriter) { 114 this.errorLogWriter = errorLogWriter; 115 return this; 116 } 117 118 /** 119 * Runs an SQL script (read in using the Reader parameter). 120 * 121 * @param reader 122 * - the source of the script 123 * @throws IOException 124 * Signals that an I/O exception has occurred. 125 * @throws DaoException 126 * the wrapped SQL exception 127 */ 128 public void runScript(Reader reader) throws IOException, DaoException { 129 try { 130 Connection connection = Manager.getInstance().getConnection(); 131 boolean originalAutoCommit = connection.getAutoCommit(); 132 boolean commit = false; 133 try { 134 if (originalAutoCommit != this.autoCommit) { 135 connection.setAutoCommit(this.autoCommit); 136 } 137 runScript(connection, checkNotNull(reader,"reader is null")); 138 commit = true; 139 } finally { 140 if(!autoCommit){ 141 if(commit){ 142 connection.commit(); 143 }else{ 144 connection.rollback(); 145 } 146 } 147 connection.setAutoCommit(originalAutoCommit); 148 Manager.getInstance().releaseConnection(connection); 149 } 150 151 } catch (SQLException e) { 152 throw new DaoException(e); 153 }catch (Exception e) { 154 Throwables.throwIfInstanceOf(e, IOException.class); 155 Throwables.throwIfUnchecked(e); 156 throw new RuntimeException(e); 157 } 158 } 159 /** 160 * Runs an SQL script (read in using the String parameter). 161 * @param input 162 * - the source of the script 163 * @throws IOException 164 * @throws DaoException 165 */ 166 public void runScript(String input) throws IOException, DaoException { 167 runScript(new StringReader(checkNotNull(input,"input is null"))); 168 } 169 /** 170 * Runs an SQL script (read in using the InputStream parameter). 171 * @param input 172 * - the source of the script 173 * @throws IOException 174 * @throws DaoException 175 */ 176 public void runScript(InputStream input) throws IOException, DaoException { 177 runScript(new InputStreamReader(checkNotNull(input,"input is null"))); 178 } 179 /** 180 * Runs an SQL script (read in using the Reader parameter) using the connection passed in. 181 * 182 * @param conn 183 * - the connection to use for the script 184 * @param reader 185 * - the source of the script 186 * @throws IOException 187 * if there is an error reading from the Reader 188 * @throws SQLException 189 * if any SQL errors occur 190 */ 191 private void runScript(Connection conn, Reader reader) throws IOException, SQLException { 192 StringBuilder command = null; 193 // auto close the reader 194 try (LineNumberReader lineReader = new LineNumberReader(reader)){ 195 String line = null; 196 while ((line = lineReader.readLine()) != null) { 197 if (command == null) { 198 command = new StringBuilder(); 199 } 200 String trimmedLine = line.trim(); 201 if (trimmedLine.startsWith("--")) { 202 println(trimmedLine); 203 } else if (trimmedLine.length() < 1 || trimmedLine.startsWith("//")) { 204 // Do nothing 205 } else if (trimmedLine.length() < 1 || trimmedLine.startsWith("--")) { 206 // Do nothing 207 } else if (!fullLineDelimiter && trimmedLine.endsWith(getDelimiter()) 208 || fullLineDelimiter && trimmedLine.equals(getDelimiter())) { 209 command.append(line.substring(0, line.lastIndexOf(getDelimiter()))); 210 command.append(" "); 211 Statement statement = conn.createStatement(); 212 213 println(command); 214 215 boolean hasResults = false; 216 if (stopOnError) { 217 hasResults = statement.execute(command.toString()); 218 } else { 219 try { 220 statement.execute(command.toString()); 221 } catch (SQLException e) { 222 e.fillInStackTrace(); 223 printlnError("Error executing: " + command); 224 printlnError(e); 225 } 226 } 227 228// if (autoCommit && !conn.getAutoCommit()) { 229// conn.commit(); 230// } 231 232 ResultSet rs = statement.getResultSet(); 233 if (hasResults && rs != null) { 234 ResultSetMetaData md = rs.getMetaData(); 235 int cols = md.getColumnCount(); 236 for (int i = 0; i < cols; i++) { 237 String name = md.getColumnLabel(i + 1); 238 print(name + "\t"); 239 } 240 println(""); 241 while (rs.next()) { 242 for (int i = 0; i < cols; i++) { 243 String value = rs.getString(i + 1); 244 print(value + "\t"); 245 } 246 println(""); 247 } 248 } 249 250 command = null; 251 try { 252 statement.close(); 253 } catch (Exception e) { 254 // Ignore to workaround a bug in Jakarta DBCP 255 } 256 Thread.yield(); 257 } else { 258 command.append(line); 259 command.append(" "); 260 } 261 } 262// if (!autoCommit) { 263// conn.commit(); 264// } 265 } catch (SQLException e) { 266 e.fillInStackTrace(); 267 printlnError("Error executing: " + command); 268 printlnError(e); 269 throw e; 270 } catch (IOException e) { 271 e.fillInStackTrace(); 272 printlnError("Error executing: " + command); 273 printlnError(e); 274 throw e; 275 } finally { 276// conn.rollback(); 277 flush(); 278 } 279 } 280 281 /** 282 * Gets the delimiter. 283 * 284 * @return the delimiter 285 */ 286 private String getDelimiter() { 287 return delimiter; 288 } 289 290 /** 291 * Prints the. 292 * 293 * @param o 294 * the o 295 */ 296 private void print(Object o) { 297 if (logWriter != null) { 298 System.out.print(o); 299 } 300 } 301 302 /** 303 * Println. 304 * 305 * @param o 306 * the o 307 */ 308 private void println(Object o) { 309 if (logWriter != null) { 310 logWriter.println(o); 311 } 312 } 313 314 /** 315 * Println error. 316 * 317 * @param o 318 * the o 319 */ 320 private void printlnError(Object o) { 321 if (errorLogWriter != null) { 322 errorLogWriter.println(o); 323 } 324 } 325 326 /** 327 * Flush. 328 */ 329 private void flush() { 330 if (logWriter != null) { 331 logWriter.flush(); 332 } 333 if (errorLogWriter != null) { 334 errorLogWriter.flush(); 335 } 336 } 337 338}