From 4c25b51292eb154deee1da5f6df14f3ccfa6889b Mon Sep 17 00:00:00 2001
From: "Hou Zhijie" <houzj.fnst@fujitsu.com>
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

