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.
PartitionDispatch *partition_dispatch_info;
ResultRelInfo *partitions;
TupleConversionMap **partition_tupconv_maps;
+ TupleTableSlot *partition_tuple_slot;
int num_parted,
num_partitions;
&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
/* 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()
* 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);
ExecCloseIndices(resultRelInfo);
heap_close(resultRelInfo->ri_RelationDesc, NoLock);
}
+
+ /* Release the standalone partition tuple descriptor */
+ ExecDropSingleTupleTableSlot(cstate->partition_tuple_slot);
}
FreeExecutorState(estate);
* 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
PartitionDispatch **pd,
ResultRelInfo **partitions,
TupleConversionMap ***tup_conv_maps,
+ TupleTableSlot **partition_tuple_slot,
int *num_parted, int *num_partitions)
{
TupleDesc tupDesc = RelationGetDescr(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)
* 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);
PartitionDispatch *partition_dispatch_info;
ResultRelInfo *partitions;
TupleConversionMap **partition_tupconv_maps;
+ TupleTableSlot *partition_tuple_slot;
int num_parted,
num_partitions;
&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.
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
*/
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,
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 */
ResultRelInfo *mt_partitions; /* Per partition result relation */
TupleConversionMap **mt_partition_tupconv_maps;
/* Per partition tuple conversion map */
+ TupleTableSlot *mt_partition_tuple_slot;
} ModifyTableState;
/* ----------------