From b1bab0a22d811d9d3de457e29ed2d7cae123b108 Mon Sep 17 00:00:00 2001 From: Euler Taveira Date: Tue, 16 Dec 2025 11:30:42 -0300 Subject: [PATCH v1] Fix unsupported relations for publications Although publication check for unsupported relations for the table list, it is not checking the partitions of a partitioned table. The consequence is that data from this partitioned table is not replicated. Inheritance is already covered because parent and children tables are included in the publication-relation mapping. There is no test coverage for this case so add it. This is not a complete solution. SQL commands that manipulate the partitioned table (ALTER TABLE ... ATTACH PARTITION, ALTER TABLE ... SET UNLOGGED, CREATE TABLE ... PARTITION OF) might break this contract. --- src/backend/catalog/pg_publication.c | 18 +++++++++++--- src/test/regress/expected/publication.out | 29 ++++++++++++++++++++++- src/test/regress/sql/publication.sql | 24 ++++++++++++++++++- 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c index 7aa3f179924..306187012fb 100644 --- a/src/backend/catalog/pg_publication.c +++ b/src/backend/catalog/pg_publication.c @@ -466,8 +466,23 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri, RelationGetRelationName(targetrel), pub->name))); } + /* + * Check for supported relation. For partitioned tables, all partitions + * should be supported relations too. + */ check_publication_add_relation(targetrel); + relids = GetPubPartitionOptionRelations(relids, PUBLICATION_PART_ALL, + relid); + foreach_oid(partoid, relids) + { + Relation partrel = RelationIdGetRelation(partoid); + + check_publication_add_relation(partrel); + RelationClose(partrel); + } + + /* Validate and translate column names into a Bitmapset of attnums. */ attnums = pub_collist_validate(pri->relation, pri->columns); @@ -537,9 +552,6 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri, * mentioned in the publication. This is required because we implicitly * publish the child tables when the parent table is published. */ - relids = GetPubPartitionOptionRelations(relids, PUBLICATION_PART_ALL, - relid); - InvalidatePublicationRels(relids); return myself; diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out index e72d1308967..e6638c6e517 100644 --- a/src/test/regress/expected/publication.out +++ b/src/test/regress/expected/publication.out @@ -326,6 +326,20 @@ ERROR: invalid publication object list LINE 1: ...equences_alltables FOR ALL SEQUENCES, ALL TABLES, ALL SEQUEN... ^ DETAIL: ALL SEQUENCES can be specified only once. +-- Tests for inheritance +CREATE TABLE testpub_inh (a int); +CREATE TABLE testpub_inh1 () INHERITS(testpub_inh); +CREATE TEMPORARY TABLE testpub_inh2 () INHERITS(testpub_inh); +SET client_min_messages = 'ERROR'; +-- fail - unsupported relation as a child relation +CREATE PUBLICATION testpub_inh FOR TABLE testpub_inh; +ERROR: cannot add relation "testpub_inh2" to publication +DETAIL: This operation is not supported for temporary tables. +ALTER TABLE testpub_inh2 NO INHERIT testpub_inh; +CREATE PUBLICATION testpub_inh FOR TABLE testpub_inh; +RESET client_min_messages; +DROP TABLE testpub_inh, testpub_inh1, testpub_inh2; +DROP PUBLICATION testpub_inh; -- Tests for partitioned tables SET client_min_messages = 'ERROR'; CREATE PUBLICATION testpub_forparted; @@ -333,9 +347,22 @@ CREATE PUBLICATION testpub_forparted1; RESET client_min_messages; CREATE TABLE testpub_parted1 (LIKE testpub_parted); CREATE TABLE testpub_parted2 (LIKE testpub_parted); +CREATE UNLOGGED TABLE testpub_parted3 (LIKE testpub_parted); ALTER PUBLICATION testpub_forparted1 SET (publish='insert'); ALTER TABLE testpub_parted ATTACH PARTITION testpub_parted1 FOR VALUES IN (1); ALTER TABLE testpub_parted ATTACH PARTITION testpub_parted2 FOR VALUES IN (2); +ALTER TABLE testpub_parted ATTACH PARTITION testpub_parted3 FOR VALUES IN (3); +-- fail - unsupported relation as a partition +SET client_min_messages = 'ERROR'; +CREATE PUBLICATION testpub_forparted2 FOR TABLE testpub_parted; +ERROR: cannot add relation "testpub_parted3" to publication +DETAIL: This operation is not supported for unlogged tables. +RESET client_min_messages; +-- fail - unsupported relation as a partition +ALTER PUBLICATION testpub_forparted ADD TABLE testpub_parted; +ERROR: cannot add relation "testpub_parted3" to publication +DETAIL: This operation is not supported for unlogged tables. +ALTER TABLE testpub_parted DETACH PARTITION testpub_parted3; -- works despite missing REPLICA IDENTITY, because updates are not replicated UPDATE testpub_parted1 SET a = 1; -- only parent is listed as being in publication, not the partition @@ -373,7 +400,7 @@ HINT: To enable updating the table, set REPLICA IDENTITY using ALTER TABLE. ALTER PUBLICATION testpub_forparted DROP TABLE testpub_parted; -- works again, because update is no longer replicated UPDATE testpub_parted2 SET a = 2; -DROP TABLE testpub_parted1, testpub_parted2; +DROP TABLE testpub_parted1, testpub_parted2, testpub_parted3; DROP PUBLICATION testpub_forparted, testpub_forparted1; -- Tests for row filters CREATE TABLE testpub_rf_tbl1 (a integer, b text); diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql index 00390aecd47..b5a4c291516 100644 --- a/src/test/regress/sql/publication.sql +++ b/src/test/regress/sql/publication.sql @@ -166,6 +166,19 @@ CREATE PUBLICATION regress_pub_for_allsequences_alltables FOR ALL SEQUENCES, ALL -- fail - Specifying ALL SEQUENCES more than once CREATE PUBLICATION regress_pub_for_allsequences_alltables FOR ALL SEQUENCES, ALL TABLES, ALL SEQUENCES; +-- Tests for inheritance +CREATE TABLE testpub_inh (a int); +CREATE TABLE testpub_inh1 () INHERITS(testpub_inh); +CREATE TEMPORARY TABLE testpub_inh2 () INHERITS(testpub_inh); +SET client_min_messages = 'ERROR'; +-- fail - unsupported relation as a child relation +CREATE PUBLICATION testpub_inh FOR TABLE testpub_inh; +ALTER TABLE testpub_inh2 NO INHERIT testpub_inh; +CREATE PUBLICATION testpub_inh FOR TABLE testpub_inh; +RESET client_min_messages; +DROP TABLE testpub_inh, testpub_inh1, testpub_inh2; +DROP PUBLICATION testpub_inh; + -- Tests for partitioned tables SET client_min_messages = 'ERROR'; CREATE PUBLICATION testpub_forparted; @@ -173,9 +186,18 @@ CREATE PUBLICATION testpub_forparted1; RESET client_min_messages; CREATE TABLE testpub_parted1 (LIKE testpub_parted); CREATE TABLE testpub_parted2 (LIKE testpub_parted); +CREATE UNLOGGED TABLE testpub_parted3 (LIKE testpub_parted); ALTER PUBLICATION testpub_forparted1 SET (publish='insert'); ALTER TABLE testpub_parted ATTACH PARTITION testpub_parted1 FOR VALUES IN (1); ALTER TABLE testpub_parted ATTACH PARTITION testpub_parted2 FOR VALUES IN (2); +ALTER TABLE testpub_parted ATTACH PARTITION testpub_parted3 FOR VALUES IN (3); +-- fail - unsupported relation as a partition +SET client_min_messages = 'ERROR'; +CREATE PUBLICATION testpub_forparted2 FOR TABLE testpub_parted; +RESET client_min_messages; +-- fail - unsupported relation as a partition +ALTER PUBLICATION testpub_forparted ADD TABLE testpub_parted; +ALTER TABLE testpub_parted DETACH PARTITION testpub_parted3; -- works despite missing REPLICA IDENTITY, because updates are not replicated UPDATE testpub_parted1 SET a = 1; -- only parent is listed as being in publication, not the partition @@ -195,7 +217,7 @@ UPDATE testpub_parted2 SET a = 2; ALTER PUBLICATION testpub_forparted DROP TABLE testpub_parted; -- works again, because update is no longer replicated UPDATE testpub_parted2 SET a = 2; -DROP TABLE testpub_parted1, testpub_parted2; +DROP TABLE testpub_parted1, testpub_parted2, testpub_parted3; DROP PUBLICATION testpub_forparted, testpub_forparted1; -- Tests for row filters -- 2.39.5