summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-rw-r--r--psycopg/connection_int.c11
-rw-r--r--psycopg/connection_type.c2
-rw-r--r--psycopg/cursor_type.c6
-rw-r--r--tests/dbapi20.py4
-rwxr-xr-xtests/test_connection.py6
-rwxr-xr-xtests/test_cursor.py6
7 files changed, 29 insertions, 8 deletions
diff --git a/NEWS b/NEWS
index 39510c1..4c94a98 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,8 @@
What's new in psycopg 2.4.5
---------------------------
+ - The close() methods on connections and cursors don't raise exceptions
+ if called on already closed objects.
- Fixed fetchmany() with no argument in cursor subclasses
(ticket #84).
- Use lo_creat() instead of lo_create() when possible for better
diff --git a/psycopg/connection_int.c b/psycopg/connection_int.c
index 7046513..2395c00 100644
--- a/psycopg/connection_int.c
+++ b/psycopg/connection_int.c
@@ -906,6 +906,10 @@ conn_poll(connectionObject *self)
void
conn_close(connectionObject *self)
{
+ if (self->closed) {
+ return;
+ }
+
/* sets this connection as closed even for other threads; also note that
we need to check the value of pgconn, because we get called even when
the connection fails! */
@@ -922,14 +926,13 @@ conn_close(connectionObject *self)
* closed only in status CONN_STATUS_READY.
*/
- if (self->closed == 0)
- self->closed = 1;
+ self->closed = 1;
if (self->pgconn) {
PQfinish(self->pgconn);
- PQfreeCancel(self->cancel);
- Dprintf("conn_close: PQfinish called");
self->pgconn = NULL;
+ Dprintf("conn_close: PQfinish called");
+ PQfreeCancel(self->cancel);
self->cancel = NULL;
}
diff --git a/psycopg/connection_type.c b/psycopg/connection_type.c
index 693de3c..09ced62 100644
--- a/psycopg/connection_type.c
+++ b/psycopg/connection_type.c
@@ -122,8 +122,6 @@ psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *keywds)
static PyObject *
psyco_conn_close(connectionObject *self, PyObject *args)
{
- EXC_IF_CONN_CLOSED(self);
-
Dprintf("psyco_conn_close: closing connection at %p", self);
conn_close(self);
Dprintf("psyco_conn_close: connection at %p closed", self);
diff --git a/psycopg/cursor_type.c b/psycopg/cursor_type.c
index bb9db69..4de0163 100644
--- a/psycopg/cursor_type.c
+++ b/psycopg/cursor_type.c
@@ -52,9 +52,12 @@ extern PyObject *pyPsycopgTzFixedOffsetTimezone;
static PyObject *
psyco_curs_close(cursorObject *self, PyObject *args)
{
- EXC_IF_CURS_CLOSED(self);
EXC_IF_ASYNC_IN_PROGRESS(self, close);
+ if (self->closed) {
+ goto exit;
+ }
+
if (self->name != NULL) {
char buffer[128];
@@ -66,6 +69,7 @@ psyco_curs_close(cursorObject *self, PyObject *args)
self->closed = 1;
Dprintf("psyco_curs_close: cursor at %p closed", self);
+exit:
Py_INCREF(Py_None);
return Py_None;
}
diff --git a/tests/dbapi20.py b/tests/dbapi20.py
index 59232a5..6231ed7 100644
--- a/tests/dbapi20.py
+++ b/tests/dbapi20.py
@@ -380,7 +380,9 @@ class DatabaseAPI20Test(unittest.TestCase):
self.assertRaises(self.driver.Error,con.commit)
# connection.close should raise an Error if called more than once
- self.assertRaises(self.driver.Error,con.close)
+ # Issue discussed on DB-SIG: consensus seem that close() should not
+ # raised if called on closed objects. Issue reported back to Stuart.
+ # self.assertRaises(self.driver.Error,con.close)
def test_execute(self):
con = self._connect()
diff --git a/tests/test_connection.py b/tests/test_connection.py
index 584bdb4..07400fa 100755
--- a/tests/test_connection.py
+++ b/tests/test_connection.py
@@ -48,6 +48,12 @@ class ConnectionTests(unittest.TestCase):
conn.close()
self.assertEqual(conn.closed, True)
+ def test_close_idempotent(self):
+ conn = self.conn
+ conn.close()
+ conn.close()
+ self.assert_(conn.closed)
+
def test_cursor_closed_attribute(self):
conn = self.conn
curs = conn.cursor()
diff --git a/tests/test_cursor.py b/tests/test_cursor.py
index 6286942..051c9f2 100755
--- a/tests/test_cursor.py
+++ b/tests/test_cursor.py
@@ -37,6 +37,12 @@ class CursorTests(unittest.TestCase):
def tearDown(self):
self.conn.close()
+ def test_close_idempotent(self):
+ cur = self.conn.cursor()
+ cur.close()
+ cur.close()
+ self.assert_(cur.closed)
+
def test_empty_query(self):
cur = self.conn.cursor()
self.assertRaises(psycopg2.ProgrammingError, cur.execute, "")