Closing a Connection or Statement object twice should be a no-op

instead of throwing an Exception.

Per report from Victor Sergienko.
This commit is contained in:
Kris Jurka 2004-02-24 13:11:45 +00:00
parent 27ae96c2b6
commit 935e6e502d
5 changed files with 60 additions and 23 deletions

View File

@ -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;
}
/**

View File

@ -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

View File

@ -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();
}
}

View File

@ -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();

View File

@ -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();
}
}