On 2023-May-20, Alexander Lakhin wrote: > Starting from 038f586d5, the following script: > echo " > \startpipeline > \endpipeline > " >test.sql > pgbench -n -M prepared -f test.sql > > leads to the pgbench's segfault:
Hah, yeah, that's because an empty pipeline never calls the code to allocate the flag array. Here's the trivial fix. -- Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/ "El hombre nunca sabe de lo que es capaz hasta que lo intenta" (C. Dickens)
>From 50685847e057eb8e7509293fdd81247eb49854ef Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Mon, 22 May 2023 13:45:47 +0200 Subject: [PATCH] Fix pgbench in prepared mode with empty pipeline --- src/bin/pgbench/pgbench.c | 44 ++++++++++++-------- src/bin/pgbench/t/001_pgbench_with_server.pl | 2 + 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 7dbb2ed6a77..6caa84282c7 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -3049,6 +3049,27 @@ chooseScript(TState *thread) return i - 1; } +/* + * Allocate space for 'prepared' flags of a script: we need one boolean + * for each command of each script. + */ +static void +allocatePreparedFlags(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); - } - } + allocatePreparedFlags(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) + allocatePreparedFlags(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++) diff --git a/src/bin/pgbench/t/001_pgbench_with_server.pl b/src/bin/pgbench/t/001_pgbench_with_server.pl index 363a1ffabd5..f8ca8a922d1 100644 --- a/src/bin/pgbench/t/001_pgbench_with_server.pl +++ b/src/bin/pgbench/t/001_pgbench_with_server.pl @@ -790,6 +790,8 @@ $node->pgbench( '001_pgbench_pipeline_prep' => q{ -- test startpipeline \startpipeline +\endpipeline +\startpipeline } . "select 1;\n" x 10 . q{ \endpipeline } -- 2.39.2