From 12317557da20d84baf12054d8dfce11ba8976cb6 Mon Sep 17 00:00:00 2001 From: Greg Ward Date: Tue, 28 Jun 2016 18:03:05 -0400 Subject: [PATCH] Always raise OperationalError when connection was closed externally. From the DB-API (https://www.python.org/dev/peps/pep-0249/): OperationalError Exception raised for errors that are related to the database's operation and not necessarily under the control of the programmer, e.g. an unexpected disconnect occurs, [...] Additionally, psycopg2 was inconsistent, at least in the async case: depending on how the "connection closed" error was reported from the kernel to libpq, it would sometimes raise OperationalError and sometimes DatabaseError. Now it always raises OperationalError. --- psycopg/pqpath.c | 10 ++++++---- tests/test_cursor.py | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/psycopg/pqpath.c b/psycopg/pqpath.c index 222696be..f270ce8f 100644 --- a/psycopg/pqpath.c +++ b/psycopg/pqpath.c @@ -179,8 +179,10 @@ pq_raise(connectionObject *conn, cursorObject *curs, PGresult **pgres) /* if the connection has somehow been broken, we mark the connection object as closed but requiring cleanup */ - if (conn->pgconn != NULL && PQstatus(conn->pgconn) == CONNECTION_BAD) + if (conn->pgconn != NULL && PQstatus(conn->pgconn) == CONNECTION_BAD) { conn->closed = 2; + exc = OperationalError; + } if (pgres == NULL && curs != NULL) pgres = &curs->pgres; @@ -214,9 +216,9 @@ pq_raise(connectionObject *conn, cursorObject *curs, PGresult **pgres) if (code != NULL) { exc = exception_from_sqlstate(code); } - else { - /* Fallback if there is no exception code (reported happening e.g. - * when the connection is closed). */ + else if (exc == NULL) { + /* Fallback if there is no exception code (unless we already + determined that the connection was closed). */ exc = DatabaseError; } diff --git a/tests/test_cursor.py b/tests/test_cursor.py index f9fc66ca..98891ea7 100755 --- a/tests/test_cursor.py +++ b/tests/test_cursor.py @@ -575,7 +575,7 @@ class CursorTests(ConnectingTestCase): cur.execute('select pg_terminate_backend(%s)', (pid1,)) time.sleep(0.001) - with self.assertRaises(psycopg2.DatabaseError): + with self.assertRaises(psycopg2.OperationalError): with victim_conn.cursor() as cur: cur.execute('select 1') wait_func(victim_conn)