Redesign initialization of partition routing structures

This speeds up write operations (INSERT, UPDATE, DELETE, COPY, as well
as the future MERGE) on partitioned tables.

This changes the setup for tuple routing so that it does far less work
during the initial setup and pushes more work out to when partitions
receive tuples.  PartitionDispatchData structs for sub-partitioned
tables are only created when a tuple gets routed through it.  The
possibly large arrays in the PartitionTupleRouting struct have largely
been removed.  The partitions[] array remains but now never contains any
NULL gaps.  Previously the NULLs had to be skipped during
ExecCleanupTupleRouting(), which could add a large overhead to the
cleanup when the number of partitions was large.  The partitions[] array
is allocated small to start with and only enlarged when we route tuples
to enough partitions that it runs out of space. This allows us to keep
simple single-row partition INSERTs running quickly.  Redesign

The arrays in PartitionTupleRouting which stored the tuple translation maps
have now been removed.  These have been moved out into a
PartitionRoutingInfo struct which is an additional field in ResultRelInfo.

The find_all_inheritors() call still remains by far the slowest part of
ExecSetupPartitionTupleRouting(). This commit just removes the other slow
parts.

In passing also rename the tuple translation maps from being ParentToChild
and ChildToParent to being RootToPartition and PartitionToRoot. The old
names mislead you into thinking that a partition of some sub-partitioned
table would translate to the rowtype of the sub-partitioned table rather
than the root partitioned table.

Authors: David Rowley and Amit Langote, heavily revised by Álvaro Herrera
Testing help from Jesper Pedersen and Kato Sho.
Discussion: https://postgr.es/m/CAKJS1f_1RJyFquuCKRFHTdcXqoPX-PYqAd7nz=GVBwvGh4a6xA@mail.gmail.com
This commit is contained in:
Alvaro Herrera 2018-11-16 14:54:15 -03:00
parent a387a3dff9
commit 3f2393edef
9 changed files with 639 additions and 716 deletions

View File

@ -2316,6 +2316,7 @@ CopyFrom(CopyState cstate)
bool *nulls;
ResultRelInfo *resultRelInfo;
ResultRelInfo *target_resultRelInfo;
ResultRelInfo *prevResultRelInfo = NULL;
EState *estate = CreateExecutorState(); /* for ExecConstraints() */
ModifyTableState *mtstate;
ExprContext *econtext;
@ -2331,7 +2332,6 @@ CopyFrom(CopyState cstate)
CopyInsertMethod insertMethod;
uint64 processed = 0;
int nBufferedTuples = 0;
int prev_leaf_part_index = -1;
bool has_before_insert_row_trig;
bool has_instead_insert_row_trig;
bool leafpart_use_multi_insert = false;
@ -2515,8 +2515,12 @@ CopyFrom(CopyState cstate)
/*
* If there are any triggers with transition tables on the named relation,
* we need to be prepared to capture transition tuples.
*
* Because partition tuple routing would like to know about whether
* transition capture is active, we also set it in mtstate, which is
* passed to ExecFindPartition() below.
*/
cstate->transition_capture =
cstate->transition_capture = mtstate->mt_transition_capture =
MakeTransitionCaptureState(cstate->rel->trigdesc,
RelationGetRelid(cstate->rel),
CMD_INSERT);
@ -2526,19 +2530,8 @@ CopyFrom(CopyState cstate)
* CopyFrom tuple routing.
*/
if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
proute = ExecSetupPartitionTupleRouting(NULL, cstate->rel);
/*
* If we are capturing transition tuples, they may need to be
* converted from partition format back to partitioned table format
* (this is only ever necessary if a BEFORE trigger modifies the
* tuple).
*/
if (cstate->transition_capture != NULL)
ExecSetupChildParentMapForLeaf(proute);
}
/*
* 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()
@ -2694,25 +2687,17 @@ CopyFrom(CopyState cstate)
/* Determine the partition to heap_insert the tuple into */
if (proute)
{
int leaf_part_index;
TupleConversionMap *map;
/*
* Away we go ... If we end up not finding a partition after all,
* ExecFindPartition() does not return and errors out instead.
* Otherwise, the returned value is to be used as an index into
* arrays mt_partitions[] and mt_partition_tupconv_maps[] that
* will get us the ResultRelInfo and TupleConversionMap for the
* partition, respectively.
* Attempt to find a partition suitable for this tuple.
* ExecFindPartition() will raise an error if none can be found or
* if the found partition is not suitable for INSERTs.
*/
leaf_part_index = ExecFindPartition(target_resultRelInfo,
proute->partition_dispatch_info,
slot,
estate);
Assert(leaf_part_index >= 0 &&
leaf_part_index < proute->num_partitions);
resultRelInfo = ExecFindPartition(mtstate, target_resultRelInfo,
proute, slot, estate);
if (prev_leaf_part_index != leaf_part_index)
if (prevResultRelInfo != resultRelInfo)
{
/* Check if we can multi-insert into this partition */
if (insertMethod == CIM_MULTI_CONDITIONAL)
@ -2725,12 +2710,9 @@ CopyFrom(CopyState cstate)
if (nBufferedTuples > 0)
{
ExprContext *swapcontext;
ResultRelInfo *presultRelInfo;
presultRelInfo = proute->partitions[prev_leaf_part_index];
CopyFromInsertBatch(cstate, estate, mycid, hi_options,
presultRelInfo, myslot, bistate,
prevResultRelInfo, myslot, bistate,
nBufferedTuples, bufferedTuples,
firstBufferedLineNo);
nBufferedTuples = 0;
@ -2787,21 +2769,6 @@ CopyFrom(CopyState cstate)
}
}
/*
* Overwrite resultRelInfo with the corresponding partition's
* one.
*/
resultRelInfo = proute->partitions[leaf_part_index];
if (unlikely(resultRelInfo == NULL))
{
resultRelInfo = ExecInitPartitionInfo(mtstate,
target_resultRelInfo,
proute, estate,
leaf_part_index);
proute->partitions[leaf_part_index] = resultRelInfo;
Assert(resultRelInfo != NULL);
}
/* Determine which triggers exist on this partition */
has_before_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
resultRelInfo->ri_TrigDesc->trig_insert_before_row);
@ -2827,7 +2794,7 @@ CopyFrom(CopyState cstate)
* buffer when the partition being inserted into changes.
*/
ReleaseBulkInsertStatePin(bistate);
prev_leaf_part_index = leaf_part_index;
prevResultRelInfo = resultRelInfo;
}
/*
@ -2837,7 +2804,7 @@ CopyFrom(CopyState cstate)
/*
* If we're capturing transition tuples, we might need to convert
* from the partition rowtype to parent rowtype.
* from the partition rowtype to root rowtype.
*/
if (cstate->transition_capture != NULL)
{
@ -2850,8 +2817,7 @@ CopyFrom(CopyState cstate)
*/
cstate->transition_capture->tcs_original_insert_tuple = NULL;
cstate->transition_capture->tcs_map =
TupConvMapForLeaf(proute, target_resultRelInfo,
leaf_part_index);
resultRelInfo->ri_PartitionInfo->pi_PartitionToRootMap;
}
else
{
@ -2865,18 +2831,18 @@ CopyFrom(CopyState cstate)
}
/*
* We might need to convert from the parent rowtype to the
* partition rowtype.
* We might need to convert from the root rowtype to the partition
* rowtype.
*/
map = proute->parent_child_tupconv_maps[leaf_part_index];
map = resultRelInfo->ri_PartitionInfo->pi_RootToPartitionMap;
if (map != NULL)
{
TupleTableSlot *new_slot;
MemoryContext oldcontext;
Assert(proute->partition_tuple_slots != NULL &&
proute->partition_tuple_slots[leaf_part_index] != NULL);
new_slot = proute->partition_tuple_slots[leaf_part_index];
new_slot = resultRelInfo->ri_PartitionInfo->pi_PartitionTupleSlot;
Assert(new_slot != NULL);
slot = execute_attr_map_slot(map->attrMap, slot, new_slot);
/*
@ -3021,12 +2987,8 @@ CopyFrom(CopyState cstate)
{
if (insertMethod == CIM_MULTI_CONDITIONAL)
{
ResultRelInfo *presultRelInfo;
presultRelInfo = proute->partitions[prev_leaf_part_index];
CopyFromInsertBatch(cstate, estate, mycid, hi_options,
presultRelInfo, myslot, bistate,
prevResultRelInfo, myslot, bistate,
nBufferedTuples, bufferedTuples,
firstBufferedLineNo);
}

View File

@ -1345,7 +1345,7 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
resultRelInfo->ri_PartitionCheck = partition_check;
resultRelInfo->ri_PartitionRoot = partition_root;
resultRelInfo->ri_PartitionReadyForRouting = false;
resultRelInfo->ri_PartitionInfo = NULL; /* may be set later */
}
/*

File diff suppressed because it is too large Load Diff

View File

@ -68,7 +68,6 @@ static TupleTableSlot *ExecPrepareTupleRouting(ModifyTableState *mtstate,
ResultRelInfo *targetRelInfo,
TupleTableSlot *slot);
static ResultRelInfo *getTargetResultRelInfo(ModifyTableState *node);
static void ExecSetupChildParentMapForTcs(ModifyTableState *mtstate);
static void ExecSetupChildParentMapForSubplan(ModifyTableState *mtstate);
static TupleConversionMap *tupconv_map_for_subplan(ModifyTableState *node,
int whichplan);
@ -1157,7 +1156,8 @@ lreplace:;
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,
mtstate->mt_root_tuple_slot);
/*
* Prepare for tuple routing, making it look like we're inserting
@ -1653,7 +1653,7 @@ ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
if (mtstate->mt_transition_capture != NULL ||
mtstate->mt_oc_transition_capture != NULL)
{
ExecSetupChildParentMapForTcs(mtstate);
ExecSetupChildParentMapForSubplan(mtstate);
/*
* Install the conversion map for the first plan for UPDATE and DELETE
@ -1686,52 +1686,21 @@ ExecPrepareTupleRouting(ModifyTableState *mtstate,
TupleTableSlot *slot)
{
ModifyTable *node;
int partidx;
ResultRelInfo *partrel;
PartitionRoutingInfo *partrouteinfo;
HeapTuple tuple;
TupleConversionMap *map;
/*
* Determine the target partition. If ExecFindPartition does not find a
* partition after all, it doesn't return here; otherwise, the returned
* value is to be used as an index into the arrays for the ResultRelInfo
* and TupleConversionMap for the partition.
* Lookup the target partition's ResultRelInfo. If ExecFindPartition does
* not find a valid partition for the tuple in 'slot' then an error is
* raised. An error may also be raised if the found partition is not a
* valid target for INSERTs. This is required since a partitioned table
* UPDATE to another partition becomes a DELETE+INSERT.
*/
partidx = ExecFindPartition(targetRelInfo,
proute->partition_dispatch_info,
slot,
estate);
Assert(partidx >= 0 && partidx < proute->num_partitions);
/*
* Get the ResultRelInfo corresponding to the selected partition; if not
* yet there, initialize it.
*/
partrel = proute->partitions[partidx];
if (partrel == NULL)
partrel = ExecInitPartitionInfo(mtstate, targetRelInfo,
proute, estate,
partidx);
/*
* Check whether the partition is routable if we didn't yet
*
* Note: an UPDATE of a partition key invokes an INSERT that moves the
* tuple to a new partition. This check would be applied to a subplan
* partition of such an UPDATE that is chosen as the partition to route
* the tuple to. The reason we do this check here rather than in
* ExecSetupPartitionTupleRouting is to avoid aborting such an UPDATE
* unnecessarily due to non-routable subplan partitions that may not be
* chosen for update tuple movement after all.
*/
if (!partrel->ri_PartitionReadyForRouting)
{
/* Verify the partition is a valid target for INSERT. */
CheckValidResultRel(partrel, CMD_INSERT);
/* Set up information needed for routing tuples to the partition. */
ExecInitRoutingInfo(mtstate, estate, proute, partrel, partidx);
}
partrel = ExecFindPartition(mtstate, targetRelInfo, proute, slot, estate);
partrouteinfo = partrel->ri_PartitionInfo;
Assert(partrouteinfo != NULL);
/*
* Make it look like we are inserting into the partition.
@ -1743,7 +1712,7 @@ ExecPrepareTupleRouting(ModifyTableState *mtstate,
/*
* If we're capturing transition tuples, we might need to convert from the
* partition rowtype to parent rowtype.
* partition rowtype to root partitioned table's rowtype.
*/
if (mtstate->mt_transition_capture != NULL)
{
@ -1756,7 +1725,7 @@ ExecPrepareTupleRouting(ModifyTableState *mtstate,
*/
mtstate->mt_transition_capture->tcs_original_insert_tuple = NULL;
mtstate->mt_transition_capture->tcs_map =
TupConvMapForLeaf(proute, targetRelInfo, partidx);
partrouteinfo->pi_PartitionToRootMap;
}
else
{
@ -1771,20 +1740,17 @@ ExecPrepareTupleRouting(ModifyTableState *mtstate,
if (mtstate->mt_oc_transition_capture != NULL)
{
mtstate->mt_oc_transition_capture->tcs_map =
TupConvMapForLeaf(proute, targetRelInfo, partidx);
partrouteinfo->pi_PartitionToRootMap;
}
/*
* Convert the tuple, if necessary.
*/
map = proute->parent_child_tupconv_maps[partidx];
map = partrouteinfo->pi_RootToPartitionMap;
if (map != NULL)
{
TupleTableSlot *new_slot;
TupleTableSlot *new_slot = partrouteinfo->pi_PartitionTupleSlot;
Assert(proute->partition_tuple_slots != NULL &&
proute->partition_tuple_slots[partidx] != NULL);
new_slot = proute->partition_tuple_slots[partidx];
slot = execute_attr_map_slot(map->attrMap, slot, new_slot);
}
@ -1822,17 +1788,6 @@ ExecSetupChildParentMapForSubplan(ModifyTableState *mtstate)
int numResultRelInfos = mtstate->mt_nplans;
int i;
/*
* First check if there is already a per-subplan array allocated. Even if
* there is already a per-leaf map array, we won't require a per-subplan
* one, since we will use the subplan offset array to convert the subplan
* index to per-leaf index.
*/
if (mtstate->mt_per_subplan_tupconv_maps ||
(mtstate->mt_partition_tuple_routing &&
mtstate->mt_partition_tuple_routing->child_parent_tupconv_maps))
return;
/*
* Build array of conversion maps from each child's TupleDesc to the one
* used in the target relation. The map pointers may be NULL when no
@ -1854,79 +1809,18 @@ ExecSetupChildParentMapForSubplan(ModifyTableState *mtstate)
}
}
/*
* Initialize the child-to-root tuple conversion map array required for
* capturing transition tuples.
*
* The map array can be indexed either by subplan index or by leaf-partition
* index. For transition tables, we need a subplan-indexed access to the map,
* and where tuple-routing is present, we also require a leaf-indexed access.
*/
static void
ExecSetupChildParentMapForTcs(ModifyTableState *mtstate)
{
PartitionTupleRouting *proute = mtstate->mt_partition_tuple_routing;
/*
* If partition tuple routing is set up, we will require partition-indexed
* access. In that case, create the map array indexed by partition; we
* will still be able to access the maps using a subplan index by
* converting the subplan index to a partition index using
* subplan_partition_offsets. If tuple routing is not set up, it means we
* don't require partition-indexed access. In that case, create just a
* subplan-indexed map.
*/
if (proute)
{
/*
* If a partition-indexed map array is to be created, the subplan map
* array has to be NULL. If the subplan map array is already created,
* we won't be able to access the map using a partition index.
*/
Assert(mtstate->mt_per_subplan_tupconv_maps == NULL);
ExecSetupChildParentMapForLeaf(proute);
}
else
ExecSetupChildParentMapForSubplan(mtstate);
}
/*
* For a given subplan index, get the tuple conversion map.
*/
static TupleConversionMap *
tupconv_map_for_subplan(ModifyTableState *mtstate, int whichplan)
{
/*
* If a partition-index tuple conversion map array is allocated, we need
* to first get the index into the partition array. Exactly *one* of the
* two arrays is allocated. This is because if there is a partition array
* required, we don't require subplan-indexed array since we can translate
* subplan index into partition index. And, we create a subplan-indexed
* array *only* if partition-indexed array is not required.
*/
/* If nobody else set the per-subplan array of maps, do so ourselves. */
if (mtstate->mt_per_subplan_tupconv_maps == NULL)
{
int leaf_index;
PartitionTupleRouting *proute = mtstate->mt_partition_tuple_routing;
ExecSetupChildParentMapForSubplan(mtstate);
/*
* If subplan-indexed array is NULL, things should have been arranged
* to convert the subplan index to partition index.
*/
Assert(proute && proute->subplan_partition_offsets != NULL &&
whichplan < proute->num_subplan_partition_offsets);
leaf_index = proute->subplan_partition_offsets[whichplan];
return TupConvMapForLeaf(proute, getTargetResultRelInfo(mtstate),
leaf_index);
}
else
{
Assert(whichplan >= 0 && whichplan < mtstate->mt_nplans);
return mtstate->mt_per_subplan_tupconv_maps[whichplan];
}
Assert(whichplan >= 0 && whichplan < mtstate->mt_nplans);
return mtstate->mt_per_subplan_tupconv_maps[whichplan];
}
/* ----------------------------------------------------------------
@ -2370,10 +2264,15 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
* descriptor of a source partition does not match the root partitioned
* table descriptor. In such a case we need to convert tuples to the root
* tuple descriptor, because the search for destination partition starts
* from the root. Skip this setup if it's not a partition key update.
* from the root. We'll also need a slot to store these converted tuples.
* We can skip this setup if it's not a partition key update.
*/
if (update_tuple_routing_needed)
{
ExecSetupChildParentMapForSubplan(mtstate);
mtstate->mt_root_tuple_slot = MakeTupleTableSlot(RelationGetDescr(rel),
&TTSOpsHeapTuple);
}
/*
* Initialize any WITH CHECK OPTION constraints if needed.
@ -2716,10 +2615,18 @@ ExecEndModifyTable(ModifyTableState *node)
resultRelInfo);
}
/* Close all the partitioned tables, leaf partitions, and their indices */
/*
* Close all the partitioned tables, leaf partitions, and their indices
* and release the slot used for tuple routing, if set.
*/
if (node->mt_partition_tuple_routing)
{
ExecCleanupTupleRouting(node, node->mt_partition_tuple_routing);
if (node->mt_root_tuple_slot)
ExecDropSingleTupleTableSlot(node->mt_root_tuple_slot);
}
/*
* Free the exprcontext
*/

View File

@ -1657,9 +1657,6 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
/*
* expand_partitioned_rtentry
* Recursively expand an RTE for a partitioned table.
*
* Note that RelationGetPartitionDispatchInfo will expand partitions in the
* same order as this code.
*/
static void
expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,

View File

@ -340,15 +340,23 @@ RelationBuildPartitionDesc(Relation rel)
oldcxt = MemoryContextSwitchTo(rel->rd_pdcxt);
partdesc->boundinfo = partition_bounds_copy(boundinfo, key);
partdesc->oids = (Oid *) palloc(partdesc->nparts * sizeof(Oid));
partdesc->is_leaf = (bool *) palloc(partdesc->nparts * sizeof(bool));
/*
* Now assign OIDs from the original array into mapped indexes of the
* result array. Order of OIDs in the former is defined by the catalog
* scan that retrieved them, whereas that in the latter is defined by
* canonicalized representation of the partition bounds.
* result array. The order of OIDs in the former is defined by the
* catalog scan that retrieved them, whereas that in the latter is defined
* by canonicalized representation of the partition bounds.
*/
for (i = 0; i < partdesc->nparts; i++)
partdesc->oids[mapping[i]] = oids_orig[i];
{
int index = mapping[i];
partdesc->oids[index] = oids_orig[i];
/* Record if the partition is a leaf partition */
partdesc->is_leaf[index] =
(get_rel_relkind(oids_orig[i]) != RELKIND_PARTITIONED_TABLE);
}
MemoryContextSwitchTo(oldcxt);
rel->rd_partdesc = partdesc;

View File

@ -25,7 +25,11 @@
typedef struct PartitionDescData
{
int nparts; /* Number of partitions */
Oid *oids; /* OIDs of partitions */
Oid *oids; /* Array of 'nparts' elements containing
* partition OIDs in order of the their bounds */
bool *is_leaf; /* Array of 'nparts' elements storing whether
* the corresponding 'oids' element belongs to
* a leaf partition or not */
PartitionBoundInfo boundinfo; /* collection of partition bounds */
} PartitionDescData;

View File

@ -18,74 +18,36 @@
#include "nodes/plannodes.h"
#include "partitioning/partprune.h"
/* See execPartition.c for the definition. */
/* See execPartition.c for the definitions. */
typedef struct PartitionDispatchData *PartitionDispatch;
typedef struct PartitionTupleRouting PartitionTupleRouting;
/*-----------------------
* PartitionTupleRouting - Encapsulates all information required to execute
* tuple-routing between partitions.
/*
* PartitionRoutingInfo
*
* partition_dispatch_info Array of PartitionDispatch objects with one
* entry for every partitioned table in the
* partition tree.
* num_dispatch number of partitioned tables in the partition
* tree (= length of partition_dispatch_info[])
* partition_oids Array of leaf partitions OIDs with one entry
* for every leaf partition in the partition tree,
* initialized in full by
* ExecSetupPartitionTupleRouting.
* partitions Array of ResultRelInfo* objects with one entry
* for every leaf partition in the partition tree,
* initialized lazily by ExecInitPartitionInfo.
* num_partitions Number of leaf partitions in the partition tree
* (= 'partitions_oid'/'partitions' array length)
* parent_child_tupconv_maps Array of TupleConversionMap objects with one
* entry for every leaf partition (required to
* convert tuple from the root table's rowtype to
* a leaf partition's rowtype after tuple routing
* is done)
* child_parent_tupconv_maps Array of TupleConversionMap objects with one
* entry for every leaf partition (required to
* convert an updated tuple from the leaf
* partition's rowtype to the root table's rowtype
* so that tuple routing can be done)
* child_parent_map_not_required Array of bool. True value means that a map is
* determined to be not required for the given
* partition. False means either we haven't yet
* checked if a map is required, or it was
* determined to be required.
* subplan_partition_offsets Integer array ordered by UPDATE subplans. Each
* element of this array has the index into the
* corresponding partition in partitions array.
* num_subplan_partition_offsets Length of 'subplan_partition_offsets' array
* 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
* root_tuple_slot TupleTableSlot to be used to transiently hold
* copy of a tuple that's being moved across
* partitions in the root partitioned table's
* rowtype
*-----------------------
* Additional result relation information specific to routing tuples to a
* table partition.
*/
typedef struct PartitionTupleRouting
typedef struct PartitionRoutingInfo
{
PartitionDispatch *partition_dispatch_info;
int num_dispatch;
Oid *partition_oids;
ResultRelInfo **partitions;
int num_partitions;
TupleConversionMap **parent_child_tupconv_maps;
TupleConversionMap **child_parent_tupconv_maps;
bool *child_parent_map_not_required;
int *subplan_partition_offsets;
int num_subplan_partition_offsets;
TupleTableSlot **partition_tuple_slots;
TupleTableSlot *root_tuple_slot;
} PartitionTupleRouting;
/*
* Map for converting tuples in root partitioned table format into
* partition format, or NULL if no conversion is required.
*/
TupleConversionMap *pi_RootToPartitionMap;
/*
* Map for converting tuples in partition format into the root partitioned
* table format, or NULL if no conversion is required.
*/
TupleConversionMap *pi_PartitionToRootMap;
/*
* Slot to store tuples in partition format, or NULL when no translation
* is required between root and partition.
*/
TupleTableSlot *pi_PartitionTupleSlot;
} PartitionRoutingInfo;
/*
* PartitionedRelPruningData - Per-partitioned-table data for run-time pruning
@ -175,22 +137,11 @@ typedef struct PartitionPruneState
extern PartitionTupleRouting *ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
Relation rel);
extern int ExecFindPartition(ResultRelInfo *resultRelInfo,
PartitionDispatch *pd,
extern ResultRelInfo *ExecFindPartition(ModifyTableState *mtstate,
ResultRelInfo *rootResultRelInfo,
PartitionTupleRouting *proute,
TupleTableSlot *slot,
EState *estate);
extern ResultRelInfo *ExecInitPartitionInfo(ModifyTableState *mtstate,
ResultRelInfo *resultRelInfo,
PartitionTupleRouting *proute,
EState *estate, int partidx);
extern void ExecInitRoutingInfo(ModifyTableState *mtstate,
EState *estate,
PartitionTupleRouting *proute,
ResultRelInfo *partRelInfo,
int partidx);
extern void ExecSetupChildParentMapForLeaf(PartitionTupleRouting *proute);
extern TupleConversionMap *TupConvMapForLeaf(PartitionTupleRouting *proute,
ResultRelInfo *rootRelInfo, int leaf_index);
extern void ExecCleanupTupleRouting(ModifyTableState *mtstate,
PartitionTupleRouting *proute);
extern PartitionPruneState *ExecCreatePartitionPruneState(PlanState *planstate,

View File

@ -33,6 +33,7 @@
struct PlanState; /* forward references in this file */
struct PartitionRoutingInfo;
struct ParallelHashJoinState;
struct ExecRowMark;
struct ExprState;
@ -469,8 +470,8 @@ typedef struct ResultRelInfo
/* relation descriptor for root partitioned table */
Relation ri_PartitionRoot;
/* true if ready for tuple routing */
bool ri_PartitionReadyForRouting;
/* Additional information specific to partition tuple routing */
struct PartitionRoutingInfo *ri_PartitionInfo;
} ResultRelInfo;
/* ----------------
@ -1112,6 +1113,12 @@ typedef struct ModifyTableState
List *mt_excludedtlist; /* the excluded pseudo relation's tlist */
TupleTableSlot *mt_conflproj; /* CONFLICT ... SET ... projection target */
/*
* Slot for storing tuples in the root partitioned table's rowtype during
* an UPDATE of a partitioned table.
*/
TupleTableSlot *mt_root_tuple_slot;
/* Tuple-routing support info */
struct PartitionTupleRouting *mt_partition_tuple_routing;