conversion_map_changes.patch
application/octet-stream
Filename: conversion_map_changes.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/backend/commands/copy.c | 4 | 16 |
| src/backend/executor/execPartition.c | 65 | 2 |
| src/backend/executor/nodeModifyTable.c | 70 | 86 |
| src/include/executor/execPartition.h | 18 | 2 |
| src/include/nodes/execnodes.h | 2 | 3 |
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index d869ac5..04a24c6 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -170,7 +170,6 @@ typedef struct CopyStateData
PartitionTupleRouting *partition_tuple_routing;
TransitionCaptureState *transition_capture;
- TupleConversionMap **transition_tupconv_maps;
/*
* These variables are used to reduce overhead in textual COPY FROM.
@@ -2481,19 +2480,7 @@ CopyFrom(CopyState cstate)
* tuple).
*/
if (cstate->transition_capture != NULL)
- {
- int i;
-
- cstate->transition_tupconv_maps = (TupleConversionMap **)
- palloc0(sizeof(TupleConversionMap *) * proute->num_partitions);
- for (i = 0; i < proute->num_partitions; ++i)
- {
- cstate->transition_tupconv_maps[i] =
- convert_tuples_by_name(RelationGetDescr(proute->partitions[i]->ri_RelationDesc),
- RelationGetDescr(cstate->rel),
- gettext_noop("could not convert row type"));
- }
- }
+ ExecSetupChildParentMapForLeaf(proute);
}
/*
@@ -2650,7 +2637,8 @@ CopyFrom(CopyState cstate)
*/
cstate->transition_capture->tcs_original_insert_tuple = NULL;
cstate->transition_capture->tcs_map =
- cstate->transition_tupconv_maps[leaf_part_index];
+ TupConvMapForLeaf(proute, saved_resultRelInfo,
+ leaf_part_index);
}
else
{
@@ -2667,7 +2655,7 @@ CopyFrom(CopyState cstate)
* We might need to convert from the parent rowtype to the
* partition rowtype.
*/
- tuple = ConvertPartitionTupleSlot(proute->partition_tupconv_maps[leaf_part_index],
+ tuple = ConvertPartitionTupleSlot(proute->parent_child_tupconv_maps[leaf_part_index],
tuple,
proute->partition_tuple_slot,
&slot);
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index 5100d82..9d3677f 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -73,7 +73,7 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
proute->num_partitions = list_length(leaf_parts);
proute->partitions = (ResultRelInfo **) palloc(proute->num_partitions *
sizeof(ResultRelInfo *));
- proute->partition_tupconv_maps =
+ proute->parent_child_tupconv_maps =
(TupleConversionMap **) palloc0(proute->num_partitions *
sizeof(TupleConversionMap *));
@@ -198,7 +198,7 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
* Save a tuple conversion map to convert a tuple routed to this
* partition from the parent's type to the partition's.
*/
- proute->partition_tupconv_maps[i] =
+ proute->parent_child_tupconv_maps[i] =
convert_tuples_by_name(tupDesc, part_tupdesc,
gettext_noop("could not convert row type"));
@@ -358,6 +358,69 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
}
/*
+ * Initialize the per-leaf-partition child-to-root tuple conversion map array.
+ *
+ * This map is required for capturing transition tuples when the target table
+ * is a partitioned table. For tuple that is routed by INSERT or UPDATE, we
+ * need to convert from the leaf partition to the target table descriptor.
+ *
+ */
+void
+ExecSetupChildParentMapForLeaf(PartitionTupleRouting *proute)
+{
+ Assert(proute != NULL);
+
+ /*
+ * These array elements gets filled up with maps on an on-demand basis.
+ * Initially just set all of them to NULL.
+ */
+ proute->child_parent_tupconv_maps =
+ palloc0(sizeof(TupleConversionMap *) * proute->num_partitions);
+
+ /* Same is the case for this array. */
+ proute->child_parent_tupconv_map_not_reqd =
+ (bool *) palloc0(sizeof(bool) * proute->num_partitions);
+}
+
+/*
+ * TupConvMapForLeaf -- For a given leaf partitions index, get the tuple
+ * conversion map.
+ */
+TupleConversionMap *
+TupConvMapForLeaf(PartitionTupleRouting *proute,
+ ResultRelInfo *rootRelInfo, int leaf_index)
+{
+ Assert(leaf_index >= 0 && leaf_index < proute->num_partitions);
+ Assert(proute->child_parent_tupconv_maps != NULL);
+
+ /* If it is already determined that the map is not required, return NULL. */
+ if (proute->child_parent_tupconv_map_not_reqd[leaf_index])
+ return NULL;
+ else
+ {
+ ResultRelInfo **resultRelInfos = proute->partitions;
+ TupleConversionMap **map = proute->child_parent_tupconv_maps + leaf_index;
+
+ /*
+ * Either the map is already allocated, or it is yet to be determined
+ * if the map is required.
+ */
+ if (!*map)
+ {
+ *map =
+ convert_tuples_by_name(RelationGetDescr(resultRelInfos[leaf_index]->ri_RelationDesc),
+ RelationGetDescr(rootRelInfo->ri_RelationDesc),
+ gettext_noop("could not convert row type"));
+
+ /* Update the array element with the new info */
+ proute->child_parent_tupconv_map_not_reqd[leaf_index] =
+ (*map == NULL);
+ }
+ return *map;
+ }
+}
+
+/*
* ConvertPartitionTupleSlot -- convenience function for tuple conversion using
* 'map'. The tuple, if converted, is stored in 'new_slot', and 'p_my_slot' is
* updated with the 'new_slot'. 'new_slot' typically should be one of the
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 5f1c51f..0335339 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -64,7 +64,9 @@ static bool ExecOnConflictUpdate(ModifyTableState *mtstate,
EState *estate,
bool canSetTag,
TupleTableSlot **returning);
-static void ExecSetupChildParentMap(ModifyTableState *mtstate, bool perleaf);
+static ResultRelInfo *getASTriggerResultRelInfo(ModifyTableState *node);
+static void ExecSetupChildParentMapForTcs(ModifyTableState *mtstate);
+static void ExecSetupChildParentMapForSubplan(ModifyTableState *mtstate);
static inline TupleConversionMap *tupconv_map_for_subplan(ModifyTableState *node,
int whichplan);
/*
@@ -336,9 +338,10 @@ ExecInsert(ModifyTableState *mtstate,
*/
mtstate->mt_transition_capture->tcs_original_insert_tuple = NULL;
- Assert(mtstate->mt_is_tupconv_perpart);
mtstate->mt_transition_capture->tcs_map =
- mtstate->mt_childparent_tupconv_maps[leaf_part_index];
+ TupConvMapForLeaf(proute,
+ getASTriggerResultRelInfo(mtstate),
+ leaf_part_index);
}
else
{
@@ -352,16 +355,16 @@ ExecInsert(ModifyTableState *mtstate,
}
if (mtstate->mt_oc_transition_capture != NULL)
{
- Assert(mtstate->mt_is_tupconv_perpart);
mtstate->mt_oc_transition_capture->tcs_map =
- mtstate->mt_childparent_tupconv_maps[leaf_part_index];
+ TupConvMapForLeaf(proute, getASTriggerResultRelInfo(mtstate),
+ leaf_part_index);
}
/*
* We might need to convert from the parent rowtype to the partition
* rowtype.
*/
- tuple = ConvertPartitionTupleSlot(proute->partition_tupconv_maps[leaf_part_index],
+ tuple = ConvertPartitionTupleSlot(proute->parent_child_tupconv_maps[leaf_part_index],
tuple,
proute->partition_tuple_slot,
&slot);
@@ -1682,8 +1685,7 @@ ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
if (mtstate->mt_transition_capture != NULL ||
mtstate->mt_oc_transition_capture != NULL)
{
- ExecSetupChildParentMap(mtstate,
- (mtstate->mt_partition_tuple_routing != NULL));
+ ExecSetupChildParentMapForTcs(mtstate);
/*
* Install the conversion map for the first plan for UPDATE and DELETE
@@ -1698,55 +1700,32 @@ ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
}
/*
- * Initialize the child-to-root tuple conversion map array.
+ * Initialize the child-to-root tuple conversion map array for UPDATE subplans.
*
* This map array is required for two purposes:
* 1. For update-tuple-routing. We need to convert the tuple from the subplan
* result rel to the root partitioned table descriptor.
- * 2. For capturing transition tuples when the target table is a partitioned
- * table. For updates, we need to convert the tuple from the subplan result
- * rel to the target table descriptor, and for inserts, we need to convert
- * the inserted tuple from the leaf partition to the target table
- * descriptor.
- *
- * The caller can request either a per-subplan map or per-leaf-partition map.
+ * 2. For capturing transition tuples For updates, we need to convert the tuple
+ * from the subplan result rel to the target table descriptor.
*/
-static void
-ExecSetupChildParentMap(ModifyTableState *mtstate, bool perleaf)
+void
+ExecSetupChildParentMapForSubplan(ModifyTableState *mtstate)
{
ResultRelInfo *rootRelInfo = getASTriggerResultRelInfo(mtstate);
- PartitionTupleRouting *proute = mtstate->mt_partition_tuple_routing;
+ ResultRelInfo *resultRelInfos = mtstate->resultRelInfo;
TupleDesc outdesc;
- int numResultRelInfos;
+ int numResultRelInfos = mtstate->mt_nplans;
int i;
- /* First check if there is already one */
- if (mtstate->mt_childparent_tupconv_maps)
- {
- /*
- * If per-leaf map is required and the map is already created, that map
- * has to be per-leaf. If that map is per-subplan, we won't be able to
- * access the maps leaf-partition-wise. But if the map is per-leaf, we
- * will be able to access the maps subplan-wise using the
- * subplan_partition_offsets map using function
- * tupconv_map_for_subplan(). So if the callers might need to access
- * the map both leaf-partition-wise and subplan-wise, they should make
- * sure that the first time this function is called, it should be
- * called with perleaf=true so that the map created is per-leaf, not
- * per-subplan.
- */
- Assert(!(perleaf && !mtstate->mt_is_tupconv_perpart));
+ /*
+ * First check if there is already one. Even if there is already a per-leaf
+ * map, 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;
- }
-
- /* If perleaf is true, partition tuple routing info has to be present */
- Assert(!perleaf || proute != NULL);
-
- numResultRelInfos = (perleaf ? proute->num_partitions :
- mtstate->mt_nplans);
-
- /* Get tuple descriptor of the root partitioned table. */
- outdesc = RelationGetDescr(rootRelInfo->ri_RelationDesc);
/*
* Build array of conversion maps from each child's TupleDesc to the
@@ -1754,48 +1733,55 @@ ExecSetupChildParentMap(ModifyTableState *mtstate, bool perleaf)
* conversion is necessary, which is hopefully a common case for
* partitions.
*/
- mtstate->mt_childparent_tupconv_maps = (TupleConversionMap **)
+
+ /* Get tuple descriptor of the root partitioned table. */
+ outdesc = RelationGetDescr(rootRelInfo->ri_RelationDesc);
+
+ mtstate->mt_per_subplan_tupconv_maps =
palloc(sizeof(TupleConversionMap *) * numResultRelInfos);
- /* Choose the right set of partitions */
- if (perleaf)
+ for (i = 0; i < numResultRelInfos; ++i)
{
- /*
- * For tuple routing among partitions, we need TupleDescs based on the
- * partition routing table.
- */
- ResultRelInfo **resultRelInfos;
-
- resultRelInfos = proute->partitions;
+ mtstate->mt_per_subplan_tupconv_maps[i] =
+ convert_tuples_by_name(RelationGetDescr(resultRelInfos[i].ri_RelationDesc),
+ outdesc,
+ gettext_noop("could not convert row type"));
+ }
+}
- for (i = 0; i < numResultRelInfos; ++i)
- {
- mtstate->mt_childparent_tupconv_maps[i] =
- convert_tuples_by_name(RelationGetDescr(resultRelInfos[i]->ri_RelationDesc),
- outdesc,
- gettext_noop("could not convert row type"));
- }
+/*
+ * Initialize the child-to-root tuple conversion map array required for
+ * capturing transition tuples.
+ *
+ * For updates, a per-subplan map is required, and additionally a
+ * per-leaf-partition map is required when tuples are routed in case of updates
+ * or inserts.
+ */
+static void
+ExecSetupChildParentMapForTcs(ModifyTableState *mtstate)
+{
+ PartitionTupleRouting *proute = mtstate->mt_partition_tuple_routing;
+ /*
+ * For transition tables, we need a subplan-indexed access, and where
+ * tuple-routing is present, we also require a leaf-indexed access.
+ */
+ if (proute)
+ {
/*
- * Save the info that the tuple conversion map is per-leaf, not
- * per-subplan
+ * If per-leaf map is to be created, the subplan map has to be NULL.
+ * If the subplan map is already created, we won't be able to access
+ * the map leaf-partition-wise. But if the map is per-leaf, we will be
+ * able to access the maps subplan-wise using the
+ * subplan_partition_offsets map using function
+ * tupconv_map_for_subplan().
*/
- mtstate->mt_is_tupconv_perpart = true;
- }
- else
- {
- /* Otherwise we need the ResultRelInfo for each subplan. */
- ResultRelInfo *resultRelInfos = mtstate->resultRelInfo;
+ Assert(mtstate->mt_per_subplan_tupconv_maps == NULL);
- for (i = 0; i < numResultRelInfos; ++i)
- {
- mtstate->mt_childparent_tupconv_maps[i] =
- convert_tuples_by_name(RelationGetDescr(resultRelInfos[i].ri_RelationDesc),
- outdesc,
- gettext_noop("could not convert row type"));
- }
+ ExecSetupChildParentMapForLeaf(proute);
}
-
+ else
+ ExecSetupChildParentMapForSubplan(mtstate);
}
/*
@@ -1804,13 +1790,11 @@ ExecSetupChildParentMap(ModifyTableState *mtstate, bool perleaf)
static inline TupleConversionMap *
tupconv_map_for_subplan(ModifyTableState *mtstate, int whichplan)
{
- Assert(mtstate->mt_childparent_tupconv_maps != NULL);
-
/*
* If the tuple conversion map array is per-partition, we need to first get
* the index into the partition array.
*/
- if (mtstate->mt_is_tupconv_perpart)
+ if (mtstate->mt_per_subplan_tupconv_maps == NULL)
{
int leaf_index;
PartitionTupleRouting *proute = mtstate->mt_partition_tuple_routing;
@@ -1818,13 +1802,13 @@ tupconv_map_for_subplan(ModifyTableState *mtstate, int whichplan)
Assert(proute && proute->subplan_partition_offsets != NULL);
leaf_index = proute->subplan_partition_offsets[whichplan];
- Assert(leaf_index >= 0 && leaf_index < proute->num_partitions);
- return mtstate->mt_childparent_tupconv_maps[leaf_index];
+ return TupConvMapForLeaf(proute, getASTriggerResultRelInfo(mtstate),
+ leaf_index);
}
else
{
Assert(whichplan >= 0 && whichplan < mtstate->mt_nplans);
- return mtstate->mt_childparent_tupconv_maps[whichplan];
+ return mtstate->mt_per_subplan_tupconv_maps[whichplan];
}
}
@@ -2270,7 +2254,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
* from the root. Skip this setup if it's not a partition key update.
*/
if (update_tuple_routing_needed)
- ExecSetupChildParentMap(mtstate, false);
+ ExecSetupChildParentMapForSubplan(mtstate);
/*
* Initialize any WITH CHECK OPTION constraints if needed.
diff --git a/src/include/executor/execPartition.h b/src/include/executor/execPartition.h
index 0afa41e..06e6edd 100644
--- a/src/include/executor/execPartition.h
+++ b/src/include/executor/execPartition.h
@@ -62,11 +62,22 @@ typedef struct PartitionDispatchData *PartitionDispatch;
* 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
+ * parent_child_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)
+ * child_parent_tupconv_maps Array of TupleConversionMap objects with one
+ * entry for every leaf partition (required to
+ * convert input tuple based on the leaf
+ * partition's rowtype to the root table's rowtype
+ * after tuple routing is done)
+ * child_parent_tupconv_map_not_reqd
+ * 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 int array ordered by UPDATE subplans. Each
* element of this array has the index into the
* corresponding partition in 'partitions' array.
@@ -82,7 +93,9 @@ typedef struct PartitionTupleRouting
int num_dispatch;
ResultRelInfo **partitions;
int num_partitions;
- TupleConversionMap **partition_tupconv_maps;
+ TupleConversionMap **parent_child_tupconv_maps;
+ TupleConversionMap **child_parent_tupconv_maps;
+ bool *child_parent_tupconv_map_not_reqd;
int *subplan_partition_offsets;
TupleTableSlot *partition_tuple_slot;
TupleTableSlot *root_tuple_slot;
@@ -95,6 +108,9 @@ extern int ExecFindPartition(ResultRelInfo *resultRelInfo,
PartitionDispatch *pd,
TupleTableSlot *slot,
EState *estate);
+extern void ExecSetupChildParentMapForLeaf(PartitionTupleRouting *proute);
+extern TupleConversionMap *TupConvMapForLeaf(PartitionTupleRouting *proute,
+ ResultRelInfo *rootRelInfo, int leaf_index);
extern HeapTuple ConvertPartitionTupleSlot(TupleConversionMap *map,
HeapTuple tuple,
TupleTableSlot *new_slot,
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 8b5391d..defd5cd 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -991,9 +991,8 @@ typedef struct ModifyTableState
/* controls transition table population for specified operation */
struct TransitionCaptureState *mt_oc_transition_capture;
/* controls transition table population for INSERT...ON CONFLICT UPDATE */
- TupleConversionMap **mt_childparent_tupconv_maps;
- /* Per plan/partition map for tuple conversion from child to root */
- bool mt_is_tupconv_perpart; /* Is the above map per-partition ? */
+ TupleConversionMap **mt_per_subplan_tupconv_maps;
+ /* Per plan map for tuple conversion from child to root */
} ModifyTableState;
/* ----------------