aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2023-05-25 12:36:18 +0200
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2023-05-25 12:36:18 +0200
commit8f5e42d3346924b5d6330208d62ec1b19fdbc110 (patch)
tree84450645d8944e28206b0ec1ad3ac156fec5632d
parentecb968e7e3da69a39d3efab69fa63fe6c8d04b5f (diff)
downloadpostgresql-8f5e42d3346924b5d6330208d62ec1b19fdbc110.tar.gz
postgresql-8f5e42d3346924b5d6330208d62ec1b19fdbc110.zip
Fix pgbench in prepared mode with an empty pipeline
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
-rw-r--r--src/bin/pgbench/pgbench.c44
-rw-r--r--src/bin/pgbench/t/001_pgbench_with_server.pl2
2 files changed, 28 insertions, 18 deletions
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index 7dbb2ed6a77..1d1670d4c2b 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -3050,6 +3050,27 @@ chooseScript(TState *thread)
}
/*
+ * 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.
*/
static void
@@ -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++)
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
}