Attached patch does what is described in the title, hopefully. Continuations in other pgbench backslash-commands should be dealt with elsewhere...Also attached is a small test script.
Here is another approach, with "infered" continuations: no backslash is needed, the parsing is pursued if the last token of the line cannot end an expression (eg an operator) or if there is an unclosed parenthesis.
I think that backslashes are less surprising for the classically minded user, but this one is more fun:-) Also, this version changes a little more the scanner because on each token the next state (continued or not) must be decided.
-- Fabien.
diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml index 285608d..f066be1 100644 --- a/doc/src/sgml/ref/pgbench.sgml +++ b/doc/src/sgml/ref/pgbench.sgml @@ -826,13 +826,17 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</> <literal>%</>) with their usual precedence and associativity, <link linkend="pgbench-builtin-functions">function calls</>, and parentheses. + Expressions can spead several lines till completed: the parsing is + pursued if a token at the end of the line cannot end an expression + or if there is an unclosed parenthesis. </para> <para> Examples: <programlisting> \set ntellers 10 * :scale -\set aid (1021 * random(1, 100000 * :scale)) % (100000 * :scale) + 1 +\set aid (1021 * random(1, 100000 * :scale)) % + (100000 * :scale) + 1 </programlisting></para> </listitem> </varlistentry> diff --git a/src/bin/pgbench/exprscan.l b/src/bin/pgbench/exprscan.l index 20891a3..1b0d4d0 100644 --- a/src/bin/pgbench/exprscan.l +++ b/src/bin/pgbench/exprscan.l @@ -43,6 +43,16 @@ static bool last_was_newline = false; extern int expr_yyget_column(yyscan_t yyscanner); extern void expr_yyset_column(int column_no, yyscan_t yyscanner); +/* the expression cannot end on this token */ +#define TO_COEX \ + cur_state->start_state = COEX; \ + BEGIN(COEX) + +/* continuation if unclosed parentheses */ +#define TO_EXPR \ + cur_state->start_state = cur_state->paren_depth > 0 ? COEX : EXPR; \ + BEGIN(cur_state->start_state) + %} /* Except for the prefix, these options should match psqlscan.l */ @@ -67,7 +77,7 @@ nonspace [^ \t\r\f\v\n] newline [\n] /* Exclusive states */ -%x EXPR +%x EXPR COEX %% @@ -104,46 +114,64 @@ newline [\n] return 0; } + /* COEX (continued expression) state */ + +<COEX>{ + +{newline} { /* ignore */ } + +} + /* EXPR state */ <EXPR>{ -"+" { return '+'; } -"-" { return '-'; } -"*" { return '*'; } -"/" { return '/'; } -"%" { return '%'; } -"(" { return '('; } -")" { return ')'; } -"," { return ','; } +{newline} { + /* report end of command */ + last_was_newline = true; + return 0; + } +} + + /* EXPR & COEX states common rules */ + +<EXPR,COEX>{ + +"+" { TO_COEX; return '+'; } +"-" { TO_COEX; return '-'; } +"*" { TO_COEX; return '*'; } +"/" { TO_COEX; return '/'; } +"%" { TO_COEX; return '%'; } +"(" { cur_state->paren_depth++; TO_COEX; return '('; } +")" { cur_state->paren_depth--; TO_EXPR; return ')'; } +"," { TO_COEX; return ','; } :{alnum}+ { yylval->str = pg_strdup(yytext + 1); + TO_EXPR; return VARIABLE; } {digit}+ { yylval->ival = strtoint64(yytext); + TO_EXPR; return INTEGER_CONST; } {digit}+(\.{digit}*)?([eE][-+]?{digit}+)? { yylval->dval = atof(yytext); + TO_EXPR; return DOUBLE_CONST; } \.{digit}+([eE][-+]?{digit}+)? { yylval->dval = atof(yytext); + TO_EXPR; return DOUBLE_CONST; } {alpha}{alnum}* { yylval->str = pg_strdup(yytext); + TO_COEX; return FUNCTION; } -{newline} { - /* report end of command */ - last_was_newline = true; - return 0; - } - {space}+ { /* ignore */ } . {
cont2.sql
Description: application/sql
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers