|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.138 2010/01/10 17:15:18 tgl Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.139 2010/01/10 17:56:50 tgl Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
@@ -56,7 +56,9 @@ union YYSTYPE; /* need forward reference for tok_is_keyword */
|
56 | 56 |
|
57 | 57 | static bool tok_is_keyword(int token, union YYSTYPE *lval,
|
58 | 58 | int kw_token, const char *kw_str);
|
59 |
| -static void token_is_not_variable(int tok); |
| 59 | +static void word_is_not_variable(PLword *word, int location); |
| 60 | +static void cword_is_not_variable(PLcword *cword, int location); |
| 61 | +static void current_token_is_not_variable(int tok); |
60 | 62 | static PLpgSQL_expr *read_sql_construct(int until,
|
61 | 63 | int until2,
|
62 | 64 | int until3,
|
@@ -851,12 +853,12 @@ getdiag_target : T_DATUM
|
851 | 853 | | T_WORD
|
852 | 854 | {
|
853 | 855 | /* just to give a better message than "syntax error" */
|
854 |
| - token_is_not_variable(T_WORD); |
| 856 | + word_is_not_variable(&($1), @1); |
855 | 857 | }
|
856 | 858 | | T_CWORD
|
857 | 859 | {
|
858 | 860 | /* just to give a better message than "syntax error" */
|
859 |
| - token_is_not_variable(T_CWORD); |
| 861 | + cword_is_not_variable(&($1), @1); |
860 | 862 | }
|
861 | 863 | ;
|
862 | 864 |
|
@@ -1371,19 +1373,12 @@ for_variable : T_DATUM
|
1371 | 1373 | tok = yylex();
|
1372 | 1374 | plpgsql_push_back_token(tok);
|
1373 | 1375 | if (tok == ',')
|
1374 |
| - { |
1375 |
| - /* can't use token_is_not_variable here */ |
1376 |
| - ereport(ERROR, |
1377 |
| - (errcode(ERRCODE_SYNTAX_ERROR), |
1378 |
| - errmsg("\"%s\" is not a known variable", |
1379 |
| - $1.ident), |
1380 |
| - parser_errposition(@1))); |
1381 |
| - } |
| 1376 | + word_is_not_variable(&($1), @1); |
1382 | 1377 | }
|
1383 | 1378 | | T_CWORD
|
1384 | 1379 | {
|
1385 | 1380 | /* just to give a better message than "syntax error" */
|
1386 |
| - token_is_not_variable(T_CWORD); |
| 1381 | + cword_is_not_variable(&($1), @1); |
1387 | 1382 | }
|
1388 | 1383 | ;
|
1389 | 1384 |
|
@@ -1587,15 +1582,38 @@ loop_body : proc_sect K_END K_LOOP opt_label ';'
|
1587 | 1582 |
|
1588 | 1583 | /*
|
1589 | 1584 | * T_WORD+T_CWORD match any initial identifier that is not a known plpgsql
|
1590 |
| - * variable. The composite case is probably a syntax error, but we'll let |
1591 |
| - * the core parser decide that. |
| 1585 | + * variable. (The composite case is probably a syntax error, but we'll let |
| 1586 | + * the core parser decide that.) Normally, we should assume that such a |
| 1587 | + * word is a SQL statement keyword that isn't also a plpgsql keyword. |
| 1588 | + * However, if the next token is assignment or '[', it can't be a valid |
| 1589 | + * SQL statement, and what we're probably looking at is an intended variable |
| 1590 | + * assignment. Give an appropriate complaint for that, instead of letting |
| 1591 | + * the core parser throw an unhelpful "syntax error". |
1592 | 1592 | */
|
1593 | 1593 | stmt_execsql : K_INSERT
|
1594 |
| - { $$ = make_execsql_stmt(K_INSERT, @1); } |
| 1594 | + { |
| 1595 | + $$ = make_execsql_stmt(K_INSERT, @1); |
| 1596 | + } |
1595 | 1597 | | T_WORD
|
1596 |
| - { $$ = make_execsql_stmt(T_WORD, @1); } |
| 1598 | + { |
| 1599 | + int tok; |
| 1600 | + |
| 1601 | + tok = yylex(); |
| 1602 | + plpgsql_push_back_token(tok); |
| 1603 | + if (tok == '=' || tok == COLON_EQUALS || tok == '[') |
| 1604 | + word_is_not_variable(&($1), @1); |
| 1605 | + $$ = make_execsql_stmt(T_WORD, @1); |
| 1606 | + } |
1597 | 1607 | | T_CWORD
|
1598 |
| - { $$ = make_execsql_stmt(T_CWORD, @1); } |
| 1608 | + { |
| 1609 | + int tok; |
| 1610 | + |
| 1611 | + tok = yylex(); |
| 1612 | + plpgsql_push_back_token(tok); |
| 1613 | + if (tok == '=' || tok == COLON_EQUALS || tok == '[') |
| 1614 | + cword_is_not_variable(&($1), @1); |
| 1615 | + $$ = make_execsql_stmt(T_CWORD, @1); |
| 1616 | + } |
1599 | 1617 | ;
|
1600 | 1618 |
|
1601 | 1619 | stmt_dynexecute : K_EXECUTE
|
@@ -1793,12 +1811,12 @@ cursor_variable : T_DATUM
|
1793 | 1811 | | T_WORD
|
1794 | 1812 | {
|
1795 | 1813 | /* just to give a better message than "syntax error" */
|
1796 |
| - token_is_not_variable(T_WORD); |
| 1814 | + word_is_not_variable(&($1), @1); |
1797 | 1815 | }
|
1798 | 1816 | | T_CWORD
|
1799 | 1817 | {
|
1800 | 1818 | /* just to give a better message than "syntax error" */
|
1801 |
| - token_is_not_variable(T_CWORD); |
| 1819 | + cword_is_not_variable(&($1), @1); |
1802 | 1820 | }
|
1803 | 1821 | ;
|
1804 | 1822 |
|
@@ -2045,26 +2063,43 @@ tok_is_keyword(int token, union YYSTYPE *lval,
|
2045 | 2063 | return false; /* not the keyword */
|
2046 | 2064 | }
|
2047 | 2065 |
|
| 2066 | +/* |
| 2067 | + * Convenience routine to complain when we expected T_DATUM and got T_WORD, |
| 2068 | + * ie, unrecognized variable. |
| 2069 | + */ |
| 2070 | +static void |
| 2071 | +word_is_not_variable(PLword *word, int location) |
| 2072 | +{ |
| 2073 | + ereport(ERROR, |
| 2074 | + (errcode(ERRCODE_SYNTAX_ERROR), |
| 2075 | + errmsg("\"%s\" is not a known variable", |
| 2076 | + word->ident), |
| 2077 | + parser_errposition(location))); |
| 2078 | +} |
| 2079 | + |
| 2080 | +/* Same, for a CWORD */ |
| 2081 | +static void |
| 2082 | +cword_is_not_variable(PLcword *cword, int location) |
| 2083 | +{ |
| 2084 | + ereport(ERROR, |
| 2085 | + (errcode(ERRCODE_SYNTAX_ERROR), |
| 2086 | + errmsg("\"%s\" is not a known variable", |
| 2087 | + NameListToString(cword->idents)), |
| 2088 | + parser_errposition(location))); |
| 2089 | +} |
| 2090 | + |
2048 | 2091 | /*
|
2049 | 2092 | * Convenience routine to complain when we expected T_DATUM and got
|
2050 | 2093 | * something else. "tok" must be the current token, since we also
|
2051 | 2094 | * look at yylval and yylloc.
|
2052 | 2095 | */
|
2053 | 2096 | static void
|
2054 |
| -token_is_not_variable(int tok) |
| 2097 | +current_token_is_not_variable(int tok) |
2055 | 2098 | {
|
2056 | 2099 | if (tok == T_WORD)
|
2057 |
| - ereport(ERROR, |
2058 |
| - (errcode(ERRCODE_SYNTAX_ERROR), |
2059 |
| - errmsg("\"%s\" is not a known variable", |
2060 |
| - yylval.word.ident), |
2061 |
| - parser_errposition(yylloc))); |
| 2100 | + word_is_not_variable(&(yylval.word), yylloc); |
2062 | 2101 | else if (tok == T_CWORD)
|
2063 |
| - ereport(ERROR, |
2064 |
| - (errcode(ERRCODE_SYNTAX_ERROR), |
2065 |
| - errmsg("\"%s\" is not a known variable", |
2066 |
| - NameListToString(yylval.cword.idents)), |
2067 |
| - parser_errposition(yylloc))); |
| 2102 | + cword_is_not_variable(&(yylval.cword), yylloc); |
2068 | 2103 | else
|
2069 | 2104 | yyerror("syntax error");
|
2070 | 2105 | }
|
@@ -2848,7 +2883,7 @@ read_into_target(PLpgSQL_rec **rec, PLpgSQL_row **row, bool *strict)
|
2848 | 2883 |
|
2849 | 2884 | default:
|
2850 | 2885 | /* just to give a better message than "syntax error" */
|
2851 |
| - token_is_not_variable(tok); |
| 2886 | + current_token_is_not_variable(tok); |
2852 | 2887 | }
|
2853 | 2888 | }
|
2854 | 2889 |
|
@@ -2901,7 +2936,7 @@ read_into_scalar_list(char *initial_name,
|
2901 | 2936 |
|
2902 | 2937 | default:
|
2903 | 2938 | /* just to give a better message than "syntax error" */
|
2904 |
| - token_is_not_variable(tok); |
| 2939 | + current_token_is_not_variable(tok); |
2905 | 2940 | }
|
2906 | 2941 | }
|
2907 | 2942 |
|
|
0 commit comments