aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2022-12-02 10:35:55 +0100
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2022-12-02 10:35:55 +0100
commitfb958b5da86da69651f6fb9f540c2cfb1346cdc5 (patch)
treea059d6e4ceab797bc94f2212a5d748f5e1b3fa6d /src
parent40b1491357a4a092ea054176944cf76e2fe3eff8 (diff)
downloadpostgresql-fb958b5da86da69651f6fb9f540c2cfb1346cdc5.tar.gz
postgresql-fb958b5da86da69651f6fb9f540c2cfb1346cdc5.zip
Generalize ri_RootToPartitionMap to use for non-partition children
ri_RootToPartitionMap is currently only initialized for tuple routing target partitions, though a future commit will need the ability to use it even for the non-partition child tables, so make adjustments to the decouple it from the partitioning code. Also, make it lazily initialized via ExecGetRootToChildMap(), making that function its preferred access path. Existing third-party code accessing it directly should no longer do so; consequently, it's been renamed to ri_RootToChildMap, which also makes it consistent with ri_ChildToRootMap. ExecGetRootToChildMap() houses the logic of setting the map appropriately depending on whether a given child relation is partition or not. To support this, also add a separate entry point for TupleConversionMap creation that receives an AttrMap. No new code here, just split an existing function in two. Author: Amit Langote <amitlangote09@gmail.com> Discussion: https://postgr.es/m/CA+HiwqEYUhDXSK5BTvG_xk=eaAEJCD4GS3C6uH7ybBvv+Z_Tmg@mail.gmail.com
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/common/tupconvert.c19
-rw-r--r--src/backend/commands/copyfrom.c2
-rw-r--r--src/backend/executor/execMain.c8
-rw-r--r--src/backend/executor/execPartition.c27
-rw-r--r--src/backend/executor/execUtils.c57
-rw-r--r--src/backend/executor/nodeModifyTable.c2
-rw-r--r--src/backend/replication/logical/worker.c4
-rw-r--r--src/include/access/tupconvert.h3
-rw-r--r--src/include/executor/executor.h1
-rw-r--r--src/include/nodes/execnodes.h30
10 files changed, 104 insertions, 49 deletions
diff --git a/src/backend/access/common/tupconvert.c b/src/backend/access/common/tupconvert.c
index b2f892d2fdf..4023f533d74 100644
--- a/src/backend/access/common/tupconvert.c
+++ b/src/backend/access/common/tupconvert.c
@@ -102,9 +102,7 @@ TupleConversionMap *
convert_tuples_by_name(TupleDesc indesc,
TupleDesc outdesc)
{
- TupleConversionMap *map;
AttrMap *attrMap;
- int n = outdesc->natts;
/* Verify compatibility and prepare attribute-number map */
attrMap = build_attrmap_by_name_if_req(indesc, outdesc, false);
@@ -115,6 +113,23 @@ convert_tuples_by_name(TupleDesc indesc,
return NULL;
}
+ return convert_tuples_by_name_attrmap(indesc, outdesc, attrMap);
+}
+
+/*
+ * Set up tuple conversion for input and output TupleDescs using the given
+ * AttrMap.
+ */
+TupleConversionMap *
+convert_tuples_by_name_attrmap(TupleDesc indesc,
+ TupleDesc outdesc,
+ AttrMap *attrMap)
+{
+ int n = outdesc->natts;
+ TupleConversionMap *map;
+
+ Assert(attrMap != NULL);
+
/* Prepare the map structure */
map = (TupleConversionMap *) palloc(sizeof(TupleConversionMap));
map->indesc = indesc;
diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c
index a079c70152f..504afcb8110 100644
--- a/src/backend/commands/copyfrom.c
+++ b/src/backend/commands/copyfrom.c
@@ -1088,7 +1088,7 @@ CopyFrom(CopyFromState cstate)
* We might need to convert from the root rowtype to the partition
* rowtype.
*/
- map = resultRelInfo->ri_RootToPartitionMap;
+ map = ExecGetRootToChildMap(resultRelInfo, estate);
if (insertMethod == CIM_SINGLE || !leafpart_use_multi_insert)
{
/* non batch insert */
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index b6751da5743..12ff4f3de58 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1256,9 +1256,11 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
* this field is filled in ExecInitModifyTable().
*/
resultRelInfo->ri_RootResultRelInfo = partition_root_rri;
- resultRelInfo->ri_RootToPartitionMap = NULL; /* set by
- * ExecInitRoutingInfo */
- resultRelInfo->ri_PartitionTupleSlot = NULL; /* ditto */
+ /* Set by ExecGetRootToChildMap */
+ resultRelInfo->ri_RootToChildMap = NULL;
+ resultRelInfo->ri_RootToChildMapValid = false;
+ /* Set by ExecInitRoutingInfo */
+ resultRelInfo->ri_PartitionTupleSlot = NULL;
resultRelInfo->ri_ChildToRootMap = NULL;
resultRelInfo->ri_ChildToRootMapValid = false;
resultRelInfo->ri_CopyMultiInsertBuffer = NULL;
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index 8e6453aec2a..88d0ea3adb1 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -463,7 +463,7 @@ ExecFindPartition(ModifyTableState *mtstate,
*/
if (is_leaf)
{
- TupleConversionMap *map = rri->ri_RootToPartitionMap;
+ TupleConversionMap *map = ExecGetRootToChildMap(rri, estate);
if (map)
slot = execute_attr_map_slot(map->attrMap, rootslot,
@@ -727,7 +727,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
OnConflictSetState *onconfl = makeNode(OnConflictSetState);
TupleConversionMap *map;
- map = leaf_part_rri->ri_RootToPartitionMap;
+ map = ExecGetRootToChildMap(leaf_part_rri, estate);
Assert(node->onConflictSet != NIL);
Assert(rootResultRelInfo->ri_onConflict != NULL);
@@ -977,33 +977,24 @@ ExecInitRoutingInfo(ModifyTableState *mtstate,
int partidx,
bool is_borrowed_rel)
{
- ResultRelInfo *rootRelInfo = partRelInfo->ri_RootResultRelInfo;
MemoryContext oldcxt;
int rri_index;
oldcxt = MemoryContextSwitchTo(proute->memcxt);
/*
- * Set up a tuple conversion map to convert a tuple routed to the
- * partition from the parent's type to the partition's.
+ * Set up tuple conversion between root parent and the partition if the
+ * two have different rowtypes. If conversion is indeed required, also
+ * initialize a slot dedicated to storing this partition's converted
+ * tuples. Various operations that are applied to tuples after routing,
+ * such as checking constraints, will refer to this slot.
*/
- partRelInfo->ri_RootToPartitionMap =
- convert_tuples_by_name(RelationGetDescr(rootRelInfo->ri_RelationDesc),
- RelationGetDescr(partRelInfo->ri_RelationDesc));
-
- /*
- * If a partition has a different rowtype than the root parent, initialize
- * a slot dedicated to storing this partition's tuples. The slot is used
- * for various operations that are applied to tuples after routing, such
- * as checking constraints.
- */
- if (partRelInfo->ri_RootToPartitionMap != NULL)
+ if (ExecGetRootToChildMap(partRelInfo, estate) != NULL)
{
Relation partrel = partRelInfo->ri_RelationDesc;
/*
- * Initialize the slot itself setting its descriptor to this
- * partition's TupleDesc; TupleDesc reference will be released at the
+ * This pins the partition's TupleDesc, which will be released at the
* end of the command.
*/
partRelInfo->ri_PartitionTupleSlot =
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 9695de85b9a..572c87e4536 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -1253,6 +1253,45 @@ ExecGetChildToRootMap(ResultRelInfo *resultRelInfo)
return resultRelInfo->ri_ChildToRootMap;
}
+/*
+ * Returns the map needed to convert given root result relation's tuples to
+ * the rowtype of the given child relation. Note that a NULL result is valid
+ * and means that no conversion is needed.
+ */
+TupleConversionMap *
+ExecGetRootToChildMap(ResultRelInfo *resultRelInfo, EState *estate)
+{
+ /* Mustn't get called for a non-child result relation. */
+ Assert(resultRelInfo->ri_RootResultRelInfo);
+
+ /* If we didn't already do so, compute the map for this child. */
+ if (!resultRelInfo->ri_RootToChildMapValid)
+ {
+ ResultRelInfo *rootRelInfo = resultRelInfo->ri_RootResultRelInfo;
+ TupleDesc indesc = RelationGetDescr(rootRelInfo->ri_RelationDesc);
+ TupleDesc outdesc = RelationGetDescr(resultRelInfo->ri_RelationDesc);
+ Relation childrel = resultRelInfo->ri_RelationDesc;
+ AttrMap *attrMap;
+ MemoryContext oldcontext;
+
+ /*
+ * When this child table is not a partition (!relispartition), it may
+ * have columns that are not present in the root table, which we ask
+ * to ignore by passing true for missing_ok.
+ */
+ oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
+ attrMap = build_attrmap_by_name_if_req(indesc, outdesc,
+ !childrel->rd_rel->relispartition);
+ if (attrMap)
+ resultRelInfo->ri_RootToChildMap =
+ convert_tuples_by_name_attrmap(indesc, outdesc, attrMap);
+ MemoryContextSwitchTo(oldcontext);
+ resultRelInfo->ri_RootToChildMapValid = true;
+ }
+
+ return resultRelInfo->ri_RootToChildMap;
+}
+
/* Return a bitmap representing columns being inserted */
Bitmapset *
ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate)
@@ -1273,10 +1312,10 @@ ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate)
{
ResultRelInfo *rootRelInfo = relinfo->ri_RootResultRelInfo;
RangeTblEntry *rte = exec_rt_fetch(rootRelInfo->ri_RangeTableIndex, estate);
+ TupleConversionMap *map = ExecGetRootToChildMap(relinfo, estate);
- if (relinfo->ri_RootToPartitionMap != NULL)
- return execute_attr_map_cols(relinfo->ri_RootToPartitionMap->attrMap,
- rte->insertedCols);
+ if (map != NULL)
+ return execute_attr_map_cols(map->attrMap, rte->insertedCols);
else
return rte->insertedCols;
}
@@ -1307,10 +1346,10 @@ ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
{
ResultRelInfo *rootRelInfo = relinfo->ri_RootResultRelInfo;
RangeTblEntry *rte = exec_rt_fetch(rootRelInfo->ri_RangeTableIndex, estate);
+ TupleConversionMap *map = ExecGetRootToChildMap(relinfo, estate);
- if (relinfo->ri_RootToPartitionMap != NULL)
- return execute_attr_map_cols(relinfo->ri_RootToPartitionMap->attrMap,
- rte->updatedCols);
+ if (map != NULL)
+ return execute_attr_map_cols(map->attrMap, rte->updatedCols);
else
return rte->updatedCols;
}
@@ -1333,10 +1372,10 @@ ExecGetExtraUpdatedCols(ResultRelInfo *relinfo, EState *estate)
{
ResultRelInfo *rootRelInfo = relinfo->ri_RootResultRelInfo;
RangeTblEntry *rte = exec_rt_fetch(rootRelInfo->ri_RangeTableIndex, estate);
+ TupleConversionMap *map = ExecGetRootToChildMap(relinfo, estate);
- if (relinfo->ri_RootToPartitionMap != NULL)
- return execute_attr_map_cols(relinfo->ri_RootToPartitionMap->attrMap,
- rte->extraUpdatedCols);
+ if (map != NULL)
+ return execute_attr_map_cols(map->attrMap, rte->extraUpdatedCols);
else
return rte->extraUpdatedCols;
}
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 271ff2be8ef..a3988b11754 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -3481,7 +3481,7 @@ ExecPrepareTupleRouting(ModifyTableState *mtstate,
/*
* Convert the tuple, if necessary.
*/
- map = partrel->ri_RootToPartitionMap;
+ map = ExecGetRootToChildMap(partrel, estate);
if (map != NULL)
{
TupleTableSlot *new_slot = partrel->ri_PartitionTupleSlot;
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index e48a3f589ae..f9efe6c4c67 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -2193,7 +2193,7 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
remoteslot_part = partrelinfo->ri_PartitionTupleSlot;
if (remoteslot_part == NULL)
remoteslot_part = table_slot_create(partrel, &estate->es_tupleTable);
- map = partrelinfo->ri_RootToPartitionMap;
+ map = ExecGetRootToChildMap(partrelinfo, estate);
if (map != NULL)
{
attrmap = map->attrMap;
@@ -2353,7 +2353,7 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
if (remoteslot_part == NULL)
remoteslot_part = table_slot_create(partrel_new,
&estate->es_tupleTable);
- map = partrelinfo_new->ri_RootToPartitionMap;
+ map = ExecGetRootToChildMap(partrelinfo_new, estate);
if (map != NULL)
{
remoteslot_part = execute_attr_map_slot(map->attrMap,
diff --git a/src/include/access/tupconvert.h b/src/include/access/tupconvert.h
index a37dafc666d..2badb8c239d 100644
--- a/src/include/access/tupconvert.h
+++ b/src/include/access/tupconvert.h
@@ -39,6 +39,9 @@ extern TupleConversionMap *convert_tuples_by_position(TupleDesc indesc,
extern TupleConversionMap *convert_tuples_by_name(TupleDesc indesc,
TupleDesc outdesc);
+extern TupleConversionMap *convert_tuples_by_name_attrmap(TupleDesc indesc,
+ TupleDesc outdesc,
+ AttrMap *attrMap);
extern HeapTuple execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map);
extern TupleTableSlot *execute_attr_map_slot(AttrMap *attrMap,
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index ed95ed1176d..aaf2bc78b9c 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -600,6 +600,7 @@ extern TupleTableSlot *ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relI
extern TupleTableSlot *ExecGetTriggerNewSlot(EState *estate, ResultRelInfo *relInfo);
extern TupleTableSlot *ExecGetReturningSlot(EState *estate, ResultRelInfo *relInfo);
extern TupleConversionMap *ExecGetChildToRootMap(ResultRelInfo *resultRelInfo);
+extern TupleConversionMap *ExecGetRootToChildMap(ResultRelInfo *resultRelInfo, EState *estate);
extern Bitmapset *ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate);
extern Bitmapset *ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index a2008846c63..71248a94660 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -539,6 +539,21 @@ typedef struct ResultRelInfo
ExprState *ri_PartitionCheckExpr;
/*
+ * Map to convert child result relation tuples to the format of the table
+ * actually mentioned in the query (called "root"). Computed only if
+ * needed. A NULL map value indicates that no conversion is needed, so we
+ * must have a separate flag to show if the map has been computed.
+ */
+ TupleConversionMap *ri_ChildToRootMap;
+ bool ri_ChildToRootMapValid;
+
+ /*
+ * As above, but in the other direction.
+ */
+ TupleConversionMap *ri_RootToChildMap;
+ bool ri_RootToChildMapValid;
+
+ /*
* Information needed by tuple routing target relations
*
* RootResultRelInfo gives the target relation mentioned in the query, if
@@ -546,23 +561,12 @@ typedef struct ResultRelInfo
* mentioned in the query is an inherited table, nor when tuple routing is
* not needed.
*
- * RootToPartitionMap and PartitionTupleSlot, initialized by
- * ExecInitRoutingInfo, are non-NULL if partition has a different tuple
- * format than the root table.
+ * PartitionTupleSlot is non-NULL if RootToChild conversion is needed and
+ * the relation is a partition.
*/
struct ResultRelInfo *ri_RootResultRelInfo;
- TupleConversionMap *ri_RootToPartitionMap;
TupleTableSlot *ri_PartitionTupleSlot;
- /*
- * Map to convert child result relation tuples to the format of the table
- * actually mentioned in the query (called "root"). Computed only if
- * needed. A NULL map value indicates that no conversion is needed, so we
- * must have a separate flag to show if the map has been computed.
- */
- TupleConversionMap *ri_ChildToRootMap;
- bool ri_ChildToRootMapValid;
-
/* for use by copyfrom.c when performing multi-inserts */
struct CopyMultiInsertBuffer *ri_CopyMultiInsertBuffer;