nocfbot-0006-tidy-plumbing.txt

text/plain

Filename: nocfbot-0006-tidy-plumbing.txt
Type: text/plain
Part: 5
Message: Re: Row pattern recognition
From b8484088192a3ea8d24bdbff4b4596450e1383c3 Mon Sep 17 00:00:00 2001
From: Henson Choi <assam258@gmail.com>
Date: Wed, 17 Jun 2026 13:12:36 +0900
Subject: [PATCH 06/13] Tidy up row pattern recognition plumbing

Several behavior-neutral cleanups to the row pattern recognition code,
with no change to planner or executor output:

- Remove the dead collectPatternVariables() and buildDefineVariableList()
  helpers.  The parser already guarantees that every DEFINE variable
  appears in PATTERN, so create_windowagg_plan() and cost_windowagg() walk
  the DEFINE clause directly instead.

- Drop the redundant rpSkipTo and defineClause arguments of
  make_windowagg(); both are read from the WindowClause.

- Mark RPRNavExpr.resulttype as query_jumble_ignore, matching the other
  derived result-type fields.

- Rename WindowAggState.defineClauseList to defineClauseExprs to reflect
  that it stores ExprState nodes.

- Replace a post-loop ListCell NULL test in remove_unused_subquery_outputs()
  with a boolean flag, flatten the nested block in show_window_def(), and
  flatten the DEFINE init loop in ExecInitWindowAgg().

- Minor regression-test comment cleanup.
---
 src/backend/commands/explain.c                | 94 +++++++++----------
 src/backend/executor/README.rpr               |  5 +-
 src/backend/executor/execRPR.c                |  2 +-
 src/backend/executor/nodeWindowAgg.c          | 41 ++++----
 src/backend/optimizer/path/allpaths.c         | 13 ++-
 src/backend/optimizer/path/costsize.c         | 22 +----
 src/backend/optimizer/plan/createplan.c       | 24 +++--
 src/backend/optimizer/plan/rpr.c              | 77 ---------------
 src/include/nodes/execnodes.h                 |  2 +-
 src/include/nodes/primnodes.h                 |  3 +-
 src/include/optimizer/rpr.h                   |  3 -
 src/test/regress/expected/rpr_integration.out | 29 ++----
 src/test/regress/sql/rpr_integration.sql      | 31 ++----
 13 files changed, 110 insertions(+), 236 deletions(-)

diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 70fd7f386a0..696bdb9c8b5 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -3212,77 +3212,73 @@ show_window_def(WindowAggState *planstate, List *ancestors, ExplainState *es)
 	/* Show Row Pattern Recognition pattern if present */
 	if (wagg->rpPattern != NULL)
 	{
+		RPRNavOffsetKind maxKind = wagg->navMaxOffsetKind;
+		int64		maxOffset = wagg->navMaxOffset;
+		RPRNavOffsetKind firstKind = wagg->navFirstOffsetKind;
+		int64		firstOffset = wagg->navFirstOffset;
+
 		char	   *patternStr = deparse_rpr_pattern(wagg->rpPattern);
 
-		if (patternStr != NULL)
-		{
-			ExplainPropertyText("Pattern", patternStr, es);
-			pfree(patternStr);
-		}
+		ExplainPropertyText("Pattern", patternStr, es);
+
+		pfree(patternStr);
 
 		/*
 		 * Show navigation offsets for tuplestore trim.  For EXPLAIN ANALYZE,
 		 * use the executor-resolved values (which may differ from the plan
 		 * when NEEDS_EVAL was resolved to FIXED or RETAIN_ALL at init).
 		 */
+		if (es->analyze)
 		{
-			RPRNavOffsetKind maxKind = wagg->navMaxOffsetKind;
-			int64		maxOffset = wagg->navMaxOffset;
-			RPRNavOffsetKind firstKind = wagg->navFirstOffsetKind;
-			int64		firstOffset = wagg->navFirstOffset;
+			maxKind = planstate->navMaxOffsetKind;
+			maxOffset = planstate->navMaxOffset;
+			firstKind = planstate->navFirstOffsetKind;
+			firstOffset = planstate->navFirstOffset;
+		}
 
-			if (es->analyze)
-			{
-				maxKind = planstate->navMaxOffsetKind;
-				maxOffset = planstate->navMaxOffset;
-				firstKind = planstate->navFirstOffsetKind;
-				firstOffset = planstate->navFirstOffset;
-			}
+		switch (maxKind)
+		{
+			case RPR_NAV_OFFSET_NEEDS_EVAL:
+				ExplainPropertyText("Nav Mark Lookback", "runtime", es);
+				break;
+			case RPR_NAV_OFFSET_RETAIN_ALL:
+				ExplainPropertyText("Nav Mark Lookback", "retain all", es);
+				break;
+			case RPR_NAV_OFFSET_FIXED:
+				ExplainPropertyInteger("Nav Mark Lookback", NULL,
+									   maxOffset, es);
+				break;
+			default:
+				elog(ERROR, "unrecognized RPR nav offset kind: %d",
+					 maxKind);
+				break;
+		}
 
-			switch (maxKind)
+		if (wagg->hasFirstNav)
+		{
+			switch (firstKind)
 			{
 				case RPR_NAV_OFFSET_NEEDS_EVAL:
-					ExplainPropertyText("Nav Mark Lookback", "runtime", es);
+					ExplainPropertyText("Nav Mark Lookahead", "runtime",
+										es);
 					break;
 				case RPR_NAV_OFFSET_RETAIN_ALL:
-					ExplainPropertyText("Nav Mark Lookback", "retain all", es);
+					ExplainPropertyText("Nav Mark Lookahead", "retain all",
+										es);
 					break;
 				case RPR_NAV_OFFSET_FIXED:
-					ExplainPropertyInteger("Nav Mark Lookback", NULL,
-										   maxOffset, es);
+					if (firstOffset == PG_INT64_MAX)
+						ExplainPropertyText("Nav Mark Lookahead", "infinite",
+											es);
+					else
+						ExplainPropertyInteger("Nav Mark Lookahead", NULL,
+											   firstOffset, es);
 					break;
 				default:
 					elog(ERROR, "unrecognized RPR nav offset kind: %d",
-						 maxKind);
+						 firstKind);
 					break;
 			}
-
-			if (wagg->hasFirstNav)
-			{
-				switch (firstKind)
-				{
-					case RPR_NAV_OFFSET_NEEDS_EVAL:
-						ExplainPropertyText("Nav Mark Lookahead", "runtime",
-											es);
-						break;
-					case RPR_NAV_OFFSET_RETAIN_ALL:
-						ExplainPropertyText("Nav Mark Lookahead", "retain all",
-											es);
-						break;
-					case RPR_NAV_OFFSET_FIXED:
-						if (firstOffset == PG_INT64_MAX)
-							ExplainPropertyText("Nav Mark Lookahead", "infinite",
-												es);
-						else
-							ExplainPropertyInteger("Nav Mark Lookahead", NULL,
-												   firstOffset, es);
-						break;
-					default:
-						elog(ERROR, "unrecognized RPR nav offset kind: %d",
-							 firstKind);
-						break;
-				}
-			}
 		}
 	}
 }
diff --git a/src/backend/executor/README.rpr b/src/backend/executor/README.rpr
index 00af86681b8..713ad84e1d9 100644
--- a/src/backend/executor/README.rpr
+++ b/src/backend/executor/README.rpr
@@ -188,7 +188,6 @@ Chapter IV  Compilation Phase
 IV-1. Entry Point
 
   create_windowagg_plan() (createplan.c)
-    +-- buildDefineVariableList()    Build variable name list from DEFINE
     +-- buildRPRPattern()           NFA compilation (6 phases)
 
 IV-2. The 6 Phases of buildRPRPattern()
@@ -1468,8 +1467,6 @@ Appendix A. Key Function Index
   --------------------------------------------------------------------------
   transformRPR                  parse_rpr.c           Parser entry point
   transformDefineClause         parse_rpr.c           DEFINE transformation
-  collectPatternVariables       rpr.c                 Variable collection
-  buildDefineVariableList       rpr.c                 DEFINE variable list
   buildRPRPattern               rpr.c                 NFA compilation main
   optimizeRPRPattern            rpr.c                 AST optimization
   fillRPRPattern                rpr.c                 NFA element generation
@@ -1538,7 +1535,7 @@ Appendix B. Data Structure Relationship Diagram
     |--- rpSkipTo: RPSkipTo (AFTER MATCH SKIP mode)
     |--- rpPattern: RPRPattern* (copied from plan)
     |--- defineVariableList: List<String> (variable names, DEFINE order)
-    |--- defineClauseList: List<ExprState>
+    |--- defineClauseExprs: List<ExprState>
     |--- nfaVarMatched: bool[] (per-row cache)
     |--- defineMatchStartDependent: Bitmapset* (match_start_dependent
     |        DEFINE vars; see VI-4)
diff --git a/src/backend/executor/execRPR.c b/src/backend/executor/execRPR.c
index cea7e0b2973..def0b8423b3 100644
--- a/src/backend/executor/execRPR.c
+++ b/src/backend/executor/execRPR.c
@@ -1606,7 +1606,7 @@ nfa_reevaluate_dependent_vars(WindowAggState *winstate, RPRNFAContext *ctx,
 	/* Invalidate nav_slot cache since match_start changed */
 	winstate->nav_slot_pos = -1;
 
-	foreach_ptr(ExprState, exprState, winstate->defineClauseList)
+	foreach_ptr(ExprState, exprState, winstate->defineClauseExprs)
 	{
 		int			varIdx = foreach_current_index(exprState);
 
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 2d97710da8a..5d4832d1db9 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -3067,27 +3067,26 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
 
 	/* Set up row pattern recognition DEFINE clause */
 	winstate->defineVariableList = NIL;
-	winstate->defineClauseList = NIL;
-	if (node->defineClause != NIL)
+	winstate->defineClauseExprs = NIL;
+
+	/*
+	 * Compile DEFINE clause expressions.  PREV/NEXT navigation is handled by
+	 * EEOP_RPR_NAV_SET/RESTORE opcodes emitted during ExecInitExpr, so no
+	 * varno rewriting is needed here.
+	 */
+	foreach_node(TargetEntry, te, node->defineClause)
 	{
-		/*
-		 * Compile DEFINE clause expressions.  PREV/NEXT navigation is handled
-		 * by EEOP_RPR_NAV_SET/RESTORE opcodes emitted during ExecInitExpr, so
-		 * no varno rewriting is needed here.
-		 */
-		foreach_node(TargetEntry, te, node->defineClause)
-		{
-			char	   *name = te->resname;
-			Expr	   *expr = te->expr;
-			ExprState  *exps;
-
-			winstate->defineVariableList =
-				lappend(winstate->defineVariableList,
-						makeString(pstrdup(name)));
-			exps = ExecInitExpr(expr, (PlanState *) winstate);
-			winstate->defineClauseList =
-				lappend(winstate->defineClauseList, exps);
-		}
+		char	   *name = te->resname;
+		ExprState  *exprstate;
+
+		winstate->defineVariableList =
+			lappend(winstate->defineVariableList,
+					makeString(pstrdup(name)));
+
+		exprstate = ExecInitExpr(te->expr, (PlanState *) winstate);
+
+		winstate->defineClauseExprs =
+			lappend(winstate->defineClauseExprs, exprstate);
 	}
 
 	/* Initialize NFA free lists for row pattern matching */
@@ -4669,7 +4668,7 @@ nfa_evaluate_row(WindowObject winobj, int64 pos, bool *varMatched)
 	/* Invalidate nav_slot cache so PREV/NEXT re-fetch for new row */
 	winstate->nav_slot_pos = -1;
 
-	foreach_ptr(ExprState, exprState, winstate->defineClauseList)
+	foreach_ptr(ExprState, exprState, winstate->defineClauseExprs)
 	{
 		Datum		result;
 		bool		isnull;
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index f3c9f3c0bd6..44864b3635b 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -4807,20 +4807,19 @@ remove_unused_subquery_outputs(Query *subquery, RelOptInfo *rel,
 		 */
 		if (IsA(texpr, WindowFunc))
 		{
+			bool		is_rpr = false;
 			WindowFunc *wfunc = (WindowFunc *) texpr;
-			ListCell   *wlc;
 
-			foreach(wlc, subquery->windowClause)
+			foreach_node(WindowClause, wc, subquery->windowClause)
 			{
-				WindowClause *wc = lfirst_node(WindowClause, wlc);
-
-				if (wc->winref == wfunc->winref &&
-					wc->defineClause != NIL)
+				if (wc->winref == wfunc->winref && wc->defineClause != NIL)
 				{
+					is_rpr = true;
 					break;
 				}
 			}
-			if (wlc != NULL)
+
+			if (is_rpr)
 				continue;
 		}
 
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 82472c3fe96..32a4b172e3d 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -3231,30 +3231,18 @@ cost_windowagg(Path *path, PlannerInfo *root,
 	 * so we'll just do this for now.
 	 *
 	 * Moreover, if row pattern recognition is used, we charge the DEFINE
-	 * expressions once per tuple for each variable that appears in PATTERN.
+	 * expressions once per tuple for each DEFINE variable.
 	 */
 	if (winclause->rpPattern)
 	{
-		List	   *pattern_vars;
 		QualCost	defcosts;
 
-		pattern_vars = collectPatternVariables(winclause->rpPattern);
-
-		foreach_node(String, pv, pattern_vars)
+		foreach_node(TargetEntry, def, winclause->defineClause)
 		{
-			char	   *ptname = strVal(pv);
-
-			foreach_node(TargetEntry, def, winclause->defineClause)
-			{
-				if (!strcmp(ptname, def->resname))
-				{
-					cost_qual_eval_node(&defcosts, (Node *) def->expr, root);
-					startup_cost += defcosts.startup;
-					total_cost += defcosts.per_tuple * input_tuples;
-				}
-			}
+			cost_qual_eval_node(&defcosts, (Node *) def->expr, root);
+			startup_cost += defcosts.startup;
+			total_cost += defcosts.per_tuple * input_tuples;
 		}
-		list_free_deep(pattern_vars);
 	}
 
 	foreach(lc, windowFuncs)
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index cca4126e511..d96e76b0221 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -290,9 +290,8 @@ static Memoize *make_memoize(Plan *lefttree, Oid *hashoperators,
 static WindowAgg *make_windowagg(List *tlist, WindowClause *wc,
 								 int partNumCols, AttrNumber *partColIdx, Oid *partOperators, Oid *partCollations,
 								 int ordNumCols, AttrNumber *ordColIdx, Oid *ordOperators, Oid *ordCollations,
-								 List *runCondition, RPSkipTo rpSkipTo,
+								 List *runCondition,
 								 RPRPattern *compiledPattern,
-								 List *defineClause,
 								 Bitmapset *defineMatchStartDependent,
 								 RPRNavOffsetKind navMaxOffsetKind, int64 navMaxOffset,
 								 bool hasFirstNav,
@@ -2822,7 +2821,6 @@ create_windowagg_plan(PlannerInfo *root, WindowAggPath *best_path)
 	Oid		   *ordCollations;
 	ListCell   *lc;
 	List	   *defineVariableList = NIL;
-	List	   *filteredDefineClause = NIL;
 	RPRPattern *compiledPattern = NULL;
 	Bitmapset  *matchStartDependent = NULL;
 	RPRNavOffsetKind navMaxOffsetKind = RPR_NAV_OFFSET_FIXED;
@@ -2889,8 +2887,9 @@ create_windowagg_plan(PlannerInfo *root, WindowAggPath *best_path)
 		 * rejects DEFINE variables not used in PATTERN, so no filtering is
 		 * needed.
 		 */
-		buildDefineVariableList(wc->defineClause, &defineVariableList);
-		filteredDefineClause = wc->defineClause;
+		foreach_node(TargetEntry, te, wc->defineClause)
+			defineVariableList = lappend(defineVariableList,
+										 makeString(pstrdup(te->resname)));
 
 		/*
 		 * Walk DEFINE once: collect nav offsets (for tuplestore trim) and the
@@ -2923,13 +2922,13 @@ create_windowagg_plan(PlannerInfo *root, WindowAggPath *best_path)
 						  ordOperators,
 						  ordCollations,
 						  best_path->runCondition,
-						  wc->rpSkipTo,
 						  compiledPattern,
-						  filteredDefineClause,
 						  matchStartDependent,
-						  navMaxOffsetKind, navMaxOffset,
+						  navMaxOffsetKind,
+						  navMaxOffset,
 						  hasFirstNav,
-						  navFirstOffsetKind, navFirstOffset,
+						  navFirstOffsetKind,
+						  navFirstOffset,
 						  best_path->qual,
 						  best_path->topwindow,
 						  subplan);
@@ -7000,9 +6999,8 @@ static WindowAgg *
 make_windowagg(List *tlist, WindowClause *wc,
 			   int partNumCols, AttrNumber *partColIdx, Oid *partOperators, Oid *partCollations,
 			   int ordNumCols, AttrNumber *ordColIdx, Oid *ordOperators, Oid *ordCollations,
-			   List *runCondition, RPSkipTo rpSkipTo,
+			   List *runCondition,
 			   RPRPattern *compiledPattern,
-			   List *defineClause,
 			   Bitmapset *defineMatchStartDependent,
 			   RPRNavOffsetKind navMaxOffsetKind, int64 navMaxOffset,
 			   bool hasFirstNav,
@@ -7034,12 +7032,12 @@ make_windowagg(List *tlist, WindowClause *wc,
 	node->inRangeAsc = wc->inRangeAsc;
 	node->inRangeNullsFirst = wc->inRangeNullsFirst;
 	node->topWindow = topWindow;
-	node->rpSkipTo = rpSkipTo;
+	node->rpSkipTo = wc->rpSkipTo;
 
 	/* Store compiled pattern for NFA execution */
 	node->rpPattern = compiledPattern;
 
-	node->defineClause = defineClause;
+	node->defineClause = wc->defineClause;
 
 	/* Store pre-computed match_start dependency bitmapset */
 	node->defineMatchStartDependent = defineMatchStartDependent;
diff --git a/src/backend/optimizer/plan/rpr.c b/src/backend/optimizer/plan/rpr.c
index 50bca59451f..48b76a842ed 100644
--- a/src/backend/optimizer/plan/rpr.c
+++ b/src/backend/optimizer/plan/rpr.c
@@ -96,9 +96,6 @@ static void computeAbsorbabilityRecursive(RPRPattern *pattern,
 										  bool *hasAbsorbable);
 static void computeAbsorbability(RPRPattern *pattern);
 
-static void collectPatternVariablesRecursive(RPRPatternNode *node,
-											 List **varNames);
-
 /*
  * rprPatternEqual
  *		Compare two RPRPatternNode trees for equality.
@@ -1824,59 +1821,6 @@ computeAbsorbability(RPRPattern *pattern)
 	pattern->isAbsorbable = hasAbsorbable;
 }
 
-/*
- * collectPatternVariablesRecursive
- *		Recursively collect variable names from pattern AST.
- */
-static void
-collectPatternVariablesRecursive(RPRPatternNode *node, List **varNames)
-{
-	Assert(node != NULL);
-
-	check_stack_depth();
-
-	switch (node->nodeType)
-	{
-		case RPR_PATTERN_VAR:
-			/* Add variable if not already in list */
-			foreach_node(String, varname, *varNames)
-			{
-				if (strcmp(strVal(varname), node->varName) == 0)
-					return;		/* Already collected */
-			}
-			*varNames = lappend(*varNames, makeString(pstrdup(node->varName)));
-			break;
-
-		case RPR_PATTERN_SEQ:
-		case RPR_PATTERN_ALT:
-		case RPR_PATTERN_GROUP:
-			foreach_node(RPRPatternNode, child, node->children)
-			{
-				collectPatternVariablesRecursive(child, varNames);
-			}
-			break;
-	}
-}
-
-/*
- * collectPatternVariables
- *		Collect unique variable names used in PATTERN clause.
- *
- * Returns a list of String nodes containing variable names.
- * Used to filter defineClause before varId assignment.
- */
-List *
-collectPatternVariables(RPRPatternNode *pattern)
-{
-	List	   *varNames = NIL;
-
-	/* Caller ensures pattern is not NULL */
-	Assert(pattern != NULL);
-
-	collectPatternVariablesRecursive(pattern, &varNames);
-	return varNames;
-}
-
 /*
  * rpr_volatile_func_checker
  *		check_functions_in_node callback: true if funcid is VOLATILE.
@@ -1953,27 +1897,6 @@ validate_rpr_define_volatility(List *defineClause)
 	}
 }
 
-/*
- * buildDefineVariableList
- *		Build defineVariableList from defineClause.
- *
- * The parser already ensures that all DEFINE variables appear in PATTERN,
- * so no filtering is needed here.
- *
- * Sets *defineVariableList to list of variable names (String nodes).
- */
-void
-buildDefineVariableList(List *defineClause, List **defineVariableList)
-{
-	*defineVariableList = NIL;
-
-	foreach_node(TargetEntry, te, defineClause)
-	{
-		*defineVariableList = lappend(*defineVariableList,
-									  makeString(pstrdup(te->resname)));
-	}
-}
-
 /*
  * buildRPRPattern
  *		Compile pattern AST to flat bytecode array.
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 5b4ac8a6c33..59b8656c857 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -2654,7 +2654,7 @@ typedef struct WindowAggState
 	struct RPRPattern *rpPattern;	/* compiled pattern for NFA execution */
 	List	   *defineVariableList; /* list of row pattern definition
 									 * variables (list of String) */
-	List	   *defineClauseList;	/* expression for row pattern definition
+	List	   *defineClauseExprs;	/* expression for row pattern definition
 									 * search conditions ExprState list */
 	RPRNFAContext *nfaContext;	/* active matching contexts (head) */
 	RPRNFAContext *nfaContextTail;	/* tail of active contexts (for reverse
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 7c1b3d1bb07..8576a3c9c5b 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -687,7 +687,8 @@ typedef struct RPRNavExpr
 	Expr	   *offset_arg;		/* offset expression, or NULL for default */
 	Expr	   *compound_offset_arg;	/* outer offset for compound nav, or
 										 * NULL if simple */
-	Oid			resulttype;		/* result type (same as arg's type) */
+	/* result type (same as arg's type) */
+	Oid			resulttype pg_node_attr(query_jumble_ignore);
 	/* OID of collation of result */
 	Oid			resultcollid pg_node_attr(query_jumble_ignore);
 	/* token location, or -1 if unknown */
diff --git a/src/include/optimizer/rpr.h b/src/include/optimizer/rpr.h
index b4f87d8caa4..23763442b65 100644
--- a/src/include/optimizer/rpr.h
+++ b/src/include/optimizer/rpr.h
@@ -67,10 +67,7 @@
 #define RPRElemIsFin(e)			((e)->varId == RPR_VARID_FIN)
 #define RPRElemCanSkip(e)		((e)->min == 0)
 
-extern List *collectPatternVariables(RPRPatternNode *pattern);
 extern void validate_rpr_define_volatility(List *defineClause);
-extern void buildDefineVariableList(List *defineClause,
-									List **defineVariableList);
 extern RPRPattern *buildRPRPattern(RPRPatternNode *pattern, List *defineVariableList,
 								   RPSkipTo rpSkipTo, int frameOptions,
 								   bool hasMatchStartDependent);
diff --git a/src/test/regress/expected/rpr_integration.out b/src/test/regress/expected/rpr_integration.out
index 80a32cca9ab..652989927d7 100644
--- a/src/test/regress/expected/rpr_integration.out
+++ b/src/test/regress/expected/rpr_integration.out
@@ -240,9 +240,9 @@ ORDER BY id;
 -- must therefore yield two separate WindowAgg nodes.  Inline specs
 -- are used here because dedup only applies to inline windows.
 -- Baseline: two inline RPR windows that are structurally identical
--- (same ORDER BY, frame, PATTERN, and DEFINE) are deduped by the
--- parser into a single WindowAgg node, confirming that parser-level
--- dedup is active for RPR windows whose DEFINE matches.
+-- (same PARTITION BY, ORDER BY, frame, PATTERN, and DEFINE) are deduped by the
+-- parser into a single WindowAgg node, confirming that parser-level dedup is
+-- active for RPR windows whose DEFINE matches.
 EXPLAIN (COSTS OFF)
 SELECT
     count(*) OVER (ORDER BY id
@@ -325,15 +325,10 @@ ORDER BY id;
 -- A5. Unused window removal prevention
 -- ============================================================
 -- Verify that remove_unused_subquery_outputs() does not drop an RPR
--- window function even when the outer query does not reference its
--- result.  The RPR WindowAgg node is responsible for performing pattern
--- matching, so removing the window function would silently skip the
--- pattern match even though the surrounding query still depends on
--- RPR semantics.
--- The outer query ignores the per-row window result, yet pattern
--- matching must still execute.  The plan must still contain a
--- WindowAgg node below the outer Aggregate; if the window were
--- removed, only Aggregate + Seq Scan would appear.
+-- window function when the outer query does not reference its result.
+-- The WindowAgg node performs the pattern match itself; without it,
+-- the match would be silently skipped.  The plan must contain a
+-- WindowAgg node beneath the outer Aggregate.
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM (
     SELECT count(*) OVER w FROM rpr_integ
@@ -587,10 +582,8 @@ WHERE cnt > 0;
 -- EXPLAIN VERBOSE is therefore expected to show a clean targetlist on
 -- the outer WindowAgg, with no DEFINE-derived expression leaking in.
 -- Note: columns referenced by DEFINE (e.g., "val") may appear as
--- resjunk entries in upper WindowAgg targetlists -- that is a
--- harmless byproduct of the column guard's broad scope and does not
--- affect client output.  The claim here is limited to the full
--- DEFINE boolean expression.
+-- resjunk entries in upper WindowAgg targetlists -- but that is harmless.
+-- The claim here is limited to the full DEFINE boolean expression.
 EXPLAIN (VERBOSE, COSTS OFF)
 SELECT
     count(*) OVER w_rpr AS rpr_cnt,
@@ -620,10 +613,6 @@ WINDOW
                      Output: id, val
 (13 rows)
 
--- Executing the same query shows the client result is limited to
--- the two projected columns; "id" and "val" that appeared in the
--- upper WindowAgg Output line are resjunk-only and do not reach
--- the client.
 SELECT
     count(*) OVER w_rpr AS rpr_cnt,
     count(*) OVER w_normal AS normal_cnt
diff --git a/src/test/regress/sql/rpr_integration.sql b/src/test/regress/sql/rpr_integration.sql
index 1d6075265bb..2b990b24704 100644
--- a/src/test/regress/sql/rpr_integration.sql
+++ b/src/test/regress/sql/rpr_integration.sql
@@ -166,9 +166,9 @@ ORDER BY id;
 -- are used here because dedup only applies to inline windows.
 
 -- Baseline: two inline RPR windows that are structurally identical
--- (same ORDER BY, frame, PATTERN, and DEFINE) are deduped by the
--- parser into a single WindowAgg node, confirming that parser-level
--- dedup is active for RPR windows whose DEFINE matches.
+-- (same PARTITION BY, ORDER BY, frame, PATTERN, and DEFINE) are deduped by the
+-- parser into a single WindowAgg node, confirming that parser-level dedup is
+-- active for RPR windows whose DEFINE matches.
 EXPLAIN (COSTS OFF)
 SELECT
     count(*) OVER (ORDER BY id
@@ -214,16 +214,10 @@ ORDER BY id;
 -- A5. Unused window removal prevention
 -- ============================================================
 -- Verify that remove_unused_subquery_outputs() does not drop an RPR
--- window function even when the outer query does not reference its
--- result.  The RPR WindowAgg node is responsible for performing pattern
--- matching, so removing the window function would silently skip the
--- pattern match even though the surrounding query still depends on
--- RPR semantics.
-
--- The outer query ignores the per-row window result, yet pattern
--- matching must still execute.  The plan must still contain a
--- WindowAgg node below the outer Aggregate; if the window were
--- removed, only Aggregate + Seq Scan would appear.
+-- window function when the outer query does not reference its result.
+-- The WindowAgg node performs the pattern match itself; without it,
+-- the match would be silently skipped.  The plan must contain a
+-- WindowAgg node beneath the outer Aggregate.
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM (
     SELECT count(*) OVER w FROM rpr_integ
@@ -399,11 +393,8 @@ WHERE cnt > 0;
 -- EXPLAIN VERBOSE is therefore expected to show a clean targetlist on
 -- the outer WindowAgg, with no DEFINE-derived expression leaking in.
 -- Note: columns referenced by DEFINE (e.g., "val") may appear as
--- resjunk entries in upper WindowAgg targetlists -- that is a
--- harmless byproduct of the column guard's broad scope and does not
--- affect client output.  The claim here is limited to the full
--- DEFINE boolean expression.
-
+-- resjunk entries in upper WindowAgg targetlists -- but that is harmless.
+-- The claim here is limited to the full DEFINE boolean expression.
 EXPLAIN (VERBOSE, COSTS OFF)
 SELECT
     count(*) OVER w_rpr AS rpr_cnt,
@@ -417,10 +408,6 @@ WINDOW
     w_normal AS (ORDER BY id
         ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING);
 
--- Executing the same query shows the client result is limited to
--- the two projected columns; "id" and "val" that appeared in the
--- upper WindowAgg Output line are resjunk-only and do not reach
--- the client.
 SELECT
     count(*) OVER w_rpr AS rpr_cnt,
     count(*) OVER w_normal AS normal_cnt
-- 
2.50.1 (Apple Git-155)