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-dbcp.git
The following commit(s) were added to refs/heads/master by this push: new 6e86e0d [DBCP-551] org.apache.commons.dbcp2.DelegatingStatement.close() should try to close ALL of its result sets. 6e86e0d is described below commit 6e86e0de00af300293d2182e5395e17f4447f1ab Author: Gary Gregory <gardgreg...@gmail.com> AuthorDate: Tue Jul 30 17:42:32 2019 -0400 [DBCP-551] org.apache.commons.dbcp2.DelegatingStatement.close() should try to close ALL of its result sets. --- src/changes/changes.xml | 3 + .../apache/commons/dbcp2/DelegatingConnection.java | 20 +- .../apache/commons/dbcp2/DelegatingStatement.java | 59 +-- .../org/apache/commons/dbcp2/SQLExceptionList.java | 51 +++ .../commons/dbcp2/TestDelegatingStatement.java | 400 +++++++++++---------- .../apache/commons/dbcp2/TestSQLExceptionList.java | 38 ++ .../org/apache/commons/dbcp2/TesterConnection.java | 3 +- .../commons/dbcp2/TesterPreparedStatement.java | 1 + .../org/apache/commons/dbcp2/TesterResultSet.java | 28 +- .../org/apache/commons/dbcp2/TesterStatement.java | 21 +- 10 files changed, 406 insertions(+), 218 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index cd94f1d..b69108a 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -124,6 +124,9 @@ The <action> type attribute can be add,update,fix,remove. <action dev="ggregory" type="update" due-to="Gary Gregory"> Update tests from org.mockito:mockito-core 2.28.2 to 3.0.0. </action> + <action dev="ggregory" type="update" issue="DBCP-551" due-to="Gary Gregory"> + org.apache.commons.dbcp2.DelegatingStatement.close() should try to close ALL of its result sets. + </action> </release> <release version="2.6.0" date="2019-02-14" description="This is a minor release, including bug fixes and enhancements."> <action dev="chtompki" type="add" issue="DBCP-534" due-to="Peter Wicks"> diff --git a/src/main/java/org/apache/commons/dbcp2/DelegatingConnection.java b/src/main/java/org/apache/commons/dbcp2/DelegatingConnection.java index fe0de9d..2b8853f 100644 --- a/src/main/java/org/apache/commons/dbcp2/DelegatingConnection.java +++ b/src/main/java/org/apache/commons/dbcp2/DelegatingConnection.java @@ -246,7 +246,23 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i } protected void handleException(final SQLException e) throws SQLException { - throw e; + handleException(e, true); + } + + /** + * Rethrows the given {@code SQLException} if {@code rethrow} is true. + * + * @param e The SQLException + * @param rethrow Wether or not to rethrow + * @return the given {@code SQLException} + * @throws SQLException the given {@code SQLException} + * @since 2.7.0 + */ + protected SQLException handleException(final SQLException e, final boolean rethrow) throws SQLException { + if (rethrow) { + throw e; + } + return e; } private void initializeStatement(final DelegatingStatement ds) throws SQLException { @@ -608,7 +624,7 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i // Statement's when it is closed. // DBCP-288. Not all the traced objects will be statements final List<AbandonedTrace> traces = getTrace(); - if (traces != null && traces.size() > 0) { + if (traces != null && !traces.isEmpty()) { final Iterator<AbandonedTrace> traceIter = traces.iterator(); while (traceIter.hasNext()) { final Object trace = traceIter.next(); diff --git a/src/main/java/org/apache/commons/dbcp2/DelegatingStatement.java b/src/main/java/org/apache/commons/dbcp2/DelegatingStatement.java index 8a1725f..88f01e5 100644 --- a/src/main/java/org/apache/commons/dbcp2/DelegatingStatement.java +++ b/src/main/java/org/apache/commons/dbcp2/DelegatingStatement.java @@ -21,6 +21,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.Statement; +import java.util.ArrayList; import java.util.List; /** @@ -125,35 +126,53 @@ public class DelegatingStatement extends AbandonedTrace implements Statement { if (isClosed()) { return; } + final List<SQLException> thrown = new ArrayList<>(); try { - try { - if (connection != null) { - connection.removeTrace(this); - connection = null; - } + if (connection != null) { + connection.removeTrace(this); + connection = null; + } - // The JDBC spec requires that a statement close any open - // ResultSet's when it is closed. - // FIXME The PreparedStatement we're wrapping should handle this for us. - // See bug 17301 for what could happen when ResultSets are closed twice. - final List<AbandonedTrace> resultSets = getTrace(); - if (resultSets != null) { - final ResultSet[] set = resultSets.toArray(new ResultSet[resultSets.size()]); - for (final ResultSet element : set) { - element.close(); + // The JDBC spec requires that a statement close any open + // ResultSet's when it is closed. + // FIXME The PreparedStatement we're wrapping should handle this for us. + // See bug 17301 for what could happen when ResultSets are closed twice. + final List<AbandonedTrace> resultSetList = getTrace(); + if (resultSetList != null) { + final int size = resultSetList.size(); + final ResultSet[] resultSets = resultSetList.toArray(new ResultSet[size]); + for (final ResultSet resultSet : resultSets) { + if (resultSet != null) { + try { + resultSet.close(); + } catch (SQLException e) { + if (connection != null) { + // Does not rethrow e. + connection.handleException(e, false); + } + thrown.add(e); + } } - clearTrace(); } - - if (statement != null) { + clearTrace(); + } + if (statement != null) { + try { statement.close(); + } catch (SQLException e) { + if (connection != null) { + // Does not rethrow e. + connection.handleException(e, false); + } + thrown.add(e); } - } catch (final SQLException e) { - handleException(e); } } finally { closed = true; statement = null; + if (!thrown.isEmpty()) { + throw new SQLExceptionList(thrown); + } } } @@ -615,7 +634,7 @@ public class DelegatingStatement extends AbandonedTrace implements Statement { } /* - * Note was protected prior to JDBC 4 + * Note: This method was protected prior to JDBC 4. */ @Override public boolean isClosed() throws SQLException { diff --git a/src/main/java/org/apache/commons/dbcp2/SQLExceptionList.java b/src/main/java/org/apache/commons/dbcp2/SQLExceptionList.java new file mode 100644 index 0000000..1df9356 --- /dev/null +++ b/src/main/java/org/apache/commons/dbcp2/SQLExceptionList.java @@ -0,0 +1,51 @@ +/* + * 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.dbcp2; + +import java.sql.SQLException; +import java.util.List; + +/** + * A SQLException based on a list of SQLException causes. + * <p> + * The first exception in the list is used as this exception's cause and is accessible with the usual + * {@link #getCause()} while the complete list is accessible with {@link #getCauseList()}. + * </p> + * + * @since 2.7.0 + */ +public class SQLExceptionList extends SQLException { + + private static final long serialVersionUID = 1L; + private final List<? extends SQLException> causeList; + + /** + * Creates a new exception caused by a list of exceptions. + * + * @param causeList a list of cause exceptions. + */ + public SQLExceptionList(List<? extends SQLException> causeList) { + super(String.format("%,d SQLExceptions: %s", causeList.size(), causeList), causeList.get(0)); + this.causeList = causeList; + } + + public List<? extends SQLException> getCauseList() { + return causeList; + } + +} diff --git a/src/test/java/org/apache/commons/dbcp2/TestDelegatingStatement.java b/src/test/java/org/apache/commons/dbcp2/TestDelegatingStatement.java index f9867f8..f187cbf 100644 --- a/src/test/java/org/apache/commons/dbcp2/TestDelegatingStatement.java +++ b/src/test/java/org/apache/commons/dbcp2/TestDelegatingStatement.java @@ -28,43 +28,71 @@ import static org.mockito.Mockito.verify; import java.lang.reflect.Proxy; import java.sql.Connection; +import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class TestDelegatingStatement { - private DelegatingConnection<Connection> conn = null; - private Connection delegateConn = null; - private Statement obj = null; - private DelegatingStatement delegate = null; + private static class TesterStatementNonWrapping extends TesterStatement { + + public TesterStatementNonWrapping(final Connection conn) { + super(conn); + } + + @Override + public boolean isWrapperFor(final Class<?> iface) throws SQLException { + return false; + } + } + + private DelegatingConnection<Connection> delegatingConnection; + private TesterConnection testerConnection; + private Statement mockedStatement; + private DelegatingStatement delegatingStatement; + private DelegatingStatement delegatingTesterStatement; + private TesterResultSet testerResultSet; + private TesterStatement testerStatement; @BeforeEach public void setUp() throws Exception { - delegateConn = new TesterConnection("test", "test"); - conn = new DelegatingConnection<>(delegateConn); - obj = mock(Statement.class); - delegate = new DelegatingStatement(conn, obj); + testerConnection = new TesterConnection("test", "test"); + delegatingConnection = new DelegatingConnection<>(testerConnection); + mockedStatement = mock(Statement.class); + testerStatement = new TesterStatement(testerConnection); + delegatingStatement = new DelegatingStatement(delegatingConnection, mockedStatement); + delegatingTesterStatement = new DelegatingStatement(delegatingConnection, testerStatement); + testerResultSet = new TesterResultSet(mockedStatement); } @Test - public void testExecuteQueryReturnsNull() throws Exception { - assertNull(delegate.executeQuery("null")); + public void testAddBatchString() throws Exception { + try { + delegatingStatement.addBatch("foo"); + } catch (final SQLException e) { + } + verify(mockedStatement, times(1)).addBatch("foo"); } @Test - public void testGetDelegate() throws Exception { - assertEquals(obj,delegate.getDelegate()); + public void testCancel() throws Exception { + try { + delegatingStatement.cancel(); + } catch (final SQLException e) { + } + verify(mockedStatement, times(1)).cancel(); } @Test public void testCheckOpen() throws Exception { - delegate.checkOpen(); - delegate.close(); + delegatingStatement.checkOpen(); + delegatingStatement.close(); try { - delegate.checkOpen(); + delegatingStatement.checkOpen(); fail("Expecting SQLException"); } catch (final SQLException ex) { // expected @@ -72,222 +100,207 @@ public class TestDelegatingStatement { } @Test - public void testIsWrapperFor() throws Exception { - final TesterConnection tstConn = new TesterConnection("test", "test"); - final TesterStatement tstStmt = new TesterStatementNonWrapping(tstConn); - final DelegatingConnection<TesterConnection> dconn = new DelegatingConnection<>(tstConn); - final DelegatingStatement stamt = new DelegatingStatement(dconn, tstStmt); - - final Class<?> stmtProxyClass = Proxy.getProxyClass( - this.getClass().getClassLoader(), - Statement.class); - - assertTrue(stamt.isWrapperFor(DelegatingStatement.class)); - assertTrue(stamt.isWrapperFor(TesterStatement.class)); - assertFalse(stamt.isWrapperFor(stmtProxyClass)); - - stamt.close(); - } - - private static class TesterStatementNonWrapping extends TesterStatement { - - public TesterStatementNonWrapping(final Connection conn) { - super(conn); - } - - @Override - public boolean isWrapperFor(final Class<?> iface) throws SQLException { - return false; - } - } - - @Test - public void testAddBatchString() throws Exception { + public void testClearBatch() throws Exception { try { - delegate.addBatch("foo"); + delegatingStatement.clearBatch(); } catch (final SQLException e) { } - verify(obj, times(1)).addBatch("foo"); + verify(mockedStatement, times(1)).clearBatch(); } @Test - public void testCancel() throws Exception { + public void testClearWarnings() throws Exception { try { - delegate.cancel(); + delegatingStatement.clearWarnings(); } catch (final SQLException e) { } - verify(obj, times(1)).cancel(); + verify(mockedStatement, times(1)).clearWarnings(); } @Test - public void testClearBatch() throws Exception { + public void testClose() throws Exception { try { - delegate.clearBatch(); + delegatingStatement.close(); } catch (final SQLException e) { } - verify(obj, times(1)).clearBatch(); + verify(mockedStatement, times(1)).close(); } @Test - public void testClearWarnings() throws Exception { + public void testCloseWithResultSetCloseException() throws Exception { try { - delegate.clearWarnings(); + testerResultSet.setSqlExceptionOnClose(true); + delegatingStatement.addTrace(testerResultSet); + delegatingStatement.close(); + Assertions.fail("Excpected a SQLExceptionList"); } catch (final SQLException e) { + Assertions.assertTrue(e instanceof SQLExceptionList); + } finally { + testerResultSet.setSqlExceptionOnClose(false); } - verify(obj, times(1)).clearWarnings(); + verify(mockedStatement, times(1)).close(); } @Test - public void testClose() throws Exception { + public void testCloseWithStatementCloseException() throws Exception { try { - delegate.close(); + testerStatement.setSqlExceptionOnClose(true); + delegatingTesterStatement.close(); + Assertions.fail("Excpected a SQLExceptionList"); } catch (final SQLException e) { + Assertions.assertTrue(e instanceof SQLExceptionList); + } finally { + testerStatement.setSqlExceptionOnClose(false); } - verify(obj, times(1)).close(); } @Test public void testCloseOnCompletion() throws Exception { try { - delegate.closeOnCompletion(); + delegatingStatement.closeOnCompletion(); } catch (final SQLException e) { } - verify(obj, times(1)).closeOnCompletion(); + verify(mockedStatement, times(1)).closeOnCompletion(); } @Test - public void testExecuteStringIntegerArray() throws Exception { + public void testExecuteBatch() throws Exception { try { - delegate.execute("foo", (int[]) null); + delegatingStatement.executeBatch(); } catch (final SQLException e) { } - verify(obj, times(1)).execute("foo", (int[]) null); + verify(mockedStatement, times(1)).executeBatch(); } @Test - public void testExecuteString() throws Exception { + public void testExecuteLargeBatch() throws Exception { try { - delegate.execute("foo"); + delegatingStatement.executeLargeBatch(); } catch (final SQLException e) { } - verify(obj, times(1)).execute("foo"); + verify(mockedStatement, times(1)).executeLargeBatch(); } @Test - public void testExecuteStringStringArray() throws Exception { + public void testExecuteLargeUpdateString() throws Exception { try { - delegate.execute("foo", (String[]) null); + delegatingStatement.executeLargeUpdate("foo"); } catch (final SQLException e) { } - verify(obj, times(1)).execute("foo", (String[]) null); + verify(mockedStatement, times(1)).executeLargeUpdate("foo"); } @Test - public void testExecuteStringInteger() throws Exception { + public void testExecuteLargeUpdateStringInteger() throws Exception { try { - delegate.execute("foo", 1); + delegatingStatement.executeLargeUpdate("foo", 1); } catch (final SQLException e) { } - verify(obj, times(1)).execute("foo", 1); + verify(mockedStatement, times(1)).executeLargeUpdate("foo", 1); } @Test - public void testExecuteBatch() throws Exception { + public void testExecuteLargeUpdateStringIntegerArray() throws Exception { try { - delegate.executeBatch(); + delegatingStatement.executeLargeUpdate("foo", (int[]) null); } catch (final SQLException e) { } - verify(obj, times(1)).executeBatch(); + verify(mockedStatement, times(1)).executeLargeUpdate("foo", (int[]) null); } @Test - public void testExecuteLargeBatch() throws Exception { + public void testExecuteLargeUpdateStringStringArray() throws Exception { try { - delegate.executeLargeBatch(); + delegatingStatement.executeLargeUpdate("foo", (String[]) null); } catch (final SQLException e) { } - verify(obj, times(1)).executeLargeBatch(); + verify(mockedStatement, times(1)).executeLargeUpdate("foo", (String[]) null); } @Test - public void testExecuteLargeUpdateStringInteger() throws Exception { + public void testExecuteQueryReturnsNull() throws Exception { + assertNull(delegatingStatement.executeQuery("null")); + } + + @Test + public void testExecuteQueryString() throws Exception { try { - delegate.executeLargeUpdate("foo", 1); + delegatingStatement.executeQuery("foo"); } catch (final SQLException e) { } - verify(obj, times(1)).executeLargeUpdate("foo", 1); + verify(mockedStatement, times(1)).executeQuery("foo"); } @Test - public void testExecuteLargeUpdateStringIntegerArray() throws Exception { + public void testExecuteString() throws Exception { try { - delegate.executeLargeUpdate("foo", (int[]) null); + delegatingStatement.execute("foo"); } catch (final SQLException e) { } - verify(obj, times(1)).executeLargeUpdate("foo", (int[]) null); + verify(mockedStatement, times(1)).execute("foo"); } @Test - public void testExecuteLargeUpdateString() throws Exception { + public void testExecuteStringInteger() throws Exception { try { - delegate.executeLargeUpdate("foo"); + delegatingStatement.execute("foo", 1); } catch (final SQLException e) { } - verify(obj, times(1)).executeLargeUpdate("foo"); + verify(mockedStatement, times(1)).execute("foo", 1); } @Test - public void testExecuteLargeUpdateStringStringArray() throws Exception { + public void testExecuteStringIntegerArray() throws Exception { try { - delegate.executeLargeUpdate("foo", (String[]) null); + delegatingStatement.execute("foo", (int[]) null); } catch (final SQLException e) { } - verify(obj, times(1)).executeLargeUpdate("foo", (String[]) null); + verify(mockedStatement, times(1)).execute("foo", (int[]) null); } @Test - public void testExecuteQueryString() throws Exception { + public void testExecuteStringStringArray() throws Exception { try { - delegate.executeQuery("foo"); + delegatingStatement.execute("foo", (String[]) null); } catch (final SQLException e) { } - verify(obj, times(1)).executeQuery("foo"); + verify(mockedStatement, times(1)).execute("foo", (String[]) null); } @Test - public void testExecuteUpdateStringIntegerArray() throws Exception { + public void testExecuteUpdateString() throws Exception { try { - delegate.executeUpdate("foo", (int[]) null); + delegatingStatement.executeUpdate("foo"); } catch (final SQLException e) { } - verify(obj, times(1)).executeUpdate("foo", (int[]) null); + verify(mockedStatement, times(1)).executeUpdate("foo"); } @Test - public void testExecuteUpdateStringStringArray() throws Exception { + public void testExecuteUpdateStringInteger() throws Exception { try { - delegate.executeUpdate("foo", (String[]) null); + delegatingStatement.executeUpdate("foo", 1); } catch (final SQLException e) { } - verify(obj, times(1)).executeUpdate("foo", (String[]) null); + verify(mockedStatement, times(1)).executeUpdate("foo", 1); } @Test - public void testExecuteUpdateString() throws Exception { + public void testExecuteUpdateStringIntegerArray() throws Exception { try { - delegate.executeUpdate("foo"); + delegatingStatement.executeUpdate("foo", (int[]) null); } catch (final SQLException e) { } - verify(obj, times(1)).executeUpdate("foo"); + verify(mockedStatement, times(1)).executeUpdate("foo", (int[]) null); } @Test - public void testExecuteUpdateStringInteger() throws Exception { + public void testExecuteUpdateStringStringArray() throws Exception { try { - delegate.executeUpdate("foo", 1); + delegatingStatement.executeUpdate("foo", (String[]) null); } catch (final SQLException e) { } - verify(obj, times(1)).executeUpdate("foo", 1); + verify(mockedStatement, times(1)).executeUpdate("foo", (String[]) null); } /** @@ -299,163 +312,159 @@ public class TestDelegatingStatement { @Test public void testGetConnection() throws Exception { try { - delegate.getConnection(); + delegatingStatement.getConnection(); } catch (final SQLException e) { } - verify(obj, times(0)).getConnection(); + verify(mockedStatement, times(0)).getConnection(); + } + + @Test + public void testGetDelegate() throws Exception { + assertEquals(mockedStatement,delegatingStatement.getDelegate()); } @Test public void testGetFetchDirection() throws Exception { try { - delegate.getFetchDirection(); + delegatingStatement.getFetchDirection(); } catch (final SQLException e) { } - verify(obj, times(1)).getFetchDirection(); + verify(mockedStatement, times(1)).getFetchDirection(); } @Test public void testGetFetchSize() throws Exception { try { - delegate.getFetchSize(); + delegatingStatement.getFetchSize(); } catch (final SQLException e) { } - verify(obj, times(1)).getFetchSize(); + verify(mockedStatement, times(1)).getFetchSize(); } @Test public void testGetGeneratedKeys() throws Exception { try { - delegate.getGeneratedKeys(); + delegatingStatement.getGeneratedKeys(); } catch (final SQLException e) { } - verify(obj, times(1)).getGeneratedKeys(); + verify(mockedStatement, times(1)).getGeneratedKeys(); } @Test public void testGetLargeMaxRows() throws Exception { try { - delegate.getLargeMaxRows(); + delegatingStatement.getLargeMaxRows(); } catch (final SQLException e) { } - verify(obj, times(1)).getLargeMaxRows(); + verify(mockedStatement, times(1)).getLargeMaxRows(); } @Test public void testGetLargeUpdateCount() throws Exception { try { - delegate.getLargeUpdateCount(); + delegatingStatement.getLargeUpdateCount(); } catch (final SQLException e) { } - verify(obj, times(1)).getLargeUpdateCount(); + verify(mockedStatement, times(1)).getLargeUpdateCount(); } @Test public void testGetMaxFieldSize() throws Exception { try { - delegate.getMaxFieldSize(); + delegatingStatement.getMaxFieldSize(); } catch (final SQLException e) { } - verify(obj, times(1)).getMaxFieldSize(); + verify(mockedStatement, times(1)).getMaxFieldSize(); } @Test public void testGetMaxRows() throws Exception { try { - delegate.getMaxRows(); + delegatingStatement.getMaxRows(); } catch (final SQLException e) { } - verify(obj, times(1)).getMaxRows(); + verify(mockedStatement, times(1)).getMaxRows(); } @Test - public void testGetMoreResultsInteger() throws Exception { + public void testGetMoreResults() throws Exception { try { - delegate.getMoreResults(1); + delegatingStatement.getMoreResults(); } catch (final SQLException e) { } - verify(obj, times(1)).getMoreResults(1); + verify(mockedStatement, times(1)).getMoreResults(); } @Test - public void testGetMoreResults() throws Exception { + public void testGetMoreResultsInteger() throws Exception { try { - delegate.getMoreResults(); + delegatingStatement.getMoreResults(1); } catch (final SQLException e) { } - verify(obj, times(1)).getMoreResults(); + verify(mockedStatement, times(1)).getMoreResults(1); } @Test public void testGetQueryTimeout() throws Exception { try { - delegate.getQueryTimeout(); + delegatingStatement.getQueryTimeout(); } catch (final SQLException e) { } - verify(obj, times(1)).getQueryTimeout(); + verify(mockedStatement, times(1)).getQueryTimeout(); } @Test public void testGetResultSet() throws Exception { try { - delegate.getResultSet(); + delegatingStatement.getResultSet(); } catch (final SQLException e) { } - verify(obj, times(1)).getResultSet(); + verify(mockedStatement, times(1)).getResultSet(); } @Test public void testGetResultSetConcurrency() throws Exception { try { - delegate.getResultSetConcurrency(); + delegatingStatement.getResultSetConcurrency(); } catch (final SQLException e) { } - verify(obj, times(1)).getResultSetConcurrency(); + verify(mockedStatement, times(1)).getResultSetConcurrency(); } @Test public void testGetResultSetHoldability() throws Exception { try { - delegate.getResultSetHoldability(); + delegatingStatement.getResultSetHoldability(); } catch (final SQLException e) { } - verify(obj, times(1)).getResultSetHoldability(); + verify(mockedStatement, times(1)).getResultSetHoldability(); } @Test public void testGetResultSetType() throws Exception { try { - delegate.getResultSetType(); + delegatingStatement.getResultSetType(); } catch (final SQLException e) { } - verify(obj, times(1)).getResultSetType(); + verify(mockedStatement, times(1)).getResultSetType(); } @Test public void testGetUpdateCount() throws Exception { try { - delegate.getUpdateCount(); + delegatingStatement.getUpdateCount(); } catch (final SQLException e) { } - verify(obj, times(1)).getUpdateCount(); + verify(mockedStatement, times(1)).getUpdateCount(); } @Test public void testGetWarnings() throws Exception { try { - delegate.getWarnings(); + delegatingStatement.getWarnings(); } catch (final SQLException e) { } - verify(obj, times(1)).getWarnings(); - } - - @Test - public void testIsCloseOnCompletion() throws Exception { - try { - delegate.isCloseOnCompletion(); - } catch (final SQLException e) { - } - verify(obj, times(1)).isCloseOnCompletion(); + verify(mockedStatement, times(1)).getWarnings(); } /** @@ -467,111 +476,138 @@ public class TestDelegatingStatement { @Test public void testIsClosed() throws Exception { try { - delegate.isClosed(); + delegatingStatement.isClosed(); } catch (final SQLException e) { } - verify(obj, times(0)).isClosed(); + verify(mockedStatement, times(0)).isClosed(); + } + + @Test + public void testIsCloseOnCompletion() throws Exception { + try { + delegatingStatement.isCloseOnCompletion(); + } catch (final SQLException e) { + } + verify(mockedStatement, times(1)).isCloseOnCompletion(); } @Test public void testIsPoolable() throws Exception { try { - delegate.isPoolable(); + delegatingStatement.isPoolable(); } catch (final SQLException e) { } - verify(obj, times(1)).isPoolable(); + verify(mockedStatement, times(1)).isPoolable(); + } + + @Test + public void testIsWrapperFor() throws Exception { + final TesterConnection tstConn = new TesterConnection("test", "test"); + final TesterStatement tstStmt = new TesterStatementNonWrapping(tstConn); + final DelegatingConnection<TesterConnection> dconn = new DelegatingConnection<>(tstConn); + final DelegatingStatement stamt = new DelegatingStatement(dconn, tstStmt); + + final Class<?> stmtProxyClass = Proxy.getProxyClass( + this.getClass().getClassLoader(), + Statement.class); + + assertTrue(stamt.isWrapperFor(DelegatingStatement.class)); + assertTrue(stamt.isWrapperFor(TesterStatement.class)); + assertFalse(stamt.isWrapperFor(stmtProxyClass)); + + stamt.close(); } @Test public void testSetCursorNameString() throws Exception { try { - delegate.setCursorName("foo"); + delegatingStatement.setCursorName("foo"); } catch (final SQLException e) { } - verify(obj, times(1)).setCursorName("foo"); + verify(mockedStatement, times(1)).setCursorName("foo"); } @Test public void testSetEscapeProcessingBoolean() throws Exception { try { - delegate.setEscapeProcessing(Boolean.TRUE); + delegatingStatement.setEscapeProcessing(Boolean.TRUE); } catch (final SQLException e) { } - verify(obj, times(1)).setEscapeProcessing(Boolean.TRUE); + verify(mockedStatement, times(1)).setEscapeProcessing(Boolean.TRUE); } @Test public void testSetFetchDirectionInteger() throws Exception { try { - delegate.setFetchDirection(1); + delegatingStatement.setFetchDirection(1); } catch (final SQLException e) { } - verify(obj, times(1)).setFetchDirection(1); + verify(mockedStatement, times(1)).setFetchDirection(1); } @Test public void testSetFetchSizeInteger() throws Exception { try { - delegate.setFetchSize(1); + delegatingStatement.setFetchSize(1); } catch (final SQLException e) { } - verify(obj, times(1)).setFetchSize(1); + verify(mockedStatement, times(1)).setFetchSize(1); } @Test public void testSetLargeMaxRowsLong() throws Exception { try { - delegate.setLargeMaxRows(1l); + delegatingStatement.setLargeMaxRows(1l); } catch (final SQLException e) { } - verify(obj, times(1)).setLargeMaxRows(1l); + verify(mockedStatement, times(1)).setLargeMaxRows(1l); } @Test public void testSetMaxFieldSizeInteger() throws Exception { try { - delegate.setMaxFieldSize(1); + delegatingStatement.setMaxFieldSize(1); } catch (final SQLException e) { } - verify(obj, times(1)).setMaxFieldSize(1); + verify(mockedStatement, times(1)).setMaxFieldSize(1); } @Test public void testSetMaxRowsInteger() throws Exception { try { - delegate.setMaxRows(1); + delegatingStatement.setMaxRows(1); } catch (final SQLException e) { } - verify(obj, times(1)).setMaxRows(1); + verify(mockedStatement, times(1)).setMaxRows(1); } @Test public void testSetPoolableBoolean() throws Exception { try { - delegate.setPoolable(Boolean.TRUE); + delegatingStatement.setPoolable(Boolean.TRUE); } catch (final SQLException e) { } - verify(obj, times(1)).setPoolable(Boolean.TRUE); + verify(mockedStatement, times(1)).setPoolable(Boolean.TRUE); } @Test public void testSetQueryTimeoutInteger() throws Exception { try { - delegate.setQueryTimeout(1); + delegatingStatement.setQueryTimeout(1); } catch (final SQLException e) { } - verify(obj, times(1)).setQueryTimeout(1); + verify(mockedStatement, times(1)).setQueryTimeout(1); } @Test public void testWrap() throws SQLException { - assertEquals(delegate, delegate.unwrap(Statement.class)); - assertEquals(delegate, delegate.unwrap(DelegatingStatement.class)); - assertEquals(obj, delegate.unwrap(obj.getClass())); - assertNull(delegate.unwrap(String.class)); - assertTrue(delegate.isWrapperFor(Statement.class)); - assertTrue(delegate.isWrapperFor(DelegatingStatement.class)); - assertTrue(delegate.isWrapperFor(obj.getClass())); - assertFalse(delegate.isWrapperFor(String.class)); + assertEquals(delegatingStatement, delegatingStatement.unwrap(Statement.class)); + assertEquals(delegatingStatement, delegatingStatement.unwrap(DelegatingStatement.class)); + assertEquals(mockedStatement, delegatingStatement.unwrap(mockedStatement.getClass())); + assertNull(delegatingStatement.unwrap(String.class)); + assertTrue(delegatingStatement.isWrapperFor(Statement.class)); + assertTrue(delegatingStatement.isWrapperFor(DelegatingStatement.class)); + assertTrue(delegatingStatement.isWrapperFor(mockedStatement.getClass())); + assertFalse(delegatingStatement.isWrapperFor(String.class)); } } diff --git a/src/test/java/org/apache/commons/dbcp2/TestSQLExceptionList.java b/src/test/java/org/apache/commons/dbcp2/TestSQLExceptionList.java new file mode 100644 index 0000000..ebb0bd8 --- /dev/null +++ b/src/test/java/org/apache/commons/dbcp2/TestSQLExceptionList.java @@ -0,0 +1,38 @@ +/* + * 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.dbcp2; + +import java.sql.SQLTransientException; +import java.util.Collections; +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestSQLExceptionList { + + @Test + public void testCause() { + final SQLTransientException cause = new SQLTransientException(); + final List<SQLTransientException> list = Collections.singletonList(cause); + final SQLExceptionList sqlExceptionList = new SQLExceptionList(list); + Assertions.assertEquals(cause, sqlExceptionList.getCause()); + Assertions.assertEquals(list, sqlExceptionList.getCauseList()); + sqlExceptionList.printStackTrace(); + } +} diff --git a/src/test/java/org/apache/commons/dbcp2/TesterConnection.java b/src/test/java/org/apache/commons/dbcp2/TesterConnection.java index 4329b1f..dae4380 100644 --- a/src/test/java/org/apache/commons/dbcp2/TesterConnection.java +++ b/src/test/java/org/apache/commons/dbcp2/TesterConnection.java @@ -38,7 +38,8 @@ import java.util.concurrent.Executor; /** * A dummy {@link Connection}, for testing purposes. */ -public class TesterConnection implements Connection { +public class TesterConnection extends AbandonedTrace implements Connection { + protected boolean _open = true; protected boolean _autoCommit = true; protected int _transactionIsolation = 1; diff --git a/src/test/java/org/apache/commons/dbcp2/TesterPreparedStatement.java b/src/test/java/org/apache/commons/dbcp2/TesterPreparedStatement.java index 5883cb8..5ee864d 100644 --- a/src/test/java/org/apache/commons/dbcp2/TesterPreparedStatement.java +++ b/src/test/java/org/apache/commons/dbcp2/TesterPreparedStatement.java @@ -39,6 +39,7 @@ import java.sql.SQLXML; * A dummy {@link PreparedStatement}, for testing purposes. */ public class TesterPreparedStatement extends TesterStatement implements PreparedStatement { + private final ResultSetMetaData _resultSetMetaData = null; private String _sql = null; private String _catalog = null; diff --git a/src/test/java/org/apache/commons/dbcp2/TesterResultSet.java b/src/test/java/org/apache/commons/dbcp2/TesterResultSet.java index afc4c1e..0d37499 100644 --- a/src/test/java/org/apache/commons/dbcp2/TesterResultSet.java +++ b/src/test/java/org/apache/commons/dbcp2/TesterResultSet.java @@ -40,18 +40,16 @@ import java.sql.SQLXML; /** * A dummy {@link ResultSet}, for testing purposes. */ -public class TesterResultSet implements ResultSet { +public class TesterResultSet extends AbandonedTrace implements ResultSet { + protected int _type = ResultSet.TYPE_FORWARD_ONLY; - protected int _concurrency = ResultSet.CONCUR_READ_ONLY; - protected Object[][] _data = null; - protected int _currentRow = -1; protected Statement _statement = null; - protected int _rowsLeft = 2; protected boolean _open = true; + protected boolean _sqlExceptionOnClose = false; public TesterResultSet(final Statement stmt) { _statement = stmt; @@ -101,6 +99,10 @@ public class TesterResultSet implements ResultSet { @Override public void close() throws SQLException { + if (_sqlExceptionOnClose) { + throw new SQLException("TestSQLExceptionOnClose"); + } + if (!_open) { return; } @@ -641,6 +643,10 @@ public java.sql.Date getDate(final int columnIndex, final Calendar cal) throws S return _rowsLeft == 0; } + public boolean isSqlExceptionOnClose() { + return _sqlExceptionOnClose; + } + @Override public boolean isWrapperFor(final Class<?> iface) throws SQLException { throw new SQLException("Not implemented."); @@ -720,6 +726,10 @@ public java.sql.Date getDate(final int columnIndex, final Calendar cal) throws S checkOpen(); } + public void setSqlExceptionOnClose(final boolean sqlExceptionOnClose) { + this._sqlExceptionOnClose = sqlExceptionOnClose; + } + @Override public <T> T unwrap(final Class<T> iface) throws SQLException { throw new SQLException("Not implemented."); @@ -742,6 +752,7 @@ public java.sql.Date getDate(final int columnIndex, final Calendar cal) throws S throw new SQLException("Not implemented."); } + @Override public void updateAsciiStream(final int columnIndex, final InputStream inputStream, final long length) throws SQLException { throw new SQLException("Not implemented."); @@ -754,7 +765,6 @@ public java.sql.Date getDate(final int columnIndex, final Calendar cal) throws S checkOpen(); } - @Override public void updateAsciiStream(final String columnLabel, final InputStream inputStream) throws SQLException { throw new SQLException("Not implemented."); @@ -890,6 +900,7 @@ public java.sql.Date getDate(final int columnIndex, final Calendar cal) throws S throw new SQLException("Not implemented."); } + @Override public void updateCharacterStream(final int columnIndex, final Reader reader, final long length) throws SQLException { throw new SQLException("Not implemented."); @@ -902,7 +913,6 @@ public java.sql.Date getDate(final int columnIndex, final Calendar cal) throws S checkOpen(); } - @Override public void updateCharacterStream(final String columnLabel, final Reader reader) throws SQLException { throw new SQLException("Not implemented."); @@ -1175,13 +1185,13 @@ public java.sql.Date getDate(final int columnIndex, final Calendar cal) throws S public void updateTimestamp(final int columnIndex, final java.sql.Timestamp x) throws SQLException { checkOpen(); } - + @Override public void updateTimestamp(final String columnName, final java.sql.Timestamp x) throws SQLException { checkOpen(); } - + @Override public boolean wasNull() throws SQLException { checkOpen(); diff --git a/src/test/java/org/apache/commons/dbcp2/TesterStatement.java b/src/test/java/org/apache/commons/dbcp2/TesterStatement.java index 99cc9f9..5a70f64 100644 --- a/src/test/java/org/apache/commons/dbcp2/TesterStatement.java +++ b/src/test/java/org/apache/commons/dbcp2/TesterStatement.java @@ -26,13 +26,11 @@ import java.sql.Statement; /** * A dummy {@link Statement}, for testing purposes. */ -public class TesterStatement implements Statement { +public class TesterStatement extends AbandonedTrace implements Statement { + protected Connection _connection = null; - protected boolean _open = true; - protected long _rowsUpdated = 1; - protected boolean _executeResponse = true; protected int _maxFieldSize = 1024; protected long _maxRows = 1024; @@ -45,15 +43,18 @@ public class TesterStatement implements Statement { protected int _resultSetType = 1; private int _resultSetHoldability = 1; protected ResultSet _resultSet = null; + protected boolean _sqlExceptionOnClose = false; public TesterStatement(final Connection conn) { _connection = conn; } + public TesterStatement(final Connection conn, final int resultSetType, final int resultSetConcurrency) { _connection = conn; _resultSetType = resultSetType; _resultSetConcurrency = resultSetConcurrency; } + public TesterStatement(final Connection conn, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) { _connection = conn; @@ -90,6 +91,10 @@ public class TesterStatement implements Statement { @Override public void close() throws SQLException { + if (_sqlExceptionOnClose) { + throw new SQLException("TestSQLExceptionOnClose"); + } + // calling close twice has no effect if (!_open) { return; @@ -331,6 +336,10 @@ public class TesterStatement implements Statement { throw new SQLException("Not implemented."); } + public boolean isSqlExceptionOnClose() { + return _sqlExceptionOnClose; + } + @Override public boolean isWrapperFor(final Class<?> iface) throws SQLException { throw new SQLException("Not implemented."); @@ -389,6 +398,10 @@ public class TesterStatement implements Statement { _queryTimeout = seconds; } + public void setSqlExceptionOnClose(final boolean _sqlExceptionOnClose) { + this._sqlExceptionOnClose = _sqlExceptionOnClose; + } + @Override public <T> T unwrap(final Class<T> iface) throws SQLException { throw new SQLException("Not implemented.");