|
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 | staticbooltok_is_keyword(int token,union YYSTYPE *lval, |
58 | 58 | int kw_token,constchar *kw_str); |
59 | | -staticvoidtoken_is_not_variable(int tok); |
| 59 | +staticvoidword_is_not_variable(PLword *word,int location); |
| 60 | +staticvoidcword_is_not_variable(PLcword *cword,int location); |
| 61 | +staticvoidcurrent_token_is_not_variable(int tok); |
60 | 62 | staticPLpgSQL_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 | +inttok; |
| 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 | +inttok; |
| 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 |
|
|