From 6fdcae7ffda13d81de73414b2c405f5bbd6274c5 Mon Sep 17 00:00:00 2001
From: "houzj.fnst" <houzj.fnst@fujitsu.com>
Date: Thu, 28 Oct 2021 13:58:51 +0800
Subject: [PATCH] Fix double publish of child table's data.

if publish_via_partition_root is true, then the child table's data will be
copied twice if adding both child and parent table to the publication. The
reason is that the subscriber will fetch the table list from publisher's
pg_publication_tables view to do the table synchronization. But the view always
show both child and parent table which cause the extra synchronization
for the child table.

Fix it by making pg_publication_tables only show parent table if both parent
and child exists in the publication.

---
 src/backend/catalog/pg_publication.c      | 18 ++++--------------
 src/test/regress/expected/publication.out |  8 ++++++++
 src/test/regress/sql/publication.sql      |  4 ++++
 3 files changed, 16 insertions(+), 14 deletions(-)

diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index fed83b89a9..019ee16d36 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -136,7 +136,7 @@ is_publishable_class(Oid relid, Form_pg_class reltuple)
  * the publication.
  */
 static List *
-filter_partitions(List *relids, List *schemarelids)
+filter_partitions(List *relids)
 {
 	List	   *result = NIL;
 	ListCell   *lc;
@@ -157,14 +157,8 @@ filter_partitions(List *relids, List *schemarelids)
 
 			/*
 			 * Check if the parent table exists in the published table list.
-			 *
-			 * XXX As of now, we do this if the partition relation or the
-			 * partition relation's ancestor is present in schema publication
-			 * relations.
 			 */
-			if (list_member_oid(relids, ancestor) &&
-				(list_member_oid(schemarelids, relid) ||
-				 list_member_oid(schemarelids, ancestor)))
+			if (list_member_oid(relids, ancestor))
 			{
 				skip = true;
 				break;
@@ -873,7 +867,7 @@ pg_get_publication_tables(PG_FUNCTION_ARGS)
 															PUBLICATION_PART_ROOT :
 															PUBLICATION_PART_LEAF);
 			tables = list_concat_unique_oid(relids, schemarelids);
-			if (schemarelids && publication->pubviaroot)
+			if (publication->pubviaroot)
 			{
 				/*
 				 * If the publication publishes partition changes via their
@@ -882,12 +876,8 @@ pg_get_publication_tables(PG_FUNCTION_ARGS)
 				 * tables. Otherwise, the function could return both the child
 				 * and parent tables which could cause data of the child table
 				 * to be double-published on the subscriber side.
-				 *
-				 * XXX As of now, we do this when a publication has associated
-				 * schema or for all tables publication. See
-				 * GetAllTablesPublicationRelations().
 				 */
-				tables = filter_partitions(tables, schemarelids);
+				tables = filter_partitions(tables);
 			}
 		}
 
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 0f4fe4db8f..55777223ce 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -798,6 +798,14 @@ SELECT * FROM pg_publication_tables;
  pub     | sch2       | tbl1_part1
 (1 row)
 
+-- Table publication that includes both the parent table and the child table
+ALTER PUBLICATION pub ADD TABLE sch1.tbl1;
+SELECT * FROM pg_publication_tables;
+ pubname | schemaname | tablename 
+---------+------------+-----------
+ pub     | sch1       | tbl1
+(1 row)
+
 DROP PUBLICATION pub;
 -- Schema publication that does not include the schema that has the parent table
 CREATE PUBLICATION pub FOR ALL TABLES IN SCHEMA sch2 WITH (PUBLISH_VIA_PARTITION_ROOT=0);
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index 85a5302a74..04e462d371 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -445,6 +445,10 @@ DROP PUBLICATION pub;
 CREATE PUBLICATION pub FOR TABLE sch2.tbl1_part1 WITH (PUBLISH_VIA_PARTITION_ROOT=1);
 SELECT * FROM pg_publication_tables;
 
+-- Table publication that includes both the parent table and the child table
+ALTER PUBLICATION pub ADD TABLE sch1.tbl1;
+SELECT * FROM pg_publication_tables;
+
 DROP PUBLICATION pub;
 -- Schema publication that does not include the schema that has the parent table
 CREATE PUBLICATION pub FOR ALL TABLES IN SCHEMA sch2 WITH (PUBLISH_VIA_PARTITION_ROOT=0);
-- 
2.18.4

