diff --git a/src/backend/distributed/connection/remote_commands.c b/src/backend/distributed/connection/remote_commands.c index 186ca8f50..1f7f833d9 100644 --- a/src/backend/distributed/connection/remote_commands.c +++ b/src/backend/distributed/connection/remote_commands.c @@ -48,8 +48,8 @@ IsResponseOK(PGresult *result) /* * ForgetResults clears a connection from pending activity. * - * XXX: In the future it might be a good idea to use use PQcancel() if results - * would require network IO. + * Note that this might require network IO. If that's not acceptable, use + * NonblockingForgetResults(). */ void ForgetResults(MultiConnection *connection) @@ -75,6 +75,74 @@ ForgetResults(MultiConnection *connection) } +/* + * NonblockingForgetResults clears a connection from pending activity if doing + * so does not require network IO. Returns true if successful, false + * otherwise. + */ +bool +NonblockingForgetResults(MultiConnection *connection) +{ + PGconn *pgConn = connection->pgConn; + + if (PQstatus(pgConn) != CONNECTION_OK) + { + return false; + } + + Assert(PQisnonblocking(pgConn)); + + while (true) + { + PGresult *result = NULL; + + /* just in case there's a lot of results */ + CHECK_FOR_INTERRUPTS(); + + /* + * If busy, there might still be results already received and buffered + * by the OS. As connection is in non-blocking mode, we can check for + * that without blocking. + */ + if (PQisBusy(pgConn)) + { + if (PQflush(pgConn) == -1) + { + /* write failed */ + return false; + } + if (PQconsumeInput(pgConn) == 0) + { + /* some low-level failure */ + return false; + } + } + + /* clearing would require blocking IO, return */ + if (PQisBusy(pgConn)) + { + return false; + } + + result = PQgetResult(pgConn); + if (PQresultStatus(result) == PGRES_COPY_IN) + { + /* in copy, can't reliably recover without blocking */ + return false; + } + + if (result == NULL) + { + return true; + } + + PQclear(result); + } + + pg_unreachable(); +} + + /* * SqlStateMatchesCategory returns true if the given sql state (which may be * NULL if unknown) is in the given error category. Note that we use diff --git a/src/include/distributed/remote_commands.h b/src/include/distributed/remote_commands.h index 6d3f2abb3..6cdc28802 100644 --- a/src/include/distributed/remote_commands.h +++ b/src/include/distributed/remote_commands.h @@ -26,6 +26,7 @@ extern bool LogRemoteCommands; /* simple helpers */ extern bool IsResponseOK(struct pg_result *result); extern void ForgetResults(MultiConnection *connection); +extern bool NonblockingForgetResults(MultiConnection *connection); extern bool SqlStateMatchesCategory(char *sqlStateString, int category); /* report errors & warnings */