mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-24 18:55:04 +08:00
Simplify and encapsulate tuple routing support code.
Instead of having ExecSetupPartitionTupleRouting return multiple out parameters, have it return a pointer to a structure containing all of those different things. Also, provide and use a cleanup function, ExecCleanupTupleRouting, instead of cleaning up all of the resources allocated by ExecSetupPartitionTupleRouting individually. Amit Khandekar, reviewed by Amit Langote, David Rowley, and me Discussion: http://postgr.es/m/CAJ3gD9fWfxgKC+PfJZF3hkgAcNOy-LpfPxVYitDEXKHjeieWQQ@mail.gmail.com
This commit is contained in:
parent
d3fb72ea6d
commit
cc6337d2fe
@ -166,12 +166,9 @@ typedef struct CopyStateData
|
|||||||
bool volatile_defexprs; /* is any of defexprs volatile? */
|
bool volatile_defexprs; /* is any of defexprs volatile? */
|
||||||
List *range_table;
|
List *range_table;
|
||||||
|
|
||||||
PartitionDispatch *partition_dispatch_info;
|
/* Tuple-routing support info */
|
||||||
int num_dispatch; /* Number of entries in the above array */
|
PartitionTupleRouting *partition_tuple_routing;
|
||||||
int num_partitions; /* Number of members in the following arrays */
|
|
||||||
ResultRelInfo **partitions; /* Per partition result relation pointers */
|
|
||||||
TupleConversionMap **partition_tupconv_maps;
|
|
||||||
TupleTableSlot *partition_tuple_slot;
|
|
||||||
TransitionCaptureState *transition_capture;
|
TransitionCaptureState *transition_capture;
|
||||||
TupleConversionMap **transition_tupconv_maps;
|
TupleConversionMap **transition_tupconv_maps;
|
||||||
|
|
||||||
@ -2472,28 +2469,10 @@ CopyFrom(CopyState cstate)
|
|||||||
*/
|
*/
|
||||||
if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
|
if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
|
||||||
{
|
{
|
||||||
PartitionDispatch *partition_dispatch_info;
|
PartitionTupleRouting *proute;
|
||||||
ResultRelInfo **partitions;
|
|
||||||
TupleConversionMap **partition_tupconv_maps;
|
|
||||||
TupleTableSlot *partition_tuple_slot;
|
|
||||||
int num_parted,
|
|
||||||
num_partitions;
|
|
||||||
|
|
||||||
ExecSetupPartitionTupleRouting(NULL,
|
proute = cstate->partition_tuple_routing =
|
||||||
cstate->rel,
|
ExecSetupPartitionTupleRouting(NULL, cstate->rel, 1, estate);
|
||||||
1,
|
|
||||||
estate,
|
|
||||||
&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;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are capturing transition tuples, they may need to be
|
* If we are capturing transition tuples, they may need to be
|
||||||
@ -2506,11 +2485,11 @@ CopyFrom(CopyState cstate)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
cstate->transition_tupconv_maps = (TupleConversionMap **)
|
cstate->transition_tupconv_maps = (TupleConversionMap **)
|
||||||
palloc0(sizeof(TupleConversionMap *) * cstate->num_partitions);
|
palloc0(sizeof(TupleConversionMap *) * proute->num_partitions);
|
||||||
for (i = 0; i < cstate->num_partitions; ++i)
|
for (i = 0; i < proute->num_partitions; ++i)
|
||||||
{
|
{
|
||||||
cstate->transition_tupconv_maps[i] =
|
cstate->transition_tupconv_maps[i] =
|
||||||
convert_tuples_by_name(RelationGetDescr(cstate->partitions[i]->ri_RelationDesc),
|
convert_tuples_by_name(RelationGetDescr(proute->partitions[i]->ri_RelationDesc),
|
||||||
RelationGetDescr(cstate->rel),
|
RelationGetDescr(cstate->rel),
|
||||||
gettext_noop("could not convert row type"));
|
gettext_noop("could not convert row type"));
|
||||||
}
|
}
|
||||||
@ -2530,7 +2509,7 @@ CopyFrom(CopyState cstate)
|
|||||||
if ((resultRelInfo->ri_TrigDesc != NULL &&
|
if ((resultRelInfo->ri_TrigDesc != NULL &&
|
||||||
(resultRelInfo->ri_TrigDesc->trig_insert_before_row ||
|
(resultRelInfo->ri_TrigDesc->trig_insert_before_row ||
|
||||||
resultRelInfo->ri_TrigDesc->trig_insert_instead_row)) ||
|
resultRelInfo->ri_TrigDesc->trig_insert_instead_row)) ||
|
||||||
cstate->partition_dispatch_info != NULL ||
|
cstate->partition_tuple_routing != NULL ||
|
||||||
cstate->volatile_defexprs)
|
cstate->volatile_defexprs)
|
||||||
{
|
{
|
||||||
useHeapMultiInsert = false;
|
useHeapMultiInsert = false;
|
||||||
@ -2605,10 +2584,11 @@ CopyFrom(CopyState cstate)
|
|||||||
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
|
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
|
||||||
|
|
||||||
/* Determine the partition to heap_insert the tuple into */
|
/* Determine the partition to heap_insert the tuple into */
|
||||||
if (cstate->partition_dispatch_info)
|
if (cstate->partition_tuple_routing)
|
||||||
{
|
{
|
||||||
int leaf_part_index;
|
int leaf_part_index;
|
||||||
TupleConversionMap *map;
|
TupleConversionMap *map;
|
||||||
|
PartitionTupleRouting *proute = cstate->partition_tuple_routing;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Away we go ... If we end up not finding a partition after all,
|
* Away we go ... If we end up not finding a partition after all,
|
||||||
@ -2619,11 +2599,11 @@ CopyFrom(CopyState cstate)
|
|||||||
* partition, respectively.
|
* partition, respectively.
|
||||||
*/
|
*/
|
||||||
leaf_part_index = ExecFindPartition(resultRelInfo,
|
leaf_part_index = ExecFindPartition(resultRelInfo,
|
||||||
cstate->partition_dispatch_info,
|
proute->partition_dispatch_info,
|
||||||
slot,
|
slot,
|
||||||
estate);
|
estate);
|
||||||
Assert(leaf_part_index >= 0 &&
|
Assert(leaf_part_index >= 0 &&
|
||||||
leaf_part_index < cstate->num_partitions);
|
leaf_part_index < proute->num_partitions);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this tuple is mapped to a partition that is not same as the
|
* If this tuple is mapped to a partition that is not same as the
|
||||||
@ -2641,7 +2621,7 @@ CopyFrom(CopyState cstate)
|
|||||||
* to the selected partition.
|
* to the selected partition.
|
||||||
*/
|
*/
|
||||||
saved_resultRelInfo = resultRelInfo;
|
saved_resultRelInfo = resultRelInfo;
|
||||||
resultRelInfo = cstate->partitions[leaf_part_index];
|
resultRelInfo = proute->partitions[leaf_part_index];
|
||||||
|
|
||||||
/* We do not yet have a way to insert into a foreign partition */
|
/* We do not yet have a way to insert into a foreign partition */
|
||||||
if (resultRelInfo->ri_FdwRoutine)
|
if (resultRelInfo->ri_FdwRoutine)
|
||||||
@ -2688,7 +2668,7 @@ CopyFrom(CopyState cstate)
|
|||||||
* We might need to convert from the parent rowtype to the
|
* We might need to convert from the parent rowtype to the
|
||||||
* partition rowtype.
|
* partition rowtype.
|
||||||
*/
|
*/
|
||||||
map = cstate->partition_tupconv_maps[leaf_part_index];
|
map = proute->partition_tupconv_maps[leaf_part_index];
|
||||||
if (map)
|
if (map)
|
||||||
{
|
{
|
||||||
Relation partrel = resultRelInfo->ri_RelationDesc;
|
Relation partrel = resultRelInfo->ri_RelationDesc;
|
||||||
@ -2700,7 +2680,7 @@ CopyFrom(CopyState cstate)
|
|||||||
* point on. Use a dedicated slot from this point on until
|
* point on. Use a dedicated slot from this point on until
|
||||||
* we're finished dealing with the partition.
|
* we're finished dealing with the partition.
|
||||||
*/
|
*/
|
||||||
slot = cstate->partition_tuple_slot;
|
slot = proute->partition_tuple_slot;
|
||||||
Assert(slot != NULL);
|
Assert(slot != NULL);
|
||||||
ExecSetSlotDescriptor(slot, RelationGetDescr(partrel));
|
ExecSetSlotDescriptor(slot, RelationGetDescr(partrel));
|
||||||
ExecStoreTuple(tuple, slot, InvalidBuffer, true);
|
ExecStoreTuple(tuple, slot, InvalidBuffer, true);
|
||||||
@ -2852,34 +2832,8 @@ CopyFrom(CopyState cstate)
|
|||||||
ExecCloseIndices(resultRelInfo);
|
ExecCloseIndices(resultRelInfo);
|
||||||
|
|
||||||
/* Close all the partitioned tables, leaf partitions, and their indices */
|
/* Close all the partitioned tables, leaf partitions, and their indices */
|
||||||
if (cstate->partition_dispatch_info)
|
if (cstate->partition_tuple_routing)
|
||||||
{
|
ExecCleanupTupleRouting(cstate->partition_tuple_routing);
|
||||||
int i;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Remember cstate->partition_dispatch_info[0] corresponds to the root
|
|
||||||
* partitioned table, which we must not try to close, because it is
|
|
||||||
* the main target table of COPY that will be closed eventually by
|
|
||||||
* DoCopy(). Also, tupslot is NULL for the root partitioned table.
|
|
||||||
*/
|
|
||||||
for (i = 1; i < cstate->num_dispatch; i++)
|
|
||||||
{
|
|
||||||
PartitionDispatch pd = cstate->partition_dispatch_info[i];
|
|
||||||
|
|
||||||
heap_close(pd->reldesc, NoLock);
|
|
||||||
ExecDropSingleTupleTableSlot(pd->tupslot);
|
|
||||||
}
|
|
||||||
for (i = 0; i < cstate->num_partitions; i++)
|
|
||||||
{
|
|
||||||
ResultRelInfo *resultRelInfo = cstate->partitions[i];
|
|
||||||
|
|
||||||
ExecCloseIndices(resultRelInfo);
|
|
||||||
heap_close(resultRelInfo->ri_RelationDesc, NoLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Release the standalone partition tuple descriptor */
|
|
||||||
ExecDropSingleTupleTableSlot(cstate->partition_tuple_slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close any trigger target relations */
|
/* Close any trigger target relations */
|
||||||
ExecCleanUpTriggerState(estate);
|
ExecCleanUpTriggerState(estate);
|
||||||
|
@ -38,58 +38,40 @@ static char *ExecBuildSlotPartitionKeyDescription(Relation rel,
|
|||||||
int maxfieldlen);
|
int maxfieldlen);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ExecSetupPartitionTupleRouting - set up information needed during
|
* ExecSetupPartitionTupleRouting - sets up information needed during
|
||||||
* tuple routing for partitioned tables
|
* tuple routing for partitioned tables, encapsulates it in
|
||||||
*
|
* PartitionTupleRouting, and returns it.
|
||||||
* Output arguments:
|
|
||||||
* 'pd' receives an array of PartitionDispatch objects with one entry for
|
|
||||||
* every partitioned table in the partition tree
|
|
||||||
* 'partitions' receives an array of ResultRelInfo* objects with one entry for
|
|
||||||
* every leaf partition in the partition tree
|
|
||||||
* 'tup_conv_maps' receives an array of TupleConversionMap objects with one
|
|
||||||
* 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
|
|
||||||
* tree (= the number of entries in the 'partitions' and 'tup_conv_maps'
|
|
||||||
* output arrays
|
|
||||||
*
|
*
|
||||||
* Note that all the relations in the partition tree are locked using the
|
* Note that all the relations in the partition tree are locked using the
|
||||||
* RowExclusiveLock mode upon return from this function.
|
* RowExclusiveLock mode upon return from this function.
|
||||||
*/
|
*/
|
||||||
void
|
PartitionTupleRouting *
|
||||||
ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
|
ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
|
||||||
Relation rel,
|
Relation rel, Index resultRTindex,
|
||||||
Index resultRTindex,
|
EState *estate)
|
||||||
EState *estate,
|
|
||||||
PartitionDispatch **pd,
|
|
||||||
ResultRelInfo ***partitions,
|
|
||||||
TupleConversionMap ***tup_conv_maps,
|
|
||||||
TupleTableSlot **partition_tuple_slot,
|
|
||||||
int *num_parted, int *num_partitions)
|
|
||||||
{
|
{
|
||||||
TupleDesc tupDesc = RelationGetDescr(rel);
|
TupleDesc tupDesc = RelationGetDescr(rel);
|
||||||
List *leaf_parts;
|
List *leaf_parts;
|
||||||
ListCell *cell;
|
ListCell *cell;
|
||||||
int i;
|
int i;
|
||||||
ResultRelInfo *leaf_part_rri;
|
ResultRelInfo *leaf_part_rri;
|
||||||
|
PartitionTupleRouting *proute;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the information about the partition tree after locking all the
|
* Get the information about the partition tree after locking all the
|
||||||
* partitions.
|
* partitions.
|
||||||
*/
|
*/
|
||||||
(void) find_all_inheritors(RelationGetRelid(rel), RowExclusiveLock, NULL);
|
(void) find_all_inheritors(RelationGetRelid(rel), RowExclusiveLock, NULL);
|
||||||
*pd = RelationGetPartitionDispatchInfo(rel, num_parted, &leaf_parts);
|
proute = (PartitionTupleRouting *) palloc0(sizeof(PartitionTupleRouting));
|
||||||
*num_partitions = list_length(leaf_parts);
|
proute->partition_dispatch_info =
|
||||||
*partitions = (ResultRelInfo **) palloc(*num_partitions *
|
RelationGetPartitionDispatchInfo(rel, &proute->num_dispatch,
|
||||||
sizeof(ResultRelInfo *));
|
&leaf_parts);
|
||||||
*tup_conv_maps = (TupleConversionMap **) palloc0(*num_partitions *
|
proute->num_partitions = list_length(leaf_parts);
|
||||||
sizeof(TupleConversionMap *));
|
proute->partitions = (ResultRelInfo **) palloc(proute->num_partitions *
|
||||||
|
sizeof(ResultRelInfo *));
|
||||||
|
proute->partition_tupconv_maps =
|
||||||
|
(TupleConversionMap **) palloc0(proute->num_partitions *
|
||||||
|
sizeof(TupleConversionMap *));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize an empty slot that will be used to manipulate tuples of any
|
* Initialize an empty slot that will be used to manipulate tuples of any
|
||||||
@ -97,9 +79,9 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
|
|||||||
* (such as ModifyTableState) and released when the node finishes
|
* (such as ModifyTableState) and released when the node finishes
|
||||||
* processing.
|
* processing.
|
||||||
*/
|
*/
|
||||||
*partition_tuple_slot = MakeTupleTableSlot();
|
proute->partition_tuple_slot = MakeTupleTableSlot();
|
||||||
|
|
||||||
leaf_part_rri = (ResultRelInfo *) palloc0(*num_partitions *
|
leaf_part_rri = (ResultRelInfo *) palloc0(proute->num_partitions *
|
||||||
sizeof(ResultRelInfo));
|
sizeof(ResultRelInfo));
|
||||||
i = 0;
|
i = 0;
|
||||||
foreach(cell, leaf_parts)
|
foreach(cell, leaf_parts)
|
||||||
@ -109,8 +91,8 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* We locked all the partitions above including the leaf partitions.
|
* We locked all the partitions above including the leaf partitions.
|
||||||
* Note that each of the relations in *partitions are eventually
|
* Note that each of the relations in proute->partitions are
|
||||||
* closed by the caller.
|
* eventually closed by the caller.
|
||||||
*/
|
*/
|
||||||
partrel = heap_open(lfirst_oid(cell), NoLock);
|
partrel = heap_open(lfirst_oid(cell), NoLock);
|
||||||
part_tupdesc = RelationGetDescr(partrel);
|
part_tupdesc = RelationGetDescr(partrel);
|
||||||
@ -119,8 +101,9 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
|
|||||||
* Save a tuple conversion map to convert a tuple routed to this
|
* Save a tuple conversion map to convert a tuple routed to this
|
||||||
* partition from the parent's type to the partition's.
|
* partition from the parent's type to the partition's.
|
||||||
*/
|
*/
|
||||||
(*tup_conv_maps)[i] = convert_tuples_by_name(tupDesc, part_tupdesc,
|
proute->partition_tupconv_maps[i] =
|
||||||
gettext_noop("could not convert row type"));
|
convert_tuples_by_name(tupDesc, part_tupdesc,
|
||||||
|
gettext_noop("could not convert row type"));
|
||||||
|
|
||||||
InitResultRelInfo(leaf_part_rri,
|
InitResultRelInfo(leaf_part_rri,
|
||||||
partrel,
|
partrel,
|
||||||
@ -149,9 +132,11 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
|
|||||||
estate->es_leaf_result_relations =
|
estate->es_leaf_result_relations =
|
||||||
lappend(estate->es_leaf_result_relations, leaf_part_rri);
|
lappend(estate->es_leaf_result_relations, leaf_part_rri);
|
||||||
|
|
||||||
(*partitions)[i] = leaf_part_rri++;
|
proute->partitions[i] = leaf_part_rri++;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return proute;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -272,6 +257,45 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ExecCleanupTupleRouting -- Clean up objects allocated for partition tuple
|
||||||
|
* routing.
|
||||||
|
*
|
||||||
|
* Close all the partitioned tables, leaf partitions, and their indices.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ExecCleanupTupleRouting(PartitionTupleRouting * proute)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remember, proute->partition_dispatch_info[0] corresponds to the root
|
||||||
|
* partitioned table, which we must not try to close, because it is the
|
||||||
|
* main target table of the query that will be closed by callers such as
|
||||||
|
* ExecEndPlan() or DoCopy(). Also, tupslot is NULL for the root
|
||||||
|
* partitioned table.
|
||||||
|
*/
|
||||||
|
for (i = 1; i < proute->num_dispatch; i++)
|
||||||
|
{
|
||||||
|
PartitionDispatch pd = proute->partition_dispatch_info[i];
|
||||||
|
|
||||||
|
heap_close(pd->reldesc, NoLock);
|
||||||
|
ExecDropSingleTupleTableSlot(pd->tupslot);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < proute->num_partitions; i++)
|
||||||
|
{
|
||||||
|
ResultRelInfo *resultRelInfo = proute->partitions[i];
|
||||||
|
|
||||||
|
ExecCloseIndices(resultRelInfo);
|
||||||
|
heap_close(resultRelInfo->ri_RelationDesc, NoLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the standalone partition tuple descriptor, if any */
|
||||||
|
if (proute->partition_tuple_slot)
|
||||||
|
ExecDropSingleTupleTableSlot(proute->partition_tuple_slot);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RelationGetPartitionDispatchInfo
|
* RelationGetPartitionDispatchInfo
|
||||||
* Returns information necessary to route tuples down a partition tree
|
* Returns information necessary to route tuples down a partition tree
|
||||||
|
@ -279,32 +279,33 @@ ExecInsert(ModifyTableState *mtstate,
|
|||||||
resultRelInfo = estate->es_result_relation_info;
|
resultRelInfo = estate->es_result_relation_info;
|
||||||
|
|
||||||
/* Determine the partition to heap_insert the tuple into */
|
/* Determine the partition to heap_insert the tuple into */
|
||||||
if (mtstate->mt_partition_dispatch_info)
|
if (mtstate->mt_partition_tuple_routing)
|
||||||
{
|
{
|
||||||
int leaf_part_index;
|
int leaf_part_index;
|
||||||
|
PartitionTupleRouting *proute = mtstate->mt_partition_tuple_routing;
|
||||||
TupleConversionMap *map;
|
TupleConversionMap *map;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Away we go ... If we end up not finding a partition after all,
|
* Away we go ... If we end up not finding a partition after all,
|
||||||
* ExecFindPartition() does not return and errors out instead.
|
* ExecFindPartition() does not return and errors out instead.
|
||||||
* Otherwise, the returned value is to be used as an index into arrays
|
* Otherwise, the returned value is to be used as an index into arrays
|
||||||
* mt_partitions[] and mt_partition_tupconv_maps[] that will get us
|
* proute->partitions[] and proute->partition_tupconv_maps[] that will
|
||||||
* the ResultRelInfo and TupleConversionMap for the partition,
|
* get us the ResultRelInfo and TupleConversionMap for the partition,
|
||||||
* respectively.
|
* respectively.
|
||||||
*/
|
*/
|
||||||
leaf_part_index = ExecFindPartition(resultRelInfo,
|
leaf_part_index = ExecFindPartition(resultRelInfo,
|
||||||
mtstate->mt_partition_dispatch_info,
|
proute->partition_dispatch_info,
|
||||||
slot,
|
slot,
|
||||||
estate);
|
estate);
|
||||||
Assert(leaf_part_index >= 0 &&
|
Assert(leaf_part_index >= 0 &&
|
||||||
leaf_part_index < mtstate->mt_num_partitions);
|
leaf_part_index < proute->num_partitions);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save the old ResultRelInfo and switch to the one corresponding to
|
* Save the old ResultRelInfo and switch to the one corresponding to
|
||||||
* the selected partition.
|
* the selected partition.
|
||||||
*/
|
*/
|
||||||
saved_resultRelInfo = resultRelInfo;
|
saved_resultRelInfo = resultRelInfo;
|
||||||
resultRelInfo = mtstate->mt_partitions[leaf_part_index];
|
resultRelInfo = proute->partitions[leaf_part_index];
|
||||||
|
|
||||||
/* We do not yet have a way to insert into a foreign partition */
|
/* We do not yet have a way to insert into a foreign partition */
|
||||||
if (resultRelInfo->ri_FdwRoutine)
|
if (resultRelInfo->ri_FdwRoutine)
|
||||||
@ -352,7 +353,7 @@ ExecInsert(ModifyTableState *mtstate,
|
|||||||
* We might need to convert from the parent rowtype to the partition
|
* We might need to convert from the parent rowtype to the partition
|
||||||
* rowtype.
|
* rowtype.
|
||||||
*/
|
*/
|
||||||
map = mtstate->mt_partition_tupconv_maps[leaf_part_index];
|
map = proute->partition_tupconv_maps[leaf_part_index];
|
||||||
if (map)
|
if (map)
|
||||||
{
|
{
|
||||||
Relation partrel = resultRelInfo->ri_RelationDesc;
|
Relation partrel = resultRelInfo->ri_RelationDesc;
|
||||||
@ -364,7 +365,7 @@ ExecInsert(ModifyTableState *mtstate,
|
|||||||
* on, until we're finished dealing with the partition. Use the
|
* on, until we're finished dealing with the partition. Use the
|
||||||
* dedicated slot for that.
|
* dedicated slot for that.
|
||||||
*/
|
*/
|
||||||
slot = mtstate->mt_partition_tuple_slot;
|
slot = proute->partition_tuple_slot;
|
||||||
Assert(slot != NULL);
|
Assert(slot != NULL);
|
||||||
ExecSetSlotDescriptor(slot, RelationGetDescr(partrel));
|
ExecSetSlotDescriptor(slot, RelationGetDescr(partrel));
|
||||||
ExecStoreTuple(tuple, slot, InvalidBuffer, true);
|
ExecStoreTuple(tuple, slot, InvalidBuffer, true);
|
||||||
@ -1500,9 +1501,10 @@ ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
|
|||||||
mtstate->mt_oc_transition_capture != NULL)
|
mtstate->mt_oc_transition_capture != NULL)
|
||||||
{
|
{
|
||||||
int numResultRelInfos;
|
int numResultRelInfos;
|
||||||
|
PartitionTupleRouting *proute = mtstate->mt_partition_tuple_routing;
|
||||||
|
|
||||||
numResultRelInfos = (mtstate->mt_partition_tuple_slot != NULL ?
|
numResultRelInfos = (proute != NULL ?
|
||||||
mtstate->mt_num_partitions :
|
proute->num_partitions :
|
||||||
mtstate->mt_nplans);
|
mtstate->mt_nplans);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1515,13 +1517,13 @@ ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
|
|||||||
palloc0(sizeof(TupleConversionMap *) * numResultRelInfos);
|
palloc0(sizeof(TupleConversionMap *) * numResultRelInfos);
|
||||||
|
|
||||||
/* Choose the right set of partitions */
|
/* Choose the right set of partitions */
|
||||||
if (mtstate->mt_partition_dispatch_info != NULL)
|
if (proute != NULL)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* For tuple routing among partitions, we need TupleDescs based on
|
* For tuple routing among partitions, we need TupleDescs based on
|
||||||
* the partition routing table.
|
* the partition routing table.
|
||||||
*/
|
*/
|
||||||
ResultRelInfo **resultRelInfos = mtstate->mt_partitions;
|
ResultRelInfo **resultRelInfos = proute->partitions;
|
||||||
|
|
||||||
for (i = 0; i < numResultRelInfos; ++i)
|
for (i = 0; i < numResultRelInfos; ++i)
|
||||||
{
|
{
|
||||||
@ -1832,6 +1834,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
|
|||||||
ListCell *l;
|
ListCell *l;
|
||||||
int i;
|
int i;
|
||||||
Relation rel;
|
Relation rel;
|
||||||
|
PartitionTupleRouting *proute = NULL;
|
||||||
|
int num_partitions = 0;
|
||||||
|
|
||||||
/* check for unsupported flags */
|
/* check for unsupported flags */
|
||||||
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
|
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
|
||||||
@ -1945,28 +1949,11 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
|
|||||||
if (operation == CMD_INSERT &&
|
if (operation == CMD_INSERT &&
|
||||||
rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
|
rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
|
||||||
{
|
{
|
||||||
PartitionDispatch *partition_dispatch_info;
|
proute = mtstate->mt_partition_tuple_routing =
|
||||||
ResultRelInfo **partitions;
|
ExecSetupPartitionTupleRouting(mtstate,
|
||||||
TupleConversionMap **partition_tupconv_maps;
|
rel, node->nominalRelation,
|
||||||
TupleTableSlot *partition_tuple_slot;
|
estate);
|
||||||
int num_parted,
|
num_partitions = proute->num_partitions;
|
||||||
num_partitions;
|
|
||||||
|
|
||||||
ExecSetupPartitionTupleRouting(mtstate,
|
|
||||||
rel,
|
|
||||||
node->nominalRelation,
|
|
||||||
estate,
|
|
||||||
&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;
|
|
||||||
mtstate->mt_partition_tuple_slot = partition_tuple_slot;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2009,7 +1996,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
|
|||||||
* will suffice. This only occurs for the INSERT case; UPDATE/DELETE
|
* will suffice. This only occurs for the INSERT case; UPDATE/DELETE
|
||||||
* cases are handled above.
|
* cases are handled above.
|
||||||
*/
|
*/
|
||||||
if (node->withCheckOptionLists != NIL && mtstate->mt_num_partitions > 0)
|
if (node->withCheckOptionLists != NIL && num_partitions > 0)
|
||||||
{
|
{
|
||||||
List *wcoList;
|
List *wcoList;
|
||||||
PlanState *plan;
|
PlanState *plan;
|
||||||
@ -2026,14 +2013,14 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
|
|||||||
mtstate->mt_nplans == 1);
|
mtstate->mt_nplans == 1);
|
||||||
wcoList = linitial(node->withCheckOptionLists);
|
wcoList = linitial(node->withCheckOptionLists);
|
||||||
plan = mtstate->mt_plans[0];
|
plan = mtstate->mt_plans[0];
|
||||||
for (i = 0; i < mtstate->mt_num_partitions; i++)
|
for (i = 0; i < num_partitions; i++)
|
||||||
{
|
{
|
||||||
Relation partrel;
|
Relation partrel;
|
||||||
List *mapped_wcoList;
|
List *mapped_wcoList;
|
||||||
List *wcoExprs = NIL;
|
List *wcoExprs = NIL;
|
||||||
ListCell *ll;
|
ListCell *ll;
|
||||||
|
|
||||||
resultRelInfo = mtstate->mt_partitions[i];
|
resultRelInfo = proute->partitions[i];
|
||||||
partrel = resultRelInfo->ri_RelationDesc;
|
partrel = resultRelInfo->ri_RelationDesc;
|
||||||
|
|
||||||
/* varno = node->nominalRelation */
|
/* varno = node->nominalRelation */
|
||||||
@ -2101,12 +2088,12 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
|
|||||||
* are handled above.
|
* are handled above.
|
||||||
*/
|
*/
|
||||||
returningList = linitial(node->returningLists);
|
returningList = linitial(node->returningLists);
|
||||||
for (i = 0; i < mtstate->mt_num_partitions; i++)
|
for (i = 0; i < num_partitions; i++)
|
||||||
{
|
{
|
||||||
Relation partrel;
|
Relation partrel;
|
||||||
List *rlist;
|
List *rlist;
|
||||||
|
|
||||||
resultRelInfo = mtstate->mt_partitions[i];
|
resultRelInfo = proute->partitions[i];
|
||||||
partrel = resultRelInfo->ri_RelationDesc;
|
partrel = resultRelInfo->ri_RelationDesc;
|
||||||
|
|
||||||
/* varno = node->nominalRelation */
|
/* varno = node->nominalRelation */
|
||||||
@ -2372,32 +2359,9 @@ ExecEndModifyTable(ModifyTableState *node)
|
|||||||
resultRelInfo);
|
resultRelInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Close all the partitioned tables, leaf partitions, and their indices */
|
||||||
* Close all the partitioned tables, leaf partitions, and their indices
|
if (node->mt_partition_tuple_routing)
|
||||||
*
|
ExecCleanupTupleRouting(node->mt_partition_tuple_routing);
|
||||||
* Remember node->mt_partition_dispatch_info[0] corresponds to the root
|
|
||||||
* partitioned table, which we must not try to close, because it is the
|
|
||||||
* main target table of the query that will be closed by ExecEndPlan().
|
|
||||||
* Also, tupslot is NULL for the root partitioned table.
|
|
||||||
*/
|
|
||||||
for (i = 1; i < node->mt_num_dispatch; i++)
|
|
||||||
{
|
|
||||||
PartitionDispatch pd = node->mt_partition_dispatch_info[i];
|
|
||||||
|
|
||||||
heap_close(pd->reldesc, NoLock);
|
|
||||||
ExecDropSingleTupleTableSlot(pd->tupslot);
|
|
||||||
}
|
|
||||||
for (i = 0; i < node->mt_num_partitions; i++)
|
|
||||||
{
|
|
||||||
ResultRelInfo *resultRelInfo = node->mt_partitions[i];
|
|
||||||
|
|
||||||
ExecCloseIndices(resultRelInfo);
|
|
||||||
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
|
* Free the exprcontext
|
||||||
|
@ -49,18 +49,47 @@ typedef struct PartitionDispatchData
|
|||||||
|
|
||||||
typedef struct PartitionDispatchData *PartitionDispatch;
|
typedef struct PartitionDispatchData *PartitionDispatch;
|
||||||
|
|
||||||
extern void ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
|
/*-----------------------
|
||||||
Relation rel,
|
* PartitionTupleRouting - Encapsulates all information required to execute
|
||||||
Index resultRTindex,
|
* tuple-routing between partitions.
|
||||||
EState *estate,
|
*
|
||||||
PartitionDispatch **pd,
|
* partition_dispatch_info Array of PartitionDispatch objects with one
|
||||||
ResultRelInfo ***partitions,
|
* entry for every partitioned table in the
|
||||||
TupleConversionMap ***tup_conv_maps,
|
* partition tree.
|
||||||
TupleTableSlot **partition_tuple_slot,
|
* num_dispatch number of partitioned tables in the partition
|
||||||
int *num_parted, int *num_partitions);
|
* tree (= length of partition_dispatch_info[])
|
||||||
|
* partitions Array of ResultRelInfo* objects with one entry
|
||||||
|
* for every leaf partition in the partition tree.
|
||||||
|
* num_partitions Number of leaf partitions in the partition tree
|
||||||
|
* (= 'partitions' array length)
|
||||||
|
* partition_tupconv_maps Array of TupleConversionMap objects with one
|
||||||
|
* 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 TupleTableSlot to be used to manipulate any
|
||||||
|
* given leaf partition's rowtype after that
|
||||||
|
* partition is chosen for insertion by
|
||||||
|
* tuple-routing.
|
||||||
|
*-----------------------
|
||||||
|
*/
|
||||||
|
typedef struct PartitionTupleRouting
|
||||||
|
{
|
||||||
|
PartitionDispatch *partition_dispatch_info;
|
||||||
|
int num_dispatch;
|
||||||
|
ResultRelInfo **partitions;
|
||||||
|
int num_partitions;
|
||||||
|
TupleConversionMap **partition_tupconv_maps;
|
||||||
|
TupleTableSlot *partition_tuple_slot;
|
||||||
|
} PartitionTupleRouting;
|
||||||
|
|
||||||
|
extern PartitionTupleRouting *ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
|
||||||
|
Relation rel, Index resultRTindex,
|
||||||
|
EState *estate);
|
||||||
extern int ExecFindPartition(ResultRelInfo *resultRelInfo,
|
extern int ExecFindPartition(ResultRelInfo *resultRelInfo,
|
||||||
PartitionDispatch *pd,
|
PartitionDispatch *pd,
|
||||||
TupleTableSlot *slot,
|
TupleTableSlot *slot,
|
||||||
EState *estate);
|
EState *estate);
|
||||||
|
extern void ExecCleanupTupleRouting(PartitionTupleRouting *proute);
|
||||||
|
|
||||||
#endif /* EXECPARTITION_H */
|
#endif /* EXECPARTITION_H */
|
||||||
|
@ -985,15 +985,8 @@ typedef struct ModifyTableState
|
|||||||
TupleTableSlot *mt_existing; /* slot to store existing target tuple in */
|
TupleTableSlot *mt_existing; /* slot to store existing target tuple in */
|
||||||
List *mt_excludedtlist; /* the excluded pseudo relation's tlist */
|
List *mt_excludedtlist; /* the excluded pseudo relation's tlist */
|
||||||
TupleTableSlot *mt_conflproj; /* CONFLICT ... SET ... projection target */
|
TupleTableSlot *mt_conflproj; /* CONFLICT ... SET ... projection target */
|
||||||
struct PartitionDispatchData **mt_partition_dispatch_info;
|
struct PartitionTupleRouting *mt_partition_tuple_routing;
|
||||||
/* Tuple-routing support info */
|
/* Tuple-routing support info */
|
||||||
int mt_num_dispatch; /* Number of entries in the above array */
|
|
||||||
int mt_num_partitions; /* Number of members in the following
|
|
||||||
* arrays */
|
|
||||||
ResultRelInfo **mt_partitions; /* Per partition result relation pointers */
|
|
||||||
TupleConversionMap **mt_partition_tupconv_maps;
|
|
||||||
/* Per partition tuple conversion map */
|
|
||||||
TupleTableSlot *mt_partition_tuple_slot;
|
|
||||||
struct TransitionCaptureState *mt_transition_capture;
|
struct TransitionCaptureState *mt_transition_capture;
|
||||||
/* controls transition table population for specified operation */
|
/* controls transition table population for specified operation */
|
||||||
struct TransitionCaptureState *mt_oc_transition_capture;
|
struct TransitionCaptureState *mt_oc_transition_capture;
|
||||||
|
Loading…
Reference in New Issue
Block a user