]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
libpq: Reset singlerow flag correctly in pipeline mode
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Fri, 14 Oct 2022 17:06:26 +0000 (19:06 +0200)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Fri, 14 Oct 2022 17:06:26 +0000 (19:06 +0200)
When a query whose results were requested in single-row mode is the last
in the queue by the time those results are being read, the single-row
flag was not being reset, because we were returning early from
pqPipelineProcessQueue.  Move that stanza up so that the flag is always
reset at the end of sending that query's results.

Add a test for the situation.

Backpatch to 14.

Author: Denis Laxalde <denis.laxalde@dalibo.com>
Discussion: https://postgr.es/m/01af18c5-dacc-a8c8-07ee-aecc7650c3e8@dalibo.com

src/interfaces/libpq/fe-exec.c
src/test/modules/libpq_pipeline/libpq_pipeline.c
src/test/modules/libpq_pipeline/traces/singlerow.trace

index 8484c4dda1a938fa9a5de3ac99bacf724cce5cdb..8989f7102d417693368e303b7a20b5718307e8d7 100644 (file)
@@ -3101,6 +3101,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.
@@ -3120,12 +3126,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)
        {
index bff7d4b90cc73f6f1a1406a40b54c596f33c1784..27332932a1e75f8789efec607df5275de47b171a 100644 (file)
@@ -1155,11 +1155,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];
@@ -1251,6 +1251,49 @@ 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));
 
index 9de99befcc1f54bab9ff0430151b016eb62bfe6a..83043e1407e855624a372f713ccc594eaee4cc81 100644 (file)
@@ -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