Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 2d7f136

Browse files
committed
Improve plpgsql parsing to report "foo is not a known variable", rather than a
generic syntax error, when seeing "foo := something" and foo isn't recognized. This buys back most of the helpfulness discarded in my previous patch by not throwing errors when a qualified name appears to match a row variable but the last component doesn't match any field of the row. It covers other cases where our error messages left something to be desired, too.
1 parent 01f7d29 commit 2d7f136

File tree

1 file changed

+68
-33
lines changed

1 file changed

+68
-33
lines changed

src/pl/plpgsql/src/gram.y

+68-33
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* 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 $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -56,7 +56,9 @@ union YYSTYPE; /* need forward reference for tok_is_keyword */
5656

5757
static bool tok_is_keyword(int token, union YYSTYPE *lval,
5858
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);
6062
static PLpgSQL_expr *read_sql_construct(int until,
6163
int until2,
6264
int until3,
@@ -851,12 +853,12 @@ getdiag_target : T_DATUM
851853
| T_WORD
852854
{
853855
/* just to give a better message than "syntax error" */
854-
token_is_not_variable(T_WORD);
856+
word_is_not_variable(&($1), @1);
855857
}
856858
| T_CWORD
857859
{
858860
/* just to give a better message than "syntax error" */
859-
token_is_not_variable(T_CWORD);
861+
cword_is_not_variable(&($1), @1);
860862
}
861863
;
862864

@@ -1371,19 +1373,12 @@ for_variable : T_DATUM
13711373
tok = yylex();
13721374
plpgsql_push_back_token(tok);
13731375
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);
13821377
}
13831378
| T_CWORD
13841379
{
13851380
/* just to give a better message than "syntax error" */
1386-
token_is_not_variable(T_CWORD);
1381+
cword_is_not_variable(&($1), @1);
13871382
}
13881383
;
13891384

@@ -1587,15 +1582,38 @@ loop_body : proc_sect K_END K_LOOP opt_label ';'
15871582

15881583
/*
15891584
* 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".
15921592
*/
15931593
stmt_execsql : K_INSERT
1594-
{ $$ = make_execsql_stmt(K_INSERT, @1); }
1594+
{
1595+
$$ = make_execsql_stmt(K_INSERT, @1);
1596+
}
15951597
| 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+
}
15971607
| 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+
}
15991617
;
16001618

16011619
stmt_dynexecute : K_EXECUTE
@@ -1793,12 +1811,12 @@ cursor_variable : T_DATUM
17931811
| T_WORD
17941812
{
17951813
/* just to give a better message than "syntax error" */
1796-
token_is_not_variable(T_WORD);
1814+
word_is_not_variable(&($1), @1);
17971815
}
17981816
| T_CWORD
17991817
{
18001818
/* just to give a better message than "syntax error" */
1801-
token_is_not_variable(T_CWORD);
1819+
cword_is_not_variable(&($1), @1);
18021820
}
18031821
;
18041822

@@ -2045,26 +2063,43 @@ tok_is_keyword(int token, union YYSTYPE *lval,
20452063
return false; /* not the keyword */
20462064
}
20472065

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+
20482091
/*
20492092
* Convenience routine to complain when we expected T_DATUM and got
20502093
* something else. "tok" must be the current token, since we also
20512094
* look at yylval and yylloc.
20522095
*/
20532096
static void
2054-
token_is_not_variable(int tok)
2097+
current_token_is_not_variable(int tok)
20552098
{
20562099
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);
20622101
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);
20682103
else
20692104
yyerror("syntax error");
20702105
}
@@ -2848,7 +2883,7 @@ read_into_target(PLpgSQL_rec **rec, PLpgSQL_row **row, bool *strict)
28482883

28492884
default:
28502885
/* just to give a better message than "syntax error" */
2851-
token_is_not_variable(tok);
2886+
current_token_is_not_variable(tok);
28522887
}
28532888
}
28542889

@@ -2901,7 +2936,7 @@ read_into_scalar_list(char *initial_name,
29012936

29022937
default:
29032938
/* just to give a better message than "syntax error" */
2904-
token_is_not_variable(tok);
2939+
current_token_is_not_variable(tok);
29052940
}
29062941
}
29072942

0 commit comments

Comments
 (0)