Logical Replication: Revisiting is_table_publication and is_schema_publication Implementation
Core Problem
In PostgreSQL's logical replication subsystem, two internal functions — is_table_publication() and is_schema_publication() — determine the "type" of a publication by scanning system catalogs. Specifically:
is_table_publication()checks whether a publication was created with aFOR TABLE t1clause by scanningpg_publication_rel.is_schema_publication()checks whether a publication was created with aFOR TABLES IN SCHEMA s1clause by scanningpg_publication_namespace.
These functions are called during ALTER PUBLICATION operations, particularly when adding EXCEPT clauses or modifying publication membership. The existing implementations unconditionally perform catalog scans (via SysScanDesc) even in cases where the answer can be trivially derived from the publication's Form_pg_publication metadata — specifically the puballtables and puballsequences boolean flags.
The key architectural invariant being exploited is that FOR ALL TABLES, FOR ALL SEQUENCES, FOR TABLE ..., and FOR TABLES IN SCHEMA ... are mutually exclusive publication modes. This means:
- If
puballtablesis true, the publication cannot simultaneously have entries inpg_publication_rel(for individual tables) orpg_publication_namespace(for schemas). - Similarly, if
puballsequencesis true, the same exclusivity applies.
Therefore, both functions can short-circuit and return false immediately when either of these flags is set, avoiding unnecessary catalog scans entirely.
Proposed Solution
Patch v1
The initial patch adds an early-return check at the top of both is_table_publication() and is_schema_publication():
/* FOR TABLE / FOR TABLES IN SCHEMA cannot coexist with FOR ALL TABLES. */
if (pubform->puballtables)
return false;
Additional cleanup includes:
- Removing the
prexceptcheck fromis_table_publication(). The original code apparently inspected whether rows inpg_publication_relhad theprexceptflag set (indicating EXCEPT entries rather than positive table membership). The patch author argues this check is unnecessary given the short-circuit logic, though the thread doesn't deeply explore whether this removal is fully safe in all edge cases. - Making both functions structurally parallel, improving code consistency and maintainability.
Patch v2
After Shveta Malik pointed out that FOR ALL SEQUENCES is also mutually exclusive with FOR TABLE and FOR TABLES IN SCHEMA (a constraint the patch author initially missed), v2 adds an analogous short-circuit:
if (pubform->puballsequences)
return false;
This ensures completeness: all three "global" publication modes (puballtables, puballsequences, and potentially future ones) are handled before falling through to the catalog scan path.
Where the Optimization Actually Helps
Shveta Malik's analysis in her April 9 message is the most architecturally precise in the thread. She identifies the specific code path where the optimization provides real benefit:
-
Adding EXCEPT to an ALL TABLES publication: This is a valid, non-erroneous operation. Before this patch,
is_table_publication()andis_schema_publication()would scanpg_publication_relandpg_publication_namespacerespectively, only to find no rows. With the patch, they returnfalseimmediately. -
Adding tables/schemas to an ALL TABLES publication: This errors out in
CheckAlterPublication()before these functions are called, so the optimization doesn't help here. -
Adding tables/schemas to a normal (non-ALL) publication: The catalog scan is still needed to determine the publication's actual membership, so the optimization doesn't help here either.
-
Error paths (e.g., adding EXCEPT to a FOR TABLE publication): The scan is still required to distinguish between a publication with actual table entries vs. an empty publication.
The optimization is therefore narrowly targeted but hits a valid production code path — specifically the EXCEPT clause workflow on ALL TABLES publications.
Technical Tradeoffs
- Cost of the check: A single boolean comparison against
pubform->puballtables(andpuballsequencesin v2) — essentially free, aspubformis already in memory. - Benefit: Avoids opening
pg_publication_rel/pg_publication_namespace, setting up a scan key, performing an index scan, and closing the relation. Even if the scan finds zero rows quickly, there's non-trivial overhead in the relation open/close and scan setup. - Code clarity: The patch makes both functions structurally identical (check flags → scan catalog → return result), which is a maintainability win.
- Removal of
prexceptcheck: This is the least-discussed aspect and potentially the most consequential. Ifis_table_publication()previously filtered out EXCEPT-only entries to avoid false positives, removing that logic needs careful validation. The thread doesn't fully resolve whether this is safe in all cases.
Open Questions and Status
The patch received generally positive feedback but stalled without a committer picking it up. As of the last message (May 18, 2026), the author is seeking guidance on how to advance it. The patch lacks:
- Committer review: No committer has weighed in on the thread.
- Deep analysis of the
prexceptremoval: The simplification ofis_table_publication()to no longer checkprexceptdeserves more scrutiny. - Regression test coverage: No discussion of whether existing tests cover the optimized paths or whether new tests are needed.
This is a minor optimization/cleanup patch — the kind that often languishes without a champion among committers, particularly during busy development cycles.