Re: Fix missing EvalPlanQual recheck for TID scans

From: Chao Li <li(dot)evan(dot)chao(at)gmail(dot)com>
To: Sophie Alpert <pg(at)sophiebits(dot)com>
Cc: David Rowley <dgrowleyml(at)gmail(dot)com>, pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: Re: Fix missing EvalPlanQual recheck for TID scans
Date: 2025-09-11 05:30:20
Message-ID: C901CB5D-7E79-4125-B310-C5A3052196A8@gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

> On Sep 10, 2025, at 13:18, Chao Li <li(dot)evan(dot)chao(at)gmail(dot)com> wrote:
>
> With my proposal, my theory is that, TidNext() fetches a tuple by ctid, if other concurrent transaction update/delete the tuple, the tuple's visibility changes.
>

I did some more debugging on this issue today, and I withdraw my previous proposal of checking visibility.

I can confirm that, every time when TidRecheck() is called, “node” is brand new, so the current patch do duplicately calculate TidListEval().

But, why can't we make TidRecheck() to simplify return FALSE?

Looks like the only case where TidRecheck() is called is a concurrent transaction upadated the row, and in that case, ctid have must be changed.

The following case WON’T call TidRecheck():

Case 1. Concurrent delete
=====
S1:
Begin;
delete t where ctid = ‘(0,1)’

S2:
Update t set something where ctid = ‘(0,1)’; // block

S1:
Commit;

S2 will just fail to update the row because the row has been deleted by s1.

Case 2: select for update/share
======
S1:
Begin;
Select * from t where ctid = ‘(0,1)’ for share;

S2:
Update t set something where ctid = ‘(0,1)’; // block

S1:
Commit;

S2 will just successfully update the row, because s1 release the lock and the row is still there.

Case 3: join update
======
S1:
Begin;
Update t2 set something where id = 1;

S2:
Update t2 set something where id = (select id from t where ctid = ‘(0, 1)’); // block

S1: commit

S2 will successfully update t2’s row. In this process, index scan’t recheck against t2 will be called, TidRecheck() against t will not be called.
======

Unless I missed some cases, we can simply return FALSE from TidRecheck().

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Robins Tharakan 2025-09-11 05:31:43 Re: someone else to do the list of acknowledgments
Previous Message Shlok Kyal 2025-09-11 05:30:02 Re: issue with synchronized_standby_slots