Skip to content

Commit 414d29a

Browse files
committed
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
1 parent 0eede96 commit 414d29a

File tree

1 file changed

+17
-3
lines changed

1 file changed

+17
-3
lines changed

src/backend/replication/logical/worker.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2151,6 +2151,15 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
21512151
Assert(partrelinfo != NULL);
21522152
partrel = partrelinfo->ri_RelationDesc;
21532153

2154+
/*
2155+
* Check for supported relkind. We need this since partitions might be of
2156+
* unsupported relkinds; and the set of partitions can change, so checking
2157+
* at CREATE/ALTER SUBSCRIPTION would be insufficient.
2158+
*/
2159+
CheckSubscriptionRelkind(partrel->rd_rel->relkind,
2160+
get_namespace_name(RelationGetNamespace(partrel)),
2161+
RelationGetRelationName(partrel));
2162+
21542163
/*
21552164
* To perform any of the operations below, the tuple must match the
21562165
* partition's rowtype. Convert if needed or just copy, using a dedicated
@@ -2204,6 +2213,7 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
22042213
{
22052214
TupleTableSlot *localslot;
22062215
ResultRelInfo *partrelinfo_new;
2216+
Relation partrel_new;
22072217
bool found;
22082218

22092219
/* Get the matching local tuple from the partition. */
@@ -2289,14 +2299,19 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
22892299
slot_getallattrs(remoteslot);
22902300
}
22912301

2292-
22932302
/* Find the new partition. */
22942303
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
22952304
partrelinfo_new = ExecFindPartition(mtstate, relinfo,
22962305
proute, remoteslot,
22972306
estate);
22982307
MemoryContextSwitchTo(oldctx);
22992308
Assert(partrelinfo_new != partrelinfo);
2309+
partrel_new = partrelinfo_new->ri_RelationDesc;
2310+
2311+
/* Check that new partition also has supported relkind. */
2312+
CheckSubscriptionRelkind(partrel_new->rd_rel->relkind,
2313+
get_namespace_name(RelationGetNamespace(partrel_new)),
2314+
RelationGetRelationName(partrel_new));
23002315

23012316
/* DELETE old tuple found in the old partition. */
23022317
apply_handle_delete_internal(edata, partrelinfo,
@@ -2309,10 +2324,9 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
23092324
* partition rowtype.
23102325
*/
23112326
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
2312-
partrel = partrelinfo_new->ri_RelationDesc;
23132327
remoteslot_part = partrelinfo_new->ri_PartitionTupleSlot;
23142328
if (remoteslot_part == NULL)
2315-
remoteslot_part = table_slot_create(partrel,
2329+
remoteslot_part = table_slot_create(partrel_new,
23162330
&estate->es_tupleTable);
23172331
map = partrelinfo_new->ri_RootToPartitionMap;
23182332
if (map != NULL)

0 commit comments

Comments
 (0)