BUG #15044: materialized views incompatibility with logical replication in postgres 10
The following bug has been logged on the website:
Bug reference: 15044
Logged by: Chad T
Email address: chad@iris.washington.edu
PostgreSQL version: 10.1
Operating system: CentOS 7.4.1708 and macOS 10.13.3
Description:
The built-in logical replication in postgres 10 is documented as not being
able to replication materialized views, notably here:
https://www.postgresql.org/docs/10/static/logical-replication-restrictions.html
Unfortunately, there appears to be an incompatibility with logical
replication and materialized views.
Here is a procedure to illustrate the problem:
# Create data directories for publisher and subscriber and initialize
mkdir pub sub
initdb pub
initdb sub
echo "wal_level = logical" >> pub/postgresql.conf
echo "wal_level = logical" >> sub/postgresql.conf
# Start servers:
pg_ctl -D pub -l pub.log -o "-p 5433" start
pg_ctl -D sub -l sub.log -o "-p 5434" start
# Create tables on both publisher and subscriber
psql -p 5433 -d postgres -c "CREATE TABLE testtable (id int,value text);"
psql -p 5434 -d postgres -c "CREATE TABLE testtable (id int,value text);"
# Create publication and subscription
psql -p 5433 -d postgres -c "CREATE PUBLICATION pub FOR ALL TABLES;"
psql -p 5434 -d postgres -c "CREATE SUBSCRIPTION sub CONNECTION
'host=localhost port=5433 dbname=postgres' PUBLICATION pub;"
# Insert a row into the test table and verify that replication is in a
streaming state
psql -p 5433 -d postgres -c "INSERT INTO testtable (id,value) VALUES
(1,'string');"
psql -p 5433 -d postgres -c "SELECT
state,sent_lsn,write_lsn,flush_lsn,replay_lsn FROM pg_stat_replication;"
# Create materialized view on publisher
psql -p 5433 -d postgres -c "CREATE MATERIALIZED VIEW mvid AS SELECT id FROM
testtable;"
With that CREATE MATERIALIZED VIEW statement the replication broken, with
these errors in the subscriber's log:
2018-02-01 16:34:27.639 PST [68409] ERROR: logical replication target
relation "public.mvid" does not exist
2018-02-01 16:34:27.642 PST [68391] LOG: worker process: logical
replication worker for subscription 16390 (PID 68409) exited with exit code
1
I have tried variations to work around this, all in vain, that include 1)
creating a regular table on the subscriber (allows replication to stream,
but the table is not populated) and 2) creating the MATERIALIZED VIEW before
creating the publication/subscription link (then it breaks on a REFRESH).
On Thursday, February 1, 2018, PG Bug reporting form <noreply@postgresql.org>
wrote:
Bug reference: 15044
The built-in logical replication in postgres 10 is documented as not being
able to replication materialized views, notably here:
https://www.postgresql.org/docs/10/static/logical-replicatio
n-restrictions.htmlUnfortunately, there appears to be an incompatibility with logical
replication and materialized views.
[...]
# Create publication and subscription
psql -p 5433 -d postgres -c "CREATE PUBLICATION pub FOR ALL TABLES;"[...]
# Create materialized view on publisher
psql -p 5433 -d postgres -c "CREATE MATERIALIZED VIEW mvid AS SELECT id
FROM
testtable;"With that CREATE MATERIALIZED VIEW statement the replication broken, with
these errors in the subscriber's log:2018-02-01 16:34:27.639 PST [68409] ERROR: logical replication target
relation "public.mvid" does not exist
It seems the work-around is to not use "for all tables" in your publication
definition.
As described it does seem bugged. The table matview itself is not being
published, as documented, but knowledge of its existence as part of the
publication is...
David J.
On February 1, 2018 17:16:08 "David G. Johnston"
<david.g.johnston@gmail.com> wrote:
Bug reference: 15044
It seems the work-around is to not use "for all tables" in your publication
definition.
Indeed. My real world case 700+ tables with semi regular additions and two
materialized views so ALL TABLES was the right fit.
As described it does seem bugged. The table matview itself is not being
published, as documented, but knowledge of its existence as part of the
publication is...
Exactly. The matview does not show up in pg_publication_tables but it's
registered at some level.
Hi,
On 02/02/18 02:39, Chad Trabant wrote:
On February 1, 2018 17:16:08 "David G. Johnston"
<david.g.johnston@gmail.com> wrote:Bug reference:����� 15044
It seems the work-around is to not use "for all tables" in your
publication
definition.
Indeed.� My real world case 700+ tables with semi regular additions and
two materialized views so ALL TABLES was the right fit.As described it does seem bugged.� The table matview itself is not being
published, as documented, but knowledge of its existence as part of the
publication is...Exactly.� The matview does not show up in pg_publication_tables but it's
registered at some level.
Indeed this is a bug. For normal publications we take care of this when
adding the relation to the publication but since ALL TABLES publications
don't check for membership we have to filter this directly in the output
plugin.
The attached patch should fix it (CCing to PeterE as the original
committer).
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
Attachments:
0001-Fix-filtering-of-unsupported-relations-in-pgoutput.patchtext/x-patch; name=0001-Fix-filtering-of-unsupported-relations-in-pgoutput.patchDownload
From 4272e15faefadc692e89ba06dcde64f07f4e075f Mon Sep 17 00:00:00 2001
From: Petr Jelinek <pjmodos@pjmodos.net>
Date: Mon, 5 Feb 2018 16:09:37 +0100
Subject: [PATCH] Fix filtering of unsupported relations in pgoutput
For normal publications this was already handled when such relation was
requested to be added to given publication by user. However the
alltables publications don't use relation membership check so we have to
handle filtering of unsupported relation kinds directly in pgoutput.
---
src/backend/replication/pgoutput/pgoutput.c | 33 ++++++++++++++++++-----------
1 file changed, 21 insertions(+), 12 deletions(-)
diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c
index 40a1ef3c1d..37756474b9 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -509,15 +509,16 @@ get_rel_sync_entry(PGOutputData *data, Oid relid)
Publication *pub = lfirst(lc);
/*
- * Skip tables that look like they are from a heap rewrite (see
- * make_new_heap()). We need to skip them because the subscriber
- * won't have a table by that name to receive the data. That
- * means we won't ship the new data in, say, an added column with
- * a DEFAULT, but if the user applies the same DDL manually on the
- * subscriber, then this will work out for them.
+ * We might see changes here from relations which we don't know
+ * how to handle correcly, hence we have to filter them out.
*
- * We only need to consider the alltables case, because such a
- * transient heap won't be an explicit member of a publication.
+ * These include:
+ * a) materialized views
+ * b) temporary relations used for heap rewrite
+ *
+ * We only care about those in alltables publications because
+ * for normal publications they will fail membership test. Also
+ * see check_publication_add_relation().
*/
if (pub->alltables)
{
@@ -525,12 +526,20 @@ get_rel_sync_entry(PGOutputData *data, Oid relid)
unsigned int u;
int n;
+ /*
+ * We don't allow publishing of anything that's not a
+ * relation.
+ */
+ if (get_rel_relkind(relid) != RELKIND_RELATION)
+ break;
+
+ /*
+ * We also don't allow publishing temporary heaps for relation
+ * rewrite. See make_new_heap().
+ */
if (sscanf(relname, "pg_temp_%u%n", &u, &n) == 1 &&
relname[n] == '\0')
- {
- if (get_rel_relkind(u) == RELKIND_RELATION)
- break;
- }
+ break;
}
if (pub->alltables || list_member_oid(pubids, pub->oid))
--
2.14.1
On 2/5/18 10:33, Petr Jelinek wrote:
Exactly.� The matview does not show up in pg_publication_tables but it's
registered at some level.Indeed this is a bug. For normal publications we take care of this when
adding the relation to the publication but since ALL TABLES publications
don't check for membership we have to filter this directly in the output
plugin.
I think the filtering in pgoutput ought to make use of
is_publishable_class() in some way. That takes care of non-tables such
as materialized views, but it also filters out the information_schema
tables for example. Right now, if you insert something into one of the
IS tables, it gets shipped over the wire but is then dropped by the
apply because there is no pg_subscription_rel entry of the table. That
doesn't quite have the user-visible effect as this bug, but it's bogus
nonetheless.
So I propose this alternative patch that covers all these cases.
--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachments:
0001-Fix-filtering-of-unsupported-relations-in-pgoutput.patchtext/plain; charset=UTF-8; name=0001-Fix-filtering-of-unsupported-relations-in-pgoutput.patch; x-mac-creator=0; x-mac-type=0Download
From fb9ad748f903e0e67b173022f3fd39b0a82034ba Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter_e@gmx.net>
Date: Sat, 17 Feb 2018 22:30:18 -0500
Subject: [PATCH] Fix filtering of unsupported relations in pgoutput
Bug: #15044
---
src/backend/catalog/pg_publication.c | 9 +++++++++
src/backend/replication/pgoutput/pgoutput.c | 3 +++
src/include/catalog/pg_publication.h | 1 +
3 files changed, 13 insertions(+)
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 3ef7ba8cd5..a0973f43e2 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -105,6 +105,15 @@ is_publishable_class(Oid relid, Form_pg_class reltuple)
relid >= FirstNormalObjectId;
}
+/*
+ * Another variant of this, taking a Relation.
+ */
+bool
+is_publishable_relation(Relation rel)
+{
+ return is_publishable_class(RelationGetRelid(rel), rel->rd_rel);
+}
+
/*
* SQL-callable variant of the above
diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c
index 61e53aba19..38b0eab7d2 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -264,6 +264,9 @@ pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
MemoryContext old;
RelationSyncEntry *relentry;
+ if (!is_publishable_relation(relation))
+ return;
+
relentry = get_rel_sync_entry(data, RelationGetRelid(relation));
/* First check the table filter */
diff --git a/src/include/catalog/pg_publication.h b/src/include/catalog/pg_publication.h
index aa148960cd..be4987505d 100644
--- a/src/include/catalog/pg_publication.h
+++ b/src/include/catalog/pg_publication.h
@@ -93,6 +93,7 @@ extern List *GetPublicationRelations(Oid pubid);
extern List *GetAllTablesPublications(void);
extern List *GetAllTablesPublicationRelations(void);
+extern bool is_publishable_relation(Relation rel);
extern ObjectAddress publication_add_relation(Oid pubid, Relation targetrel,
bool if_not_exists);
--
2.16.1
Adding -hackers to this in the interest of getting it committed by Monday's
wrap-up.
/messages/by-id/6e375316-91a4-7825-ef8b-9b8915ab6980@2ndquadrant.com
David J.
On Sat, Feb 17, 2018 at 8:43 PM, Peter Eisentraut <
peter.eisentraut@2ndquadrant.com> wrote:
Show quoted text
On 2/5/18 10:33, Petr Jelinek wrote:
Exactly. The matview does not show up in pg_publication_tables but it's
registered at some level.Indeed this is a bug. For normal publications we take care of this when
adding the relation to the publication but since ALL TABLES publications
don't check for membership we have to filter this directly in the output
plugin.I think the filtering in pgoutput ought to make use of
is_publishable_class() in some way. That takes care of non-tables such
as materialized views, but it also filters out the information_schema
tables for example. Right now, if you insert something into one of the
IS tables, it gets shipped over the wire but is then dropped by the
apply because there is no pg_subscription_rel entry of the table. That
doesn't quite have the user-visible effect as this bug, but it's bogus
nonetheless.So I propose this alternative patch that covers all these cases.
Attachments:
0001-Fix-filtering-of-unsupported-relations-in-pgoutput.patchapplication/octet-stream; name=0001-Fix-filtering-of-unsupported-relations-in-pgoutput.patchDownload
From fb9ad748f903e0e67b173022f3fd39b0a82034ba Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter_e@gmx.net>
Date: Sat, 17 Feb 2018 22:30:18 -0500
Subject: [PATCH] Fix filtering of unsupported relations in pgoutput
Bug: #15044
---
src/backend/catalog/pg_publication.c | 9 +++++++++
src/backend/replication/pgoutput/pgoutput.c | 3 +++
src/include/catalog/pg_publication.h | 1 +
3 files changed, 13 insertions(+)
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 3ef7ba8cd5..a0973f43e2 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -105,6 +105,15 @@ is_publishable_class(Oid relid, Form_pg_class reltuple)
relid >= FirstNormalObjectId;
}
+/*
+ * Another variant of this, taking a Relation.
+ */
+bool
+is_publishable_relation(Relation rel)
+{
+ return is_publishable_class(RelationGetRelid(rel), rel->rd_rel);
+}
+
/*
* SQL-callable variant of the above
diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c
index 61e53aba19..38b0eab7d2 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -264,6 +264,9 @@ pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
MemoryContext old;
RelationSyncEntry *relentry;
+ if (!is_publishable_relation(relation))
+ return;
+
relentry = get_rel_sync_entry(data, RelationGetRelid(relation));
/* First check the table filter */
diff --git a/src/include/catalog/pg_publication.h b/src/include/catalog/pg_publication.h
index aa148960cd..be4987505d 100644
--- a/src/include/catalog/pg_publication.h
+++ b/src/include/catalog/pg_publication.h
@@ -93,6 +93,7 @@ extern List *GetPublicationRelations(Oid pubid);
extern List *GetAllTablesPublications(void);
extern List *GetAllTablesPublicationRelations(void);
+extern bool is_publishable_relation(Relation rel);
extern ObjectAddress publication_add_relation(Oid pubid, Relation targetrel,
bool if_not_exists);
--
2.16.1
On 2/17/18 22:43, Peter Eisentraut wrote:
On 2/5/18 10:33, Petr Jelinek wrote:
Exactly.� The matview does not show up in pg_publication_tables but it's
registered at some level.Indeed this is a bug. For normal publications we take care of this when
adding the relation to the publication but since ALL TABLES publications
don't check for membership we have to filter this directly in the output
plugin.I think the filtering in pgoutput ought to make use of
is_publishable_class() in some way. That takes care of non-tables such
as materialized views, but it also filters out the information_schema
tables for example. Right now, if you insert something into one of the
IS tables, it gets shipped over the wire but is then dropped by the
apply because there is no pg_subscription_rel entry of the table. That
doesn't quite have the user-visible effect as this bug, but it's bogus
nonetheless.So I propose this alternative patch that covers all these cases.
Committed, and also added a new test in the master branch.
--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services