v50-0006-tidy-plumbing.patch
application/octet-stream
Filename: v50-0006-tidy-plumbing.patch
Type: application/octet-stream
Part: 14
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-0006
Subject: Tidy up row pattern recognition plumbing
| File | + | − |
|---|---|---|
| src/backend/commands/explain.c | 45 | 49 |
| src/backend/executor/execRPR.c | 1 | 1 |
| src/backend/executor/nodeWindowAgg.c | 20 | 21 |
| src/backend/executor/README.rpr | 1 | 4 |
| src/backend/optimizer/path/allpaths.c | 6 | 7 |
| src/backend/optimizer/path/costsize.c | 5 | 17 |
| src/backend/optimizer/plan/createplan.c | 11 | 13 |
| src/backend/optimizer/plan/rpr.c | 0 | 77 |
| src/include/nodes/execnodes.h | 1 | 1 |
| src/include/nodes/primnodes.h | 2 | 1 |
| src/include/optimizer/rpr.h | 0 | 3 |
| src/test/regress/expected/rpr_integration.out | 9 | 20 |
| src/test/regress/sql/rpr_integration.sql | 9 | 22 |
From f2fd251b2369b56bb174034c7ad510984c8d76a7 Mon Sep 17 00:00:00 2001
From: Henson Choi <assam258@gmail.com>
Date: Wed, 17 Jun 2026 13:12:36 +0900
Subject: [PATCH v50 15/29] 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)