On Sun, Sep 14, 2025 at 6:49 PM, Chao Li <[email protected]> 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
