Fix pgbench in prepared mode with an empty pipeline
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 25 May 2023 10:36:18 +0000 (12:36 +0200)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 25 May 2023 10:36:18 +0000 (12:36 +0200)
It crashes because it references memory that's not allocated in that
particular case.  Fix by allocating it.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Discussion: https://postgr.es/m/bcf802a6-afc1-95b9-7bf4-c5dd868ec144@gmail.com

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

index 7dbb2ed6a779d7cc3c17b8c0e169df274546b0ac..1d1670d4c2b570420011479c260b34ddfd0c19ff 100644 (file)
@@ -3049,6 +3049,27 @@ chooseScript(TState *thread)
    return i - 1;
 }
 
+/*
+ * Allocate space for CState->prepared: we need one boolean for each command
+ * of each script.
+ */
+static void
+allocCStatePrepared(CState *st)
+{
+   Assert(st->prepared == NULL);
+
+   st->prepared = pg_malloc(sizeof(bool *) * num_scripts);
+   for (int i = 0; i < num_scripts; i++)
+   {
+       ParsedScript *script = &sql_script[i];
+       int         numcmds;
+
+       for (numcmds = 0; script->commands[numcmds] != NULL; numcmds++)
+           ;
+       st->prepared[i] = pg_malloc0(sizeof(bool) * numcmds);
+   }
+}
+
 /*
  * Prepare the SQL command from st->use_file at command_num.
  */
@@ -3061,23 +3082,8 @@ prepareCommand(CState *st, int command_num)
    if (command->type != SQL_COMMAND)
        return;
 
-   /*
-    * If not already done, allocate space for 'prepared' flags: one boolean
-    * for each command of each script.
-    */
    if (!st->prepared)
-   {
-       st->prepared = pg_malloc(sizeof(bool *) * num_scripts);
-       for (int i = 0; i < num_scripts; i++)
-       {
-           ParsedScript *script = &sql_script[i];
-           int         numcmds;
-
-           for (numcmds = 0; script->commands[numcmds] != NULL; numcmds++)
-               ;
-           st->prepared[i] = pg_malloc0(sizeof(bool) * numcmds);
-       }
-   }
+       allocCStatePrepared(st);
 
    if (!st->prepared[st->use_file][command_num])
    {
@@ -3109,13 +3115,15 @@ prepareCommandsInPipeline(CState *st)
    Assert(commands[st->command]->type == META_COMMAND &&
           commands[st->command]->meta == META_STARTPIPELINE);
 
+   if (!st->prepared)
+       allocCStatePrepared(st);
+
    /*
     * We set the 'prepared' flag on the \startpipeline itself to flag that we
     * don't need to do this next time without calling prepareCommand(), even
     * though we don't actually prepare this command.
     */
-   if (st->prepared &&
-       st->prepared[st->use_file][st->command])
+   if (st->prepared[st->use_file][st->command])
        return;
 
    for (j = st->command + 1; commands[j] != NULL; j++)
index 363a1ffabd597ad8512af1f3f029cd7b094ae7c0..f8ca8a922d172da6b4e37b48b82bc05bb3dd9db3 100644 (file)
@@ -790,6 +790,8 @@ $node->pgbench(
        '001_pgbench_pipeline_prep' => q{
 -- test startpipeline
 \startpipeline
+\endpipeline
+\startpipeline
 } . "select 1;\n" x 10 . q{
 \endpipeline
 }