v50-0014-unbounded-quantifier-sentinel.patch
application/octet-stream
Filename: v50-0014-unbounded-quantifier-sentinel.patch
Type: application/octet-stream
Part: 22
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 v50-0014
Subject: Tidy up the row pattern unbounded-quantifier sentinel
| File | + | − |
|---|---|---|
| src/backend/optimizer/plan/rpr.c | 10 | 14 |
| src/backend/parser/gram.y | 39 | 39 |
From d51f2f55d4da92fb4f4c6e0880ee49361b48e152 Mon Sep 17 00:00:00 2001
From: Henson Choi <assam258@gmail.com>
Date: Mon, 22 Jun 2026 22:46:26 +0900
Subject: [PATCH v50 23/29] Tidy up the row pattern unbounded-quantifier
sentinel
The grammar and planner spelled the unbounded quantifier bound as a bare
PG_INT32_MAX, while the executor already used RPR_QUANTITY_INF for the
same value. Use RPR_QUANTITY_INF on the parser and planner side as well
so every stage shares one sentinel; gram.y keeps a local copy of the
macro to avoid including the planner header.
With the parser emitting RPR_QUANTITY_INF directly, the explicit
PG_INT32_MAX-to-RPR_QUANTITY_INF mapping in fillRPRPattern* becomes an
identity and is removed, and the adjacent quantifier-range Asserts are
simplified accordingly.
Also rewrite splitRPRTrailingAlt's loop with foreach_node() and
foreach_current_index(), and add a comment to makeRPRQuantifier.
Based on a patch by Jian He.
---
src/backend/optimizer/plan/rpr.c | 24 ++++------
src/backend/parser/gram.y | 78 ++++++++++++++++----------------
2 files changed, 49 insertions(+), 53 deletions(-)
diff --git a/src/backend/optimizer/plan/rpr.c b/src/backend/optimizer/plan/rpr.c
index 62292508aad..3d7752bd5ed 100644
--- a/src/backend/optimizer/plan/rpr.c
+++ b/src/backend/optimizer/plan/rpr.c
@@ -1187,10 +1187,9 @@ fillRPRPatternVar(RPRPatternNode *node, RPRPattern *pat, int *idx, RPRDepth dept
elem->varId = getVarIdFromPattern(pat, node->varName);
elem->depth = depth;
elem->min = node->min;
- elem->max = (node->max == PG_INT32_MAX) ? RPR_QUANTITY_INF : node->max;
+ elem->max = node->max;
Assert(elem->min >= 0 && elem->min < RPR_QUANTITY_INF &&
- elem->max >= 1 &&
- (elem->max == RPR_QUANTITY_INF || elem->min <= elem->max));
+ elem->max >= 1 && elem->min <= elem->max);
elem->next = RPR_ELEMIDX_INVALID;
elem->jump = RPR_ELEMIDX_INVALID;
if (node->reluctant)
@@ -1239,10 +1238,9 @@ fillRPRPatternGroup(RPRPatternNode *node, RPRPattern *pat, int *idx, RPRDepth de
elem->varId = RPR_VARID_BEGIN;
elem->depth = depth;
elem->min = node->min;
- elem->max = (node->max == PG_INT32_MAX) ? RPR_QUANTITY_INF : node->max;
+ elem->max = node->max;
Assert(elem->min >= 0 && elem->min < RPR_QUANTITY_INF &&
- elem->max >= 1 &&
- (elem->max == RPR_QUANTITY_INF || elem->min <= elem->max));
+ elem->max >= 1 && elem->min <= elem->max);
elem->next = RPR_ELEMIDX_INVALID; /* set by finalize */
elem->jump = RPR_ELEMIDX_INVALID; /* set after END */
if (node->reluctant)
@@ -1267,19 +1265,18 @@ fillRPRPatternGroup(RPRPatternNode *node, RPRPattern *pat, int *idx, RPRDepth de
endElem->varId = RPR_VARID_END;
endElem->depth = depth;
endElem->min = node->min;
- endElem->max = (node->max == PG_INT32_MAX) ? RPR_QUANTITY_INF : node->max;
+ endElem->max = node->max;
Assert(endElem->min >= 0 && endElem->min < RPR_QUANTITY_INF &&
- endElem->max >= 1 &&
- (endElem->max == RPR_QUANTITY_INF || endElem->min <= endElem->max));
+ endElem->max >= 1 && endElem->min <= endElem->max);
endElem->next = RPR_ELEMIDX_INVALID;
endElem->jump = groupStartIdx; /* loop to first child */
if (node->reluctant)
endElem->flags |= RPR_ELEM_RELUCTANT;
/*
- * If the group body is nullable (all paths can match empty), mark the
- * END element so that nfa_advance_end can fast-forward the iteration
- * count to min when reached via empty-match skip paths.
+ * If the group body is nullable, mark the END element so that
+ * nfa_advance_end can fast-forward the iteration count to min when
+ * reached via empty-match skip paths.
*/
if (bodyNullable)
endElem->flags |= RPR_ELEM_EMPTY_LOOP;
@@ -1455,8 +1452,7 @@ finalizeRPRPattern(RPRPattern *result)
/* Verify quantifier range is valid */
Assert(elem->min >= 0 && elem->min < RPR_QUANTITY_INF &&
- elem->max >= 1 &&
- (elem->max == RPR_QUANTITY_INF || elem->min <= elem->max));
+ elem->max >= 1 && elem->min <= elem->max);
}
/* Add FIN marker at the end */
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 6eb01ea7f0b..731b01eb742 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -151,6 +151,9 @@ typedef struct KeyActions
#define parser_yyerror(msg) scanner_yyerror(msg, yyscanner)
#define parser_errposition(pos) scanner_errposition(pos, yyscanner)
+/* unbounded quantifier; must match RPR_QUANTITY_INF in optimizer/rpr.h */
+#define RPR_QUANTITY_INF PG_INT32_MAX
+
static void base_yyerror(YYLTYPE *yylloc, core_yyscan_t yyscanner,
const char *msg);
static RawStmt *makeRawStmt(Node *stmt, int stmt_location);
@@ -17744,11 +17747,11 @@ row_pattern_quantifier_opt:
}
| '*'
{
- $$ = (Node *) makeRPRQuantifier(0, PG_INT32_MAX, false, @1);
+ $$ = (Node *) makeRPRQuantifier(0, RPR_QUANTITY_INF, false, @1);
}
| '+'
{
- $$ = (Node *) makeRPRQuantifier(1, PG_INT32_MAX, false, @1);
+ $$ = (Node *) makeRPRQuantifier(1, RPR_QUANTITY_INF, false, @1);
}
| Op
{
@@ -17756,19 +17759,19 @@ row_pattern_quantifier_opt:
if (strcmp($1, "?") == 0)
$$ = (Node *) makeRPRQuantifier(0, 1, false, @1);
else if (strcmp($1, "*?") == 0)
- $$ = (Node *) makeRPRQuantifier(0, PG_INT32_MAX, true, @1);
+ $$ = (Node *) makeRPRQuantifier(0, RPR_QUANTITY_INF, true, @1);
else if (strcmp($1, "+?") == 0)
- $$ = (Node *) makeRPRQuantifier(1, PG_INT32_MAX, true, @1);
+ $$ = (Node *) makeRPRQuantifier(1, RPR_QUANTITY_INF, true, @1);
else if (strcmp($1, "??") == 0)
$$ = (Node *) makeRPRQuantifier(0, 1, true, @1);
else if (strcmp($1, "*|") == 0)
{
- $$ = (Node *) makeRPRQuantifier(0, PG_INT32_MAX, false, @1);
+ $$ = (Node *) makeRPRQuantifier(0, RPR_QUANTITY_INF, false, @1);
((RPRPatternNode *) $$)->trailing_alt = true;
}
else if (strcmp($1, "+|") == 0)
{
- $$ = (Node *) makeRPRQuantifier(1, PG_INT32_MAX, false, @1);
+ $$ = (Node *) makeRPRQuantifier(1, RPR_QUANTITY_INF, false, @1);
((RPRPatternNode *) $$)->trailing_alt = true;
}
else if (strcmp($1, "?|") == 0)
@@ -17778,12 +17781,12 @@ row_pattern_quantifier_opt:
}
else if (strcmp($1, "*?|") == 0)
{
- $$ = (Node *) makeRPRQuantifier(0, PG_INT32_MAX, true, @1);
+ $$ = (Node *) makeRPRQuantifier(0, RPR_QUANTITY_INF, true, @1);
((RPRPatternNode *) $$)->trailing_alt = true;
}
else if (strcmp($1, "+?|") == 0)
{
- $$ = (Node *) makeRPRQuantifier(1, PG_INT32_MAX, true, @1);
+ $$ = (Node *) makeRPRQuantifier(1, RPR_QUANTITY_INF, true, @1);
((RPRPatternNode *) $$)->trailing_alt = true;
}
else if (strcmp($1, "??|") == 0)
@@ -17802,11 +17805,11 @@ row_pattern_quantifier_opt:
| '*' Op
{
if (strcmp($2, "?") == 0)
- $$ = (Node *) makeRPRQuantifier(0, PG_INT32_MAX, true, @1);
+ $$ = (Node *) makeRPRQuantifier(0, RPR_QUANTITY_INF, true, @1);
else if (strcmp($2, "?|") == 0)
{
/* "A* ?|B" = reluctant "A*?" plus alternation */
- $$ = (Node *) makeRPRQuantifier(0, PG_INT32_MAX, true, @1);
+ $$ = (Node *) makeRPRQuantifier(0, RPR_QUANTITY_INF, true, @1);
((RPRPatternNode *) $$)->trailing_alt = true;
}
else
@@ -17819,11 +17822,11 @@ row_pattern_quantifier_opt:
| '+' Op
{
if (strcmp($2, "?") == 0)
- $$ = (Node *) makeRPRQuantifier(1, PG_INT32_MAX, true, @1);
+ $$ = (Node *) makeRPRQuantifier(1, RPR_QUANTITY_INF, true, @1);
else if (strcmp($2, "?|") == 0)
{
/* "A+ ?|B" = reluctant "A+?" plus alternation */
- $$ = (Node *) makeRPRQuantifier(1, PG_INT32_MAX, true, @1);
+ $$ = (Node *) makeRPRQuantifier(1, RPR_QUANTITY_INF, true, @1);
((RPRPatternNode *) $$)->trailing_alt = true;
}
else
@@ -17859,37 +17862,37 @@ row_pattern_quantifier_opt:
/* {n}, {n,}, {,m}, {n,m} quantifiers */
| '{' Iconst '}'
{
- if ($2 <= 0 || $2 >= PG_INT32_MAX)
+ if ($2 <= 0 || $2 >= RPR_QUANTITY_INF)
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("quantifier bound must be between 1 and %d", PG_INT32_MAX - 1),
+ errmsg("quantifier bound must be between 1 and %d", RPR_QUANTITY_INF - 1),
parser_errposition(@2));
$$ = (Node *) makeRPRQuantifier($2, $2, false, @1);
}
| '{' Iconst ',' '}'
{
- if ($2 < 0 || $2 >= PG_INT32_MAX)
+ if ($2 < 0 || $2 >= RPR_QUANTITY_INF)
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("quantifier bound must be between 0 and %d", PG_INT32_MAX - 1),
+ errmsg("quantifier bound must be between 0 and %d", RPR_QUANTITY_INF - 1),
parser_errposition(@2));
- $$ = (Node *) makeRPRQuantifier($2, PG_INT32_MAX, false, @1);
+ $$ = (Node *) makeRPRQuantifier($2, RPR_QUANTITY_INF, false, @1);
}
| '{' ',' Iconst '}'
{
- if ($3 <= 0 || $3 >= PG_INT32_MAX)
+ if ($3 <= 0 || $3 >= RPR_QUANTITY_INF)
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("quantifier bound must be between 1 and %d", PG_INT32_MAX - 1),
+ errmsg("quantifier bound must be between 1 and %d", RPR_QUANTITY_INF - 1),
parser_errposition(@3));
$$ = (Node *) makeRPRQuantifier(0, $3, false, @1);
}
| '{' Iconst ',' Iconst '}'
{
- if ($2 < 0 || $4 <= 0 || $2 >= PG_INT32_MAX || $4 >= PG_INT32_MAX)
+ if ($2 < 0 || $4 <= 0 || $2 >= RPR_QUANTITY_INF || $4 >= RPR_QUANTITY_INF)
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("quantifier bounds must be between 0 and %d with max >= 1", PG_INT32_MAX - 1),
+ errmsg("quantifier bounds must be between 0 and %d with max >= 1", RPR_QUANTITY_INF - 1),
parser_errposition(@2));
if ($2 > $4)
ereport(ERROR,
@@ -17907,10 +17910,10 @@ row_pattern_quantifier_opt:
errmsg("invalid token \"%s\" after range quantifier", rpr_invalid_quantifier_token($4)),
errhint("Only \"?\" is allowed after {n} to make it reluctant."),
parser_errposition(@4));
- if ($2 <= 0 || $2 >= PG_INT32_MAX)
+ if ($2 <= 0 || $2 >= RPR_QUANTITY_INF)
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("quantifier bound must be between 1 and %d", PG_INT32_MAX - 1),
+ errmsg("quantifier bound must be between 1 and %d", RPR_QUANTITY_INF - 1),
parser_errposition(@2));
$$ = (Node *) makeRPRQuantifier($2, $2, true, @1);
if (strcmp($4, "?|") == 0)
@@ -17924,12 +17927,12 @@ row_pattern_quantifier_opt:
errmsg("invalid token \"%s\" after range quantifier", rpr_invalid_quantifier_token($5)),
errhint("Only \"?\" is allowed after {n,} or {,m} to make it reluctant."),
parser_errposition(@5));
- if ($2 < 0 || $2 >= PG_INT32_MAX)
+ if ($2 < 0 || $2 >= RPR_QUANTITY_INF)
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("quantifier bound must be between 0 and %d", PG_INT32_MAX - 1),
+ errmsg("quantifier bound must be between 0 and %d", RPR_QUANTITY_INF - 1),
parser_errposition(@2));
- $$ = (Node *) makeRPRQuantifier($2, PG_INT32_MAX, true, @1);
+ $$ = (Node *) makeRPRQuantifier($2, RPR_QUANTITY_INF, true, @1);
if (strcmp($5, "?|") == 0)
((RPRPatternNode *) $$)->trailing_alt = true;
}
@@ -17941,10 +17944,10 @@ row_pattern_quantifier_opt:
errmsg("invalid token \"%s\" after range quantifier", rpr_invalid_quantifier_token($5)),
errhint("Only \"?\" is allowed after {n,} or {,m} to make it reluctant."),
parser_errposition(@5));
- if ($3 <= 0 || $3 >= PG_INT32_MAX)
+ if ($3 <= 0 || $3 >= RPR_QUANTITY_INF)
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("quantifier bound must be between 1 and %d", PG_INT32_MAX - 1),
+ errmsg("quantifier bound must be between 1 and %d", RPR_QUANTITY_INF - 1),
parser_errposition(@3));
$$ = (Node *) makeRPRQuantifier(0, $3, true, @1);
if (strcmp($5, "?|") == 0)
@@ -17958,10 +17961,10 @@ row_pattern_quantifier_opt:
errmsg("invalid token \"%s\" after range quantifier", rpr_invalid_quantifier_token($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)
+ if ($2 < 0 || $4 <= 0 || $2 >= RPR_QUANTITY_INF || $4 >= RPR_QUANTITY_INF)
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("quantifier bounds must be between 0 and %d with max >= 1", PG_INT32_MAX - 1),
+ errmsg("quantifier bounds must be between 0 and %d with max >= 1", RPR_QUANTITY_INF - 1),
parser_errposition(@2));
if ($2 > $4)
ereport(ERROR,
@@ -21407,6 +21410,8 @@ makeRPRQuantifier(int32 min, int32 max, bool reluctant, int location)
n->max = max;
n->reluctant = reluctant;
n->location = location;
+
+ /* Other fields are irrelevant for a quantifier node */
return n;
}
@@ -21442,9 +21447,6 @@ makeRPRSeqOrSingle(List *children, int location)
static RPRPatternNode *
splitRPRTrailingAlt(RPRPatternNode *node, core_yyscan_t yyscanner)
{
- ListCell *lc;
- int i = 0;
-
if (node->nodeType != RPR_PATTERN_SEQ)
{
if (node->trailing_alt)
@@ -21458,14 +21460,13 @@ splitRPRTrailingAlt(RPRPatternNode *node, core_yyscan_t yyscanner)
return node;
}
- foreach(lc, node->children)
+ foreach_node(RPRPatternNode, child, node->children)
{
- RPRPatternNode *child = (RPRPatternNode *) lfirst(lc);
-
if (child->trailing_alt)
{
- List *lefthalf = list_copy_head(node->children, i + 1);
- List *righthalf = list_copy_tail(node->children, i + 1);
+ int splitIdx = foreach_current_index(child);
+ List *lefthalf = list_copy_head(node->children, splitIdx + 1);
+ List *righthalf = list_copy_tail(node->children, splitIdx + 1);
RPRPatternNode *altn;
RPRPatternNode *rightnode;
@@ -21490,7 +21491,6 @@ splitRPRTrailingAlt(RPRPatternNode *node, core_yyscan_t yyscanner)
altn->location = node->location;
return altn;
}
- i++;
}
return node;
}
--
2.50.1 (Apple Git-155)