From 283157f1e47eec2e64668fef65db8176599f697c Mon Sep 17 00:00:00 2001 From: jian he 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