org.codehaus.mojo.sql.SqlExecMojo Maven / Gradle / Ivy
package org.codehaus.mojo.sql;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
* file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Reader;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.settings.Server;
import org.apache.maven.settings.Settings;
import org.apache.maven.shared.filtering.MavenFileFilter;
import org.apache.maven.shared.filtering.MavenFileFilterRequest;
import org.apache.maven.shared.filtering.MavenFilteringException;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.StringUtils;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
/**
* Executes SQL against a database.
*
* @goal execute
*/
public class SqlExecMojo extends AbstractMojo {
/**
* Call {@link #setOnError(String)} with this value to abort SQL command execution if an error is found.
*/
public static final String ON_ERROR_ABORT = "abort";
/**
* Call {@link #setOnError(String)} with this value to continue SQL command execution until all commands have been
* attempted, then abort the build if an SQL error occurred in any of the commands.
*/
public static final String ON_ERROR_ABORT_AFTER = "abortAfter";
/**
* Call {@link #setOnError(String)} with this value to continue SQL command execution if an error is found.
*/
public static final String ON_ERROR_CONTINUE = "continue";
// ////////////////////////// User Info ///////////////////////////////////
/**
* Database username. If not given, it will be looked up through settings.xml
's server with
* ${settingsKey}
as key.
*
* @since 1.0
* @parameter expression="${username}"
*/
private String username;
/**
* Database password. If not given, it will be looked up through settings.xml
's server with
* ${settingsKey}
as key.
*
* @since 1.0
* @parameter expression="${password}"
*/
private String password;
/**
* Ignore the password and use anonymous access. This may be useful for databases like MySQL which do not allow
* empty password parameters in the connection initialization.
*
* @since 1.4
* @parameter default-value="false"
*/
private boolean enableAnonymousPassword;
/**
* Additional key=value pairs separated by comma to be passed into JDBC driver.
*
* @since 1.0
* @parameter expression="${driverProperties}" default-value = ""
*/
private String driverProperties;
/**
* @parameter expression="${settings}"
* @required
* @since 1.0
* @readonly
*/
private Settings settings;
/**
* Server's id
in settings.xml
to look up username and password. Defaults to
* ${url}
if not given.
*
* @since 1.0
* @parameter expression="${settingsKey}"
*/
private String settingsKey;
/**
* Skip execution when there is an error obtaining a connection. This is a special case to support databases, such
* as embedded Derby, that can shutdown the database via the URL (i.e. shutdown=true
).
*
* @since 1.1
* @parameter expression="${skipOnConnectionError}" default-value="false"
*/
private boolean skipOnConnectionError;
/**
* Setting this parameter to true
will force the execution of this mojo, even if it would get skipped
* usually.
*
* @parameter expression="${forceOpenJpaExecution}" default-value=false
* @required
*/
private boolean forceMojoExecution;
/**
* The Maven Project Object
*
* @parameter default-value="${project}"
* @required
* @readonly
*/
protected MavenProject project;
/**
* @parameter default-value="${session}"
* @required
* @readonly
*/
private MavenSession mavenSession;
// ////////////////////////////// Source info /////////////////////////////
/**
* SQL input commands separated by ${delimiter}
.
*
* @since 1.0
* @parameter expression="${sqlCommand}" default-value=""
*/
private String sqlCommand = "";
/**
* List of files containing SQL statements to load.
*
* @since 1.0
* @parameter
*/
private File[] srcFiles;
/**
* List of resources containing SQL statements
*
* @since 1.5
* @parameter
*/
private String[] resourceLocations;
/**
* File(s) containing SQL statements to load.
*
* @since 1.0
* @parameter
*/
private Fileset fileset;
/**
* When true
, skip the execution.
*
* @since 1.0
* @parameter default-value="false"
*/
private boolean skip;
// //////////////////////////////// Database info /////////////////////////
/**
* Database URL.
*
* @parameter expression="${url}"
* @required
* @since 1.0-beta-1
*/
private String url;
/**
* Database driver classname.
*
* @since 1.0
* @parameter expression="${driver}"
* @required
*/
private String driver;
// //////////////////////////// Operation Configuration ////////////////////
/**
* Set to true
to execute none-transactional SQL.
*
* @since 1.0
* @parameter expression="${autocommit}" default-value="false"
*/
private boolean autocommit;
/**
* Action to perform if an error is found. Possible values are abort
and continue
.
*
* @since 1.0
* @parameter expression="${onError}" default-value="abort"
*/
private String onError = ON_ERROR_ABORT;
// //////////////////////////// Parser Configuration ////////////////////
/**
* Set the delimiter that separates SQL statements.
*
* @since 1.0
* @parameter expression="${delimiter}" default-value=";"
*/
private String delimiter = ";";
/**
*
* The delimiter type takes two values - "normal" and "row". Normal means that any occurrence of the delimiter
* terminate the SQL command whereas with row, only a line containing just the delimiter is recognized as the end of
* the command.
*
*
* For example, set this to "go" and delimiterType to "row" for Sybase ASE or MS SQL Server.
*
*
* @since 1.2
* @parameter expression="${delimiterType}" default-value="normal"
*/
private String delimiterType = DelimiterType.NORMAL;
/**
* Set the order in which the SQL files will be executed. Possible values are ASCENDING
and
* DESCENDING
and NONE
.
*
* @since 1.1
* @parameter expression="${orderFile}" default-value="NONE";
*/
private Order orderFile;
/**
* When true
, the whole SQL content in sqlCommand
, srcFiles
and
* fileset
are sent directly to JDBC in one SQL statement. This option is for executing database stored
* procedures/functions.
*
* @deprecated used delimiterType instead.
* @since 1.1
* @parameter expression="${enableBlockMode}"
*/
@Deprecated
private boolean enableBlockMode = false;
/**
* Keep the format of an SQL block.
*
* @since 1.1
* @parameter expression="${keepFormat}" default-value="false"
*/
private boolean keepFormat = false;
// /////////////////////////////////////////////////////////////////////////////////////
/**
* Print SQL results.
*
* @parameter
* @since 1.3
*/
private boolean printResultSet = false;
/**
* Print header columns.
*/
private boolean showheaders = true;
/**
* Dump the SQL exection's output to a file. Default is stdout.
*
* @parameter
* @since 1.3
*/
private File outputFile;
/**
* @parameter default-value=","
* @since 1.4
*/
private String outputDelimiter;
/**
* Encoding to use when reading SQL statements from a file.
*
* @parameter expression="${encoding}" default-value= "${project.build.sourceEncoding}"
* @since 1.1
*/
private String encoding = "";
/**
* Append to an existing file or overwrite it?
*/
private boolean append = false;
/**
* Argument to Statement.setEscapeProcessing If you want the driver to use regular SQL syntax then set this to
* false.
*
* @since 1.4
* @parameter expression="${escapeProcessing}" default-value="true"
*/
private boolean escapeProcessing = true;
// //////////////////////////////// Internal
// properties//////////////////////
/**
* number of successful executed statements
*/
private int successfulStatements = 0;
/**
* number of total executed statements
*/
private int totalStatements = 0;
/**
* Database connection
*/
private Connection conn = null;
/**
* SQL statement
*/
private Statement statement = null;
/**
* SQL transactions to perform
*/
private Vector transactions = new Vector();
/**
* @component role="org.apache.maven.shared.filtering.MavenFileFilter"
* @since 1.4
*/
private MavenFileFilter fileFilter;
/**
* Set to true if you want to filter the srcFiles using system-, user- and project properties
*
* @parameter
* @since 1.4
*/
private boolean enableFiltering;
/**
* Set to false to disable executing SQL that appears without a delimiter at the end of a file (is enabled by
* default for backwards compatibility)
*
* @parameter expression="${sql.executeTrailingSQL}" default-value="true"
* @since 1.7
*/
private boolean executeTrailingSQL;
/**
* Interpolator especially for braceless expressions
*/
// private Interpolator interpolator = new
// RegexBasedInterpolator("\\$([^\\s;)]+?)", "(?=[\\s;)])");
/**
* Add a SQL transaction to execute
*
* @return a new SqlExecMojo.Transaction
*/
public Transaction createTransaction() {
Transaction t = new Transaction();
transactions.addElement(t);
return t;
}
/**
* Set an inline SQL command to execute. NB: Properties are not expanded in this text.
*
* @param sql
* the sql statement to add
*/
public void addText(String sql) {
this.sqlCommand += sql;
}
/**
* Set the file encoding to use on the SQL files read in
*
* @param encoding
* the encoding to use on the files
*/
public void setEncoding(String encoding) {
this.encoding = encoding;
}
/**
* Set the delimiter that separates SQL statements. Defaults to ";";
*
* @param delimiter
* the new delimiter
*/
public void setDelimiter(String delimiter) {
this.delimiter = delimiter;
}
/**
* Set the delimiter type: "normal" or "row" (default "normal").
*
* @param delimiterType
* the new delimiterType
*/
public void setDelimiterType(String delimiterType) {
this.delimiterType = delimiterType;
}
/**
* Print result sets from the statements; optional, default false
*
* @param print
* true
to print the resultset, otherwise false
* @deprecated typo, use setPrintResultSet()
*/
@Deprecated
public void setPrintResutlSet(boolean print) {
setPrintResultSet(print);
}
/**
* Print result sets from the statements; optional, default false
*
* @param print
* true
to print the resultset, otherwise false
*/
public void setPrintResultSet(boolean print) {
this.printResultSet = print;
}
/**
* Print headers for result sets from the statements; optional, default true.
*
* @param showheaders
* true
to show the headers, otherwise false
*/
public void setShowheaders(boolean showheaders) {
this.showheaders = showheaders;
}
/**
* Set the output file;
*
* @param output
* the output file
*/
public void setOutputFile(File output) {
this.outputFile = output;
}
/**
* whether output should be appended to or overwrite an existing file. Defaults to false.
*
* @param append
* true
to append, otherwise false
to overwrite
*/
public void setAppend(boolean append) {
this.append = append;
}
/**
* whether or not format should be preserved. Defaults to false.
*
* @param keepformat
* The keepformat to set
*/
public void setKeepFormat(boolean keepformat) {
this.keepFormat = keepformat;
}
/**
* Set escape processing for statements.
*
* @param enable
* true
to escape, otherwiser false
*/
public void setEscapeProcessing(boolean enable) {
escapeProcessing = enable;
}
/**
*
* Determine if the mojo execution should get skipped.
*
* This is the case if:
*
* - {@link #skip} is
true
* - if the mojo gets executed on a project with packaging type 'pom' and {@link #forceMojoExecution} is
*
false
*
*
* @return true
if the mojo execution should be skipped.
*/
protected boolean skipMojo() {
if (skip) {
getLog().info("Skip sql execution");
return true;
}
if (!forceMojoExecution && project != null && "pom".equals(project.getPackaging())) {
getLog().info("Skipping sql execution for project with packaging type 'pom'");
return true;
}
return false;
}
/**
* Load the sql file and then execute it
*
* @throws MojoExecutionException
*/
@Override
public void execute() throws MojoExecutionException {
if (skipMojo()) {
return;
}
successfulStatements = 0;
totalStatements = 0;
loadUserInfoFromSettings();
addCommandToTransactions();
addFilesToTransactions();
addFileSetToTransactions();
addResourcesToTransactions();
sortTransactions();
try {
conn = getConnection();
} catch (SQLException e) {
if (!this.skipOnConnectionError) {
throw new MojoExecutionException(e.getMessage(), e);
} else {
// error on get connection and user asked to skip the rest
return;
}
}
try {
statement = conn.createStatement();
statement.setEscapeProcessing(escapeProcessing);
PrintStream out = System.out;
try {
if (outputFile != null) {
getLog().debug("Opening PrintStream to output file " + outputFile);
out = new PrintStream(new BufferedOutputStream(new FileOutputStream(outputFile.getAbsolutePath(),
append)));
}
// Process all transactions
for (Enumeration e = transactions.elements(); e.hasMoreElements();) {
Transaction t = e.nextElement();
t.runTransaction(out);
if (!autocommit) {
getLog().debug("Committing transaction");
conn.commit();
}
}
} finally {
if (out != null && out != System.out) {
out.close();
}
}
} catch (IOException e) {
throw new MojoExecutionException(e.getMessage(), e);
} catch (SQLException e) {
if (!autocommit && conn != null && ON_ERROR_ABORT.equalsIgnoreCase(getOnError())) {
try {
conn.rollback();
} catch (SQLException ex) {
// ignore
}
}
throw new MojoExecutionException(e.getMessage(), e);
} finally {
try {
if (statement != null) {
statement.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException ex) {
// ignore
}
}
getLog().info(
getSuccessfulStatements() + " of " + getTotalStatements() + " SQL statements executed successfully");
if (ON_ERROR_ABORT_AFTER.equalsIgnoreCase(getOnError()) && totalStatements != successfulStatements) {
throw new MojoExecutionException("Some SQL statements failed to execute");
}
}
/**
* Add sql command to transactions list.
*
*/
private void addCommandToTransactions() {
createTransaction().addText(sqlCommand.trim());
}
/**
* Add user sql fileset to transation list
*
*/
private void addFileSetToTransactions() {
String[] includedFiles;
if (fileset != null) {
fileset.scan();
includedFiles = fileset.getIncludedFiles();
} else {
includedFiles = new String[0];
}
for (int j = 0; j < includedFiles.length; j++) {
createTransaction().setSrc(new File(fileset.getBasedir(), includedFiles[j]));
}
}
protected Resource[] getResources(String[] locations) throws MojoExecutionException {
if (locations == null || locations.length == 0) {
return new Resource[] {};
}
ResourceLoader loader = new DefaultResourceLoader();
List resources = new ArrayList();
for (int i = 0; i < locations.length; i++) {
String location = locations[i];
// Skip it if the location is empty
if (StringUtils.isEmpty(location)) {
continue;
}
Resource resource = loader.getResource(location);
if (!resource.exists()) {
// The location was not empty, but we couldn't find it
throw new MojoExecutionException("Resource " + location + " was not found");
}
resources.add(resource);
}
return resources.toArray(new Resource[resources.size()]);
}
protected void copy(Resource resource, File file) throws IOException {
InputStream in = resource.getInputStream();
OutputStream out = new FileOutputStream(file);
IOUtils.copyLarge(in, out);
}
/**
* Add user input of srcFiles to transaction list.
*
* @throws MojoExecutionException
*/
private void addResourcesToTransactions() throws MojoExecutionException {
String[] locations = getResourceLocations();
Resource[] resources = getResources(locations);
MavenFileFilterRequest request = new MavenFileFilterRequest();
request.setEncoding(encoding);
request.setMavenSession(mavenSession);
request.setMavenProject(project);
request.setFiltering(enableFiltering);
for (int i = 0; i < resources.length; i++) {
Resource resource = resources[i];
String filename = resource.getFilename();
String basename = FileUtils.basename(filename);
String extension = FileUtils.extension(filename);
if (!extension.startsWith(".")) {
extension = "." + extension;
}
File sourceFile = FileUtils.createTempFile(basename, extension, null);
if (!getLog().isDebugEnabled()) {
sourceFile.deleteOnExit();
}
try {
copy(resource, sourceFile);
} catch (IOException e) {
throw new MojoExecutionException("Error copying resource " + resource + " to a local temporary file", e);
}
if (!enableFiltering) {
createTransaction().setSrc(sourceFile);
continue;
}
File targetFile = FileUtils.createTempFile(basename, extension, null);
if (!getLog().isDebugEnabled()) {
sourceFile.deleteOnExit();
}
request.setFrom(sourceFile);
request.setTo(targetFile);
try {
fileFilter.copyFile(request);
} catch (MavenFilteringException e) {
throw new MojoExecutionException(e.getMessage());
}
createTransaction().setSrc(targetFile);
}
}
/**
* Add user input of srcFiles to transaction list.
*
* @throws MojoExecutionException
*/
private void addFilesToTransactions() throws MojoExecutionException {
File[] files = getSrcFiles();
MavenFileFilterRequest request = new MavenFileFilterRequest();
request.setEncoding(encoding);
request.setMavenSession(mavenSession);
request.setMavenProject(project);
request.setFiltering(enableFiltering);
for (int i = 0; files != null && i < files.length; ++i) {
if (files[i] != null && !files[i].exists()) {
throw new MojoExecutionException(files[i].getPath() + " not found.");
}
if (!enableFiltering) {
createTransaction().setSrc(files[i]);
continue;
}
File sourceFile = files[i];
String basename = FileUtils.basename(sourceFile.getName());
String extension = FileUtils.extension(sourceFile.getName());
if (!extension.startsWith(".")) {
extension = "." + extension;
}
File targetFile = FileUtils.createTempFile(basename, extension, null);
if (!getLog().isDebugEnabled()) {
targetFile.deleteOnExit();
}
request.setFrom(sourceFile);
request.setTo(targetFile);
try {
fileFilter.copyFile(request);
} catch (MavenFilteringException e) {
throw new MojoExecutionException(e.getMessage());
}
createTransaction().setSrc(targetFile);
}
}
/**
* Sort the transaction list.
*/
protected void sortTransactions() {
switch (orderFile) {
case ASCENDING:
Collections.sort(transactions);
break;
case DESCENDING:
Collections.sort(transactions, Collections.reverseOrder());
break;
case NONE:
break;
default:
throw new RuntimeException("Unknown value for orderFile: " + orderFile);
}
}
/**
* Load username password from settings if user has not set them in JVM properties
*
* @throws MojoExecutionException
*/
private void loadUserInfoFromSettings() throws MojoExecutionException {
if (this.settingsKey == null) {
this.settingsKey = getUrl();
}
if ((getUsername() == null || getPassword() == null) && (settings != null)) {
Server server = this.settings.getServer(this.settingsKey);
if (server != null) {
if (getUsername() == null) {
setUsername(server.getUsername());
}
if (getPassword() == null) {
setPassword(server.getPassword());
}
}
}
if (getUsername() == null) {
// allow emtpy username
setUsername("");
}
if (getPassword() == null) {
// allow emtpy password
setPassword("");
}
}
/**
* Creates a new Connection as using the driver, url, userid and password specified.
*
* The calling method is responsible for closing the connection.
*
* @return Connection the newly created connection.
* @throws MojoExecutionException
* if the UserId/Password/Url is not set or there is no suitable driver or the driver fails to load.
* @throws SQLException
* if there is problem getting connection with valid url
*
*/
private Connection getConnection() throws MojoExecutionException, SQLException {
getLog().debug("connecting to " + getUrl());
Properties info = new Properties();
info.put("user", getUsername());
if (!enableAnonymousPassword) {
info.put("password", getPassword());
}
info.putAll(this.getDriverProperties());
Driver driverInstance = null;
try {
Class> dc = Class.forName(getDriver());
driverInstance = (Driver) dc.newInstance();
} catch (ClassNotFoundException e) {
throw new MojoExecutionException("Driver class not found: " + getDriver(), e);
} catch (Exception e) {
throw new MojoExecutionException("Failure loading driver: " + getDriver(), e);
}
Connection conn = driverInstance.connect(getUrl(), info);
if (conn == null) {
// Driver doesn't understand the URL
throw new SQLException("No suitable Driver for " + getUrl());
}
conn.setAutoCommit(autocommit);
return conn;
}
/**
* parse driverProperties into Properties set
*
* @return the driver properties
* @throws MojoExecutionException
*/
protected Properties getDriverProperties() throws MojoExecutionException {
Properties properties = new Properties();
if (!StringUtils.isEmpty(this.driverProperties)) {
String[] tokens = StringUtils.split(this.driverProperties, ",");
for (int i = 0; i < tokens.length; ++i) {
String[] keyValueTokens = StringUtils.split(tokens[i].trim(), "=");
if (keyValueTokens.length != 2) {
throw new MojoExecutionException("Invalid JDBC Driver properties: " + this.driverProperties);
}
properties.setProperty(keyValueTokens[0], keyValueTokens[1]);
}
}
return properties;
}
/**
* read in lines and execute them
*
* @param reader
* the reader
* @param out
* the outputstream
* @throws SQLException
* @throws IOException
*/
private void runStatements(Reader reader, PrintStream out) throws SQLException, IOException {
String line;
if (enableBlockMode) {
// no need to parse the content, ship it directly to jdbc in one sql
// statement
line = IOUtil.toString(reader);
execSQL(line, out);
return;
}
StringBuffer sql = new StringBuffer();
BufferedReader in = new BufferedReader(reader);
while ((line = in.readLine()) != null) {
getLog().debug("line='" + line + "'");
if (!keepFormat) {
line = line.trim();
}
if (!keepFormat) {
if (line.startsWith("//")) {
continue;
}
if (line.startsWith("--")) {
continue;
}
StringTokenizer st = new StringTokenizer(line);
if (st.hasMoreTokens()) {
String token = st.nextToken();
if ("REM".equalsIgnoreCase(token)) {
continue;
}
}
}
if (!keepFormat) {
sql.append(" ").append(line);
} else {
sql.append("\n").append(line);
}
// SQL defines "--" as a comment to EOL
// but in Oracle it may contain a hint
// so we cannot just remove it, instead we must end it
if (!keepFormat) {
if (SqlSplitter.containsSqlEnd(line, delimiter) == SqlSplitter.NO_END) {
sql.append("\n");
}
}
if (isEnd(line)) {
execSQL(sql.substring(0, sql.length() - delimiter.length()), out);
sql.setLength(0); // clean buffer
}
}
// Catch any statements not followed by ;
if (executeTrailingSQL && !sql.toString().equals("")) {
execSQL(sql.toString(), out);
}
}
protected boolean isEnd(String line) {
if (delimiterType.equals(DelimiterType.ROW)) {
return line.trim().equals(delimiter);
}
int pos = SqlSplitter.containsSqlEnd(line, delimiter);
if (delimiterType.equals(DelimiterType.NORMAL) && pos > 0) {
return true;
}
return false;
}
/**
* Exec the sql statement.
*
* @param sql
* query to execute
* @param out
* the outputstream
*/
private void execSQL(String sql, PrintStream out) throws SQLException {
// Check and ignore empty statements
if ("".equals(sql.trim())) {
return;
}
ResultSet resultSet = null;
try {
totalStatements++;
getLog().debug("SQL: " + sql);
boolean ret;
int updateCountTotal = 0;
ret = statement.execute(sql);
do {
if (!ret) {
int updateCount = statement.getUpdateCount();
if (updateCount != -1) {
updateCountTotal += updateCount;
}
} else {
resultSet = statement.getResultSet();
if (printResultSet) {
printResultSet(resultSet, out);
}
}
ret = statement.getMoreResults();
} while (ret);
getLog().debug(updateCountTotal + " rows affected");
if (printResultSet) {
StringBuffer line = new StringBuffer();
line.append(updateCountTotal).append(" rows affected");
out.println(line);
}
SQLWarning warning = conn.getWarnings();
while (warning != null) {
getLog().debug(warning + " sql warning");
warning = warning.getNextWarning();
}
conn.clearWarnings();
successfulStatements++;
} catch (SQLException e) {
getLog().error("Failed to execute: " + sql);
if (ON_ERROR_ABORT.equalsIgnoreCase(getOnError())) {
throw e;
}
getLog().error(e.toString());
} finally {
if (resultSet != null) {
resultSet.close();
}
}
}
/**
* print any results in the result set.
*
* @param rs
* the resultset to print information about
* @param out
* the place to print results
* @throws SQLException
* on SQL problems.
*/
private void printResultSet(ResultSet rs, PrintStream out) throws SQLException {
if (rs != null) {
getLog().debug("Processing new result set.");
ResultSetMetaData md = rs.getMetaData();
int columnCount = md.getColumnCount();
StringBuffer line = new StringBuffer();
if (showheaders) {
boolean first = true;
for (int col = 1; col <= columnCount; col++) {
String columnValue = md.getColumnName(col);
if (columnValue != null) {
columnValue = columnValue.trim();
if (",".equals(outputDelimiter)) {
columnValue = StringEscapeUtils.escapeCsv(columnValue);
}
}
if (first) {
first = false;
} else {
line.append(outputDelimiter);
}
line.append(columnValue);
}
out.println(line);
line = new StringBuffer();
}
while (rs.next()) {
boolean first = true;
for (int col = 1; col <= columnCount; col++) {
String columnValue = rs.getString(col);
if (columnValue != null) {
columnValue = columnValue.trim();
if (",".equals(outputDelimiter)) {
columnValue = StringEscapeUtils.escapeCsv(columnValue);
}
}
if (first) {
first = false;
} else {
line.append(outputDelimiter);
}
line.append(columnValue);
}
out.println(line);
line = new StringBuffer();
}
}
out.println();
}
/**
* Contains the definition of a new transaction element. Transactions allow several files or blocks of statements to
* be executed using the same JDBC connection and commit operation in between.
*/
private class Transaction implements Comparable {
private File tSrcFile = null;
private String tSqlCommand = "";
/**
*
*/
public void setSrc(File src) {
this.tSrcFile = src;
}
/**
*
*/
public void addText(String sql) {
this.tSqlCommand += sql;
}
/**
*
*/
private void runTransaction(PrintStream out) throws IOException, SQLException {
if (tSqlCommand.length() != 0) {
getLog().info("Executing commands");
runStatements(new StringReader(tSqlCommand), out);
}
if (tSrcFile != null) {
getLog().info("Executing file: " + tSrcFile.getAbsolutePath());
Reader reader = null;
if (StringUtils.isEmpty(encoding)) {
reader = new FileReader(tSrcFile);
} else {
reader = new InputStreamReader(new FileInputStream(tSrcFile), encoding);
}
try {
runStatements(reader, out);
} finally {
reader.close();
}
}
}
@Override
public int compareTo(Transaction transaction) {
if (transaction.tSrcFile == null) {
if (this.tSrcFile == null) {
return 0;
} else {
return Integer.MAX_VALUE;
}
} else {
if (this.tSrcFile == null) {
return Integer.MIN_VALUE;
} else {
return this.tSrcFile.compareTo(transaction.tSrcFile);
}
}
}
}
//
// helper accessors for unit test purposes
//
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUrl() {
return this.url;
}
public void setUrl(String url) {
this.url = url;
}
public String getDriver() {
return this.driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
void setAutocommit(boolean autocommit) {
this.autocommit = autocommit;
}
void setFileset(Fileset fileset) {
this.fileset = fileset;
}
public File[] getSrcFiles() {
return this.srcFiles;
}
public void setSrcFiles(File[] files) {
this.srcFiles = files;
}
/**
* @deprecated use {@link #getSuccessfulStatements()}
*/
@Deprecated
int getGoodSqls() {
return this.getSuccessfulStatements();
}
/**
* Number of SQL statements executed so far that caused errors.
*
* @return the number
*/
public int getSuccessfulStatements() {
return successfulStatements;
}
/**
* Number of SQL statements executed so far, including the ones that caused errors.
*
* @return the number
*/
public int getTotalStatements() {
return totalStatements;
}
public String getOnError() {
return this.onError;
}
public void setOnError(String action) {
if (ON_ERROR_ABORT.equalsIgnoreCase(action)) {
this.onError = ON_ERROR_ABORT;
} else if (ON_ERROR_CONTINUE.equalsIgnoreCase(action)) {
this.onError = ON_ERROR_CONTINUE;
} else if (ON_ERROR_ABORT_AFTER.equalsIgnoreCase(action)) {
this.onError = ON_ERROR_ABORT_AFTER;
} else {
throw new IllegalArgumentException(action + " is not a valid value for onError, only '" + ON_ERROR_ABORT
+ "', '" + ON_ERROR_ABORT_AFTER + "', or '" + ON_ERROR_CONTINUE + "'.");
}
}
void setSettings(Settings settings) {
this.settings = settings;
}
void setSettingsKey(String key) {
this.settingsKey = key;
}
void setSkip(boolean skip) {
this.skip = skip;
}
public void setDriverProperties(String driverProperties) {
this.driverProperties = driverProperties;
}
public boolean isEnableBlockMode() {
return enableBlockMode;
}
public void setEnableBlockMode(boolean enableBlockMode) {
this.enableBlockMode = enableBlockMode;
}
public String getSqlCommand() {
return sqlCommand;
}
public void setSqlCommand(String sqlCommand) {
this.sqlCommand = sqlCommand;
}
public Vector getTransactions() {
return transactions;
}
public void setTransactions(Vector transactions) {
this.transactions = transactions;
}
public void setFileFilter(MavenFileFilter filter) {
this.fileFilter = filter;
}
public String[] getResourceLocations() {
return resourceLocations;
}
public void setResourceLocations(String[] resourceLocations) {
this.resourceLocations = resourceLocations;
}
public boolean isExecuteTrailingSQL() {
return executeTrailingSQL;
}
public void setExecuteTrailingSQL(boolean executeTrailingSQL) {
this.executeTrailingSQL = executeTrailingSQL;
}
public Order getOrderFile() {
return orderFile;
}
public void setOrderFile(String orderFile) {
this.orderFile = Order.valueOf(orderFile.toUpperCase());
}
}