Abort pgbench if script end is reached with an open pipeline
authorAlvaro Herrera
Mon, 22 Jan 2024 16:48:30 +0000 (17:48 +0100)
committerAlvaro Herrera
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 
Reported-by: Michael Paquier
Discussion: https://postgr.es/m/[email protected]

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

index 895afcbd0e0b57eb21f013cb8fa02c139ca6d45d..e5ee1a0ffa2f0eb8a6569787271c4e3dec835576 100644 (file)
@@ -3778,10 +3778,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 c1e7cffb7b8c568402b01020cd2dd1fc5fc8e6d7..85eb5bc9f00e3742db669963a7a745f21fc9f9e6 100644 (file)
@@ -841,6 +841,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',