Hi, hackers!

I am looking at subscription creation command:

CREATE SUBSCRIPTION sub CONNECTION '...' PUBLICATION pub WITH (origin = none, copy_data = on);

For now we log a warning if the publisher has subscribed to the same table from some other publisher. However, in case of publication with publish_via_partition_root option, we will not raise such warinigs because SQL command in check_publications_origin() checks only directly published tables.
For example:

CREATE TABLE t(id int) PARTITION BY RANGE(id);
CREATE TABLE part1 PARTITION OF t FOR VALUES FROM (0) TO (5);
CREATE TABLE part2 PARTITION OF t FOR VALUES FROM (5) TO (10);
-- subscribe to part2
CREATE SUBSCRIPTION sub_part2 CONNECTION '...' PUBLICATION pub_part2;
CREATE PUBLICATION pub_t FOR TABLE t;
CREATE PUBLICATION pub_t_via_root FOR TABLE t WITH (publish_via_partition_root);

and now this command will raise a warning:
CREATE SUBSCRIPTION sub1 CONNECTION '...' PUBLICATION pub_t WITH (origin = none, copy_data = on);

but not this:
CREATE SUBSCRIPTION sub1 CONNECTION '...' PUBLICATION pub_t_via_root WITH (origin = none, copy_data = on);

We also do not take into account cases of foreign partitions:
CREATE TABLE t(id int) PARTITION BY RANGE(id);
CREATE TABLE part1 PARTITION OF t FOR VALUES FROM (0) TO (5);
CREATE FOREIGN TABLE part2 PARTITION OF t FOR VALUES FROM (5) TO (10) SERVER fdw_server;
CREATE PUBLICATION pub_t FOR TABLE t;

Maybe we should raise WARNING (or even ERROR) in such cases?
I would also note that the (origin = none) will work as expected, but in case of (origin = any) it will lead to inappropriate behavior - we will perform an initial sync of "t", but we unable to
replicate further updates for "part2".

I have attached patch, demonstrating this problems
diff --git a/src/test/subscription/Makefile b/src/test/subscription/Makefile
index ce1ca43009..e5e9bb469c 100644
--- a/src/test/subscription/Makefile
+++ b/src/test/subscription/Makefile
@@ -13,7 +13,7 @@ subdir = src/test/subscription
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-EXTRA_INSTALL = contrib/hstore
+EXTRA_INSTALL = contrib/hstore contrib/postgres_fdw
 
 export with_icu
 
diff --git a/src/test/subscription/t/030_origin.pl b/src/test/subscription/t/030_origin.pl
index adfae1a56e..d310e79ba8 100644
--- a/src/test/subscription/t/030_origin.pl
+++ b/src/test/subscription/t/030_origin.pl
@@ -255,6 +255,134 @@ $node_A->safe_psql('postgres', "DROP TABLE tab_new");
 $node_B->safe_psql('postgres', "DROP TABLE tab_new");
 $node_A->safe_psql('postgres', "DROP SUBSCRIPTION $subname_AB2");
 
+###############################################################################
+# Setting the origin option to NONE must raise WARNING if we subscribe to a
+# partitioned table, if this table contains any remotely originated data, even
+# if a publication was created with the publish_via_partition_root option.
+#
+#                       node_A                                  node_C
+#                     _____________________                   __________
+#                    |        ts.t         |---------------->|   ts.t   |
+#                    |_____________________|                 |__________|
+#                    | ts.part1 | ts.part2 |
+#                    |__________|__________|
+#     node_B                         ^
+#   __________                       |
+#  | ts.part2 |----------------------
+#  |__________|
+#
+###############################################################################
+$node_B->safe_psql('postgres', qq(
+CREATE SCHEMA ts;
+CREATE TABLE ts.part2(id int);
+CREATE PUBLICATION pub_b FOR TABLE ts.part2;
+));
+$node_A->safe_psql('postgres', qq(
+CREATE SCHEMA ts;
+CREATE TABLE ts.t(id int) PARTITION BY RANGE(id);
+CREATE TABLE ts.part1 PARTITION OF ts.t FOR VALUES FROM (0) TO (5);
+CREATE TABLE ts.part2 PARTITION OF ts.t FOR VALUES FROM (5) TO (10);
+));
+$node_A->safe_psql('postgres',"CREATE SUBSCRIPTION sub_b CONNECTION '$node_B_connstr' PUBLICATION pub_b;");
+$node_A->safe_psql('postgres',"
+CREATE PUBLICATION pub_a FOR TABLE ts.t;
+CREATE PUBLICATION pub_a_via_root FOR TABLE ts.t WITH (publish_via_partition_root);
+CREATE PUBLICATION pub_a_schema FOR TABLES IN SCHEMA ts WITH (publish_via_partition_root);
+");
+
+$node_C->safe_psql('postgres',"
+CREATE SCHEMA ts;
+CREATE TABLE ts.t(id int) PARTITION BY RANGE(id);
+CREATE TABLE ts.part1 PARTITION OF ts.t FOR VALUES FROM (0) TO (5);
+CREATE TABLE ts.part2 PARTITION OF ts.t FOR VALUES FROM (5) TO (10);");
+
+my $pub;
+# in this case, only "pub_a" will raise WARNING. However, all of them must do it.
+my @publications = ("pub_a", "pub_a_via_root", "pub_a_schema");
+foreach $pub (@publications)
+{
+	note("check warning for publication $pub");
+	($result, $stdout, $stderr) = $node_C->psql('postgres',"
+		CREATE SUBSCRIPTION sub_c CONNECTION '$node_A_connstr' PUBLICATION $pub WITH (origin = none, copy_data = on);
+	");
+
+	like(
+		$stderr,
+		qr/WARNING: ( [A-Z0-9]+:)? subscription "sub_c" requested copy_data with origin = NONE but might copy data that had a different origin/,
+		"subscribe to $pub must raise WARNING"
+	);
+	$node_C->psql('postgres',"DROP SUBSCRIPTION IF EXISTS sub_c");
+}
+$node_A->safe_psql('postgres',qq(
+DROP SCHEMA ts CASCADE;
+DROP PUBLICATION pub_a;
+DROP PUBLICATION pub_a_via_root;
+DROP PUBLICATION pub_a_schema;
+));
+$node_B->safe_psql('postgres',"DROP SCHEMA ts CASCADE");
+$node_C->safe_psql('postgres',"DROP SCHEMA ts CASCADE");
+
+###############################################################################
+# Also, we must check foreign partitions if the origin option is set to NONE.
+# Maybe we should raise ERROR in these cases for any origin value?
+###############################################################################
+$node_A->safe_psql('postgres',"CREATE EXTENSION postgres_fdw");
+$node_B->safe_psql('postgres',"CREATE TABLE part22(id int);");
+my $fdwconnstr = "dbname 'postgres', host  '" . $node_B->host . "', port  '" . $node_B->port . "'";
+$node_A->safe_psql('postgres',qq(
+CREATE SERVER fdw FOREIGN DATA WRAPPER postgres_fdw  OPTIONS ($fdwconnstr);
+CREATE USER MAPPING FOR CURRENT_USER SERVER fdw;
+));
+
+#  Create a partitioned table:
+#   _______________________________________
+#  |                     t                 |
+#  |_______________________________________|
+#  | part1 |          part2                |
+#  |_______|_______________________________|
+#          |   part21   | part22 (foreign) |
+#          |____________|__________________|
+$node_A->safe_psql('postgres',qq(
+CREATE TABLE t(id int) PARTITION BY RANGE(id);
+CREATE TABLE part1 PARTITION OF t FOR VALUES FROM (0) TO (5);
+CREATE TABLE part2 PARTITION OF t FOR VALUES FROM (5) TO (15) PARTITION BY RANGE(id);
+CREATE TABLE part21 PARTITION OF part2 FOR VALUES FROM (5) TO (10);
+CREATE FOREIGN TABLE part22 PARTITION OF part2 FOR VALUES FROM (10) TO (15) SERVER fdw;
+INSERT INTO t SELECT id FROM generate_series(0,14) id;
+));
+$node_C->safe_psql('postgres',qq(
+CREATE TABLE t(id int) PARTITION BY RANGE(id);
+CREATE TABLE part1 PARTITION OF t FOR VALUES FROM (0) TO (5);
+CREATE TABLE part2 PARTITION OF t FOR VALUES FROM (5) TO (15) PARTITION BY RANGE(id);
+CREATE TABLE part21 PARTITION OF part2 FOR VALUES FROM (5) TO (10);
+CREATE TABLE part22 PARTITION OF part2 FOR VALUES FROM (10) TO (15);
+));
+
+$node_A->safe_psql('postgres',qq(
+CREATE PUBLICATION fdwpub FOR TABLE t;
+CREATE PUBLICATION fdwpub_via_root FOR TABLE t WITH (publish_via_partition_root);
+));
+
+# Here, both commands must raise WARNING.
+@publications = ("fdwpub", "fdwpub_via_root");
+foreach $pub (@publications)
+{
+	note("check warning for publication $pub");
+	($result, $stdout, $stderr) = $node_C->psql('postgres',"
+		CREATE SUBSCRIPTION sub_c CONNECTION '$node_A_connstr' PUBLICATION $pub WITH (origin = none, copy_data = on);
+	");
+
+	like(
+		$stderr,
+		qr/WARNING: ( [A-Z0-9]+:)? subscription "sub_c" requested copy_data with origin = NONE but might copy data that had a different origin/,
+		"subscribe to $pub must raise WARNING"
+	);
+	$node_C->psql('postgres',"DROP SUBSCRIPTION IF EXISTS sub_c");
+}
+$node_A->safe_psql('postgres',"DROP TABLE t CASCADE");
+$node_B->safe_psql('postgres',"DROP TABLE part22");
+$node_C->safe_psql('postgres',"DROP TABLE t CASCADE");
+
 # shutdown
 $node_B->stop('fast');
 $node_A->stop('fast');

Reply via email to