aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/SQLExec.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/SQLExec.java')
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/SQLExec.java1162
1 files changed, 1162 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/SQLExec.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/SQLExec.java
new file mode 100644
index 00000000..6d1e5148
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/SQLExec.java
@@ -0,0 +1,1162 @@
+/*
+ * 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.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+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.Blob;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.Statement;
+import java.sql.Types;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.Appendable;
+import org.apache.tools.ant.types.resources.FileProvider;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.Union;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.KeepAliveOutputStream;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * Executes a series of SQL statements on a database using JDBC.
+ *
+ * <p>Statements can
+ * either be read in from a text file using the <i>src</i> attribute or from
+ * between the enclosing SQL tags.</p>
+ *
+ * <p>Multiple statements can be provided, separated by semicolons (or the
+ * defined <i>delimiter</i>). Individual lines within the statements can be
+ * commented using either --, // or REM at the start of the line.</p>
+ *
+ * <p>The <i>autocommit</i> attribute specifies whether auto-commit should be
+ * turned on or off whilst executing the statements. If auto-commit is turned
+ * on each statement will be executed and committed. If it is turned off the
+ * statements will all be executed as one transaction.</p>
+ *
+ * <p>The <i>onerror</i> attribute specifies how to proceed when an error occurs
+ * during the execution of one of the statements.
+ * The possible values are: <b>continue</b> execution, only show the error;
+ * <b>stop</b> execution and commit transaction;
+ * and <b>abort</b> execution and transaction and fail task.</p>
+ *
+ * @since Ant 1.2
+ *
+ * @ant.task name="sql" category="database"
+ */
+public class SQLExec extends JDBCTask {
+
+ /**
+ * delimiters we support, "normal" and "row"
+ */
+ public static class DelimiterType extends EnumeratedAttribute {
+ /** The enumerated strings */
+ public static final String NORMAL = "normal", ROW = "row";
+ /** @return the enumerated strings */
+ @Override
+ public String[] getValues() {
+ return new String[] {NORMAL, ROW};
+ }
+ }
+
+ private int goodSql = 0;
+
+ private int totalSql = 0;
+
+ /**
+ * Database connection
+ */
+ private Connection conn = null;
+
+ /**
+ * files to load
+ */
+ private Union resources;
+
+ /**
+ * SQL statement
+ */
+ private Statement statement = null;
+
+ /**
+ * SQL input file
+ */
+ private File srcFile = null;
+
+ /**
+ * SQL input command
+ */
+ private String sqlCommand = "";
+
+ /**
+ * SQL transactions to perform
+ */
+ private Vector transactions = new Vector();
+
+ /**
+ * SQL Statement delimiter
+ */
+ private String delimiter = ";";
+
+ /**
+ * The delimiter type indicating whether the delimiter will
+ * only be recognized on a line by itself
+ */
+ private String delimiterType = DelimiterType.NORMAL;
+
+ /**
+ * Print SQL results.
+ */
+ private boolean print = false;
+
+ /**
+ * Print header columns.
+ */
+ private boolean showheaders = true;
+
+ /**
+ * Print SQL stats (rows affected)
+ */
+ private boolean showtrailers = true;
+
+ /**
+ * Results Output Resource.
+ */
+ private Resource output = null;
+
+ /**
+ * Output encoding.
+ */
+ private String outputEncoding = null;
+
+ /**
+ * Action to perform if an error is found
+ */
+ private String onError = "abort";
+
+ /**
+ * Encoding to use when reading SQL statements from a file
+ */
+ private String encoding = null;
+
+ /**
+ * Append to an existing file or overwrite it?
+ */
+ private boolean append = false;
+
+ /**
+ * Keep the format of a sql block?
+ */
+ private boolean keepformat = false;
+
+ /**
+ * Argument to Statement.setEscapeProcessing
+ *
+ * @since Ant 1.6
+ */
+ private boolean escapeProcessing = true;
+
+ /**
+ * should properties be expanded in text?
+ * false for backwards compatibility
+ *
+ * @since Ant 1.7
+ */
+ private boolean expandProperties = true;
+
+ /**
+ * should we print raw BLOB data?
+ * @since Ant 1.7.1
+ */
+ private boolean rawBlobs;
+
+ /**
+ * delimiters must match in case and whitespace is significant.
+ * @since Ant 1.8.0
+ */
+ private boolean strictDelimiterMatching = true;
+
+ /**
+ * whether to show SQLWarnings as WARN messages.
+ * @since Ant 1.8.0
+ */
+ private boolean showWarnings = false;
+
+ /**
+ * The column separator used when printing the results.
+ *
+ * <p>Defaults to ","</p>
+ *
+ * @since Ant 1.8.0
+ */
+ private String csvColumnSep = ",";
+
+ /**
+ * The character used to quote column values.
+ *
+ * <p>If set, columns that contain either the column separator or
+ * the quote character itself will be surrounded by the quote
+ * character. The quote character itself will be doubled if it
+ * appears inside of the column's value.</p>
+ *
+ * <p>If this value is not set (the default), no column values
+ * will be quoted, not even if they contain the column
+ * separator.</p>
+ *
+ * <p><b>Note:<b> BLOB values will never be quoted.</p>
+ *
+ * <p>Defaults to "not set"</p>
+ *
+ * @since Ant 1.8.0
+ */
+ private String csvQuoteChar = null;
+
+ /**
+ * Whether a warning is an error - in which case onError applies.
+ * @since Ant 1.8.0
+ */
+ private boolean treatWarningsAsErrors = false;
+
+ /**
+ * The name of the property to set in the event of an error
+ * @since Ant 1.8.0
+ */
+ private String errorProperty = null;
+
+ /**
+ * The name of the property to set in the event of a warning
+ * @since Ant 1.8.0
+ */
+ private String warningProperty = null;
+
+ /**
+ * The name of the property that receives the number of rows
+ * returned
+ * @since Ant 1.8.0
+ */
+ private String rowCountProperty = null;
+
+ /**
+ * Set the name of the SQL file to be run.
+ * Required unless statements are enclosed in the build file
+ * @param srcFile the file containing the SQL command.
+ */
+ public void setSrc(File srcFile) {
+ this.srcFile = srcFile;
+ }
+
+ /**
+ * Enable property expansion inside nested text
+ *
+ * @param expandProperties if true expand properties.
+ * @since Ant 1.7
+ */
+ public void setExpandProperties(boolean expandProperties) {
+ this.expandProperties = expandProperties;
+ }
+
+ /**
+ * is property expansion inside inline text enabled?
+ *
+ * @return true if properties are to be expanded.
+ * @since Ant 1.7
+ */
+ public boolean getExpandProperties() {
+ return expandProperties;
+ }
+
+ /**
+ * Set an inline SQL command to execute.
+ * NB: Properties are not expanded in this text unless {@link #expandProperties}
+ * is set.
+ * @param sql an inline string containing the SQL command.
+ */
+ public void addText(String sql) {
+ //there is no need to expand properties here as that happens when Transaction.addText is
+ //called; to do so here would be an error.
+ this.sqlCommand += sql;
+ }
+
+ /**
+ * Adds a set of files (nested fileset attribute).
+ * @param set a set of files contains SQL commands, each File is run in
+ * a separate transaction.
+ */
+ public void addFileset(FileSet set) {
+ add(set);
+ }
+
+ /**
+ * Adds a collection of resources (nested element).
+ * @param rc a collection of resources containing SQL commands,
+ * each resource is run in a separate transaction.
+ * @since Ant 1.7
+ */
+ public void add(ResourceCollection rc) {
+ if (rc == null) {
+ throw new BuildException("Cannot add null ResourceCollection");
+ }
+ synchronized (this) {
+ if (resources == null) {
+ resources = new Union();
+ }
+ }
+ resources.add(rc);
+ }
+
+ /**
+ * Add a SQL transaction to execute
+ * @return a Transaction to be configured.
+ */
+ public Transaction createTransaction() {
+ Transaction t = new Transaction();
+ transactions.addElement(t);
+ return t;
+ }
+
+ /**
+ * 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 &quot;;&quot;;
+ * optional
+ *
+ * <p>For example, set this to "go" and delimitertype to "ROW" for
+ * Sybase ASE or MS SQL Server.</p>
+ * @param delimiter the separator.
+ */
+ public void setDelimiter(String delimiter) {
+ this.delimiter = delimiter;
+ }
+
+ /**
+ * Set the delimiter type: "normal" or "row" (default "normal").
+ *
+ * <p>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.</p>
+ * @param delimiterType the type of delimiter - "normal" or "row".
+ */
+ public void setDelimiterType(DelimiterType delimiterType) {
+ this.delimiterType = delimiterType.getValue();
+ }
+
+ /**
+ * Print result sets from the statements;
+ * optional, default false
+ * @param print if true print result sets.
+ */
+ public void setPrint(boolean print) {
+ this.print = print;
+ }
+
+ /**
+ * Print headers for result sets from the
+ * statements; optional, default true.
+ * @param showheaders if true print headers of result sets.
+ */
+ public void setShowheaders(boolean showheaders) {
+ this.showheaders = showheaders;
+ }
+
+ /**
+ * Print trailing info (rows affected) for the SQL
+ * Addresses Bug/Request #27446
+ * @param showtrailers if true prints the SQL rows affected
+ * @since Ant 1.7
+ */
+ public void setShowtrailers(boolean showtrailers) {
+ this.showtrailers = showtrailers;
+ }
+
+ /**
+ * Set the output file;
+ * optional, defaults to the Ant log.
+ * @param output the output file to use for logging messages.
+ */
+ public void setOutput(File output) {
+ setOutput(new FileResource(getProject(), output));
+ }
+
+ /**
+ * Set the output Resource;
+ * optional, defaults to the Ant log.
+ * @param output the output Resource to store results.
+ * @since Ant 1.8
+ */
+ public void setOutput(Resource output) {
+ this.output = output;
+ }
+
+ /**
+ * The encoding to use when writing the result to a resource.
+ * <p>Default's to the platform's default encoding</p>
+ * @param outputEncoding the name of the encoding or null for the
+ * platform's default encoding
+ * @since Ant 1.9.4
+ */
+ public void setOutputEncoding(String outputEncoding) {
+ this.outputEncoding = outputEncoding;
+ }
+
+ /**
+ * whether output should be appended to or overwrite
+ * an existing file. Defaults to false.
+ *
+ * @since Ant 1.5
+ * @param append if true append to an existing file.
+ */
+ public void setAppend(boolean append) {
+ this.append = append;
+ }
+
+
+ /**
+ * Action to perform when statement fails: continue, stop, or abort
+ * optional; default &quot;abort&quot;
+ * @param action the action to perform on statement failure.
+ */
+ public void setOnerror(OnError action) {
+ this.onError = action.getValue();
+ }
+
+ /**
+ * 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 if true enable escape processing, default is true.
+ * @since Ant 1.6
+ */
+ public void setEscapeProcessing(boolean enable) {
+ escapeProcessing = enable;
+ }
+
+ /**
+ * Set whether to print raw BLOBs rather than their string (hex) representations.
+ * @param rawBlobs whether to print raw BLOBs.
+ * @since Ant 1.7.1
+ */
+ public void setRawBlobs(boolean rawBlobs) {
+ this.rawBlobs = rawBlobs;
+ }
+
+ /**
+ * If false, delimiters will be searched for in a case-insensitive
+ * manner (i.e. delimiter="go" matches "GO") and surrounding
+ * whitespace will be ignored (delimiter="go" matches "GO ").
+ * @since Ant 1.8.0
+ */
+ public void setStrictDelimiterMatching(boolean b) {
+ strictDelimiterMatching = b;
+ }
+
+ /**
+ * whether to show SQLWarnings as WARN messages.
+ * @since Ant 1.8.0
+ */
+ public void setShowWarnings(boolean b) {
+ showWarnings = b;
+ }
+
+ /**
+ * Whether a warning is an error - in which case onError applies.
+ * @since Ant 1.8.0
+ */
+ public void setTreatWarningsAsErrors(boolean b) {
+ treatWarningsAsErrors = b;
+ }
+
+ /**
+ * The column separator used when printing the results.
+ *
+ * <p>Defaults to ","</p>
+ *
+ * @since Ant 1.8.0
+ */
+ public void setCsvColumnSeparator(String s) {
+ csvColumnSep = s;
+ }
+
+ /**
+ * The character used to quote column values.
+ *
+ * <p>If set, columns that contain either the column separator or
+ * the quote character itself will be surrounded by the quote
+ * character. The quote character itself will be doubled if it
+ * appears inside of the column's value.</p>
+ *
+ * <p>If this value is not set (the default), no column values
+ * will be quoted, not even if they contain the column
+ * separator.</p>
+ *
+ * <p><b>Note:</b> BLOB values will never be quoted.</p>
+ *
+ * <p>Defaults to "not set"</p>
+ *
+ * @since Ant 1.8.0
+ */
+ public void setCsvQuoteCharacter(String s) {
+ if (s != null && s.length() > 1) {
+ throw new BuildException("The quote character must be a single"
+ + " character.");
+ }
+ csvQuoteChar = s;
+ }
+
+ /**
+ * Property to set to "true" if a statement throws an error.
+ *
+ * @param errorProperty the name of the property to set in the
+ * event of an error.
+ * @since Ant 1.8.0
+ */
+ public void setErrorProperty(String errorProperty) {
+ this.errorProperty = errorProperty;
+ }
+
+ /**
+ * Property to set to "true" if a statement produces a warning.
+ *
+ * @param warningProperty the name of the property to set in the
+ * event of a warning.
+ * @since Ant 1.8.0
+ */
+ public void setWarningProperty(String warningProperty) {
+ this.warningProperty = warningProperty;
+ }
+
+ /**
+ * Sets a given property to the number of rows in the first
+ * statement that returned a row count.
+ * @since Ant 1.8.0
+ */
+ public void setRowCountProperty(String rowCountProperty) {
+ this.rowCountProperty = rowCountProperty;
+ }
+
+ /**
+ * Load the sql file and then execute it
+ * @throws BuildException on error.
+ */
+ @Override
+ public void execute() throws BuildException {
+ Vector savedTransaction = (Vector) transactions.clone();
+ String savedSqlCommand = sqlCommand;
+
+ sqlCommand = sqlCommand.trim();
+
+ try {
+ if (srcFile == null && sqlCommand.length() == 0 && resources == null) {
+ if (transactions.size() == 0) {
+ throw new BuildException("Source file or resource collection, "
+ + "transactions or sql statement "
+ + "must be set!", getLocation());
+ }
+ }
+
+ if (srcFile != null && !srcFile.isFile()) {
+ throw new BuildException("Source file " + srcFile
+ + " is not a file!", getLocation());
+ }
+
+ if (resources != null) {
+ // deal with the resources
+ for (Resource r : resources) {
+ // Make a transaction for each resource
+ Transaction t = createTransaction();
+ t.setSrcResource(r);
+ }
+ }
+
+ // Make a transaction group for the outer command
+ Transaction t = createTransaction();
+ t.setSrc(srcFile);
+ t.addText(sqlCommand);
+
+ if (getConnection() == null) {
+ // not a valid rdbms
+ return;
+ }
+
+ try {
+ PrintStream out = KeepAliveOutputStream.wrapSystemOut();
+ try {
+ if (output != null) {
+ log("Opening PrintStream to output Resource " + output, Project.MSG_VERBOSE);
+ OutputStream os = null;
+ FileProvider fp =
+ output.as(FileProvider.class);
+ if (fp != null) {
+ os = new FileOutputStream(fp.getFile(), append);
+ } else {
+ if (append) {
+ Appendable a =
+ output.as(Appendable.class);
+ if (a != null) {
+ os = a.getAppendOutputStream();
+ }
+ }
+ if (os == null) {
+ os = output.getOutputStream();
+ if (append) {
+ log("Ignoring append=true for non-appendable"
+ + " resource " + output,
+ Project.MSG_WARN);
+ }
+ }
+ }
+ if (outputEncoding != null) {
+ out = new PrintStream(new BufferedOutputStream(os),
+ false, outputEncoding);
+ } else {
+ out = new PrintStream(new BufferedOutputStream(os));
+ }
+ }
+
+ // Process all transactions
+ for (Enumeration e = transactions.elements();
+ e.hasMoreElements();) {
+
+ ((Transaction) e.nextElement()).runTransaction(out);
+ if (!isAutocommit()) {
+ log("Committing transaction", Project.MSG_VERBOSE);
+ getConnection().commit();
+ }
+ }
+ } finally {
+ FileUtils.close(out);
+ }
+ } catch (IOException e) {
+ closeQuietly();
+ setErrorProperty();
+ if (onError.equals("abort")) {
+ throw new BuildException(e, getLocation());
+ }
+ } catch (SQLException e) {
+ closeQuietly();
+ setErrorProperty();
+ if (onError.equals("abort")) {
+ throw new BuildException(e, getLocation());
+ }
+ } finally {
+ try {
+ if (getStatement() != null) {
+ getStatement().close();
+ }
+ } catch (SQLException ex) {
+ // ignore
+ }
+ try {
+ if (getConnection() != null) {
+ getConnection().close();
+ }
+ } catch (SQLException ex) {
+ // ignore
+ }
+ }
+
+ log(goodSql + " of " + totalSql + " SQL statements executed successfully");
+ } finally {
+ transactions = savedTransaction;
+ sqlCommand = savedSqlCommand;
+ }
+ }
+
+ /**
+ * read in lines and execute them
+ * @param reader the reader contains sql lines.
+ * @param out the place to output results.
+ * @throws SQLException on sql problems
+ * @throws IOException on io problems
+ */
+ protected void runStatements(Reader reader, PrintStream out)
+ throws SQLException, IOException {
+ StringBuffer sql = new StringBuffer();
+ String line;
+
+ BufferedReader in = new BufferedReader(reader);
+
+ while ((line = in.readLine()) != null) {
+ if (!keepformat) {
+ line = line.trim();
+ }
+ if (expandProperties) {
+ line = getProject().replaceProperties(line);
+ }
+ 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;
+ }
+ }
+ }
+
+ sql.append(keepformat ? "\n" : " ").append(line);
+
+ // SQL defines "--" as a comment to EOL
+ // and in Oracle it may contain a hint
+ // so we cannot just remove it, instead we must end it
+ if (!keepformat && line.indexOf("--") >= 0) {
+ sql.append("\n");
+ }
+ int lastDelimPos = lastDelimiterPosition(sql, line);
+ if (lastDelimPos > -1) {
+ execSQL(sql.substring(0, lastDelimPos), out);
+ sql.replace(0, sql.length(), "");
+ }
+ }
+ // Catch any statements not followed by ;
+ if (sql.length() > 0) {
+ execSQL(sql.toString(), out);
+ }
+ }
+
+ /**
+ * Exec the sql statement.
+ * @param sql the SQL statement to execute
+ * @param out the place to put output
+ * @throws SQLException on SQL problems
+ */
+ protected void execSQL(String sql, PrintStream out) throws SQLException {
+ // Check and ignore empty statements
+ if ("".equals(sql.trim())) {
+ return;
+ }
+
+ ResultSet resultSet = null;
+ try {
+ totalSql++;
+ log("SQL: " + sql, Project.MSG_VERBOSE);
+
+ boolean ret;
+ int updateCount = 0, updateCountTotal = 0;
+
+ ret = getStatement().execute(sql);
+ updateCount = getStatement().getUpdateCount();
+ do {
+ if (updateCount != -1) {
+ updateCountTotal += updateCount;
+ }
+ if (ret) {
+ resultSet = getStatement().getResultSet();
+ printWarnings(resultSet.getWarnings(), false);
+ resultSet.clearWarnings();
+ if (print) {
+ printResults(resultSet, out);
+ }
+ }
+ ret = getStatement().getMoreResults();
+ updateCount = getStatement().getUpdateCount();
+ } while (ret || updateCount != -1);
+
+ printWarnings(getStatement().getWarnings(), false);
+ getStatement().clearWarnings();
+
+ log(updateCountTotal + " rows affected", Project.MSG_VERBOSE);
+ if (updateCountTotal != -1) {
+ setRowCountProperty(updateCountTotal);
+ }
+
+ if (print && showtrailers) {
+ out.println(updateCountTotal + " rows affected");
+ }
+ SQLWarning warning = getConnection().getWarnings();
+ printWarnings(warning, true);
+ getConnection().clearWarnings();
+ goodSql++;
+ } catch (SQLException e) {
+ log("Failed to execute: " + sql, Project.MSG_ERR);
+ setErrorProperty();
+ if (!onError.equals("abort")) {
+ log(e.toString(), Project.MSG_ERR);
+ }
+ if (!onError.equals("continue")) {
+ throw e;
+ }
+ } finally {
+ if (resultSet != null) {
+ try {
+ resultSet.close();
+ } catch (SQLException e) {
+ //ignore
+ }
+ }
+ }
+ }
+
+ /**
+ * print any results in the statement
+ * @deprecated since 1.6.x.
+ * Use {@link #printResults(java.sql.ResultSet, java.io.PrintStream)
+ * the two arg version} instead.
+ * @param out the place to print results
+ * @throws SQLException on SQL problems.
+ */
+ @Deprecated
+ protected void printResults(PrintStream out) throws SQLException {
+ ResultSet rs = getStatement().getResultSet();
+ try {
+ printResults(rs, out);
+ } finally {
+ if (rs != null) {
+ rs.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.
+ * @since Ant 1.6.3
+ */
+ protected void printResults(ResultSet rs, PrintStream out) throws SQLException {
+ if (rs != null) {
+ log("Processing new result set.", Project.MSG_VERBOSE);
+ ResultSetMetaData md = rs.getMetaData();
+ int columnCount = md.getColumnCount();
+ if (columnCount > 0) {
+ if (showheaders) {
+ out.print(md.getColumnName(1));
+ for (int col = 2; col <= columnCount; col++) {
+ out.print(csvColumnSep);
+ out.print(maybeQuote(md.getColumnName(col)));
+ }
+ out.println();
+ }
+ while (rs.next()) {
+ printValue(rs, 1, out);
+ for (int col = 2; col <= columnCount; col++) {
+ out.print(csvColumnSep);
+ printValue(rs, col, out);
+ }
+ out.println();
+ printWarnings(rs.getWarnings(), false);
+ }
+ }
+ }
+ out.println();
+ }
+
+ private void printValue(ResultSet rs, int col, PrintStream out)
+ throws SQLException {
+ if (rawBlobs && rs.getMetaData().getColumnType(col) == Types.BLOB) {
+ Blob blob = rs.getBlob(col);
+ if (blob != null) {
+ new StreamPumper(rs.getBlob(col).getBinaryStream(), out).run();
+ }
+ } else {
+ out.print(maybeQuote(rs.getString(col)));
+ }
+ }
+
+ private String maybeQuote(String s) {
+ if (csvQuoteChar == null || s == null
+ || (s.indexOf(csvColumnSep) == -1 && s.indexOf(csvQuoteChar) == -1)
+ ) {
+ return s;
+ }
+ StringBuffer sb = new StringBuffer(csvQuoteChar);
+ int len = s.length();
+ char q = csvQuoteChar.charAt(0);
+ for (int i = 0; i < len; i++) {
+ char c = s.charAt(i);
+ if (c == q) {
+ sb.append(q);
+ }
+ sb.append(c);
+ }
+ return sb.append(csvQuoteChar).toString();
+ }
+
+ /*
+ * Closes an unused connection after an error and doesn't rethrow
+ * a possible SQLException
+ * @since Ant 1.7
+ */
+ private void closeQuietly() {
+ if (!isAutocommit() && getConnection() != null && onError.equals("abort")) {
+ try {
+ getConnection().rollback();
+ } catch (SQLException ex) {
+ // ignore
+ }
+ }
+ }
+
+
+ /**
+ * Caches the connection returned by the base class's getConnection method.
+ *
+ * <p>Subclasses that need to provide a different connection than
+ * the base class would, should override this method but keep in
+ * mind that this class expects to get the same connection
+ * instance on consecutive calls.</p>
+ *
+ * <p>returns null if the connection does not connect to the
+ * expected RDBMS.</p>
+ */
+ @Override
+ protected Connection getConnection() {
+ if (conn == null) {
+ conn = super.getConnection();
+ if (!isValidRdbms(conn)) {
+ conn = null;
+ }
+ }
+ return conn;
+ }
+
+ /**
+ * Creates and configures a Statement instance which is then
+ * cached for subsequent calls.
+ *
+ * <p>Subclasses that want to provide different Statement
+ * instances, should override this method but keep in mind that
+ * this class expects to get the same connection instance on
+ * consecutive calls.</p>
+ */
+ protected Statement getStatement() throws SQLException {
+ if (statement == null) {
+ statement = getConnection().createStatement();
+ statement.setEscapeProcessing(escapeProcessing);
+ }
+
+ return statement;
+ }
+
+ /**
+ * The action a task should perform on an error,
+ * one of "continue", "stop" and "abort"
+ */
+ public static class OnError extends EnumeratedAttribute {
+ /** @return the enumerated values */
+ @Override
+ public String[] getValues() {
+ return new String[] {"continue", "stop", "abort"};
+ }
+ }
+
+ /**
+ * 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.
+ */
+ public class Transaction {
+ private Resource tSrcResource = null;
+ private String tSqlCommand = "";
+
+ /**
+ * Set the source file attribute.
+ * @param src the source file
+ */
+ public void setSrc(File src) {
+ //there are places (in this file, and perhaps elsewhere, where it is assumed
+ //that null is an acceptable parameter.
+ if (src != null) {
+ setSrcResource(new FileResource(src));
+ }
+ }
+
+ /**
+ * Set the source resource attribute.
+ * @param src the source file
+ * @since Ant 1.7
+ */
+ public void setSrcResource(Resource src) {
+ if (tSrcResource != null) {
+ throw new BuildException("only one resource per transaction");
+ }
+ tSrcResource = src;
+ }
+
+ /**
+ * Set inline text
+ * @param sql the inline text
+ */
+ public void addText(String sql) {
+ if (sql != null) {
+ this.tSqlCommand += sql;
+ }
+ }
+
+ /**
+ * Set the source resource.
+ * @param a the source resource collection.
+ * @since Ant 1.7
+ */
+ public void addConfigured(ResourceCollection a) {
+ if (a.size() != 1) {
+ throw new BuildException("only single argument resource "
+ + "collections are supported.");
+ }
+ setSrcResource(a.iterator().next());
+ }
+
+ /**
+ *
+ */
+ private void runTransaction(PrintStream out)
+ throws IOException, SQLException {
+ if (tSqlCommand.length() != 0) {
+ log("Executing commands", Project.MSG_INFO);
+ runStatements(new StringReader(tSqlCommand), out);
+ }
+
+ if (tSrcResource != null) {
+ log("Executing resource: " + tSrcResource.toString(),
+ Project.MSG_INFO);
+ InputStream is = null;
+ Reader reader = null;
+ try {
+ is = tSrcResource.getInputStream();
+ reader = (encoding == null) ? new InputStreamReader(is)
+ : new InputStreamReader(is, encoding);
+ runStatements(reader, out);
+ } finally {
+ FileUtils.close(is);
+ FileUtils.close(reader);
+ }
+ }
+ }
+ }
+
+ public int lastDelimiterPosition(StringBuffer buf, String currentLine) {
+ if (strictDelimiterMatching) {
+ if ((delimiterType.equals(DelimiterType.NORMAL)
+ && StringUtils.endsWith(buf, delimiter)) ||
+ (delimiterType.equals(DelimiterType.ROW)
+ && currentLine.equals(delimiter))) {
+ return buf.length() - delimiter.length();
+ }
+ // no match
+ return -1;
+ } else {
+ String d = delimiter.trim().toLowerCase(Locale.ENGLISH);
+ if (delimiterType.equals(DelimiterType.NORMAL)) {
+ // still trying to avoid wasteful copying, see
+ // StringUtils.endsWith
+ int endIndex = delimiter.length() - 1;
+ int bufferIndex = buf.length() - 1;
+ while (bufferIndex >= 0
+ && Character.isWhitespace(buf.charAt(bufferIndex))) {
+ --bufferIndex;
+ }
+ if (bufferIndex < endIndex) {
+ return -1;
+ }
+ while (endIndex >= 0) {
+ if (buf.substring(bufferIndex, bufferIndex + 1)
+ .toLowerCase(Locale.ENGLISH).charAt(0)
+ != d.charAt(endIndex)) {
+ return -1;
+ }
+ bufferIndex--;
+ endIndex--;
+ }
+ return bufferIndex + 1;
+ } else {
+ return currentLine.trim().toLowerCase(Locale.ENGLISH).equals(d)
+ ? buf.length() - currentLine.length() : -1;
+ }
+ }
+ }
+
+ private void printWarnings(SQLWarning warning, boolean force)
+ throws SQLException {
+ SQLWarning initialWarning = warning;
+ if (showWarnings || force) {
+ while (warning != null) {
+ log(warning + " sql warning",
+ showWarnings ? Project.MSG_WARN : Project.MSG_VERBOSE);
+ warning = warning.getNextWarning();
+ }
+ }
+ if (initialWarning != null) {
+ setWarningProperty();
+ }
+ if (treatWarningsAsErrors && initialWarning != null) {
+ throw initialWarning;
+ }
+ }
+
+ protected final void setErrorProperty() {
+ setProperty(errorProperty, "true");
+ }
+
+ protected final void setWarningProperty() {
+ setProperty(warningProperty, "true");
+ }
+
+ protected final void setRowCountProperty(int rowCount) {
+ setProperty(rowCountProperty, Integer.toString(rowCount));
+ }
+
+ private void setProperty(String name, String value) {
+ if (name != null) {
+ getProject().setNewProperty(name, value);
+ }
+ }
+}