aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2022-11-02 12:29:39 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2022-11-02 12:29:39 -0400
commit414d29a826f3a63fabae5e9ac2eb5b17f03787d8 (patch)
tree067df60fb35dab54ea7b4adba86b7eab5e946cec
parent0eede9625659d47a9b3fb1292f71c8b16667326b (diff)
downloadpostgresql-414d29a826f3a63fabae5e9ac2eb5b17f03787d8.tar.gz
postgresql-414d29a826f3a63fabae5e9ac2eb5b17f03787d8.zip
Defend against unsupported partition relkind in logical replication worker.
Since partitions can be foreign tables not only plain tables, but logical replication only supports plain tables, we'd better check the relkind of a partition after we find it. (There was some discussion of checking this when adding a partitioned table to a subscription; but that would be inadequate since the troublesome partition could be added later.) Without this, the situation leads to a segfault or assertion failure. In passing, add a separate variable for the target Relation of a cross-partition UPDATE; reusing partrel seemed mighty confusing and error-prone. Shi Yu and Tom Lane, per report from Ilya Gladyshev. Back-patch to v13 where logical replication into partitioned tables became a thing. Discussion: https://postgr.es/m/6b93e3748ba43298694f376ca8797279d7945e29.camel@gmail.com
-rw-r--r--src/backend/replication/logical/worker.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 6c97ef02809..1825daf903e 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -2152,6 +2152,15 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
partrel = partrelinfo->ri_RelationDesc;
/*
+ * Check for supported relkind. We need this since partitions might be of
+ * unsupported relkinds; and the set of partitions can change, so checking
+ * at CREATE/ALTER SUBSCRIPTION would be insufficient.
+ */
+ CheckSubscriptionRelkind(partrel->rd_rel->relkind,
+ get_namespace_name(RelationGetNamespace(partrel)),
+ RelationGetRelationName(partrel));
+
+ /*
* To perform any of the operations below, the tuple must match the
* partition's rowtype. Convert if needed or just copy, using a dedicated
* slot to store the tuple in any case.
@@ -2204,6 +2213,7 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
{
TupleTableSlot *localslot;
ResultRelInfo *partrelinfo_new;
+ Relation partrel_new;
bool found;
/* Get the matching local tuple from the partition. */
@@ -2289,7 +2299,6 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
slot_getallattrs(remoteslot);
}
-
/* Find the new partition. */
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
partrelinfo_new = ExecFindPartition(mtstate, relinfo,
@@ -2297,6 +2306,12 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
estate);
MemoryContextSwitchTo(oldctx);
Assert(partrelinfo_new != partrelinfo);
+ partrel_new = partrelinfo_new->ri_RelationDesc;
+
+ /* Check that new partition also has supported relkind. */
+ CheckSubscriptionRelkind(partrel_new->rd_rel->relkind,
+ get_namespace_name(RelationGetNamespace(partrel_new)),
+ RelationGetRelationName(partrel_new));
/* DELETE old tuple found in the old partition. */
apply_handle_delete_internal(edata, partrelinfo,
@@ -2309,10 +2324,9 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
* partition rowtype.
*/
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
- partrel = partrelinfo_new->ri_RelationDesc;
remoteslot_part = partrelinfo_new->ri_PartitionTupleSlot;
if (remoteslot_part == NULL)
- remoteslot_part = table_slot_create(partrel,
+ remoteslot_part = table_slot_create(partrel_new,
&estate->es_tupleTable);
map = partrelinfo_new->ri_RootToPartitionMap;
if (map != NULL)