summaryrefslogtreecommitdiff
path: root/src/bin/psql/common.c
diff options
context:
space:
mode:
authorMichael Paquier <michael@paquier.xyz>2025-04-24 12:22:53 +0900
committerMichael Paquier <michael@paquier.xyz>2025-04-24 12:22:53 +0900
commit3631612eae9c2def99151c4f36b1b3771f53cba7 (patch)
treeab808935d3d4c4e621760c447bbcfd28acf2d77c /src/bin/psql/common.c
parent923ae50cf55986efb5f3feb0f15253a69a5e224c (diff)
psql: Fix assertion failures with pipeline mode
A correct cocktail of COPY FROM, SELECT and/or DML queries and \syncpipeline was able to break the logic in charge of discarding results of a pipeline, done in discardAbortedPipelineResults(). Such sequence make the backend generate a FATAL, due to a protocol synchronization loss. This problem comes down to the fact that we did not consider the case of libpq returning a PGRES_FATAL_ERROR when discarding the results of an aborted pipeline. The discarding code is changed so as this result status is handled as a special case, with the caller of discardAbortedPipelineResults() being responsible for consuming the result. A couple of tests are added to cover the problems reported, bringing an interesting gain in coverage as there were no tests in the tree covering the case of protocol synchronization loss. Issue introduced by 41625ab8ea3d. Reported-by: Alexander Kozhemyakin <a.kozhemyakin@postgrespro.ru> Author: Anthonin Bonnefoy <anthonin.bonnefoy@datadoghq.com> Co-authored-by: Michael Paquier <michael@paquier.xyz> Discussion: https://postgr.es/m/ebf6ce77-b180-4d6b-8eab-71f641499ddf@postgrespro.ru
Diffstat (limited to 'src/bin/psql/common.c')
-rw-r--r--src/bin/psql/common.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index 21d660a8961..3e4e444f3fd 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -1478,6 +1478,23 @@ discardAbortedPipelineResults(void)
*/
return res;
}
+ else if (res != NULL && result_status == PGRES_FATAL_ERROR)
+ {
+ /*
+ * Found a FATAL error sent by the backend, and we cannot recover
+ * from this state. Instead, return the last result and let the
+ * outer loop handle it.
+ */
+ PGresult *fatal_res PG_USED_FOR_ASSERTS_ONLY;
+
+ /*
+ * Fetch result to consume the end of the current query being
+ * processed.
+ */
+ fatal_res = PQgetResult(pset.db);
+ Assert(fatal_res == NULL);
+ return res;
+ }
else if (res == NULL)
{
/* A query was processed, decrement the counters */