v47-0001-misc-refactor-for-v47-ExecRPRProcessRow.no-cfbot

application/octet-stream

Filename: v47-0001-misc-refactor-for-v47-ExecRPRProcessRow.no-cfbot
Type: application/octet-stream
Part: 0
Message: Re: Row pattern recognition
From afe2e7b503d135f72f006072fb7e1aab8ce8fce8 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Thu, 28 May 2026 21:15:43 +0800
Subject: [PATCH v47 1/1] misc refactor for v47 ExecRPRProcessRow

---
 src/backend/executor/README.rpr      |  2 +-
 src/backend/executor/execRPR.c       |  7 +++----
 src/backend/executor/nodeWindowAgg.c | 11 ++++++-----
 src/include/executor/execRPR.h       |  3 +--
 4 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/src/backend/executor/README.rpr b/src/backend/executor/README.rpr
index 52bcd77390c..2bf7703c777 100644
--- a/src/backend/executor/README.rpr
+++ b/src/backend/executor/README.rpr
@@ -1048,7 +1048,7 @@ X-3. INITIAL vs SEEK
 X-4. Bounded Frame Handling
 
   When the frame is bounded (e.g., ROWS BETWEEN CURRENT ROW AND 5
-  FOLLOWING), ExecRPRProcessRow receives hasLimitedFrame=true and
+  FOLLOWING), ExecRPRProcessRow receives (frameOffset > 0) and
   frameOffset indicating the upper bound.  Before the match phase,
   any context whose match has exceeded the frame boundary
   (currentPos >= matchStartRow + frameOffset + 1) is finalized early
diff --git a/src/backend/executor/execRPR.c b/src/backend/executor/execRPR.c
index 242ae9c6dcf..f381a84961d 100644
--- a/src/backend/executor/execRPR.c
+++ b/src/backend/executor/execRPR.c
@@ -1620,8 +1620,7 @@ nfa_reevaluate_dependent_vars(WindowAggState *winstate, RPRNFAContext *ctx,
  *   3. Advance all contexts (divergence) - create new states for next row
  */
 void
-ExecRPRProcessRow(WindowAggState *winstate, int64 currentPos,
-				  bool hasLimitedFrame, int64 frameOffset)
+ExecRPRProcessRow(WindowAggState *winstate, int64 currentPos, int64 frameOffset)
 {
 	RPRNFAContext *ctx;
 	bool	   *varMatched = winstate->nfaVarMatched;
@@ -1640,7 +1639,7 @@ ExecRPRProcessRow(WindowAggState *winstate, int64 currentPos,
 			continue;
 
 		/* Check frame boundary - finalize if exceeded */
-		if (hasLimitedFrame)
+		if (frameOffset > 0)
 		{
 			int64		ctxFrameEnd;
 
@@ -1696,7 +1695,7 @@ ExecRPRProcessRow(WindowAggState *winstate, int64 currentPos,
 		 * states are at VAR positions after advance). So any surviving
 		 * context here must be within its frame boundary.
 		 */
-		Assert(!hasLimitedFrame ||
+		Assert(frameOffset == 0 ||
 			   ctx->matchStartRow > PG_INT64_MAX - frameOffset - 1 ||
 			   currentPos < ctx->matchStartRow + frameOffset + 1);
 
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index f1cd9b66098..d4d57ffd795 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -4383,7 +4383,6 @@ update_reduced_frame(WindowObject winobj, int64 pos)
 	int64		currentPos;
 	int64		startPos;
 	int			frameOptions = winstate->frameOptions;
-	bool		hasLimitedFrame;
 	int64		frameOffset = 0;
 	int64		matchLen;
 
@@ -4391,11 +4390,13 @@ update_reduced_frame(WindowObject winobj, int64 pos)
 	 * Check if we have a limited frame (ROWS ... N FOLLOWING). Each context
 	 * needs its own frame end based on matchStartRow + offset.
 	 */
-	hasLimitedFrame = (frameOptions & FRAMEOPTION_ROWS) &&
-		!(frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING);
-	if (hasLimitedFrame && winstate->endOffsetValue != 0)
+	Assert(frameOptions & FRAMEOPTION_ROWS);
+
+	if (!(frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING))
 		frameOffset = DatumGetInt64(winstate->endOffsetValue);
 
+	Assert(frameOffset >= 0);
+
 	/*
 	 * Case 1: pos is before any existing context's start position. This means
 	 * the position was already processed and determined unmatched. Head is
@@ -4488,7 +4489,7 @@ update_reduced_frame(WindowObject winobj, int64 pos)
 		 *   2. Absorb redundant
 		 *   3. Advance all (divergence)
 		 */
-		ExecRPRProcessRow(winstate, currentPos, hasLimitedFrame, frameOffset);
+		ExecRPRProcessRow(winstate, currentPos, frameOffset);
 
 		/*
 		 * Create a new context for the next potential start position. This
diff --git a/src/include/executor/execRPR.h b/src/include/executor/execRPR.h
index 7b2b0febb76..a9700f56209 100644
--- a/src/include/executor/execRPR.h
+++ b/src/include/executor/execRPR.h
@@ -25,8 +25,7 @@ extern RPRNFAContext *ExecRPRGetHeadContext(WindowAggState *winstate,
 extern void ExecRPRFreeContext(WindowAggState *winstate, RPRNFAContext *ctx);
 
 /* NFA processing */
-extern void ExecRPRProcessRow(WindowAggState *winstate, int64 currentPos,
-							  bool hasLimitedFrame, int64 frameOffset);
+extern void ExecRPRProcessRow(WindowAggState *winstate, int64 currentPos, int64 frameOffset);
 extern void ExecRPRCleanupDeadContexts(WindowAggState *winstate,
 									   RPRNFAContext *excludeCtx);
 extern void ExecRPRFinalizeAllContexts(WindowAggState *winstate, int64 lastPos);
-- 
2.34.1