diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index b45972682f..2b5e71b843 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -2528,7 +2528,7 @@ CopyFrom(CopyState cstate) * CopyFrom tuple routing. */ if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) - proute = ExecSetupPartitionTupleRouting(NULL, cstate->rel); + proute = ExecSetupPartitionTupleRouting(mtstate, cstate->rel); /* * It's more efficient to prepare a bunch of tuples for insertion, and diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 4b27874f01..0978a55f48 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -66,6 +66,98 @@ typedef struct PartitionDispatchData int indexes[FLEXIBLE_ARRAY_MEMBER]; } PartitionDispatchData; +/*----------------------- + * PartitionTupleRouting - Encapsulates all information required to + * route a tuple inserted into a partitioned table to one of its leaf + * partitions + * + * partition_root The partitioned table that's the target of the + * command. + * + * partition_dispatch_info Array of 'dispatch_allocsize' elements containing + * a pointer to a PartitionDispatch objects for every + * partitioned table touched by tuple routing. The + * entry for the target partitioned table is *always* + * present in the 0th element of this array. See + * comment for PartitionDispatchData->indexes for + * details on how this array is indexed. + * + * num_dispatch The current number of items stored in the + * 'partition_dispatch_info' array. Also serves as + * the index of the next free array element for new + * PartitionDispatch which need to be stored. + * + * dispatch_allocsize The current allocated size of the + * 'partition_dispatch_info' array. + * + * partitions Array of 'partitions_allocsize' elements + * containing pointers to a ResultRelInfos of all + * leaf partitions touched by tuple routing. Some of + * these are pointers to ResultRelInfos which are + * borrowed out of 'subplan_resultrel_hash'. The + * remainder have been built especially for tuple + * routing. See comment for + * PartitionDispatchData->indexes for details on how + * this array is indexed. + * + * num_partitions The current number of items stored in the + * 'partitions' array. Also serves as the index of + * the next free array element for new ResultRelInfos + * which need to be stored. + * + * partitions_allocsize The current allocated size of the 'partitions' + * array. Also, if they're non-NULL, marks the size + * of the 'parent_child_tupconv_maps', + * 'child_parent_tupconv_maps', + * 'child_parent_map_not_required' and + * 'partition_tuple_slots' arrays. + * + * parent_child_tupconv_maps Array of partitions_allocsize elements + * containing information on how to convert tuples of + * partition_root's rowtype to the rowtype of the + * corresponding partition as stored in 'partitions', + * or NULL if no conversion is required. The entire + * array is only allocated when the first conversion + * map needs to stored. When not allocated it's set + * to NULL. + * + * partition_tuple_slots Array of TupleTableSlot objects; if non-NULL, + * contains one entry for every leaf partition, + * of which only those of the leaf partitions + * whose attribute numbers differ from the root + * parent have a non-NULL value. NULL if all of + * the partitions encountered by a given command + * happen to have same rowtype as the root parent + * + * child_parent_tupconv_maps As 'parent_child_tupconv_maps' but stores + * conversion maps to translate partition tuples into + * partition_root's rowtype, needed if transition + * capture is active + * + * Note: The following fields are used only when UPDATE ends up needing to + * do tuple routing. + * + * subplan_resultrel_hash Hash table to store subplan ResultRelInfos by Oid. + * This is used to cache ResultRelInfos from subplans + * of a ModifyTable node. Some of these may be + * useful for tuple routing to save having to build + * duplicates. + *----------------------- + */ +typedef struct PartitionTupleRouting +{ + Relation partition_root; + PartitionDispatch *partition_dispatch_info; + int num_dispatch; + int dispatch_allocsize; + ResultRelInfo **partitions; + int num_partitions; + int partitions_allocsize; + TupleConversionMap **parent_child_tupconv_maps; + TupleConversionMap **child_parent_tupconv_maps; + TupleTableSlot **partition_tuple_slots; + HTAB *subplan_resultrel_hash; +} PartitionTupleRouting; static void ExecHashSubPlanResultRelsByOid(ModifyTableState *mtstate, PartitionTupleRouting *proute); @@ -179,12 +271,12 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, Relation rel) if (node && node->operation == CMD_UPDATE) { ExecHashSubPlanResultRelsByOid(mtstate, proute); - proute->root_tuple_slot = MakeTupleTableSlot(RelationGetDescr(rel)); + mtstate->mt_root_tuple_slot = MakeTupleTableSlot(RelationGetDescr(rel)); } else { proute->subplan_resultrel_hash = NULL; - proute->root_tuple_slot = NULL; + mtstate->mt_root_tuple_slot = NULL; } return proute; @@ -1175,10 +1267,6 @@ ExecCleanupTupleRouting(ModifyTableState *mtstate, ExecCloseIndices(resultRelInfo); heap_close(resultRelInfo->ri_RelationDesc, NoLock); } - - /* Release the standalone partition tuple descriptors, if any */ - if (proute->root_tuple_slot) - ExecDropSingleTupleTableSlot(proute->root_tuple_slot); } /* ---------------- diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 18c55e2b19..390191bdc8 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -1161,8 +1161,8 @@ lreplace:; Assert(map_index >= 0 && map_index < mtstate->mt_nplans); tupconv_map = tupconv_map_for_subplan(mtstate, map_index); if (tupconv_map != NULL) - slot = execute_attr_map_slot(tupconv_map->attrMap, - slot, proute->root_tuple_slot); + slot = execute_attr_map_slot(tupconv_map->attrMap, slot, + mtstate->mt_root_tuple_slot); /* * Prepare for tuple routing, making it look like we're inserting @@ -2616,6 +2616,10 @@ ExecEndModifyTable(ModifyTableState *node) */ for (i = 0; i < node->mt_nplans; i++) ExecEndNode(node->mt_plans[i]); + + /* Release the standalone partition tuple descriptors, if any */ + if (node->mt_root_tuple_slot) + ExecDropSingleTupleTableSlot(node->mt_root_tuple_slot); } void diff --git a/src/include/executor/execPartition.h b/src/include/executor/execPartition.h index 7c8314362c..91886f1b19 100644 --- a/src/include/executor/execPartition.h +++ b/src/include/executor/execPartition.h @@ -18,108 +18,9 @@ #include "nodes/plannodes.h" #include "partitioning/partprune.h" -/* See execPartition.c for the definition. */ +/* See execPartition.c for the definitions. */ typedef struct PartitionDispatchData *PartitionDispatch; - -/*----------------------- - * PartitionTupleRouting - Encapsulates all information required to - * route a tuple inserted into a partitioned table to one of its leaf - * partitions - * - * partition_root The partitioned table that's the target of the - * command. - * - * partition_dispatch_info Array of 'dispatch_allocsize' elements containing - * a pointer to a PartitionDispatch objects for every - * partitioned table touched by tuple routing. The - * entry for the target partitioned table is *always* - * present in the 0th element of this array. See - * comment for PartitionDispatchData->indexes for - * details on how this array is indexed. - * - * num_dispatch The current number of items stored in the - * 'partition_dispatch_info' array. Also serves as - * the index of the next free array element for new - * PartitionDispatch which need to be stored. - * - * dispatch_allocsize The current allocated size of the - * 'partition_dispatch_info' array. - * - * partitions Array of 'partitions_allocsize' elements - * containing pointers to a ResultRelInfos of all - * leaf partitions touched by tuple routing. Some of - * these are pointers to ResultRelInfos which are - * borrowed out of 'subplan_resultrel_hash'. The - * remainder have been built especially for tuple - * routing. See comment for - * PartitionDispatchData->indexes for details on how - * this array is indexed. - * - * num_partitions The current number of items stored in the - * 'partitions' array. Also serves as the index of - * the next free array element for new ResultRelInfos - * which need to be stored. - * - * partitions_allocsize The current allocated size of the 'partitions' - * array. Also, if they're non-NULL, marks the size - * of the 'parent_child_tupconv_maps', - * 'child_parent_tupconv_maps', - * 'child_parent_map_not_required' and - * 'partition_tuple_slots' arrays. - * - * parent_child_tupconv_maps Array of partitions_allocsize elements - * containing information on how to convert tuples of - * partition_root's rowtype to the rowtype of the - * corresponding partition as stored in 'partitions', - * or NULL if no conversion is required. The entire - * array is only allocated when the first conversion - * map needs to stored. When not allocated it's set - * to NULL. - * - * partition_tuple_slots Array of TupleTableSlot objects; if non-NULL, - * contains one entry for every leaf partition, - * of which only those of the leaf partitions - * whose attribute numbers differ from the root - * parent have a non-NULL value. NULL if all of - * the partitions encountered by a given command - * happen to have same rowtype as the root parent - * - * child_parent_tupconv_maps As 'parent_child_tupconv_maps' but stores - * conversion maps to translate partition tuples into - * partition_root's rowtype, needed if transition - * capture is active - * - * Note: The following fields are used only when UPDATE ends up needing to - * do tuple routing. - * - * subplan_resultrel_hash Hash table to store subplan ResultRelInfos by Oid. - * This is used to cache ResultRelInfos from subplans - * of a ModifyTable node. Some of these may be - * useful for tuple routing to save having to build - * duplicates. - * - * root_tuple_slot During UPDATE tuple routing, this tuple slot is - * used to transiently store a tuple using the root - * table's rowtype after converting it from the - * tuple's source leaf partition's rowtype. That is, - * if leaf partition's rowtype is different. - *----------------------- - */ -typedef struct PartitionTupleRouting -{ - Relation partition_root; - PartitionDispatch *partition_dispatch_info; - int num_dispatch; - int dispatch_allocsize; - ResultRelInfo **partitions; - int num_partitions; - int partitions_allocsize; - TupleConversionMap **parent_child_tupconv_maps; - TupleConversionMap **child_parent_tupconv_maps; - TupleTableSlot **partition_tuple_slots; - TupleTableSlot *root_tuple_slot; - HTAB *subplan_resultrel_hash; -} PartitionTupleRouting; +typedef struct PartitionTupleRouting PartitionTupleRouting; /* * PartitionedRelPruningData - Per-partitioned-table data for run-time pruning diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 880a03e4e4..73ecc20074 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -1084,6 +1084,14 @@ typedef struct ModifyTableState /* Per plan map for tuple conversion from child to root */ TupleConversionMap **mt_per_subplan_tupconv_maps; + + /* + * During UPDATE tuple routing, this tuple slot is used to transiently + * store a tuple using the root table's rowtype after converting it from + * the tuple's source leaf partition's rowtype. That is, if leaf + * partition's rowtype is different. + */ + TupleTableSlot *mt_root_tuple_slot; } ModifyTableState; /* ----------------