| From: | "David G(dot) Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com> |
|---|---|
| To: | Leendert Gravendeel <leenderthenk(at)gmail(dot)com> |
| Cc: | pgsql-bugs(at)postgresql(dot)org |
| Subject: | Re: BUG: PL/pgSQL FOREACH misparses variable named "slice" with SLICE clause |
| Date: | 2026-04-17 15:17:52 |
| Message-ID: | CAKFQuwbjcqPV-xf6FUq4ECrwmt0woWVB78gs2sszJWVzJH5dYA@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-bugs |
On Fri, Apr 17, 2026 at 7:33 AM Leendert Gravendeel <leenderthenk(at)gmail(dot)com>
wrote:
> I believe I have found a parser issue in PL/pgSQL involving the
> FOREACH ... SLICE syntax.
>
Thanks for the report!
>
> CREATE FUNCTION test_slice_conflict() RETURNS text
> LANGUAGE plpgsql AS $$
> DECLARE
> slice integer[];
> arr integer[] := ARRAY[[1,2],[3,4]];
> BEGIN
> FOREACH slice SLICE 1 IN ARRAY arr LOOP
> END LOOP;
> RETURN 'ok';
> END;
> $$;
>
> Observed behavior:
> The function fails to compile due to incorrect parsing of `slice`
> as the SLICE keyword.
>
> Expected behavior:
> `slice` should be treated as a normal identifier (loop variable),
> and the function should compile and run successfully.
>
>
Confirmed on master.
Chat provided much more context for how/why this happened and why this
seems like a good fix; prior art is my main argument though.
If a PL/pgSQL variable is named "slice", using it in a FOREACH ... SLICE
loop produces a spurious syntax error:
DO $$ DECLARE
slice integer[];
arr integer[] := ARRAY[[1,2],[3,4]];
BEGIN
FOREACH slice SLICE 1 IN ARRAY arr LOOP
END LOOP;
END; $$;
ERROR: syntax error at or near "SLICE"
The one-token lookahead in the for_variable grammar action runs under
normal identifier lookup, so when "slice" is in scope the following SLICE
keyword is consumed as a T_DATUM reference rather than K_SLICE, and
foreach_slice fails.
The fix is to suppress variable lookup for that lookahead, using the same
save/restore pattern already used in pl_gram.y::read_cursor_args():
/* Read the argument name, ignoring any matching variable */
save_IdentifierLookup = plpgsql_IdentifierLookup;
plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_DECLARE;
yylex(yylvalp, yyllocp, yyscanner);
argname = yylvalp->str;
plpgsql_IdentifierLookup = save_IdentifierLookup;
Therefore we need:
diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y
index 5009e59a78f..681fd3d5cff 100644
--- a/src/pl/plpgsql/src/pl_gram.y
+++ b/src/pl/plpgsql/src/pl_gram.y
@@ -1635,11 +1635,15 @@ for_variable : T_DATUM
else
{
int tok;
+ IdentifierLookup save_IdentifierLookup;
$$.scalar = $1.datum;
$$.row = NULL;
/* check for comma-separated list */
+ save_IdentifierLookup = plpgsql_IdentifierLookup;
+ plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_DECLARE;
tok = yylex(&yylval, &yylloc, yyscanner);
+ plpgsql_IdentifierLookup = save_IdentifierLookup;
plpgsql_push_back_token(tok, &yylval, &yylloc,
yyscanner);
if (tok == ',')
$$.row = (PLpgSQL_datum *)
David J.
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Jacob Champion | 2026-04-17 19:14:49 | Re: PostgreSQL 17: Bug in libpq when libpq is dlopened/closed multiple times |
| Previous Message | Tom Lane | 2026-04-17 15:16:20 | Re: BUG: PL/pgSQL FOREACH misparses variable named "slice" with SLICE clause |