nocfbot-0046-Tidy-up-forward-declarations-and-helper-placement.txt

text/plain

Filename: nocfbot-0046-Tidy-up-forward-declarations-and-helper-placement.txt
Type: text/plain
Part: 45
Message: Re: Row pattern recognition
From 178fe9979b1a5c18e06af67a696e12f0ee9da107 Mon Sep 17 00:00:00 2001
From: Henson Choi <assam258@gmail.com>
Date: Fri, 5 Jun 2026 12:32:38 +0900
Subject: [PATCH 46/68] Tidy up forward declarations and helper placement for
 row pattern recognition

Bring the row pattern recognition code in line with the surrounding
conventions for static helpers:

- each static helper has a forward declaration;
- static helpers are defined above the "API exposed" banner, public
  entry points below;
- the forward-declaration block uses a single banner, not per-group
  labels;
- forward declarations follow definition order.

Pure code movement and comments, no behavior change.

Per review comments from Tatsuo Ishii and Jian He.
---
 src/backend/executor/execRPR.c       | 110 +++----
 src/backend/executor/nodeWindowAgg.c | 454 +++++++++++++--------------
 src/backend/optimizer/plan/rpr.c     |  12 +-
 src/backend/parser/parse_rpr.c       |   2 +-
 4 files changed, 289 insertions(+), 289 deletions(-)

diff --git a/src/backend/executor/execRPR.c b/src/backend/executor/execRPR.c
index 580b25f398d..56399c0c7fd 100644
--- a/src/backend/executor/execRPR.c
+++ b/src/backend/executor/execRPR.c
@@ -83,8 +83,6 @@ static bool nfa_eval_var_match(WindowAggState *winstate,
 							   RPRPatternElement *elem, bool *varMatched);
 static void nfa_match(WindowAggState *winstate, RPRNFAContext *ctx,
 					  bool *varMatched);
-static void nfa_advance_state(WindowAggState *winstate, RPRNFAContext *ctx,
-							  RPRNFAState *state, int64 currentPos);
 static void nfa_route_to_elem(WindowAggState *winstate, RPRNFAContext *ctx,
 							  RPRNFAState *state, RPRPatternElement *nextElem,
 							  int64 currentPos);
@@ -100,9 +98,15 @@ static void nfa_advance_end(WindowAggState *winstate, RPRNFAContext *ctx,
 static void nfa_advance_var(WindowAggState *winstate, RPRNFAContext *ctx,
 							RPRNFAState *state, RPRPatternElement *elem,
 							int64 currentPos);
+static void nfa_advance_state(WindowAggState *winstate, RPRNFAContext *ctx,
+							  RPRNFAState *state, int64 currentPos);
 static void nfa_advance(WindowAggState *winstate, RPRNFAContext *ctx,
 						int64 currentPos);
 
+static void nfa_reevaluate_dependent_vars(WindowAggState *winstate,
+										  RPRNFAContext *ctx,
+										  int64 currentPos);
+
 /*
  * NFA-based pattern matching implementation
  *
@@ -1552,6 +1556,57 @@ nfa_advance(WindowAggState *winstate, RPRNFAContext *ctx, int64 currentPos)
 	}
 }
 
+/*
+ * nfa_reevaluate_dependent_vars
+ *		Re-evaluate match_start-dependent DEFINE variables for a specific
+ *		context whose matchStartRow differs from the shared evaluation's
+ *		nav_match_start.
+ *
+ * Only variables in defineMatchStartDependent are re-evaluated.  The
+ * current row's slot (ecxt_outertuple) must already be set up by
+ * nfa_evaluate_row().
+ */
+static void
+nfa_reevaluate_dependent_vars(WindowAggState *winstate, RPRNFAContext *ctx,
+							  int64 currentPos)
+{
+	ExprContext *econtext = winstate->ss.ps.ps_ExprContext;
+	int64		saved_match_start = winstate->nav_match_start;
+	int64		saved_pos = winstate->currentpos;
+	int			varIdx = 0;
+	ListCell   *lc;
+
+	/* Temporarily set nav_match_start and currentpos for FIRST/LAST */
+	winstate->nav_match_start = ctx->matchStartRow;
+	winstate->currentpos = currentPos;
+
+	/* Invalidate nav_slot cache since match_start changed */
+	winstate->nav_slot_pos = -1;
+
+	foreach(lc, winstate->defineClauseList)
+	{
+		if (bms_is_member(varIdx, winstate->defineMatchStartDependent))
+		{
+			ExprState  *exprState = (ExprState *) lfirst(lc);
+			Datum		result;
+			bool		isnull;
+
+			/* Per-tuple context; scratch freed by the per-row reset */
+			result = ExecEvalExprSwitchContext(exprState, econtext, &isnull);
+			winstate->nfaVarMatched[varIdx] = (!isnull && DatumGetBool(result));
+		}
+
+		varIdx++;
+		if (varIdx >= list_length(winstate->defineVariableList))
+			break;
+	}
+
+	/* Restore original match_start, currentpos, and invalidate cache */
+	winstate->nav_match_start = saved_match_start;
+	winstate->currentpos = saved_pos;
+	winstate->nav_slot_pos = -1;
+}
+
 
 /***********************************************************************
  * API exposed to nodeWindowAgg.c
@@ -1696,57 +1751,6 @@ ExecRPRRecordContextFailure(WindowAggState *winstate, int64 failedLen)
 	}
 }
 
-/*
- * nfa_reevaluate_dependent_vars
- *		Re-evaluate match_start-dependent DEFINE variables for a specific
- *		context whose matchStartRow differs from the shared evaluation's
- *		nav_match_start.
- *
- * Only variables in defineMatchStartDependent are re-evaluated.  The
- * current row's slot (ecxt_outertuple) must already be set up by
- * nfa_evaluate_row().
- */
-static void
-nfa_reevaluate_dependent_vars(WindowAggState *winstate, RPRNFAContext *ctx,
-							  int64 currentPos)
-{
-	ExprContext *econtext = winstate->ss.ps.ps_ExprContext;
-	int64		saved_match_start = winstate->nav_match_start;
-	int64		saved_pos = winstate->currentpos;
-	int			varIdx = 0;
-	ListCell   *lc;
-
-	/* Temporarily set nav_match_start and currentpos for FIRST/LAST */
-	winstate->nav_match_start = ctx->matchStartRow;
-	winstate->currentpos = currentPos;
-
-	/* Invalidate nav_slot cache since match_start changed */
-	winstate->nav_slot_pos = -1;
-
-	foreach(lc, winstate->defineClauseList)
-	{
-		if (bms_is_member(varIdx, winstate->defineMatchStartDependent))
-		{
-			ExprState  *exprState = (ExprState *) lfirst(lc);
-			Datum		result;
-			bool		isnull;
-
-			/* Per-tuple context; scratch freed by the per-row reset */
-			result = ExecEvalExprSwitchContext(exprState, econtext, &isnull);
-			winstate->nfaVarMatched[varIdx] = (!isnull && DatumGetBool(result));
-		}
-
-		varIdx++;
-		if (varIdx >= list_length(winstate->defineVariableList))
-			break;
-	}
-
-	/* Restore original match_start, currentpos, and invalidate cache */
-	winstate->nav_match_start = saved_match_start;
-	winstate->currentpos = saved_pos;
-	winstate->nav_slot_pos = -1;
-}
-
 /*
  * ExecRPRProcessRow
  *
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 408bbc120b7..86b39bf7f61 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -4627,6 +4627,233 @@ nfa_evaluate_row(WindowObject winobj, int64 pos, bool *varMatched)
 	return true;				/* Row exists */
 }
 
+/*
+ * WinGetSlotInFrame
+ * slot: TupleTableSlot to store the result
+ * relpos: signed rowcount offset from the seek position
+ * seektype: WINDOW_SEEK_HEAD or WINDOW_SEEK_TAIL
+ * set_mark: If the row is found/in frame and set_mark is true, the mark is
+ *		moved to the row as a side-effect.
+ * isnull: output argument, receives isnull status of result
+ * isout: output argument, set to indicate whether target row position
+ *		is out of frame (can pass NULL if caller doesn't care about this)
+ *
+ * Returns 0 if we successfully got the slot, or nonzero if out of frame.
+ * (isout is also set in the latter case.)
+ */
+static int
+WinGetSlotInFrame(WindowObject winobj, TupleTableSlot *slot,
+				  int relpos, int seektype, bool set_mark,
+				  bool *isnull, bool *isout)
+{
+	WindowAggState *winstate;
+	int64		abs_pos;
+	int64		mark_pos;
+	int64		num_reduced_frame;
+
+	Assert(WindowObjectIsValid(winobj));
+	winstate = winobj->winstate;
+
+	switch (seektype)
+	{
+		case WINDOW_SEEK_CURRENT:
+			elog(ERROR, "WINDOW_SEEK_CURRENT is not supported for WinGetFuncArgInFrame");
+			abs_pos = mark_pos = 0; /* keep compiler quiet */
+			break;
+		case WINDOW_SEEK_HEAD:
+			/* rejecting relpos < 0 is easy and simplifies code below */
+			if (relpos < 0)
+				goto out_of_frame;
+			update_frameheadpos(winstate);
+			abs_pos = winstate->frameheadpos + relpos;
+			mark_pos = abs_pos;
+
+			/*
+			 * Account for exclusion option if one is active, but advance only
+			 * abs_pos not mark_pos.  This prevents changes of the current
+			 * row's peer group from resulting in trying to fetch a row before
+			 * some previous mark position.
+			 *
+			 * Note that in some corner cases such as current row being
+			 * outside frame, these calculations are theoretically too simple,
+			 * but it doesn't matter because we'll end up deciding the row is
+			 * out of frame.  We do not attempt to avoid fetching rows past
+			 * end of frame; that would happen in some cases anyway.
+			 */
+			switch (winstate->frameOptions & FRAMEOPTION_EXCLUSION)
+			{
+				case 0:
+					/* no adjustment needed */
+					break;
+				case FRAMEOPTION_EXCLUDE_CURRENT_ROW:
+					if (abs_pos >= winstate->currentpos &&
+						winstate->currentpos >= winstate->frameheadpos)
+						abs_pos++;
+					break;
+				case FRAMEOPTION_EXCLUDE_GROUP:
+					update_grouptailpos(winstate);
+					if (abs_pos >= winstate->groupheadpos &&
+						winstate->grouptailpos > winstate->frameheadpos)
+					{
+						int64		overlapstart = Max(winstate->groupheadpos,
+													   winstate->frameheadpos);
+
+						abs_pos += winstate->grouptailpos - overlapstart;
+					}
+					break;
+				case FRAMEOPTION_EXCLUDE_TIES:
+					update_grouptailpos(winstate);
+					if (abs_pos >= winstate->groupheadpos &&
+						winstate->grouptailpos > winstate->frameheadpos)
+					{
+						int64		overlapstart = Max(winstate->groupheadpos,
+													   winstate->frameheadpos);
+
+						if (abs_pos == overlapstart)
+							abs_pos = winstate->currentpos;
+						else
+							abs_pos += winstate->grouptailpos - overlapstart - 1;
+					}
+					break;
+				default:
+					elog(ERROR, "unrecognized frame option state: 0x%x",
+						 winstate->frameOptions);
+					break;
+			}
+			num_reduced_frame = row_is_in_reduced_frame(winobj,
+														winstate->frameheadpos);
+			if (num_reduced_frame < 0)
+				goto out_of_frame;
+			else if (num_reduced_frame > 0)
+				if (relpos >= num_reduced_frame)
+					goto out_of_frame;
+			break;
+		case WINDOW_SEEK_TAIL:
+			/* rejecting relpos > 0 is easy and simplifies code below */
+			if (relpos > 0)
+				goto out_of_frame;
+
+			/*
+			 * RPR cares about frame head pos. Need to call
+			 * update_frameheadpos
+			 */
+			update_frameheadpos(winstate);
+
+			update_frametailpos(winstate);
+			abs_pos = winstate->frametailpos - 1 + relpos;
+
+			/*
+			 * Account for exclusion option if one is active.  If there is no
+			 * exclusion, we can safely set the mark at the accessed row.  But
+			 * if there is, we can only mark the frame start, because we can't
+			 * be sure how far back in the frame the exclusion might cause us
+			 * to fetch in future.  Furthermore, we have to actually check
+			 * against frameheadpos here, since it's unsafe to try to fetch a
+			 * row before frame start if the mark might be there already.
+			 */
+			switch (winstate->frameOptions & FRAMEOPTION_EXCLUSION)
+			{
+				case 0:
+					/* no adjustment needed */
+					mark_pos = abs_pos;
+					break;
+				case FRAMEOPTION_EXCLUDE_CURRENT_ROW:
+					if (abs_pos <= winstate->currentpos &&
+						winstate->currentpos < winstate->frametailpos)
+						abs_pos--;
+					update_frameheadpos(winstate);
+					if (abs_pos < winstate->frameheadpos)
+						goto out_of_frame;
+					mark_pos = winstate->frameheadpos;
+					break;
+				case FRAMEOPTION_EXCLUDE_GROUP:
+					update_grouptailpos(winstate);
+					if (abs_pos < winstate->grouptailpos &&
+						winstate->groupheadpos < winstate->frametailpos)
+					{
+						int64		overlapend = Min(winstate->grouptailpos,
+													 winstate->frametailpos);
+
+						abs_pos -= overlapend - winstate->groupheadpos;
+					}
+					update_frameheadpos(winstate);
+					if (abs_pos < winstate->frameheadpos)
+						goto out_of_frame;
+					mark_pos = winstate->frameheadpos;
+					break;
+				case FRAMEOPTION_EXCLUDE_TIES:
+					update_grouptailpos(winstate);
+					if (abs_pos < winstate->grouptailpos &&
+						winstate->groupheadpos < winstate->frametailpos)
+					{
+						int64		overlapend = Min(winstate->grouptailpos,
+													 winstate->frametailpos);
+
+						if (abs_pos == overlapend - 1)
+							abs_pos = winstate->currentpos;
+						else
+							abs_pos -= overlapend - 1 - winstate->groupheadpos;
+					}
+					update_frameheadpos(winstate);
+					if (abs_pos < winstate->frameheadpos)
+						goto out_of_frame;
+					mark_pos = winstate->frameheadpos;
+					break;
+				default:
+					elog(ERROR, "unrecognized frame option state: 0x%x",
+						 winstate->frameOptions);
+					mark_pos = 0;	/* keep compiler quiet */
+					break;
+			}
+
+			num_reduced_frame = row_is_in_reduced_frame(winobj,
+														winstate->frameheadpos);
+			if (num_reduced_frame < 0)
+				goto out_of_frame;
+			else if (num_reduced_frame > 0)
+			{
+				if (-relpos >= num_reduced_frame)
+					goto out_of_frame;
+				abs_pos = winstate->frameheadpos + relpos +
+					num_reduced_frame - 1;
+			}
+			break;
+		default:
+			elog(ERROR, "unrecognized window seek type: %d", seektype);
+			abs_pos = mark_pos = 0; /* keep compiler quiet */
+			break;
+	}
+
+	if (!window_gettupleslot(winobj, abs_pos, slot))
+		goto out_of_frame;
+
+	/* The code above does not detect all out-of-frame cases, so check */
+	if (row_is_in_frame(winobj, abs_pos, slot, false) <= 0)
+		goto out_of_frame;
+
+	if (isout)
+		*isout = false;
+	if (set_mark)
+	{
+		/*
+		 * If RPR is enabled and seek type is WINDOW_SEEK_TAIL, we set the
+		 * mark position unconditionally to frameheadpos. In this case the
+		 * frame always starts at CURRENT_ROW and never goes back, thus
+		 * setting the mark at the position is safe.
+		 */
+		if (winstate->rpPattern != NULL && seektype == WINDOW_SEEK_TAIL)
+			mark_pos = winstate->frameheadpos;
+		WinSetMarkPosition(winobj, mark_pos);
+	}
+	return 0;
+
+out_of_frame:
+	if (isout)
+		*isout = true;
+	*isnull = true;
+	return -1;
+}
+
 
 /***********************************************************************
  * API exposed to window functions
@@ -5019,233 +5246,6 @@ WinGetFuncArgInFrame(WindowObject winobj, int argno,
 	return (Datum) 0;
 }
 
-/*
- * WinGetSlotInFrame
- * slot: TupleTableSlot to store the result
- * relpos: signed rowcount offset from the seek position
- * seektype: WINDOW_SEEK_HEAD or WINDOW_SEEK_TAIL
- * set_mark: If the row is found/in frame and set_mark is true, the mark is
- *		moved to the row as a side-effect.
- * isnull: output argument, receives isnull status of result
- * isout: output argument, set to indicate whether target row position
- *		is out of frame (can pass NULL if caller doesn't care about this)
- *
- * Returns 0 if we successfully got the slot, or nonzero if out of frame.
- * (isout is also set in the latter case.)
- */
-static int
-WinGetSlotInFrame(WindowObject winobj, TupleTableSlot *slot,
-				  int relpos, int seektype, bool set_mark,
-				  bool *isnull, bool *isout)
-{
-	WindowAggState *winstate;
-	int64		abs_pos;
-	int64		mark_pos;
-	int64		num_reduced_frame;
-
-	Assert(WindowObjectIsValid(winobj));
-	winstate = winobj->winstate;
-
-	switch (seektype)
-	{
-		case WINDOW_SEEK_CURRENT:
-			elog(ERROR, "WINDOW_SEEK_CURRENT is not supported for WinGetFuncArgInFrame");
-			abs_pos = mark_pos = 0; /* keep compiler quiet */
-			break;
-		case WINDOW_SEEK_HEAD:
-			/* rejecting relpos < 0 is easy and simplifies code below */
-			if (relpos < 0)
-				goto out_of_frame;
-			update_frameheadpos(winstate);
-			abs_pos = winstate->frameheadpos + relpos;
-			mark_pos = abs_pos;
-
-			/*
-			 * Account for exclusion option if one is active, but advance only
-			 * abs_pos not mark_pos.  This prevents changes of the current
-			 * row's peer group from resulting in trying to fetch a row before
-			 * some previous mark position.
-			 *
-			 * Note that in some corner cases such as current row being
-			 * outside frame, these calculations are theoretically too simple,
-			 * but it doesn't matter because we'll end up deciding the row is
-			 * out of frame.  We do not attempt to avoid fetching rows past
-			 * end of frame; that would happen in some cases anyway.
-			 */
-			switch (winstate->frameOptions & FRAMEOPTION_EXCLUSION)
-			{
-				case 0:
-					/* no adjustment needed */
-					break;
-				case FRAMEOPTION_EXCLUDE_CURRENT_ROW:
-					if (abs_pos >= winstate->currentpos &&
-						winstate->currentpos >= winstate->frameheadpos)
-						abs_pos++;
-					break;
-				case FRAMEOPTION_EXCLUDE_GROUP:
-					update_grouptailpos(winstate);
-					if (abs_pos >= winstate->groupheadpos &&
-						winstate->grouptailpos > winstate->frameheadpos)
-					{
-						int64		overlapstart = Max(winstate->groupheadpos,
-													   winstate->frameheadpos);
-
-						abs_pos += winstate->grouptailpos - overlapstart;
-					}
-					break;
-				case FRAMEOPTION_EXCLUDE_TIES:
-					update_grouptailpos(winstate);
-					if (abs_pos >= winstate->groupheadpos &&
-						winstate->grouptailpos > winstate->frameheadpos)
-					{
-						int64		overlapstart = Max(winstate->groupheadpos,
-													   winstate->frameheadpos);
-
-						if (abs_pos == overlapstart)
-							abs_pos = winstate->currentpos;
-						else
-							abs_pos += winstate->grouptailpos - overlapstart - 1;
-					}
-					break;
-				default:
-					elog(ERROR, "unrecognized frame option state: 0x%x",
-						 winstate->frameOptions);
-					break;
-			}
-			num_reduced_frame = row_is_in_reduced_frame(winobj,
-														winstate->frameheadpos);
-			if (num_reduced_frame < 0)
-				goto out_of_frame;
-			else if (num_reduced_frame > 0)
-				if (relpos >= num_reduced_frame)
-					goto out_of_frame;
-			break;
-		case WINDOW_SEEK_TAIL:
-			/* rejecting relpos > 0 is easy and simplifies code below */
-			if (relpos > 0)
-				goto out_of_frame;
-
-			/*
-			 * RPR cares about frame head pos. Need to call
-			 * update_frameheadpos
-			 */
-			update_frameheadpos(winstate);
-
-			update_frametailpos(winstate);
-			abs_pos = winstate->frametailpos - 1 + relpos;
-
-			/*
-			 * Account for exclusion option if one is active.  If there is no
-			 * exclusion, we can safely set the mark at the accessed row.  But
-			 * if there is, we can only mark the frame start, because we can't
-			 * be sure how far back in the frame the exclusion might cause us
-			 * to fetch in future.  Furthermore, we have to actually check
-			 * against frameheadpos here, since it's unsafe to try to fetch a
-			 * row before frame start if the mark might be there already.
-			 */
-			switch (winstate->frameOptions & FRAMEOPTION_EXCLUSION)
-			{
-				case 0:
-					/* no adjustment needed */
-					mark_pos = abs_pos;
-					break;
-				case FRAMEOPTION_EXCLUDE_CURRENT_ROW:
-					if (abs_pos <= winstate->currentpos &&
-						winstate->currentpos < winstate->frametailpos)
-						abs_pos--;
-					update_frameheadpos(winstate);
-					if (abs_pos < winstate->frameheadpos)
-						goto out_of_frame;
-					mark_pos = winstate->frameheadpos;
-					break;
-				case FRAMEOPTION_EXCLUDE_GROUP:
-					update_grouptailpos(winstate);
-					if (abs_pos < winstate->grouptailpos &&
-						winstate->groupheadpos < winstate->frametailpos)
-					{
-						int64		overlapend = Min(winstate->grouptailpos,
-													 winstate->frametailpos);
-
-						abs_pos -= overlapend - winstate->groupheadpos;
-					}
-					update_frameheadpos(winstate);
-					if (abs_pos < winstate->frameheadpos)
-						goto out_of_frame;
-					mark_pos = winstate->frameheadpos;
-					break;
-				case FRAMEOPTION_EXCLUDE_TIES:
-					update_grouptailpos(winstate);
-					if (abs_pos < winstate->grouptailpos &&
-						winstate->groupheadpos < winstate->frametailpos)
-					{
-						int64		overlapend = Min(winstate->grouptailpos,
-													 winstate->frametailpos);
-
-						if (abs_pos == overlapend - 1)
-							abs_pos = winstate->currentpos;
-						else
-							abs_pos -= overlapend - 1 - winstate->groupheadpos;
-					}
-					update_frameheadpos(winstate);
-					if (abs_pos < winstate->frameheadpos)
-						goto out_of_frame;
-					mark_pos = winstate->frameheadpos;
-					break;
-				default:
-					elog(ERROR, "unrecognized frame option state: 0x%x",
-						 winstate->frameOptions);
-					mark_pos = 0;	/* keep compiler quiet */
-					break;
-			}
-
-			num_reduced_frame = row_is_in_reduced_frame(winobj,
-														winstate->frameheadpos);
-			if (num_reduced_frame < 0)
-				goto out_of_frame;
-			else if (num_reduced_frame > 0)
-			{
-				if (-relpos >= num_reduced_frame)
-					goto out_of_frame;
-				abs_pos = winstate->frameheadpos + relpos +
-					num_reduced_frame - 1;
-			}
-			break;
-		default:
-			elog(ERROR, "unrecognized window seek type: %d", seektype);
-			abs_pos = mark_pos = 0; /* keep compiler quiet */
-			break;
-	}
-
-	if (!window_gettupleslot(winobj, abs_pos, slot))
-		goto out_of_frame;
-
-	/* The code above does not detect all out-of-frame cases, so check */
-	if (row_is_in_frame(winobj, abs_pos, slot, false) <= 0)
-		goto out_of_frame;
-
-	if (isout)
-		*isout = false;
-	if (set_mark)
-	{
-		/*
-		 * If RPR is enabled and seek type is WINDOW_SEEK_TAIL, we set the
-		 * mark position unconditionally to frameheadpos. In this case the
-		 * frame always starts at CURRENT_ROW and never goes back, thus
-		 * setting the mark at the position is safe.
-		 */
-		if (winstate->rpPattern != NULL && seektype == WINDOW_SEEK_TAIL)
-			mark_pos = winstate->frameheadpos;
-		WinSetMarkPosition(winobj, mark_pos);
-	}
-	return 0;
-
-out_of_frame:
-	if (isout)
-		*isout = true;
-	*isnull = true;
-	return -1;
-}
-
 /*
  * WinGetFuncArgCurrent
  *		Evaluate a window function's argument expression on the current row.
diff --git a/src/backend/optimizer/plan/rpr.c b/src/backend/optimizer/plan/rpr.c
index 3205559c03a..43114088c3f 100644
--- a/src/backend/optimizer/plan/rpr.c
+++ b/src/backend/optimizer/plan/rpr.c
@@ -44,14 +44,12 @@
 #include "nodes/nodeFuncs.h"
 #include "optimizer/rpr.h"
 
-/* Forward declarations - pattern comparison */
+/* Forward declarations */
 static bool rprPatternEqual(RPRPatternNode *a, RPRPatternNode *b);
 static bool rprPatternChildrenEqual(List *a, List *b);
 
-/* Forward declarations - pattern optimization (shared) */
 static RPRPatternNode *tryUnwrapSingleChild(RPRPatternNode *pattern);
 
-/* Forward declarations - SEQ optimization */
 static List *flattenSeqChildren(List *children);
 static List *mergeConsecutiveVars(List *children);
 static List *mergeConsecutiveGroups(List *children);
@@ -59,20 +57,16 @@ static List *mergeConsecutiveAlts(List *children);
 static List *mergeGroupPrefixSuffix(List *children);
 static RPRPatternNode *optimizeSeqPattern(RPRPatternNode *pattern);
 
-/* Forward declarations - ALT optimization */
 static List *flattenAltChildren(List *children);
 static List *removeDuplicateAlternatives(List *children);
 static RPRPatternNode *optimizeAltPattern(RPRPatternNode *pattern);
 
-/* Forward declarations - GROUP optimization */
 static RPRPatternNode *tryMultiplyQuantifiers(RPRPatternNode *pattern);
 static RPRPatternNode *tryUnwrapGroup(RPRPatternNode *pattern);
 static RPRPatternNode *optimizeGroupPattern(RPRPatternNode *pattern);
 
-/* Forward declarations - optimization dispatcher */
 static RPRPatternNode *optimizeRPRPattern(RPRPatternNode *pattern);
 
-/* Forward declarations - pattern compilation */
 static int	collectDefineVariables(List *defineVariableList, char **varNames);
 static void scanRPRPatternRecursive(RPRPatternNode *node, char **varNames,
 									int *numVars, int *numElements,
@@ -92,7 +86,6 @@ static bool fillRPRPattern(RPRPatternNode *node, RPRPattern *pat,
 						   int *idx, RPRDepth depth);
 static void finalizeRPRPattern(RPRPattern *result);
 
-/* Forward declarations - context absorption */
 static bool isFixedLengthChildren(RPRPattern *pattern, RPRElemIdx idx,
 								  RPRDepth scopeDepth);
 static bool isUnboundedStart(RPRPattern *pattern, RPRElemIdx idx);
@@ -101,6 +94,9 @@ 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.
diff --git a/src/backend/parser/parse_rpr.c b/src/backend/parser/parse_rpr.c
index 3872035110a..c9469b56b7b 100644
--- a/src/backend/parser/parse_rpr.c
+++ b/src/backend/parser/parse_rpr.c
@@ -61,8 +61,8 @@ static void validateRPRPatternVarCount(ParseState *pstate, RPRPatternNode *node,
 									   List *rpDefs, List **varNames);
 static List *transformDefineClause(ParseState *pstate, WindowClause *wc,
 								   WindowDef *windef, List **targetlist);
-static bool define_walker(Node *node, void *context);
 static bool nav_volatile_func_checker(Oid funcid, void *context);
+static bool define_walker(Node *node, void *context);
 
 /*
  * transformRPR
-- 
2.50.1 (Apple Git-155)