nocfbot-0006-allow-a0-quantifier.patch
application/octet-stream
Filename: nocfbot-0006-allow-a0-quantifier.patch
Type: application/octet-stream
Part: 5
Message:
Re: Row pattern recognition
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch 0006
Subject: Allow A{0} quantifier
| File | + | − |
|---|---|---|
| src/backend/executor/nodeWindowAgg.c | 7 | 0 |
| src/backend/parser/gram.y | 4 | 4 |
| src/test/regress/expected/rpr_base.out | 20 | 9 |
| src/test/regress/sql/rpr_base.sql | 4 | 4 |
From 2db769b38bb4b339f57a9d2cff6bdd8f1305c551 Mon Sep 17 00:00:00 2001
From: Henson Choi <assam258@gmail.com>
Date: Mon, 23 Feb 2026 14:56:42 +0900
Subject: [PATCH 6/6] Allow A{0} quantifier
---
src/backend/executor/nodeWindowAgg.c | 7 +++++++
src/backend/parser/gram.y | 8 +++----
src/test/regress/expected/rpr_base.out | 29 ++++++++++++++++++--------
src/test/regress/sql/rpr_base.sql | 8 +++----
4 files changed, 35 insertions(+), 17 deletions(-)
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 98546fb17f7..72ded5efc1f 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -6070,6 +6070,13 @@ nfa_route_to_elem(WindowAggState *winstate, RPRNFAContext *ctx,
{
if (RPRElemIsVar(nextElem))
{
+ if (nextElem->max == 0)
+ {
+ /* max=0: variable never matches, treat as epsilon transition */
+ state->elemIdx = nextElem->next;
+ nfa_advance_state(winstate, ctx, state, currentPos, initialAdvance);
+ return;
+ }
nfa_add_state_unique(winstate, ctx, state);
if (RPRElemCanSkip(nextElem))
{
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 5a3d141e992..17503b38e3a 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -17070,10 +17070,10 @@ row_pattern_quantifier_opt:
/* {n}, {n,}, {,m}, {n,m} quantifiers */
| '{' Iconst '}'
{
- if ($2 <= 0 || $2 >= INT_MAX)
+ if ($2 < 0 || $2 >= INT_MAX)
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("quantifier bound must be between 1 and %d", INT_MAX - 1),
+ errmsg("quantifier bound must be between 0 and %d", INT_MAX - 1),
parser_errposition(@2));
$$ = (Node *) makeRPRQuantifier($2, $2, -1, @1, yyscanner);
}
@@ -17118,10 +17118,10 @@ row_pattern_quantifier_opt:
errmsg("invalid token after range quantifier"),
errhint("Only \"?\" is allowed after {n} to make it reluctant."),
parser_errposition(@4)));
- if ($2 <= 0 || $2 >= INT_MAX)
+ if ($2 < 0 || $2 >= INT_MAX)
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("quantifier bound must be between 1 and %d", INT_MAX - 1),
+ errmsg("quantifier bound must be between 0 and %d", INT_MAX - 1),
parser_errposition(@2));
$$ = (Node *) makeRPRQuantifier($2, $2, @4, @1, yyscanner);
}
diff --git a/src/test/regress/expected/rpr_base.out b/src/test/regress/expected/rpr_base.out
index 43eea32130f..7df71aaa904 100644
--- a/src/test/regress/expected/rpr_base.out
+++ b/src/test/regress/expected/rpr_base.out
@@ -923,7 +923,7 @@ ORDER BY id;
(10 rows)
-- Edge case quantifiers
--- {0} is not allowed (min must be >= 1)
+-- {0} always skips the variable (zero iterations)
SELECT id, val, COUNT(*) OVER w as cnt
FROM rpr_quant
WINDOW w AS (
@@ -933,10 +933,21 @@ WINDOW w AS (
DEFINE A AS val > 1000, B AS val > 0
)
ORDER BY id;
-ERROR: quantifier bound must be between 1 and 2147483646
-LINE 6: PATTERN (A{0} B)
- ^
--- Expected: ERROR: quantifier bound must be between 1 and 2147483646
+ id | val | cnt
+----+-----+-----
+ 1 | 10 | 1
+ 2 | 20 | 1
+ 3 | 30 | 1
+ 4 | 40 | 1
+ 5 | 50 | 1
+ 6 | 60 | 1
+ 7 | 70 | 1
+ 8 | 80 | 1
+ 9 | 90 | 1
+ 10 | 100 | 1
+(10 rows)
+
+-- Expected: A{0} skips A, only B matches each row
-- {0,0} is not allowed (max must be >= 1)
SELECT id, val, COUNT(*) OVER w as cnt
FROM rpr_quant
@@ -1274,10 +1285,10 @@ WINDOW w AS (
PATTERN (A{2147483647}?)
DEFINE A AS val > 0
);
-ERROR: quantifier bound must be between 1 and 2147483646
+ERROR: quantifier bound must be between 0 and 2147483646
LINE 6: PATTERN (A{2147483647}?)
^
--- Expected: ERROR: quantifier bound must be between 1 and 2147483646
+-- Expected: ERROR: quantifier bound must be between 0 and 2147483646
-- {-1,}? (negative lower bound)
SELECT COUNT(*) OVER w
FROM rpr_reluctant
@@ -1537,10 +1548,10 @@ WINDOW w AS (
PATTERN (A{2147483647})
DEFINE A AS id > 0
);
-ERROR: quantifier bound must be between 1 and 2147483646
+ERROR: quantifier bound must be between 0 and 2147483646
LINE 6: PATTERN (A{2147483647})
^
--- Expected: ERROR: quantifier bound must be between 1 and 2147483646
+-- Expected: ERROR: quantifier bound must be between 0 and 2147483646
-- {n,} boundary errors
-- Negative lower bound in {n,}
SELECT COUNT(*) OVER w
diff --git a/src/test/regress/sql/rpr_base.sql b/src/test/regress/sql/rpr_base.sql
index 992c081205a..d25ca07adaf 100644
--- a/src/test/regress/sql/rpr_base.sql
+++ b/src/test/regress/sql/rpr_base.sql
@@ -673,7 +673,7 @@ ORDER BY id;
-- Edge case quantifiers
--- {0} is not allowed (min must be >= 1)
+-- {0} always skips the variable (zero iterations)
SELECT id, val, COUNT(*) OVER w as cnt
FROM rpr_quant
WINDOW w AS (
@@ -683,7 +683,7 @@ WINDOW w AS (
DEFINE A AS val > 1000, B AS val > 0
)
ORDER BY id;
--- Expected: ERROR: quantifier bound must be between 1 and 2147483646
+-- Expected: A{0} skips A, only B matches each row
-- {0,0} is not allowed (max must be >= 1)
SELECT id, val, COUNT(*) OVER w as cnt
@@ -911,7 +911,7 @@ WINDOW w AS (
PATTERN (A{2147483647}?)
DEFINE A AS val > 0
);
--- Expected: ERROR: quantifier bound must be between 1 and 2147483646
+-- Expected: ERROR: quantifier bound must be between 0 and 2147483646
-- {-1,}? (negative lower bound)
SELECT COUNT(*) OVER w
@@ -1118,7 +1118,7 @@ WINDOW w AS (
PATTERN (A{2147483647})
DEFINE A AS id > 0
);
--- Expected: ERROR: quantifier bound must be between 1 and 2147483646
+-- Expected: ERROR: quantifier bound must be between 0 and 2147483646
-- {n,} boundary errors
--
2.50.1 (Apple Git-155)