From 382f1a2ba65406dcfc5b52ca87f124efa453f0c9 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Mon, 8 Jun 2026 19:00:24 +0800
Subject: [PATCH v47 1/4] v47 rpr reformat gram.y again

Row pattern recognition: include the offending token in quantifier error messages

When an unrecognized token follows a quantifier (*?, +?, ??, {n}?, {n,}?, {,m}?,
{n,m}?), the error message now quotes the actual token that was found, making it
easier to diagnose the problem.

SELECT FROM rpr_err WINDOW w AS ( ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A {2}??) DEFINE A AS TRUE);
ERROR:  invalid token "??" after range quantifier
LINE 1: ...BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A {2}??) DEFINE...
                                                             ^
HINT:  Only "?" is allowed after {n} to make it reluctant.

Here, the ? follows a range quantifier. Even though we only have two of them,
explicitly quoting the wrong token makes it much easier to read.
---
 src/backend/parser/gram.y              | 14 ++++++-------
 src/test/regress/expected/rpr_base.out | 29 +++++++++++++++-----------
 src/test/regress/sql/rpr_base.sql      |  3 ++-
 3 files changed, 26 insertions(+), 20 deletions(-)

diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index ac2e5d7914..b3d2435cf2 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -17813,7 +17813,7 @@ row_pattern_quantifier_opt:
 					else
 						ereport(ERROR,
 								errcode(ERRCODE_SYNTAX_ERROR),
-								errmsg("invalid token after \"*\" quantifier"),
+								errmsg("invalid token \"%s\" after \"*\" quantifier", $2),
 								errhint("Did you mean \"*?\" for reluctant quantifier?"),
 								parser_errposition(@2));
 				}
@@ -17830,7 +17830,7 @@ row_pattern_quantifier_opt:
 					else
 						ereport(ERROR,
 								errcode(ERRCODE_SYNTAX_ERROR),
-								errmsg("invalid token after \"+\" quantifier"),
+								errmsg("invalid token \"%s\" after \"+\" quantifier", $2),
 								errhint("Did you mean \"+?\" for reluctant quantifier?"),
 								parser_errposition(@2));
 				}
@@ -17839,7 +17839,7 @@ row_pattern_quantifier_opt:
 					if (strcmp($1, "?") != 0)
 						ereport(ERROR,
 								errcode(ERRCODE_SYNTAX_ERROR),
-								errmsg("invalid quantifier combination"),
+								errmsg("invalid quantifier combination: \"%s%s\"", $1, $2),
 								errhint("Did you mean \"??\" for reluctant quantifier?"),
 								parser_errposition(@1));
 					if (strcmp($2, "?") == 0)
@@ -17905,7 +17905,7 @@ row_pattern_quantifier_opt:
 					if (strcmp($4, "?") != 0 && strcmp($4, "?|") != 0)
 						ereport(ERROR,
 								errcode(ERRCODE_SYNTAX_ERROR),
-								errmsg("invalid token after range quantifier"),
+								errmsg("invalid token \"%s\" after range quantifier", $4),
 								errhint("Only \"?\" is allowed after {n} to make it reluctant."),
 								parser_errposition(@4));
 					if ($2 <= 0 || $2 >= PG_INT32_MAX)
@@ -17922,7 +17922,7 @@ row_pattern_quantifier_opt:
 					if (strcmp($5, "?") != 0 && strcmp($5, "?|") != 0)
 						ereport(ERROR,
 								errcode(ERRCODE_SYNTAX_ERROR),
-								errmsg("invalid token after range quantifier"),
+								errmsg("invalid token \"%s\" after range quantifier", $5),
 								errhint("Only \"?\" is allowed after {n,} or {,m} to make it reluctant."),
 								parser_errposition(@5));
 					if ($2 < 0 || $2 >= PG_INT32_MAX)
@@ -17939,7 +17939,7 @@ row_pattern_quantifier_opt:
 					if (strcmp($5, "?") != 0 && strcmp($5, "?|") != 0)
 						ereport(ERROR,
 								errcode(ERRCODE_SYNTAX_ERROR),
-								errmsg("invalid token after range quantifier"),
+								errmsg("invalid token \"%s\" after range quantifier", $5),
 								errhint("Only \"?\" is allowed after {n,} or {,m} to make it reluctant."),
 								parser_errposition(@5));
 					if ($3 <= 0 || $3 >= PG_INT32_MAX)
@@ -17956,7 +17956,7 @@ row_pattern_quantifier_opt:
 					if (strcmp($6, "?") != 0 && strcmp($6, "?|") != 0)
 						ereport(ERROR,
 								errcode(ERRCODE_SYNTAX_ERROR),
-								errmsg("invalid token after range quantifier"),
+								errmsg("invalid token \"%s\" after range quantifier", $6),
 								errhint("Only \"?\" is allowed after {n,m} to make it reluctant."),
 								parser_errposition(@6));
 					if ($2 < 0 || $4 <= 0 || $2 >= PG_INT32_MAX || $4 >= PG_INT32_MAX)
diff --git a/src/test/regress/expected/rpr_base.out b/src/test/regress/expected/rpr_base.out
index 2407c45516..43683c79e3 100644
--- a/src/test/regress/expected/rpr_base.out
+++ b/src/test/regress/expected/rpr_base.out
@@ -3217,12 +3217,12 @@ ERROR:  alternation operator "|" requires a pattern on both sides
 LINE 1: ...EEN CURRENT ROW AND UNBOUNDED FOLLOWING PATTERN ((A*|)) DEFI...
                                                              ^
 SELECT count(*) OVER w FROM rpr_glue WINDOW w AS (ORDER BY id ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING PATTERN (A* *|B) DEFINE A AS val > 0, B AS val <= 0);
-ERROR:  invalid token after "*" quantifier
+ERROR:  invalid token "*|" after "*" quantifier
 LINE 1: ...N CURRENT ROW AND UNBOUNDED FOLLOWING PATTERN (A* *|B) DEFIN...
                                                              ^
 HINT:  Did you mean "*?" for reluctant quantifier?
 SELECT count(*) OVER w FROM rpr_glue WINDOW w AS (ORDER BY id ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING PATTERN (A* *?|B) DEFINE A AS val > 0, B AS val <= 0);
-ERROR:  invalid token after "*" quantifier
+ERROR:  invalid token "*?|" after "*" quantifier
 LINE 1: ...N CURRENT ROW AND UNBOUNDED FOLLOWING PATTERN (A* *?|B) DEFI...
                                                              ^
 HINT:  Did you mean "*?" for reluctant quantifier?
@@ -3232,12 +3232,12 @@ LINE 1: ...EEN CURRENT ROW AND UNBOUNDED FOLLOWING PATTERN (A? *?|B) DE...
                                                              ^
 HINT:  Did you mean "??" for reluctant quantifier?
 SELECT count(*) OVER w FROM rpr_glue WINDOW w AS (ORDER BY id ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING PATTERN (A{2}*?|B) DEFINE A AS val > 0, B AS val <= 0);
-ERROR:  invalid token after range quantifier
+ERROR:  invalid token "*?|" after range quantifier
 LINE 1: ... CURRENT ROW AND UNBOUNDED FOLLOWING PATTERN (A{2}*?|B) DEFI...
                                                              ^
 HINT:  Only "?" is allowed after {n} to make it reluctant.
 SELECT count(*) OVER w FROM rpr_glue WINDOW w AS (ORDER BY id ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING PATTERN (A{2} *?|B) DEFINE A AS val > 0, B AS val <= 0);
-ERROR:  invalid token after range quantifier
+ERROR:  invalid token "*?|" after range quantifier
 LINE 1: ...CURRENT ROW AND UNBOUNDED FOLLOWING PATTERN (A{2} *?|B) DEFI...
                                                              ^
 HINT:  Only "?" is allowed after {n} to make it reluctant.
@@ -3283,19 +3283,19 @@ ERROR:  unsupported quantifier "+!"
 LINE 6:     PATTERN (A+!)
                       ^
 HINT:  Valid quantifiers are: *, +, ?, *?, +?, ??, {n}, {n,}, {,m}, {n,m} and their reluctant versions.
--- none of the following 4 queries should be accepted
+-- none of the following queries should be accepted
 SELECT FROM rpr_err WINDOW w AS ( ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A+ !) DEFINE A AS TRUE);
-ERROR:  invalid token after "+" quantifier
+ERROR:  invalid token "!" after "+" quantifier
 LINE 1: ...S BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A+ !) DEFINE ...
                                                              ^
 HINT:  Did you mean "+?" for reluctant quantifier?
 SELECT FROM rpr_err WINDOW w AS ( ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A+ ?+) DEFINE A AS TRUE);
-ERROR:  invalid token after "+" quantifier
+ERROR:  invalid token "?+" after "+" quantifier
 LINE 1: ...S BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A+ ?+) DEFINE...
                                                              ^
 HINT:  Did you mean "+?" for reluctant quantifier?
 SELECT FROM rpr_err WINDOW w AS ( ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A* ?+) DEFINE A AS TRUE);
-ERROR:  invalid token after "*" quantifier
+ERROR:  invalid token "?+" after "*" quantifier
 LINE 1: ...S BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A* ?+) DEFINE...
                                                              ^
 HINT:  Did you mean "*?" for reluctant quantifier?
@@ -3304,24 +3304,29 @@ ERROR:  invalid quantifier combination
 LINE 1: ...OWS BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A? ??) DEFI...
                                                              ^
 HINT:  Did you mean "??" for reluctant quantifier?
+SELECT FROM rpr_err WINDOW w AS ( ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A {1,2}??) DEFINE A AS TRUE);
+ERROR:  invalid token "??" after range quantifier
+LINE 1: ...TWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A {1,2}??) DEFINE...
+                                                             ^
+HINT:  Only "?" is allowed after {n,m} to make it reluctant.
 -- none of the following 4 range-quantifier queries should be accepted
 SELECT FROM rpr_err WINDOW w AS ( ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A{2} !) DEFINE A AS TRUE);
-ERROR:  invalid token after range quantifier
+ERROR:  invalid token "!" after range quantifier
 LINE 1: ...BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A{2} !) DEFINE ...
                                                              ^
 HINT:  Only "?" is allowed after {n} to make it reluctant.
 SELECT FROM rpr_err WINDOW w AS ( ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A{2,} !) DEFINE A AS TRUE);
-ERROR:  invalid token after range quantifier
+ERROR:  invalid token "!" after range quantifier
 LINE 1: ...ETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A{2,} !) DEFINE ...
                                                              ^
 HINT:  Only "?" is allowed after {n,} or {,m} to make it reluctant.
 SELECT FROM rpr_err WINDOW w AS ( ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A{,3} !) DEFINE A AS TRUE);
-ERROR:  invalid token after range quantifier
+ERROR:  invalid token "!" after range quantifier
 LINE 1: ...ETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A{,3} !) DEFINE ...
                                                              ^
 HINT:  Only "?" is allowed after {n,} or {,m} to make it reluctant.
 SELECT FROM rpr_err WINDOW w AS ( ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A{2,3} !) DEFINE A AS TRUE);
-ERROR:  invalid token after range quantifier
+ERROR:  invalid token "!" after range quantifier
 LINE 1: ...TWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A{2,3} !) DEFINE ...
                                                              ^
 HINT:  Only "?" is allowed after {n,m} to make it reluctant.
diff --git a/src/test/regress/sql/rpr_base.sql b/src/test/regress/sql/rpr_base.sql
index cec7ea1e8d..5e95859f75 100644
--- a/src/test/regress/sql/rpr_base.sql
+++ b/src/test/regress/sql/rpr_base.sql
@@ -2146,11 +2146,12 @@ WINDOW w AS (
     DEFINE A AS val > 0
 );
 
--- none of the following 4 queries should be accepted
+-- none of the following queries should be accepted
 SELECT FROM rpr_err WINDOW w AS ( ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A+ !) DEFINE A AS TRUE);
 SELECT FROM rpr_err WINDOW w AS ( ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A+ ?+) DEFINE A AS TRUE);
 SELECT FROM rpr_err WINDOW w AS ( ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A* ?+) DEFINE A AS TRUE);
 SELECT FROM rpr_err WINDOW w AS ( ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A? ??) DEFINE A AS TRUE);
+SELECT FROM rpr_err WINDOW w AS ( ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A {1,2}??) DEFINE A AS TRUE);
 
 -- none of the following 4 range-quantifier queries should be accepted
 SELECT FROM rpr_err WINDOW w AS ( ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING PATTERN (A{2} !) DEFINE A AS TRUE);
-- 
2.34.1

