You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2018/05/04 16:14:22 UTC
commons-dbutils git commit: Sort methods in AB order.
Repository: commons-dbutils
Updated Branches:
refs/heads/master 8d41daf40 -> e672a7b52
Sort methods in AB order.
Project: http://git-wip-us.apache.org/repos/asf/commons-dbutils/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-dbutils/commit/e672a7b5
Tree: http://git-wip-us.apache.org/repos/asf/commons-dbutils/tree/e672a7b5
Diff: http://git-wip-us.apache.org/repos/asf/commons-dbutils/diff/e672a7b5
Branch: refs/heads/master
Commit: e672a7b526b05c5cc36b09fd589e03d87c2c7076
Parents: 8d41daf
Author: Gary Gregory <ga...@gmail.com>
Authored: Fri May 4 10:14:20 2018 -0600
Committer: Gary Gregory <ga...@gmail.com>
Committed: Fri May 4 10:14:20 2018 -0600
----------------------------------------------------------------------
.../commons/dbutils/AbstractQueryRunner.java | 1210 +++++++++---------
1 file changed, 605 insertions(+), 605 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/e672a7b5/src/main/java/org/apache/commons/dbutils/AbstractQueryRunner.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils/AbstractQueryRunner.java b/src/main/java/org/apache/commons/dbutils/AbstractQueryRunner.java
index 4e3a56c..f0c3590 100644
--- a/src/main/java/org/apache/commons/dbutils/AbstractQueryRunner.java
+++ b/src/main/java/org/apache/commons/dbutils/AbstractQueryRunner.java
@@ -1,605 +1,605 @@
-/*
- * 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.beans.IntrospectionException;
-import java.beans.Introspector;
-import java.beans.PropertyDescriptor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.sql.CallableStatement;
-import java.sql.Connection;
-import java.sql.ParameterMetaData;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.SQLFeatureNotSupportedException;
-import java.sql.Statement;
-import java.sql.Types;
-import java.util.Arrays;
-
-import javax.sql.DataSource;
-
-/**
- * The base class for QueryRunner & AsyncQueryRunner. This class is thread safe.
- *
- * @since 1.4 (mostly extracted from QueryRunner)
- */
-public abstract class AbstractQueryRunner {
- /**
- * Is {@link ParameterMetaData#getParameterType(int)} broken (have we tried
- * it yet)?
- */
- private volatile boolean pmdKnownBroken = false;
-
- /**
- * The DataSource to retrieve connections from.
- * @deprecated Access to this field should be through {@link #getDataSource()}.
- */
- @Deprecated
- protected final DataSource ds;
-
- /**
- * Configuration to use when preparing statements.
- */
- private final StatementConfiguration stmtConfig;
-
- /**
- * Default constructor, sets pmdKnownBroken to false, ds to null and stmtConfig to null.
- */
- public AbstractQueryRunner() {
- ds = null;
- this.stmtConfig = null;
- }
-
- /**
- * Constructor to control the use of <code>ParameterMetaData</code>.
- *
- * @param pmdKnownBroken
- * Some drivers don't support
- * {@link ParameterMetaData#getParameterType(int) }; if
- * <code>pmdKnownBroken</code> 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 AbstractQueryRunner(boolean pmdKnownBroken) {
- this.pmdKnownBroken = pmdKnownBroken;
- ds = null;
- this.stmtConfig = null;
- }
-
- /**
- * Constructor to provide a <code>DataSource</code>. Methods that do not
- * take a <code>Connection</code> parameter will retrieve connections from
- * this <code>DataSource</code>.
- *
- * @param ds
- * The <code>DataSource</code> to retrieve connections from.
- */
- public AbstractQueryRunner(DataSource ds) {
- this.ds = ds;
- this.stmtConfig = null;
- }
-
- /**
- * Constructor for QueryRunner that takes a <code>StatementConfiguration</code> to configure statements when
- * preparing them.
- *
- * @param stmtConfig The configuration to apply to statements when they are prepared.
- */
- public AbstractQueryRunner(StatementConfiguration stmtConfig) {
- this.ds = null;
- this.stmtConfig = stmtConfig;
- }
-
- /**
- * Constructor to provide a <code>DataSource</code> and control the use of
- * <code>ParameterMetaData</code>. Methods that do not take a
- * <code>Connection</code> parameter will retrieve connections from this
- * <code>DataSource</code>.
- *
- * @param ds
- * The <code>DataSource</code> to retrieve connections from.
- * @param pmdKnownBroken
- * Some drivers don't support
- * {@link ParameterMetaData#getParameterType(int) }; if
- * <code>pmdKnownBroken</code> 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 AbstractQueryRunner(DataSource ds, boolean pmdKnownBroken) {
- this.pmdKnownBroken = pmdKnownBroken;
- this.ds = ds;
- this.stmtConfig = null;
- }
-
- /**
- * Constructor for QueryRunner that takes a <code>DataSource</code> to use and a <code>StatementConfiguration</code>.
- *
- * Methods that do not take a <code>Connection</code> parameter will retrieve connections from this
- * <code>DataSource</code>.
- *
- * @param ds The <code>DataSource</code> to retrieve connections from.
- * @param stmtConfig The configuration to apply to statements when they are prepared.
- */
- public AbstractQueryRunner(DataSource ds, StatementConfiguration stmtConfig) {
- this.ds = ds;
- this.stmtConfig = stmtConfig;
- }
-
- /**
- * Constructor for QueryRunner that takes a <code>DataSource</code>, a <code>StatementConfiguration</code>, and
- * controls the use of <code>ParameterMetaData</code>. Methods that do not take a <code>Connection</code> parameter
- * will retrieve connections from this <code>DataSource</code>.
- *
- * @param ds The <code>DataSource</code> to retrieve connections from.
- * @param pmdKnownBroken Some drivers don't support {@link java.sql.ParameterMetaData#getParameterType(int) };
- * if <code>pmdKnownBroken</code> 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 AbstractQueryRunner(DataSource ds, boolean pmdKnownBroken, StatementConfiguration stmtConfig) {
- this.pmdKnownBroken = pmdKnownBroken;
- this.ds = ds;
- this.stmtConfig = stmtConfig;
- }
-
- /**
- * Returns the <code>DataSource</code> this runner is using.
- * <code>QueryRunner</code> methods always call this method to get the
- * <code>DataSource</code> so subclasses can provide specialized behavior.
- *
- * @return DataSource the runner is using
- */
- public DataSource getDataSource() {
- return this.ds;
- }
-
- /**
- * Some drivers don't support
- * {@link ParameterMetaData#getParameterType(int) }; if
- * <code>pmdKnownBroken</code> 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.
- *
- * @return the flag to skip (or not)
- * {@link ParameterMetaData#getParameterType(int) }
- * @since 1.4
- */
- public boolean isPmdKnownBroken() {
- return pmdKnownBroken;
- }
-
- /**
- * Factory method that creates and initializes a
- * <code>PreparedStatement</code> object for the given SQL.
- * <code>QueryRunner</code> methods always call this method to prepare
- * statements for them. Subclasses can override this method to provide
- * special PreparedStatement configuration if needed. This implementation
- * simply calls <code>conn.prepareStatement(sql)</code>.
- *
- * @param conn
- * The <code>Connection</code> used to create the
- * <code>PreparedStatement</code>
- * @param sql
- * The SQL statement to prepare.
- * @return An initialized <code>PreparedStatement</code>.
- * @throws SQLException
- * if a database access error occurs
- */
- protected PreparedStatement prepareStatement(Connection conn, String sql)
- throws SQLException {
-
- PreparedStatement ps = conn.prepareStatement(sql);
- try {
- configureStatement(ps);
- } catch (SQLException e) {
- ps.close();
- throw e;
- }
- return ps;
- }
-
- /**
- * Factory method that creates and initializes a
- * <code>PreparedStatement</code> object for the given SQL.
- * <code>QueryRunner</code> methods always call this method to prepare
- * statements for them. Subclasses can override this method to provide
- * special PreparedStatement configuration if needed. This implementation
- * simply calls <code>conn.prepareStatement(sql, returnedKeys)</code>
- * which will result in the ability to retrieve the automatically-generated
- * keys from an auto_increment column.
- *
- * @param conn
- * The <code>Connection</code> used to create the
- * <code>PreparedStatement</code>
- * @param sql
- * The SQL statement to prepare.
- * @param returnedKeys
- * Flag indicating whether to return generated keys or not.
- *
- * @return An initialized <code>PreparedStatement</code>.
- * @throws SQLException
- * if a database access error occurs
- * @since 1.6
- */
- protected PreparedStatement prepareStatement(Connection conn, String sql, int returnedKeys)
- throws SQLException {
-
- PreparedStatement ps = conn.prepareStatement(sql, returnedKeys);
- try {
- configureStatement(ps);
- } catch (SQLException e) {
- ps.close();
- throw e;
- }
- return ps;
- }
-
- private void configureStatement(Statement stmt) throws SQLException {
-
- if (stmtConfig != null) {
- if (stmtConfig.isFetchDirectionSet()) {
- stmt.setFetchDirection(stmtConfig.getFetchDirection());
- }
-
- if (stmtConfig.isFetchSizeSet()) {
- stmt.setFetchSize(stmtConfig.getFetchSize());
- }
-
- if (stmtConfig.isMaxFieldSizeSet()) {
- stmt.setMaxFieldSize(stmtConfig.getMaxFieldSize());
- }
-
- if (stmtConfig.isMaxRowsSet()) {
- stmt.setMaxRows(stmtConfig.getMaxRows());
- }
-
- if (stmtConfig.isQueryTimeoutSet()) {
- stmt.setQueryTimeout(stmtConfig.getQueryTimeout());
- }
- }
- }
-
- /**
- * Factory method that creates and initializes a
- * <code>CallableStatement</code> object for the given SQL.
- * <code>QueryRunner</code> methods always call this method to prepare
- * callable statements for them. Subclasses can override this method to
- * provide special CallableStatement configuration if needed. This
- * implementation simply calls <code>conn.prepareCall(sql)</code>.
- *
- * @param conn
- * The <code>Connection</code> used to create the
- * <code>CallableStatement</code>
- * @param sql
- * The SQL statement to prepare.
- * @return An initialized <code>CallableStatement</code>.
- * @throws SQLException
- * if a database access error occurs
- */
- protected CallableStatement prepareCall(Connection conn, String sql)
- throws SQLException {
-
- return conn.prepareCall(sql);
- }
-
- /**
- * Factory method that creates and initializes a <code>Connection</code>
- * object. <code>QueryRunner</code> methods always call this method to
- * retrieve connections from its DataSource. Subclasses can override this
- * method to provide special <code>Connection</code> configuration if
- * needed. This implementation simply calls <code>ds.getConnection()</code>.
- *
- * @return An initialized <code>Connection</code>.
- * @throws SQLException
- * if a database access error occurs
- * @since DbUtils 1.1
- */
- protected Connection prepareConnection() throws SQLException {
- if (this.getDataSource() == null) {
- throw new SQLException(
- "QueryRunner requires a DataSource to be "
- + "invoked in this way, or a Connection should be passed in");
- }
- return this.getDataSource().getConnection();
- }
-
- /**
- * Fill the <code>PreparedStatement</code> replacement parameters with the
- * given objects.
- *
- * @param stmt
- * PreparedStatement to fill
- * @param params
- * Query replacement parameters; <code>null</code> is a valid
- * value to pass in.
- * @throws SQLException
- * if a database access error occurs
- */
- public void fillStatement(PreparedStatement stmt, Object... params)
- throws SQLException {
-
- // check the parameter count, if we can
- ParameterMetaData pmd = null;
- if (!pmdKnownBroken) {
- try {
- pmd = stmt.getParameterMetaData();
- if (pmd == null) { // can be returned by implementations that don't support the method
- pmdKnownBroken = true;
- } else {
- int stmtCount = pmd.getParameterCount();
- int paramsCount = params == null ? 0 : params.length;
-
- if (stmtCount != paramsCount) {
- throw new SQLException("Wrong number of parameters: expected "
- + stmtCount + ", was given " + paramsCount);
- }
- }
- } catch (SQLFeatureNotSupportedException ex) {
- pmdKnownBroken = true;
- }
- // TODO see DBUTILS-117: would it make sense to catch any other SQLEx types here?
- }
-
- // nothing to do here
- if (params == null) {
- return;
- }
-
- CallableStatement call = null;
- if (stmt instanceof CallableStatement) {
- call = (CallableStatement) stmt;
- }
-
- for (int i = 0; i < params.length; i++) {
- if (params[i] != null) {
- if (call != null && params[i] instanceof OutParameter) {
- ((OutParameter)params[i]).register(call, i + 1);
- } else {
- stmt.setObject(i + 1, params[i]);
- }
- } else {
- // VARCHAR works with many drivers regardless
- // of the actual column type. Oddly, NULL and
- // OTHER don't work with Oracle's drivers.
- int sqlType = Types.VARCHAR;
- if (!pmdKnownBroken) {
- // TODO see DBUTILS-117: does it make sense to catch SQLEx here?
- try {
- /*
- * It's not possible for pmdKnownBroken to change from
- * true to false, (once true, always true) so pmd cannot
- * be null here.
- */
- sqlType = pmd.getParameterType(i + 1);
- } catch (SQLException e) {
- pmdKnownBroken = true;
- }
- }
- stmt.setNull(i + 1, sqlType);
- }
- }
- }
-
- /**
- * Fill the <code>PreparedStatement</code> replacement parameters with the
- * given object's bean property values.
- *
- * @param stmt
- * PreparedStatement to fill
- * @param bean
- * a JavaBean object
- * @param properties
- * an ordered array of properties; this gives the order to insert
- * values in the statement
- * @throws SQLException
- * if a database access error occurs
- */
- public void fillStatementWithBean(PreparedStatement stmt, Object bean,
- PropertyDescriptor[] properties) throws SQLException {
- Object[] params = new Object[properties.length];
- for (int i = 0; i < properties.length; i++) {
- PropertyDescriptor property = properties[i];
- Object value = null;
- Method method = property.getReadMethod();
- if (method == null) {
- throw new RuntimeException("No read method for bean property "
- + bean.getClass() + " " + property.getName());
- }
- try {
- value = method.invoke(bean, new Object[0]);
- } catch (InvocationTargetException e) {
- throw new RuntimeException("Couldn't invoke method: " + method,
- e);
- } catch (IllegalArgumentException e) {
- throw new RuntimeException(
- "Couldn't invoke method with 0 arguments: " + method, e);
- } catch (IllegalAccessException e) {
- throw new RuntimeException("Couldn't invoke method: " + method,
- e);
- }
- params[i] = value;
- }
- fillStatement(stmt, params);
- }
-
- /**
- * Fill the <code>PreparedStatement</code> replacement parameters with the
- * given object's bean property values.
- *
- * @param stmt
- * PreparedStatement to fill
- * @param bean
- * A JavaBean object
- * @param propertyNames
- * An ordered array of property names (these should match the
- * getters/setters); this gives the order to insert values in the
- * statement
- * @throws SQLException
- * If a database access error occurs
- */
- public void fillStatementWithBean(PreparedStatement stmt, Object bean,
- String... propertyNames) throws SQLException {
- PropertyDescriptor[] descriptors;
- try {
- descriptors = Introspector.getBeanInfo(bean.getClass())
- .getPropertyDescriptors();
- } catch (IntrospectionException e) {
- throw new RuntimeException("Couldn't introspect bean "
- + bean.getClass().toString(), e);
- }
- PropertyDescriptor[] sorted = new PropertyDescriptor[propertyNames.length];
- for (int i = 0; i < propertyNames.length; i++) {
- String propertyName = propertyNames[i];
- if (propertyName == null) {
- throw new NullPointerException("propertyName can't be null: "
- + i);
- }
- boolean found = false;
- for (int j = 0; j < descriptors.length; j++) {
- PropertyDescriptor descriptor = descriptors[j];
- if (propertyName.equals(descriptor.getName())) {
- sorted[i] = descriptor;
- found = true;
- break;
- }
- }
- if (!found) {
- throw new RuntimeException("Couldn't find bean property: "
- + bean.getClass() + " " + propertyName);
- }
- }
- fillStatementWithBean(stmt, bean, sorted);
- }
-
- /**
- * Throws a new exception with a more informative error message.
- *
- * @param cause
- * The original exception that will be chained to the new
- * exception when it's rethrown.
- *
- * @param sql
- * The query that was executing when the exception happened.
- *
- * @param params
- * The query replacement parameters; <code>null</code> is a valid
- * value to pass in.
- *
- * @throws SQLException
- * if a database access error occurs
- */
- protected void rethrow(SQLException cause, String sql, Object... params)
- throws SQLException {
-
- String causeMessage = cause.getMessage();
- if (causeMessage == null) {
- causeMessage = "";
- }
- StringBuffer msg = new StringBuffer(causeMessage);
-
- msg.append(" Query: ");
- msg.append(sql);
- msg.append(" Parameters: ");
-
- if (params == null) {
- msg.append("[]");
- } else {
- msg.append(Arrays.deepToString(params));
- }
-
- SQLException e = new SQLException(msg.toString(), cause.getSQLState(),
- cause.getErrorCode());
- e.setNextException(cause);
-
- throw e;
- }
-
- /**
- * Wrap the <code>ResultSet</code> in a decorator before processing it. This
- * implementation returns the <code>ResultSet</code> it is given without any
- * decoration.
- *
- * <p>
- * Often, the implementation of this method can be done in an anonymous
- * inner class like this:
- * </p>
- *
- * <pre>
- * QueryRunner run = new QueryRunner() {
- * protected ResultSet wrap(ResultSet rs) {
- * return StringTrimmedResultSet.wrap(rs);
- * }
- * };
- * </pre>
- *
- * @param rs
- * The <code>ResultSet</code> to decorate; never
- * <code>null</code>.
- * @return The <code>ResultSet</code> wrapped in some decorator.
- */
- protected ResultSet wrap(ResultSet rs) {
- return rs;
- }
-
- /**
- * Close a <code>Connection</code>. This implementation avoids closing if
- * null and does <strong>not</strong> suppress any exceptions. Subclasses
- * can override to provide special handling like logging.
- *
- * @param conn
- * Connection to close
- * @throws SQLException
- * if a database access error occurs
- * @since DbUtils 1.1
- */
- protected void close(Connection conn) throws SQLException {
- DbUtils.close(conn);
- }
-
- /**
- * Close a <code>Statement</code>. This implementation avoids closing if
- * null and does <strong>not</strong> suppress any exceptions. Subclasses
- * can override to provide special handling like logging.
- *
- * @param stmt
- * Statement to close
- * @throws SQLException
- * if a database access error occurs
- * @since DbUtils 1.1
- */
- protected void close(Statement stmt) throws SQLException {
- DbUtils.close(stmt);
- }
-
- /**
- * Close a <code>ResultSet</code>. This implementation avoids closing if
- * null and does <strong>not</strong> suppress any exceptions. Subclasses
- * can override to provide special handling like logging.
- *
- * @param rs
- * ResultSet to close
- * @throws SQLException
- * if a database access error occurs
- * @since DbUtils 1.1
- */
- protected void close(ResultSet rs) throws SQLException {
- DbUtils.close(rs);
- }
-
-}
+/*
+ * 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.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.ParameterMetaData;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.sql.Statement;
+import java.sql.Types;
+import java.util.Arrays;
+
+import javax.sql.DataSource;
+
+/**
+ * The base class for QueryRunner & AsyncQueryRunner. This class is thread safe.
+ *
+ * @since 1.4 (mostly extracted from QueryRunner)
+ */
+public abstract class AbstractQueryRunner {
+ /**
+ * Is {@link ParameterMetaData#getParameterType(int)} broken (have we tried
+ * it yet)?
+ */
+ private volatile boolean pmdKnownBroken = false;
+
+ /**
+ * The DataSource to retrieve connections from.
+ * @deprecated Access to this field should be through {@link #getDataSource()}.
+ */
+ @Deprecated
+ protected final DataSource ds;
+
+ /**
+ * Configuration to use when preparing statements.
+ */
+ private final StatementConfiguration stmtConfig;
+
+ /**
+ * Default constructor, sets pmdKnownBroken to false, ds to null and stmtConfig to null.
+ */
+ public AbstractQueryRunner() {
+ ds = null;
+ this.stmtConfig = null;
+ }
+
+ /**
+ * Constructor to control the use of <code>ParameterMetaData</code>.
+ *
+ * @param pmdKnownBroken
+ * Some drivers don't support
+ * {@link ParameterMetaData#getParameterType(int) }; if
+ * <code>pmdKnownBroken</code> 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 AbstractQueryRunner(boolean pmdKnownBroken) {
+ this.pmdKnownBroken = pmdKnownBroken;
+ ds = null;
+ this.stmtConfig = null;
+ }
+
+ /**
+ * Constructor to provide a <code>DataSource</code>. Methods that do not
+ * take a <code>Connection</code> parameter will retrieve connections from
+ * this <code>DataSource</code>.
+ *
+ * @param ds
+ * The <code>DataSource</code> to retrieve connections from.
+ */
+ public AbstractQueryRunner(DataSource ds) {
+ this.ds = ds;
+ this.stmtConfig = null;
+ }
+
+ /**
+ * Constructor to provide a <code>DataSource</code> and control the use of
+ * <code>ParameterMetaData</code>. Methods that do not take a
+ * <code>Connection</code> parameter will retrieve connections from this
+ * <code>DataSource</code>.
+ *
+ * @param ds
+ * The <code>DataSource</code> to retrieve connections from.
+ * @param pmdKnownBroken
+ * Some drivers don't support
+ * {@link ParameterMetaData#getParameterType(int) }; if
+ * <code>pmdKnownBroken</code> 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 AbstractQueryRunner(DataSource ds, boolean pmdKnownBroken) {
+ this.pmdKnownBroken = pmdKnownBroken;
+ this.ds = ds;
+ this.stmtConfig = null;
+ }
+
+ /**
+ * Constructor for QueryRunner that takes a <code>DataSource</code>, a <code>StatementConfiguration</code>, and
+ * controls the use of <code>ParameterMetaData</code>. Methods that do not take a <code>Connection</code> parameter
+ * will retrieve connections from this <code>DataSource</code>.
+ *
+ * @param ds The <code>DataSource</code> to retrieve connections from.
+ * @param pmdKnownBroken Some drivers don't support {@link java.sql.ParameterMetaData#getParameterType(int) };
+ * if <code>pmdKnownBroken</code> 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 AbstractQueryRunner(DataSource ds, boolean pmdKnownBroken, StatementConfiguration stmtConfig) {
+ this.pmdKnownBroken = pmdKnownBroken;
+ this.ds = ds;
+ this.stmtConfig = stmtConfig;
+ }
+
+ /**
+ * Constructor for QueryRunner that takes a <code>DataSource</code> to use and a <code>StatementConfiguration</code>.
+ *
+ * Methods that do not take a <code>Connection</code> parameter will retrieve connections from this
+ * <code>DataSource</code>.
+ *
+ * @param ds The <code>DataSource</code> to retrieve connections from.
+ * @param stmtConfig The configuration to apply to statements when they are prepared.
+ */
+ public AbstractQueryRunner(DataSource ds, StatementConfiguration stmtConfig) {
+ this.ds = ds;
+ this.stmtConfig = stmtConfig;
+ }
+
+ /**
+ * Constructor for QueryRunner that takes a <code>StatementConfiguration</code> to configure statements when
+ * preparing them.
+ *
+ * @param stmtConfig The configuration to apply to statements when they are prepared.
+ */
+ public AbstractQueryRunner(StatementConfiguration stmtConfig) {
+ this.ds = null;
+ this.stmtConfig = stmtConfig;
+ }
+
+ /**
+ * Close a <code>Connection</code>. This implementation avoids closing if
+ * null and does <strong>not</strong> suppress any exceptions. Subclasses
+ * can override to provide special handling like logging.
+ *
+ * @param conn
+ * Connection to close
+ * @throws SQLException
+ * if a database access error occurs
+ * @since DbUtils 1.1
+ */
+ protected void close(Connection conn) throws SQLException {
+ DbUtils.close(conn);
+ }
+
+ /**
+ * Close a <code>ResultSet</code>. This implementation avoids closing if
+ * null and does <strong>not</strong> suppress any exceptions. Subclasses
+ * can override to provide special handling like logging.
+ *
+ * @param rs
+ * ResultSet to close
+ * @throws SQLException
+ * if a database access error occurs
+ * @since DbUtils 1.1
+ */
+ protected void close(ResultSet rs) throws SQLException {
+ DbUtils.close(rs);
+ }
+
+ /**
+ * Close a <code>Statement</code>. This implementation avoids closing if
+ * null and does <strong>not</strong> suppress any exceptions. Subclasses
+ * can override to provide special handling like logging.
+ *
+ * @param stmt
+ * Statement to close
+ * @throws SQLException
+ * if a database access error occurs
+ * @since DbUtils 1.1
+ */
+ protected void close(Statement stmt) throws SQLException {
+ DbUtils.close(stmt);
+ }
+
+ private void configureStatement(Statement stmt) throws SQLException {
+
+ if (stmtConfig != null) {
+ if (stmtConfig.isFetchDirectionSet()) {
+ stmt.setFetchDirection(stmtConfig.getFetchDirection());
+ }
+
+ if (stmtConfig.isFetchSizeSet()) {
+ stmt.setFetchSize(stmtConfig.getFetchSize());
+ }
+
+ if (stmtConfig.isMaxFieldSizeSet()) {
+ stmt.setMaxFieldSize(stmtConfig.getMaxFieldSize());
+ }
+
+ if (stmtConfig.isMaxRowsSet()) {
+ stmt.setMaxRows(stmtConfig.getMaxRows());
+ }
+
+ if (stmtConfig.isQueryTimeoutSet()) {
+ stmt.setQueryTimeout(stmtConfig.getQueryTimeout());
+ }
+ }
+ }
+
+ /**
+ * Fill the <code>PreparedStatement</code> replacement parameters with the
+ * given objects.
+ *
+ * @param stmt
+ * PreparedStatement to fill
+ * @param params
+ * Query replacement parameters; <code>null</code> is a valid
+ * value to pass in.
+ * @throws SQLException
+ * if a database access error occurs
+ */
+ public void fillStatement(PreparedStatement stmt, Object... params)
+ throws SQLException {
+
+ // check the parameter count, if we can
+ ParameterMetaData pmd = null;
+ if (!pmdKnownBroken) {
+ try {
+ pmd = stmt.getParameterMetaData();
+ if (pmd == null) { // can be returned by implementations that don't support the method
+ pmdKnownBroken = true;
+ } else {
+ int stmtCount = pmd.getParameterCount();
+ int paramsCount = params == null ? 0 : params.length;
+
+ if (stmtCount != paramsCount) {
+ throw new SQLException("Wrong number of parameters: expected "
+ + stmtCount + ", was given " + paramsCount);
+ }
+ }
+ } catch (SQLFeatureNotSupportedException ex) {
+ pmdKnownBroken = true;
+ }
+ // TODO see DBUTILS-117: would it make sense to catch any other SQLEx types here?
+ }
+
+ // nothing to do here
+ if (params == null) {
+ return;
+ }
+
+ CallableStatement call = null;
+ if (stmt instanceof CallableStatement) {
+ call = (CallableStatement) stmt;
+ }
+
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] != null) {
+ if (call != null && params[i] instanceof OutParameter) {
+ ((OutParameter)params[i]).register(call, i + 1);
+ } else {
+ stmt.setObject(i + 1, params[i]);
+ }
+ } else {
+ // VARCHAR works with many drivers regardless
+ // of the actual column type. Oddly, NULL and
+ // OTHER don't work with Oracle's drivers.
+ int sqlType = Types.VARCHAR;
+ if (!pmdKnownBroken) {
+ // TODO see DBUTILS-117: does it make sense to catch SQLEx here?
+ try {
+ /*
+ * It's not possible for pmdKnownBroken to change from
+ * true to false, (once true, always true) so pmd cannot
+ * be null here.
+ */
+ sqlType = pmd.getParameterType(i + 1);
+ } catch (SQLException e) {
+ pmdKnownBroken = true;
+ }
+ }
+ stmt.setNull(i + 1, sqlType);
+ }
+ }
+ }
+
+ /**
+ * Fill the <code>PreparedStatement</code> replacement parameters with the
+ * given object's bean property values.
+ *
+ * @param stmt
+ * PreparedStatement to fill
+ * @param bean
+ * a JavaBean object
+ * @param properties
+ * an ordered array of properties; this gives the order to insert
+ * values in the statement
+ * @throws SQLException
+ * if a database access error occurs
+ */
+ public void fillStatementWithBean(PreparedStatement stmt, Object bean,
+ PropertyDescriptor[] properties) throws SQLException {
+ Object[] params = new Object[properties.length];
+ for (int i = 0; i < properties.length; i++) {
+ PropertyDescriptor property = properties[i];
+ Object value = null;
+ Method method = property.getReadMethod();
+ if (method == null) {
+ throw new RuntimeException("No read method for bean property "
+ + bean.getClass() + " " + property.getName());
+ }
+ try {
+ value = method.invoke(bean, new Object[0]);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException("Couldn't invoke method: " + method,
+ e);
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(
+ "Couldn't invoke method with 0 arguments: " + method, e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException("Couldn't invoke method: " + method,
+ e);
+ }
+ params[i] = value;
+ }
+ fillStatement(stmt, params);
+ }
+
+ /**
+ * Fill the <code>PreparedStatement</code> replacement parameters with the
+ * given object's bean property values.
+ *
+ * @param stmt
+ * PreparedStatement to fill
+ * @param bean
+ * A JavaBean object
+ * @param propertyNames
+ * An ordered array of property names (these should match the
+ * getters/setters); this gives the order to insert values in the
+ * statement
+ * @throws SQLException
+ * If a database access error occurs
+ */
+ public void fillStatementWithBean(PreparedStatement stmt, Object bean,
+ String... propertyNames) throws SQLException {
+ PropertyDescriptor[] descriptors;
+ try {
+ descriptors = Introspector.getBeanInfo(bean.getClass())
+ .getPropertyDescriptors();
+ } catch (IntrospectionException e) {
+ throw new RuntimeException("Couldn't introspect bean "
+ + bean.getClass().toString(), e);
+ }
+ PropertyDescriptor[] sorted = new PropertyDescriptor[propertyNames.length];
+ for (int i = 0; i < propertyNames.length; i++) {
+ String propertyName = propertyNames[i];
+ if (propertyName == null) {
+ throw new NullPointerException("propertyName can't be null: "
+ + i);
+ }
+ boolean found = false;
+ for (int j = 0; j < descriptors.length; j++) {
+ PropertyDescriptor descriptor = descriptors[j];
+ if (propertyName.equals(descriptor.getName())) {
+ sorted[i] = descriptor;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ throw new RuntimeException("Couldn't find bean property: "
+ + bean.getClass() + " " + propertyName);
+ }
+ }
+ fillStatementWithBean(stmt, bean, sorted);
+ }
+
+ /**
+ * Returns the <code>DataSource</code> this runner is using.
+ * <code>QueryRunner</code> methods always call this method to get the
+ * <code>DataSource</code> so subclasses can provide specialized behavior.
+ *
+ * @return DataSource the runner is using
+ */
+ public DataSource getDataSource() {
+ return this.ds;
+ }
+
+ /**
+ * Some drivers don't support
+ * {@link ParameterMetaData#getParameterType(int) }; if
+ * <code>pmdKnownBroken</code> 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.
+ *
+ * @return the flag to skip (or not)
+ * {@link ParameterMetaData#getParameterType(int) }
+ * @since 1.4
+ */
+ public boolean isPmdKnownBroken() {
+ return pmdKnownBroken;
+ }
+
+ /**
+ * Factory method that creates and initializes a
+ * <code>CallableStatement</code> object for the given SQL.
+ * <code>QueryRunner</code> methods always call this method to prepare
+ * callable statements for them. Subclasses can override this method to
+ * provide special CallableStatement configuration if needed. This
+ * implementation simply calls <code>conn.prepareCall(sql)</code>.
+ *
+ * @param conn
+ * The <code>Connection</code> used to create the
+ * <code>CallableStatement</code>
+ * @param sql
+ * The SQL statement to prepare.
+ * @return An initialized <code>CallableStatement</code>.
+ * @throws SQLException
+ * if a database access error occurs
+ */
+ protected CallableStatement prepareCall(Connection conn, String sql)
+ throws SQLException {
+
+ return conn.prepareCall(sql);
+ }
+
+ /**
+ * Factory method that creates and initializes a <code>Connection</code>
+ * object. <code>QueryRunner</code> methods always call this method to
+ * retrieve connections from its DataSource. Subclasses can override this
+ * method to provide special <code>Connection</code> configuration if
+ * needed. This implementation simply calls <code>ds.getConnection()</code>.
+ *
+ * @return An initialized <code>Connection</code>.
+ * @throws SQLException
+ * if a database access error occurs
+ * @since DbUtils 1.1
+ */
+ protected Connection prepareConnection() throws SQLException {
+ if (this.getDataSource() == null) {
+ throw new SQLException(
+ "QueryRunner requires a DataSource to be "
+ + "invoked in this way, or a Connection should be passed in");
+ }
+ return this.getDataSource().getConnection();
+ }
+
+ /**
+ * Factory method that creates and initializes a
+ * <code>PreparedStatement</code> object for the given SQL.
+ * <code>QueryRunner</code> methods always call this method to prepare
+ * statements for them. Subclasses can override this method to provide
+ * special PreparedStatement configuration if needed. This implementation
+ * simply calls <code>conn.prepareStatement(sql)</code>.
+ *
+ * @param conn
+ * The <code>Connection</code> used to create the
+ * <code>PreparedStatement</code>
+ * @param sql
+ * The SQL statement to prepare.
+ * @return An initialized <code>PreparedStatement</code>.
+ * @throws SQLException
+ * if a database access error occurs
+ */
+ protected PreparedStatement prepareStatement(Connection conn, String sql)
+ throws SQLException {
+
+ PreparedStatement ps = conn.prepareStatement(sql);
+ try {
+ configureStatement(ps);
+ } catch (SQLException e) {
+ ps.close();
+ throw e;
+ }
+ return ps;
+ }
+
+ /**
+ * Factory method that creates and initializes a
+ * <code>PreparedStatement</code> object for the given SQL.
+ * <code>QueryRunner</code> methods always call this method to prepare
+ * statements for them. Subclasses can override this method to provide
+ * special PreparedStatement configuration if needed. This implementation
+ * simply calls <code>conn.prepareStatement(sql, returnedKeys)</code>
+ * which will result in the ability to retrieve the automatically-generated
+ * keys from an auto_increment column.
+ *
+ * @param conn
+ * The <code>Connection</code> used to create the
+ * <code>PreparedStatement</code>
+ * @param sql
+ * The SQL statement to prepare.
+ * @param returnedKeys
+ * Flag indicating whether to return generated keys or not.
+ *
+ * @return An initialized <code>PreparedStatement</code>.
+ * @throws SQLException
+ * if a database access error occurs
+ * @since 1.6
+ */
+ protected PreparedStatement prepareStatement(Connection conn, String sql, int returnedKeys)
+ throws SQLException {
+
+ PreparedStatement ps = conn.prepareStatement(sql, returnedKeys);
+ try {
+ configureStatement(ps);
+ } catch (SQLException e) {
+ ps.close();
+ throw e;
+ }
+ return ps;
+ }
+
+ /**
+ * Throws a new exception with a more informative error message.
+ *
+ * @param cause
+ * The original exception that will be chained to the new
+ * exception when it's rethrown.
+ *
+ * @param sql
+ * The query that was executing when the exception happened.
+ *
+ * @param params
+ * The query replacement parameters; <code>null</code> is a valid
+ * value to pass in.
+ *
+ * @throws SQLException
+ * if a database access error occurs
+ */
+ protected void rethrow(SQLException cause, String sql, Object... params)
+ throws SQLException {
+
+ String causeMessage = cause.getMessage();
+ if (causeMessage == null) {
+ causeMessage = "";
+ }
+ StringBuffer msg = new StringBuffer(causeMessage);
+
+ msg.append(" Query: ");
+ msg.append(sql);
+ msg.append(" Parameters: ");
+
+ if (params == null) {
+ msg.append("[]");
+ } else {
+ msg.append(Arrays.deepToString(params));
+ }
+
+ SQLException e = new SQLException(msg.toString(), cause.getSQLState(),
+ cause.getErrorCode());
+ e.setNextException(cause);
+
+ throw e;
+ }
+
+ /**
+ * Wrap the <code>ResultSet</code> in a decorator before processing it. This
+ * implementation returns the <code>ResultSet</code> it is given without any
+ * decoration.
+ *
+ * <p>
+ * Often, the implementation of this method can be done in an anonymous
+ * inner class like this:
+ * </p>
+ *
+ * <pre>
+ * QueryRunner run = new QueryRunner() {
+ * protected ResultSet wrap(ResultSet rs) {
+ * return StringTrimmedResultSet.wrap(rs);
+ * }
+ * };
+ * </pre>
+ *
+ * @param rs
+ * The <code>ResultSet</code> to decorate; never
+ * <code>null</code>.
+ * @return The <code>ResultSet</code> wrapped in some decorator.
+ */
+ protected ResultSet wrap(ResultSet rs) {
+ return rs;
+ }
+
+}