Re: Row pattern recognition

From: Henson Choi <assam258(at)gmail(dot)com>
To: Tatsuo Ishii <ishii(at)postgresql(dot)org>
Cc: zsolt(dot)parragi(at)percona(dot)com, vik(at)postgresfriends(dot)org, er(at)xs4all(dot)nl, jacob(dot)champion(at)enterprisedb(dot)com, david(dot)g(dot)johnston(at)gmail(dot)com, peter(at)eisentraut(dot)org, pgsql-hackers(at)postgresql(dot)org
Subject: Re: Row pattern recognition
Date: 2026-03-14 14:14:26
Message-ID: CAAAe_zDrCxodQG+ybLnUqo7t6e8g9kU7PEZfSF_KnibUe+Dh+g@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi Tatsuo,

Looks great. Do you have any idea how to let the existing ExecEvalExpr
> handle the swap/restore mechanism?

Yes. I think the key insight is that ExecEvalExpr compiles expressions into
a flat array of ExprEvalStep operations, which makes the swap/restore
natural
to implement without any changes to the ExecEvalExpr caller interface.

I should also say that this approach was shaped by the constraints you
identified early on -- the three-slot model's limitations and the need
for variable offsets. Without that clear problem framing, I would not
have thought in this direction.

The idea is to introduce two new ExprEvalOp steps:

EEOP_RPR_NAV_SET -- save current slot, swap to target row
EEOP_RPR_NAV_RESTORE -- restore original slot

These two steps bracket the inner expression steps in the flat array.

For `price > PREV(price)`:
1. EEOP_OUTER_VAR -- fetch price from current slot --> datum_a
2. EEOP_RPR_NAV_SET -- save current slot, swap to (currentpos - 1)
3. EEOP_OUTER_VAR -- fetch price from swapped slot --> datum_b
4. EEOP_RPR_NAV_RESTORE -- restore original slot
5. EEOP_GT -- evaluate datum_a > datum_b
6. EEOP_DONE

For `price > PREV(price, 3)` (with offset):
1. EEOP_OUTER_VAR -- fetch price from current slot --> datum_a
2. EEOP_CONST -- evaluate offset constant 3 --> datum_off
3. EEOP_RPR_NAV_SET -- save current slot, swap to (currentpos - 3)
4. EEOP_OUTER_VAR -- fetch price from swapped slot --> datum_b
5. EEOP_RPR_NAV_RESTORE -- restore original slot
6. EEOP_GT -- evaluate datum_a > datum_b
7. EEOP_DONE

For `price < NEXT(price)`:
1. EEOP_OUTER_VAR -- fetch price from current slot --> datum_a
2. EEOP_RPR_NAV_SET -- save current slot, swap to (currentpos + 1)
3. EEOP_OUTER_VAR -- fetch price from swapped slot --> datum_b
4. EEOP_RPR_NAV_RESTORE -- restore original slot
5. EEOP_LT -- evaluate datum_a < datum_b
6. EEOP_DONE

ExprState holds the flat array of ExprEvalSteps, and each step carries
its own payload. The RPR navigation steps would store a pointer to the
window execution state in their payload, so that they can access the
current row position and the tuplestore at evaluation time. Since
PREV/NEXT are only permitted in the DEFINE clause, the window execution
state is always valid when these steps are evaluated, which eliminates
the risk of accessing stale or invalid state.

The EEOP_RPR_NAV_SET step would:
1. Save the current slot for later restore
2. Compute the target position from currentpos and the direction offset
3. Fetch the corresponding TupleTableSlot from the tuplestore
4. Replace econtext->ecxt_outertuple with the target slot

The EEOP_RPR_NAV_RESTORE step would:
1. Retrieve the previously saved slot
2. Restore econtext->ecxt_outertuple to the original slot

This design also fits well with the future roadmap for FIRST/LAST
navigation.
Once the match history infrastructure is in place, FIRST/LAST can look
up the first or last row matched by a given pattern variable from the
history, compute the target position from that, and pass it to
EEOP_RPR_NAV_SET -- the save/restore mechanism itself stays the same.

I would like to work on an experimental implementation of this approach,
including the parser-level check to reject nested PREV/NEXT calls as
required by the standard. The nesting check will be part of the same
implementation rather than a separate fix, as the parser structure may
need to be adjusted as part of the redesign anyway.

Since the expression compilation infrastructure is not an area I am
deeply familiar with, it may take some time to get right. I would
appreciate your patience in reviewing it when it is ready.

Best regards,
Henson

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Jelte Fennema-Nio 2026-03-14 14:16:56 Re: Bump soft open file limit (RLIMIT_NOFILE) to hard limit on startup
Previous Message Jelte Fennema-Nio 2026-03-14 14:03:20 Re: RFC: adding pytest as a supported test framework