Re: PL/pgSQL: "missing X at end of SQL expression" is never reported at end of input

From: Heikki Linnakangas <hlinnaka(at)iki(dot)fi>
To: Jeevan Chalke <jeevan(dot)chalke(at)enterprisedb(dot)com>, PostgreSQL Hackers <pgsql-hackers(at)postgresql(dot)org>, PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Re: PL/pgSQL: "missing X at end of SQL expression" is never reported at end of input
Date: 2026-10-31 11:01:07
Message-ID: 0410a125-cfad-4a6a-ace6-bf4b293e9667@iki.fi
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On 30/10/2026 08:59, Jeevan Chalke wrote:
> read_sql_construct() in pl_gram.y takes up to three terminator tokens.
> Callers pass 0 for the ones they don't use, but 0 is also the token code
> for end of input.  The loop compares against until2 and until3 before it
> gets to its own "tok == 0" check, which is what produces the
> missing "%s" at end of SQL expression/statement
> error.
>
> So when a function body ends in the middle of a construct, EOF is taken
> as a valid terminator and the helpful message is skipped.  The text read
> so far is then handed to the core parser or the next grammar rule, which
> reports something generic or misleading:
>
>     do $$ begin if true $$;
>     ERROR:  syntax error at end of input
>
>     do $$ begin while true $$;
>     ERROR:  syntax error at end of input
>
>     do $$ begin case 1 $$;
>     ERROR:  missing expression at end of input
>
>     do $$ declare x int; begin x := 1 $$;
>     ERROR:  syntax error at end of input
>
> The attached patch only compares against until2/until3 when they are
> non-zero (until is always non-zero for every caller).  With it:
>
>     do $$ begin if true $$;
>     ERROR:  missing "THEN" at end of SQL expression
>
>     do $$ begin while true $$;
>     ERROR:  missing "LOOP" at end of SQL expression
>
>     do $$ begin case 1 $$;
>     ERROR:  missing "WHEN" at end of SQL expression
>
>     do $$ declare x int; begin x := 1 $$;
>     ERROR:  missing ";" at end of SQL statement
>
> The error position is the same as before (end of input).

Nice catch.

> I added the four statements above to plpgsql.sql; no existing
> expected output changes.
I moved the tests to src/plpgsql/src/sql/plpgsql_misc.sql. The division
isn't totally clear, but I think the main suite's plpgsql.sql is more
geared towards for PL/pgSQL's interactions with the rest of the system,
and the tests in src/plpgsql/src/ are more for pl/pgSQL's internal
business. I also removed two of those variants as redundant; they all
reach the same codepath in read_sql_construct() function in the end.

> Since this only changes error message text, which tests and external
> tools may match on, I think master only is the safer choice (or v19 as
> it is not yet released), but I'm happy to hear
> other opinions.

Committed to master, thanks!

- Heikki

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Amit Kapila 2026-10-31 11:05:40 Re: Proposal: Conflict log history table for Logical Replication
Previous Message Roman Khapov 2026-10-31 10:57:50 pgbench --unlogged-tables silently ignored for branches/tellers/history when --partitions is used