Re: Support EXCEPT for TABLES IN SCHEMA publications

From: Nisha Moond <nisha(dot)moond412(at)gmail(dot)com>
To: shveta malik <shveta(dot)malik(at)gmail(dot)com>
Cc: Peter Smith <smithpb2250(at)gmail(dot)com>, Amit Kapila <amit(dot)kapila16(at)gmail(dot)com>, Zsolt Parragi <zsolt(dot)parragi(at)percona(dot)com>, pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: Re: Support EXCEPT for TABLES IN SCHEMA publications
Date: 2026-07-15 16:46:13
Message-ID: CABdArM7B8-KsLc5nSBWnT658iTzcM2TaMTkA=iRuYgDYMsrG_Q@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Mon, Jul 13, 2026 at 3:31 PM shveta malik <shveta(dot)malik(at)gmail(dot)com> wrote:
>
> On Fri, Jul 10, 2026 at 5:07 PM Nisha Moond <nisha(dot)moond412(at)gmail(dot)com> wrote:
> >
> >
> > Yes, that works for me as we have FOR TABLES example to follow. I've
> > made the changes in v20.
> >
>
> Thanks! I had a quick look, few initial comments:
>
>
> 1)
> GetTopMostAncestorInPublication():
>
> + if (ancestors == NIL)
> + return InvalidOid;
>
> Should this be Assert or can there be a case where ancestors list can
> come as NIL?
>

I found one case where ancestors can be NIL.
Test case:
CREATE TABLE t1 (a int) PARTITION BY RANGE (a);
CREATE TABLE t1_part PARTITION OF t1 FOR VALUES FROM (1) TO (100);
CREATE PUBLICATION mypub FOR TABLE t1;

-- Get the partition into the pending-detach state:
-- Session A:
BEGIN;
SELECT * FROM t1;
-- leave open

-- Session B (blocks, waiting on Session A's lock on t1):
ALTER TABLE t1 DETACH PARTITION t1_part CONCURRENTLY;

-- Session C, while B is blocked:
SELECT * FROM pg_get_publication_tables('{mypub}'::text[],
't1_part'::regclass);

In this scenario, Session C reaches GetTopMostAncestorInPublication()
with ancestors == NIL. So I think we should keep return InvalidOid;
rather than replacing it with an Assert.

While investigating this race, I also hit assertions at places that
call "llast_oid(ancestors)" without checking for NIL, for example in
check_publication_add_relation() and RelationBuildPublicationDesc(). I
fixed those by guarding with if (ancestors != NIL).

But due to this same race, other existing callers of llast_oid() on
HEAD that assume ancestors is never NIL can also hit the following
assertion:
"TRAP: failed Assert("list != NIL"), File:
"../../../../src/include/nodes/pg_list.h" ..."

One such case is pgoutput.c:get_rel_sync_entry(). To reproduce on HEAD:
-- create a slot
SELECT pg_create_logical_replication_slot('myslot', 'pgoutput');

-- get the partition into the pending-detach state (using same A & B
sessions), and in session C run -
INSERT INTO t1_part VALUES (5);
SELECT * FROM pg_logical_slot_get_binary_changes('myslot', NULL, NULL,
'proto_version', '1', 'publication_names', 'mypub');

I think this should be handled separately after analyzing whether
there's a better fix than simply adding if (ancestors != NIL) guards
at each call site.
Note: Other callers of llast_oid(ancestors) may need similar review.

Thoughts?

> 2)
> GetAllSchemaPublicationRelations
>
> + if (!excluded && get_rel_relispartition(relid))
> + {
> + List *ancestors = get_partition_ancestors(relid);
> + ListCell *alc;
> +
> + foreach(alc, ancestors)
> + {
> + if (list_member_oid(except_relids, lfirst_oid(alc)))
> + {
> + excluded = true;
> + break;
> + }
> + }
> + list_free(ancestors);
> + }
>
> Should we check root only in except_relids instead of complete ancestor chain?
>

yes, corrected.

> 3)
> postgres=# ALTER TABLE s2.tab_root_new ATTACH PARTITION s2.tab_root
> FOR VALUES FROM (1) TO (2000);
> ERROR: 55000: cannot attach table "tab_root" as partition because it
> is referenced in publication "pub1" EXCEPT clause
> DETAIL: The publication EXCEPT clause cannot contain tables that are
> partitions.
> HINT: Change the publication's EXCEPT clause using ALTER PUBLICATION
> ... SET ALL TABLES.
> LOCATION: ATExecAttachPartition, tablecmds.c:21107
>
> pub1 is a schmea publication table here, I think HINT needs some adjustment.
>

Fixed.

> 4)
> + root_tup = SearchSysCache2(PUBLICATIONRELMAP,
> + ObjectIdGetDatum(llast_oid(ancestors)),
> + ObjectIdGetDatum(pub->oid));
> + if (HeapTupleIsValid(root_tup))
> + {
> + bool root_except = ((Form_pg_publication_rel) GETSTRUCT(root_tup))->prexcept;
> +
> + ReleaseSysCache(root_tup);
> + if (root_except)
> + return false;
> + }
>
> Above code snipet appears a lot many times either for relid or
> llast_oid(ancestors), can we replace this with a common function like:
>
> bool lookup_pub_relmap(Oid pubid, Oid relid, bool *is_except); (or
> get_publication_rel_entry or anything which you find better)
>
> The return value will indicate when the relid is present. 'is_except'
> will indicate whetehr it is marked with except flag or not. Then above
> can be replaced with:
>
> if (lookup_pub_relmap(pub->oid, llast_oid(ancestors), &root_except)
> && root_except)
> return false;
>
> Do this only if you feel it will simplify the code and apply it where it helps.
>

You're right. The same check appears in five places. I replaced it
with a helper function, get_publication_rel_entry(), which
significantly reduces code duplication.
~~~

Attached is the v21 patch set addressing the above changes, along with
all other comments for v20 at [1], [2], and [3].

[1] https://www.postgresql.org/message-id/CAJpy0uCFCdL97L3Pt8f586br5irqkzCa_i3tXMjH6JFCPxxr4Q%40mail.gmail.com
[2] https://www.postgresql.org/message-id/CAHut%2BPuJE947Y3WPo%2BcaEpEojQdRXryS2KjBLBr12rb9RQ95Zw%40mail.gmail.com
[3] https://www.postgresql.org/message-id/CAHut%2BPsGg7Pi2CM5eBjb8s6FCPb5XmyWaBUxPrDSzt_2wK4Gfg%40mail.gmail.com

--
Thanks,
Nisha

Attachment Content-Type Size
v21-0001-Support-EXCEPT-clause-for-schema-level-publicati.patch application/x-patch 78.7 KB
v21-0002-Restrict-conflicting-EXCEPT-lists-in-multi-schem.patch application/x-patch 14.9 KB
v21-0003-Add-EXCEPT-support-to-ALTER-PUBLICATION-ADD-TABL.patch application/x-patch 21.9 KB
v21-0004-Add-EXCEPT-support-to-ALTER-PUBLICATION-SET-TABL.patch application/x-patch 27.4 KB
v21-0005-Documentation-Patch.patch application/x-patch 11.6 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Nisha Moond 2026-07-15 16:48:17 Re: Support EXCEPT for TABLES IN SCHEMA publications
Previous Message Tristan Partin 2026-07-15 16:30:47 Re: meson: avoid PATH bloat from NLS .mo targets in tmp_install test setup