| From: | "Zhijie Hou (Fujitsu)" <houzj(dot)fnst(at)fujitsu(dot)com> |
|---|---|
| To: | Amit Kapila <amit(dot)kapila16(at)gmail(dot)com> |
| Cc: | Matthias van de Meent <boekewurm+postgres(at)gmail(dot)com>, Shinya Kato <shinya11(dot)kato(at)gmail(dot)com>, PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org> |
| Subject: | RE: Logical replication row filter loses unchanged toasted columns |
| Date: | 2026-08-17 15:28:04 |
| Message-ID: | TY4PR01MB17718D001102126DA402F622994A72@TY4PR01MB17718.jpnprd01.prod.outlook.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
On Monday, August 17, 2026 3:43 PM Amit Kapila <amit(dot)kapila16(at)gmail(dot)com> wrote:
>
> On Fri, Aug 14, 2026 at 10:09 PM Zhijie Hou (Fujitsu) <houzj(dot)fnst(at)fujitsu(dot)com>
> wrote:
> >
> > 0001: heap_update check
> >
>
> Few comments on 0001:
Thanks for the comments.
> ===================
> 1.
> @@ -3453,6 +3478,34 @@ heap_update(Relation relation, const
> ItemPointerData *otid, HeapTuple newtup,
> id_attrs, &oldtup,
> newtup, &id_has_external);
>
> + id_changed = bms_overlap(modified_attrs, id_attrs);
> +
> + /*
> + * If the update could be transformed into an insert by a publication
> + row
> + * filter during decoding, reject it when it would lose an unchanged
> + * out-of-line value of a column that is not part of the replica identity.
> + */
> + if (check_unchanged_external && id_changed)
>
> Why did you place the above check in heap_update before label l2? If the
> check ran before l2: (e.g. right where modified_attrs/id_key_changed are first
> computed), a raised
> ereport(ERROR) there could fire for an update attempt that was never actually
> going to happen, the row might get updated by someone else in the interim,
> EvalPlanQual retries with a different row version, and our error would have
> been wrong or at least premature. Placing the check after the TM_Ok
> confirmation and after the VM-pin retry (i.e.
> after every goto l2 site) guarantees no more retries follow, so raising the error
> here means the update really was about to proceed against this exact tuple.
Right, I agree we should move this after l2.
>
> 2. Can we check the required value from relation's pubdesc before calling
> RelationBuildPublicationDesc()?
I think we can do this by adding a new relcache API that only accesses the new
flag. I've done that in this version.
>
> > I haven't added doc yet, but I can add it once we reach consensus.
> >
>
> Feel free to add where required.
Added.
Here's the updated version.
In this version, I extended pub_rf_contains_invalid_column to also check for row
filter existence, rather than adding a new function. This is fine for HEAD, but
for back branches we typically avoid changing public interfaces, so a new
function might be needed there. However, since this is an internal cache
function and I couldn't find any extensions (via GitHub or Debian code search)
that use it, changing the interface is probably acceptable.
I am sharing one version v2_PG18 that does not change existing function
interface for PG18 for reference.
BTW, I also couldn't find any extensions that depend on the size of this struct, so
I personally think backpatching should be fine.
Best Regards,
Zhijie Hou
| Attachment | Content-Type | Size |
|---|---|---|
| v2-0001-Reject-UPDATEs-that-would-silently-lose-a-row-fil.patch | application/octet-stream | 18.3 KB |
| v2-PG18-0001-Reject-UPDATEs-that-would-silently-lose-a-row-fil.patch | application/octet-stream | 18.6 KB |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Bharath Rupireddy | 2026-08-17 15:34:00 | Re: Infinite Autovacuum loop caused by failing virtual generated column expression |
| Previous Message | Álvaro Herrera | 2026-08-17 15:16:46 | Re: [PATCH] ternary reloption type |