Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4879a51

Browse files
committed
Support plpgsql variable names that conflict with unreserved SQL keywords.
A variable name matching a statement-introducing keyword, such as"comment" or "update", caused parse failures if one tried to writea statement using that keyword. Commitbb1b8f6 already addressedthis scenario for the case of variable names matching unreservedplpgsql keywords, but we didn't think about unreserved core-grammarkeywords. The same heuristic (viz, it can't be a variable nameunless the next token is assignment or '[') should work fine forthat case too, and as a bonus the code gets shorter and lessduplicative.Per bug #15555 from Feike Steenbergen. Since this hasn't beencomplained of before, and is easily worked around anyway,I won't risk a back-patch.Discussion:https://postgr.es/m/15555-149bbd70ddc7b4b6@postgresql.org
1 parentcb719fa commit4879a51

File tree

5 files changed

+75
-49
lines changed

5 files changed

+75
-49
lines changed

‎src/pl/plpgsql/src/pl_comp.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,24 +1353,27 @@ make_datum_param(PLpgSQL_expr *expr, int dno, int location)
13531353
* yytxt is the original token text; we need this to check for quoting,
13541354
* so that later checks for unreserved keywords work properly.
13551355
*
1356+
* We attempt to recognize the token as a variable only if lookup is true
1357+
* and the plpgsql_IdentifierLookup context permits it.
1358+
*
13561359
* If recognized as a variable, fill in *wdatum and return true;
13571360
* if not recognized, fill in *word and return false.
13581361
* (Note: those two pointers actually point to members of the same union,
13591362
* but for notational reasons we pass them separately.)
13601363
* ----------
13611364
*/
13621365
bool
1363-
plpgsql_parse_word(char*word1,constchar*yytxt,
1366+
plpgsql_parse_word(char*word1,constchar*yytxt,boollookup,
13641367
PLwdatum*wdatum,PLword*word)
13651368
{
13661369
PLpgSQL_nsitem*ns;
13671370

13681371
/*
1369-
* We shoulddo nothingin DECLARE sections. In SQL expressions, there's
1370-
* no need to doanything either --- lookup will happen when the
1371-
* expression is compiled.
1372+
* We shouldnot lookup variablesin DECLARE sections. In SQL
1373+
*expressions, there'sno need to doso either --- lookup will happen
1374+
*when theexpression is compiled.
13721375
*/
1373-
if (plpgsql_IdentifierLookup==IDENTIFIER_LOOKUP_NORMAL)
1376+
if (lookup&&plpgsql_IdentifierLookup==IDENTIFIER_LOOKUP_NORMAL)
13741377
{
13751378
/*
13761379
* Do a lookup in the current namespace stack

‎src/pl/plpgsql/src/pl_scanner.c

Lines changed: 31 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ plpgsql_yylex(void)
328328
push_back_token(tok2,&aux2);
329329
if (plpgsql_parse_word(aux1.lval.str,
330330
core_yy.scanbuf+aux1.lloc,
331+
true,
331332
&aux1.lval.wdatum,
332333
&aux1.lval.word))
333334
tok1=T_DATUM;
@@ -349,53 +350,40 @@ plpgsql_yylex(void)
349350
push_back_token(tok2,&aux2);
350351

351352
/*
352-
* If we are at start of statement, prefer unreserved keywords
353-
* over variable names, unless the next token is assignment or
354-
* '[', in which case prefer variable names. (Note we need not
355-
* consider '.' as the next token; that case was handled above,
356-
* and we always prefer variable names in that case.) If we are
357-
* not at start of statement, always prefer variable names over
358-
* unreserved keywords.
353+
* See if it matches a variable name, except in the context where
354+
* we are at start of statement and the next token isn't
355+
* assignment or '['. In that case, it couldn't validly be a
356+
* variable name, and skipping the lookup allows variable names to
357+
* be used that would conflict with plpgsql or core keywords that
358+
* introduce statements (e.g., "comment"). Without this special
359+
* logic, every statement-introducing keyword would effectively be
360+
* reserved in PL/pgSQL, which would be unpleasant.
361+
*
362+
* If it isn't a variable name, try to match against unreserved
363+
* plpgsql keywords. If not one of those either, it's T_WORD.
364+
*
365+
* Note: we must call plpgsql_parse_word even if we don't want to
366+
* do variable lookup, because it sets up aux1.lval.word for the
367+
* non-variable cases.
359368
*/
360-
if (AT_STMT_START(plpgsql_yytoken)&&
361-
!(tok2=='='||tok2==COLON_EQUALS||tok2=='['))
369+
if (plpgsql_parse_word(aux1.lval.str,
370+
core_yy.scanbuf+aux1.lloc,
371+
(!AT_STMT_START(plpgsql_yytoken)||
372+
(tok2=='='||tok2==COLON_EQUALS||
373+
tok2=='[')),
374+
&aux1.lval.wdatum,
375+
&aux1.lval.word))
376+
tok1=T_DATUM;
377+
elseif (!aux1.lval.word.quoted&&
378+
(kw=ScanKeywordLookup(aux1.lval.word.ident,
379+
unreserved_keywords,
380+
num_unreserved_keywords)))
362381
{
363-
/* try for unreserved keyword, then for variable name */
364-
if (core_yy.scanbuf[aux1.lloc]!='"'&&
365-
(kw=ScanKeywordLookup(aux1.lval.str,
366-
unreserved_keywords,
367-
num_unreserved_keywords)))
368-
{
369-
aux1.lval.keyword=kw->name;
370-
tok1=kw->value;
371-
}
372-
elseif (plpgsql_parse_word(aux1.lval.str,
373-
core_yy.scanbuf+aux1.lloc,
374-
&aux1.lval.wdatum,
375-
&aux1.lval.word))
376-
tok1=T_DATUM;
377-
else
378-
tok1=T_WORD;
382+
aux1.lval.keyword=kw->name;
383+
tok1=kw->value;
379384
}
380385
else
381-
{
382-
/* try for variable name, then for unreserved keyword */
383-
if (plpgsql_parse_word(aux1.lval.str,
384-
core_yy.scanbuf+aux1.lloc,
385-
&aux1.lval.wdatum,
386-
&aux1.lval.word))
387-
tok1=T_DATUM;
388-
elseif (!aux1.lval.word.quoted&&
389-
(kw=ScanKeywordLookup(aux1.lval.word.ident,
390-
unreserved_keywords,
391-
num_unreserved_keywords)))
392-
{
393-
aux1.lval.keyword=kw->name;
394-
tok1=kw->value;
395-
}
396-
else
397-
tok1=T_WORD;
398-
}
386+
tok1=T_WORD;
399387
}
400388
}
401389
else

‎src/pl/plpgsql/src/plpgsql.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1175,7 +1175,7 @@ extern PLpgSQL_function *plpgsql_compile(FunctionCallInfo fcinfo,
11751175
externPLpgSQL_function*plpgsql_compile_inline(char*proc_source);
11761176
externvoidplpgsql_parser_setup(structParseState*pstate,
11771177
PLpgSQL_expr*expr);
1178-
externboolplpgsql_parse_word(char*word1,constchar*yytxt,
1178+
externboolplpgsql_parse_word(char*word1,constchar*yytxt,boollookup,
11791179
PLwdatum*wdatum,PLword*word);
11801180
externboolplpgsql_parse_dblword(char*word1,char*word2,
11811181
PLwdatum*wdatum,PLcword*cword);

‎src/test/regress/expected/plpgsql.out

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4781,6 +4781,27 @@ select unreserved_test();
47814781
43
47824782
(1 row)
47834783

4784+
create or replace function unreserved_test() returns int as $$
4785+
declare
4786+
comment int := 21;
4787+
begin
4788+
comment := comment * 2;
4789+
comment on function unreserved_test() is 'this is a test';
4790+
return comment;
4791+
end
4792+
$$ language plpgsql;
4793+
select unreserved_test();
4794+
unreserved_test
4795+
-----------------
4796+
42
4797+
(1 row)
4798+
4799+
select obj_description('unreserved_test()'::regprocedure, 'pg_proc');
4800+
obj_description
4801+
-----------------
4802+
this is a test
4803+
(1 row)
4804+
47844805
drop function unreserved_test();
47854806
--
47864807
-- Test FOREACH over arrays

‎src/test/regress/sql/plpgsql.sql

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3892,6 +3892,20 @@ $$ language plpgsql;
38923892
38933893
select unreserved_test();
38943894
3895+
create or replace function unreserved_test() returns int as $$
3896+
declare
3897+
comment int := 21;
3898+
begin
3899+
comment := comment * 2;
3900+
comment on function unreserved_test() is'this is a test';
3901+
return comment;
3902+
end
3903+
$$ language plpgsql;
3904+
3905+
select unreserved_test();
3906+
3907+
select obj_description('unreserved_test()'::regprocedure,'pg_proc');
3908+
38953909
drop function unreserved_test();
38963910
38973911
--

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp