Re: Row pattern recognition
Tatsuo Ishii <ishii@postgresql.org>
From: Tatsuo Ishii <ishii@postgresql.org>
To: assam258@gmail.com
Cc: zsolt.parragi@percona.com, vik@postgresfriends.org, er@xs4all.nl,
jacob.champion@enterprisedb.com, david.g.johnston@gmail.com,
peter@eisentraut.org, pgsql-hackers@postgresql.org
Date: 2026-03-16T06:47:32Z
Lists: pgsql-hackers
> I was not able to find the definition for EEOP_GT. Is this a new one?
>>
>
> You're right -- EEOP_GT does not exist. I oversimplified the example.
>
> In PostgreSQL, comparison operators like `>` are not dedicated opcodes.
> They are dispatched through EEOP_FUNCEXPR variants as regular function
> calls. For example, `price > PREV(price)`:
>
> - The parser resolves `>` to the appropriate pg_operator entry
> - The expression compiler emits an EEOP_FUNCEXPR variant
> - At runtime, op->d.func.fn_addr points to the operator function,
Ok.
> I am afraid ExecEvalExpr does not allow this because ExecEvalExpr does
>> not accept arguments like WindowObject or WindowAggState that are
>> necessary for accessing the tuplestore created for the Window
>> aggregate node.
>
>
> This is the key question. You are right that ExecEvalExpr's signature
> does not accept WindowAggState, and I do not intend to change it.
>
> The approach is to pass WindowAggState through the step's own payload,
> the same way EEOP_WINDOW_FUNC carries WindowFuncExprState in
> op->d.window_func.wfstate. Each ExprEvalStep has a union of per-opcode
> payload structs. A new payload for RPR navigation would look like:
>
> struct
> {
> WindowAggState *winstate; /* access to tuplestore */
> int64 offset; /* signed offset: PREV=-1, NEXT=+1 */
> } rpr_nav;
>
> The expression compiler (ExecInitExprRec) populates this when it
> encounters a PREV/NEXT node, storing the pointer to the enclosing
> WindowAggState. At runtime, EEOP_RPR_NAV_SET retrieves it from the
> payload and uses it to fetch the target row:
>
> /* pseudo-code for EEOP_RPR_NAV_SET */
> winstate = op->d.rpr_nav.winstate;
> /* 1. save current slot into winstate for later restore */
> winstate->saved_outertuple = econtext->ecxt_outertuple;
> /* 2. compute target position */
> target_pos = winstate->currentpos + op->d.rpr_nav.offset;
> /* 3. fetch target row from tuplestore via winstate */
> target_slot = fetch_row_from_tuplestore(winstate, target_pos);
> /* 4. swap */
> econtext->ecxt_outertuple = target_slot;
>
> /* pseudo-code for EEOP_RPR_NAV_RESTORE */
> winstate = op->d.rpr_nav.winstate;
> econtext->ecxt_outertuple = winstate->saved_outertuple;
>
> The key difference from EEOP_WINDOW_FUNC: existing steps read
> precomputed values, but PREV/NEXT requires fetching a *different*
> row at runtime -- because the target depends on the current row
> position during pattern matching, which is not known in advance.
> The mechanism for passing state is the same (step payload), but
> the runtime behavior is a departure from the existing pattern.
>
> I have examined the alternatives carefully:
>
> - The precomputation approach (EEOP_WINDOW_FUNC style) does not apply
> here: there is no fixed set of values to precompute, because the
> target row depends on the current position during pattern matching.
>
> - The three-slot model (current implementation) cannot support variable
> offsets like PREV(price, 3), and requires varno rewriting that adds
> complexity elsewhere.
>
> - A callback-based approach (registering a fetch function in econtext)
> would still require passing WindowAggState somehow, just through a
> different indirection.
>
> The step payload approach is the only path I have found that:
>
> - Leaves ExecEvalExpr's signature unchanged
> - Eliminates varno rewriting entirely
> - Supports variable offsets naturally
> - Extends to FIRST/LAST navigation later
Thank you for the detailed explanation. I agreed the approach.
> If anyone sees a cleaner path, I would genuinely welcome the
> discussion.
>
> I plan to have an experimental implementation ready before next week.
> The initial version will pass WindowAggState broadly; we can
> narrow the interface to the minimum required during review.
> Let's continue the discussion with actual code.
Looking forward to reviewing the implementation.
Best regards,
--
Tatsuo Ishii
SRA OSS K.K.
English: http://www.sraoss.co.jp/index_en/
Japanese:http://www.sraoss.co.jp
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Adjust cross-version upgrade tests for seg_out() fix
- 3e3d7875e956 19 (unreleased) cited
-
Rationalize error comments in partition split/merge tests
- ecb2508aaf9b 19 (unreleased) cited
-
Add fast path for foreign key constraint checks
- 2da86c1ef9b5 19 (unreleased) cited
-
Fix assorted pretty-trivial memory leaks in the backend.
- e78d1d6d47dc 19 (unreleased) cited
-
Add temporal FOREIGN KEY contraints
- 89f908a6d0ac 18.0 cited
-
Add trailing commas to enum definitions
- 611806cd726f 17.0 cited
-
Remove obsolete executor cleanup code
- d060e921ea5a 17.0 cited