Re: Fix missing EvalPlanQual recheck for TID scans

Sophie Alpert <pg@sophiebits.com>

From: "Sophie Alpert" <pg@sophiebits.com>
To: "Chao Li" <li.evan.chao@gmail.com>
Cc: "David Rowley" <dgrowleyml@gmail.com>, pgsql-hackers@lists.postgresql.org
Date: 2025-09-15T03:09:32Z
Lists: pgsql-hackers
On Sun, Sep 14, 2025 at  6:49 PM, Chao Li <li.evan.chao@gmail.com> wrote:
> This is a wrong example and (0,3) should NOT be updated. According to the definition of “read committed”:
> https://www.postgresql.org/docs/current/transaction-iso.html#XACT-READ-COMMITTED
> “A query sees only data committed before the query began”.

You paraphrased the docs here but did so incorrectly: the actual quote is "a SELECT query (without a FOR UPDATE/SHARE clause) sees only data committed before the query began". We are not discussing the behavior of a plain SELECT query so this description is not relevant. For Update and LockRows, the expected EvalPlanQual behavior is that rows are checked against the predicate twice — once as of the statement snapshot and once as of locking time — and the rows that match both times are used.

In my example with ctid (0,3), the row matches the 'ctid = (0,1) OR ctid = (0,3)' predicate both times. The row is not newly created, so the newly-created row in your example is not analogous.

I continue to believe that my implementation of TidRecheck plainly satisfies the contract for what the scan recheck is meant to do; the fact that it matches the enable_tidscan=OFF behavior is further corroboration of that fact.

Sophie



Commits

  1. Add missing EPQ recheck for TID Range Scan

  2. Add missing EPQ recheck for TID Scan

  3. Repair problems with EvalPlanQual where target table is scanned as

  4. Tid access method feature from Hiroshi Inoue, Inoue@tpf.co.jp