mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
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
This commit is contained in:
parent
40b1491357
commit
fb958b5da8
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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 =
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -538,22 +538,6 @@ typedef struct ResultRelInfo
|
||||
/* partition check expression state (NULL if not set up yet) */
|
||||
ExprState *ri_PartitionCheckExpr;
|
||||
|
||||
/*
|
||||
* Information needed by tuple routing target relations
|
||||
*
|
||||
* RootResultRelInfo gives the target relation mentioned in the query, if
|
||||
* it's a partitioned table. It is not set if the target relation
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
@ -563,6 +547,26 @@ typedef struct ResultRelInfo
|
||||
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
|
||||
* it's a partitioned table. It is not set if the target relation
|
||||
* mentioned in the query is an inherited table, nor when tuple routing is
|
||||
* not needed.
|
||||
*
|
||||
* PartitionTupleSlot is non-NULL if RootToChild conversion is needed and
|
||||
* the relation is a partition.
|
||||
*/
|
||||
struct ResultRelInfo *ri_RootResultRelInfo;
|
||||
TupleTableSlot *ri_PartitionTupleSlot;
|
||||
|
||||
/* for use by copyfrom.c when performing multi-inserts */
|
||||
struct CopyMultiInsertBuffer *ri_CopyMultiInsertBuffer;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user