v50-0003-no-need-compile-and-evaluate-offset-in-expression-evaluation.partial

application/octet-stream

Filename: v50-0003-no-need-compile-and-evaluate-offset-in-expression-evaluation.partial
Type: application/octet-stream
Part: 3
Message: Re: Row pattern recognition
From 6c877a423d04e7d9b641b7aee877b7aa5aadb239 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Thu, 2 Jul 2026 17:39:11 +0800
Subject: [PATCH v50 3/4] no need compile and evaluate offset in expression
 evaluation

execExpr.c, execExprInterp.c offset, compound_offset value checking is not
necessary.

Based on https://github.com/assam258-5892/postgres/commits/RPR
---
 src/backend/executor/execExpr.c       | 56 +--------------------------
 src/backend/executor/execExprInterp.c | 47 ++--------------------
 src/backend/executor/nodeWindowAgg.c  |  3 ++
 src/backend/parser/parse_rpr.c        |  2 +
 src/include/executor/execExpr.h       |  6 +--
 src/include/nodes/primnodes.h         | 25 +++++++++---
 6 files changed, 34 insertions(+), 105 deletions(-)

diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 3036782503..de13ac693f 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -1198,10 +1198,6 @@ ExecInitExprRec(Expr *node, ExprState *state,
 				 * swaps ecxt_outertuple to the target row, the argument
 				 * expression is compiled normally (reads from the swapped
 				 * slot), and the RESTORE opcode restores the original slot.
-				 *
-				 * Default offset when offset_arg is NULL: PREV/NEXT: 1
-				 * (physical offset from currentpos) FIRST/LAST: 0 (logical
-				 * offset from match boundary)
 				 */
 				RPRNavExpr *nav = (RPRNavExpr *) node;
 				WindowAggState *winstate;
@@ -1213,56 +1209,8 @@ ExecInitExprRec(Expr *node, ExprState *state,
 				scratch.opcode = EEOP_RPR_NAV_SET;
 				scratch.d.rpr_nav.winstate = winstate;
 				scratch.d.rpr_nav.kind = nav->kind;
-
-				if (nav->kind >= RPR_NAV_PREV_FIRST)
-				{
-					/*
-					 * Compound navigation: allocate array of 2 for inner [0]
-					 * and outer [1] offsets.
-					 */
-					Datum	   *offset_values = palloc_array(Datum, 2);
-					bool	   *offset_isnulls = palloc_array(bool, 2);
-
-					/* Inner offset (default 0 for FIRST/LAST) */
-					if (nav->offset_arg != NULL)
-						ExecInitExprRec(nav->offset_arg, state,
-										&offset_values[0], &offset_isnulls[0]);
-					else
-					{
-						offset_values[0] = Int64GetDatum(0);
-						offset_isnulls[0] = false;
-					}
-
-					/* Outer offset (default 1 for PREV/NEXT) */
-					if (nav->compound_offset_arg != NULL)
-						ExecInitExprRec(nav->compound_offset_arg, state,
-										&offset_values[1], &offset_isnulls[1]);
-					else
-					{
-						offset_values[1] = Int64GetDatum(1);
-						offset_isnulls[1] = false;
-					}
-
-					scratch.d.rpr_nav.offset_value = offset_values;
-					scratch.d.rpr_nav.offset_isnull = offset_isnulls;
-				}
-				else if (nav->offset_arg != NULL)
-				{
-					/* Simple navigation with explicit offset */
-					Datum	   *offset_value = palloc_object(Datum);
-					bool	   *offset_isnull = palloc_object(bool);
-
-					ExecInitExprRec(nav->offset_arg, state,
-									offset_value, offset_isnull);
-					scratch.d.rpr_nav.offset_value = offset_value;
-					scratch.d.rpr_nav.offset_isnull = offset_isnull;
-				}
-				else
-				{
-					/* Simple navigation with default offset */
-					scratch.d.rpr_nav.offset_value = NULL;
-					scratch.d.rpr_nav.offset_isnull = NULL;
-				}
+				scratch.d.rpr_nav.offset = nav->offset;
+				scratch.d.rpr_nav.compound_offset = nav->compound_offset;
 
 				ExprEvalPushStep(state, &scratch);
 
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index af50a2e16d..5c26c5e848 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -6011,20 +6011,6 @@ ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans,
 	MemoryContextSwitchTo(oldContext);
 }
 
-/*
- * Extract compound (outer) offset from step data.
- * For compound nav, offset_value is an array: [0]=inner, [1]=outer.
- * Returns the outer offset; errors on NULL or negative.
- * Default is 1 (like PREV/NEXT implicit offset).
- */
-static int64
-rpr_nav_get_compound_offset(ExprEvalStep *op)
-{
-	Assert(op->d.rpr_nav.offset_value != NULL);
-
-	return DatumGetInt64(op->d.rpr_nav.offset_value[1]);
-}
-
 /*
  * Evaluate RPR navigation (PREV/NEXT/FIRST/LAST): swap slot to target row.
  *
@@ -6040,32 +6026,15 @@ ExecEvalRPRNavSet(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 {
 	WindowAggState *winstate = op->d.rpr_nav.winstate;
 	int64		offset;
+	int64		compound_offset;
 	int64		target_pos;
 	TupleTableSlot *target_slot;
 
 	/* Save current slot for later restore */
 	winstate->nav_saved_outertuple = econtext->ecxt_outertuple;
 
-	/*
-	 * Determine the inner offset.  NULL or negative offsets are errors per
-	 * the SQL standard.
-	 *
-	 * Default offset when offset_arg is NULL: PREV/NEXT: 1 (standard 5.6.2)
-	 * FIRST/LAST and compound: 0 for inner, 1 for outer
-	 */
-	if (op->d.rpr_nav.offset_value != NULL)
-	{
-		offset = DatumGetInt64(*op->d.rpr_nav.offset_value);
-	}
-	else
-	{
-		/* Default offset: 1 for simple PREV/NEXT, 0 otherwise */
-		if (op->d.rpr_nav.kind == RPR_NAV_PREV ||
-			op->d.rpr_nav.kind == RPR_NAV_NEXT)
-			offset = 1;
-		else
-			offset = 0;
-	}
+	offset = op->d.rpr_nav.offset;
+	compound_offset = op->d.rpr_nav.compound_offset;
 
 	/*
 	 * Calculate target position based on navigation direction.  On overflow,
@@ -6105,7 +6074,6 @@ ExecEvalRPRNavSet(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 		case RPR_NAV_PREV_FIRST:
 		case RPR_NAV_NEXT_FIRST:
 			{
-				int64		compound_offset;
 				int64		inner_pos;
 
 				/* Inner: match_start + offset */
@@ -6120,9 +6088,6 @@ ExecEvalRPRNavSet(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 					break;
 				}
 
-				/* Outer offset */
-				compound_offset = rpr_nav_get_compound_offset(op);
-
 				/* Apply outer: PREV subtracts, NEXT adds */
 				if (op->d.rpr_nav.kind == RPR_NAV_PREV_FIRST)
 				{
@@ -6144,7 +6109,6 @@ ExecEvalRPRNavSet(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 		case RPR_NAV_PREV_LAST:
 		case RPR_NAV_NEXT_LAST:
 			{
-				int64		compound_offset;
 				int64		inner_pos;
 
 				/* Inner: currentpos - offset */
@@ -6159,9 +6123,6 @@ ExecEvalRPRNavSet(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 					break;
 				}
 
-				/* Outer offset */
-				compound_offset = rpr_nav_get_compound_offset(op);
-
 				/* Apply outer: PREV subtracts, NEXT adds */
 				if (op->d.rpr_nav.kind == RPR_NAV_PREV_LAST)
 				{
@@ -6182,7 +6143,7 @@ ExecEvalRPRNavSet(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 			break;
 		default:
 			elog(ERROR, "unrecognized RPR navigation kind: %d",
-				 op->d.rpr_nav.kind);
+				 (int) op->d.rpr_nav.kind);
 			break;
 	}
 
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index fec21c2835..fdd69f494e 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -4074,6 +4074,9 @@ visit_nav_exec(NavTraversal *t, RPRNavExpr *nav)
 		outer = eval_nav_offset_helper(context->winstate,
 									   nav->compound_offset_arg);
 
+	nav->offset = inner;
+	nav->compound_offset = outer;
+
 	/* Backward reach: PREV, LAST-with-offset */
 	if (!context->maxOverflow)
 	{
diff --git a/src/backend/parser/parse_rpr.c b/src/backend/parser/parse_rpr.c
index ac29c26e20..87b6d8f138 100644
--- a/src/backend/parser/parse_rpr.c
+++ b/src/backend/parser/parse_rpr.c
@@ -566,6 +566,8 @@ define_walker(Node *node, void *context)
 						nav->kind = RPR_NAV_NEXT_FIRST;
 					else if (nav->kind == RPR_NAV_NEXT && inner->kind == RPR_NAV_LAST)
 						nav->kind = RPR_NAV_NEXT_LAST;
+					else
+						elog(ERROR, "Invalid compound forms: outer: %d, inner: %d", (int) nav->kind, (int) inner->kind);
 
 					nav->compound_offset_arg = nav->offset_arg;
 					nav->offset_arg = inner->offset_arg;
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index db66ebe313..0561fd8f40 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -703,9 +703,9 @@ typedef struct ExprEvalStep
 		struct
 		{
 			WindowAggState *winstate;
-			RPRNavKind	kind;	/* navigation kind (simple or compound) */
-			Datum	   *offset_value;	/* offset value(s), or NULL */
-			bool	   *offset_isnull;	/* offset null flag(s) */
+			RPRNavKind	kind;
+			int64		offset;
+			int64		compound_offset;
 			/* For compound nav: offset_value[0] = inner, [1] = outer */
 			int16		resulttyplen;	/* RESTORE: result type length */
 			bool		resulttypbyval; /* RESTORE: result pass-by-value? */
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 8ba530333b..902521ff83 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -682,11 +682,26 @@ typedef enum RPRNavKind
 typedef struct RPRNavExpr
 {
 	Expr		xpr;
-	RPRNavKind	kind;			/* navigation kind */
-	Expr	   *arg;			/* argument expression */
-	Expr	   *offset_arg;		/* offset expression, or NULL for default */
-	Expr	   *compound_offset_arg;	/* outer offset for compound nav, or
-										 * NULL if simple */
+	RPRNavKind	kind;
+	/* argument expression */
+	Expr	   *arg;
+	/* offset expression */
+	Expr	   *offset_arg;
+	/* outer offset for compound navigation */
+	Expr	   *compound_offset_arg;
+
+	/*
+	 * The computed offset value, for default value see RPRNavKind comments
+	 * above. The value will be set in visit_nav_exec.
+	 */
+	int64		offset;
+
+	/*
+	 * The computeed compound_offset offset value, for default value see
+	 * RPRNavKind comments above. The value will be set in visit_nav_exec.
+	 */
+	int64		compound_offset;
+
 	/* result type (same as arg's type) */
 	Oid			resulttype pg_node_attr(query_jumble_ignore);
 	/* OID of collation of result */
-- 
2.34.1