Fix plpgsql to not treat INSERT INTO as an INTO-variables clause anywhere
in the string, not just at the start. Per bug #4629 from Martin Blazek. Back-patch to 8.2; prior versions don't have the problem, at least not in the reported case, because they don't try to recognize INTO in non-SELECT statements. (IOW, this is really fallout from the RETURNING patch.)
This commit is contained in:
parent
775f1b379e
commit
c401a5ce58
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.119 2009/01/07 13:44:37 tgl Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.120 2009/02/02 20:25:38 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -149,7 +149,7 @@ static List *read_raise_options(void);
|
|||||||
%type <loop_body> loop_body
|
%type <loop_body> loop_body
|
||||||
%type <stmt> proc_stmt pl_block
|
%type <stmt> proc_stmt pl_block
|
||||||
%type <stmt> stmt_assign stmt_if stmt_loop stmt_while stmt_exit
|
%type <stmt> stmt_assign stmt_if stmt_loop stmt_while stmt_exit
|
||||||
%type <stmt> stmt_return stmt_raise stmt_execsql stmt_execsql_insert
|
%type <stmt> stmt_return stmt_raise stmt_execsql
|
||||||
%type <stmt> stmt_dynexecute stmt_for stmt_perform stmt_getdiag
|
%type <stmt> stmt_dynexecute stmt_for stmt_perform stmt_getdiag
|
||||||
%type <stmt> stmt_open stmt_fetch stmt_move stmt_close stmt_null
|
%type <stmt> stmt_open stmt_fetch stmt_move stmt_close stmt_null
|
||||||
%type <stmt> stmt_case
|
%type <stmt> stmt_case
|
||||||
@ -646,8 +646,6 @@ proc_stmt : pl_block ';'
|
|||||||
{ $$ = $1; }
|
{ $$ = $1; }
|
||||||
| stmt_execsql
|
| stmt_execsql
|
||||||
{ $$ = $1; }
|
{ $$ = $1; }
|
||||||
| stmt_execsql_insert
|
|
||||||
{ $$ = $1; }
|
|
||||||
| stmt_dynexecute
|
| stmt_dynexecute
|
||||||
{ $$ = $1; }
|
{ $$ = $1; }
|
||||||
| stmt_perform
|
| stmt_perform
|
||||||
@ -1482,27 +1480,15 @@ stmt_execsql : execsql_start lno
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
/* this matches any otherwise-unrecognized starting keyword */
|
/* T_WORD+T_ERROR match any otherwise-unrecognized starting keyword */
|
||||||
execsql_start : T_WORD
|
execsql_start : K_INSERT
|
||||||
|
{ $$ = pstrdup(yytext); }
|
||||||
|
| T_WORD
|
||||||
{ $$ = pstrdup(yytext); }
|
{ $$ = pstrdup(yytext); }
|
||||||
| T_ERROR
|
| T_ERROR
|
||||||
{ $$ = pstrdup(yytext); }
|
{ $$ = pstrdup(yytext); }
|
||||||
;
|
;
|
||||||
|
|
||||||
stmt_execsql_insert : K_INSERT lno K_INTO
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We have to special-case INSERT so that its INTO
|
|
||||||
* won't be treated as an INTO-variables clause.
|
|
||||||
*
|
|
||||||
* Fortunately, this is the only valid use of INTO
|
|
||||||
* in a pl/pgsql SQL command, and INTO is already
|
|
||||||
* a fully reserved word in the main grammar.
|
|
||||||
*/
|
|
||||||
$$ = make_execsql_stmt("INSERT INTO", $2);
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
stmt_dynexecute : K_EXECUTE lno
|
stmt_dynexecute : K_EXECUTE lno
|
||||||
{
|
{
|
||||||
PLpgSQL_stmt_dynexecute *new;
|
PLpgSQL_stmt_dynexecute *new;
|
||||||
@ -2156,20 +2142,36 @@ make_execsql_stmt(const char *sqlstart, int lineno)
|
|||||||
PLpgSQL_row *row = NULL;
|
PLpgSQL_row *row = NULL;
|
||||||
PLpgSQL_rec *rec = NULL;
|
PLpgSQL_rec *rec = NULL;
|
||||||
int tok;
|
int tok;
|
||||||
|
int prev_tok;
|
||||||
bool have_into = false;
|
bool have_into = false;
|
||||||
bool have_strict = false;
|
bool have_strict = false;
|
||||||
|
|
||||||
plpgsql_dstring_init(&ds);
|
plpgsql_dstring_init(&ds);
|
||||||
plpgsql_dstring_append(&ds, sqlstart);
|
plpgsql_dstring_append(&ds, sqlstart);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We have to special-case the sequence INSERT INTO, because we don't want
|
||||||
|
* that to be taken as an INTO-variables clause. Fortunately, this is the
|
||||||
|
* only valid use of INTO in a pl/pgsql SQL command, and INTO is already a
|
||||||
|
* fully reserved word in the main grammar. We have to treat it that way
|
||||||
|
* anywhere in the string, not only at the start; consider CREATE RULE
|
||||||
|
* containing an INSERT statement.
|
||||||
|
*/
|
||||||
|
if (pg_strcasecmp(sqlstart, "insert") == 0)
|
||||||
|
tok = K_INSERT;
|
||||||
|
else
|
||||||
|
tok = 0;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
prev_tok = tok;
|
||||||
tok = yylex();
|
tok = yylex();
|
||||||
if (tok == ';')
|
if (tok == ';')
|
||||||
break;
|
break;
|
||||||
if (tok == 0)
|
if (tok == 0)
|
||||||
yyerror("unexpected end of function definition");
|
yyerror("unexpected end of function definition");
|
||||||
if (tok == K_INTO)
|
|
||||||
|
if (tok == K_INTO && prev_tok != K_INSERT)
|
||||||
{
|
{
|
||||||
if (have_into)
|
if (have_into)
|
||||||
yyerror("INTO specified more than once");
|
yyerror("INTO specified more than once");
|
||||||
|
Loading…
Reference in New Issue
Block a user