v50-0015-pass-windowclause.patch
application/octet-stream
Filename: v50-0015-pass-windowclause.patch
Type: application/octet-stream
Part: 23
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-0015
Subject: Simplify row pattern compilation by passing the WindowClause
| File | + | − |
|---|---|---|
| src/backend/optimizer/plan/createplan.c | 2 | 16 |
| src/backend/optimizer/plan/rpr.c | 33 | 59 |
| src/include/optimizer/rpr.h | 1 | 3 |
| src/include/parser/parse_node.h | 1 | 1 |
From d598f7bc61e2fc828ff5a92cf16fc000284bf492 Mon Sep 17 00:00:00 2001
From: Henson Choi <assam258@gmail.com>
Date: Mon, 22 Jun 2026 23:28:53 +0900
Subject: [PATCH v50 24/29] Simplify row pattern compilation by passing the
WindowClause
buildRPRPattern() took rpPattern, rpSkipTo, frameOptions, and a
pre-built defineVariableList as separate arguments. Pass the
WindowClause directly instead: it carries all of these, and
buildRPRPattern can walk wc->defineClause itself to collect the DEFINE
variable names. This removes the intermediate List that
create_windowagg_plan built only to hand off, along with the
collectDefineVariables() helper that unpacked it.
Also inline tryUnwrapSingleChild() into its two callers
(optimizeSeqPattern and optimizeAltPattern); it was a trivial one-liner.
Based on a patch by Jian He.
---
src/backend/optimizer/plan/createplan.c | 18 +----
src/backend/optimizer/plan/rpr.c | 92 +++++++++----------------
src/include/optimizer/rpr.h | 4 +-
src/include/parser/parse_node.h | 2 +-
4 files changed, 37 insertions(+), 79 deletions(-)
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index d96e76b0221..d860fb9711e 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -2820,7 +2820,6 @@ create_windowagg_plan(PlannerInfo *root, WindowAggPath *best_path)
Oid *ordOperators;
Oid *ordCollations;
ListCell *lc;
- List *defineVariableList = NIL;
RPRPattern *compiledPattern = NULL;
Bitmapset *matchStartDependent = NULL;
RPRNavOffsetKind navMaxOffsetKind = RPR_NAV_OFFSET_FIXED;
@@ -2879,18 +2878,9 @@ create_windowagg_plan(PlannerInfo *root, WindowAggPath *best_path)
ordNumCols++;
}
- /* Build RPR pattern and defineVariableList */
+ /* Build RPR pattern */
if (wc->rpPattern)
{
- /*
- * Build defineVariableList from defineClause. The parser already
- * rejects DEFINE variables not used in PATTERN, so no filtering is
- * needed.
- */
- foreach_node(TargetEntry, te, wc->defineClause)
- defineVariableList = lappend(defineVariableList,
- makeString(pstrdup(te->resname)));
-
/*
* Walk DEFINE once: collect nav offsets (for tuplestore trim) and the
* bitmapset of match_start-dependent variables (for absorption
@@ -2903,11 +2893,7 @@ create_windowagg_plan(PlannerInfo *root, WindowAggPath *best_path)
&matchStartDependent);
/* Compile and optimize RPR patterns */
- compiledPattern = buildRPRPattern(wc->rpPattern,
- defineVariableList,
- wc->rpSkipTo,
- wc->frameOptions,
- !bms_is_empty(matchStartDependent));
+ compiledPattern = buildRPRPattern(wc, !bms_is_empty(matchStartDependent));
}
/* And finally we can make the WindowAgg node */
diff --git a/src/backend/optimizer/plan/rpr.c b/src/backend/optimizer/plan/rpr.c
index 3d7752bd5ed..1c59e8a70a0 100644
--- a/src/backend/optimizer/plan/rpr.c
+++ b/src/backend/optimizer/plan/rpr.c
@@ -48,9 +48,6 @@
/* Forward declarations */
static bool rprPatternEqual(RPRPatternNode *a, RPRPatternNode *b);
static bool rprPatternChildrenEqual(List *a, List *b);
-
-static RPRPatternNode *tryUnwrapSingleChild(RPRPatternNode *pattern);
-
static List *flattenSeqChildren(List *children);
static List *mergeConsecutiveVars(List *children);
static List *mergeConsecutiveGroups(List *children);
@@ -67,8 +64,6 @@ static RPRPatternNode *tryUnwrapGroup(RPRPatternNode *pattern);
static RPRPatternNode *optimizeGroupPattern(RPRPatternNode *pattern);
static RPRPatternNode *optimizeRPRPattern(RPRPatternNode *pattern);
-
-static int collectDefineVariables(List *defineVariableList, char **varNames);
static void scanRPRPatternRecursive(RPRPatternNode *node, char **varNames,
int *numVars, int *numElements,
RPRDepth depth, RPRDepth *maxDepth);
@@ -155,27 +150,6 @@ rprPatternChildrenEqual(List *a, List *b)
return true;
}
-/*
- * tryUnwrapSingleChild
- * Try to unwrap pattern node with single child.
- *
- * Examples (internal node representation):
- * SEQ[A] -> A (single-element sequence becomes the element)
- * ALT[A] -> A (single-alternative becomes the alternative)
- *
- * If pattern has exactly one child, return the child directly.
- * Otherwise returns the pattern unchanged.
- * Used by both SEQ and ALT optimization.
- */
-static RPRPatternNode *
-tryUnwrapSingleChild(RPRPatternNode *pattern)
-{
- if (list_length(pattern->children) == 1)
- return (RPRPatternNode *) linitial(pattern->children);
-
- return pattern;
-}
-
/*
* flattenSeqChildren
* Recursively optimize children and flatten nested SEQ.
@@ -669,8 +643,11 @@ optimizeSeqPattern(RPRPatternNode *pattern)
/* Merge prefix/suffix into GROUP with matching children */
pattern->children = mergeGroupPrefixSuffix(pattern->children);
- /* Unwrap single-item SEQ */
- return tryUnwrapSingleChild(pattern);
+ /* Unwrap single-item SEQ: SEQ[A] -> A */
+ if (list_length(pattern->children) == 1)
+ return (RPRPatternNode *) linitial(pattern->children);
+
+ return pattern;
}
/*
@@ -754,8 +731,11 @@ optimizeAltPattern(RPRPatternNode *pattern)
/* Remove duplicate alternatives */
pattern->children = removeDuplicateAlternatives(pattern->children);
- /* Unwrap single-item ALT */
- return tryUnwrapSingleChild(pattern);
+ /* Unwrap single-item ALT: ALT[A] -> A */
+ if (list_length(pattern->children) == 1)
+ return (RPRPatternNode *) linitial(pattern->children);
+
+ return pattern;
}
/*
@@ -969,30 +949,6 @@ optimizeRPRPattern(RPRPatternNode *pattern)
return pattern;
}
-/*
- * collectDefineVariables
- * Collect variable names from DEFINE clause.
- *
- * Populates varNames array with variable names in DEFINE order.
- * This ensures varId == defineIdx, eliminating runtime mapping.
- * Returns the number of variables collected.
- */
-static int
-collectDefineVariables(List *defineVariableList, char **varNames)
-{
- int numVars = 0;
-
- foreach_node(String, varname, defineVariableList)
- {
- /* Parser already checked this limit in transformDefineClause */
- Assert(numVars <= RPR_VARID_MAX);
-
- varNames[numVars++] = strVal(varname);
- }
-
- return numVars;
-}
-
/*
* scanRPRPatternRecursive
* Recursively scan pattern parse tree (pass 1 internal).
@@ -1904,9 +1860,7 @@ validate_rpr_define_volatility(List *defineClause)
* Called from createplan.c during plan creation.
*/
RPRPattern *
-buildRPRPattern(RPRPatternNode *pattern, List *defineVariableList,
- RPSkipTo rpSkipTo, int frameOptions,
- bool hasMatchStartDependent)
+buildRPRPattern(WindowClause *wc, bool hasMatchStartDependent)
{
RPRPattern *result;
RPRPatternNode *optimized;
@@ -1915,6 +1869,9 @@ buildRPRPattern(RPRPatternNode *pattern, List *defineVariableList,
int numElements;
RPRDepth maxDepth;
int idx;
+ RPRPatternNode *pattern = wc->rpPattern;
+ RPSkipTo rpSkipTo = wc->rpSkipTo;
+ int frameOptions = wc->frameOptions;
/* Caller must check for NULL pattern before calling */
Assert(pattern != NULL);
@@ -1924,12 +1881,29 @@ buildRPRPattern(RPRPatternNode *pattern, List *defineVariableList,
/* Optimize the pattern tree */
optimized = optimizeRPRPattern(copyObject(pattern));
- /* Collect variable names from DEFINE clause */
- numVars = collectDefineVariables(defineVariableList, varNamesStack);
+ numVars = 0;
+
+ /*
+ * Populate varNamesStack with the DEFINE variable names in DEFINE order.
+ * This ensures varId == defineClause index, eliminating runtime mapping.
+ */
+ foreach_node(TargetEntry, te, wc->defineClause)
+ {
+ /* Parser always assigns a name to each DEFINE entry */
+ Assert(te->resname != NULL);
+
+ varNamesStack[numVars++] = pstrdup(te->resname);
+ }
/* Scan pattern: collect variables, count elements, validate limits */
scanRPRPattern(optimized, varNamesStack, &numVars, &numElements, &maxDepth);
+ /*
+ * numVars may reach RPR_VARID_MAX + 1 (valid varIds are 0 ..
+ * RPR_VARID_MAX)
+ */
+ Assert(numVars <= RPR_VARID_MAX + 1);
+
/* Allocate result structure */
result = makeRPRPattern(numVars, numElements, maxDepth, varNamesStack);
diff --git a/src/include/optimizer/rpr.h b/src/include/optimizer/rpr.h
index f5462ab2a7c..1de7f86f867 100644
--- a/src/include/optimizer/rpr.h
+++ b/src/include/optimizer/rpr.h
@@ -75,9 +75,7 @@
#define RPRElemCanSkip(e) ((e)->min == 0)
extern void validate_rpr_define_volatility(List *defineClause);
-extern RPRPattern *buildRPRPattern(RPRPatternNode *pattern, List *defineVariableList,
- RPSkipTo rpSkipTo, int frameOptions,
- bool hasMatchStartDependent);
+extern RPRPattern *buildRPRPattern(WindowClause *wc, bool hasMatchStartDependent);
/*
* Shared traversal walker for DEFINE clause RPRNavExpr collection.
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index cb9d02c00c4..78c6ca9fb5b 100644
--- a/src/include/parser/parse_node.h
+++ b/src/include/parser/parse_node.h
@@ -231,7 +231,7 @@ struct ParseState
ParseNamespaceItem *p_grouping_nsitem; /* NSItem for grouping, or NULL */
List *p_windowdefs; /* raw representations of window clauses */
ParseExprKind p_expr_kind; /* what kind of expression we're parsing */
- List *p_rpr_pattern_vars; /* RPR variable names for DEFINE clause */
+ List *p_rpr_pattern_vars; /* Row pattern variable names */
int p_next_resno; /* next targetlist resno to assign */
List *p_multiassign_exprs; /* junk tlist entries for multiassign */
List *p_locking_clause; /* raw FOR UPDATE/FOR SHARE info */
--
2.50.1 (Apple Git-155)