pg.ddx.io  pgsql-hackers@postgresql.org mailing list archive  
help / color / mirror / Atom feed
[PATCH] Reset single-row processing mode at end of pipeline commands queue
2+ messages / 2 participants
[nested] [flat]

Commits from this thread:
  2022-10-14 db1b931a4e 27ca0bce5f b8af4166ff  libpq: Reset singlerow flag correctly in pipeline mode
* [PATCH] Reset single-row processing mode at end of pipeline commands queue
@ 2022-10-07 13:08  Denis Laxalde <denis.laxalde@dalibo.com>
  0 siblings, 1 reply; 2+ messages in thread

From: Denis Laxalde @ 2022-10-07 13:08 UTC (permalink / raw)
  To: pgsql-hackers@lists.postgresql.org

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.c index 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.c index 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.trace index 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
^ permalink raw reply [nested|flat] 2+ messages in thread

* Re: [PATCH] Reset single-row processing mode at end of pipeline commands queue
@ 2022-10-14 17:34  Alvaro Herrera <alvherre@alvh.no-ip.org>
  parent: Denis Laxalde <denis.laxalde@dalibo.com>
  0 siblings, 0 replies; 2+ messages in thread

From: Alvaro Herrera @ 2022-10-14 17:34 UTC (permalink / raw)
  To: Denis Laxalde <denis.laxalde@dalibo.com>; +Cc: pgsql-hackers@lists.postgresql.org

Hello Denis,

On 2022-Oct-07, Denis Laxalde wrote:

> 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.

Your suggestion to move the code up seems correct to me.  Therefore, I
have pushed this including the added test code.  Thanks for an excellent
report and patch.

-- 
Álvaro Herrera        Breisgau, Deutschland  —  https://www.EnterpriseDB.com/





^ permalink  raw  reply  [nested|flat] 2+ messages in thread


end of thread, other threads:[~2022-10-14 17:34 UTC | newest]

Thread overview: 2+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2022-10-07 13:08 [PATCH] Reset single-row processing mode at end of pipeline commands queue Denis Laxalde <denis.laxalde@dalibo.com>
2022-10-14 17:34 ` Alvaro Herrera <alvherre@alvh.no-ip.org>

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