mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-27 08:39:28 +08:00
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.
This commit is contained in:
parent
01f7d29902
commit
2d7f136ff7
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.138 2010/01/10 17:15:18 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.139 2010/01/10 17:56:50 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -56,7 +56,9 @@ union YYSTYPE; /* need forward reference for tok_is_keyword */
|
||||
|
||||
static bool tok_is_keyword(int token, union YYSTYPE *lval,
|
||||
int kw_token, const char *kw_str);
|
||||
static void token_is_not_variable(int tok);
|
||||
static void word_is_not_variable(PLword *word, int location);
|
||||
static void cword_is_not_variable(PLcword *cword, int location);
|
||||
static void current_token_is_not_variable(int tok);
|
||||
static PLpgSQL_expr *read_sql_construct(int until,
|
||||
int until2,
|
||||
int until3,
|
||||
@ -851,12 +853,12 @@ getdiag_target : T_DATUM
|
||||
| T_WORD
|
||||
{
|
||||
/* just to give a better message than "syntax error" */
|
||||
token_is_not_variable(T_WORD);
|
||||
word_is_not_variable(&($1), @1);
|
||||
}
|
||||
| T_CWORD
|
||||
{
|
||||
/* just to give a better message than "syntax error" */
|
||||
token_is_not_variable(T_CWORD);
|
||||
cword_is_not_variable(&($1), @1);
|
||||
}
|
||||
;
|
||||
|
||||
@ -1371,19 +1373,12 @@ for_variable : T_DATUM
|
||||
tok = yylex();
|
||||
plpgsql_push_back_token(tok);
|
||||
if (tok == ',')
|
||||
{
|
||||
/* can't use token_is_not_variable here */
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("\"%s\" is not a known variable",
|
||||
$1.ident),
|
||||
parser_errposition(@1)));
|
||||
}
|
||||
word_is_not_variable(&($1), @1);
|
||||
}
|
||||
| T_CWORD
|
||||
{
|
||||
/* just to give a better message than "syntax error" */
|
||||
token_is_not_variable(T_CWORD);
|
||||
cword_is_not_variable(&($1), @1);
|
||||
}
|
||||
;
|
||||
|
||||
@ -1587,15 +1582,38 @@ loop_body : proc_sect K_END K_LOOP opt_label ';'
|
||||
|
||||
/*
|
||||
* T_WORD+T_CWORD match any initial identifier that is not a known plpgsql
|
||||
* variable. The composite case is probably a syntax error, but we'll let
|
||||
* the core parser decide that.
|
||||
* variable. (The composite case is probably a syntax error, but we'll let
|
||||
* the core parser decide that.) Normally, we should assume that such a
|
||||
* word is a SQL statement keyword that isn't also a plpgsql keyword.
|
||||
* However, if the next token is assignment or '[', it can't be a valid
|
||||
* SQL statement, and what we're probably looking at is an intended variable
|
||||
* assignment. Give an appropriate complaint for that, instead of letting
|
||||
* the core parser throw an unhelpful "syntax error".
|
||||
*/
|
||||
stmt_execsql : K_INSERT
|
||||
{ $$ = make_execsql_stmt(K_INSERT, @1); }
|
||||
{
|
||||
$$ = make_execsql_stmt(K_INSERT, @1);
|
||||
}
|
||||
| T_WORD
|
||||
{ $$ = make_execsql_stmt(T_WORD, @1); }
|
||||
{
|
||||
int tok;
|
||||
|
||||
tok = yylex();
|
||||
plpgsql_push_back_token(tok);
|
||||
if (tok == '=' || tok == COLON_EQUALS || tok == '[')
|
||||
word_is_not_variable(&($1), @1);
|
||||
$$ = make_execsql_stmt(T_WORD, @1);
|
||||
}
|
||||
| T_CWORD
|
||||
{ $$ = make_execsql_stmt(T_CWORD, @1); }
|
||||
{
|
||||
int tok;
|
||||
|
||||
tok = yylex();
|
||||
plpgsql_push_back_token(tok);
|
||||
if (tok == '=' || tok == COLON_EQUALS || tok == '[')
|
||||
cword_is_not_variable(&($1), @1);
|
||||
$$ = make_execsql_stmt(T_CWORD, @1);
|
||||
}
|
||||
;
|
||||
|
||||
stmt_dynexecute : K_EXECUTE
|
||||
@ -1793,12 +1811,12 @@ cursor_variable : T_DATUM
|
||||
| T_WORD
|
||||
{
|
||||
/* just to give a better message than "syntax error" */
|
||||
token_is_not_variable(T_WORD);
|
||||
word_is_not_variable(&($1), @1);
|
||||
}
|
||||
| T_CWORD
|
||||
{
|
||||
/* just to give a better message than "syntax error" */
|
||||
token_is_not_variable(T_CWORD);
|
||||
cword_is_not_variable(&($1), @1);
|
||||
}
|
||||
;
|
||||
|
||||
@ -2045,26 +2063,43 @@ tok_is_keyword(int token, union YYSTYPE *lval,
|
||||
return false; /* not the keyword */
|
||||
}
|
||||
|
||||
/*
|
||||
* Convenience routine to complain when we expected T_DATUM and got T_WORD,
|
||||
* ie, unrecognized variable.
|
||||
*/
|
||||
static void
|
||||
word_is_not_variable(PLword *word, int location)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("\"%s\" is not a known variable",
|
||||
word->ident),
|
||||
parser_errposition(location)));
|
||||
}
|
||||
|
||||
/* Same, for a CWORD */
|
||||
static void
|
||||
cword_is_not_variable(PLcword *cword, int location)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("\"%s\" is not a known variable",
|
||||
NameListToString(cword->idents)),
|
||||
parser_errposition(location)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Convenience routine to complain when we expected T_DATUM and got
|
||||
* something else. "tok" must be the current token, since we also
|
||||
* look at yylval and yylloc.
|
||||
*/
|
||||
static void
|
||||
token_is_not_variable(int tok)
|
||||
current_token_is_not_variable(int tok)
|
||||
{
|
||||
if (tok == T_WORD)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("\"%s\" is not a known variable",
|
||||
yylval.word.ident),
|
||||
parser_errposition(yylloc)));
|
||||
word_is_not_variable(&(yylval.word), yylloc);
|
||||
else if (tok == T_CWORD)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("\"%s\" is not a known variable",
|
||||
NameListToString(yylval.cword.idents)),
|
||||
parser_errposition(yylloc)));
|
||||
cword_is_not_variable(&(yylval.cword), yylloc);
|
||||
else
|
||||
yyerror("syntax error");
|
||||
}
|
||||
@ -2848,7 +2883,7 @@ read_into_target(PLpgSQL_rec **rec, PLpgSQL_row **row, bool *strict)
|
||||
|
||||
default:
|
||||
/* just to give a better message than "syntax error" */
|
||||
token_is_not_variable(tok);
|
||||
current_token_is_not_variable(tok);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2901,7 +2936,7 @@ read_into_scalar_list(char *initial_name,
|
||||
|
||||
default:
|
||||
/* just to give a better message than "syntax error" */
|
||||
token_is_not_variable(tok);
|
||||
current_token_is_not_variable(tok);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user