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

Commitdc5824a

Browse files
committed
Fix plpgsql's handling of -- comments following expressions.
Up to now, read_sql_construct() has collected all the source text fromthe statement or expression's initial token up to the character justbefore the "until" token. It normally tries to strip trailingwhitespace from that, largely for neatness. If there was a "-- text"comment after the expression, this resulted in removing the newlinethat terminates the comment, which creates a hazard if we try to pastethe collected text into a larger SQL construct without inserting anewline after it. In particular this caused our handling of CASEconstructs to fail if there's a comment after a WHEN expression.Commit4adead1 noticed a similar problem with cursor arguments,and worked around it through the rather crude hack of suppressingthe whitespace-trimming behavior for those. Rather than do thatand leave the hazard open for future hackers to trip over, let'sfix it properly. pl_scanner.c already has enough infrastructureto report the end location of the expression's last token, sowe can copy up to that location and never collect any trailingwhitespace or comment to begin with.Erik Wienhold and Tom Lane, per report from Michal Bartak.Back-patch to all supported branches.Discussion:https://postgr.es/m/CAAVzF_FjRoi8fOVuLCZhQJx6HATQ7MKm=aFOHWZODFnLmjX-xA@mail.gmail.com
1 parent2e56ad6 commitdc5824a

File tree

7 files changed

+76
-36
lines changed

7 files changed

+76
-36
lines changed

‎src/pl/plpgsql/src/expected/plpgsql_control.out

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,3 +681,20 @@ select case_test(13);
681681
other
682682
(1 row)
683683

684+
-- test line comment between WHEN and THEN
685+
create or replace function case_comment(int) returns text as $$
686+
begin
687+
case $1
688+
when 1 -- comment before THEN
689+
then return 'one';
690+
else
691+
return 'other';
692+
end case;
693+
end;
694+
$$ language plpgsql immutable;
695+
select case_comment(1);
696+
case_comment
697+
--------------
698+
one
699+
(1 row)
700+

‎src/pl/plpgsql/src/pl_gram.y

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ staticPLpgSQL_expr*read_sql_construct(int until,
6969
RawParseMode parsemode,
7070
bool isexpression,
7171
bool valid_sql,
72-
bool trim,
7372
int *startloc,
7473
int *endtoken);
7574
staticPLpgSQL_expr*read_sql_expression(int until,
@@ -921,7 +920,7 @@ stmt_perform: K_PERFORM
921920
*/
922921
new->expr =read_sql_construct(';',0,0,";",
923922
RAW_PARSE_DEFAULT,
924-
false,false,true,
923+
false,false,
925924
&startloc,NULL);
926925
/* overwrite "perform" ...*/
927926
memcpy(new->expr->query," SELECT",7);
@@ -1007,7 +1006,7 @@ stmt_assign: T_DATUM
10071006
plpgsql_push_back_token(T_DATUM);
10081007
new->expr =read_sql_construct(';',0,0,";",
10091008
pmode,
1010-
false,true,true,
1009+
false,true,
10111010
NULL,NULL);
10121011

10131012
$$ = (PLpgSQL_stmt *)new;
@@ -1496,7 +1495,6 @@ for_control: for_variable K_IN
14961495
RAW_PARSE_DEFAULT,
14971496
true,
14981497
false,
1499-
true,
15001498
&expr1loc,
15011499
&tok);
15021500

@@ -1901,7 +1899,7 @@ stmt_raise: K_RAISE
19011899
expr =read_sql_construct(',',';', K_USING,
19021900
", or ; or USING",
19031901
RAW_PARSE_PLPGSQL_EXPR,
1904-
true,true,true,
1902+
true,true,
19051903
NULL, &tok);
19061904
new->params =lappend(new->params, expr);
19071905
}
@@ -2034,7 +2032,7 @@ stmt_dynexecute : K_EXECUTE
20342032
expr =read_sql_construct(K_INTO, K_USING,';',
20352033
"INTO or USING or ;",
20362034
RAW_PARSE_PLPGSQL_EXPR,
2037-
true,true,true,
2035+
true,true,
20382036
NULL, &endtoken);
20392037

20402038
new =palloc(sizeof(PLpgSQL_stmt_dynexecute));
@@ -2073,7 +2071,7 @@ stmt_dynexecute : K_EXECUTE
20732071
expr =read_sql_construct(',',';', K_INTO,
20742072
", or ; or INTO",
20752073
RAW_PARSE_PLPGSQL_EXPR,
2076-
true,true,true,
2074+
true,true,
20772075
NULL, &endtoken);
20782076
new->params =lappend(new->params, expr);
20792077
}while (endtoken ==',');
@@ -2656,7 +2654,7 @@ read_sql_expression(int until, const char *expected)
26562654
{
26572655
return read_sql_construct(until, 0, 0, expected,
26582656
RAW_PARSE_PLPGSQL_EXPR,
2659-
true, true,true,NULL, NULL);
2657+
true, true, NULL, NULL);
26602658
}
26612659

26622660
/* Convenience routine to read an expression with two possible terminators*/
@@ -2666,7 +2664,7 @@ read_sql_expression2(int until, int until2, const char *expected,
26662664
{
26672665
return read_sql_construct(until, until2, 0, expected,
26682666
RAW_PARSE_PLPGSQL_EXPR,
2669-
true, true,true,NULL, endtoken);
2667+
true, true, NULL, endtoken);
26702668
}
26712669

26722670
/* Convenience routine to read a SQL statement that must end with ';'*/
@@ -2675,7 +2673,7 @@ read_sql_stmt(void)
26752673
{
26762674
return read_sql_construct(';', 0, 0, ";",
26772675
RAW_PARSE_DEFAULT,
2678-
false, true,true,NULL, NULL);
2676+
false, true, NULL, NULL);
26792677
}
26802678

26812679
/*
@@ -2688,7 +2686,6 @@ read_sql_stmt(void)
26882686
* parsemode:raw_parser() mode to use
26892687
* isexpression: whether to say we're reading an "expression" or a "statement"
26902688
* valid_sql: whether to check the syntax of the expr
2691-
* trim:trim trailing whitespace
26922689
* startloc:if not NULL, location of first token is stored at *startloc
26932690
* endtoken:if not NULL, ending token is stored at *endtoken
26942691
*(this is only interesting if until2 or until3 isn't zero)
@@ -2701,14 +2698,14 @@ read_sql_construct(int until,
27012698
RawParseMode parsemode,
27022699
bool isexpression,
27032700
bool valid_sql,
2704-
bool trim,
27052701
int *startloc,
27062702
int *endtoken)
27072703
{
27082704
inttok;
27092705
StringInfoDatads;
27102706
IdentifierLookupsave_IdentifierLookup;
27112707
intstartlocation = -1;
2708+
intendlocation = -1;
27122709
intparenlevel = 0;
27132710
PLpgSQL_expr*expr;
27142711

@@ -2759,6 +2756,8 @@ read_sql_construct(int until,
27592756
expected),
27602757
parser_errposition(yylloc)));
27612758
}
2759+
/* Remember end+1 location of last accepted token*/
2760+
endlocation = yylloc + plpgsql_token_length();
27622761
}
27632762

27642763
plpgsql_IdentifierLookup = save_IdentifierLookup;
@@ -2769,22 +2768,22 @@ read_sql_construct(int until,
27692768
*endtoken = tok;
27702769

27712770
/* give helpful complaint about empty input*/
2772-
if (startlocation >=yylloc)
2771+
if (startlocation >=endlocation)
27732772
{
27742773
if (isexpression)
27752774
yyerror("missing expression");
27762775
else
27772776
yyerror("missing SQL statement");
27782777
}
27792778

2780-
plpgsql_append_source_text(&ds, startlocation, yylloc);
2781-
2782-
/* trim any trailing whitespace, for neatness*/
2783-
if (trim)
2784-
{
2785-
while (ds.len > 0 && scanner_isspace(ds.data[ds.len - 1]))
2786-
ds.data[--ds.len] = '\0';
2787-
}
2779+
/*
2780+
* We save only the text from startlocation to endlocation-1. This
2781+
* suppresses the "until" token as well as any whitespace or comments
2782+
* following the last accepted token. (We used to strip such trailing
2783+
* whitespace by hand, but that causes problems if there's a "-- comment"
2784+
* in front of said whitespace.)
2785+
*/
2786+
plpgsql_append_source_text(&ds, startlocation, endlocation);
27882787

27892788
expr = palloc0(sizeof(PLpgSQL_expr));
27902789
expr->query= pstrdup(ds.data);
@@ -3923,16 +3922,12 @@ read_cursor_args(PLpgSQL_var *cursor, int until)
39233922
* Read the value expression. To provide the user with meaningful
39243923
* parse error positions, we check the syntax immediately, instead of
39253924
* checking the final expression that may have the arguments
3926-
* reordered. Trailing whitespace must not be trimmed, because
3927-
* otherwise input of the form (param -- comment\n, param) would be
3928-
* translated into a form where the second parameter is commented
3929-
* out.
3925+
* reordered.
39303926
*/
39313927
item = read_sql_construct(',', ')', 0,
39323928
",\" or \")",
39333929
RAW_PARSE_PLPGSQL_EXPR,
39343930
true, true,
3935-
false,/* do not trim*/
39363931
NULL, &endtoken);
39373932

39383933
argv[argpos] = item->query;

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ plpgsql_yylex(void)
184184
tok1=T_DATUM;
185185
else
186186
tok1=T_CWORD;
187+
/* Adjust token length to include A.B.C */
188+
aux1.leng=aux5.lloc-aux1.lloc+aux5.leng;
187189
}
188190
else
189191
{
@@ -197,6 +199,8 @@ plpgsql_yylex(void)
197199
tok1=T_DATUM;
198200
else
199201
tok1=T_CWORD;
202+
/* Adjust token length to include A.B */
203+
aux1.leng=aux3.lloc-aux1.lloc+aux3.leng;
200204
}
201205
}
202206
else
@@ -210,6 +214,8 @@ plpgsql_yylex(void)
210214
tok1=T_DATUM;
211215
else
212216
tok1=T_CWORD;
217+
/* Adjust token length to include A.B */
218+
aux1.leng=aux3.lloc-aux1.lloc+aux3.leng;
213219
}
214220
}
215221
else
@@ -298,6 +304,17 @@ plpgsql_yylex(void)
298304
returntok1;
299305
}
300306

307+
/*
308+
* Return the length of the token last returned by plpgsql_yylex().
309+
*
310+
* In the case of compound tokens, the length includes all the parts.
311+
*/
312+
int
313+
plpgsql_token_length(void)
314+
{
315+
returnplpgsql_yyleng;
316+
}
317+
301318
/*
302319
* Internal yylex function. This wraps the core lexer and adds one feature:
303320
* a token pushback stack. We also make a couple of trivial single-token

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,6 +1302,7 @@ extern void plpgsql_dumptree(PLpgSQL_function *func);
13021302
*/
13031303
externintplpgsql_base_yylex(void);
13041304
externintplpgsql_yylex(void);
1305+
externintplpgsql_token_length(void);
13051306
externvoidplpgsql_push_back_token(inttoken);
13061307
externboolplpgsql_token_is_unreserved_keyword(inttoken);
13071308
externvoidplpgsql_append_source_text(StringInfobuf,

‎src/pl/plpgsql/src/sql/plpgsql_control.sql

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,3 +486,17 @@ select case_test(1);
486486
select case_test(2);
487487
select case_test(12);
488488
select case_test(13);
489+
490+
-- test line comment between WHEN and THEN
491+
create or replacefunctioncase_comment(int) returnstextas $$
492+
begin
493+
case $1
494+
when1-- comment before THEN
495+
then return'one';
496+
else
497+
return'other';
498+
end case;
499+
end;
500+
$$ language plpgsql immutable;
501+
502+
select case_comment(1);

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2363,11 +2363,9 @@ select namedparmcursor_test7();
23632363
ERROR: division by zero
23642364
CONTEXT: SQL expression "42/0 AS p1, 77 AS p2"
23652365
PL/pgSQL function namedparmcursor_test7() line 6 at OPEN
2366-
-- check that line comments work correctly within the argument list (there
2367-
-- is some special handling of this case in the code: the newline after the
2368-
-- comment must be preserved when the argument-evaluating query is
2369-
-- constructed, otherwise the comment effectively comments out the next
2370-
-- argument, too)
2366+
-- check that line comments work correctly within the argument list
2367+
-- (this used to require a special hack in the code; it no longer does,
2368+
-- but let's keep the test anyway)
23712369
create function namedparmcursor_test8() returns int4 as $$
23722370
declare
23732371
c1 cursor (p1 int, p2 int) for

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2023,11 +2023,9 @@ begin
20232023
end $$ language plpgsql;
20242024
select namedparmcursor_test7();
20252025

2026-
-- check that line comments work correctly within the argument list (there
2027-
-- is some special handling of this case in the code: the newline after the
2028-
-- comment must be preserved when the argument-evaluating query is
2029-
-- constructed, otherwise the comment effectively comments out the next
2030-
-- argument, too)
2026+
-- check that line comments work correctly within the argument list
2027+
-- (this used to require a special hack in the code; it no longer does,
2028+
-- but let's keep the test anyway)
20312029
createfunctionnamedparmcursor_test8() returns int4as $$
20322030
declare
20332031
c1 cursor (p1int, p2int) for

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp