Search Postgresql Archives

Re: logical replication - negative bitmapset member not allowed

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 2019-11-05 17:05, Jehan-Guillaume de Rorthais wrote:
I have simplified your reproduction steps from the previous message to a
test case, and I can confirm that your proposed fix addresses the issue.

Thanks for the feedback and the test case. I wonder if ALTER SUBSCRIPTION
DISABLE/ENABLE is useful in the test case?

Turns out it's not necessary. Attached is an updated patch that simplifies the test even further and moves it into the 008_diff_schema.pl file.

--
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From dcc12ec8315ecb8613190052d4f787cf0554e2c2 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@xxxxxxxxxxxxxx>
Date: Thu, 7 Nov 2019 13:48:59 +0100
Subject: [PATCH v2] Fix negative bitmapset member not allowed error in logical
 replication

This happens when we add a replica identity column on a subscriber
that does not yet exist on the publisher, according to the mapping
maintained by the subscriber.  Code that checks whether the target
relation on the subscriber is updatable would check the replica
identity attribute bitmap with a column number -1, which would result
in an error.  To fix, skip such columns in the bitmap lookup and
consider the relation not updatable.  The result is consistent with
the rule that the replica identity columns on the subscriber must be a
subset of those on the publisher, since if the column doesn't exist on
the publisher, the column set on the subscriber can't be a subset.

Reported-by: Tim Clarke <tim.clarke@xxxxxxxxxxxx>
Analyzed-by: Jehan-Guillaume de Rorthais <jgdr@xxxxxxxxxx>
Discussion: https://www.postgresql.org/message-id/flat/a9139c29-7ddd-973b-aa7f-71fed9c38d75%40minerva.info
---
 src/backend/replication/logical/relation.c |  3 +-
 src/test/subscription/t/008_diff_schema.pl | 37 ++++++++++++++++++++--
 2 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/src/backend/replication/logical/relation.c b/src/backend/replication/logical/relation.c
index f938d1fa48..b386f8460d 100644
--- a/src/backend/replication/logical/relation.c
+++ b/src/backend/replication/logical/relation.c
@@ -340,7 +340,8 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
 
 			attnum = AttrNumberGetAttrOffset(attnum);
 
-			if (!bms_is_member(entry->attrmap[attnum], remoterel->attkeys))
+			if (entry->attrmap[attnum] < 0 ||
+				!bms_is_member(entry->attrmap[attnum], remoterel->attkeys))
 			{
 				entry->updatable = false;
 				break;
diff --git a/src/test/subscription/t/008_diff_schema.pl b/src/test/subscription/t/008_diff_schema.pl
index 3ad00eae3b..d1c8fb7061 100644
--- a/src/test/subscription/t/008_diff_schema.pl
+++ b/src/test/subscription/t/008_diff_schema.pl
@@ -3,7 +3,7 @@
 use warnings;
 use PostgresNode;
 use TestLib;
-use Test::More tests => 4;
+use Test::More tests => 5;
 
 # Create publisher node
 my $node_publisher = get_new_node('publisher');
@@ -29,7 +29,7 @@
 # Setup logical replication
 my $publisher_connstr = $node_publisher->connstr . ' dbname=postgres';
 $node_publisher->safe_psql('postgres',
-	"CREATE PUBLICATION tap_pub FOR TABLE test_tab");
+	"CREATE PUBLICATION tap_pub FOR ALL TABLES");
 
 $node_subscriber->safe_psql('postgres',
 	"CREATE SUBSCRIPTION tap_sub CONNECTION '$publisher_connstr' PUBLICATION tap_pub"
@@ -88,5 +88,38 @@
 is($result, qq(3|3|3|3),
 	'check extra columns contain local defaults after apply');
 
+
+# Check a bug about adding a replica identity column on the subscriber
+# that was not yet mapped to a column on the publisher.  This would
+# result in errors on the subscriber and replication thus not
+# progressing.
+# (https://www.postgresql.org/message-id/flat/a9139c29-7ddd-973b-aa7f-71fed9c38d75%40minerva.info)
+
+$node_publisher->safe_psql('postgres',
+	"CREATE TABLE test_tab2 (a int)");
+
+$node_subscriber->safe_psql('postgres',
+	"CREATE TABLE test_tab2 (a int)");
+
+$node_subscriber->safe_psql('postgres',
+	"ALTER SUBSCRIPTION tap_sub REFRESH PUBLICATION");
+
+# Add replica identity column.  (The serial is not necessary, but it's
+# a convenient way to get a default on the new column so that rows
+# from the publisher that don't have the column yet can be inserted.)
+$node_subscriber->safe_psql('postgres',
+	"ALTER TABLE test_tab2 ADD COLUMN b serial PRIMARY KEY");
+
+$node_publisher->safe_psql('postgres',
+	"INSERT INTO test_tab2 VALUES (1)");
+
+$node_publisher->wait_for_catchup('tap_sub');
+
+is($node_subscriber->safe_psql('postgres',
+							   "SELECT count(*), min(a), max(a) FROM test_tab2"),
+   qq(1|1|1),
+   'check replicated inserts on subscriber');
+
+
 $node_subscriber->stop;
 $node_publisher->stop;

base-commit: e5cfb8cbbe91e73ee92d9e4ab023ca208f3b748a
-- 
2.23.0


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Postgresql Jobs]     [Postgresql Admin]     [Postgresql Performance]     [Linux Clusters]     [PHP Home]     [PHP on Windows]     [Kernel Newbies]     [PHP Classes]     [PHP Books]     [PHP Databases]     [Postgresql & PHP]     [Yosemite]

  Powered by Linux