nocfbot-0002-fix-rpr-reluctant-quantifier-flag-lost-during-view-s.txt

text/plain

Filename: nocfbot-0002-fix-rpr-reluctant-quantifier-flag-lost-during-view-s.txt
Type: text/plain
Part: 1
Message: Re: Row pattern recognition
From 2bc7f29dcfceefc83fd787eb138c96247f565360 Mon Sep 17 00:00:00 2001
From: Henson Choi <assam258@gmail.com>
Date: Tue, 3 Mar 2026 15:50:48 +0900
Subject: [PATCH 2/8] Fix RPR reluctant quantifier flag lost during VIEW
 serialization


diff --git a/src/backend/optimizer/plan/rpr.c b/src/backend/optimizer/plan/rpr.c
index 8792d8174fa..009c0f5019d 100644
--- a/src/backend/optimizer/plan/rpr.c
+++ b/src/backend/optimizer/plan/rpr.c
@@ -198,7 +198,7 @@ flattenSeqChildren(List *children)
 
 		/* GROUP{1,1} should have been unwrapped by optimizeGroupPattern */
 		Assert(!(opt->nodeType == RPR_PATTERN_GROUP &&
-				 opt->min == 1 && opt->max == 1 && opt->reluctant < 0));
+				 opt->min == 1 && opt->max == 1 && opt->reluctant == false));
 
 		if (opt->nodeType == RPR_PATTERN_SEQ)
 		{
@@ -234,7 +234,7 @@ mergeConsecutiveVars(List *children)
 	{
 		RPRPatternNode *child = (RPRPatternNode *) lfirst(lc);
 
-		if (child->nodeType == RPR_PATTERN_VAR && child->reluctant < 0)
+		if (child->nodeType == RPR_PATTERN_VAR && child->reluctant == false)
 		{
 			/* ----------------------
 			 * Can merge consecutive VAR nodes if:
@@ -253,7 +253,7 @@ mergeConsecutiveVars(List *children)
 				 * Merge: accumulate min/max into prev. prev is guaranteed to
 				 * be a non-reluctant VAR by the outer condition.
 				 */
-				Assert(prev->nodeType == RPR_PATTERN_VAR && prev->reluctant < 0);
+				Assert(prev->nodeType == RPR_PATTERN_VAR && prev->reluctant == false);
 
 				prev->min += child->min;
 
@@ -308,7 +308,7 @@ mergeConsecutiveGroups(List *children)
 	{
 		RPRPatternNode *child = (RPRPatternNode *) lfirst(lc);
 
-		if (child->nodeType == RPR_PATTERN_GROUP && child->reluctant < 0)
+		if (child->nodeType == RPR_PATTERN_GROUP && child->reluctant == false)
 		{
 			/* ----------------------
 			 * Can merge consecutive GROUP nodes if:
@@ -327,7 +327,7 @@ mergeConsecutiveGroups(List *children)
 				 * Merge: accumulate min/max into prev. prev is guaranteed to
 				 * be a non-reluctant GROUP by the outer condition.
 				 */
-				Assert(prev->nodeType == RPR_PATTERN_GROUP && prev->reluctant < 0);
+				Assert(prev->nodeType == RPR_PATTERN_GROUP && prev->reluctant == false);
 
 				prev->min += child->min;
 
@@ -385,7 +385,7 @@ mergeConsecutiveAlts(List *children)
 	{
 		RPRPatternNode *child = (RPRPatternNode *) lfirst(lc);
 
-		if (child->nodeType == RPR_PATTERN_ALT && child->reluctant < 0)
+		if (child->nodeType == RPR_PATTERN_ALT && child->reluctant == false)
 		{
 			if (prev != NULL &&
 				rprPatternChildrenEqual(prev->children, child->children))
@@ -406,7 +406,8 @@ mergeConsecutiveAlts(List *children)
 						group->nodeType = RPR_PATTERN_GROUP;
 						group->min = count;
 						group->max = count;
-						group->reluctant = -1;
+						group->reluctant = false;
+						group->reluctant_location = -1;
 						group->location = -1;
 						group->children = list_make1(prev);
 						mergedChildren = lappend(mergedChildren, group);
@@ -430,7 +431,8 @@ mergeConsecutiveAlts(List *children)
 					group->nodeType = RPR_PATTERN_GROUP;
 					group->min = count;
 					group->max = count;
-					group->reluctant = -1;
+					group->reluctant = false;
+					group->reluctant_location = -1;
 					group->location = -1;
 					group->children = list_make1(prev);
 					mergedChildren = lappend(mergedChildren, group);
@@ -454,7 +456,8 @@ mergeConsecutiveAlts(List *children)
 			group->nodeType = RPR_PATTERN_GROUP;
 			group->min = count;
 			group->max = count;
-			group->reluctant = -1;
+			group->reluctant = false;
+			group->reluctant_location = -1;
 			group->location = -1;
 			group->children = list_make1(prev);
 			mergedChildren = lappend(mergedChildren, group);
@@ -498,7 +501,7 @@ mergeGroupPrefixSuffix(List *children)
 		 * children. GROUP's content may be wrapped in a SEQ - unwrap for
 		 * comparison.
 		 */
-		if (child->nodeType == RPR_PATTERN_GROUP && child->reluctant < 0)
+		if (child->nodeType == RPR_PATTERN_GROUP && child->reluctant == false)
 		{
 			List	   *groupContent = child->children;
 			int			groupChildCount;
@@ -773,14 +776,14 @@ tryMultiplyQuantifiers(RPRPatternNode *pattern)
 	/* Parser always creates GROUP with exactly one child */
 	Assert(list_length(pattern->children) == 1);
 
-	if (pattern->reluctant >= 0)
+	if (pattern->reluctant)
 		return pattern;
 
 	child = (RPRPatternNode *) linitial(pattern->children);
 
 	if ((child->nodeType != RPR_PATTERN_VAR &&
 		 child->nodeType != RPR_PATTERN_GROUP) ||
-		child->reluctant >= 0)
+		child->reluctant)
 		return pattern;
 
 	/* Case 1: Both unbounded - (A*)* -> A*, (A+)+ -> A+ */
@@ -862,11 +865,12 @@ tryUnwrapGroup(RPRPatternNode *pattern)
 	 * the child and unwrap.  E.g., (A)?? -> A??, (A)+? -> A+?
 	 */
 	if (child->nodeType == RPR_PATTERN_VAR &&
-		child->min == 1 && child->max == 1 && child->reluctant < 0)
+		child->min == 1 && child->max == 1 && child->reluctant == false)
 	{
 		child->min = pattern->min;
 		child->max = pattern->max;
 		child->reluctant = pattern->reluctant;
+		child->reluctant_location = pattern->reluctant_location;
 		return child;
 	}
 
@@ -1150,7 +1154,7 @@ fillRPRPatternVar(RPRPatternNode *node, RPRPattern *pat, int *idx, RPRDepth dept
 	elem->max = (node->max == INT_MAX) ? RPR_QUANTITY_INF : node->max;
 	elem->next = RPR_ELEMIDX_INVALID;
 	elem->jump = RPR_ELEMIDX_INVALID;
-	if (node->reluctant >= 0)
+	if (node->reluctant)
 		elem->flags |= RPR_ELEM_RELUCTANT;
 	(*idx)++;
 
@@ -1189,7 +1193,7 @@ fillRPRPatternGroup(RPRPatternNode *node, RPRPattern *pat, int *idx, RPRDepth de
 		elem->max = (node->max == INT_MAX) ? RPR_QUANTITY_INF : node->max;
 		elem->next = RPR_ELEMIDX_INVALID;	/* set by finalize */
 		elem->jump = RPR_ELEMIDX_INVALID;	/* set after END */
-		if (node->reluctant >= 0)
+		if (node->reluctant)
 			elem->flags |= RPR_ELEM_RELUCTANT;
 		(*idx)++;
 		groupStartIdx = *idx;	/* children start after BEGIN */
@@ -1214,7 +1218,7 @@ fillRPRPatternGroup(RPRPatternNode *node, RPRPattern *pat, int *idx, RPRDepth de
 		endElem->max = (node->max == INT_MAX) ? RPR_QUANTITY_INF : node->max;
 		endElem->next = RPR_ELEMIDX_INVALID;
 		endElem->jump = groupStartIdx;	/* loop to first child */
-		if (node->reluctant >= 0)
+		if (node->reluctant)
 			endElem->flags |= RPR_ELEM_RELUCTANT;
 
 		/*
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index b55a11cc837..f1a71cd036b 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -16967,7 +16967,8 @@ row_pattern_alt:
 						n->children = list_make2($1, $3);
 						n->min = 1;
 						n->max = 1;
-						n->reluctant = -1;
+						n->reluctant = false;
+						n->reluctant_location = -1;
 						n->location = @1;
 						$$ = (Node *) n;
 					}
@@ -16994,7 +16995,8 @@ row_pattern_seq:
 						n->children = list_make2($1, $2);
 						n->min = 1;
 						n->max = 1;
-						n->reluctant = -1;
+						n->reluctant = false;
+						n->reluctant_location = -1;
 						n->location = @1;
 						$$ = (Node *) n;
 					}
@@ -17010,6 +17012,7 @@ row_pattern_term:
 					n->min = q->min;
 					n->max = q->max;
 					n->reluctant = q->reluctant;
+					n->reluctant_location = q->reluctant_location;
 					$$ = (Node *) n;
 				}
 		;
@@ -17022,7 +17025,8 @@ row_pattern_primary:
 					n->varName = $1;
 					n->min = 1;
 					n->max = 1;
-					n->reluctant = -1;
+					n->reluctant = false;
+					n->reluctant_location = -1;
 					n->children = NIL;
 					n->location = @1;
 					$$ = (Node *) n;
@@ -17035,7 +17039,8 @@ row_pattern_primary:
 					n->children = list_make1(inner);
 					n->min = 1;
 					n->max = 1;
-					n->reluctant = -1;
+					n->reluctant = false;
+					n->reluctant_location = -1;
 					n->location = @1;
 					$$ = (Node *) n;
 				}
@@ -20400,14 +20405,15 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query)
  *		Create an RPRPatternNode with specified quantifier bounds.
  */
 static RPRPatternNode *
-makeRPRQuantifier(int min, int max, ParseLoc reluctant, int location,
+makeRPRQuantifier(int min, int max, ParseLoc reluctant_location, int location,
 				  core_yyscan_t yyscanner)
 {
 	RPRPatternNode *n = makeNode(RPRPatternNode);
 
 	n->min = min;
 	n->max = max;
-	n->reluctant = reluctant;
+	n->reluctant = (reluctant_location >= 0);
+	n->reluctant_location = reluctant_location;
 	n->location = location;
 	return n;
 }
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index f5bb81e8c05..928bed2e9fb 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -6778,7 +6778,7 @@ append_pattern_quantifier(StringInfo buf, RPRPatternNode *node)
 	else
 		appendStringInfo(buf, "{%d,%d}", node->min, node->max);
 
-	if (node->reluctant >= 0)
+	if (node->reluctant)
 	{
 		if (!has_quantifier)
 			appendStringInfo(buf, "{1}");	/* make reluctant ? unambiguous */
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 8af527b57d3..22e856c671d 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -608,8 +608,8 @@ typedef struct RPRPatternNode
 	RPRPatternNodeType nodeType;	/* VAR, SEQ, ALT, GROUP */
 	int			min;			/* minimum repetitions (0 for *, ?) */
 	int			max;			/* maximum repetitions (INT_MAX for *, +) */
-	ParseLoc	reluctant;		/* location of '?' for reluctant, -1 for
-								 * greedy */
+	bool		reluctant;		/* true for reluctant (non-greedy) */
+	ParseLoc	reluctant_location; /* location of '?' token, or -1 */
 	ParseLoc	location;		/* token location, or -1 */
 	char	   *varName;		/* VAR: variable name */
 	List	   *children;		/* SEQ, ALT, GROUP: child nodes */
-- 
2.50.1 (Apple Git-155)