summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2009-05-01 23:57:34 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2009-05-01 23:57:34 +0000
commitccc6759dbb4140de5df7ba23c0623772c54c9d54 (patch)
treefa0826b466f7b79289f6499625b26b832d7b8e49 /src
parentfe1b07a6f9f476b08301e9a7fddacaa427f949df (diff)
Fix a couple of cases where the plpgsql grammar looked for T_WORD and
failed to consider the possibility that it would get T_SCALAR, T_RECORD, or T_ROW instead because the word happens to match a plpgsql variable name. In particular, give "duplicate declaration" rather than generic "syntax error" if the same identifier is declared twice in the same block, as per my recent complaint. Also behave more sanely when decl_aliasitem or proc_condition or opt_lblname is coincidentally not T_WORD. Refactor the related productions a bit to reduce duplication. This is a longstanding bug, but it doesn't seem critical enough to back-patch.
Diffstat (limited to 'src')
-rw-r--r--src/pl/plpgsql/src/gram.y137
1 files changed, 78 insertions, 59 deletions
diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y
index 939c95b5413..0fd9a697915 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.123 2009/04/19 21:50:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.124 2009/05/01 23:57:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -144,7 +144,7 @@ static List *read_raise_options(void);
%type <forvariable> for_variable
%type <stmt> for_control
-%type <str> opt_lblname opt_block_label opt_label
+%type <str> any_identifier any_name opt_block_label opt_label
%type <str> execsql_start
%type <list> proc_sect proc_stmts stmt_else
@@ -331,7 +331,7 @@ decl_stmts : decl_stmts decl_stmt
{ $$ = $1; }
;
-decl_stmt : '<' '<' opt_lblname '>' '>'
+decl_stmt : '<' '<' any_name '>' '>'
{ $$ = $3; }
| K_DECLARE
{ $$ = NULL; }
@@ -512,12 +512,12 @@ decl_cursor_arg : decl_varname decl_datatype
decl_is_for : K_IS | /* Oracle */
K_FOR; /* ANSI */
-decl_aliasitem : T_WORD
+decl_aliasitem : any_identifier
{
char *name;
PLpgSQL_nsitem *nsi;
- plpgsql_convert_ident(yytext, &name, 1);
+ plpgsql_convert_ident($1, &name, 1);
if (name[0] != '$')
yyerror("only positional parameters can be aliased");
@@ -549,8 +549,27 @@ decl_varname : T_WORD
$$.name = name;
$$.lineno = plpgsql_scanner_lineno();
}
+ | T_SCALAR
+ {
+ /*
+ * Since the scanner is only searching the topmost
+ * namestack entry, getting T_SCALAR etc can only
+ * happen if the name is already declared in this
+ * block.
+ */
+ yyerror("duplicate declaration");
+ }
+ | T_ROW
+ {
+ yyerror("duplicate declaration");
+ }
+ | T_RECORD
+ {
+ yyerror("duplicate declaration");
+ }
;
+/* XXX this is broken because it doesn't allow for T_SCALAR,T_ROW,T_RECORD */
decl_renname : T_WORD
{
char *name;
@@ -1752,45 +1771,39 @@ proc_conditions : proc_conditions K_OR proc_condition
}
;
-proc_condition : opt_lblname
+proc_condition : any_name
{
- $$ = plpgsql_parse_err_condition($1);
- }
- | T_SCALAR
- {
- /*
- * Because we know the special sqlstate variable
- * is at the top of the namestack (see the
- * exception_sect production), the SQLSTATE
- * keyword will always lex as T_SCALAR. This
- * might not be true in other parsing contexts!
- */
- PLpgSQL_condition *new;
- char *sqlstatestr;
-
- if (pg_strcasecmp(yytext, "sqlstate") != 0)
- yyerror("syntax error");
+ if (strcmp($1, "sqlstate") != 0)
+ {
+ $$ = plpgsql_parse_err_condition($1);
+ }
+ else
+ {
+ PLpgSQL_condition *new;
+ char *sqlstatestr;
- /* next token should be a string literal */
- if (yylex() != T_STRING)
- yyerror("syntax error");
- sqlstatestr = parse_string_token(yytext);
-
- if (strlen(sqlstatestr) != 5)
- yyerror("invalid SQLSTATE code");
- if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5)
- yyerror("invalid SQLSTATE code");
-
- new = palloc(sizeof(PLpgSQL_condition));
- new->sqlerrstate = MAKE_SQLSTATE(sqlstatestr[0],
- sqlstatestr[1],
- sqlstatestr[2],
- sqlstatestr[3],
- sqlstatestr[4]);
- new->condname = sqlstatestr;
- new->next = NULL;
-
- $$ = new;
+ /* next token should be a string literal */
+ if (yylex() != T_STRING)
+ yyerror("syntax error");
+ sqlstatestr = parse_string_token(yytext);
+
+ if (strlen(sqlstatestr) != 5)
+ yyerror("invalid SQLSTATE code");
+ if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5)
+ yyerror("invalid SQLSTATE code");
+
+ new = palloc(sizeof(PLpgSQL_condition));
+ new->sqlerrstate =
+ MAKE_SQLSTATE(sqlstatestr[0],
+ sqlstatestr[1],
+ sqlstatestr[2],
+ sqlstatestr[3],
+ sqlstatestr[4]);
+ new->condname = sqlstatestr;
+ new->next = NULL;
+
+ $$ = new;
+ }
}
;
@@ -1815,49 +1828,55 @@ opt_block_label :
plpgsql_ns_push(NULL);
$$ = NULL;
}
- | '<' '<' opt_lblname '>' '>'
+ | '<' '<' any_name '>' '>'
{
plpgsql_ns_push($3);
$$ = $3;
}
;
-/*
- * need all the options because scanner will have tried to resolve as variable
- */
opt_label :
{
$$ = NULL;
}
- | T_WORD
+ | any_identifier
{
- $$ = check_label(yytext);
+ $$ = check_label($1);
+ }
+ ;
+
+opt_exitcond : ';'
+ { $$ = NULL; }
+ | K_WHEN expr_until_semi
+ { $$ = $2; }
+ ;
+
+/*
+ * need all the options because scanner will have tried to resolve as variable
+ */
+any_identifier : T_WORD
+ {
+ $$ = yytext;
}
| T_SCALAR
{
- $$ = check_label(yytext);
+ $$ = yytext;
}
| T_RECORD
{
- $$ = check_label(yytext);
+ $$ = yytext;
}
| T_ROW
{
- $$ = check_label(yytext);
+ $$ = yytext;
}
;
-opt_exitcond : ';'
- { $$ = NULL; }
- | K_WHEN expr_until_semi
- { $$ = $2; }
- ;
-
-opt_lblname : T_WORD
+any_name : any_identifier
{
char *name;
- plpgsql_convert_ident(yytext, &name, 1);
+ plpgsql_convert_ident($1, &name, 1);
$$ = name;
}
;