Generalize ri_RootToPartitionMap to use for non-partition children
authorAlvaro Herrera <[email protected]>
Fri, 2 Dec 2022 09:35:55 +0000 (10:35 +0100)
committerAlvaro Herrera <[email protected]>
Fri, 2 Dec 2022 09:35:55 +0000 (10:35 +0100)
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 <[email protected]>
Discussion: https://postgr.es/m/CA+HiwqEYUhDXSK5BTvG_xk=eaAEJCD4GS3C6uH7ybBvv+Z_Tmg@mail.gmail.com

src/backend/access/common/tupconvert.c
src/backend/commands/copyfrom.c
src/backend/executor/execMain.c
src/backend/executor/execPartition.c
src/backend/executor/execUtils.c
src/backend/executor/nodeModifyTable.c
src/backend/replication/logical/worker.c
src/include/access/tupconvert.h
src/include/executor/executor.h
src/include/nodes/execnodes.h

index b2f892d2fdf0bbfcf855de5d943ca979e822ff53..4023f533d74d944f9972fe368469bc2df41425bc 100644 (file)
@@ -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;
index a079c70152f4b953d3bd8f85fbfdfac159051a98..504afcb8110cb5d5cb54188e628ae6eca9080158 100644 (file)
@@ -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 */
index b6751da5743a22c140c12b8daf018fb06e2187b9..12ff4f3de582a6fa36bbff4cd871144e4ea43c13 100644 (file)
@@ -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;
index 8e6453aec2a52b8f39bc9da05c65ccf33e18d80f..88d0ea3adb1fae26f24ed887398e544e4c51ebbf 100644 (file)
@@ -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 =
index 9695de85b9ab76deb9e8b402acd6f5e896b86a83..572c87e4536918a78694a929f1261ffd4ef6abd6 100644 (file)
@@ -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;
        }
index 271ff2be8efe2d5ce3749730bbca27c83d2af9d1..a3988b117543a19710868348cbb79ed093655ca8 100644 (file)
@@ -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;
index e48a3f589aefbfe4369c38f7fee1c976679ea186..f9efe6c4c674541d78411459f8dd52dfbae8c040 100644 (file)
@@ -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,
index a37dafc666d9be051215b6dfaa8183b55be8c672..2badb8c239da84715ca5363312e60fef12807afa 100644 (file)
@@ -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,
index ed95ed1176da9dfb7e3e8b3eb7c114bd4b77e72c..aaf2bc78b9c71c4dcdeb8fc2ad09ec3c50bc0070 100644 (file)
@@ -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);
index a2008846c63f7ee81bd569bb42e0d5bf346832b9..71248a9466071c6e0196f997c2cebf822ca48262 100644 (file)
@@ -538,6 +538,21 @@ typedef struct ResultRelInfo
        /* partition check expression state (NULL if not set up yet) */
        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
         *
@@ -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;