Skip to content

Commit a5b7821

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 2896aa9 commit a5b7821

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
@@ -1706,6 +1706,15 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
17061706
Assert(partrelinfo != NULL);
17071707
partrel = partrelinfo->ri_RelationDesc;
17081708

1709+
/*
1710+
* Check for supported relkind. We need this since partitions might be of
1711+
* unsupported relkinds; and the set of partitions can change, so checking
1712+
* at CREATE/ALTER SUBSCRIPTION would be insufficient.
1713+
*/
1714+
CheckSubscriptionRelkind(partrel->rd_rel->relkind,
1715+
get_namespace_name(RelationGetNamespace(partrel)),
1716+
RelationGetRelationName(partrel));
1717+
17091718
/*
17101719
* To perform any of the operations below, the tuple must match the
17111720
* partition's rowtype. Convert if needed or just copy, using a dedicated
@@ -1759,6 +1768,7 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
17591768
{
17601769
TupleTableSlot *localslot;
17611770
ResultRelInfo *partrelinfo_new;
1771+
Relation partrel_new;
17621772
bool found;
17631773

17641774
/* Get the matching local tuple from the partition. */
@@ -1842,14 +1852,19 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
18421852
slot_getallattrs(remoteslot);
18431853
}
18441854

1845-
18461855
/* Find the new partition. */
18471856
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
18481857
partrelinfo_new = ExecFindPartition(mtstate, relinfo,
18491858
proute, remoteslot,
18501859
estate);
18511860
MemoryContextSwitchTo(oldctx);
18521861
Assert(partrelinfo_new != partrelinfo);
1862+
partrel_new = partrelinfo_new->ri_RelationDesc;
1863+
1864+
/* Check that new partition also has supported relkind. */
1865+
CheckSubscriptionRelkind(partrel_new->rd_rel->relkind,
1866+
get_namespace_name(RelationGetNamespace(partrel_new)),
1867+
RelationGetRelationName(partrel_new));
18531868

18541869
/* DELETE old tuple found in the old partition. */
18551870
apply_handle_delete_internal(edata, partrelinfo,
@@ -1862,10 +1877,9 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
18621877
* partition rowtype.
18631878
*/
18641879
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
1865-
partrel = partrelinfo_new->ri_RelationDesc;
18661880
remoteslot_part = partrelinfo_new->ri_PartitionTupleSlot;
18671881
if (remoteslot_part == NULL)
1868-
remoteslot_part = table_slot_create(partrel,
1882+
remoteslot_part = table_slot_create(partrel_new,
18691883
&estate->es_tupleTable);
18701884
map = partrelinfo_new->ri_RootToPartitionMap;
18711885
if (map != NULL)

0 commit comments

Comments
 (0)