From bac95fd4740e3ac13baf5c2ad38b9c9dc26f9c9d Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 26 Sep 2012 22:27:36 -0400 Subject: [PATCH] Make plpgsql's unreserved keywords more unreserved. There were assorted places where unreserved keywords were not treated the same as T_WORD (that is, a random unrecognized identifier). Fix them. It might not always be possible to allow this, but it is in all these places, so I don't see any downside. Per gripe from Jim Wilson. Arguably this is a bug fix, but given the lack of other complaints and the ease of working around it (just quote the word), I won't risk back-patching. --- src/pl/plpgsql/src/gram.y | 57 +++++++++++++++++++++++++++++++-- src/pl/plpgsql/src/pl_scanner.c | 19 +++++++++++ src/pl/plpgsql/src/plpgsql.h | 1 + 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y index 4967a2a6a7..9c3d254a0f 100644 --- a/src/pl/plpgsql/src/gram.y +++ b/src/pl/plpgsql/src/gram.y @@ -642,6 +642,21 @@ decl_aliasitem : T_WORD parser_errposition(@1))); $$ = nsi; } + | unreserved_keyword + { + PLpgSQL_nsitem *nsi; + + nsi = plpgsql_ns_lookup(plpgsql_ns_top(), false, + $1, NULL, NULL, + NULL); + if (nsi == NULL) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("variable \"%s\" does not exist", + $1), + parser_errposition(@1))); + $$ = nsi; + } | T_CWORD { PLpgSQL_nsitem *nsi; @@ -722,6 +737,11 @@ decl_collate : $$ = get_collation_oid(list_make1(makeString($2.ident)), false); } + | K_COLLATE unreserved_keyword + { + $$ = get_collation_oid(list_make1(makeString(pstrdup($2))), + false); + } | K_COLLATE T_CWORD { $$ = get_collation_oid($2.idents, false); @@ -1720,9 +1740,12 @@ stmt_raise : K_RAISE } else { - if (tok != T_WORD) + if (tok == T_WORD) + new->condname = yylval.word.ident; + else if (plpgsql_token_is_unreserved_keyword(tok)) + new->condname = pstrdup(yylval.keyword); + else yyerror("syntax error"); - new->condname = yylval.word.ident; plpgsql_recognize_err_condition(new->condname, false); } @@ -2185,12 +2208,16 @@ opt_exitcond : ';' ; /* - * need both options because scanner will have tried to resolve as variable + * need to allow DATUM because scanner will have tried to resolve as variable */ any_identifier : T_WORD { $$ = $1.ident; } + | unreserved_keyword + { + $$ = pstrdup($1); + } | T_DATUM { if ($1.ident == NULL) /* composite name not OK */ @@ -2513,6 +2540,30 @@ read_datatype(int tok) } } } + else if (plpgsql_token_is_unreserved_keyword(tok)) + { + char *dtname = pstrdup(yylval.keyword); + + tok = yylex(); + if (tok == '%') + { + tok = yylex(); + if (tok_is_keyword(tok, &yylval, + K_TYPE, "type")) + { + result = plpgsql_parse_wordtype(dtname); + if (result) + return result; + } + else if (tok_is_keyword(tok, &yylval, + K_ROWTYPE, "rowtype")) + { + result = plpgsql_parse_wordrowtype(dtname); + if (result) + return result; + } + } + } else if (tok == T_CWORD) { List *dtnames = yylval.cword.idents; diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c index ebce3fd860..c78527c309 100644 --- a/src/pl/plpgsql/src/pl_scanner.c +++ b/src/pl/plpgsql/src/pl_scanner.c @@ -410,6 +410,25 @@ plpgsql_push_back_token(int token) push_back_token(token, &auxdata); } +/* + * Tell whether a token is an unreserved keyword. + * + * (If it is, its lowercased form was returned as the token value, so we + * do not need to offer that data here.) + */ +bool +plpgsql_token_is_unreserved_keyword(int token) +{ + int i; + + for (i = 0; i < num_unreserved_keywords; i++) + { + if (unreserved_keywords[i].value == token) + return true; + } + return false; +} + /* * Append the function text starting at startlocation and extending to * (not including) endlocation onto the existing contents of "buf". diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index dcf80743b8..7ea696033b 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -973,6 +973,7 @@ extern void plpgsql_dumptree(PLpgSQL_function *func); extern int plpgsql_base_yylex(void); extern int plpgsql_yylex(void); extern void plpgsql_push_back_token(int token); +extern bool plpgsql_token_is_unreserved_keyword(int token); extern void plpgsql_append_source_text(StringInfo buf, int startlocation, int endlocation); extern void plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc,