From 4c25b51292eb154deee1da5f6df14f3ccfa6889b Mon Sep 17 00:00:00 2001 From: "Hou Zhijie" Date: Mon, 6 Sep 2021 15:06:12 +0800 Subject: [PATCH] fix create publication invalidation Invalid all the leaf partitions' relcache when add or drop a partitioned table from a publication so that publication info is rebuilt. --- src/backend/catalog/pg_publication.c | 6 ++---- src/backend/commands/publicationcmds.c | 15 +++++++++++++++ src/include/catalog/pg_publication.h | 3 +++ src/test/regress/expected/publication.out | 11 ++++++++++- src/test/regress/sql/publication.sql | 9 ++++++++- 5 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c index a587e09d00..ac53fe3fe8 100644 --- a/src/backend/catalog/pg_publication.c +++ b/src/backend/catalog/pg_publication.c @@ -31,6 +31,7 @@ #include "catalog/pg_publication.h" #include "catalog/pg_publication_rel.h" #include "catalog/pg_type.h" +#include "commands/publicationcmds.h" #include "funcapi.h" #include "miscadmin.h" #include "utils/array.h" @@ -140,7 +141,7 @@ pg_relation_is_publishable(PG_FUNCTION_ARGS) * Gets the relations based on the publication partition option for a specified * relation. */ -static List * +List * GetPubPartitionOptionRelations(List *result, PublicationPartOpt pub_partopt, Oid relid) { @@ -244,9 +245,6 @@ publication_add_relation(Oid pubid, Relation targetrel, /* Close the table. */ table_close(rel, RowExclusiveLock); - /* Invalidate relcache so that publication info is rebuilt. */ - CacheInvalidateRelcache(targetrel); - return myself; } diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c index e1d17f6fa6..0e5ae76242 100644 --- a/src/backend/commands/publicationcmds.c +++ b/src/backend/commands/publicationcmds.c @@ -608,6 +608,7 @@ PublicationAddTables(Oid pubid, List *rels, bool if_not_exists, AlterPublicationStmt *stmt) { ListCell *lc; + List *relids = NIL; Assert(!stmt || !stmt->for_all_tables); @@ -622,6 +623,10 @@ PublicationAddTables(Oid pubid, List *rels, bool if_not_exists, RelationGetRelationName(rel)); obj = publication_add_relation(pubid, rel, if_not_exists); + + relids = GetPubPartitionOptionRelations(relids, PUBLICATION_PART_LEAF, + RelationGetRelid(rel)); + if (stmt) { EventTriggerCollectSimpleCommand(obj, InvalidObjectAddress, @@ -631,6 +636,9 @@ PublicationAddTables(Oid pubid, List *rels, bool if_not_exists, obj.objectId, 0); } } + + /* Invalidate relcache so that publication info is rebuilt. */ + InvalidatePublicationRels(relids); } /* @@ -642,6 +650,7 @@ PublicationDropTables(Oid pubid, List *rels, bool missing_ok) ObjectAddress obj; ListCell *lc; Oid prid; + List *relids = NIL; foreach(lc, rels) { @@ -664,7 +673,13 @@ PublicationDropTables(Oid pubid, List *rels, bool missing_ok) ObjectAddressSet(obj, PublicationRelRelationId, prid); performDeletion(&obj, DROP_CASCADE, 0); + + relids = GetPubPartitionOptionRelations(relids, PUBLICATION_PART_LEAF, + relid); } + + /* Invalidate relcache so that publication info is rebuilt. */ + InvalidatePublicationRels(relids); } /* diff --git a/src/include/catalog/pg_publication.h b/src/include/catalog/pg_publication.h index f332bad4d4..758bb15e1e 100644 --- a/src/include/catalog/pg_publication.h +++ b/src/include/catalog/pg_publication.h @@ -110,6 +110,9 @@ extern List *GetAllTablesPublicationRelations(bool pubviaroot); extern bool is_publishable_relation(Relation rel); extern ObjectAddress publication_add_relation(Oid pubid, Relation targetrel, bool if_not_exists); +extern List *GetPubPartitionOptionRelations(List *result, + PublicationPartOpt pub_partopt, + Oid relid); extern Oid get_publication_oid(const char *pubname, bool missing_ok); extern char *get_publication_name(Oid pubid, bool missing_ok); diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out index 4a5ef0bc24..6523909e1d 100644 --- a/src/test/regress/expected/publication.out +++ b/src/test/regress/expected/publication.out @@ -126,10 +126,12 @@ CREATE PUBLICATION testpub_forparted; CREATE PUBLICATION testpub_forparted1; RESET client_min_messages; CREATE TABLE testpub_parted1 (LIKE testpub_parted); +CREATE TABLE testpub_parted2 (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); -- works despite missing REPLICA IDENTITY, because updates are not replicated UPDATE testpub_parted1 SET a = 1; -ALTER TABLE testpub_parted ATTACH PARTITION testpub_parted1 FOR VALUES IN (1); -- only parent is listed as being in publication, not the partition ALTER PUBLICATION testpub_forparted ADD TABLE testpub_parted; \dRp+ testpub_forparted @@ -156,6 +158,13 @@ ALTER PUBLICATION testpub_forparted SET (publish_via_partition_root = true); Tables: "public.testpub_parted" +-- still fail, because parent's publication replicates updates +UPDATE testpub_parted2 SET a = 2; +ERROR: cannot update table "testpub_parted2" because it does not have a replica identity and publishes updates +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; DROP PUBLICATION testpub_forparted, testpub_forparted1; -- fail - view diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql index d844075368..20cb1c4bd9 100644 --- a/src/test/regress/sql/publication.sql +++ b/src/test/regress/sql/publication.sql @@ -76,10 +76,12 @@ CREATE PUBLICATION testpub_forparted; CREATE PUBLICATION testpub_forparted1; RESET client_min_messages; CREATE TABLE testpub_parted1 (LIKE testpub_parted); +CREATE TABLE testpub_parted2 (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); -- works despite missing REPLICA IDENTITY, because updates are not replicated UPDATE testpub_parted1 SET a = 1; -ALTER TABLE testpub_parted ATTACH PARTITION testpub_parted1 FOR VALUES IN (1); -- only parent is listed as being in publication, not the partition ALTER PUBLICATION testpub_forparted ADD TABLE testpub_parted; \dRp+ testpub_forparted @@ -90,6 +92,11 @@ ALTER TABLE testpub_parted DETACH PARTITION testpub_parted1; UPDATE testpub_parted1 SET a = 1; ALTER PUBLICATION testpub_forparted SET (publish_via_partition_root = true); \dRp+ testpub_forparted +-- still fail, because parent's publication replicates updates +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; DROP PUBLICATION testpub_forparted, testpub_forparted1; -- 2.18.4