plpgsql-still-less-reserved-1.patch
text/x-diff
Filename: plpgsql-still-less-reserved-1.patch
Type: text/x-diff
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/pl/plpgsql/src/pl_comp.c | 0 | 0 |
| src/pl/plpgsql/src/plpgsql.h | 0 | 0 |
| src/pl/plpgsql/src/pl_scanner.c | 0 | 0 |
| src/test/regress/expected/plpgsql.out | 0 | 0 |
| src/test/regress/sql/plpgsql.sql | 0 | 0 |
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 8bacc74..03e7c6c 100644
*** a/src/pl/plpgsql/src/pl_comp.c
--- b/src/pl/plpgsql/src/pl_comp.c
*************** make_datum_param(PLpgSQL_expr *expr, int
*** 1353,1358 ****
--- 1353,1361 ----
* yytxt is the original token text; we need this to check for quoting,
* so that later checks for unreserved keywords work properly.
*
+ * We attempt to recognize the token as a variable only if lookup is true
+ * and the plpgsql_IdentifierLookup context permits it.
+ *
* If recognized as a variable, fill in *wdatum and return true;
* if not recognized, fill in *word and return false.
* (Note: those two pointers actually point to members of the same union,
*************** make_datum_param(PLpgSQL_expr *expr, int
*** 1360,1376 ****
* ----------
*/
bool
! plpgsql_parse_word(char *word1, const char *yytxt,
PLwdatum *wdatum, PLword *word)
{
PLpgSQL_nsitem *ns;
/*
! * We should do nothing in DECLARE sections. In SQL expressions, there's
! * no need to do anything either --- lookup will happen when the
! * expression is compiled.
*/
! if (plpgsql_IdentifierLookup == IDENTIFIER_LOOKUP_NORMAL)
{
/*
* Do a lookup in the current namespace stack
--- 1363,1379 ----
* ----------
*/
bool
! plpgsql_parse_word(char *word1, const char *yytxt, bool lookup,
PLwdatum *wdatum, PLword *word)
{
PLpgSQL_nsitem *ns;
/*
! * We should not lookup variables in DECLARE sections. In SQL
! * expressions, there's no need to do so either --- lookup will happen
! * when the expression is compiled.
*/
! if (lookup && plpgsql_IdentifierLookup == IDENTIFIER_LOOKUP_NORMAL)
{
/*
* Do a lookup in the current namespace stack
diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c
index ab18946..3e746d1 100644
*** a/src/pl/plpgsql/src/pl_scanner.c
--- b/src/pl/plpgsql/src/pl_scanner.c
*************** plpgsql_yylex(void)
*** 328,333 ****
--- 328,334 ----
push_back_token(tok2, &aux2);
if (plpgsql_parse_word(aux1.lval.str,
core_yy.scanbuf + aux1.lloc,
+ true,
&aux1.lval.wdatum,
&aux1.lval.word))
tok1 = T_DATUM;
*************** plpgsql_yylex(void)
*** 349,401 ****
push_back_token(tok2, &aux2);
/*
! * If we are at start of statement, prefer unreserved keywords
! * over variable names, unless the next token is assignment or
! * '[', in which case prefer variable names. (Note we need not
! * consider '.' as the next token; that case was handled above,
! * and we always prefer variable names in that case.) If we are
! * not at start of statement, always prefer variable names over
! * unreserved keywords.
*/
! if (AT_STMT_START(plpgsql_yytoken) &&
! !(tok2 == '=' || tok2 == COLON_EQUALS || tok2 == '['))
{
! /* try for unreserved keyword, then for variable name */
! if (core_yy.scanbuf[aux1.lloc] != '"' &&
! (kw = ScanKeywordLookup(aux1.lval.str,
! unreserved_keywords,
! num_unreserved_keywords)))
! {
! aux1.lval.keyword = kw->name;
! tok1 = kw->value;
! }
! else if (plpgsql_parse_word(aux1.lval.str,
! core_yy.scanbuf + aux1.lloc,
! &aux1.lval.wdatum,
! &aux1.lval.word))
! tok1 = T_DATUM;
! else
! tok1 = T_WORD;
}
else
! {
! /* try for variable name, then for unreserved keyword */
! if (plpgsql_parse_word(aux1.lval.str,
! core_yy.scanbuf + aux1.lloc,
! &aux1.lval.wdatum,
! &aux1.lval.word))
! tok1 = T_DATUM;
! else if (!aux1.lval.word.quoted &&
! (kw = ScanKeywordLookup(aux1.lval.word.ident,
! unreserved_keywords,
! num_unreserved_keywords)))
! {
! aux1.lval.keyword = kw->name;
! tok1 = kw->value;
! }
! else
! tok1 = T_WORD;
! }
}
}
else
--- 350,389 ----
push_back_token(tok2, &aux2);
/*
! * See if it matches a variable name, except in the context where
! * we are at start of statement and the next token isn't
! * assignment or '['. In that case, it couldn't validly be a
! * variable name, and skipping the lookup allows variable names to
! * be used that would conflict with plpgsql or core keywords that
! * introduce statements (e.g., "comment"). Without this special
! * logic, every statement-introducing keyword would effectively be
! * reserved in PL/pgSQL, which would be unpleasant.
! *
! * If it isn't a variable name, try to match against unreserved
! * plpgsql keywords. If not one of those either, it's T_WORD.
! *
! * Note: we must call plpgsql_parse_word even if we don't want to
! * do variable lookup, because it sets up aux1.lval.word for the
! * non-variable cases.
*/
! if (plpgsql_parse_word(aux1.lval.str,
! core_yy.scanbuf + aux1.lloc,
! (!AT_STMT_START(plpgsql_yytoken) ||
! (tok2 == '=' || tok2 == COLON_EQUALS ||
! tok2 == '[')),
! &aux1.lval.wdatum,
! &aux1.lval.word))
! tok1 = T_DATUM;
! else if (!aux1.lval.word.quoted &&
! (kw = ScanKeywordLookup(aux1.lval.word.ident,
! unreserved_keywords,
! num_unreserved_keywords)))
{
! aux1.lval.keyword = kw->name;
! tok1 = kw->value;
}
else
! tok1 = T_WORD;
}
}
else
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 42177cc..962b9c2 100644
*** a/src/pl/plpgsql/src/plpgsql.h
--- b/src/pl/plpgsql/src/plpgsql.h
*************** extern PLpgSQL_function *plpgsql_compile
*** 1175,1181 ****
extern PLpgSQL_function *plpgsql_compile_inline(char *proc_source);
extern void plpgsql_parser_setup(struct ParseState *pstate,
PLpgSQL_expr *expr);
! extern bool plpgsql_parse_word(char *word1, const char *yytxt,
PLwdatum *wdatum, PLword *word);
extern bool plpgsql_parse_dblword(char *word1, char *word2,
PLwdatum *wdatum, PLcword *cword);
--- 1175,1181 ----
extern PLpgSQL_function *plpgsql_compile_inline(char *proc_source);
extern void plpgsql_parser_setup(struct ParseState *pstate,
PLpgSQL_expr *expr);
! extern bool plpgsql_parse_word(char *word1, const char *yytxt, bool lookup,
PLwdatum *wdatum, PLword *word);
extern bool plpgsql_parse_dblword(char *word1, char *word2,
PLwdatum *wdatum, PLcword *cword);
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index b9a987d..d2f68e1 100644
*** a/src/test/regress/expected/plpgsql.out
--- b/src/test/regress/expected/plpgsql.out
*************** select unreserved_test();
*** 4781,4786 ****
--- 4781,4807 ----
43
(1 row)
+ create or replace function unreserved_test() returns int as $$
+ declare
+ comment int := 21;
+ begin
+ comment := comment * 2;
+ comment on function unreserved_test() is 'this is a test';
+ return comment;
+ end
+ $$ language plpgsql;
+ select unreserved_test();
+ unreserved_test
+ -----------------
+ 42
+ (1 row)
+
+ select obj_description('unreserved_test()'::regprocedure, 'pg_proc');
+ obj_description
+ -----------------
+ this is a test
+ (1 row)
+
drop function unreserved_test();
--
-- Test FOREACH over arrays
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index 01239e2..9c8cf75 100644
*** a/src/test/regress/sql/plpgsql.sql
--- b/src/test/regress/sql/plpgsql.sql
*************** $$ language plpgsql;
*** 3892,3897 ****
--- 3892,3911 ----
select unreserved_test();
+ create or replace function unreserved_test() returns int as $$
+ declare
+ comment int := 21;
+ begin
+ comment := comment * 2;
+ comment on function unreserved_test() is 'this is a test';
+ return comment;
+ end
+ $$ language plpgsql;
+
+ select unreserved_test();
+
+ select obj_description('unreserved_test()'::regprocedure, 'pg_proc');
+
drop function unreserved_test();
--