Hi Chao,

Thanks for taking a look.

On Tue, Sep  9, 2025 at 12:52 AM, Chao Li <li.evan.c...@gmail.com> wrote:
> However, I noticed that, when “TidRecheck()” is called, it is actually passed 
> with “epqstate->recheckplanstate” that is always newly created, which means 
> we repeatedly call “TidListEval(node)” and run “bsearch()” when there are 
> multiple row involved in the update. If update qual is just “ctid = <a single 
> ctid>”, that should fine. But if we do “update .. where ctid in (a list of 
> ctid)”, then duplicately call “TidListEval()” might not be a good thing.

Based on my current understanding, the EPQ PlanState is shared across all EPQ
checks for a given plan and that ReScan is called at similar times as it is for
the initial access path with, ExecScanFetch delegating to the appropriate *Next
or *Recheck method as each row is processed. Therefore, my patch does not
recompute the TidList for every row.

> As “TidRecheck(TidScanState *node, TupleTableSlot *slot)” gets the second 
> parameter “slot” with the updated slot, so I am thinking the other solution 
> could be that, we just check if the updated slot is visible to current 
> transaction. So I made a local change like this:
> 
> ...
> tuple = ExecCopySlotHeapTuple(slot);
> visible = HeapTupleSatisfiesVisibility(tuple, GetActiveSnapshot(), 
> slot->tts_tableOid);

This is semantically different from the patch I've proposed. My test
`permutation tid1 tidsucceed2 c1 c2 read` fails against your code, despite
passing with the `SET enable_tidscan = OFF;` flag that I understand we want to
match the behavior of. (In addition, I understand HeapTupleSatisfiesVisibility
is specific to the heap access method and can't be used here, though perhaps
tuple_fetch_row_version could be used instead.)

Sophie


Reply via email to