From: Etsuro Fujita <fujita.etsuro@lab.ntt.co.jp>
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
Cc: pgsql-hackers@lists.postgresql.org
Subject: Re: non-bulk inserts and tuple routing
Date: Fri, 16 Feb 2018 19:50:38 +0900
Message-ID: <5A86B77E.1010306@lab.ntt.co.jp> (raw)
In-Reply-To: <b34e69b2-5d67-29f1-7a35-6b6299243ec0@lab.ntt.co.jp>
References: <8975331d-d961-cbdd-f862-fdd3d97dc2d0@lab.ntt.co.jp>
<56c9f77b-830c-4652-233e-a1c5fa5a9938@lab.ntt.co.jp>
<8f53a342-e0df-4fc9-7422-c3c3c601117c@lab.ntt.co.jp>
<5A69A3B7.10403@lab.ntt.co.jp>
<37f7cc10-def8-b2d0-615d-dfe035e7b1ee@lab.ntt.co.jp>
<5A70396A.8090400@lab.ntt.co.jp>
<8399fd28-07c2-3cbc-f807-f89cdf2f98f5@lab.ntt.co.jp>
<5A704055.40207@lab.ntt.co.jp>
<5A7443DF.1010408@lab.ntt.co.jp>
<14870d0e-d9d4-2ab9-ddfe-182b3c8abfca@lab.ntt.co.jp>
<5A783549.4020409@lab.ntt.co.jp>
<5A7AD6B5.3020304@lab.ntt.co.jp>
<5A7C2364.9040700@lab.ntt.co.jp>
<481cc9d5-2dd8-b3f4-23b0-ecbccd8a85e0@lab.ntt.co.jp>
<5A7D91F3.9050309@lab.ntt.co.jp>
<4f144297-ba52-9f87-1f7a-d44fc7006d80@lab.ntt.co.jp>
<5A8578C1.20308@lab.ntt.co.jp>
<c0c02a3f-5eba-77c5-5476-95e1f003623e@lab.ntt.co.jp>
<5A8652E3.9000009@lab.ntt.co.jp>
<caf71439-fd65-864e-c441-4053430f812e@lab.ntt.co.jp>
<5A86A093.4010406@lab.ntt.co.jp>
<b34e69b2-5d67-29f1-7a35-6b6299243ec0@lab.ntt.co.jp>
(2018/02/16 18:23), Amit Langote wrote:
> On 2018/02/16 18:12, Etsuro Fujita wrote:
>> In the patch you added the comments:
>>
>> + wcoList = linitial(node->withCheckOptionLists);
>> +
>> + /*
>> + * Convert Vars in it to contain this partition's attribute numbers.
>> + * Use the WITH CHECK OPTIONS list of the first resultRelInfo as a
>> + * reference to calculate attno's for the returning expression of
>> + * this partition. In the INSERT case, that refers to the root
>> + * partitioned table, whereas in the UPDATE tuple routing case the
>> + * first partition in the mtstate->resultRelInfo array. In any case,
>> + * both that relation and this partition should have the same
>> columns,
>> + * so we should be able to map attributes successfully.
>> + */
>> + wcoList = map_partition_varattnos(wcoList, firstVarno,
>> + partrel, firstResultRel, NULL);
>>
>> This would be just nitpicking, but I think it would be better to arrange
>> these comments, maybe by dividing these to something like this:
>>
>> /*
>> * Use the WITH CHECK OPTIONS list of the first resultRelInfo as a
>> * reference to calculate attno's for the returning expression of
>> * this partition. In the INSERT case, that refers to the root
>> * partitioned table, whereas in the UPDATE tuple routing case the
>> * first partition in the mtstate->resultRelInfo array. In any case,
>> * both that relation and this partition should have the same columns,
>> * so we should be able to map attributes successfully.
>> */
>> wcoList = linitial(node->withCheckOptionLists);
>>
>> /*
>> * Convert Vars in it to contain this partition's attribute numbers.
>> */
>> wcoList = map_partition_varattnos(wcoList, firstVarno,
>> partrel, firstResultRel, NULL);
>>
>> I'd say the same thing to the comments you added for RETURNING.
>
> Good idea. Done.
Thanks. I fixed a typo (s/Converti/Convert/) and adjusted these
comments a bit further to match the preceding code/comments. Attached
is the updated version.
>> Another thing I noticed about comments in the patch is:
>>
>> + * In the case of INSERT on partitioned tables, there is only one
>> + * plan. Likewise, there is only one WCO list, not one per
>> + * partition. For UPDATE, there would be as many WCO lists as
>> + * there are plans, but we use the first one as reference. Note
>> + * that if there are SubPlans in there, they all end up attached
>> + * to the one parent Plan node.
>>
>> The patch calls ExecInitQual with mtstate->mt_plans[0] for initializing
>> WCO constraints, which would change the place to attach SubPlans in WCO
>> constraints from the parent PlanState to the subplan's PlanState, which
>> would make the last comment obsolete. Since this change would be more
>> consistent with PG10, I don't think we need to update the comment as such;
>> I would vote for just removing that comment from here.
>
> I have thought about removing it too, so done.
OK.
> Updated patch attached.
Thanks, I think the patch is in good shape, so I'll mark this as ready
for committer.
Best regards,
Etsuro Fujita
Attachments:v10-0001-During-tuple-routing-initialize-per-partition-ob-efujita.patch (text/x-diff, 22.0K) downloaddiff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.cindex b3933df..118452b 100644--- a/src/backend/commands/copy.c+++ b/src/backend/commands/copy.c@@ -2470,7 +2470,7 @@ CopyFrom(CopyState cstate)
PartitionTupleRouting *proute;
proute = cstate->partition_tuple_routing =
- ExecSetupPartitionTupleRouting(NULL, cstate->rel, 1, estate);+ ExecSetupPartitionTupleRouting(NULL, cstate->rel);
/*
* If we are capturing transition tuples, they may need to be
@@ -2607,6 +2607,14 @@ CopyFrom(CopyState cstate)
*/
saved_resultRelInfo = resultRelInfo;
resultRelInfo = proute->partitions[leaf_part_index];
+ if (resultRelInfo == NULL)+ {+ resultRelInfo = ExecInitPartitionInfo(NULL,+ saved_resultRelInfo,+ proute, estate,+ leaf_part_index);+ Assert(resultRelInfo != NULL);+ }
/* We do not yet have a way to insert into a foreign partition */
if (resultRelInfo->ri_FdwRoutine)
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.cindex 4048c3e..06a7607 100644--- a/src/backend/executor/execPartition.c+++ b/src/backend/executor/execPartition.c@@ -44,18 +44,23 @@ static char *ExecBuildSlotPartitionKeyDescription(Relation rel,
*
* Note that all the relations in the partition tree are locked using the
* RowExclusiveLock mode upon return from this function.
+ *+ * While we allocate the arrays of pointers of ResultRelInfo and+ * TupleConversionMap for all partitions here, actual objects themselves are+ * lazily allocated for a given partition if a tuple is actually routed to it;+ * see ExecInitPartitionInfo. However, if the function is invoked for update+ * tuple routing, caller would already have initialized ResultRelInfo's for+ * some of the partitions, which are reused and assigned to their respective+ * slot in the aforementioned array.
*/
PartitionTupleRouting *
-ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,- Relation rel, Index resultRTindex,- EState *estate)+ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, Relation rel)
{
TupleDesc tupDesc = RelationGetDescr(rel);
List *leaf_parts;
ListCell *cell;
int i;
- ResultRelInfo *leaf_part_arr = NULL,- *update_rri = NULL;+ ResultRelInfo *update_rri = NULL;
int num_update_rri = 0,
update_rri_index = 0;
bool is_update = false;
@@ -76,6 +81,8 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
proute->parent_child_tupconv_maps =
(TupleConversionMap **) palloc0(proute->num_partitions *
sizeof(TupleConversionMap *));
+ proute->partition_oids = (Oid *) palloc(proute->num_partitions *+ sizeof(Oid));
/* Set up details specific to the type of tuple routing we are doing. */
if (mtstate && mtstate->operation == CMD_UPDATE)
@@ -95,16 +102,6 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
*/
proute->root_tuple_slot = MakeTupleTableSlot();
}
- else- {- /*- * Since we are inserting tuples, we need to create all new result- * rels. Avoid repeated pallocs by allocating memory for all the- * result rels in bulk.- */- leaf_part_arr = (ResultRelInfo *) palloc0(proute->num_partitions *- sizeof(ResultRelInfo));- }
/*
* Initialize an empty slot that will be used to manipulate tuples of any
@@ -117,11 +114,10 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
i = 0;
foreach(cell, leaf_parts)
{
- ResultRelInfo *leaf_part_rri;- Relation partrel = NULL;- TupleDesc part_tupdesc;+ ResultRelInfo *leaf_part_rri = NULL;
Oid leaf_oid = lfirst_oid(cell);
+ proute->partition_oids[i] = leaf_oid;
if (is_update)
{
/*
@@ -136,6 +132,9 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
if (update_rri_index < num_update_rri &&
RelationGetRelid(update_rri[update_rri_index].ri_RelationDesc) == leaf_oid)
{
+ Relation partrel;+ TupleDesc part_tupdesc;+
leaf_part_rri = &update_rri[update_rri_index];
partrel = leaf_part_rri->ri_RelationDesc;
@@ -151,73 +150,26 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
proute->subplan_partition_offsets[update_rri_index] = i;
update_rri_index++;
- }- else- leaf_part_rri = (ResultRelInfo *) palloc0(sizeof(ResultRelInfo));- }- else- {- /* For INSERTs, we already have an array of result rels allocated */- leaf_part_rri = &leaf_part_arr[i];- }- /*- * If we didn't open the partition rel, it means we haven't- * initialized the result rel either.- */- if (!partrel)- {- /*- * We locked all the partitions above including the leaf- * partitions. Note that each of the newly opened relations in- * proute->partitions are eventually closed by the caller.- */- partrel = heap_open(leaf_oid, NoLock);- InitResultRelInfo(leaf_part_rri,- partrel,- resultRTindex,- rel,- estate->es_instrument);-- /*- * Since we've just initialized this ResultRelInfo, it's not in- * any list attached to the estate as yet. Add it, so that it can- * be found later.- */- estate->es_tuple_routing_result_relations =- lappend(estate->es_tuple_routing_result_relations,- leaf_part_rri);- }+ part_tupdesc = RelationGetDescr(partrel);- part_tupdesc = RelationGetDescr(partrel);-- /*- * Save a tuple conversion map to convert a tuple routed to this- * partition from the parent's type to the partition's.- */- proute->parent_child_tupconv_maps[i] =- convert_tuples_by_name(tupDesc, part_tupdesc,- gettext_noop("could not convert row type"));-- /*- * Verify result relation is a valid target for an INSERT. An UPDATE- * of a partition-key becomes a DELETE+INSERT operation, so this check- * is still required when the operation is CMD_UPDATE.- */- CheckValidResultRel(leaf_part_rri, CMD_INSERT);+ /*+ * Save a tuple conversion map to convert a tuple routed to+ * this partition from the parent's type to the partition's.+ */+ proute->parent_child_tupconv_maps[i] =+ convert_tuples_by_name(tupDesc, part_tupdesc,+ gettext_noop("could not convert row type"));- /*- * Open partition indices. The user may have asked to check for- * conflicts within this leaf partition and do "nothing" instead of- * throwing an error. Be prepared in that case by initializing the- * index information needed by ExecInsert() to perform speculative- * insertions.- */- if (leaf_part_rri->ri_RelationDesc->rd_rel->relhasindex &&- leaf_part_rri->ri_IndexRelationDescs == NULL)- ExecOpenIndices(leaf_part_rri,- mtstate != NULL &&- mtstate->mt_onconflict != ONCONFLICT_NONE);+ /*+ * Verify result relation is a valid target for an INSERT. An+ * UPDATE of a partition-key becomes a DELETE+INSERT operation,+ * so this check is required even when the operation is+ * CMD_UPDATE.+ */+ CheckValidResultRel(leaf_part_rri, CMD_INSERT);+ }+ }
proute->partitions[i] = leaf_part_rri;
i++;
@@ -352,6 +304,193 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
}
/*
+ * ExecInitPartitionInfo+ * Initialize ResultRelInfo and other information for a partition if not+ * already done+ *+ * Returns the ResultRelInfo+ */+ResultRelInfo *+ExecInitPartitionInfo(ModifyTableState *mtstate,+ ResultRelInfo *resultRelInfo,+ PartitionTupleRouting *proute,+ EState *estate, int partidx)+{+ Relation rootrel = resultRelInfo->ri_RelationDesc,+ partrel;+ ResultRelInfo *leaf_part_rri;+ ModifyTable *node = mtstate ? (ModifyTable *) mtstate->ps.plan : NULL;++ /*+ * We locked all the partitions in ExecSetupPartitionTupleRouting+ * including the leaf partitions.+ */+ partrel = heap_open(proute->partition_oids[partidx], NoLock);+ leaf_part_rri = (ResultRelInfo *) palloc0(sizeof(ResultRelInfo));+ InitResultRelInfo(leaf_part_rri,+ partrel,+ node ? node->nominalRelation : 1,+ rootrel,+ estate->es_instrument);++ /*+ * Verify result relation is a valid target for an INSERT. An UPDATE+ * of a partition-key becomes a DELETE+INSERT operation, so this check+ * is still required when the operation is CMD_UPDATE.+ */+ CheckValidResultRel(leaf_part_rri, CMD_INSERT);++ /*+ * Since we've just initialized this ResultRelInfo, it's not in+ * any list attached to the estate as yet. Add it, so that it can+ * be found later.+ *+ * Note that the entries in this list appear in no predetermined+ * order, because partition result rels are initialized as and when+ * they're needed.+ */+ estate->es_tuple_routing_result_relations =+ lappend(estate->es_tuple_routing_result_relations,+ leaf_part_rri);++ /*+ * Open partition indices. The user may have asked to check for+ * conflicts within this leaf partition and do "nothing" instead of+ * throwing an error. Be prepared in that case by initializing the+ * index information needed by ExecInsert() to perform speculative+ * insertions.+ */+ if (partrel->rd_rel->relhasindex &&+ leaf_part_rri->ri_IndexRelationDescs == NULL)+ ExecOpenIndices(leaf_part_rri,+ (mtstate != NULL &&+ mtstate->mt_onconflict != ONCONFLICT_NONE));++ /*+ * Build WITH CHECK OPTION constraints for the partition. Note that we+ * didn't build the withCheckOptionList for partitions within the planner,+ * but simple translation of varattnos will suffice. This only occurs for+ * the INSERT case or in the case of UPDATE tuple routing where we didn't+ * find a result rel to reuse in ExecSetupPartitionTupleRouting().+ */+ if (node && node->withCheckOptionLists != NIL)+ {+ List *wcoList;+ List *wcoExprs = NIL;+ ListCell *ll;+ int firstVarno = mtstate->resultRelInfo[0].ri_RangeTableIndex;+ Relation firstResultRel = mtstate->resultRelInfo[0].ri_RelationDesc;++ /*+ * In the case of INSERT on partitioned tables, there is only one+ * plan. Likewise, there is only one WCO list, not one per+ * partition. For UPDATE, there would be as many WCO lists as+ * there are plans.+ */+ Assert((node->operation == CMD_INSERT &&+ list_length(node->withCheckOptionLists) == 1 &&+ list_length(node->plans) == 1) ||+ (node->operation == CMD_UPDATE &&+ list_length(node->withCheckOptionLists) ==+ list_length(node->plans)));++ /*+ * Use the WCO list of the first plan as a reference to calculate+ * attno's for the WCO list of this partition. In the INSERT case,+ * that refers to the root partitioned table, whereas in the UPDATE+ * tuple routing case, that refers to the first partition in the+ * mtstate->resultRelInfo array. In any case, both that relation and+ * this partition should have the same columns, so we should be able+ * to map attributes successfully.+ */+ wcoList = linitial(node->withCheckOptionLists);++ /*+ * Convert Vars in it to contain this partition's attribute numbers.+ */+ wcoList = map_partition_varattnos(wcoList, firstVarno,+ partrel, firstResultRel, NULL);+ foreach(ll, wcoList)+ {+ WithCheckOption *wco = castNode(WithCheckOption, lfirst(ll));+ ExprState *wcoExpr = ExecInitQual(castNode(List, wco->qual),+ mtstate->mt_plans[0]);+ wcoExprs = lappend(wcoExprs, wcoExpr);+ }++ leaf_part_rri->ri_WithCheckOptions = wcoList;+ leaf_part_rri->ri_WithCheckOptionExprs = wcoExprs;+ }++ /*+ * Build the RETURNING projection for the partition. Note that we didn't+ * build the returningList for partitions within the planner, but simple+ * translation of varattnos will suffice. This only occurs for the INSERT+ * case or in the case of UPDATE tuple routing where we didn't find a+ * result rel to reuse in ExecSetupPartitionTupleRouting().+ */+ if (node && node->returningLists != NIL)+ {+ TupleTableSlot *slot;+ ExprContext *econtext;+ List *returningList;+ int firstVarno = mtstate->resultRelInfo[0].ri_RangeTableIndex;+ Relation firstResultRel = mtstate->resultRelInfo[0].ri_RelationDesc;++ /* See the comment above for WCO lists. */+ Assert((node->operation == CMD_INSERT &&+ list_length(node->returningLists) == 1 &&+ list_length(node->plans) == 1) ||+ (node->operation == CMD_UPDATE &&+ list_length(node->returningLists) ==+ list_length(node->plans)));++ /*+ * Use the RETURNING list of the first plan as a reference to+ * calculate attno's for the RETURNING list of this partition. See+ * the comment above for WCO lists for more details on why this is+ * okay.+ */+ returningList = linitial(node->returningLists);++ /*+ * Convert Vars in it to contain this partition's attribute numbers.+ */+ returningList = map_partition_varattnos(returningList, firstVarno,+ partrel, firstResultRel,+ NULL);++ /*+ * Initialize the projection itself.+ *+ * Use the slot and the expression context that would have been set up+ * in ExecInitModifyTable() for projection's output.+ */+ Assert(mtstate->ps.ps_ResultTupleSlot != NULL);+ slot = mtstate->ps.ps_ResultTupleSlot;+ Assert(mtstate->ps.ps_ExprContext != NULL);+ econtext = mtstate->ps.ps_ExprContext;+ leaf_part_rri->ri_projectReturning =+ ExecBuildProjectionInfo(returningList, econtext, slot,+ &mtstate->ps, RelationGetDescr(partrel));+ }++ Assert (proute->partitions[partidx] == NULL);+ proute->partitions[partidx] = leaf_part_rri;++ /*+ * Save a tuple conversion map to convert a tuple routed to this+ * partition from the parent's type to the partition's.+ */+ proute->parent_child_tupconv_maps[partidx] =+ convert_tuples_by_name(RelationGetDescr(rootrel),+ RelationGetDescr(partrel),+ gettext_noop("could not convert row type"));++ return leaf_part_rri;+}++/*
* ExecSetupChildParentMapForLeaf -- Initialize the per-leaf-partition
* child-to-root tuple conversion map array.
*
@@ -477,6 +616,10 @@ ExecCleanupTupleRouting(PartitionTupleRouting *proute)
{
ResultRelInfo *resultRelInfo = proute->partitions[i];
+ /* skip further processsing for uninitialized partitions */+ if (resultRelInfo == NULL)+ continue;+
/*
* If this result rel is one of the UPDATE subplan result rels, let
* ExecEndPlan() close it. For INSERT or COPY,
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.cindex 2a8ecbd..36e2041 100644--- a/src/backend/executor/nodeModifyTable.c+++ b/src/backend/executor/nodeModifyTable.c@@ -310,6 +310,14 @@ ExecInsert(ModifyTableState *mtstate,
*/
saved_resultRelInfo = resultRelInfo;
resultRelInfo = proute->partitions[leaf_part_index];
+ if (resultRelInfo == NULL)+ {+ resultRelInfo = ExecInitPartitionInfo(mtstate,+ saved_resultRelInfo,+ proute, estate,+ leaf_part_index);+ Assert(resultRelInfo != NULL);+ }
/* We do not yet have a way to insert into a foreign partition */
if (resultRelInfo->ri_FdwRoutine)
@@ -2098,14 +2106,10 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
ResultRelInfo *saved_resultRelInfo;
ResultRelInfo *resultRelInfo;
Plan *subplan;
- int firstVarno = 0;- Relation firstResultRel = NULL;
ListCell *l;
int i;
Relation rel;
bool update_tuple_routing_needed = node->partColsUpdated;
- PartitionTupleRouting *proute = NULL;- int num_partitions = 0;
/* check for unsupported flags */
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
@@ -2228,20 +2232,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
*/
if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
(operation == CMD_INSERT || update_tuple_routing_needed))
- {- proute = mtstate->mt_partition_tuple_routing =- ExecSetupPartitionTupleRouting(mtstate,- rel, node->nominalRelation,- estate);- num_partitions = proute->num_partitions;-- /*- * Below are required as reference objects for mapping partition- * attno's in expressions such as WithCheckOptions and RETURNING.- */- firstVarno = mtstate->resultRelInfo[0].ri_RangeTableIndex;- firstResultRel = mtstate->resultRelInfo[0].ri_RelationDesc;- }+ mtstate->mt_partition_tuple_routing =+ ExecSetupPartitionTupleRouting(mtstate, rel);
/*
* Build state for collecting transition tuples. This requires having a
@@ -2288,77 +2280,12 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
}
/*
- * Build WITH CHECK OPTION constraints for each leaf partition rel. Note- * that we didn't build the withCheckOptionList for each partition within- * the planner, but simple translation of the varattnos for each partition- * will suffice. This only occurs for the INSERT case or for UPDATE row- * movement. DELETEs and local UPDATEs are handled above.- */- if (node->withCheckOptionLists != NIL && num_partitions > 0)- {- List *first_wcoList;-- /*- * In case of INSERT on partitioned tables, there is only one plan.- * Likewise, there is only one WITH CHECK OPTIONS list, not one per- * partition. Whereas for UPDATE, there are as many WCOs as there are- * plans. So in either case, use the WCO expression of the first- * resultRelInfo as a reference to calculate attno's for the WCO- * expression of each of the partitions. We make a copy of the WCO- * qual for each partition. Note that, if there are SubPlans in there,- * they all end up attached to the one parent Plan node.- */- Assert(update_tuple_routing_needed ||- (operation == CMD_INSERT &&- list_length(node->withCheckOptionLists) == 1 &&- mtstate->mt_nplans == 1));-- first_wcoList = linitial(node->withCheckOptionLists);- for (i = 0; i < num_partitions; i++)- {- Relation partrel;- List *mapped_wcoList;- List *wcoExprs = NIL;- ListCell *ll;-- resultRelInfo = proute->partitions[i];-- /*- * If we are referring to a resultRelInfo from one of the update- * result rels, that result rel would already have- * WithCheckOptions initialized.- */- if (resultRelInfo->ri_WithCheckOptions)- continue;-- partrel = resultRelInfo->ri_RelationDesc;-- mapped_wcoList = map_partition_varattnos(first_wcoList,- firstVarno,- partrel, firstResultRel,- NULL);- foreach(ll, mapped_wcoList)- {- WithCheckOption *wco = castNode(WithCheckOption, lfirst(ll));- ExprState *wcoExpr = ExecInitQual(castNode(List, wco->qual),- &mtstate->ps);-- wcoExprs = lappend(wcoExprs, wcoExpr);- }-- resultRelInfo->ri_WithCheckOptions = mapped_wcoList;- resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;- }- }-- /*
* Initialize RETURNING projections if needed.
*/
if (node->returningLists)
{
TupleTableSlot *slot;
ExprContext *econtext;
- List *firstReturningList;
/*
* Initialize result tuple slot and assign its rowtype using the first
@@ -2389,44 +2316,6 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
resultRelInfo->ri_RelationDesc->rd_att);
resultRelInfo++;
}
-- /*- * Build a projection for each leaf partition rel. Note that we- * didn't build the returningList for each partition within the- * planner, but simple translation of the varattnos for each partition- * will suffice. This only occurs for the INSERT case or for UPDATE- * row movement. DELETEs and local UPDATEs are handled above.- */- firstReturningList = linitial(node->returningLists);- for (i = 0; i < num_partitions; i++)- {- Relation partrel;- List *rlist;-- resultRelInfo = proute->partitions[i];-- /*- * If we are referring to a resultRelInfo from one of the update- * result rels, that result rel would already have a returningList- * built.- */- if (resultRelInfo->ri_projectReturning)- continue;-- partrel = resultRelInfo->ri_RelationDesc;-- /*- * Use the returning expression of the first resultRelInfo as a- * reference to calculate attno's for the returning expression of- * each of the partitions.- */- rlist = map_partition_varattnos(firstReturningList,- firstVarno,- partrel, firstResultRel, NULL);- resultRelInfo->ri_projectReturning =- ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,- resultRelInfo->ri_RelationDesc->rd_att);- }
}
else
{
diff --git a/src/include/executor/execPartition.h b/src/include/executor/execPartition.hindex 3df9c49..e947186 100644--- a/src/include/executor/execPartition.h+++ b/src/include/executor/execPartition.h@@ -58,6 +58,7 @@ typedef struct PartitionDispatchData *PartitionDispatch;
* partition tree.
* num_dispatch number of partitioned tables in the partition
* tree (= length of partition_dispatch_info[])
+ * partition_oids Array of leaf partitions OIDs
* partitions Array of ResultRelInfo* objects with one entry
* for every leaf partition in the partition tree.
* num_partitions Number of leaf partitions in the partition tree
@@ -91,6 +92,7 @@ typedef struct PartitionTupleRouting
{
PartitionDispatch *partition_dispatch_info;
int num_dispatch;
+ Oid *partition_oids;
ResultRelInfo **partitions;
int num_partitions;
TupleConversionMap **parent_child_tupconv_maps;
@@ -103,12 +105,15 @@ typedef struct PartitionTupleRouting
} PartitionTupleRouting;
extern PartitionTupleRouting *ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
- Relation rel, Index resultRTindex,- EState *estate);+ Relation rel);
extern int ExecFindPartition(ResultRelInfo *resultRelInfo,
PartitionDispatch *pd,
TupleTableSlot *slot,
EState *estate);
+extern ResultRelInfo *ExecInitPartitionInfo(ModifyTableState *mtstate,+ ResultRelInfo *resultRelInfo,+ PartitionTupleRouting *proute,+ EState *estate, int partidx);
extern void ExecSetupChildParentMapForLeaf(PartitionTupleRouting *proute);
extern TupleConversionMap *TupConvMapForLeaf(PartitionTupleRouting *proute,
ResultRelInfo *rootRelInfo, int leaf_index);
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: fujita.etsuro@lab.ntt.co.jp, Langote_Amit_f8@lab.ntt.co.jp, pgsql-hackers@lists.postgresql.org
Subject: Re: non-bulk inserts and tuple routing
In-Reply-To: <5A86B77E.1010306@lab.ntt.co.jp>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox