Hi, I observed that, in logical replication when a subscriber is missing some columns, it currently emits an error message that says "some" columns are missing(see logicalrep_rel_open()), but it doesn't specify what the missing column names are. The comment there also says that finding the missing column names is a todo item(/* TODO, detail message with names of missing columns */).
I propose a patch to find the missing columns on the subscriber relation using the publisher relation columns and show them in the error message which can make the error more informative to the user. Here's a snapshot how the error looks with the patch: 2020-09-04 01:00:36.721 PDT [843128] ERROR: logical replication target relation "public.test_1" is missing "b1, d1" replicated columns 2020-09-04 01:00:46.784 PDT [843132] ERROR: logical replication target relation "public.test_1" is missing "b1" replicated columns 2020-09-06 21:24:53.645 PDT [902945] ERROR: logical replication target relation "public.test_1" is missing "a1, c1, d1, b1" replicated columns Thoughts? With Regards, Bharath Rupireddy. EnterpriseDB: http://www.enterprisedb.com
From e923dc6ddfa9b41c70f351ba6ad7dc8cfa8dbde3 Mon Sep 17 00:00:00 2001 From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com> Date: Fri, 4 Sep 2020 21:10:52 -0700 Subject: [PATCH v1] Detail message with names of missing columns in logical replication In logical replication when a subscriber is missing some columns, it currently emits an error message that says "some" columns are missing(see logicalrep_rel_open()), but it doesn't specify what the missing column names are. The comment there also says that finding the missing column names is a todo item(/* TODO, detail message with names of missing columns */). This patch finds the missing columns on the subscriber relation using the publisher relation columns and show them in the error message which makes error to be more informative to the user. --- src/backend/replication/logical/relation.c | 50 ++++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/src/backend/replication/logical/relation.c b/src/backend/replication/logical/relation.c index a60c73d74d..d34ea3ce39 100644 --- a/src/backend/replication/logical/relation.c +++ b/src/backend/replication/logical/relation.c @@ -227,6 +227,44 @@ logicalrep_rel_att_by_name(LogicalRepRelation *remoterel, const char *attname) return -1; } +/* + * Finds the attributes that are missing in the local relation + * compared to remote relation. + */ +static void +logicalrep_find_missing_atts(Relation localrel, + LogicalRepRelation *remoterel, + StringInfo missingatts) +{ + int i; + int j; + TupleDesc desc; + + desc = RelationGetDescr(localrel); + + for (i = 0; i < remoterel->natts; i++) + { + bool found = false; + for (j = 0; j < desc->natts; j++) + { + Form_pg_attribute attr = TupleDescAttr(desc, j); + if (strcmp(remoterel->attnames[i], NameStr(attr->attname)) == 0) + { + found = true; + break; + } + } + + if (found == false) + { + if (missingatts->len == 0) + appendStringInfoString(missingatts, remoterel->attnames[i]); + else if (missingatts->len > 0) + appendStringInfo(missingatts, ", %s", remoterel->attnames[i]); + } + } +} + /* * Open the local relation associated with the remote one. * @@ -322,13 +360,19 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode) found++; } - /* TODO, detail message with names of missing columns */ if (found < remoterel->natts) + { + StringInfoData missingatts; + + initStringInfo(&missingatts); + logicalrep_find_missing_atts(entry->localrel, remoterel, &missingatts); ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("logical replication target relation \"%s.%s\" is missing " - "some replicated columns", - remoterel->nspname, remoterel->relname))); + "\"%s\" replicated columns", + remoterel->nspname, remoterel->relname, + missingatts.data))); + } /* * Check that replica identity matches. We allow for stricter replica -- 2.25.1