Client-side fixes for delayed NOTIFY receipt.
authorTom Lane
Sat, 20 Oct 2018 02:22:57 +0000 (22:22 -0400)
committerTom Lane
Sat, 20 Oct 2018 02:22:57 +0000 (22:22 -0400)
PQnotifies() is defined to just process already-read data, not try to read
any more from the socket.  (This is a debatable decision, perhaps, but I'm
hesitant to change longstanding library behavior.)  The documentation has
long recommended calling PQconsumeInput() before PQnotifies() to ensure
that any already-arrived message would get absorbed and processed.
However, psql did not get that memo, which explains why it's not very
reliable about reporting notifications promptly.

Also, most (not quite all) callers called PQconsumeInput() just once before
a PQnotifies() loop.  Taking this recommendation seriously implies that we
should do PQconsumeInput() before each call.  This is more important now
that we have "payload" strings in notification messages than it was before;
that increases the probability of having more than one packet's worth
of notify messages.  Hence, adjust code as well as documentation examples
to do it like that.

Back-patch to 9.5 to match related server fixes.  In principle we could
probably go back further with these changes, but given lack of field
complaints I doubt it's worthwhile.

Discussion: https://postgr.es/m/CAOYf6ec-TmRYjKBXLLaGaB-jrd=mjG1Hzn1a1wufUAR39PQYhw@mail.gmail.com

doc/src/sgml/libpq.sgml
src/bin/psql/common.c
src/interfaces/ecpg/ecpglib/execute.c
src/interfaces/libpq/fe-exec.c
src/test/examples/testlibpq2.c

index f7bd9650af19136cd9c80bbfd279f6ce1ed8bac1..2913fd79750957fae29d02b2915c41b68a60f4a3 100644 (file)
@@ -5215,7 +5215,7 @@ typedef struct pgNotify
   
    PQnotifies does not actually read data from the
    server; it just returns messages previously absorbed by another
-   libpq function.  In prior releases of
+   libpq function.  In ancient releases of
    libpq, the only way to ensure timely receipt
    of NOTIFY messages was to constantly submit commands, even
    empty ones, and then check PQnotifies after each
@@ -8608,6 +8608,7 @@ main(int argc, char **argv)
                     notify->relname, notify->be_pid);
             PQfreemem(notify);
             nnotifies++;
+            PQconsumeInput(conn);
         }
     }
 
index a41932ff27575ba2edbeeff06560bde8b8ae66ce..d257be5700fde2e8d872002fbc7b92abb22b20fd 100644 (file)
@@ -788,7 +788,8 @@ PrintNotifications(void)
 {
    PGnotify   *notify;
 
-   while ((notify = PQnotifies(pset.db)))
+   PQconsumeInput(pset.db);
+   while ((notify = PQnotifies(pset.db)) != NULL)
    {
        /* for backward compatibility, only show payload if nonempty */
        if (notify->extra[0])
@@ -799,6 +800,7 @@ PrintNotifications(void)
                    notify->relname, notify->be_pid);
        fflush(pset.queryFout);
        PQfreemem(notify);
+       PQconsumeInput(pset.db);
    }
 }
 
index 9a6dde44de903d9a066a755494e257efe10d95c8..6f20cc412a2aa960a1367f466c6bc323d53b94fc 100644 (file)
@@ -1729,12 +1729,13 @@ ecpg_process_output(struct statement *stmt, bool clear_result)
    }
 
    /* check for asynchronous returns */
-   notify = PQnotifies(stmt->connection->connection);
-   if (notify)
+   PQconsumeInput(stmt->connection->connection);
+   while ((notify = PQnotifies(stmt->connection->connection)) != NULL)
    {
        ecpg_log("ecpg_process_output on line %d: asynchronous notification of \"%s\" from backend PID %d received\n",
                 stmt->lineno, notify->relname, notify->be_pid);
        PQfreemem(notify);
+       PQconsumeInput(stmt->connection->connection);
    }
 
    return status;
index a97e73cf99d321e2f05e4a4c6bad7a1920d1478e..916eb45d4a8d6b3ee228c6db30fb3f3a0bc49459 100644 (file)
@@ -2239,6 +2239,9 @@ sendFailed:
  * no unhandled async notification from the backend
  *
  * the CALLER is responsible for FREE'ing the structure returned
+ *
+ * Note that this function does not read any new data from the socket;
+ * so usually, caller should call PQconsumeInput() first.
  */
 PGnotify *
 PQnotifies(PGconn *conn)
index 62ecd68b55e39799d27789a4d980799fbcb604cb..6cdf8c8631ba89c46f7b9b271dd45c88d0762557 100644 (file)
@@ -140,6 +140,7 @@ main(int argc, char **argv)
                    notify->relname, notify->be_pid);
            PQfreemem(notify);
            nnotifies++;
+           PQconsumeInput(conn);
        }
    }