@ -482,6 +482,8 @@ typedef enum MetaCommand
META_SETSHELL , /* \setshell */
META_SHELL , /* \shell */
META_SLEEP , /* \sleep */
META_CSET , /* \cset */
META_GSET , /* \gset */
META_IF , /* \if */
META_ELIF , /* \elif */
META_ELSE , /* \else */
@ -499,16 +501,39 @@ typedef enum QueryMode
static QueryMode querymode = QUERY_SIMPLE ;
static const char * QUERYMODE [ ] = { " simple " , " extended " , " prepared " } ;
typedef struct
{
char * line ; /* text of command line */
int command_num ; /* unique index of this Command struct */
int type ; /* command type (SQL_COMMAND or META_COMMAND) */
MetaCommand meta ; /* meta command identifier, or META_NONE */
int argc ; /* number of command words */
char * argv [ MAX_ARGS ] ; /* command word list */
PgBenchExpr * expr ; /* parsed expression, if needed */
SimpleStats stats ; /* time spent in this command */
/*
* struct Command represents one command in a script .
*
* lines The raw , possibly multi - line command text . Variable substitution
* not applied .
* first_line A short , single - line extract of ' lines ' , for error reporting .
* type SQL_COMMAND or META_COMMAND
* meta The type of meta - command , or META_NONE if command is SQL
* argc Number of arguments of the command , 0 if not yet processed .
* argv Command arguments , the first of which is the command or SQL
* string itself . For SQL commands , after post - processing
* argv [ 0 ] is the same as ' lines ' with variables substituted .
* nqueries In a multi - command SQL line , the number of queries .
* varprefix SQL commands terminated with \ gset or \ cset have this set
* to a non NULL value . If nonempty , it ' s used to prefix the
* variable name that receives the value .
* varprefix_max Allocated size of the varprefix array .
* expr Parsed expression , if needed .
* stats Time spent in this command .
*/
typedef struct Command
{
PQExpBufferData lines ;
char * first_line ;
int type ;
MetaCommand meta ;
int argc ;
char * argv [ MAX_ARGS ] ;
int nqueries ;
char * * varprefix ;
int varprefix_max ;
PgBenchExpr * expr ;
SimpleStats stats ;
} Command ;
typedef struct ParsedScript
@ -521,7 +546,6 @@ typedef struct ParsedScript
static ParsedScript sql_script [ MAX_SCRIPTS ] ; /* SQL script files */
static int num_scripts ; /* number of scripts in sql_script[] */
static int num_commands = 0 ; /* total number of Command structs */
static int64 total_weight = 0 ;
static int debug = 0 ; /* debug flag */
@ -587,6 +611,7 @@ static void doLog(TState *thread, CState *st,
static void processXactStats ( TState * thread , CState * st , instr_time * now ,
bool skipped , StatsData * agg ) ;
static void pgbench_error ( const char * fmt , . . . ) pg_attribute_printf ( 1 , 2 ) ;
static void allocate_command_varprefix ( Command * cmd , int totalqueries ) ;
static void addScript ( ParsedScript script ) ;
static void * threadRun ( void * arg ) ;
static void finishCon ( CState * st ) ;
@ -2569,6 +2594,10 @@ getMetaCommand(const char *cmd)
mc = META_ELSE ;
else if ( pg_strcasecmp ( cmd , " endif " ) = = 0 )
mc = META_ENDIF ;
else if ( pg_strcasecmp ( cmd , " cset " ) = = 0 )
mc = META_CSET ;
else if ( pg_strcasecmp ( cmd , " gset " ) = = 0 )
mc = META_GSET ;
else
mc = META_NONE ;
return mc ;
@ -2796,6 +2825,109 @@ sendCommand(CState *st, Command *command)
return true ;
}
/*
* Process query response from the backend .
*
* If varprefix is not NULL , it ' s the array of variable prefix names where to
* store the results .
*
* Returns true if everything is A - OK , false if any error occurs .
*/
static bool
readCommandResponse ( CState * st , char * * varprefix )
{
PGresult * res ;
int qrynum = 0 ;
while ( ( res = PQgetResult ( st - > con ) ) ! = NULL )
{
switch ( PQresultStatus ( res ) )
{
case PGRES_COMMAND_OK : /* non-SELECT commands */
case PGRES_EMPTY_QUERY : /* may be used for testing no-op overhead */
if ( varprefix & & varprefix [ qrynum ] ! = NULL )
{
fprintf ( stderr ,
" client %d script %d command %d query %d: expected one row, got %d \n " ,
st - > id , st - > use_file , st - > command , qrynum , 0 ) ;
st - > ecnt + + ;
return false ;
}
break ;
case PGRES_TUPLES_OK :
if ( varprefix & & varprefix [ qrynum ] ! = NULL )
{
if ( PQntuples ( res ) ! = 1 )
{
fprintf ( stderr ,
" client %d script %d command %d query %d: expected one row, got %d \n " ,
st - > id , st - > use_file , st - > command , qrynum , PQntuples ( res ) ) ;
st - > ecnt + + ;
PQclear ( res ) ;
discard_response ( st ) ;
return false ;
}
/* store results into variables */
for ( int fld = 0 ; fld < PQnfields ( res ) ; fld + + )
{
char * varname = PQfname ( res , fld ) ;
/* allocate varname only if necessary, freed below */
if ( * varprefix [ qrynum ] ! = ' \0 ' )
varname =
psprintf ( " %s%s " , varprefix [ qrynum ] , varname ) ;
/* store result as a string */
if ( ! putVariable ( st , " gset " , varname ,
PQgetvalue ( res , 0 , fld ) ) )
{
/* internal error */
fprintf ( stderr ,
" client %d script %d command %d query %d: error storing into variable %s \n " ,
st - > id , st - > use_file , st - > command , qrynum ,
varname ) ;
st - > ecnt + + ;
PQclear ( res ) ;
discard_response ( st ) ;
return false ;
}
if ( * varprefix [ qrynum ] ! = ' \0 ' )
pg_free ( varname ) ;
}
}
/* otherwise the result is simply thrown away by PQclear below */
break ;
default :
/* anything else is unexpected */
fprintf ( stderr ,
" client %d script %d aborted in command %d query %d: %s " ,
st - > id , st - > use_file , st - > command , qrynum ,
PQerrorMessage ( st - > con ) ) ;
st - > ecnt + + ;
PQclear ( res ) ;
discard_response ( st ) ;
return false ;
}
PQclear ( res ) ;
qrynum + + ;
}
if ( qrynum = = 0 )
{
fprintf ( stderr , " client %d command %d: no results \n " , st - > id , st - > command ) ;
st - > ecnt + + ;
return false ;
}
return true ;
}
/*
* Parse the argument to a \ sleep command , and return the requested amount
* of delay , in microseconds . Returns true on success , false on error .
@ -2862,8 +2994,6 @@ advanceConnectionState(TState *thread, CState *st, StatsData *agg)
*/
for ( ; ; )
{
PGresult * res ;
switch ( st - > state )
{
/* Select transaction (script) to run. */
@ -3141,24 +3271,11 @@ advanceConnectionState(TState *thread, CState *st, StatsData *agg)
if ( PQisBusy ( st - > con ) )
return ; /* don't have the whole result yet */
/* Read and discard the query result */
res = PQgetResult ( st - > con ) ;
switch ( PQresultStatus ( res ) )
{
case PGRES_COMMAND_OK :
case PGRES_TUPLES_OK :
case PGRES_EMPTY_QUERY :
/* OK */
PQclear ( res ) ;
discard_response ( st ) ;
st - > state = CSTATE_END_COMMAND ;
break ;
default :
commandFailed ( st , " SQL " , PQerrorMessage ( st - > con ) ) ;
PQclear ( res ) ;
st - > state = CSTATE_ABORTED ;
break ;
}
/* store or discard the query results */
if ( readCommandResponse ( st , sql_script [ st - > use_file ] . commands [ st - > command ] - > varprefix ) )
st - > state = CSTATE_END_COMMAND ;
else
st - > state = CSTATE_ABORTED ;
break ;
/*
@ -3191,7 +3308,7 @@ advanceConnectionState(TState *thread, CState *st, StatsData *agg)
INSTR_TIME_SET_CURRENT_LAZY ( now ) ;
command = sql_script [ st - > use_file ] . commands [ st - > command ] ;
command = sql_script [ st - > use_file ] . commands [ st - > command ] ;
/* XXX could use a mutex here, but we choose not to */
addToSimpleStats ( & command - > stats ,
INSTR_TIME_GET_DOUBLE ( now ) -
@ -3235,9 +3352,8 @@ advanceConnectionState(TState *thread, CState *st, StatsData *agg)
st - > state = CSTATE_CHOOSE_SCRIPT ;
/*
* Ensure that we always return on this point , so as to
* avoid an infinite loop if the script only contains meta
* commands .
* Ensure that we always return on this point , so as to avoid
* an infinite loop if the script only contains meta commands .
*/
return ;
@ -3976,7 +4092,7 @@ runInitSteps(const char *initialize_steps)
/*
* Replace : param with $ n throughout the command ' s SQL text , which
* is a modifiable string in cmd - > argv [ 0 ] .
* is a modifiable string in cmd - > lines .
*/
static bool
parseQuery ( Command * cmd )
@ -3984,12 +4100,9 @@ parseQuery(Command *cmd)
char * sql ,
* p ;
/* We don't want to scribble on cmd->argv[0] until done */
sql = pg_strdup ( cmd - > argv [ 0 ] ) ;
cmd - > argc = 1 ;
p = sql ;
p = sql = pg_strdup ( cmd - > lines . data ) ;
while ( ( p = strchr ( p , ' : ' ) ) ! = NULL )
{
char var [ 13 ] ;
@ -4009,7 +4122,7 @@ parseQuery(Command *cmd)
if ( cmd - > argc > = MAX_ARGS )
{
fprintf ( stderr , " statement has too many arguments (maximum is %d): %s \n " ,
MAX_ARGS - 1 , cmd - > argv [ 0 ] ) ;
MAX_ARGS - 1 , cmd - > lines . data ) ;
pg_free ( name ) ;
return false ;
}
@ -4021,7 +4134,7 @@ parseQuery(Command *cmd)
cmd - > argc + + ;
}
pg_free ( cmd - > argv [ 0 ] ) ;
Assert ( cmd - > argv [ 0 ] = = NULL ) ;
cmd - > argv [ 0 ] = sql ;
return true ;
}
@ -4081,21 +4194,16 @@ syntax_error(const char *source, int lineno,
}
/*
* Parse a SQL command ; return a Command struct , or NULL if it ' s a comment
*
* On entry , psqlscan . l has collected the command into " buf " , so we don ' t
* really need to do much here except check for comment and set up a
* Command struct .
* Return a pointer to the start of the SQL command , after skipping over
* whitespace and " -- " comments .
* If the end of the string is reached , return NULL .
*/
static Command *
process_sql_command ( PQExpBuffer buf , const char * source )
static char *
skip_sql_comments ( char * sql_command )
{
Command * my_command ;
char * p ;
char * nlpos ;
char * p = sql_command ;
/* Skip any leading whitespace, as well as "--" style comments */
p = buf - > data ;
for ( ; ; )
{
if ( isspace ( ( unsigned char ) * p ) )
@ -4111,39 +4219,151 @@ process_sql_command(PQExpBuffer buf, const char *source)
break ;
}
/* If there's nothing but whitespace and comments, we're done */
/* NULL if there's nothing but whitespace and comments */
if ( * p = = ' \0 ' )
return NULL ;
return p ;
}
/*
* Parse a SQL command ; return a Command struct , or NULL if it ' s a comment
*
* On entry , psqlscan . l has collected the command into " buf " , so we don ' t
* really need to do much here except check for comments and set up a Command
* struct .
*/
static Command *
create_sql_command ( PQExpBuffer buf , const char * source , int numqueries )
{
Command * my_command ;
char * p = skip_sql_comments ( buf - > data ) ;
if ( p = = NULL )
return NULL ;
/* Allocate and initialize Command structure */
my_command = ( Command * ) pg_malloc0 ( sizeof ( Command ) ) ;
my_command - > command_num = num_commands + + ;
my_command = ( Command * ) pg_malloc ( sizeof ( Command ) ) ;
initPQExpBuffer ( & my_command - > lines ) ;
appendPQExpBufferStr ( & my_command - > lines , p ) ;
my_command - > first_line = NULL ; /* this is set later */
my_command - > type = SQL_COMMAND ;
my_command - > meta = META_NONE ;
my_command - > argc = 0 ;
memset ( my_command - > argv , 0 , sizeof ( my_command - > argv ) ) ;
my_command - > nqueries = numqueries ;
my_command - > varprefix = NULL ; /* allocated later, if needed */
my_command - > varprefix_max = 0 ;
my_command - > expr = NULL ;
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 ;
return my_command ;
}
/* Free a Command structure and associated data */
static void
free_command ( Command * command )
{
termPQExpBuffer ( & command - > lines ) ;
if ( command - > first_line )
pg_free ( command - > first_line ) ;
if ( command - > argv )
for ( int i = 0 ; i < command - > argc ; i + + )
pg_free ( command - > argv [ i ] ) ;
if ( command - > varprefix )
{
for ( int i = 0 ; i < command - > varprefix_max ; i + + )
if ( command - > varprefix [ i ] & &
command - > varprefix [ i ] [ 0 ] ! = ' \0 ' ) /* see ParseScript */
pg_free ( command - > varprefix [ i ] ) ;
pg_free ( command - > varprefix ) ;
}
/*
* If SQL command is multi - line , we only want to save the first line as
* the " line " label .
* It should also free expr recursively , but this is currently not needed
* as only \ { g , c } set commands ( which do not have an expression ) are freed .
*/
nlpos = strchr ( p , ' \n ' ) ;
if ( nlpos )
pg_free ( command ) ;
}
/*
* append " more " text to current compound command which had been interrupted
* by \ cset .
*/
static void
append_sql_command ( Command * my_command , char * more , int numqueries )
{
Assert ( my_command - > type = = SQL_COMMAND & & my_command - > lines . len > 0 ) ;
more = skip_sql_comments ( more ) ;
if ( more = = NULL )
return ;
/* append command text, embedding a ';' in place of the \cset */
appendPQExpBuffer ( & my_command - > lines , " ; \n %s " , more ) ;
my_command - > nqueries + = numqueries ;
}
/*
* Once an SQL command is fully parsed , possibly by accumulating several
* parts , complete other fields of the Command structure .
*/
static void
postprocess_sql_command ( Command * my_command )
{
char buffer [ 128 ] ;
Assert ( my_command - > type = = SQL_COMMAND ) ;
/* Save the first line for error display. */
strlcpy ( buffer , my_command - > lines . data , sizeof ( buffer ) ) ;
buffer [ strcspn ( buffer , " \n \r " ) ] = ' \0 ' ;
my_command - > first_line = pg_strdup ( buffer ) ;
/* parse query if necessary */
switch ( querymode )
{
my_command - > line = pg_malloc ( nlpos - p + 1 ) ;
memcpy ( my_command - > line , p , nlpos - p ) ;
my_command - > line [ nlpos - p ] = ' \0 ' ;
case QUERY_SIMPLE :
my_command - > argv [ 0 ] = my_command - > lines . data ;
my_command - > argc + + ;
break ;
case QUERY_EXTENDED :
case QUERY_PREPARED :
if ( ! parseQuery ( my_command ) )
exit ( 1 ) ;
break ;
default :
exit ( 1 ) ;
}
else
my_command - > line = pg_strdup ( p ) ;
}
return my_command ;
/*
* Determine the command ' s varprefix size needed and allocate memory for it
*/
static void
allocate_command_varprefix ( Command * cmd , int totalqueries )
{
int new_max ;
/* sufficient space already allocated? */
if ( totalqueries < = cmd - > varprefix_max )
return ;
/* determine the new array size */
new_max = Max ( cmd - > varprefix_max , 2 ) ;
while ( new_max < totalqueries )
new_max * = 2 ;
/* enlarge the array, zero-initializing the allocated space */
if ( cmd - > varprefix = = NULL )
cmd - > varprefix = pg_malloc0 ( sizeof ( char * ) * new_max ) ;
else
{
cmd - > varprefix = pg_realloc ( cmd - > varprefix , sizeof ( char * ) * new_max ) ;
memset ( cmd - > varprefix + cmd - > varprefix_max , 0 ,
sizeof ( char * ) * ( new_max - cmd - > varprefix_max ) ) ;
}
cmd - > varprefix_max = new_max ;
}
/*
@ -4177,7 +4397,6 @@ process_backslash_command(PsqlScanState sstate, const char *source)
/* Allocate and initialize Command structure */
my_command = ( Command * ) pg_malloc0 ( sizeof ( Command ) ) ;
my_command - > command_num = num_commands + + ;
my_command - > type = META_COMMAND ;
my_command - > argc = 0 ;
initSimpleStats ( & my_command - > stats ) ;
@ -4201,7 +4420,7 @@ process_backslash_command(PsqlScanState sstate, const char *source)
if ( my_command - > meta = = META_SET )
{
if ( ! expr_lex_one_word ( sstate , & word_buf , & word_offset ) )
syntax_error ( source , lineno , my_command - > line , my_command - > argv [ 0 ] ,
syntax_error ( source , lineno , my_command - > first_ line, my_command - > argv [ 0 ] ,
" missing argument " , NULL , - 1 ) ;
offsets [ j ] = word_offset ;
@ -4222,10 +4441,11 @@ process_backslash_command(PsqlScanState sstate, const char *source)
my_command - > expr = expr_parse_result ;
/* Save line, trimming any trailing newline */
my_command - > line = expr_scanner_get_substring ( sstate ,
start_offset ,
expr_scanner_offset ( sstate ) ,
true ) ;
my_command - > first_line =
expr_scanner_get_substring ( sstate ,
start_offset ,
expr_scanner_offset ( sstate ) ,
true ) ;
expr_scanner_finish ( yyscanner ) ;
@ -4238,7 +4458,7 @@ process_backslash_command(PsqlScanState sstate, const char *source)
while ( expr_lex_one_word ( sstate , & word_buf , & word_offset ) )
{
if ( j > = MAX_ARGS )
syntax_error ( source , lineno , my_command - > line , my_command - > argv [ 0 ] ,
syntax_error ( source , lineno , my_command - > first_ line, my_command - > argv [ 0 ] ,
" too many arguments " , NULL , - 1 ) ;
offsets [ j ] = word_offset ;
@ -4247,19 +4467,20 @@ process_backslash_command(PsqlScanState sstate, const char *source)
}
/* Save line, trimming any trailing newline */
my_command - > line = expr_scanner_get_substring ( sstate ,
start_offset ,
expr_scanner_offset ( sstate ) ,
true ) ;
my_command - > first_line =
expr_scanner_get_substring ( sstate ,
start_offset ,
expr_scanner_offset ( sstate ) ,
true ) ;
if ( my_command - > meta = = META_SLEEP )
{
if ( my_command - > argc < 2 )
syntax_error ( source , lineno , my_command - > line , my_command - > argv [ 0 ] ,
syntax_error ( source , lineno , my_command - > first_ line, my_command - > argv [ 0 ] ,
" missing argument " , NULL , - 1 ) ;
if ( my_command - > argc > 3 )
syntax_error ( source , lineno , my_command - > line , my_command - > argv [ 0 ] ,
syntax_error ( source , lineno , my_command - > first_ line, my_command - > argv [ 0 ] ,
" too many arguments " , NULL ,
offsets [ 3 ] - start_offset ) ;
@ -4288,7 +4509,7 @@ process_backslash_command(PsqlScanState sstate, const char *source)
if ( pg_strcasecmp ( my_command - > argv [ 2 ] , " us " ) ! = 0 & &
pg_strcasecmp ( my_command - > argv [ 2 ] , " ms " ) ! = 0 & &
pg_strcasecmp ( my_command - > argv [ 2 ] , " s " ) ! = 0 )
syntax_error ( source , lineno , my_command - > line , my_command - > argv [ 0 ] ,
syntax_error ( source , lineno , my_command - > first_ line, my_command - > argv [ 0 ] ,
" unrecognized time unit, must be us, ms or s " ,
my_command - > argv [ 2 ] , offsets [ 2 ] - start_offset ) ;
}
@ -4296,25 +4517,31 @@ process_backslash_command(PsqlScanState sstate, const char *source)
else if ( my_command - > meta = = META_SETSHELL )
{
if ( my_command - > argc < 3 )
syntax_error ( source , lineno , my_command - > line , my_command - > argv [ 0 ] ,
syntax_error ( source , lineno , my_command - > first_ line, my_command - > argv [ 0 ] ,
" missing argument " , NULL , - 1 ) ;
}
else if ( my_command - > meta = = META_SHELL )
{
if ( my_command - > argc < 2 )
syntax_error ( source , lineno , my_command - > line , my_command - > argv [ 0 ] ,
syntax_error ( source , lineno , my_command - > first_ line, my_command - > argv [ 0 ] ,
" missing command " , NULL , - 1 ) ;
}
else if ( my_command - > meta = = META_ELSE | | my_command - > meta = = META_ENDIF )
{
if ( my_command - > argc ! = 1 )
syntax_error ( source , lineno , my_command - > line , my_command - > argv [ 0 ] ,
syntax_error ( source , lineno , my_command - > first_ line, my_command - > argv [ 0 ] ,
" unexpected argument " , NULL , - 1 ) ;
}
else if ( my_command - > meta = = META_CSET | | my_command - > meta = = META_GSET )
{
if ( my_command - > argc > 2 )
syntax_error ( source , lineno , my_command - > first_line , my_command - > argv [ 0 ] ,
" too many arguments " , NULL , - 1 ) ;
}
else
{
/* my_command->meta == META_NONE */
syntax_error ( source , lineno , my_command - > line , my_command - > argv [ 0 ] ,
syntax_error ( source , lineno , my_command - > first_ line, my_command - > argv [ 0 ] ,
" invalid command " , NULL , - 1 ) ;
}
@ -4393,6 +4620,9 @@ ParseScript(const char *script, const char *desc, int weight)
PQExpBufferData line_buf ;
int alloc_num ;
int index ;
bool saw_cset = false ;
int lineno ;
int start_offset ;
# define COMMANDS_ALLOC_NUM 128
alloc_num = COMMANDS_ALLOC_NUM ;
@ -4416,6 +4646,7 @@ ParseScript(const char *script, const char *desc, int weight)
* stdstrings should be true , which is a bit riskier .
*/
psql_scan_setup ( sstate , script , strlen ( script ) , 0 , true ) ;
start_offset = expr_scanner_offset ( sstate ) - 1 ;
initPQExpBuffer ( & line_buf ) ;
@ -4425,45 +4656,115 @@ ParseScript(const char *script, const char *desc, int weight)
{
PsqlScanResult sr ;
promptStatus_t prompt ;
Command * command ;
Command * command = NULL ;
int semicolons ;
resetPQExpBuffer ( & line_buf ) ;
lineno = expr_scanner_get_lineno ( sstate , start_offset ) ;
sr = psql_scan ( sstate , & line_buf , & prompt ) ;
/* If we collected a SQL command, process that */
command = process_sql_command ( & line_buf , desc ) ;
if ( command )
semicolons = psql_scan_get_escaped_semicolons ( sstate ) ;
if ( saw_cset )
{
ps . commands [ index ] = command ;
index + + ;
/* the previous multi-line command ended with \cset */
append_sql_command ( ps . commands [ index - 1 ] , line_buf . data ,
semicolons + 1 ) ;
saw_cset = false ;
}
else
{
/* If we collected a new SQL command, process that */
command = create_sql_command ( & line_buf , desc , semicolons + 1 ) ;
if ( index > = alloc_num )
{
alloc_num + = COMMANDS_ALLOC_NUM ;
ps . commands = ( Command * * )
pg_realloc ( ps . commands , sizeof ( Command * ) * alloc_num ) ;
}
/* store new command */
if ( command )
ps . commands [ index + + ] = command ;
}
/* If we reached a backslash, process that */
if ( sr = = PSCAN_BACKSLASH )
{
command = process_backslash_command ( sstate , desc ) ;
if ( command )
{
ps . commands [ index ] = command ;
index + + ;
if ( index > = alloc_num )
/*
* If this is gset / cset , merge into the preceding command . ( We
* don ' t use a command slot in this case ) .
*/
if ( command - > meta = = META_CSET | |
command - > meta = = META_GSET )
{
alloc_num + = COMMANDS_ALLOC_NUM ;
ps . commands = ( Command * * )
pg_realloc ( ps . commands , sizeof ( Command * ) * alloc_num ) ;
int cindex ;
Command * cmd ;
/*
* If \ cset is seen , set flag to leave the command pending
* for the next iteration to process .
*/
saw_cset = command - > meta = = META_CSET ;
if ( index = = 0 )
syntax_error ( desc , lineno , NULL , NULL ,
" \\ gset/cset cannot start a script " ,
NULL , - 1 ) ;
cmd = ps . commands [ index - 1 ] ;
if ( cmd - > type ! = SQL_COMMAND )
syntax_error ( desc , lineno , NULL , NULL ,
" \\ gset/cset must follow a SQL command " ,
cmd - > first_line , - 1 ) ;
/* this {g,c}set applies to the previous query */
cindex = cmd - > nqueries - 1 ;
/*
* now that we know there ' s a { g , c } set in this command ,
* allocate space for the variable name prefix array .
*/
allocate_command_varprefix ( cmd , cmd - > nqueries ) ;
/*
* Don ' t allow the previous command be a gset / cset ; that
* would make no sense .
*/
if ( cmd - > varprefix [ cindex ] ! = NULL )
syntax_error ( desc , lineno , NULL , NULL ,
" \\ gset/cset cannot follow one another " ,
NULL , - 1 ) ;
/* get variable prefix */
if ( command - > argc < = 1 | | command - > argv [ 1 ] [ 0 ] = = ' \0 ' )
cmd - > varprefix [ cindex ] = " " ; /* avoid strdup */
else
cmd - > varprefix [ cindex ] = pg_strdup ( command - > argv [ 1 ] ) ;
/* cleanup unused command */
free_command ( command ) ;
continue ;
}
/* Attach any other backslash command as a new command */
ps . commands [ index + + ] = command ;
}
}
/*
* Since we used a command slot , allocate more if needed . Note we
* always allocate one more in order to accomodate the NULL terminator
* below .
*/
if ( index > = alloc_num )
{
alloc_num + = COMMANDS_ALLOC_NUM ;
ps . commands = ( Command * * )
pg_realloc ( ps . commands , sizeof ( Command * ) * alloc_num ) ;
}
/* Done if we reached EOF */
if ( sr = = PSCAN_INCOMPLETE | | sr = = PSCAN_EOL )
break ;
@ -4819,7 +5120,7 @@ printResults(TState *threads, StatsData *total, instr_time total_time,
printf ( " %11.3f %s \n " ,
( cstats - > count > 0 ) ?
1000.0 * cstats - > sum / cstats - > count : 0.0 ,
( * commands ) - > line ) ;
( * commands ) - > first_ line) ;
}
}
}
@ -5286,28 +5587,18 @@ 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 )
/* complete SQL command initialization and compute total weight */
for ( i = 0 ; i < num_scripts ; i + + )
{
for ( i = 0 ; i < num_scripts ; i + + )
{
Command * * commands = sql_script [ i ] . commands ;
int j ;
Command * * commands = sql_script [ i ] . commands ;
for ( j = 0 ; commands [ j ] ! = NULL ; j + + )
{
if ( commands [ j ] - > type ! = SQL_COMMAND )
continue ;
if ( ! parseQuery ( commands [ j ] ) )
exit ( 1 ) ;
}
}
}
for ( int j = 0 ; commands [ j ] ! = NULL ; j + + )
if ( commands [ j ] - > type = = SQL_COMMAND )
postprocess_sql_command ( commands [ j ] ) ;
/* compute total_weight */
for ( i = 0 ; i < num_scripts ; i + + )
/* cannot overflow: weight is 32b, total_weight 64b */
total_weight + = sql_script [ i ] . weight ;
}
if ( total_weight = = 0 & & ! is_init_mode )
{