From: Denis Laxalde <denis.laxalde@dalibo.com>
To: pgsql-hackers@lists.postgresql.org
Subject: [PATCH] Reset single-row processing mode at end of pipeline commands queue
Date: Fri, 7 Oct 2022 15:08:05 +0200
Message-ID: <01af18c5-dacc-a8c8-07ee-aecc7650c3e8@dalibo.com> (raw)
Hello,
I'm trying to make single-row mode and pipeline mode work together in
Psycopg using libpq. I think there is something wrong with respect to
the single-row mode flag, not being correctly reset, in some situations.
The minimal case I'm considering is (in a pipeline):
* send query 1,
* get its results in single-row mode,
* send query 2,
* get its results *not* in single-row mode.
It seems that, as the command queue in the pipeline is empty after
getting the results of query 1, the single-row mode flag is not reset
and is still active for query 2, thus leading to an unexpected
PGRES_SINGLE_TUPLE status.
The attached patch demonstrates this in the test suite. It also suggests
to move the statement resetting single-row mode up in
pqPipelineProcessQueue(), before exiting the function when the command
queue is empty in particular.
Thanks for considering,
Denis
Attachments:0001-Reset-single-row-processing-mode-at-end-of-pipeline-.patch (text/x-patch, 5.3K) download
From de28d9ac1e541c3b3a0279dc58fb5a7f23f775f8 Mon Sep 17 00:00:00 2001
From: Denis Laxalde <denis.laxalde@dalibo.com>
Date: Fri, 7 Oct 2022 14:00:24 +0200
Subject: [PATCH] Reset single-row processing mode at end of pipeline commands
queue
Previously, we'd reset the single-row mode only when processing results
of the next command in a pipeline and not if there's no more commands in
the queue. But if the client emits a query, retrieves its results in
single-row mode (thus setting single-row mode flag), then emits another
query and wants to retrieve its result in "normal" mode, the single-row
mode was not reset in pqPipelineProcessQueue(); this lead to an
erroneous PGRES_SINGLE_TUPLE instead of, e.g., PGRES_TUPLES_OK.
We fix this by resetting the single-row mode *even* if the command queue
is empty in pqPipelineProcessQueue().
---
src/interfaces/libpq/fe-exec.c | 12 +++---
.../modules/libpq_pipeline/libpq_pipeline.c | 43 ++++++++++++++++++-
.../libpq_pipeline/traces/singlerow.trace | 20 +++++++++
3 files changed, 68 insertions(+), 7 deletions(-)
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.cindex 0274c1b156..64701b562b 100644--- a/src/interfaces/libpq/fe-exec.c+++ b/src/interfaces/libpq/fe-exec.c@@ -3096,6 +3096,12 @@ pqPipelineProcessQueue(PGconn *conn)
break;
}
+ /*+ * Reset single-row processing mode. (Client has to set it up for each+ * query, if desired.)+ */+ conn->singleRowMode = false;+
/*
* If there are no further commands to process in the queue, get us in
* "real idle" mode now.
@@ -3115,12 +3121,6 @@ pqPipelineProcessQueue(PGconn *conn)
/* Initialize async result-accumulation state */
pqClearAsyncResult(conn);
- /*- * Reset single-row processing mode. (Client has to set it up for each- * query, if desired.)- */- conn->singleRowMode = false;-
if (conn->pipelineStatus == PQ_PIPELINE_ABORTED &&
conn->cmd_queue_head->queryclass != PGQUERY_SYNC)
{
diff --git a/src/test/modules/libpq_pipeline/libpq_pipeline.c b/src/test/modules/libpq_pipeline/libpq_pipeline.cindex c609f42258..4b9ccbfb4c 100644--- a/src/test/modules/libpq_pipeline/libpq_pipeline.c+++ b/src/test/modules/libpq_pipeline/libpq_pipeline.c@@ -1153,11 +1153,11 @@ test_singlerowmode(PGconn *conn)
int i;
bool pipeline_ended = false;
- /* 1 pipeline, 3 queries in it */
if (PQenterPipelineMode(conn) != 1)
pg_fatal("failed to enter pipeline mode: %s",
PQerrorMessage(conn));
+ /* One series of three commands, using single-row mode for the first two. */
for (i = 0; i < 3; i++)
{
char *param[1];
@@ -1249,6 +1249,47 @@ test_singlerowmode(PGconn *conn)
pg_fatal("didn't get expected terminating TUPLES_OK");
}
+ /*+ * Now issue one command, get its results in with single-row mode, then+ * issue another command, and get its results in normal mode; make sure+ * the single-row mode flag is reset as expected.+ */+ if (PQsendQueryParams(conn, "SELECT generate_series(0, 0)", 0, NULL, NULL, NULL, NULL, 0) != 1)+ pg_fatal("failed to send query: %s",+ PQerrorMessage(conn));+ if (PQsendFlushRequest(conn) != 1)+ pg_fatal("failed to send flush request");+ if (PQsetSingleRowMode(conn) != 1)+ pg_fatal("PQsetSingleRowMode() failed");+ res = PQgetResult(conn);+ if (res == NULL)+ pg_fatal("unexpected NULL");+ if (PQresultStatus(res) != PGRES_SINGLE_TUPLE)+ pg_fatal("Expected PGRES_SINGLE_TUPLE, got %s",+ PQresStatus(PQresultStatus(res)));+ res = PQgetResult(conn);+ if (res == NULL)+ pg_fatal("unexpected NULL");+ if (PQresultStatus(res) != PGRES_TUPLES_OK)+ pg_fatal("Expected PGRES_TUPLES_OK, got %s",+ PQresStatus(PQresultStatus(res)));+ if (PQgetResult(conn) != NULL)+ pg_fatal("expected NULL result");++ if (PQsendQueryParams(conn, "SELECT 1", 0, NULL, NULL, NULL, NULL, 0) != 1)+ pg_fatal("failed to send query: %s",+ PQerrorMessage(conn));+ if (PQsendFlushRequest(conn) != 1)+ pg_fatal("failed to send flush request");+ res = PQgetResult(conn);+ if (res == NULL)+ pg_fatal("unexpected NULL");+ if (PQresultStatus(res) != PGRES_TUPLES_OK)+ pg_fatal("Expected PGRES_TUPLES_OK, got %s",+ PQresStatus(PQresultStatus(res)));+ if (PQgetResult(conn) != NULL)+ pg_fatal("expected NULL result");+
if (PQexitPipelineMode(conn) != 1)
pg_fatal("failed to end pipeline mode: %s", PQerrorMessage(conn));
diff --git a/src/test/modules/libpq_pipeline/traces/singlerow.trace b/src/test/modules/libpq_pipeline/traces/singlerow.traceindex 9de99befcc..83043e1407 100644--- a/src/test/modules/libpq_pipeline/traces/singlerow.trace+++ b/src/test/modules/libpq_pipeline/traces/singlerow.trace@@ -36,4 +36,24 @@ B 12 DataRow 1 2 '45'
B 12 DataRow 1 2 '46'
B 13 CommandComplete "SELECT 5"
B 5 ReadyForQuery I
+F 36 Parse "" "SELECT generate_series(0, 0)" 0+F 14 Bind "" "" 0 0 1 0+F 6 Describe P ""+F 9 Execute "" 0+F 4 Flush+B 4 ParseComplete+B 4 BindComplete+B 40 RowDescription 1 "generate_series" NNNN 0 NNNN 4 -1 0+B 11 DataRow 1 1 '0'+B 13 CommandComplete "SELECT 1"+F 16 Parse "" "SELECT 1" 0+F 14 Bind "" "" 0 0 1 0+F 6 Describe P ""+F 9 Execute "" 0+F 4 Flush+B 4 ParseComplete+B 4 BindComplete+B 33 RowDescription 1 "?column?" NNNN 0 NNNN 4 -1 0+B 11 DataRow 1 1 '1'+B 13 CommandComplete "SELECT 1"
F 4 Terminate
--
2.30.2
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: denis.laxalde@dalibo.com, pgsql-hackers@lists.postgresql.org
Subject: Re: [PATCH] Reset single-row processing mode at end of pipeline commands queue
In-Reply-To: <01af18c5-dacc-a8c8-07ee-aecc7650c3e8@dalibo.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox