This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-dbutils.git
The following commit(s) were added to refs/heads/master by this push: new d8b498b Javadoc @link tags do not need to use a FQCN for classes in java.lang d8b498b is described below commit d8b498b9136513e42c9efd6d04eac85f5531e2cb Author: Gary Gregory <garydgreg...@gmail.com> AuthorDate: Mon Aug 29 07:35:54 2022 -0400 Javadoc @link tags do not need to use a FQCN for classes in java.lang --- .../org/apache/commons/dbutils/QueryRunner.java | 2000 ++++++++++---------- 1 file changed, 1000 insertions(+), 1000 deletions(-) diff --git a/src/main/java/org/apache/commons/dbutils/QueryRunner.java b/src/main/java/org/apache/commons/dbutils/QueryRunner.java index 13fd124..6a1aee1 100644 --- a/src/main/java/org/apache/commons/dbutils/QueryRunner.java +++ b/src/main/java/org/apache/commons/dbutils/QueryRunner.java @@ -1,1000 +1,1000 @@ -/* - * 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.commons.dbutils; - -import java.sql.CallableStatement; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.LinkedList; -import java.util.List; -import javax.sql.DataSource; - -/** - * Executes SQL queries with pluggable strategies for handling - * {@code ResultSet}s. This class is thread safe. - * - * @see ResultSetHandler - */ -public class QueryRunner extends AbstractQueryRunner { - - /** - * Constructor for QueryRunner. - */ - public QueryRunner() { - } - - /** - * Constructor for QueryRunner that controls the use of {@code ParameterMetaData}. - * - * @param pmdKnownBroken Some drivers don't support {@link java.sql.ParameterMetaData#getParameterType(int) }; - * if {@code pmdKnownBroken} is set to true, we won't even try it; if false, we'll try it, - * and if it breaks, we'll remember not to use it again. - */ - public QueryRunner(final boolean pmdKnownBroken) { - super(pmdKnownBroken); - } - - /** - * Constructor for QueryRunner that takes a {@code DataSource} to use. - * - * Methods that do not take a {@code Connection} parameter will retrieve connections from this - * {@code DataSource}. - * - * @param ds The {@code DataSource} to retrieve connections from. - */ - public QueryRunner(final DataSource ds) { - super(ds); - } - - /** - * Constructor for QueryRunner that takes a {@code StatementConfiguration} to configure statements when - * preparing them. - * - * @param stmtConfig The configuration to apply to statements when they are prepared. - */ - public QueryRunner(final StatementConfiguration stmtConfig) { - super(stmtConfig); - } - - /** - * Constructor for QueryRunner that takes a {@code DataSource} and controls the use of {@code ParameterMetaData}. - * Methods that do not take a {@code Connection} parameter will retrieve connections from this - * {@code DataSource}. - * - * @param ds The {@code DataSource} to retrieve connections from. - * @param pmdKnownBroken Some drivers don't support {@link java.sql.ParameterMetaData#getParameterType(int) }; - * if {@code pmdKnownBroken} is set to true, we won't even try it; if false, we'll try it, - * and if it breaks, we'll remember not to use it again. - */ - public QueryRunner(final DataSource ds, final boolean pmdKnownBroken) { - super(ds, pmdKnownBroken); - } - - /** - * Constructor for QueryRunner that takes a {@code DataSource} to use and a {@code StatementConfiguration}. - * - * Methods that do not take a {@code Connection} parameter will retrieve connections from this - * {@code DataSource}. - * - * @param ds The {@code DataSource} to retrieve connections from. - * @param stmtConfig The configuration to apply to statements when they are prepared. - */ - public QueryRunner(final DataSource ds, final StatementConfiguration stmtConfig) { - super(ds, stmtConfig); - } - - /** - * Constructor for QueryRunner that takes a {@code DataSource}, a {@code StatementConfiguration}, and - * controls the use of {@code ParameterMetaData}. Methods that do not take a {@code Connection} parameter - * will retrieve connections from this {@code DataSource}. - * - * @param ds The {@code DataSource} to retrieve connections from. - * @param pmdKnownBroken Some drivers don't support {@link java.sql.ParameterMetaData#getParameterType(int) }; - * if {@code pmdKnownBroken} is set to true, we won't even try it; if false, we'll try it, - * and if it breaks, we'll remember not to use it again. - * @param stmtConfig The configuration to apply to statements when they are prepared. - */ - public QueryRunner(final DataSource ds, final boolean pmdKnownBroken, final StatementConfiguration stmtConfig) { - super(ds, pmdKnownBroken, stmtConfig); - } - - /** - * Execute a batch of SQL INSERT, UPDATE, or DELETE queries. - * - * @param conn The Connection to use to run the query. The caller is - * responsible for closing this Connection. - * @param sql The SQL to execute. - * @param params An array of query replacement parameters. Each row in - * this array is one set of batch replacement values. - * @return The number of rows updated per statement. - * @throws SQLException if a database access error occurs - * @since DbUtils 1.1 - */ - public int[] batch(final Connection conn, final String sql, final Object[][] params) throws SQLException { - return this.batch(conn, false, sql, params); - } - - /** - * Execute a batch of SQL INSERT, UPDATE, or DELETE queries. The - * {@code Connection} is retrieved from the {@code DataSource} - * set in the constructor. This {@code Connection} must be in - * auto-commit mode or the update will not be saved. - * - * @param sql The SQL to execute. - * @param params An array of query replacement parameters. Each row in - * this array is one set of batch replacement values. - * @return The number of rows updated per statement. - * @throws SQLException if a database access error occurs - * @since DbUtils 1.1 - */ - public int[] batch(final String sql, final Object[][] params) throws SQLException { - final Connection conn = this.prepareConnection(); - - return this.batch(conn, true, sql, params); - } - - /** - * Calls update after checking the parameters to ensure nothing is null. - * @param conn The connection to use for the batch call. - * @param closeConn True if the connection should be closed, false otherwise. - * @param sql The SQL statement to execute. - * @param params An array of query replacement parameters. Each row in - * this array is one set of batch replacement values. - * @return The number of rows updated in the batch. - * @throws SQLException If there are database or parameter errors. - */ - private int[] batch(final Connection conn, final boolean closeConn, final String sql, final Object[][] params) throws SQLException { - if (conn == null) { - throw new SQLException("Null connection"); - } - - if (sql == null) { - if (closeConn) { - close(conn); - } - throw new SQLException("Null SQL statement"); - } - - if (params == null) { - if (closeConn) { - close(conn); - } - throw new SQLException("Null parameters. If parameters aren't need, pass an empty array."); - } - - PreparedStatement stmt = null; - int[] rows = null; - try { - stmt = this.prepareStatement(conn, sql); - - for (final Object[] param : params) { - this.fillStatement(stmt, param); - stmt.addBatch(); - } - rows = stmt.executeBatch(); - - } catch (final SQLException e) { - this.rethrow(e, sql, (Object[])params); - } finally { - close(stmt); - if (closeConn) { - close(conn); - } - } - - return rows; - } - - /** - * Execute an SQL SELECT query with a single replacement parameter. The - * caller is responsible for closing the connection. - * @param <T> The type of object that the handler returns - * @param conn The connection to execute the query in. - * @param sql The query to execute. - * @param param The replacement parameter. - * @param rsh The handler that converts the results into an object. - * @return The object returned by the handler. - * @throws SQLException if a database access error occurs - * @deprecated Use {@link #query(Connection, String, ResultSetHandler, Object...)} - */ - @Deprecated - public <T> T query(final Connection conn, final String sql, final Object param, final ResultSetHandler<T> rsh) throws SQLException { - return this.<T>query(conn, false, sql, rsh, param); - } - - /** - * Execute an SQL SELECT query with replacement parameters. The - * caller is responsible for closing the connection. - * @param <T> The type of object that the handler returns - * @param conn The connection to execute the query in. - * @param sql The query to execute. - * @param params The replacement parameters. - * @param rsh The handler that converts the results into an object. - * @return The object returned by the handler. - * @throws SQLException if a database access error occurs - * @deprecated Use {@link #query(Connection,String,ResultSetHandler,Object...)} instead - */ - @Deprecated - public <T> T query(final Connection conn, final String sql, final Object[] params, final ResultSetHandler<T> rsh) throws SQLException { - return this.<T>query(conn, false, sql, rsh, params); - } - - /** - * Execute an SQL SELECT query with replacement parameters. The - * caller is responsible for closing the connection. - * @param <T> The type of object that the handler returns - * @param conn The connection to execute the query in. - * @param sql The query to execute. - * @param rsh The handler that converts the results into an object. - * @param params The replacement parameters. - * @return The object returned by the handler. - * @throws SQLException if a database access error occurs - */ - public <T> T query(final Connection conn, final String sql, final ResultSetHandler<T> rsh, final Object... params) throws SQLException { - return this.<T>query(conn, false, sql, rsh, params); - } - - /** - * Execute an SQL SELECT query without any replacement parameters. The - * caller is responsible for closing the connection. - * @param <T> The type of object that the handler returns - * @param conn The connection to execute the query in. - * @param sql The query to execute. - * @param rsh The handler that converts the results into an object. - * @return The object returned by the handler. - * @throws SQLException if a database access error occurs - */ - public <T> T query(final Connection conn, final String sql, final ResultSetHandler<T> rsh) throws SQLException { - return this.<T>query(conn, false, sql, rsh, (Object[]) null); - } - - /** - * Executes the given SELECT SQL with a single replacement parameter. - * The {@code Connection} is retrieved from the - * {@code DataSource} set in the constructor. - * @param <T> The type of object that the handler returns - * @param sql The SQL statement to execute. - * @param param The replacement parameter. - * @param rsh The handler used to create the result object from - * the {@code ResultSet}. - * - * @return An object generated by the handler. - * @throws SQLException if a database access error occurs - * @deprecated Use {@link #query(String, ResultSetHandler, Object...)} - */ - @Deprecated - public <T> T query(final String sql, final Object param, final ResultSetHandler<T> rsh) throws SQLException { - final Connection conn = this.prepareConnection(); - - return this.<T>query(conn, true, sql, rsh, param); - } - - /** - * Executes the given SELECT SQL query and returns a result object. - * The {@code Connection} is retrieved from the - * {@code DataSource} set in the constructor. - * @param <T> The type of object that the handler returns - * @param sql The SQL statement to execute. - * @param params Initialize the PreparedStatement's IN parameters with - * this array. - * - * @param rsh The handler used to create the result object from - * the {@code ResultSet}. - * - * @return An object generated by the handler. - * @throws SQLException if a database access error occurs - * @deprecated Use {@link #query(String, ResultSetHandler, Object...)} - */ - @Deprecated - public <T> T query(final String sql, final Object[] params, final ResultSetHandler<T> rsh) throws SQLException { - final Connection conn = this.prepareConnection(); - - return this.<T>query(conn, true, sql, rsh, params); - } - - /** - * Executes the given SELECT SQL query and returns a result object. - * The {@code Connection} is retrieved from the - * {@code DataSource} set in the constructor. - * @param <T> The type of object that the handler returns - * @param sql The SQL statement to execute. - * @param rsh The handler used to create the result object from - * the {@code ResultSet}. - * @param params Initialize the PreparedStatement's IN parameters with - * this array. - * @return An object generated by the handler. - * @throws SQLException if a database access error occurs - */ - public <T> T query(final String sql, final ResultSetHandler<T> rsh, final Object... params) throws SQLException { - final Connection conn = this.prepareConnection(); - - return this.<T>query(conn, true, sql, rsh, params); - } - - /** - * Executes the given SELECT SQL without any replacement parameters. - * The {@code Connection} is retrieved from the - * {@code DataSource} set in the constructor. - * @param <T> The type of object that the handler returns - * @param sql The SQL statement to execute. - * @param rsh The handler used to create the result object from - * the {@code ResultSet}. - * - * @return An object generated by the handler. - * @throws SQLException if a database access error occurs - */ - public <T> T query(final String sql, final ResultSetHandler<T> rsh) throws SQLException { - final Connection conn = this.prepareConnection(); - - return this.<T>query(conn, true, sql, rsh, (Object[]) null); - } - - /** - * Calls query after checking the parameters to ensure nothing is null. - * @param conn The connection to use for the query call. - * @param closeConn True if the connection should be closed, false otherwise. - * @param sql The SQL statement to execute. - * @param params An array of query replacement parameters. Each row in - * this array is one set of batch replacement values. - * @return The results of the query. - * @throws SQLException If there are database or parameter errors. - */ - private <T> T query(final Connection conn, final boolean closeConn, final String sql, final ResultSetHandler<T> rsh, final Object... params) - throws SQLException { - if (conn == null) { - throw new SQLException("Null connection"); - } - - if (sql == null) { - if (closeConn) { - close(conn); - } - throw new SQLException("Null SQL statement"); - } - - if (rsh == null) { - if (closeConn) { - close(conn); - } - throw new SQLException("Null ResultSetHandler"); - } - - Statement stmt = null; - ResultSet rs = null; - T result = null; - - try { - if (params != null && params.length > 0) { - final PreparedStatement ps = this.prepareStatement(conn, sql); - stmt = ps; - this.fillStatement(ps, params); - rs = this.wrap(ps.executeQuery()); - } else { - stmt = conn.createStatement(); - rs = this.wrap(stmt.executeQuery(sql)); - } - result = rsh.handle(rs); - - } catch (final SQLException e) { - this.rethrow(e, sql, params); - - } finally { - closeQuietly(rs); - closeQuietly(stmt); - if (closeConn) { - close(conn); - } - } - - return result; - } - - /** - * Execute an SQL INSERT, UPDATE, or DELETE query without replacement - * parameters. - * - * @param conn The connection to use to run the query. - * @param sql The SQL to execute. - * @return The number of rows updated. - * @throws SQLException if a database access error occurs - */ - public int update(final Connection conn, final String sql) throws SQLException { - return this.update(conn, false, sql, (Object[]) null); - } - - /** - * Execute an SQL INSERT, UPDATE, or DELETE query with a single replacement - * parameter. - * - * @param conn The connection to use to run the query. - * @param sql The SQL to execute. - * @param param The replacement parameter. - * @return The number of rows updated. - * @throws SQLException if a database access error occurs - */ - public int update(final Connection conn, final String sql, final Object param) throws SQLException { - return this.update(conn, false, sql, param); - } - - /** - * Execute an SQL INSERT, UPDATE, or DELETE query. - * - * @param conn The connection to use to run the query. - * @param sql The SQL to execute. - * @param params The query replacement parameters. - * @return The number of rows updated. - * @throws SQLException if a database access error occurs - */ - public int update(final Connection conn, final String sql, final Object... params) throws SQLException { - return update(conn, false, sql, params); - } - - /** - * Executes the given INSERT, UPDATE, or DELETE SQL statement without - * any replacement parameters. The {@code Connection} is retrieved - * from the {@code DataSource} set in the constructor. This - * {@code Connection} must be in auto-commit mode or the update will - * not be saved. - * - * @param sql The SQL statement to execute. - * @throws SQLException if a database access error occurs - * @return The number of rows updated. - */ - public int update(final String sql) throws SQLException { - final Connection conn = this.prepareConnection(); - - return this.update(conn, true, sql, (Object[]) null); - } - - /** - * Executes the given INSERT, UPDATE, or DELETE SQL statement with - * a single replacement parameter. The {@code Connection} is - * retrieved from the {@code DataSource} set in the constructor. - * This {@code Connection} must be in auto-commit mode or the - * update will not be saved. - * - * @param sql The SQL statement to execute. - * @param param The replacement parameter. - * @throws SQLException if a database access error occurs - * @return The number of rows updated. - */ - public int update(final String sql, final Object param) throws SQLException { - final Connection conn = this.prepareConnection(); - - return this.update(conn, true, sql, param); - } - - /** - * Executes the given INSERT, UPDATE, or DELETE SQL statement. The - * {@code Connection} is retrieved from the {@code DataSource} - * set in the constructor. This {@code Connection} must be in - * auto-commit mode or the update will not be saved. - * - * @param sql The SQL statement to execute. - * @param params Initializes the PreparedStatement's IN (i.e. '?') - * parameters. - * @throws SQLException if a database access error occurs - * @return The number of rows updated. - */ - public int update(final String sql, final Object... params) throws SQLException { - final Connection conn = this.prepareConnection(); - - return this.update(conn, true, sql, params); - } - - /** - * Calls update after checking the parameters to ensure nothing is null. - * @param conn The connection to use for the update call. - * @param closeConn True if the connection should be closed, false otherwise. - * @param sql The SQL statement to execute. - * @param params An array of update replacement parameters. Each row in - * this array is one set of update replacement values. - * @return The number of rows updated. - * @throws SQLException If there are database or parameter errors. - */ - private int update(final Connection conn, final boolean closeConn, final String sql, final Object... params) throws SQLException { - if (conn == null) { - throw new SQLException("Null connection"); - } - - if (sql == null) { - if (closeConn) { - close(conn); - } - throw new SQLException("Null SQL statement"); - } - - Statement stmt = null; - int rows = 0; - - try { - if (params != null && params.length > 0) { - final PreparedStatement ps = this.prepareStatement(conn, sql); - stmt = ps; - this.fillStatement(ps, params); - rows = ps.executeUpdate(); - } else { - stmt = conn.createStatement(); - rows = stmt.executeUpdate(sql); - } - - } catch (final SQLException e) { - this.rethrow(e, sql, params); - - } finally { - close(stmt); - if (closeConn) { - close(conn); - } - } - - return rows; - } - - /** - * Executes the given INSERT SQL without any replacement parameters. - * The {@code Connection} is retrieved from the - * {@code DataSource} set in the constructor. - * @param <T> The type of object that the handler returns - * @param sql The SQL statement to execute. - * @param rsh The handler used to create the result object from - * the {@code ResultSet} of auto-generated keys. - * @return An object generated by the handler. - * @throws SQLException if a database access error occurs - * @since 1.6 - */ - public <T> T insert(final String sql, final ResultSetHandler<T> rsh) throws SQLException { - return insert(this.prepareConnection(), true, sql, rsh, (Object[]) null); - } - - /** - * Executes the given INSERT SQL statement. The - * {@code Connection} is retrieved from the {@code DataSource} - * set in the constructor. This {@code Connection} must be in - * auto-commit mode or the insert will not be saved. - * @param <T> The type of object that the handler returns - * @param sql The SQL statement to execute. - * @param rsh The handler used to create the result object from - * the {@code ResultSet} of auto-generated keys. - * @param params Initializes the PreparedStatement's IN (i.e. '?') - * @return An object generated by the handler. - * @throws SQLException if a database access error occurs - * @since 1.6 - */ - public <T> T insert(final String sql, final ResultSetHandler<T> rsh, final Object... params) throws SQLException { - return insert(this.prepareConnection(), true, sql, rsh, params); - } - - /** - * Execute an SQL INSERT query without replacement parameters. - * @param <T> The type of object that the handler returns - * @param conn The connection to use to run the query. - * @param sql The SQL to execute. - * @param rsh The handler used to create the result object from - * the {@code ResultSet} of auto-generated keys. - * @return An object generated by the handler. - * @throws SQLException if a database access error occurs - * @since 1.6 - */ - public <T> T insert(final Connection conn, final String sql, final ResultSetHandler<T> rsh) throws SQLException { - return insert(conn, false, sql, rsh, (Object[]) null); - } - - /** - * Execute an SQL INSERT query. - * @param <T> The type of object that the handler returns - * @param conn The connection to use to run the query. - * @param sql The SQL to execute. - * @param rsh The handler used to create the result object from - * the {@code ResultSet} of auto-generated keys. - * @param params The query replacement parameters. - * @return An object generated by the handler. - * @throws SQLException if a database access error occurs - * @since 1.6 - */ - public <T> T insert(final Connection conn, final String sql, final ResultSetHandler<T> rsh, final Object... params) throws SQLException { - return insert(conn, false, sql, rsh, params); - } - - /** - * Executes the given INSERT SQL statement. - * @param conn The connection to use for the query call. - * @param closeConn True if the connection should be closed, false otherwise. - * @param sql The SQL statement to execute. - * @param rsh The handler used to create the result object from - * the {@code ResultSet} of auto-generated keys. - * @param params The query replacement parameters. - * @return An object generated by the handler. - * @throws SQLException If there are database or parameter errors. - * @since 1.6 - */ - private <T> T insert(final Connection conn, final boolean closeConn, final String sql, final ResultSetHandler<T> rsh, final Object... params) - throws SQLException { - if (conn == null) { - throw new SQLException("Null connection"); - } - - if (sql == null) { - if (closeConn) { - close(conn); - } - throw new SQLException("Null SQL statement"); - } - - if (rsh == null) { - if (closeConn) { - close(conn); - } - throw new SQLException("Null ResultSetHandler"); - } - - Statement stmt = null; - T generatedKeys = null; - - try { - if (params != null && params.length > 0) { - final PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); - stmt = ps; - this.fillStatement(ps, params); - ps.executeUpdate(); - } else { - stmt = conn.createStatement(); - stmt.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS); - } - final ResultSet resultSet = stmt.getGeneratedKeys(); - generatedKeys = rsh.handle(resultSet); - } catch (final SQLException e) { - this.rethrow(e, sql, params); - } finally { - close(stmt); - if (closeConn) { - close(conn); - } - } - - return generatedKeys; - } - - /** - * Executes the given batch of INSERT SQL statements. The - * {@code Connection} is retrieved from the {@code DataSource} - * set in the constructor. This {@code Connection} must be in - * auto-commit mode or the insert will not be saved. - * @param <T> The type of object that the handler returns - * @param sql The SQL statement to execute. - * @param rsh The handler used to create the result object from - * the {@code ResultSet} of auto-generated keys. - * @param params Initializes the PreparedStatement's IN (i.e. '?') - * @return The result generated by the handler. - * @throws SQLException if a database access error occurs - * @since 1.6 - */ - public <T> T insertBatch(final String sql, final ResultSetHandler<T> rsh, final Object[][] params) throws SQLException { - return insertBatch(this.prepareConnection(), true, sql, rsh, params); - } - - /** - * Executes the given batch of INSERT SQL statements. - * @param <T> The type of object that the handler returns - * @param conn The connection to use to run the query. - * @param sql The SQL to execute. - * @param rsh The handler used to create the result object from - * the {@code ResultSet} of auto-generated keys. - * @param params The query replacement parameters. - * @return The result generated by the handler. - * @throws SQLException if a database access error occurs - * @since 1.6 - */ - public <T> T insertBatch(final Connection conn, final String sql, final ResultSetHandler<T> rsh, final Object[][] params) throws SQLException { - return insertBatch(conn, false, sql, rsh, params); - } - - /** - * Executes the given batch of INSERT SQL statements. - * @param conn The connection to use for the query call. - * @param closeConn True if the connection should be closed, false otherwise. - * @param sql The SQL statement to execute. - * @param rsh The handler used to create the result object from - * the {@code ResultSet} of auto-generated keys. - * @param params The query replacement parameters. - * @return The result generated by the handler. - * @throws SQLException If there are database or parameter errors. - * @since 1.6 - */ - private <T> T insertBatch(final Connection conn, final boolean closeConn, final String sql, final ResultSetHandler<T> rsh, final Object[][] params) - throws SQLException { - if (conn == null) { - throw new SQLException("Null connection"); - } - - if (sql == null) { - if (closeConn) { - close(conn); - } - throw new SQLException("Null SQL statement"); - } - - if (params == null) { - if (closeConn) { - close(conn); - } - throw new SQLException("Null parameters. If parameters aren't need, pass an empty array."); - } - - PreparedStatement stmt = null; - T generatedKeys = null; - try { - stmt = this.prepareStatement(conn, sql, Statement.RETURN_GENERATED_KEYS); - - for (final Object[] param : params) { - this.fillStatement(stmt, param); - stmt.addBatch(); - } - stmt.executeBatch(); - final ResultSet rs = stmt.getGeneratedKeys(); - generatedKeys = rsh.handle(rs); - - } catch (final SQLException e) { - this.rethrow(e, sql, (Object[])params); - } finally { - close(stmt); - if (closeConn) { - close(conn); - } - } - - return generatedKeys; - } - - /** - * Execute an SQL statement, including a stored procedure call, which does - * not return any result sets. - * Any parameters which are instances of {@link OutParameter} will be - * registered as OUT parameters. - * <p> - * Use this method when invoking a stored procedure with OUT parameters - * that does not return any result sets. If you are not invoking a stored - * procedure, or the stored procedure has no OUT parameters, consider using - * {@link #update(java.sql.Connection, java.lang.String, java.lang.Object...) }. - * If the stored procedure returns result sets, use - * {@link #execute(java.sql.Connection, java.lang.String, org.apache.commons.dbutils.ResultSetHandler, java.lang.Object...) }. - * - * @param conn The connection to use to run the query. - * @param sql The SQL to execute. - * @param params The query replacement parameters. - * @return The number of rows updated. - * @throws SQLException if a database access error occurs - */ - public int execute(final Connection conn, final String sql, final Object... params) throws SQLException { - return this.execute(conn, false, sql, params); - } - - /** - * Execute an SQL statement, including a stored procedure call, which does - * not return any result sets. - * Any parameters which are instances of {@link OutParameter} will be - * registered as OUT parameters. - * <p> - * Use this method when invoking a stored procedure with OUT parameters - * that does not return any result sets. If you are not invoking a stored - * procedure, or the stored procedure has no OUT parameters, consider using - * {@link #update(java.lang.String, java.lang.Object...) }. - * If the stored procedure returns result sets, use - * {@link #execute(java.lang.String, org.apache.commons.dbutils.ResultSetHandler, java.lang.Object...) }. - * <p> - * The {@code Connection} is retrieved from the {@code DataSource} - * set in the constructor. This {@code Connection} must be in - * auto-commit mode or the update will not be saved. - * - * @param sql The SQL statement to execute. - * @param params Initializes the CallableStatement's parameters (i.e. '?'). - * @throws SQLException if a database access error occurs - * @return The number of rows updated. - */ - public int execute(final String sql, final Object... params) throws SQLException { - final Connection conn = this.prepareConnection(); - - return this.execute(conn, true, sql, params); - } - - /** - * Execute an SQL statement, including a stored procedure call, which - * returns one or more result sets. - * Any parameters which are instances of {@link OutParameter} will be - * registered as OUT parameters. - * <p> - * Use this method when: a) running SQL statements that return multiple - * result sets; b) invoking a stored procedure that return result - * sets and OUT parameters. Otherwise you may wish to use - * {@link #query(java.sql.Connection, java.lang.String, org.apache.commons.dbutils.ResultSetHandler, java.lang.Object...) } - * (if there are no OUT parameters) or - * {@link #execute(java.sql.Connection, java.lang.String, java.lang.Object...) } - * (if there are no result sets). - * - * @param <T> The type of object that the handler returns - * @param conn The connection to use to run the query. - * @param sql The SQL to execute. - * @param rsh The result set handler - * @param params The query replacement parameters. - * @return A list of objects generated by the handler - * @throws SQLException if a database access error occurs - */ - public <T> List<T> execute(final Connection conn, final String sql, final ResultSetHandler<T> rsh, final Object... params) throws SQLException { - return this.execute(conn, false, sql, rsh, params); - } - - /** - * Execute an SQL statement, including a stored procedure call, which - * returns one or more result sets. - * Any parameters which are instances of {@link OutParameter} will be - * registered as OUT parameters. - * <p> - * Use this method when: a) running SQL statements that return multiple - * result sets; b) invoking a stored procedure that return result - * sets and OUT parameters. Otherwise you may wish to use - * {@link #query(java.lang.String, org.apache.commons.dbutils.ResultSetHandler, java.lang.Object...) } - * (if there are no OUT parameters) or - * {@link #execute(java.lang.String, java.lang.Object...) } - * (if there are no result sets). - * - * @param <T> The type of object that the handler returns - * @param sql The SQL to execute. - * @param rsh The result set handler - * @param params The query replacement parameters. - * @return A list of objects generated by the handler - * @throws SQLException if a database access error occurs - */ - public <T> List<T> execute(final String sql, final ResultSetHandler<T> rsh, final Object... params) throws SQLException { - final Connection conn = this.prepareConnection(); - - return this.execute(conn, true, sql, rsh, params); - } - - /** - * Invokes the stored procedure via update after checking the parameters to - * ensure nothing is null. - * @param conn The connection to use for the update call. - * @param closeConn True if the connection should be closed, false otherwise. - * @param sql The SQL statement to execute. - * @param params An array of update replacement parameters. Each row in - * this array is one set of update replacement values. - * @return The number of rows updated. - * @throws SQLException If there are database or parameter errors. - */ - private int execute(final Connection conn, final boolean closeConn, final String sql, final Object... params) throws SQLException { - if (conn == null) { - throw new SQLException("Null connection"); - } - - if (sql == null) { - if (closeConn) { - close(conn); - } - throw new SQLException("Null SQL statement"); - } - - CallableStatement stmt = null; - int rows = 0; - - try { - stmt = this.prepareCall(conn, sql); - this.fillStatement(stmt, params); - stmt.execute(); - rows = stmt.getUpdateCount(); - this.retrieveOutParameters(stmt, params); - - } catch (final SQLException e) { - this.rethrow(e, sql, params); - - } finally { - close(stmt); - if (closeConn) { - close(conn); - } - } - - return rows; - } - - /** - * Invokes the stored procedure via update after checking the parameters to - * ensure nothing is null. - * @param conn The connection to use for the update call. - * @param closeConn True if the connection should be closed, false otherwise. - * @param sql The SQL statement to execute. - * @param rsh The result set handler - * @param params An array of update replacement parameters. Each row in - * this array is one set of update replacement values. - * @return List of all objects generated by the ResultSetHandler for all result sets handled. - * @throws SQLException If there are database or parameter errors. - */ - private <T> List<T> execute(final Connection conn, final boolean closeConn, final String sql, final ResultSetHandler<T> rsh, final Object... params) throws SQLException { - if (conn == null) { - throw new SQLException("Null connection"); - } - - if (sql == null) { - if (closeConn) { - close(conn); - } - throw new SQLException("Null SQL statement"); - } - - if (rsh == null) { - if (closeConn) { - close(conn); - } - throw new SQLException("Null ResultSetHandler"); - } - - CallableStatement stmt = null; - final List<T> results = new LinkedList<>(); - - try { - stmt = this.prepareCall(conn, sql); - this.fillStatement(stmt, params); - boolean moreResultSets = stmt.execute(); - // Handle multiple result sets by passing them through the handler - // retaining the final result - ResultSet rs = null; - while (moreResultSets) { - try { - rs = this.wrap(stmt.getResultSet()); - results.add(rsh.handle(rs)); - moreResultSets = stmt.getMoreResults(); - - } finally { - close(rs); - } - } - this.retrieveOutParameters(stmt, params); - - } catch (final SQLException e) { - this.rethrow(e, sql, params); - - } finally { - close(stmt); - if (closeConn) { - close(conn); - } - } - - return results; - } - - /** - * Set the value on all the {@link OutParameter} instances in the - * {@code params} array using the OUT parameter values from the - * {@code stmt}. - * @param stmt the statement from which to retrieve OUT parameter values - * @param params the parameter array for the statement invocation - * @throws SQLException when the value could not be retrieved from the - * statement. - */ - private void retrieveOutParameters(final CallableStatement stmt, final Object[] params) throws SQLException { - if (params != null) { - for (int i = 0; i < params.length; i++) { - if (params[i] instanceof OutParameter) { - ((OutParameter)params[i]).setValue(stmt, i + 1); - } - } - } - } -} +/* + * 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.commons.dbutils; + +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.LinkedList; +import java.util.List; +import javax.sql.DataSource; + +/** + * Executes SQL queries with pluggable strategies for handling + * {@code ResultSet}s. This class is thread safe. + * + * @see ResultSetHandler + */ +public class QueryRunner extends AbstractQueryRunner { + + /** + * Constructor for QueryRunner. + */ + public QueryRunner() { + } + + /** + * Constructor for QueryRunner that controls the use of {@code ParameterMetaData}. + * + * @param pmdKnownBroken Some drivers don't support {@link java.sql.ParameterMetaData#getParameterType(int) }; + * if {@code pmdKnownBroken} is set to true, we won't even try it; if false, we'll try it, + * and if it breaks, we'll remember not to use it again. + */ + public QueryRunner(final boolean pmdKnownBroken) { + super(pmdKnownBroken); + } + + /** + * Constructor for QueryRunner that takes a {@code DataSource} to use. + * + * Methods that do not take a {@code Connection} parameter will retrieve connections from this + * {@code DataSource}. + * + * @param ds The {@code DataSource} to retrieve connections from. + */ + public QueryRunner(final DataSource ds) { + super(ds); + } + + /** + * Constructor for QueryRunner that takes a {@code StatementConfiguration} to configure statements when + * preparing them. + * + * @param stmtConfig The configuration to apply to statements when they are prepared. + */ + public QueryRunner(final StatementConfiguration stmtConfig) { + super(stmtConfig); + } + + /** + * Constructor for QueryRunner that takes a {@code DataSource} and controls the use of {@code ParameterMetaData}. + * Methods that do not take a {@code Connection} parameter will retrieve connections from this + * {@code DataSource}. + * + * @param ds The {@code DataSource} to retrieve connections from. + * @param pmdKnownBroken Some drivers don't support {@link java.sql.ParameterMetaData#getParameterType(int) }; + * if {@code pmdKnownBroken} is set to true, we won't even try it; if false, we'll try it, + * and if it breaks, we'll remember not to use it again. + */ + public QueryRunner(final DataSource ds, final boolean pmdKnownBroken) { + super(ds, pmdKnownBroken); + } + + /** + * Constructor for QueryRunner that takes a {@code DataSource} to use and a {@code StatementConfiguration}. + * + * Methods that do not take a {@code Connection} parameter will retrieve connections from this + * {@code DataSource}. + * + * @param ds The {@code DataSource} to retrieve connections from. + * @param stmtConfig The configuration to apply to statements when they are prepared. + */ + public QueryRunner(final DataSource ds, final StatementConfiguration stmtConfig) { + super(ds, stmtConfig); + } + + /** + * Constructor for QueryRunner that takes a {@code DataSource}, a {@code StatementConfiguration}, and + * controls the use of {@code ParameterMetaData}. Methods that do not take a {@code Connection} parameter + * will retrieve connections from this {@code DataSource}. + * + * @param ds The {@code DataSource} to retrieve connections from. + * @param pmdKnownBroken Some drivers don't support {@link java.sql.ParameterMetaData#getParameterType(int) }; + * if {@code pmdKnownBroken} is set to true, we won't even try it; if false, we'll try it, + * and if it breaks, we'll remember not to use it again. + * @param stmtConfig The configuration to apply to statements when they are prepared. + */ + public QueryRunner(final DataSource ds, final boolean pmdKnownBroken, final StatementConfiguration stmtConfig) { + super(ds, pmdKnownBroken, stmtConfig); + } + + /** + * Execute a batch of SQL INSERT, UPDATE, or DELETE queries. + * + * @param conn The Connection to use to run the query. The caller is + * responsible for closing this Connection. + * @param sql The SQL to execute. + * @param params An array of query replacement parameters. Each row in + * this array is one set of batch replacement values. + * @return The number of rows updated per statement. + * @throws SQLException if a database access error occurs + * @since DbUtils 1.1 + */ + public int[] batch(final Connection conn, final String sql, final Object[][] params) throws SQLException { + return this.batch(conn, false, sql, params); + } + + /** + * Execute a batch of SQL INSERT, UPDATE, or DELETE queries. The + * {@code Connection} is retrieved from the {@code DataSource} + * set in the constructor. This {@code Connection} must be in + * auto-commit mode or the update will not be saved. + * + * @param sql The SQL to execute. + * @param params An array of query replacement parameters. Each row in + * this array is one set of batch replacement values. + * @return The number of rows updated per statement. + * @throws SQLException if a database access error occurs + * @since DbUtils 1.1 + */ + public int[] batch(final String sql, final Object[][] params) throws SQLException { + final Connection conn = this.prepareConnection(); + + return this.batch(conn, true, sql, params); + } + + /** + * Calls update after checking the parameters to ensure nothing is null. + * @param conn The connection to use for the batch call. + * @param closeConn True if the connection should be closed, false otherwise. + * @param sql The SQL statement to execute. + * @param params An array of query replacement parameters. Each row in + * this array is one set of batch replacement values. + * @return The number of rows updated in the batch. + * @throws SQLException If there are database or parameter errors. + */ + private int[] batch(final Connection conn, final boolean closeConn, final String sql, final Object[][] params) throws SQLException { + if (conn == null) { + throw new SQLException("Null connection"); + } + + if (sql == null) { + if (closeConn) { + close(conn); + } + throw new SQLException("Null SQL statement"); + } + + if (params == null) { + if (closeConn) { + close(conn); + } + throw new SQLException("Null parameters. If parameters aren't need, pass an empty array."); + } + + PreparedStatement stmt = null; + int[] rows = null; + try { + stmt = this.prepareStatement(conn, sql); + + for (final Object[] param : params) { + this.fillStatement(stmt, param); + stmt.addBatch(); + } + rows = stmt.executeBatch(); + + } catch (final SQLException e) { + this.rethrow(e, sql, (Object[])params); + } finally { + close(stmt); + if (closeConn) { + close(conn); + } + } + + return rows; + } + + /** + * Execute an SQL SELECT query with a single replacement parameter. The + * caller is responsible for closing the connection. + * @param <T> The type of object that the handler returns + * @param conn The connection to execute the query in. + * @param sql The query to execute. + * @param param The replacement parameter. + * @param rsh The handler that converts the results into an object. + * @return The object returned by the handler. + * @throws SQLException if a database access error occurs + * @deprecated Use {@link #query(Connection, String, ResultSetHandler, Object...)} + */ + @Deprecated + public <T> T query(final Connection conn, final String sql, final Object param, final ResultSetHandler<T> rsh) throws SQLException { + return this.<T>query(conn, false, sql, rsh, param); + } + + /** + * Execute an SQL SELECT query with replacement parameters. The + * caller is responsible for closing the connection. + * @param <T> The type of object that the handler returns + * @param conn The connection to execute the query in. + * @param sql The query to execute. + * @param params The replacement parameters. + * @param rsh The handler that converts the results into an object. + * @return The object returned by the handler. + * @throws SQLException if a database access error occurs + * @deprecated Use {@link #query(Connection,String,ResultSetHandler,Object...)} instead + */ + @Deprecated + public <T> T query(final Connection conn, final String sql, final Object[] params, final ResultSetHandler<T> rsh) throws SQLException { + return this.<T>query(conn, false, sql, rsh, params); + } + + /** + * Execute an SQL SELECT query with replacement parameters. The + * caller is responsible for closing the connection. + * @param <T> The type of object that the handler returns + * @param conn The connection to execute the query in. + * @param sql The query to execute. + * @param rsh The handler that converts the results into an object. + * @param params The replacement parameters. + * @return The object returned by the handler. + * @throws SQLException if a database access error occurs + */ + public <T> T query(final Connection conn, final String sql, final ResultSetHandler<T> rsh, final Object... params) throws SQLException { + return this.<T>query(conn, false, sql, rsh, params); + } + + /** + * Execute an SQL SELECT query without any replacement parameters. The + * caller is responsible for closing the connection. + * @param <T> The type of object that the handler returns + * @param conn The connection to execute the query in. + * @param sql The query to execute. + * @param rsh The handler that converts the results into an object. + * @return The object returned by the handler. + * @throws SQLException if a database access error occurs + */ + public <T> T query(final Connection conn, final String sql, final ResultSetHandler<T> rsh) throws SQLException { + return this.<T>query(conn, false, sql, rsh, (Object[]) null); + } + + /** + * Executes the given SELECT SQL with a single replacement parameter. + * The {@code Connection} is retrieved from the + * {@code DataSource} set in the constructor. + * @param <T> The type of object that the handler returns + * @param sql The SQL statement to execute. + * @param param The replacement parameter. + * @param rsh The handler used to create the result object from + * the {@code ResultSet}. + * + * @return An object generated by the handler. + * @throws SQLException if a database access error occurs + * @deprecated Use {@link #query(String, ResultSetHandler, Object...)} + */ + @Deprecated + public <T> T query(final String sql, final Object param, final ResultSetHandler<T> rsh) throws SQLException { + final Connection conn = this.prepareConnection(); + + return this.<T>query(conn, true, sql, rsh, param); + } + + /** + * Executes the given SELECT SQL query and returns a result object. + * The {@code Connection} is retrieved from the + * {@code DataSource} set in the constructor. + * @param <T> The type of object that the handler returns + * @param sql The SQL statement to execute. + * @param params Initialize the PreparedStatement's IN parameters with + * this array. + * + * @param rsh The handler used to create the result object from + * the {@code ResultSet}. + * + * @return An object generated by the handler. + * @throws SQLException if a database access error occurs + * @deprecated Use {@link #query(String, ResultSetHandler, Object...)} + */ + @Deprecated + public <T> T query(final String sql, final Object[] params, final ResultSetHandler<T> rsh) throws SQLException { + final Connection conn = this.prepareConnection(); + + return this.<T>query(conn, true, sql, rsh, params); + } + + /** + * Executes the given SELECT SQL query and returns a result object. + * The {@code Connection} is retrieved from the + * {@code DataSource} set in the constructor. + * @param <T> The type of object that the handler returns + * @param sql The SQL statement to execute. + * @param rsh The handler used to create the result object from + * the {@code ResultSet}. + * @param params Initialize the PreparedStatement's IN parameters with + * this array. + * @return An object generated by the handler. + * @throws SQLException if a database access error occurs + */ + public <T> T query(final String sql, final ResultSetHandler<T> rsh, final Object... params) throws SQLException { + final Connection conn = this.prepareConnection(); + + return this.<T>query(conn, true, sql, rsh, params); + } + + /** + * Executes the given SELECT SQL without any replacement parameters. + * The {@code Connection} is retrieved from the + * {@code DataSource} set in the constructor. + * @param <T> The type of object that the handler returns + * @param sql The SQL statement to execute. + * @param rsh The handler used to create the result object from + * the {@code ResultSet}. + * + * @return An object generated by the handler. + * @throws SQLException if a database access error occurs + */ + public <T> T query(final String sql, final ResultSetHandler<T> rsh) throws SQLException { + final Connection conn = this.prepareConnection(); + + return this.<T>query(conn, true, sql, rsh, (Object[]) null); + } + + /** + * Calls query after checking the parameters to ensure nothing is null. + * @param conn The connection to use for the query call. + * @param closeConn True if the connection should be closed, false otherwise. + * @param sql The SQL statement to execute. + * @param params An array of query replacement parameters. Each row in + * this array is one set of batch replacement values. + * @return The results of the query. + * @throws SQLException If there are database or parameter errors. + */ + private <T> T query(final Connection conn, final boolean closeConn, final String sql, final ResultSetHandler<T> rsh, final Object... params) + throws SQLException { + if (conn == null) { + throw new SQLException("Null connection"); + } + + if (sql == null) { + if (closeConn) { + close(conn); + } + throw new SQLException("Null SQL statement"); + } + + if (rsh == null) { + if (closeConn) { + close(conn); + } + throw new SQLException("Null ResultSetHandler"); + } + + Statement stmt = null; + ResultSet rs = null; + T result = null; + + try { + if (params != null && params.length > 0) { + final PreparedStatement ps = this.prepareStatement(conn, sql); + stmt = ps; + this.fillStatement(ps, params); + rs = this.wrap(ps.executeQuery()); + } else { + stmt = conn.createStatement(); + rs = this.wrap(stmt.executeQuery(sql)); + } + result = rsh.handle(rs); + + } catch (final SQLException e) { + this.rethrow(e, sql, params); + + } finally { + closeQuietly(rs); + closeQuietly(stmt); + if (closeConn) { + close(conn); + } + } + + return result; + } + + /** + * Execute an SQL INSERT, UPDATE, or DELETE query without replacement + * parameters. + * + * @param conn The connection to use to run the query. + * @param sql The SQL to execute. + * @return The number of rows updated. + * @throws SQLException if a database access error occurs + */ + public int update(final Connection conn, final String sql) throws SQLException { + return this.update(conn, false, sql, (Object[]) null); + } + + /** + * Execute an SQL INSERT, UPDATE, or DELETE query with a single replacement + * parameter. + * + * @param conn The connection to use to run the query. + * @param sql The SQL to execute. + * @param param The replacement parameter. + * @return The number of rows updated. + * @throws SQLException if a database access error occurs + */ + public int update(final Connection conn, final String sql, final Object param) throws SQLException { + return this.update(conn, false, sql, param); + } + + /** + * Execute an SQL INSERT, UPDATE, or DELETE query. + * + * @param conn The connection to use to run the query. + * @param sql The SQL to execute. + * @param params The query replacement parameters. + * @return The number of rows updated. + * @throws SQLException if a database access error occurs + */ + public int update(final Connection conn, final String sql, final Object... params) throws SQLException { + return update(conn, false, sql, params); + } + + /** + * Executes the given INSERT, UPDATE, or DELETE SQL statement without + * any replacement parameters. The {@code Connection} is retrieved + * from the {@code DataSource} set in the constructor. This + * {@code Connection} must be in auto-commit mode or the update will + * not be saved. + * + * @param sql The SQL statement to execute. + * @throws SQLException if a database access error occurs + * @return The number of rows updated. + */ + public int update(final String sql) throws SQLException { + final Connection conn = this.prepareConnection(); + + return this.update(conn, true, sql, (Object[]) null); + } + + /** + * Executes the given INSERT, UPDATE, or DELETE SQL statement with + * a single replacement parameter. The {@code Connection} is + * retrieved from the {@code DataSource} set in the constructor. + * This {@code Connection} must be in auto-commit mode or the + * update will not be saved. + * + * @param sql The SQL statement to execute. + * @param param The replacement parameter. + * @throws SQLException if a database access error occurs + * @return The number of rows updated. + */ + public int update(final String sql, final Object param) throws SQLException { + final Connection conn = this.prepareConnection(); + + return this.update(conn, true, sql, param); + } + + /** + * Executes the given INSERT, UPDATE, or DELETE SQL statement. The + * {@code Connection} is retrieved from the {@code DataSource} + * set in the constructor. This {@code Connection} must be in + * auto-commit mode or the update will not be saved. + * + * @param sql The SQL statement to execute. + * @param params Initializes the PreparedStatement's IN (i.e. '?') + * parameters. + * @throws SQLException if a database access error occurs + * @return The number of rows updated. + */ + public int update(final String sql, final Object... params) throws SQLException { + final Connection conn = this.prepareConnection(); + + return this.update(conn, true, sql, params); + } + + /** + * Calls update after checking the parameters to ensure nothing is null. + * @param conn The connection to use for the update call. + * @param closeConn True if the connection should be closed, false otherwise. + * @param sql The SQL statement to execute. + * @param params An array of update replacement parameters. Each row in + * this array is one set of update replacement values. + * @return The number of rows updated. + * @throws SQLException If there are database or parameter errors. + */ + private int update(final Connection conn, final boolean closeConn, final String sql, final Object... params) throws SQLException { + if (conn == null) { + throw new SQLException("Null connection"); + } + + if (sql == null) { + if (closeConn) { + close(conn); + } + throw new SQLException("Null SQL statement"); + } + + Statement stmt = null; + int rows = 0; + + try { + if (params != null && params.length > 0) { + final PreparedStatement ps = this.prepareStatement(conn, sql); + stmt = ps; + this.fillStatement(ps, params); + rows = ps.executeUpdate(); + } else { + stmt = conn.createStatement(); + rows = stmt.executeUpdate(sql); + } + + } catch (final SQLException e) { + this.rethrow(e, sql, params); + + } finally { + close(stmt); + if (closeConn) { + close(conn); + } + } + + return rows; + } + + /** + * Executes the given INSERT SQL without any replacement parameters. + * The {@code Connection} is retrieved from the + * {@code DataSource} set in the constructor. + * @param <T> The type of object that the handler returns + * @param sql The SQL statement to execute. + * @param rsh The handler used to create the result object from + * the {@code ResultSet} of auto-generated keys. + * @return An object generated by the handler. + * @throws SQLException if a database access error occurs + * @since 1.6 + */ + public <T> T insert(final String sql, final ResultSetHandler<T> rsh) throws SQLException { + return insert(this.prepareConnection(), true, sql, rsh, (Object[]) null); + } + + /** + * Executes the given INSERT SQL statement. The + * {@code Connection} is retrieved from the {@code DataSource} + * set in the constructor. This {@code Connection} must be in + * auto-commit mode or the insert will not be saved. + * @param <T> The type of object that the handler returns + * @param sql The SQL statement to execute. + * @param rsh The handler used to create the result object from + * the {@code ResultSet} of auto-generated keys. + * @param params Initializes the PreparedStatement's IN (i.e. '?') + * @return An object generated by the handler. + * @throws SQLException if a database access error occurs + * @since 1.6 + */ + public <T> T insert(final String sql, final ResultSetHandler<T> rsh, final Object... params) throws SQLException { + return insert(this.prepareConnection(), true, sql, rsh, params); + } + + /** + * Execute an SQL INSERT query without replacement parameters. + * @param <T> The type of object that the handler returns + * @param conn The connection to use to run the query. + * @param sql The SQL to execute. + * @param rsh The handler used to create the result object from + * the {@code ResultSet} of auto-generated keys. + * @return An object generated by the handler. + * @throws SQLException if a database access error occurs + * @since 1.6 + */ + public <T> T insert(final Connection conn, final String sql, final ResultSetHandler<T> rsh) throws SQLException { + return insert(conn, false, sql, rsh, (Object[]) null); + } + + /** + * Execute an SQL INSERT query. + * @param <T> The type of object that the handler returns + * @param conn The connection to use to run the query. + * @param sql The SQL to execute. + * @param rsh The handler used to create the result object from + * the {@code ResultSet} of auto-generated keys. + * @param params The query replacement parameters. + * @return An object generated by the handler. + * @throws SQLException if a database access error occurs + * @since 1.6 + */ + public <T> T insert(final Connection conn, final String sql, final ResultSetHandler<T> rsh, final Object... params) throws SQLException { + return insert(conn, false, sql, rsh, params); + } + + /** + * Executes the given INSERT SQL statement. + * @param conn The connection to use for the query call. + * @param closeConn True if the connection should be closed, false otherwise. + * @param sql The SQL statement to execute. + * @param rsh The handler used to create the result object from + * the {@code ResultSet} of auto-generated keys. + * @param params The query replacement parameters. + * @return An object generated by the handler. + * @throws SQLException If there are database or parameter errors. + * @since 1.6 + */ + private <T> T insert(final Connection conn, final boolean closeConn, final String sql, final ResultSetHandler<T> rsh, final Object... params) + throws SQLException { + if (conn == null) { + throw new SQLException("Null connection"); + } + + if (sql == null) { + if (closeConn) { + close(conn); + } + throw new SQLException("Null SQL statement"); + } + + if (rsh == null) { + if (closeConn) { + close(conn); + } + throw new SQLException("Null ResultSetHandler"); + } + + Statement stmt = null; + T generatedKeys = null; + + try { + if (params != null && params.length > 0) { + final PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); + stmt = ps; + this.fillStatement(ps, params); + ps.executeUpdate(); + } else { + stmt = conn.createStatement(); + stmt.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS); + } + final ResultSet resultSet = stmt.getGeneratedKeys(); + generatedKeys = rsh.handle(resultSet); + } catch (final SQLException e) { + this.rethrow(e, sql, params); + } finally { + close(stmt); + if (closeConn) { + close(conn); + } + } + + return generatedKeys; + } + + /** + * Executes the given batch of INSERT SQL statements. The + * {@code Connection} is retrieved from the {@code DataSource} + * set in the constructor. This {@code Connection} must be in + * auto-commit mode or the insert will not be saved. + * @param <T> The type of object that the handler returns + * @param sql The SQL statement to execute. + * @param rsh The handler used to create the result object from + * the {@code ResultSet} of auto-generated keys. + * @param params Initializes the PreparedStatement's IN (i.e. '?') + * @return The result generated by the handler. + * @throws SQLException if a database access error occurs + * @since 1.6 + */ + public <T> T insertBatch(final String sql, final ResultSetHandler<T> rsh, final Object[][] params) throws SQLException { + return insertBatch(this.prepareConnection(), true, sql, rsh, params); + } + + /** + * Executes the given batch of INSERT SQL statements. + * @param <T> The type of object that the handler returns + * @param conn The connection to use to run the query. + * @param sql The SQL to execute. + * @param rsh The handler used to create the result object from + * the {@code ResultSet} of auto-generated keys. + * @param params The query replacement parameters. + * @return The result generated by the handler. + * @throws SQLException if a database access error occurs + * @since 1.6 + */ + public <T> T insertBatch(final Connection conn, final String sql, final ResultSetHandler<T> rsh, final Object[][] params) throws SQLException { + return insertBatch(conn, false, sql, rsh, params); + } + + /** + * Executes the given batch of INSERT SQL statements. + * @param conn The connection to use for the query call. + * @param closeConn True if the connection should be closed, false otherwise. + * @param sql The SQL statement to execute. + * @param rsh The handler used to create the result object from + * the {@code ResultSet} of auto-generated keys. + * @param params The query replacement parameters. + * @return The result generated by the handler. + * @throws SQLException If there are database or parameter errors. + * @since 1.6 + */ + private <T> T insertBatch(final Connection conn, final boolean closeConn, final String sql, final ResultSetHandler<T> rsh, final Object[][] params) + throws SQLException { + if (conn == null) { + throw new SQLException("Null connection"); + } + + if (sql == null) { + if (closeConn) { + close(conn); + } + throw new SQLException("Null SQL statement"); + } + + if (params == null) { + if (closeConn) { + close(conn); + } + throw new SQLException("Null parameters. If parameters aren't need, pass an empty array."); + } + + PreparedStatement stmt = null; + T generatedKeys = null; + try { + stmt = this.prepareStatement(conn, sql, Statement.RETURN_GENERATED_KEYS); + + for (final Object[] param : params) { + this.fillStatement(stmt, param); + stmt.addBatch(); + } + stmt.executeBatch(); + final ResultSet rs = stmt.getGeneratedKeys(); + generatedKeys = rsh.handle(rs); + + } catch (final SQLException e) { + this.rethrow(e, sql, (Object[])params); + } finally { + close(stmt); + if (closeConn) { + close(conn); + } + } + + return generatedKeys; + } + + /** + * Execute an SQL statement, including a stored procedure call, which does + * not return any result sets. + * Any parameters which are instances of {@link OutParameter} will be + * registered as OUT parameters. + * <p> + * Use this method when invoking a stored procedure with OUT parameters + * that does not return any result sets. If you are not invoking a stored + * procedure, or the stored procedure has no OUT parameters, consider using + * {@link #update(java.sql.Connection, String, Object...) }. + * If the stored procedure returns result sets, use + * {@link #execute(java.sql.Connection, String, org.apache.commons.dbutils.ResultSetHandler, Object...) }. + * + * @param conn The connection to use to run the query. + * @param sql The SQL to execute. + * @param params The query replacement parameters. + * @return The number of rows updated. + * @throws SQLException if a database access error occurs + */ + public int execute(final Connection conn, final String sql, final Object... params) throws SQLException { + return this.execute(conn, false, sql, params); + } + + /** + * Execute an SQL statement, including a stored procedure call, which does + * not return any result sets. + * Any parameters which are instances of {@link OutParameter} will be + * registered as OUT parameters. + * <p> + * Use this method when invoking a stored procedure with OUT parameters + * that does not return any result sets. If you are not invoking a stored + * procedure, or the stored procedure has no OUT parameters, consider using + * {@link #update(String, Object...) }. + * If the stored procedure returns result sets, use + * {@link #execute(String, org.apache.commons.dbutils.ResultSetHandler, Object...) }. + * <p> + * The {@code Connection} is retrieved from the {@code DataSource} + * set in the constructor. This {@code Connection} must be in + * auto-commit mode or the update will not be saved. + * + * @param sql The SQL statement to execute. + * @param params Initializes the CallableStatement's parameters (i.e. '?'). + * @throws SQLException if a database access error occurs + * @return The number of rows updated. + */ + public int execute(final String sql, final Object... params) throws SQLException { + final Connection conn = this.prepareConnection(); + + return this.execute(conn, true, sql, params); + } + + /** + * Execute an SQL statement, including a stored procedure call, which + * returns one or more result sets. + * Any parameters which are instances of {@link OutParameter} will be + * registered as OUT parameters. + * <p> + * Use this method when: a) running SQL statements that return multiple + * result sets; b) invoking a stored procedure that return result + * sets and OUT parameters. Otherwise you may wish to use + * {@link #query(java.sql.Connection, String, org.apache.commons.dbutils.ResultSetHandler, Object...) } + * (if there are no OUT parameters) or + * {@link #execute(java.sql.Connection, String, Object...) } + * (if there are no result sets). + * + * @param <T> The type of object that the handler returns + * @param conn The connection to use to run the query. + * @param sql The SQL to execute. + * @param rsh The result set handler + * @param params The query replacement parameters. + * @return A list of objects generated by the handler + * @throws SQLException if a database access error occurs + */ + public <T> List<T> execute(final Connection conn, final String sql, final ResultSetHandler<T> rsh, final Object... params) throws SQLException { + return this.execute(conn, false, sql, rsh, params); + } + + /** + * Execute an SQL statement, including a stored procedure call, which + * returns one or more result sets. + * Any parameters which are instances of {@link OutParameter} will be + * registered as OUT parameters. + * <p> + * Use this method when: a) running SQL statements that return multiple + * result sets; b) invoking a stored procedure that return result + * sets and OUT parameters. Otherwise you may wish to use + * {@link #query(String, org.apache.commons.dbutils.ResultSetHandler, Object...) } + * (if there are no OUT parameters) or + * {@link #execute(String, Object...) } + * (if there are no result sets). + * + * @param <T> The type of object that the handler returns + * @param sql The SQL to execute. + * @param rsh The result set handler + * @param params The query replacement parameters. + * @return A list of objects generated by the handler + * @throws SQLException if a database access error occurs + */ + public <T> List<T> execute(final String sql, final ResultSetHandler<T> rsh, final Object... params) throws SQLException { + final Connection conn = this.prepareConnection(); + + return this.execute(conn, true, sql, rsh, params); + } + + /** + * Invokes the stored procedure via update after checking the parameters to + * ensure nothing is null. + * @param conn The connection to use for the update call. + * @param closeConn True if the connection should be closed, false otherwise. + * @param sql The SQL statement to execute. + * @param params An array of update replacement parameters. Each row in + * this array is one set of update replacement values. + * @return The number of rows updated. + * @throws SQLException If there are database or parameter errors. + */ + private int execute(final Connection conn, final boolean closeConn, final String sql, final Object... params) throws SQLException { + if (conn == null) { + throw new SQLException("Null connection"); + } + + if (sql == null) { + if (closeConn) { + close(conn); + } + throw new SQLException("Null SQL statement"); + } + + CallableStatement stmt = null; + int rows = 0; + + try { + stmt = this.prepareCall(conn, sql); + this.fillStatement(stmt, params); + stmt.execute(); + rows = stmt.getUpdateCount(); + this.retrieveOutParameters(stmt, params); + + } catch (final SQLException e) { + this.rethrow(e, sql, params); + + } finally { + close(stmt); + if (closeConn) { + close(conn); + } + } + + return rows; + } + + /** + * Invokes the stored procedure via update after checking the parameters to + * ensure nothing is null. + * @param conn The connection to use for the update call. + * @param closeConn True if the connection should be closed, false otherwise. + * @param sql The SQL statement to execute. + * @param rsh The result set handler + * @param params An array of update replacement parameters. Each row in + * this array is one set of update replacement values. + * @return List of all objects generated by the ResultSetHandler for all result sets handled. + * @throws SQLException If there are database or parameter errors. + */ + private <T> List<T> execute(final Connection conn, final boolean closeConn, final String sql, final ResultSetHandler<T> rsh, final Object... params) throws SQLException { + if (conn == null) { + throw new SQLException("Null connection"); + } + + if (sql == null) { + if (closeConn) { + close(conn); + } + throw new SQLException("Null SQL statement"); + } + + if (rsh == null) { + if (closeConn) { + close(conn); + } + throw new SQLException("Null ResultSetHandler"); + } + + CallableStatement stmt = null; + final List<T> results = new LinkedList<>(); + + try { + stmt = this.prepareCall(conn, sql); + this.fillStatement(stmt, params); + boolean moreResultSets = stmt.execute(); + // Handle multiple result sets by passing them through the handler + // retaining the final result + ResultSet rs = null; + while (moreResultSets) { + try { + rs = this.wrap(stmt.getResultSet()); + results.add(rsh.handle(rs)); + moreResultSets = stmt.getMoreResults(); + + } finally { + close(rs); + } + } + this.retrieveOutParameters(stmt, params); + + } catch (final SQLException e) { + this.rethrow(e, sql, params); + + } finally { + close(stmt); + if (closeConn) { + close(conn); + } + } + + return results; + } + + /** + * Set the value on all the {@link OutParameter} instances in the + * {@code params} array using the OUT parameter values from the + * {@code stmt}. + * @param stmt the statement from which to retrieve OUT parameter values + * @param params the parameter array for the statement invocation + * @throws SQLException when the value could not be retrieved from the + * statement. + */ + private void retrieveOutParameters(final CallableStatement stmt, final Object[] params) throws SQLException { + if (params != null) { + for (int i = 0; i < params.length; i++) { + if (params[i] instanceof OutParameter) { + ((OutParameter)params[i]).setValue(stmt, i + 1); + } + } + } + } +}