Abort pgbench if script end is reached with an open pipeline
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Mon, 22 Jan 2024 16:48:30 +0000 (17:48 +0100)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Mon, 22 Jan 2024 16:48:30 +0000 (17:48 +0100)
When a pipeline is opened with \startpipeline and not closed, pgbench
will either error on the next transaction with a "already in pipeline
mode" error or successfully end if this was the last transaction --
despite not sending anything that was piped in the pipeline.

Make it an error to reach end of script is reached while there's an
open pipeline.

Backpatch to 14, where pgbench got support for pipelines.

Author: Anthonin Bonnefoy <anthonin.bonnefoy@datadoghq.com>
Reported-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/Za4IObZkDjrO4TcS@paquier.xyz

src/bin/pgbench/pgbench.c
src/bin/pgbench/t/001_pgbench_with_server.pl

index 25744548392c5ec9992e6b77587e7b190027cd31..7b53f9c24da30ba99657cb6eb3fb2796f74fbaa7 100644 (file)
@@ -3763,10 +3763,21 @@ advanceConnectionState(TState *thread, CState *st, StatsData *agg)
                        case CSTATE_START_COMMAND:
                                command = sql_script[st->use_file].commands[st->command];
 
-                               /* Transition to script end processing if done */
+                               /*
+                                * Transition to script end processing if done, but close up
+                                * shop if a pipeline is open at this point.
+                                */
                                if (command == NULL)
                                {
-                                       st->state = CSTATE_END_TX;
+                                       if (PQpipelineStatus(st->con) == PQ_PIPELINE_OFF)
+                                               st->state = CSTATE_END_TX;
+                                       else
+                                       {
+                                               pg_log_error("client %d aborted: end of script reached with pipeline open",
+                                                                        st->id);
+                                               st->state = CSTATE_ABORTED;
+                                       }
+
                                        break;
                                }
 
index fc57facf9e29be05f5c8094c2a2598c0206f1559..f60f7e89c1fbae38101c40410334c82e3cf3a201 100644 (file)
@@ -876,6 +876,34 @@ select 1 \gset f
 }
        });
 
+# Try \startpipeline without \endpipeline in a single transaction
+$node->pgbench(
+       '-t 1 -n -M extended',
+       2,
+       [],
+       [qr{end of script reached with pipeline open}],
+       'error: call \startpipeline without \endpipeline in a single transaction',
+       {
+               '001_pgbench_pipeline_5' => q{
+-- startpipeline only with single transaction
+\startpipeline
+}
+       });
+
+# Try \startpipeline without \endpipeline
+$node->pgbench(
+       '-t 2 -n -M extended',
+       2,
+       [],
+       [qr{end of script reached with pipeline open}],
+       'error: call \startpipeline without \endpipeline',
+       {
+               '001_pgbench_pipeline_6' => q{
+-- startpipeline only
+\startpipeline
+}
+       });
+
 # Working \startpipeline in prepared query mode with serializable
 $node->pgbench(
        '-c4 -t 10 -n -M prepared',