Re: [PATCH] Corruption Issue: Fix missing tts_tid in ExecForceStoreHeapTuple

From: Greg Burd <greg(at)burd(dot)me>
To: Greg Burd <greg(at)burd(dot)me>
Cc: Andres Freund <andres(at)anarazel(dot)de>, Nikolay Samokhvalov <nik(at)postgres(dot)ai>, Virender Singla <virender(dot)cse(at)gmail(dot)com>, PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>, Michael Paquier <michael(at)paquier(dot)xyz>, Dilip Kumar <dilipbalaut(at)gmail(dot)com>
Subject: Re: [PATCH] Corruption Issue: Fix missing tts_tid in ExecForceStoreHeapTuple
Date: 2026-10-03 16:29:12
Message-ID: 9iXtt12TSbriFROCwU71ZG6eUFbmcxAmi6y-1GqG_ywBetQQAmQQ1CCKcraiWnGMQDgegnHAJvWRrRiL66FvvuNBsZGqbFAr8cpMj6V4c4U=@burd.me
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hello.

v8 attached, code/fix is unchanged from v7 but just some cleanup of things
I'd overlooked or misunderstood so a new commit message and some additional
tests.

First, the tid2.sql case *is* fixed by this patch. I said otherwise, and
I'm sorry for the confusion. I'd tested against the wrong build, and then
misread EXPLAIN VERBOSE: the routed INSERT shows no "Remote SQL ...
RETURNING", which I took to mean ctid wasn't being requested. That remote
statement is built at execution time in postgresBeginForeignInsert(),
which passes ri_returningList through to deparseReturningList(), so ctid
is requested and make_tuple_from_result_row() does fill in t_self. What
lost it was the else (virtual-slot) branch of ExecForceStoreHeapTuple()
not setting tts_tid, which is exactly what moving the assignment to the
end (as you had suggested Andres) fixes.

Testing against a fresh build:

INSERT INTO parent_rows VALUES (2) RETURNING a, ctid;
v8: 2 | (0,2)fixes
execTuples.c reverted: 2 | (4294967295,0)

v8 drops the paragraph in v7's commit message that claimed this was a
separate postgres_fdw problem, and adds your case as a regression test
in postgres_fdw.sql, next to the existing insert tuple routing tests.
It inserts into itrtest and checks every returned ctid against
loct1/loct2, so as not to depend on page layout.

While writing it I found that only one of the two partitions in that
test shows the bug: remp1, whose columns match the parent, gets a virtual
result slot. remp2 declares (b, a), so its insert goes through a tuple
conversion map and a heap slot, which was already correct. The test
therefore reports one missing ctid rather than two without the fix.

Second, in my last mail I answered your cross-partition update comment
with "The postgres_fdw side looks like a separate patch". That attached
the FDW case to the wrong issue. As far as I can tell they're unrelated:
the FDW case was this bug, while

> cross-partition updates involving ctids just silently cause data to be
> inconsistent with the partition constraints :(.

is something else. I tried a few obvious shapes, a ctid-keyed UPDATE that
moves the row, a ctid-only predicate that matches (0,1) in two
partitions, and a ctid taken from a subquery against another partition,
and they all came out consistent with the partition constraints. So I
haven't found your case. Could you share what you ran? I'm happy to work
on it in a new thread.

On attribution, I'll answer my own question from last time, I've used
Co-authored-by: me and Virender, and Reported-by: you for the FDW
path. Tell me if you'd rather it were different.

Backpatching: v8 applies as-is to master and 15 through 18. On 14 the
execTuples.c hunk applies, but both test hunks need placing by hand
because gist.sql and postgres_fdw.sql have grown since. Both blocks are
self-contained and go in unchanged. I built 14 with --enable-cassert and
the placed postgres_fdw test passes with the fix and fails without it
(ctid_not_found 0 -> 1), the same as on master.

Apologies for rushing out the last email.

best.

-greg

Attachment Content-Type Size
v8-0001-Maintain-tts_tid-in-ExecForceStoreHeapTuple.patch text/x-patch 10.9 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Tom Lane 2026-10-03 16:39:29 Re: Coverage with make coverage-html is broken on latest Debian using lcov v2
Previous Message Rui Zhao 2026-10-03 16:27:36 Re: SSI can miss conflicts between index-only scans and heap writes