diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 44cf3bba12..d135f858d2 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -2684,12 +2684,15 @@ CopyFrom(CopyState cstate) * We might need to convert from the parent rowtype to the * partition rowtype. */ - tuple = ConvertPartitionTupleSlot(proute->parent_child_tupconv_maps ? - proute->parent_child_tupconv_maps[leaf_part_index] : - NULL, - tuple, - proute->partition_tuple_slot, - &slot); + if (proute->parent_child_tupconv_maps) + { + TupleConversionMap *map = + proute->parent_child_tupconv_maps[leaf_part_index]; + + tuple = ConvertPartitionTupleSlot(map, tuple, + proute->partition_tuple_slot, + &slot); + } tuple->t_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc); } diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index d7b18f52ed..7661b246e4 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -126,12 +126,15 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, Relation rel) 0); /* - * If UPDATE needs to do tuple routing, we'll need a slot that will - * transiently store the tuple being routed using the root parent's - * rowtype. We must set up at least this slot, because it's needed even - * before tuple routing begins. Other necessary information is - * initialized when tuple routing code calls - * ExecUseUpdateResultRelForRouting. + * If UPDATE needs to do tuple routing, we can reuse partition sub-plan + * result rels after tuple routing, so build a hash table to map the OIDs + * of partitions present in mtstate->resultRelInfo to their + * ResultRelInfos. Every time a tuple is routed to one of the partitions + * present in mtstate->resultRelInfo, looking its OID up in the hash table + * will give us its ResultRelInfo. + * + * Also, we'll need a slot that will transiently store the tuple being + * routed using the root parent's rowtype. */ if (node && node->operation == CMD_UPDATE) { @@ -244,9 +247,9 @@ ExecFindPartition(ModifyTableState *mtstate, if (partdesc->is_leaf[partidx]) { /* - * Get the index for PartitionTupleRouting->partitions array index - * for this leaf partition. This may require building a new - * ResultRelInfo. + * Get this leaf partition's index in the + * PartitionTupleRouting->partitions array. We may require + * building a new ResultRelInfo. */ if (likely(parent->indexes[partidx] >= 0)) { @@ -256,6 +259,10 @@ ExecFindPartition(ModifyTableState *mtstate, } else { + /* + * No ResultRelInfo found, so either use one of the + * sub-plan result rels or create a fresh one. + */ if (proute->subplan_partition_table) { ResultRelInfo *rri; @@ -858,8 +865,8 @@ ExecInitRoutingInfo(ModifyTableState *mtstate, * Initialize PartitionDispatch for a partitioned table * * This also stores it in the proute->partition_dispatch_info array at the - * specified index ('dispatchidx'), possibly expanding the array if there - * isn't space left in it. + * specified index ('partdx'), possibly expanding the array if there isn't + * space left in it. */ static PartitionDispatch ExecInitPartitionDispatchInfo(PartitionTupleRouting *proute, Oid partoid, diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 6e0c7862dc..4f7cea7668 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -1779,12 +1779,9 @@ ExecPrepareTupleRouting(ModifyTableState *mtstate, /* * Convert the tuple, if necessary. */ - ConvertPartitionTupleSlot(proute->parent_child_tupconv_maps ? - proute->parent_child_tupconv_maps[partidx] : - NULL, - tuple, - proute->partition_tuple_slot, - &slot); + if (proute->parent_child_tupconv_maps) + ConvertPartitionTupleSlot(proute->parent_child_tupconv_maps[partidx], + tuple, proute->partition_tuple_slot, &slot); /* Initialize information needed to handle ON CONFLICT DO UPDATE. */ Assert(mtstate != NULL);