Fix multiple problems in postgres_fdw query cancellation logic.
authorRobert Haas <rhaas@postgresql.org>
Mon, 16 May 2016 15:19:10 +0000 (11:19 -0400)
committerRobert Haas <rhaas@postgresql.org>
Mon, 16 May 2016 15:19:10 +0000 (11:19 -0400)
First, even if we cancel a query, we still have to roll back the
containing transaction; otherwise, the session will be left in a
failed transaction state.

Second, we need to support canceling queries whe aborting a
subtransaction as well as when aborting a toplevel transaction.

Etsuro Fujita, reviewed by Michael Paquier

contrib/postgres_fdw/connection.c

index 16ef38fff785a8a27c4b6baa86bb7eee745e72b0..43c7fc9e0807955dc7bd232e04f36bc79d389cc5 100644 (file)
@@ -677,8 +677,7 @@ pgfdw_xact_callback(XactEvent event, void *arg)
                                         * using an asynchronous execution function, the command
                                         * might not have yet completed.  Check to see if a command
                                         * is still being processed by the remote server, and if so,
-                                        * request cancellation of the command; if not, abort
-                                        * gracefully.
+                                        * request cancellation of the command.
                                         */
                                        if (PQtransactionStatus(entry->conn) == PQTRANS_ACTIVE)
                                        {
@@ -694,7 +693,6 @@ pgfdw_xact_callback(XactEvent event, void *arg)
                                                                                                errbuf)));
                                                        PQfreeCancel(cancel);
                                                }
-                                               break;
                                        }
 
                                        /* If we're aborting, abort all remote transactions too */
@@ -798,6 +796,30 @@ pgfdw_subxact_callback(SubXactEvent event, SubTransactionId mySubid,
                {
                        /* Assume we might have lost track of prepared statements */
                        entry->have_error = true;
+
+                       /*
+                        * If a command has been submitted to the remote server by using an
+                        * asynchronous execution function, the command might not have yet
+                        * completed.  Check to see if a command is still being processed by
+                        * the remote server, and if so, request cancellation of the
+                        * command.
+                        */
+                       if (PQtransactionStatus(entry->conn) == PQTRANS_ACTIVE)
+                       {
+                               PGcancel   *cancel;
+                               char            errbuf[256];
+
+                               if ((cancel = PQgetCancel(entry->conn)))
+                               {
+                                       if (!PQcancel(cancel, errbuf, sizeof(errbuf)))
+                                               ereport(WARNING,
+                                                               (errcode(ERRCODE_CONNECTION_FAILURE),
+                                                                errmsg("could not send cancel request: %s",
+                                                                               errbuf)));
+                                       PQfreeCancel(cancel);
+                               }
+                       }
+
                        /* Rollback all remote subtransactions during abort */
                        snprintf(sql, sizeof(sql),
                                         "ROLLBACK TO SAVEPOINT s%d; RELEASE SAVEPOINT s%d",