From 96925826100443442677005f91fe86b457d5460b Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 2 Feb 2009 20:25:50 +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 9f9ac12c876..f0014b89e1c 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.95.2.1 2007/02/08 18:37:38 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.95.2.2 2009/02/02 20:25:50 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -122,7 +122,7 @@ static void check_labels(const char *start_label, %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_close stmt_null @@ -602,8 +602,6 @@ proc_stmt : pl_block ';' { $$ = $1; } | stmt_execsql { $$ = $1; } - | stmt_execsql_insert - { $$ = $1; } | stmt_dynexecute { $$ = $1; } | stmt_perform @@ -1257,27 +1255,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; @@ -1883,14 +1869,29 @@ 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; @@ -1901,7 +1902,8 @@ make_execsql_stmt(const char *sqlstart, int lineno) (errcode(ERRCODE_SYNTAX_ERROR), errmsg("unexpected end of function definition"))); } - if (tok == K_INTO) + + if (tok == K_INTO && prev_tok != K_INSERT) { if (have_into) { -- 2.39.5