diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 77a8631de1270fa667423573ce4e433078beaa43..071b97dee132a0356ed98c710ea248ab2fb138a1 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -161,11 +161,14 @@ typedef struct CopyStateData ExprState **defexprs; /* array of default att expressions */ bool volatile_defexprs; /* is any of defexprs volatile? */ List *range_table; + PartitionDispatch *partition_dispatch_info; - int num_dispatch; - int num_partitions; - ResultRelInfo *partitions; + int num_dispatch; /* Number of entries in the above array */ + int num_partitions; /* Number of members in the following + * arrays */ + ResultRelInfo *partitions; /* Per partition result relation */ TupleConversionMap **partition_tupconv_maps; + TupleTableSlot *partition_tuple_slot; /* * These variables are used to reduce overhead in textual COPY FROM. @@ -1409,6 +1412,7 @@ BeginCopy(ParseState *pstate, PartitionDispatch *partition_dispatch_info; ResultRelInfo *partitions; TupleConversionMap **partition_tupconv_maps; + TupleTableSlot *partition_tuple_slot; int num_parted, num_partitions; @@ -1416,12 +1420,14 @@ BeginCopy(ParseState *pstate, &partition_dispatch_info, &partitions, &partition_tupconv_maps, + &partition_tuple_slot, &num_parted, &num_partitions); cstate->partition_dispatch_info = partition_dispatch_info; cstate->num_dispatch = num_parted; cstate->partitions = partitions; cstate->num_partitions = num_partitions; cstate->partition_tupconv_maps = partition_tupconv_maps; + cstate->partition_tuple_slot = partition_tuple_slot; } } else @@ -2435,15 +2441,6 @@ CopyFrom(CopyState cstate) /* Triggers might need a slot as well */ estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate); - /* - * Initialize a dedicated slot to manipulate tuples of any given - * partition's rowtype. - */ - if (cstate->partition_dispatch_info) - estate->es_partition_tuple_slot = ExecInitExtraTupleSlot(estate); - else - estate->es_partition_tuple_slot = NULL; - /* * It's more efficient to prepare a bunch of tuples for insertion, and * insert them in one heap_multi_insert() call, than call heap_insert() @@ -2591,7 +2588,7 @@ CopyFrom(CopyState cstate) * we're finished dealing with the partition. */ oldslot = slot; - slot = estate->es_partition_tuple_slot; + slot = cstate->partition_tuple_slot; Assert(slot != NULL); ExecSetSlotDescriptor(slot, RelationGetDescr(partrel)); ExecStoreTuple(tuple, slot, InvalidBuffer, true); @@ -2756,6 +2753,9 @@ CopyFrom(CopyState cstate) ExecCloseIndices(resultRelInfo); heap_close(resultRelInfo->ri_RelationDesc, NoLock); } + + /* Release the standalone partition tuple descriptor */ + ExecDropSingleTupleTableSlot(cstate->partition_tuple_slot); } FreeExecutorState(estate); diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 7e3c207018f36a2e0fc7dd6a1bd0ba5af7642941..eb9b528c4e4800df885c185f1d2bd4371f1137cf 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -3012,6 +3012,9 @@ EvalPlanQualEnd(EPQState *epqstate) * entry for every leaf partition (required to convert input tuple based * on the root table's rowtype to a leaf partition's rowtype after tuple * routing is done + * 'partition_tuple_slot' receives a standalone TupleTableSlot to be used + * to manipulate any given leaf partition's rowtype after that partition + * is chosen by tuple-routing. * 'num_parted' receives the number of partitioned tables in the partition * tree (= the number of entries in the 'pd' output array) * 'num_partitions' receives the number of leaf partitions in the partition @@ -3026,6 +3029,7 @@ ExecSetupPartitionTupleRouting(Relation rel, PartitionDispatch **pd, ResultRelInfo **partitions, TupleConversionMap ***tup_conv_maps, + TupleTableSlot **partition_tuple_slot, int *num_parted, int *num_partitions) { TupleDesc tupDesc = RelationGetDescr(rel); @@ -3043,6 +3047,14 @@ ExecSetupPartitionTupleRouting(Relation rel, *tup_conv_maps = (TupleConversionMap **) palloc0(*num_partitions * sizeof(TupleConversionMap *)); + /* + * Initialize an empty slot that will be used to manipulate tuples of any + * given partition's rowtype. It is attached to the caller-specified node + * (such as ModifyTableState) and released when the node finishes + * processing. + */ + *partition_tuple_slot = MakeTupleTableSlot(); + leaf_part_rri = *partitions; i = 0; foreach(cell, leaf_parts) diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index c7dd148944eabf3506e856a6a542c3ca98dfdeb0..aa364707f8d321550eff2d182b349161370095dc 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -329,7 +329,7 @@ ExecInsert(ModifyTableState *mtstate, * Use the dedicated slot for that. */ oldslot = slot; - slot = estate->es_partition_tuple_slot; + slot = mtstate->mt_partition_tuple_slot; Assert(slot != NULL); ExecSetSlotDescriptor(slot, RelationGetDescr(partrel)); ExecStoreTuple(tuple, slot, InvalidBuffer, true); @@ -1738,6 +1738,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) PartitionDispatch *partition_dispatch_info; ResultRelInfo *partitions; TupleConversionMap **partition_tupconv_maps; + TupleTableSlot *partition_tuple_slot; int num_parted, num_partitions; @@ -1745,21 +1746,15 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) &partition_dispatch_info, &partitions, &partition_tupconv_maps, + &partition_tuple_slot, &num_parted, &num_partitions); mtstate->mt_partition_dispatch_info = partition_dispatch_info; mtstate->mt_num_dispatch = num_parted; mtstate->mt_partitions = partitions; mtstate->mt_num_partitions = num_partitions; mtstate->mt_partition_tupconv_maps = partition_tupconv_maps; - - /* - * Initialize a dedicated slot to manipulate tuples of any given - * partition's rowtype. - */ - estate->es_partition_tuple_slot = ExecInitExtraTupleSlot(estate); + mtstate->mt_partition_tuple_slot = partition_tuple_slot; } - else - estate->es_partition_tuple_slot = NULL; /* * Initialize any WITH CHECK OPTION constraints if needed. @@ -2100,6 +2095,10 @@ ExecEndModifyTable(ModifyTableState *node) heap_close(resultRelInfo->ri_RelationDesc, NoLock); } + /* Release the standalone partition tuple descriptor, if any */ + if (node->mt_partition_tuple_slot) + ExecDropSingleTupleTableSlot(node->mt_partition_tuple_slot); + /* * Free the exprcontext */ diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index a3fa5f076714126fd23402a9ce2bd44f1c39483a..4a7074edd70e9ac00108ec73f4870180ea18a5ed 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -217,6 +217,7 @@ extern void ExecSetupPartitionTupleRouting(Relation rel, PartitionDispatch **pd, ResultRelInfo **partitions, TupleConversionMap ***tup_conv_maps, + TupleTableSlot **partition_tuple_slot, int *num_parted, int *num_partitions); extern int ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd, diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 486555eac4c867bc8779d6ce54da2f0963d5b130..0e05d472c90728e285429a566f249803855677fc 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -384,9 +384,6 @@ typedef struct EState TupleTableSlot *es_trig_oldtup_slot; /* for TriggerEnabled */ TupleTableSlot *es_trig_newtup_slot; /* for TriggerEnabled */ - /* Slot used to manipulate a tuple after it is routed to a partition */ - TupleTableSlot *es_partition_tuple_slot; - /* Parameter info: */ ParamListInfo es_param_list_info; /* values of external params */ ParamExecData *es_param_exec_vals; /* values of internal params */ @@ -1165,6 +1162,7 @@ typedef struct ModifyTableState ResultRelInfo *mt_partitions; /* Per partition result relation */ TupleConversionMap **mt_partition_tupconv_maps; /* Per partition tuple conversion map */ + TupleTableSlot *mt_partition_tuple_slot; } ModifyTableState; /* ----------------