From e67ec2fff608820d6818d34ba3e094286f6b69fb Mon Sep 17 00:00:00 2001 From: jian he Date: Mon, 15 Jun 2026 14:00:12 +0800 Subject: [PATCH v48 1/1] v48 misc refactoring RPRNavExpr->resulttype should also marked as pg_node_attr(query_jumble_ignore) collectPatternVariables is not needed. The parser already ensures every DEFINE variable appears in PATTERN, so there is nothing to filter. Also, we don't really do anything special (like make a dummy Const) regarding PATTERN variables that not appearing in the DEFINE clause. See nfa_evaluate_row the for loop break. buildDefineVariableList is trivial. No need to export it as an external function. Rename WindowAggState.defineClauseList to defineClauseExprs Minor refactoring of regress test comments. Flatten a needlessly nested block in show_window_def(). Replace a post-loop ListCell NULL check in remove_unused_subquery_outputs() with a boolean flag. --- src/backend/commands/explain.c | 94 +++++++++---------- src/backend/executor/README.rpr | 5 +- src/backend/executor/execRPR.c | 2 +- src/backend/executor/nodeWindowAgg.c | 39 ++++---- src/backend/optimizer/path/allpaths.c | 13 ++- src/backend/optimizer/path/costsize.c | 20 +--- src/backend/optimizer/plan/createplan.c | 24 +++-- src/backend/optimizer/plan/rpr.c | 77 --------------- src/include/nodes/execnodes.h | 2 +- src/include/nodes/parsenodes.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 ++---- src/tools/pgindent/typedefs.list | 24 +++++ 15 files changed, 133 insertions(+), 235 deletions(-) diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 70fd7f386a..696bdb9c8b 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 00af86681b..713ad84e1d 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 (variable names, DEFINE order) - |--- defineClauseList: List + |--- defineClauseExprs: List |--- 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 b326a58bbf..122a09e66d 100644 --- a/src/backend/executor/execRPR.c +++ b/src/backend/executor/execRPR.c @@ -1603,7 +1603,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 cb6a484b7d..25d1ad2143 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -3076,27 +3076,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; + char *name = te->resname; + ExprState *exprs; - winstate->defineVariableList = - lappend(winstate->defineVariableList, - makeString(pstrdup(name))); - exps = ExecInitExpr(expr, (PlanState *) winstate); - winstate->defineClauseList = - lappend(winstate->defineClauseList, exps); - } + winstate->defineVariableList = + lappend(winstate->defineVariableList, + makeString(pstrdup(name))); + + exprs = ExecInitExpr(te->expr, (PlanState *) winstate); + + winstate->defineClauseExprs = + lappend(winstate->defineClauseExprs, exprs); } /* Initialize NFA free lists for row pattern matching */ @@ -4598,7 +4597,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 f3c9f3c0bd..b289e46a95 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 82472c3fe9..02b25f6f08 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -3235,26 +3235,14 @@ cost_windowagg(Path *path, PlannerInfo *root, */ 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 cca4126e51..8bf2e89906 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 175777a8ff..fb5260c786 100644 --- a/src/backend/optimizer/plan/rpr.c +++ b/src/backend/optimizer/plan/rpr.c @@ -98,9 +98,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. @@ -1826,59 +1823,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. @@ -1955,27 +1899,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 792aa3f0d0..d5dff86dd2 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -2657,7 +2657,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/parsenodes.h b/src/include/nodes/parsenodes.h index 3266c11a71..72da32ae28 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -619,7 +619,7 @@ typedef enum RPRPatternNodeType } RPRPatternNodeType; /* - * RPRPatternNode - Row Pattern Recognition pattern AST node + * RPRPatternNode - Row Pattern Recognition pattern clause */ typedef struct RPRPatternNode { diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index d7138f5141..84caf0733e 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -695,7 +695,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 802d2f1dd6..31866245f7 100644 --- a/src/include/optimizer/rpr.h +++ b/src/include/optimizer/rpr.h @@ -66,10 +66,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 80a32cca9a..ef537396b7 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 a 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 1d6075265b..62634d0f01 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 a 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 diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index f9eb23e52c..b500ae5677 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -533,6 +533,7 @@ Constraint ConstraintCategory ConstraintInfo ConstraintsSetStmt +ContainRPRContext ControlData ControlFileData ConvInfo @@ -663,7 +664,10 @@ DecodingWorkerShared DefElem DefElemAction DefaultACLInfo +DefineMetadataContext +DefinePhase DefineStmt +DefineWalkCtx DefnDumperPtr DeleteStmt DependenciesParseState @@ -762,6 +766,7 @@ ErrorData ErrorSaveContext EstimateDSMForeignScan_function EstimationInfo +EvalDefineOffsetsContext EventTriggerCacheEntry EventTriggerCacheItem EventTriggerCacheStateType @@ -1832,6 +1837,8 @@ NamedLWLockTrancheRequest NamedTuplestoreScan NamedTuplestoreScanState NamespaceInfo +NavTraversal +NavVisitFn NestLoop NestLoopParam NestLoopState @@ -1841,6 +1848,7 @@ NewConstraint NextSampleBlock_function NextSampleTuple_function NextValueExpr +NFALengthStats Node NodeInstrumentation NodeTag @@ -2524,6 +2532,22 @@ RI_ConstraintInfo RI_FastPathEntry RI_QueryHashEntry RI_QueryKey +RPCommonSyntax +RPRDepth +RPRElemFlags +RPRElemIdx +RPRNFAContext +RPRNFAState +RPRNavExpr +RPRNavKind +RPRNavOffsetKind +RPRPattern +RPRPatternElement +RPRPatternNode +RPRPatternNodeType +RPRQuantity +RPRVarId +RPSkipTo RTEKind RTEPermissionInfo RWConflict -- 2.34.1