From c546fce5b997cd171a2e92608092f63d60d18a58 Mon Sep 17 00:00:00 2001 From: Jeevan Chalke Date: Fri, 30 Oct 2026 12:05:41 +0530 Subject: [PATCH v1] Fix PL/pgSQL "missing X at end of SQL expression" error reporting. read_sql_construct() takes up to three terminator tokens, passing zero for those not used. But zero is also the token code for end of input, so when the function body ended in the middle of an expression or statement, the loop treated EOF as a valid terminator and stopped there, instead of reaching the code that reports a missing terminator. Users got a generic "syntax error at end of input", or a misleading "missing expression at end of input", instead of e.g. 'missing "THEN" at end of SQL expression'. Don't let unused terminator slots match EOF. --- src/pl/plpgsql/src/pl_gram.y | 5 +++-- src/test/regress/expected/plpgsql.out | 17 +++++++++++++++++ src/test/regress/sql/plpgsql.sql | 6 ++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index 37785f58cc2..f088dd08fc1 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -2790,11 +2790,12 @@ read_sql_construct(int until, tok = yylex(yylvalp, yyllocp, yyscanner); if (startlocation < 0) /* remember loc of first token */ startlocation = *yyllocp; + /* until2 and until3 are zero if unused; don't let them match EOF */ if (tok == until && parenlevel == 0) break; - if (tok == until2 && parenlevel == 0) + if (until2 != 0 && tok == until2 && parenlevel == 0) break; - if (tok == until3 && parenlevel == 0) + if (until3 != 0 && tok == until3 && parenlevel == 0) break; if (tok == '(' || tok == '[') parenlevel++; diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out index b37b2abaf80..2b3ec92b41b 100644 --- a/src/test/regress/expected/plpgsql.out +++ b/src/test/regress/expected/plpgsql.out @@ -2557,6 +2557,23 @@ ERROR: control reached end of function without RETURN CONTEXT: PL/pgSQL function missing_return_expr() drop function void_return_expr(); drop function missing_return_expr(); +-- unterminated constructs should complain about the missing terminator +do $$ begin if true $$; +ERROR: missing "THEN" at end of SQL expression +LINE 1: do $$ begin if true $$; + ^ +do $$ begin while true $$; +ERROR: missing "LOOP" at end of SQL expression +LINE 1: do $$ begin while true $$; + ^ +do $$ begin case 1 $$; +ERROR: missing "WHEN" at end of SQL expression +LINE 1: do $$ begin case 1 $$; + ^ +do $$ declare x int; begin x := 1 $$; +ERROR: missing ";" at end of SQL statement +LINE 1: do $$ declare x int; begin x := 1 $$; + ^ -- -- EXECUTE ... INTO test -- diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql index ae6b67e3e22..e655aac3b6c 100644 --- a/src/test/regress/sql/plpgsql.sql +++ b/src/test/regress/sql/plpgsql.sql @@ -2183,6 +2183,12 @@ select missing_return_expr(); drop function void_return_expr(); drop function missing_return_expr(); +-- unterminated constructs should complain about the missing terminator +do $$ begin if true $$; +do $$ begin while true $$; +do $$ begin case 1 $$; +do $$ declare x int; begin x := 1 $$; + -- -- EXECUTE ... INTO test -- -- 2.43.0