On Tue, Sep 8, 2026 at 10:42 AM shveta malik <[email protected]> wrote:
>
>
> I tested it further on my machine. Here are the observations:
>
>
> 2)
> FOR TABLE root pub:
> During the intermediate state of DETACH PARTITION ... CONCURRENTLY,
> changes made directly to the partition being detached (t1_part1) are
> also replicated, even though t1_part1 is not explicitly listed in
> pg_publication_tables and pg_partition_root(t1_part1) already returns
> t1_part1. This needs some thought regarding how it should behave.
> Should t1_part1 not replicated here? Thoughts?
>
> Once the detach completes, changes to t1_part1 are no longer
> replicated through the publication of t1, which appears correct.

On debugging further, t1_part1 is also replicated (incorrectly IMO) in
Case 2 because pgoutput's RelationSyncCache is not invalidated during
the first phase of DETACH PARTITION CONCURRENTLY.

In ATExecDetachPartition(), MarkInheritDetached() only updates the
partition's pg_inherits row (inhdetachpending = true), without
generating a cache invalidation. Before commit, only the parent's
relcache is explicitly invalidated via CacheInvalidateRelcache(rel) in
ATExecDetachPartition().

As a result, the partition's previously cached (pre-detach)
RelationSyncEntry is reused, so changes to it continue to be
replicated. This is also confirmed by the fact that if no INSERT is
executed on t1_part1 before DETACH CONCURRENTLY blocks, replication
behaves correctly: the partition is not replicated because a new
RelationSyncCache entry is correctly built after inhdetachpending is
set.

Once FINALIZE runs, the issue self-corrects because
DetachPartitionFinalize() updates the partition's pg_class row
(relispartition = false), which invalidates its relcache, and also
DetachPartitionFinalize() explicitly invalidates the parent and
descendants.

Adding cache-invalidation for part-table here solves the problem, but
I am not sure if it could have any other side-effects. Please have a
look.

@@ -21758,6 +21758,8 @@ ATExecDetachPartition(List **wqueue,
AlteredTableInfo *tab, Relation rel,
                /* Invalidate relcache entries for the parent -- must
be before close */
                CacheInvalidateRelcache(rel);

+               CacheInvalidateRelcache(partRel);
+
                table_close(partRel, NoLock);
                table_close(rel, NoLock);
                tab->rel = NULL;

thanks
Shveta


Reply via email to