Skip to content

Commit

Permalink
Don't try to close the server cursor in error state
Browse files Browse the repository at this point in the history
`close()` is implicitly called by `__exit__()`, so an exit on error
would run a query on a inerr connection, causing another exception
hiding the original one. The fix is on `close()`, not on `__exit__()`,
because the semantic of the latter is simply to call the former.

Closes psycopg#262.
  • Loading branch information
dvarrazzo committed Sep 16, 2014
1 parent 48a32b7 commit 1b48033
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 3 deletions.
7 changes: 7 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ Bug fixes:
(:ticket:`#191`).


What's new in psycopg 2.5.5
^^^^^^^^^^^^^^^^^^^^^^^^^^^

- Named cursors used as context manager don't swallow the exception on exit
(:ticket:`#262`).


What's new in psycopg 2.5.4
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
20 changes: 17 additions & 3 deletions psycopg/cursor_type.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,24 @@ psyco_curs_close(cursorObject *self)

if (self->name != NULL) {
char buffer[128];
PGTransactionStatusType status;

EXC_IF_NO_MARK(self);
PyOS_snprintf(buffer, 127, "CLOSE \"%s\"", self->name);
if (pq_execute(self, buffer, 0, 0, 1) == -1) return NULL;
if (self->conn) {
status = PQtransactionStatus(self->conn->pgconn);
}
else {
status = PQTRANS_UNKNOWN;
}

if (!(status == PQTRANS_UNKNOWN || status == PQTRANS_INERROR)) {
EXC_IF_NO_MARK(self);
PyOS_snprintf(buffer, 127, "CLOSE \"%s\"", self->name);
if (pq_execute(self, buffer, 0, 0, 1) == -1) return NULL;
}
else {
Dprintf("skipping named curs close because tx status %d",
(int)status);
}
}

self->closed = 1;
Expand Down
12 changes: 12 additions & 0 deletions tests/test_with.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,18 @@ def close(self):
self.assert_(curs.closed)
self.assert_(closes)

def test_exception_swallow(self):
# bug #262: __exit__ calls cur.close() that hides the exception
# with another error.
try:
with self.conn as conn:
with conn.cursor('named') as cur:
cur.execute("select 1/0")
except psycopg2.DataError, e:
self.assertEqual(e.pgcode, '22012')
else:
self.fail("where is my exception?")


def test_suite():
return unittest.TestLoader().loadTestsFromName(__name__)
Expand Down

0 comments on commit 1b48033

Please sign in to comment.