Remove pgbench's restriction on placement of -M switch.

Previously the -M switch had to appear before any switch that directly
or indirectly specified a benchmarking script.  This was both confusing
and inadequately documented, as per gripe from Tatsuo Ishii.  We can
remove the restriction at the cost of making an extra pass over the
lists of SQL commands, which seems like a cheap price (the string scans
themselves likely cost much more).  The change is just to not extract
parameters from the SQL commands until we have finished parsing the
switches and know the final value of -M.

Per discussion, we'll treat this as a low-grade bug fix and sneak it
into v10, rather than holding it for v11.

Tom Lane, reviewed by Tatsuo Ishii and Fabien Coelho

Discussion: https://postgr.es/m/20170802.110328.1963639094551443169.t-ishii@sraoss.co.jp
Discussion: https://postgr.es/m/10208.1502465077@sss.pgh.pa.us
This commit is contained in:
Tom Lane 2017-08-11 15:19:40 -04:00
parent a1ef920e27
commit 7968184429
1 changed files with 34 additions and 25 deletions

View File

@ -2844,15 +2844,18 @@ init(bool is_no_vacuum)
}
/*
* Parse the raw sql and replace :param to $n.
* Replace :param with $n throughout the command's SQL text, which
* is a modifiable string in cmd->argv[0].
*/
static bool
parseQuery(Command *cmd, const char *raw_sql)
parseQuery(Command *cmd)
{
char *sql,
*p;
sql = pg_strdup(raw_sql);
/* We don't want to scribble on cmd->argv[0] until done */
sql = pg_strdup(cmd->argv[0]);
cmd->argc = 1;
p = sql;
@ -2874,7 +2877,8 @@ parseQuery(Command *cmd, const char *raw_sql)
if (cmd->argc >= MAX_ARGS)
{
fprintf(stderr, "statement has too many arguments (maximum is %d): %s\n", MAX_ARGS - 1, raw_sql);
fprintf(stderr, "statement has too many arguments (maximum is %d): %s\n",
MAX_ARGS - 1, cmd->argv[0]);
pg_free(name);
return false;
}
@ -2886,6 +2890,7 @@ parseQuery(Command *cmd, const char *raw_sql)
cmd->argc++;
}
pg_free(cmd->argv[0]);
cmd->argv[0] = sql;
return true;
}
@ -2983,9 +2988,15 @@ process_sql_command(PQExpBuffer buf, const char *source)
my_command = (Command *) pg_malloc0(sizeof(Command));
my_command->command_num = num_commands++;
my_command->type = SQL_COMMAND;
my_command->argc = 0;
initSimpleStats(&my_command->stats);
/*
* Install query text as the sole argv string. If we are using a
* non-simple query mode, we'll extract parameters from it later.
*/
my_command->argv[0] = pg_strdup(p);
my_command->argc = 1;
/*
* If SQL command is multi-line, we only want to save the first line as
* the "line" label.
@ -3000,21 +3011,6 @@ process_sql_command(PQExpBuffer buf, const char *source)
else
my_command->line = pg_strdup(p);
switch (querymode)
{
case QUERY_SIMPLE:
my_command->argv[0] = pg_strdup(p);
my_command->argc++;
break;
case QUERY_EXTENDED:
case QUERY_PREPARED:
if (!parseQuery(my_command, p))
exit(1);
break;
default:
exit(1);
}
return my_command;
}
@ -3896,11 +3892,6 @@ main(int argc, char **argv)
break;
case 'M':
benchmarking_option_set = true;
if (num_scripts > 0)
{
fprintf(stderr, "query mode (-M) should be specified before any transaction scripts (-f or -b)\n");
exit(1);
}
for (querymode = 0; querymode < NUM_QUERYMODE; querymode++)
if (strcmp(optarg, QUERYMODE[querymode]) == 0)
break;
@ -4006,6 +3997,24 @@ main(int argc, char **argv)
internal_script_used = true;
}
/* if not simple query mode, parse the script(s) to find parameters */
if (querymode != QUERY_SIMPLE)
{
for (i = 0; i < num_scripts; i++)
{
Command **commands = sql_script[i].commands;
int j;
for (j = 0; commands[j] != NULL; j++)
{
if (commands[j]->type != SQL_COMMAND)
continue;
if (!parseQuery(commands[j]))
exit(1);
}
}
}
/* compute total_weight */
for (i = 0; i < num_scripts; i++)
/* cannot overflow: weight is 32b, total_weight 64b */