mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-11-15 05:26:37 +03:00
Fixed infinite loop in pq_get_last_result after COPY
There will be an error downstream but we have to get out of this function first. Close #781
This commit is contained in:
parent
c97266921c
commit
5abbcb23ca
3
NEWS
3
NEWS
|
@ -6,7 +6,8 @@ What's new in psycopg 2.7.6
|
|||
|
||||
- Close named cursors if exist, even if `~cursor.execute()` wasn't called
|
||||
(:ticket:`#746`).
|
||||
- Fixed building on modern FreeBSD versions with Python 3.7 (:ticket:`#755`)
|
||||
- Fixed building on modern FreeBSD versions with Python 3.7 (:ticket:`#755`).
|
||||
- Fixed hang trying to :sql:`COPY` via `~cursor.execute()` (:ticket:`#781`).
|
||||
|
||||
|
||||
What's new in psycopg 2.7.5
|
||||
|
|
|
@ -1106,12 +1106,13 @@ pq_send_query(connectionObject *conn, const char *query)
|
|||
* The function will block only if a command is active and the
|
||||
* necessary response data has not yet been read by PQconsumeInput.
|
||||
*
|
||||
* The result should be disposed using PQclear()
|
||||
* The result should be disposed of using PQclear()
|
||||
*/
|
||||
PGresult *
|
||||
pq_get_last_result(connectionObject *conn)
|
||||
{
|
||||
PGresult *result = NULL, *res;
|
||||
ExecStatusType status;
|
||||
|
||||
/* Read until PQgetResult gives a NULL */
|
||||
while (NULL != (res = PQgetResult(conn->pgconn))) {
|
||||
|
@ -1124,11 +1125,15 @@ pq_get_last_result(connectionObject *conn)
|
|||
PQclear(result);
|
||||
}
|
||||
result = res;
|
||||
status = PQresultStatus(result);
|
||||
Dprintf("pq_get_last_result: got result %s", PQresStatus(status));
|
||||
|
||||
/* After entering copy both mode, libpq will make a phony
|
||||
/* After entering copy mode, libpq will make a phony
|
||||
* PGresult for us every time we query for it, so we need to
|
||||
* break out of this endless loop. */
|
||||
if (PQresultStatus(result) == PGRES_COPY_BOTH) {
|
||||
if (status == PGRES_COPY_BOTH
|
||||
|| status == PGRES_COPY_OUT
|
||||
|| status == PGRES_COPY_IN) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -450,6 +450,12 @@ class AsyncTests(ConnectingTestCase):
|
|||
else:
|
||||
self.fail("no exception raised")
|
||||
|
||||
@skip_before_postgres(8, 2)
|
||||
def test_copy_no_hang(self):
|
||||
cur = self.conn.cursor()
|
||||
cur.execute("copy (select 1) to stdout")
|
||||
self.assertRaises(psycopg2.ProgrammingError, self.wait, self.conn)
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
|
|
@ -27,7 +27,7 @@ import psycopg2
|
|||
import psycopg2.extensions
|
||||
import psycopg2.extras
|
||||
|
||||
from testutils import ConnectingTestCase, slow
|
||||
from testutils import ConnectingTestCase, skip_before_postgres, slow
|
||||
|
||||
|
||||
class ConnectionStub(object):
|
||||
|
@ -111,6 +111,12 @@ class GreenTestCase(ConnectingTestCase):
|
|||
curs.execute("select 1")
|
||||
self.assertEqual(curs.fetchone()[0], 1)
|
||||
|
||||
@skip_before_postgres(8, 2)
|
||||
def test_copy_no_hang(self):
|
||||
cur = self.conn.cursor()
|
||||
self.assertRaises(psycopg2.ProgrammingError,
|
||||
cur.execute, "copy (select 1) to stdout")
|
||||
|
||||
|
||||
class CallbackErrorTestCase(ConnectingTestCase):
|
||||
def setUp(self):
|
||||
|
|
Loading…
Reference in New Issue
Block a user