From 935e6e502dc8525c3449870458b1a5994c62f350 Mon Sep 17 00:00:00 2001 From: Kris Jurka Date: Tue, 24 Feb 2004 13:11:45 +0000 Subject: [PATCH] Closing a Connection or Statement object twice should be a no-op instead of throwing an Exception. Per report from Victor Sergienko. --- .../jdbc1/AbstractJdbc1Statement.java | 9 ++++++- .../jdbc2/optional/PooledConnectionImpl.java | 21 +++++++++++----- .../postgresql/test/jdbc2/ConnectionTest.java | 12 ++++++++- .../jdbc2/optional/ConnectionPoolTest.java | 16 ++---------- .../jdbc2/optional/PoolingDataSourceTest.java | 25 ++++++++++++++++++- 5 files changed, 60 insertions(+), 23 deletions(-) diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java index 50c214a30d..0addc9e47f 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java @@ -26,7 +26,7 @@ import java.sql.Timestamp; import java.sql.Types; import java.util.Vector; -/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.41.2.3 2004/02/03 05:13:55 jurka Exp $ +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.41.2.4 2004/02/24 13:11:44 jurka Exp $ * This class defines methods of the jdbc1 specification. This class is * extended by org.postgresql.jdbc2.AbstractJdbc2Statement which adds the jdbc2 * methods. The real Statement class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Statement @@ -84,6 +84,8 @@ public abstract class AbstractJdbc1Statement implements BaseStatement private boolean m_useServerPrepare = false; + private boolean isClosed = false; + // m_preparedCount is used for naming of auto-cursors and must // be synchronized so that multiple threads using the same // connection don't stomp over each others cursors. @@ -785,6 +787,10 @@ public abstract class AbstractJdbc1Statement implements BaseStatement */ public void close() throws SQLException { + // closing an already closed Statement is a no-op. + if (isClosed) + return; + // Force the ResultSet to close java.sql.ResultSet rs = getResultSet(); if (rs != null) @@ -794,6 +800,7 @@ public abstract class AbstractJdbc1Statement implements BaseStatement // Disasociate it from us (For Garbage Collection) result = null; + isClosed = true; } /** diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/optional/PooledConnectionImpl.java b/src/interfaces/jdbc/org/postgresql/jdbc2/optional/PooledConnectionImpl.java index a8be118d08..5047a956f2 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/optional/PooledConnectionImpl.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/optional/PooledConnectionImpl.java @@ -14,7 +14,7 @@ import org.postgresql.PGConnection; * * @author Aaron Mulder (ammulder@chariotsolutions.com) * @author Csaba Nagy (ncsaba@yahoo.com) - * @version $Revision: 1.7.4.2 $ + * @version $Revision: 1.7.4.3 $ */ public class PooledConnectionImpl implements PooledConnection { @@ -234,12 +234,17 @@ public class PooledConnectionImpl implements PooledConnection { return con == null ? Boolean.TRUE : Boolean.FALSE; } - if (con == null) + if (con == null && !method.getName().equals("close")) { throw new SQLException(automatic ? "Connection has been closed automatically because a new connection was opened for the same PooledConnection or the PooledConnection has been closed" : "Connection has been closed"); } if (method.getName().equals("close")) { + // we are already closed and a double close + // is not an error. + if (con == null) + return null; + SQLException ex = null; if (!con.getAutoCommit()) { @@ -358,12 +363,12 @@ public class PooledConnectionImpl implements PooledConnection return method.invoke(st, args); } // All the rest is from the Statement interface - if (st == null || con.isClosed()) - { - throw new SQLException("Statement has been closed"); - } if (method.getName().equals("close")) { + // closing an already closed object is a no-op + if (st == null || con.isClosed()) + return null; + try { st.close(); } finally { @@ -372,6 +377,10 @@ public class PooledConnectionImpl implements PooledConnection } return null; } + if (st == null || con.isClosed()) + { + throw new SQLException("Statement has been closed"); + } else if (method.getName().equals("getConnection")) { return con.getProxy(); // the proxied connection, not a physical connection diff --git a/src/interfaces/jdbc/org/postgresql/test/jdbc2/ConnectionTest.java b/src/interfaces/jdbc/org/postgresql/test/jdbc2/ConnectionTest.java index 1d79463eb1..2a28124f16 100644 --- a/src/interfaces/jdbc/org/postgresql/test/jdbc2/ConnectionTest.java +++ b/src/interfaces/jdbc/org/postgresql/test/jdbc2/ConnectionTest.java @@ -10,7 +10,7 @@ import java.sql.*; * * PS: Do you know how difficult it is to type on a train? ;-) * - * $Id: ConnectionTest.java,v 1.10 2002/10/17 05:33:52 barry Exp $ + * $Id: ConnectionTest.java,v 1.10.6.1 2004/02/24 13:11:44 jurka Exp $ */ public class ConnectionTest extends TestCase @@ -347,4 +347,14 @@ public class ConnectionTest extends TestCase assertTrue(ex.getMessage(), false); } } + + /** + * Closing a Connection more than once is not an error. + */ + public void testDoubleClose() throws SQLException + { + Connection con = TestUtil.openDB(); + con.close(); + con.close(); + } } diff --git a/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/ConnectionPoolTest.java b/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/ConnectionPoolTest.java index 6c226d0219..662f7b6264 100644 --- a/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/ConnectionPoolTest.java +++ b/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/ConnectionPoolTest.java @@ -12,7 +12,7 @@ import java.io.*; * interface to the PooledConnection is through the CPDS. * * @author Aaron Mulder (ammulder@chariotsolutions.com) - * @version $Revision: 1.6.4.3 $ + * @version $Revision: 1.6.4.4 $ */ public class ConnectionPoolTest extends BaseDataSourceTest { @@ -131,13 +131,6 @@ public class ConnectionPoolTest extends BaseDataSourceTest } catch (SQLException e) {} - try - { - con.close(); - fail("Original connection wrapper should be closed when new connection wrapper is generated"); - } - catch (SQLException e) - {} con2.close(); pc.close(); } @@ -194,13 +187,8 @@ public class ConnectionPoolTest extends BaseDataSourceTest con.close(); assertTrue(cc.getCount() == 2); assertTrue(cc.getErrorCount() == 0); - try - { + // a double close shouldn't fire additional events con.close(); - fail("Should not be able to close a connection wrapper twice"); - } - catch (SQLException e) - {} assertTrue(cc.getCount() == 2); assertTrue(cc.getErrorCount() == 0); pc.close(); diff --git a/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/PoolingDataSourceTest.java b/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/PoolingDataSourceTest.java index 701f835332..75bb4ac2e7 100644 --- a/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/PoolingDataSourceTest.java +++ b/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/PoolingDataSourceTest.java @@ -1,6 +1,7 @@ package org.postgresql.test.jdbc2.optional; import java.sql.SQLException; +import java.sql.Statement; import org.postgresql.test.TestUtil; import org.postgresql.jdbc2.optional.PoolingDataSource; import org.postgresql.jdbc2.optional.BaseDataSource; @@ -9,7 +10,7 @@ import org.postgresql.jdbc2.optional.BaseDataSource; * Minimal tests for pooling DataSource. Needs many more. * * @author Aaron Mulder (ammulder@chariotsolutions.com) - * @version $Revision: 1.1.6.1 $ + * @version $Revision: 1.1.6.2 $ */ public class PoolingDataSourceTest extends BaseDataSourceTest { @@ -96,4 +97,26 @@ public class PoolingDataSourceTest extends BaseDataSourceTest { } } + + /** + * Closing a Connection twice is not an error. + */ + public void testDoubleConnectionClose() throws SQLException + { + con = getDataSourceConnection(); + con.close(); + con.close(); + } + + /** + * Closing a Statement twice is not an error. + */ + public void testDoubleStatementClose() throws SQLException + { + con = getDataSourceConnection(); + Statement stmt = con.createStatement(); + stmt.close(); + stmt.close(); + con.close(); + } } -- 2.50.1