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
This commit is contained in:
parent
ecb968e7e3
commit
8f5e42d334
@ -3049,6 +3049,27 @@ chooseScript(TState *thread)
|
|||||||
return i - 1;
|
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.
|
* 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)
|
if (command->type != SQL_COMMAND)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
|
||||||
* If not already done, allocate space for 'prepared' flags: one boolean
|
|
||||||
* for each command of each script.
|
|
||||||
*/
|
|
||||||
if (!st->prepared)
|
if (!st->prepared)
|
||||||
{
|
allocCStatePrepared(st);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!st->prepared[st->use_file][command_num])
|
if (!st->prepared[st->use_file][command_num])
|
||||||
{
|
{
|
||||||
@ -3109,13 +3115,15 @@ prepareCommandsInPipeline(CState *st)
|
|||||||
Assert(commands[st->command]->type == META_COMMAND &&
|
Assert(commands[st->command]->type == META_COMMAND &&
|
||||||
commands[st->command]->meta == META_STARTPIPELINE);
|
commands[st->command]->meta == META_STARTPIPELINE);
|
||||||
|
|
||||||
|
if (!st->prepared)
|
||||||
|
allocCStatePrepared(st);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We set the 'prepared' flag on the \startpipeline itself to flag that we
|
* 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
|
* don't need to do this next time without calling prepareCommand(), even
|
||||||
* though we don't actually prepare this command.
|
* though we don't actually prepare this command.
|
||||||
*/
|
*/
|
||||||
if (st->prepared &&
|
if (st->prepared[st->use_file][st->command])
|
||||||
st->prepared[st->use_file][st->command])
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (j = st->command + 1; commands[j] != NULL; j++)
|
for (j = st->command + 1; commands[j] != NULL; j++)
|
||||||
|
@ -790,6 +790,8 @@ $node->pgbench(
|
|||||||
'001_pgbench_pipeline_prep' => q{
|
'001_pgbench_pipeline_prep' => q{
|
||||||
-- test startpipeline
|
-- test startpipeline
|
||||||
\startpipeline
|
\startpipeline
|
||||||
|
\endpipeline
|
||||||
|
\startpipeline
|
||||||
} . "select 1;\n" x 10 . q{
|
} . "select 1;\n" x 10 . q{
|
||||||
\endpipeline
|
\endpipeline
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user