From 68853dc0f14760f3b38c8addf16fcd96b835a6f1 Mon Sep 17 00:00:00 2001 From: amitlan Date: Mon, 28 Nov 2022 16:12:15 +0900 Subject: [PATCH v31 1/2] 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. That includes making all code sites that use ri_RootToPartitionMap to access it by calling ExecGetRootToChildMap() instead of accessing it directly. The function houses the logic of setting the map appropriately depending on whether a given child relation is partition or not. --- src/backend/access/common/tupconvert.c | 19 +++++++- src/backend/commands/copyfrom.c | 2 +- src/backend/executor/execMain.c | 8 ++-- src/backend/executor/execPartition.c | 27 ++++------- src/backend/executor/execUtils.c | 57 ++++++++++++++++++++---- src/backend/executor/nodeModifyTable.c | 2 +- src/backend/replication/logical/worker.c | 4 +- src/include/access/tupconvert.h | 3 ++ src/include/executor/executor.h | 1 + src/include/nodes/execnodes.h | 9 ++-- 10 files changed, 93 insertions(+), 39 deletions(-) diff --git a/src/backend/access/common/tupconvert.c b/src/backend/access/common/tupconvert.c index b2f892d2fd..16d5664568 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); +} + +/* + * Sets up tuple conversion for input and output TupleDescs using 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 a079c70152..504afcb811 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 7a4db80104..2d68aafc69 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -1307,9 +1307,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_RootToPartitionMap = NULL; + resultRelInfo->ri_RootToPartitionMapValid = 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 13e450c0fa..b0eb15b982 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -469,7 +469,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, @@ -733,7 +733,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); @@ -983,33 +983,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 dce93a8c9f..62c8f1688f 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -1254,6 +1254,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_RootToPartitionMapValid) + { + 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_RootToPartitionMap = + convert_tuples_by_name_attrmap(indesc, outdesc, attrMap); + MemoryContextSwitchTo(oldcontext); + resultRelInfo->ri_RootToPartitionMapValid = true; + } + + return resultRelInfo->ri_RootToPartitionMap; +} + /* Return a bitmap representing columns being inserted */ Bitmapset * ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate) @@ -1274,10 +1313,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; } @@ -1308,10 +1347,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; } @@ -1334,10 +1373,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 271ff2be8e..a3988b1175 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 e48a3f589a..f9efe6c4c6 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 a37dafc666..97091fbed4 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 c9a5e5fb68..32bbbc5927 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -603,6 +603,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 369de42caf..e01fe5646c 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -546,12 +546,15 @@ 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. + * RootToPartitionMap and PartitionTupleSlot are non-NULL if partition has + * a different tuple format than the root table. + * + * Note: Despite the naming, RootToPartitionMap can also be used for + * regular inheritance child relations. */ struct ResultRelInfo *ri_RootResultRelInfo; TupleConversionMap *ri_RootToPartitionMap; + bool ri_RootToPartitionMapValid; TupleTableSlot *ri_PartitionTupleSlot; /* -- 2.35.3