Hello,

I've encountered a bug on PG 9.2 and fixed it for 9.4. Please find attached the patch. I'd like it to be backported to at least 9.2.



[Problem]
If the backend is terminated with SIGKILL while psql is running "\copy table_name from file_name", the \copy didn't end forever. I expected \copy to be cancelled because the corresponding server process vanished.


[Cause]
psql could not get out of the loop below in handleCopyIn():

while (res = PQgetResult(conn), PQresultStatus(res) == PGRES_COPY_IN)
{
   OK = false;
   PQclear(res);

   PQputCopyEnd(pset.db, _("trying to exit copy mode"));
}

This situation is reached as follows:

1. handleCopyIn() calls PQputCopyData().
2. PQputCopyData() calls pqPutMsgEnd().
3. pqPutMsgEnd() calls pqFlush(), which calls pqSendSome().
4. pqSendSome() calls pqReadData().
5. At this moment, the backend is killed with SIGKILL.
6. pqReadData() fails to read the socket, receiving ECONNRESET. It closes the socket.
7. As a result, PQputCopyData() fails in 2.
8. handleCopyIn() then calls PQputCopyEnd().
9. PQputCopyEnd() calls pqPutMsgENd(), which calls pqFlush(), which in turn calls pqSendSome().
10. pqSendSome() fails because the socket is not open.
11. As a result, PQputCopyENd() returns an error, leaving conn->asyncStatus PGASYNC_COPY_IN. 12. Because conn->asyncStatus remains PGASYNC_COPY_IN, PQgetResult() continues to return pgresult whose status is PGRES_COPY_IN.


[Fix]
If the message transmission fails in PQputCopyEnd(), switch conn->asyncStatus back to PGASYNC_BUSY. That causes PQgetResult() to try to read data with pqReadData(). pqReadData() fails and PQgetResult() returns NULL. As a consequence, the loop in question terminates.


Regards
MauMau

Attachment: failed_copy_loops.patch
Description: Binary data

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to