From d51f2f55d4da92fb4f4c6e0880ee49361b48e152 Mon Sep 17 00:00:00 2001 From: Henson Choi 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)