v50-0004-misc.partial

application/octet-stream

Filename: v50-0004-misc.partial
Type: application/octet-stream
Part: 2
Message: Re: Row pattern recognition
From 283157f1e47eec2e64668fef65db8176599f697c Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Thu, 2 Jul 2026 20:38:17 +0800
Subject: [PATCH v50 4/4] misc.

Based on https://github.com/assam258-5892/postgres/commits/RPR
---
 src/backend/executor/execExprInterp.c   |  9 +++++--
 src/backend/executor/nodeWindowAgg.c    | 35 +++++++++++++------------
 src/backend/optimizer/plan/createplan.c |  7 ++---
 3 files changed, 27 insertions(+), 24 deletions(-)

diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 5c26c5e848..33960b757d 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -6175,8 +6175,6 @@ ExecEvalRPRNavSet(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
  * Evaluate RPR navigation: restore slot to original row.
  *
  * Restores econtext->ecxt_outertuple from the saved slot in winstate.
- * When slot swap was elided (target == currentpos), this is a harmless
- * no-op since saved and current slots are identical.
  * The caller is responsible for updating any local slot cache.
  *
  * For pass-by-reference result types, the result datum points into
@@ -6192,6 +6190,13 @@ ExecEvalRPRNavRestore(ExprState *state, ExprEvalStep *op,
 {
 	WindowAggState *winstate = op->d.rpr_nav.winstate;
 
+	/*
+	 * When slot swap was elided (target == currentpos), this is a harmless
+	 * no-op since saved and current slots are identical.
+	 */
+	if (econtext->ecxt_outertuple == winstate->nav_saved_outertuple)
+		return;
+
 	econtext->ecxt_outertuple = winstate->nav_saved_outertuple;
 
 	/* Stabilize pass-by-ref result against nav_slot re-fetch */
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index fdd69f494e..ce87811f1a 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -3978,19 +3978,16 @@ put_notnull_info(WindowObject winobj, int64 pos, int argno, bool isnull)
 }
 
 /*
- * eval_nav_offset_helper
- *		Pre-evaluate a navigation offset expression at executor init time, to
- *		bound how far navigation can reach (which sizes the frame trim).
- *		Returns the offset value, or 0 for a NULL or negative offset.
+ * eval_nav_offset
+ *		Evaluate a row pattern navigation offset expression
  *
- * The offset is not validated here.  A NULL or negative value is caught later,
- * per row, on the navigation path that consumes it (see EEOP_RPR_NAV_SET in
- * execExprInterp.c), which errors out before navigation produces any result;
- * the trim sizing computed from such an offset is therefore never used, and 0
- * is returned as a harmless placeholder.
+ * The resolved value bounds how far navigation can reach, which in turn
+ * sizes the tuplestore trim.  offset_expr may be either a simple offset or
+ * the outer (compound) offset of a compound navigation.  Returns the offset
+ * as an int64; a NULL or negative result is an error per the SQL standard.
  */
 static int64
-eval_nav_offset_helper(WindowAggState *winstate, Expr *offset_expr)
+eval_nav_offset(WindowAggState *winstate, Expr *offset_expr)
 {
 	ExprContext *econtext = winstate->ss.ps.ps_ExprContext;
 	ExprState  *estate;
@@ -4031,7 +4028,7 @@ typedef struct
  * visit_nav_exec
  *		nav_traversal_walker callback (NavVisitFn) for the executor side.
  *		At each RPRNavExpr, evaluates the nav's offset expression(s) at
- *		runtime via eval_nav_offset_helper and accumulates:
+ *		runtime via eval_nav_offset and accumulates:
  *
  *		  - maxOffset (backward reach): PREV, LAST-with-offset, compound
  *			PREV_LAST (sets maxOverflow on int64 overflow), compound
@@ -4049,8 +4046,8 @@ typedef struct
 static void
 visit_nav_exec(NavTraversal *t, RPRNavExpr *nav)
 {
-	int64		inner = 0;
-	int64		outer = 1;
+	int64		inner;
+	int64		outer;
 
 	EvalDefineOffsetsContext *context = (EvalDefineOffsetsContext *) t->data;
 
@@ -4065,14 +4062,18 @@ visit_nav_exec(NavTraversal *t, RPRNavExpr *nav)
 		   !IsA(nav->compound_offset_arg, RPRNavExpr));
 
 	if (nav->offset_arg != NULL)
-		inner = eval_nav_offset_helper(context->winstate,
-									   nav->offset_arg);
+		inner = eval_nav_offset(context->winstate,
+								nav->offset_arg);
 	else if (nav->kind == RPR_NAV_PREV || nav->kind == RPR_NAV_NEXT)
 		inner = 1;
+	else
+		inner = 0;
 
 	if (nav->compound_offset_arg != NULL)
-		outer = eval_nav_offset_helper(context->winstate,
-									   nav->compound_offset_arg);
+		outer = eval_nav_offset(context->winstate,
+								nav->compound_offset_arg);
+	else
+		outer = 1;
 
 	nav->offset = inner;
 	nav->compound_offset = outer;
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 8146ad1070..c61cadafb2 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -2495,11 +2495,8 @@ typedef struct DefineMetadataContext
  * PREV_FIRST, NEXT_FIRST, PREV_LAST/NEXT_LAST-with-offset) add
  * curVarIdx to matchStartDependent.
  *
- * Constant offsets are extracted via extract_const_offset; non-constant
- * offsets set maxNeedsEval / firstNeedsEval so the executor can resolve
- * them at init time (see visit_nav_exec).  Classification uses only the
- * outer nav kind: parser nesting restrictions prevent FIRST/LAST inside
- * a PREV/NEXT value subexpression.
+ * Classification uses only the outer nav kind: parser nesting restrictions
+ * prevent FIRST/LAST inside a PREV/NEXT value subexpression.
  */
 static void
 visit_nav_plan(NavTraversal *t, RPRNavExpr *nav)
-- 
2.34.1