Introduction
In this article, I will show you how to run a SQL script file using ScriptRunner
class. Through this class, you can execute any DDL, DML statement including SELECT
Statement and any PL/SQL Block like PROCEDURE
, FUNCTION
, TRIGGER
Quick Start
**
*
* @author Debopam Pal, Software Developer, National Informatics Center (NIC), India
* @Date July 29, 2014
* @File ScriptRunner.java
*/
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
public class ScriptRunner {
public static final String DEFAULT_DELIMITER = ";";
public static final String PL_SQL_BLOCK_SPLIT_DELIMITER = "+";
public static final String PL_SQL_BLOCK_END_DELIMITER = "#";
private final boolean autoCommit, stopOnError;
private final Connection connection;
private String delimiter = ScriptRunner.DEFAULT_DELIMITER;
private final PrintWriter out, err;
private List<Table> tableList;
private List<String> sqlOutput;
public ScriptRunner(final Connection connection, final boolean autoCommit, final boolean stopOnError) {
if (connection == null) {
throw new RuntimeException("ScriptRunner requires an SQL Connection");
}
this.connection = connection;
this.autoCommit = autoCommit;
this.stopOnError = stopOnError;
this.out = new PrintWriter(System.out);
this.err = new PrintWriter(System.err);
tableList = new ArrayList<Table>();
sqlOutput = new ArrayList<String>();
}
public void runScript(final Reader reader) throws SQLException, IOException {
final boolean originalAutoCommit = this.connection.getAutoCommit();
try {
if (originalAutoCommit != this.autoCommit) {
this.connection.setAutoCommit(this.autoCommit);
}
this.runScript(this.connection, reader);
} finally {
this.connection.setAutoCommit(originalAutoCommit);
}
}
private void runScript(final Connection conn, final Reader reader) throws SQLException, IOException {
StringBuffer command = null;
Table table = null;
try {
final LineNumberReader lineReader = new LineNumberReader(reader);
String line = null;
while ((line = lineReader.readLine()) != null) {
if (command == null) {
command = new StringBuffer();
}
if (table == null) {
table = new Table();
}
String trimmedLine = line.trim();
if (trimmedLine.startsWith("--")
|| trimmedLine.startsWith("//")
|| trimmedLine.startsWith("#")
|| trimmedLine.toLowerCase().startsWith("rem inserting into")
|| trimmedLine.toLowerCase().startsWith("set define off")) {
} else if (trimmedLine.endsWith(this.delimiter) ||
trimmedLine.endsWith(PL_SQL_BLOCK_END_DELIMITER)) {
if (trimmedLine.endsWith(this.delimiter)) {
command.append(line.substring(0, line.lastIndexOf(this.delimiter)));
command.append(" ");
} else if (trimmedLine.endsWith(PL_SQL_BLOCK_END_DELIMITER)) {
command.append(line.substring
(0, line.lastIndexOf(PL_SQL_BLOCK_END_DELIMITER)));
command.append(" ");
}
Statement stmt = null;
ResultSet rs = null;
try {
stmt = conn.createStatement();
boolean hasResults = false;
if (this.stopOnError) {
hasResults = stmt.execute(command.toString());
} else {
try {
stmt.execute(command.toString());
} catch (final SQLException e) {
e.fillInStackTrace();
err.println("Error executing SQL Command: \"" +
command + "\"");
err.println(e);
err.flush();
throw e;
}
}
rs = stmt.getResultSet();
if (hasResults && rs != null) {
List<String> headerRow = new ArrayList<String>();
List<List<String>> toupleList = new ArrayList<List<String>>();
final ResultSetMetaData md = rs.getMetaData();
final int cols = md.getColumnCount();
for (int i = 0; i < cols; i++) {
final String name = md.getColumnLabel(i + 1);
out.print(name + "\t");
headerRow.add(name);
}
table.setHeaderRow(headerRow);
out.println("");
out.println(StringUtils.repeat("---------", md.getColumnCount()));
out.flush();
while (rs.next()) {
List<String> touple = new ArrayList<String>();
for (int i = 1; i <= cols; i++) {
final String value = rs.getString(i);
out.print(value + "\t");
touple.add(value);
}
out.println("");
toupleList.add(touple);
}
out.flush();
table.setToupleList(toupleList);
this.tableList.add(table);
table = null;
} else {
sqlOutput.add(stmt.getUpdateCount() + " row(s) affected.");
out.println(stmt.getUpdateCount() + " row(s) affected.");
out.flush();
}
command = null;
} finally {
if (rs != null) {
try {
rs.close();
} catch (final Exception e) {
err.println("Failed to close result: " + e.getMessage());
err.flush();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (final Exception e) {
err.println("Failed to close statement: " + e.getMessage());
err.flush();
}
}
}
} else if (trimmedLine.endsWith(PL_SQL_BLOCK_SPLIT_DELIMITER)) {
command.append(line.substring
(0, line.lastIndexOf(this.PL_SQL_BLOCK_SPLIT_DELIMITER)));
command.append(" ");
} else {
command.append(line);
command.append(" ");
}
}
if (!this.autoCommit) {
conn.commit();
}
} catch (final SQLException e) {
conn.rollback();
e.fillInStackTrace();
err.println("Error executing SQL Command: \"" + command + "\"");
err.println(e);
err.flush();
throw e;
} catch (final IOException e) {
e.fillInStackTrace();
err.println("Error reading SQL Script.");
err.println(e);
err.flush();
throw e;
}
}
public List<Table> getTableList() {
return tableList;
}
public void setTableList(List<Table> tableList) {
this.tableList = tableList;
}
public List<String> getSqlOutput() {
return sqlOutput;
}
public void setSqlOutput(List<String> sqlOutput) {
this.sqlOutput = sqlOutput;
}
}
How to Call
ScriptRunner scriptRunner = new ScriptRunner(con, false, true);
String aSQLScriptFilePath = "path/to/sql/script.sql";
scriptRunner.runScript(new FileReader(aSQLScriptFilePath));
List<Table> tableList;
List<String> sqlOutput;
tableList = scriptRunner.getTableList();
sqlOutput = scriptRunner.getSqlOutput();
Warnings
Remember, ROLLBACK
cannot be possible for DDL Statements (CREATE
, UPDATE
, DELETE
). So, be careful while writing SQL Queries.
Rules to Obey
- You must end every SQL Statement with ; (Semicolon)
- You must end every statement within PL/SQL Block with + (Plus)
- You must end every PL/SQL Block with # (Hash)
References
- Tool to run database scripts
- How to Execute SQL Script file using Java JDBC
- mybatis, SQL Mapping Framework for Java
If you've any doubt, please post your questions. If you really like this article, please share it.
Don’t forget to vote or comment about my writing.
CodeProject