From c401a5ce585d99e5533844bb616074e693cc77cf Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 2 Feb 2009 20:25:38 +0000 Subject: [PATCH] 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.) --- src/pl/plpgsql/src/gram.y | 44 ++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y index 7ae3536754..f9a2eabe32 100644 --- a/src/pl/plpgsql/src/gram.y +++ b/src/pl/plpgsql/src/gram.y @@ -9,7 +9,7 @@ * * * 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 %type proc_stmt pl_block %type stmt_assign stmt_if stmt_loop stmt_while stmt_exit -%type stmt_return stmt_raise stmt_execsql stmt_execsql_insert +%type stmt_return stmt_raise stmt_execsql %type stmt_dynexecute stmt_for stmt_perform stmt_getdiag %type stmt_open stmt_fetch stmt_move stmt_close stmt_null %type stmt_case @@ -646,8 +646,6 @@ proc_stmt : pl_block ';' { $$ = $1; } | stmt_execsql { $$ = $1; } - | stmt_execsql_insert - { $$ = $1; } | stmt_dynexecute { $$ = $1; } | stmt_perform @@ -1482,27 +1480,15 @@ stmt_execsql : execsql_start lno } ; -/* this matches any otherwise-unrecognized starting keyword */ -execsql_start : T_WORD +/* T_WORD+T_ERROR match any otherwise-unrecognized starting keyword */ +execsql_start : K_INSERT + { $$ = pstrdup(yytext); } + | T_WORD { $$ = pstrdup(yytext); } | T_ERROR { $$ = 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 { PLpgSQL_stmt_dynexecute *new; @@ -2156,20 +2142,36 @@ make_execsql_stmt(const char *sqlstart, int lineno) PLpgSQL_row *row = NULL; PLpgSQL_rec *rec = NULL; int tok; + int prev_tok; bool have_into = false; bool have_strict = false; plpgsql_dstring_init(&ds); 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 (;;) { + prev_tok = tok; tok = yylex(); if (tok == ';') break; if (tok == 0) yyerror("unexpected end of function definition"); - if (tok == K_INTO) + + if (tok == K_INTO && prev_tok != K_INSERT) { if (have_into) yyerror("INTO specified more than once");