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