From d150377286c0e6aa61361586133d6f9e00d86c92 Mon Sep 17 00:00:00 2001
From: Petr Jelinek
Date: Sun, 28 Oct 2018 23:22:42 +0100
Subject: [PATCH] Fix REPLICA IDENTITY handling in logical replication protocol
We need column bitmap of replica identity so that we can send the
correct key to the downstream. We used to build all the index
information for this purpose but hat has two flaws:
- The logical decoding does not have proper snapshot for building index
info for functional indexes.
- It's also not very efficient to build info we will never need
This commit solves both of those by introducing special purpose function
which only builds index info and hence the bitmap for REPLICA IDENTITY
index.
---
src/backend/replication/logical/proto.c | 58 ++++++++++++++++++++++++-
1 file changed, 56 insertions(+), 2 deletions(-)
diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c
index 19451714da..d7d0fe0407 100644
--- a/src/backend/replication/logical/proto.c
+++ b/src/backend/replication/logical/proto.c
@@ -18,6 +18,7 @@
#include "libpq/pqformat.h"
#include "replication/logicalproto.h"
#include "utils/builtins.h"
+#include "utils/catcache.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
@@ -556,6 +557,60 @@ logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
}
}
+/*
+ * Get a bitmap of identity index attribute numbers.
+ *
+ * We cannot use RelationGetIndexAttrBitmap in output plugin because it would
+ * try to build IndexInfo for all the relation's indexes, which would be a
+ * problem, as the right authorization environment for that has not been set
+ * up (a problem particularly if there are any SQL-language functions.)
+ */
+static Bitmapset *
+get_rel_idattrs(Relation relation)
+{
+ Bitmapset *idattrs = NULL;
+ Oid idindex = RelationGetReplicaIndex(relation);
+ int i;
+
+ /* If we already have the bitmap, just return it. */
+ if (relation->rd_idattr != NULL)
+ return bms_copy(relation->rd_idattr);
+
+ /* Otherwise build it from the identity index if there is one. */
+ if (OidIsValid(idindex))
+ {
+ HeapTuple tuple;
+ Form_pg_index index;
+ int natts;
+ MemoryContext oldcxt;
+
+ tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(idindex));
+ if (!tuple)
+ elog(ERROR, "cache lookup failed for index %u", idindex);
+ index = (Form_pg_index) GETSTRUCT(tuple);
+ natts = index->indnkeyatts;
+
+ for (i = 0; i < natts; i++)
+ idattrs = bms_add_member(idattrs, index->indkey.values[i] -
+ FirstLowInvalidHeapAttributeNumber);
+ ReleaseSysCache(tuple);
+
+ /*
+ * Save copy of the bitmap in the relcache entry.
+ * Note this will not make the relcache index info valid for
+ * RelationGetIndexAttrBitmap, but that does not matter as we don't
+ * mind if it rebuilds it - it should not anyway as this is supposed
+ * to be only called in output plugin where
+ * RelationGetIndexAttrBitmap does not work.
+ */
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+ relation->rd_idattr = bms_copy(idattrs);
+ MemoryContextSwitchTo(oldcxt);
+ }
+
+ return idattrs;
+}
+
/*
* Write relation attributes to the stream.
*/
@@ -582,8 +637,7 @@ logicalrep_write_attrs(StringInfo out, Relation rel)
/* fetch bitmap of REPLICATION IDENTITY attributes */
replidentfull = (rel->rd_rel->relreplident == REPLICA_IDENTITY_FULL);
if (!replidentfull)
- idattrs = RelationGetIndexAttrBitmap(rel,
- INDEX_ATTR_BITMAP_IDENTITY_KEY);
+ idattrs = get_rel_idattrs(rel);
/* send the attributes */
for (i = 0; i < desc->natts; i++)
--
2.17.1