summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2009-02-02 20:25:43 +0000
committerTom Lane2009-02-02 20:25:43 +0000
commit09406122347f04025b03bab3daa248a9004c1e4b (patch)
treec9ea319b16f1320d797bdfa60c73a1d0c2e744fe
parentb1abb3340b02d77227d9419f424ef936d7cde1d8 (diff)
Fix plpgsql to not treat INSERT INTO as an INTO-variables clause anywhereREL8_3_6
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.)
-rw-r--r--src/pl/plpgsql/src/gram.y44
1 files changed, 23 insertions, 21 deletions
diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y
index c9ffb8f18b6..02b8dbfb336 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.108 2008/01/01 19:46:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.108.2.1 2009/02/02 20:25:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -125,7 +125,7 @@ static void check_labels(const char *start_label,
%type <loop_body> loop_body
%type <stmt> proc_stmt pl_block
%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_open stmt_fetch stmt_move stmt_close stmt_null
@@ -625,8 +625,6 @@ proc_stmt : pl_block ';'
{ $$ = $1; }
| stmt_execsql
{ $$ = $1; }
- | stmt_execsql_insert
- { $$ = $1; }
| stmt_dynexecute
{ $$ = $1; }
| stmt_perform
@@ -1280,27 +1278,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;
@@ -1942,20 +1928,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");