mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-11-22 17:06:33 +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
c442b3ec46
commit
c314512115
3
NEWS
3
NEWS
|
@ -33,7 +33,8 @@ What's new in psycopg 2.7.6
|
||||||
|
|
||||||
- Close named cursors if exist, even if `~cursor.execute()` wasn't called
|
- Close named cursors if exist, even if `~cursor.execute()` wasn't called
|
||||||
(:ticket:`#746`).
|
(: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
|
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
|
* The function will block only if a command is active and the
|
||||||
* necessary response data has not yet been read by PQconsumeInput.
|
* 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 *
|
PGresult *
|
||||||
pq_get_last_result(connectionObject *conn)
|
pq_get_last_result(connectionObject *conn)
|
||||||
{
|
{
|
||||||
PGresult *result = NULL, *res;
|
PGresult *result = NULL, *res;
|
||||||
|
ExecStatusType status;
|
||||||
|
|
||||||
/* Read until PQgetResult gives a NULL */
|
/* Read until PQgetResult gives a NULL */
|
||||||
while (NULL != (res = PQgetResult(conn->pgconn))) {
|
while (NULL != (res = PQgetResult(conn->pgconn))) {
|
||||||
|
@ -1124,11 +1125,15 @@ pq_get_last_result(connectionObject *conn)
|
||||||
PQclear(result);
|
PQclear(result);
|
||||||
}
|
}
|
||||||
result = res;
|
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
|
* PGresult for us every time we query for it, so we need to
|
||||||
* break out of this endless loop. */
|
* 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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -450,6 +450,12 @@ class AsyncTests(ConnectingTestCase):
|
||||||
else:
|
else:
|
||||||
self.fail("no exception raised")
|
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():
|
def test_suite():
|
||||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||||
|
|
|
@ -27,7 +27,7 @@ import psycopg2
|
||||||
import psycopg2.extensions
|
import psycopg2.extensions
|
||||||
import psycopg2.extras
|
import psycopg2.extras
|
||||||
|
|
||||||
from .testutils import ConnectingTestCase, slow
|
from .testutils import ConnectingTestCase, skip_before_postgres, slow
|
||||||
|
|
||||||
|
|
||||||
class ConnectionStub(object):
|
class ConnectionStub(object):
|
||||||
|
@ -111,6 +111,12 @@ class GreenTestCase(ConnectingTestCase):
|
||||||
curs.execute("select 1")
|
curs.execute("select 1")
|
||||||
self.assertEqual(curs.fetchone()[0], 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):
|
class CallbackErrorTestCase(ConnectingTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user