DBUTILS-70 Add statement configuration for setting parameters on sql statements
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/dbutils/trunk@1673781 13f79535-47bb-0310-9956-ffa450edef68 Project: http://git-wip-us.apache.org/repos/asf/commons-dbutils/repo Commit: http://git-wip-us.apache.org/repos/asf/commons-dbutils/commit/92c6d6d5 Tree: http://git-wip-us.apache.org/repos/asf/commons-dbutils/tree/92c6d6d5 Diff: http://git-wip-us.apache.org/repos/asf/commons-dbutils/diff/92c6d6d5 Branch: refs/heads/master Commit: 92c6d6d58f9c3f8d8370459d364daa0925ca7980 Parents: 504838b Author: Carl Franklin Hall <[email protected]> Authored: Wed Apr 15 14:25:26 2015 +0000 Committer: Carl Franklin Hall <[email protected]> Committed: Wed Apr 15 14:25:26 2015 +0000 ---------------------------------------------------------------------- .../commons/dbutils/AbstractQueryRunner.java | 86 ++++++++- .../org/apache/commons/dbutils/QueryRunner.java | 38 ++++ .../commons/dbutils/StatementConfiguration.java | 176 +++++++++++++++++++ .../apache/commons/dbutils/QueryRunnerTest.java | 13 ++ .../dbutils/StatementConfigurationTest.java | 72 ++++++++ 5 files changed, 382 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/92c6d6d5/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 b5ce0cd..bc08bd1 100644 --- a/src/main/java/org/apache/commons/dbutils/AbstractQueryRunner.java +++ b/src/main/java/org/apache/commons/dbutils/AbstractQueryRunner.java @@ -53,10 +53,16 @@ public abstract class AbstractQueryRunner { protected final DataSource ds; /** - * Default constructor, sets pmdKnownBroken to false and ds to null. + * 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; } /** @@ -72,6 +78,7 @@ public abstract class AbstractQueryRunner { public AbstractQueryRunner(boolean pmdKnownBroken) { this.pmdKnownBroken = pmdKnownBroken; ds = null; + this.stmtConfig = null; } /** @@ -84,6 +91,18 @@ public abstract class AbstractQueryRunner { */ 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; } /** @@ -104,6 +123,38 @@ public abstract class AbstractQueryRunner { 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; } /** @@ -152,7 +203,9 @@ public abstract class AbstractQueryRunner { protected PreparedStatement prepareStatement(Connection conn, String sql) throws SQLException { - return conn.prepareStatement(sql); + PreparedStatement ps = conn.prepareStatement(sql); + configureStatement(ps); + return ps; } /** @@ -181,7 +234,34 @@ public abstract class AbstractQueryRunner { protected PreparedStatement prepareStatement(Connection conn, String sql, int returnedKeys) throws SQLException { - return conn.prepareStatement(sql, returnedKeys); + PreparedStatement ps = conn.prepareStatement(sql, returnedKeys); + configureStatement(ps); + 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()); + } + } } /** http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/92c6d6d5/src/main/java/org/apache/commons/dbutils/QueryRunner.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/dbutils/QueryRunner.java b/src/main/java/org/apache/commons/dbutils/QueryRunner.java index b14b65c..aaaf157 100644 --- a/src/main/java/org/apache/commons/dbutils/QueryRunner.java +++ b/src/main/java/org/apache/commons/dbutils/QueryRunner.java @@ -63,6 +63,16 @@ public class QueryRunner extends AbstractQueryRunner { } /** + * 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 QueryRunner(StatementConfiguration stmtConfig) { + super(stmtConfig); + } + + /** * Constructor for QueryRunner that takes a <code>DataSource</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>. @@ -77,6 +87,34 @@ public class QueryRunner extends AbstractQueryRunner { } /** + * 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 QueryRunner(DataSource ds, StatementConfiguration stmtConfig) { + super(ds, 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 QueryRunner(DataSource ds, boolean pmdKnownBroken, 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 http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/92c6d6d5/src/main/java/org/apache/commons/dbutils/StatementConfiguration.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/dbutils/StatementConfiguration.java b/src/main/java/org/apache/commons/dbutils/StatementConfiguration.java new file mode 100644 index 0000000..68761ab --- /dev/null +++ b/src/main/java/org/apache/commons/dbutils/StatementConfiguration.java @@ -0,0 +1,176 @@ +/* + * 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; + +/** + * Configuration options for a {@link java.sql.Statement} when preparing statements in <code>QueryRunner</code>. + */ +public class StatementConfiguration { + private final Integer fetchDirection; + private final Integer fetchSize; + private final Integer maxFieldSize; + private final Integer maxRows; + private final Integer queryTimeout; + + /** + * Constructor for <code>StatementConfiguration</code>. For more flexibility, use {@link Builder}. + * + * @param fetchDirection The direction for fetching rows from database tables. + * @param fetchSize The number of rows that should be fetched from the database when more rows are needed. + * @param maxFieldSize The maximum number of bytes that can be returned for character and binary column values. + * @param maxRows The maximum number of rows that a <code>ResultSet</code> can produce. + * @param queryTimeout The number of seconds the driver will wait for execution. + */ + public StatementConfiguration(Integer fetchDirection, Integer fetchSize, Integer maxFieldSize, Integer maxRows, + Integer queryTimeout) { + this.fetchDirection = fetchDirection; + this.fetchSize = fetchSize; + this.maxFieldSize = maxFieldSize; + this.maxRows = maxRows; + this.queryTimeout = queryTimeout; + } + + /** + * Get the fetch direction. + * + * @return The direction to fetch or null if not set. + */ + public Integer getFetchDirection() { + return fetchDirection; + } + + /** + * Whether fetch direction is set. + * + * @return true if set, false otherwise. + */ + public boolean isFetchDirectionSet() { + return fetchDirection != null; + } + + /** + * Get the fetch size. + * + * @return The fetch size or null if not set. + */ + public Integer getFetchSize() { + return fetchSize; + } + + /** + * Whether fetch size is set. + * + * @return true if set, false otherwise. + */ + public boolean isFetchSizeSet() { + return fetchSize != null; + } + + /** + * Get the max field size. + * + * @return The max field size or null if not set. + */ + public Integer getMaxFieldSize() { + return maxFieldSize; + } + + /** + * Whether max field size is set. + * + * @return true if set, false otherwise. + */ + public boolean isMaxFieldSizeSet() { + return maxFieldSize != null; + } + + /** + * Get the max rows. + * + * @return The max rows or null if not set. + */ + public Integer getMaxRows() { + return maxRows; + } + + /** + * Whether max rows is set. + * + * @return true if set, false otherwise. + */ + public boolean isMaxRowsSet() { + return maxRows != null; + } + + /** + * Get the query timeout. + * + * @return The query timeout or null if not set. + */ + public Integer getQueryTimeout() { + return queryTimeout; + } + + /** + * Whether query timeout is set. + * + * @return true if set, false otherwise. + */ + public boolean isQueryTimeoutSet() { + return queryTimeout != null; + } + + /** + * Builder class for <code>StatementConfiguration</code> for more flexible construction. + */ + public static final class Builder { + private Integer fetchDirection; + private Integer fetchSize; + private Integer maxRows; + private Integer queryTimeout; + private Integer maxFieldSize; + + public Builder fetchDirection(final Integer fetchDirection) { + this.fetchDirection = fetchDirection; + return this; + } + + public Builder fetchSize(final Integer fetchSize) { + this.fetchSize = fetchSize; + return this; + } + + public Builder maxRows(final Integer maxRows) { + this.maxRows = maxRows; + return this; + } + + public Builder queryTimeout(final Integer queryTimeout) { + this.queryTimeout = queryTimeout; + return this; + } + + public Builder maxFieldSize(final Integer maxFieldSize) { + this.maxFieldSize = maxFieldSize; + return this; + } + + public StatementConfiguration build() { + return new StatementConfiguration(fetchDirection, fetchSize, maxFieldSize, maxRows, queryTimeout); + } + } +} http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/92c6d6d5/src/test/java/org/apache/commons/dbutils/QueryRunnerTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/dbutils/QueryRunnerTest.java b/src/test/java/org/apache/commons/dbutils/QueryRunnerTest.java index 84a5b0d..73082b4 100644 --- a/src/test/java/org/apache/commons/dbutils/QueryRunnerTest.java +++ b/src/test/java/org/apache/commons/dbutils/QueryRunnerTest.java @@ -519,6 +519,19 @@ public class QueryRunnerTest { callUpdateWithException("unit", "test"); } + @Test + public void testStatementConfiguration() throws Exception { + StatementConfiguration stmtConfig = new StatementConfiguration(1, 2, 3, 4, 5); + QueryRunner queryRunner = new QueryRunner(stmtConfig); + queryRunner.prepareStatement(conn, "select 1"); + + verify(stmt).setFetchDirection(eq(1)); + verify(stmt).setFetchSize(eq(2)); + verify(stmt).setMaxFieldSize(eq(3)); + verify(stmt).setMaxRows(eq(4)); + verify(stmt).setQueryTimeout(eq(5)); + } + // // Random tests // http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/92c6d6d5/src/test/java/org/apache/commons/dbutils/StatementConfigurationTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/dbutils/StatementConfigurationTest.java b/src/test/java/org/apache/commons/dbutils/StatementConfigurationTest.java new file mode 100644 index 0000000..a1524b9 --- /dev/null +++ b/src/test/java/org/apache/commons/dbutils/StatementConfigurationTest.java @@ -0,0 +1,72 @@ +/* + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import org.junit.Test; + +public class StatementConfigurationTest { + /** + * Test that an empty builder yields null values for all configuration settings. + */ + @Test + public void testEmptyBuilder() { + StatementConfiguration config = new StatementConfiguration.Builder().build(); + + assertNull(config.getFetchDirection()); + assertNull(config.getFetchSize()); + assertNull(config.getMaxFieldSize()); + assertNull(config.getMaxRows()); + assertNull(config.getQueryTimeout()); + } + + /** + * Test that a builder with all values set yields like values in the constructed configuration. + */ + @Test + public void testBuilder() { + StatementConfiguration.Builder builder = new StatementConfiguration.Builder() + .fetchDirection(1) + .fetchSize(2) + .maxFieldSize(3) + .maxRows(4) + .queryTimeout(5); + StatementConfiguration config = builder.build(); + + assertEquals(Integer.valueOf(1), config.getFetchDirection()); + assertEquals(Integer.valueOf(2), config.getFetchSize()); + assertEquals(Integer.valueOf(3), config.getMaxFieldSize()); + assertEquals(Integer.valueOf(4), config.getMaxRows()); + assertEquals(Integer.valueOf(5), config.getQueryTimeout()); + } + + /** + * Test that the constructor of <code>StatementConfiguration</code> correctly sets all values. + */ + @Test + public void testConstructor() { + StatementConfiguration config = new StatementConfiguration(1, 2, 3, 4, 5); + + assertEquals(Integer.valueOf(1), config.getFetchDirection()); + assertEquals(Integer.valueOf(2), config.getFetchSize()); + assertEquals(Integer.valueOf(3), config.getMaxFieldSize()); + assertEquals(Integer.valueOf(4), config.getMaxRows()); + assertEquals(Integer.valueOf(5), config.getQueryTimeout()); + } +}
