package com.linkedin.thirdeye.datalayer; import java.io.IOException; import java.io.LineNumberReader; import java.io.PrintWriter; import java.io.Reader; import java.sql.Connection; import java.sql.SQLException; /** * Tool to run database scripts */ public class ScriptRunner { private static final String DEFAULT_DELIMITER = ";"; private Connection connection; private boolean stopOnError; private boolean autoCommit; private PrintWriter logWriter = new PrintWriter(System.out); private PrintWriter errorLogWriter = new PrintWriter(System.err); private String delimiter = DEFAULT_DELIMITER; private boolean fullLineDelimiter = false; private static final String DELIMITER_LINE_REGEX = "(?i)DELIMITER.+"; private static final String DELIMITER_LINE_SPLIT_REGEX = "(?i)DELIMITER"; /** * Default constructor */ public ScriptRunner(Connection connection, boolean autoCommit, boolean stopOnError) { this.connection = connection; this.autoCommit = autoCommit; this.stopOnError = stopOnError; } public void setDelimiter(String delimiter, boolean fullLineDelimiter) { this.delimiter = delimiter; this.fullLineDelimiter = fullLineDelimiter; } /** * Setter for logWriter property * * @param logWriter - the new value of the logWriter property */ public void setLogWriter(PrintWriter logWriter) { this.logWriter = logWriter; } /** * Setter for errorLogWriter property * * @param errorLogWriter - the new value of the errorLogWriter property */ public void setErrorLogWriter(PrintWriter errorLogWriter) { this.errorLogWriter = errorLogWriter; } /** * Runs an SQL script (read in using the Reader parameter) * * @param reader - the source of the script */ public void runScript(Reader reader) throws IOException, SQLException { try { boolean originalAutoCommit = connection.getAutoCommit(); try { if (originalAutoCommit != this.autoCommit) { connection.setAutoCommit(this.autoCommit); } runScript(connection, reader); } finally { connection.setAutoCommit(originalAutoCommit); } } catch (IOException e) { throw e; } catch (SQLException e) { throw e; } catch (Exception e) { throw new RuntimeException("Error running script. Cause: " + e, e); } } /** * Runs an SQL script (read in using the Reader parameter) using the connection passed in * * @param conn - the connection to use for the script * @param reader - the source of the script * * @throws SQLException if any SQL errors occur * @throws IOException if there is an error reading from the Reader */ private void runScript(Connection conn, Reader reader) throws IOException, SQLException { StringBuffer command = null; try { LineNumberReader lineReader = new LineNumberReader(reader); String line = null; while ((line = lineReader.readLine()) != null) { if (command == null) { command = new StringBuffer(); } if (line.startsWith("--")) { continue; } command.append(line).append(" "); if (line.endsWith(";")) { conn.prepareStatement(command.toString()).executeUpdate(); System.out.println(command); command = null; } } if (!autoCommit) { conn.commit(); } } catch (SQLException e) { e.fillInStackTrace(); printlnError("Error executing: " + command); printlnError(e); // throw e; } catch (IOException e) { e.fillInStackTrace(); printlnError("Error executing: " + command); printlnError(e); throw e; } finally { conn.rollback(); flush(); } } private String getDelimiter() { return delimiter; } private void print(Object o) { if (logWriter != null) { System.out.print(o); } } private void println(Object o) { if (logWriter != null) { logWriter.println(o); } } private void printlnError(Object o) { if (errorLogWriter != null) { errorLogWriter.println(o); } } private void flush() { if (logWriter != null) { logWriter.flush(); } if (errorLogWriter != null) { errorLogWriter.flush(); } } }