Subject: plpgsql: fix parsing of integer range with underscores

From: Erik Wienhold <[email-masked]>
Date: Wed, 15 May 2024 03:14:36 +0200

plpgsql fails to parse 1_000..1_000 as 1000..1000 in FOR loops:

    DO $$
    DECLARE
        i int;
    BEGIN
        FOR i IN 1_000..1_000 LOOP
        END LOOP;
    END $$;

    ERROR:  syntax error at or near "1_000."
    LINE 5:     FOR i IN 1_000..1_000 LOOP

The scan.l defines rule "numericfail" to handle this ambiguity without
requiring extra whitespace or parenthesis around the integer literals.
But the rule only accepts digits 0-9.  Again, an oversight in
faff8f8e47.  Fixed in the attached patch.

-- 
Erik
>From 7e51d9ea7ef2ffc2a2b8c831533a382a5493575b Mon Sep 17 00:00:00 2001
From: Erik Wienhold <[email-masked]>
Date: Wed, 15 May 2024 02:43:12 +0200
Subject: [PATCH] plpgsql: fix parsing of integer range with underscores

Fix lexer rule "numericfail" that ensures that we parse 1_000..1_000 as
1000..1000 instead of failing with 'syntax error at or near "1_000."' or
requiring extra whitespace/parenthesis to resolve the ambiguity.

Oversight in faff8f8e47 which added underscores to numeric literals.
---
 src/backend/parser/scan.l                | 2 +-
 src/fe_utils/psqlscan.l                  | 2 +-
 src/interfaces/ecpg/preproc/pgc.l        | 2 +-
 src/test/regress/expected/numerology.out | 7 +++++++
 src/test/regress/sql/numerology.sql      | 8 ++++++++
 5 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index 5eaadf53b2..a8e504ad09 100644
--- a/src/backend/parser/scan.l
+++ b/src/backend/parser/scan.l
@@ -407,7 +407,7 @@ octfail			0[oO]_?
 binfail			0[bB]_?
 
 numeric			(({decinteger}\.{decinteger}?)|(\.{decinteger}))
-numericfail		{decdigit}+\.\.
+numericfail		{decinteger}\.\.
 
 real			({decinteger}|{numeric})[Ee][-+]?{decinteger}
 realfail		({decinteger}|{numeric})[Ee][-+]
diff --git a/src/fe_utils/psqlscan.l b/src/fe_utils/psqlscan.l
index c9df0594fd..7780151434 100644
--- a/src/fe_utils/psqlscan.l
+++ b/src/fe_utils/psqlscan.l
@@ -343,7 +343,7 @@ octfail			0[oO]_?
 binfail			0[bB]_?
 
 numeric			(({decinteger}\.{decinteger}?)|(\.{decinteger}))
-numericfail		{decdigit}+\.\.
+numericfail		{decinteger}\.\.
 
 real			({decinteger}|{numeric})[Ee][-+]?{decinteger}
 realfail		({decinteger}|{numeric})[Ee][-+]
diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l
index bcfbd0978b..7744d2facf 100644
--- a/src/interfaces/ecpg/preproc/pgc.l
+++ b/src/interfaces/ecpg/preproc/pgc.l
@@ -376,7 +376,7 @@ octfail			0[oO]_?
 binfail			0[bB]_?
 
 numeric			(({decinteger}\.{decinteger}?)|(\.{decinteger}))
-numericfail		{decdigit}+\.\.
+numericfail		{decinteger}\.\.
 
 real			({decinteger}|{numeric})[Ee][-+]?{decinteger}
 realfail		({decinteger}|{numeric})[Ee][-+]
diff --git a/src/test/regress/expected/numerology.out b/src/test/regress/expected/numerology.out
index f662a5050a..86caccbbc5 100644
--- a/src/test/regress/expected/numerology.out
+++ b/src/test/regress/expected/numerology.out
@@ -297,6 +297,13 @@ SELECT 1_000.5e0_1;
     10005
 (1 row)
 
+DO $$
+DECLARE
+  i int;
+BEGIN
+  FOR i IN 1_000..1_000 LOOP
+  END LOOP;
+END $$;
 -- error cases
 SELECT _100;
 ERROR:  column "_100" does not exist
diff --git a/src/test/regress/sql/numerology.sql b/src/test/regress/sql/numerology.sql
index 1941c58e68..eb8d4e48d7 100644
--- a/src/test/regress/sql/numerology.sql
+++ b/src/test/regress/sql/numerology.sql
@@ -77,6 +77,14 @@ SELECT 1_000.;
 SELECT .000_005;
 SELECT 1_000.5e0_1;
 
+DO $$
+DECLARE
+  i int;
+BEGIN
+  FOR i IN 1_000..1_000 LOOP
+  END LOOP;
+END $$;
+
 -- error cases
 SELECT _100;
 SELECT 100_;
-- 
2.45.1