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