On 2018/07/19 22:03, David Rowley wrote:
> v3-0001-Fix-run-time-partition-pruning-for-UNION-ALL-pare.patch

Thanks for updating the patch.

I studied this patch today and concluded that it's going a bit too far by
carrying the nested partition pruning info structures from the planner all
the way into the executor.

I understood the root cause of this issue as that make_partition_pruneinfo
trips when UNION ALL's parent subquery, instead of the actual individual
partitioned root tables, is treated as the root parent rel when converting
prunequals using appenrel_adjust_*.  That happens because of a flattened
partitioned_rels list whose members are all assumed by
make_partition_pruneinfo to have the same root parent and that it is an
actual partitioned table.  That assumption fails in this case because the
parent is really the UNION ALL subquery rel.

I think the fix implemented in the patch by modifying allpaths.c is
correct, whereby the partition hierarchies are preserved by having nested
Lists of partitioned rels.  So, the partitioned_rels List corresponding to
UNION ALL subquery parent itself contains Lists corresponding to
partitioned tables appearing under it.  With that,
make_partition_pruneinfo (actually, make_partitionedrel_pruneinfo in the
patch) can correctly perform its work for every sub-List, because for each
sub-List, it can identify the correct root partitioned table parent to use.

But I don't think the result of make_partition_pruneinfo itself has to be
List of PartitionedRelPruneInfo nested under PartitionPruneInfo.  I gather
that each PartitionPruneInfo corresponds to each root partitioned table
and a PartitionedRelPruneInfo contains the actual pruning information,
which is created for every partitioned table (non-leaf tables), including
the root tables.  I don't think such nesting is necessary.  I think that
just like flattened partitioned_rels list, we should put flattened list of
PartitionedRelPruneInfo into the Append or MergeAppend plan.  No need for
nesting PartitionedRelPruneInfo under PartitionPruneInfo.

We create a relid_subplan_map from the flattened list of sub-plans, where
sub-plans of leaf partitions of different partitioned tables appear in the
same list.  Similarly, I think, we should create relid_subpart_map from
the flattened list of partitioned_rels, where partitioned rel RT indexes
coming from different partitioned tables appear in the same list.
Currently relid_subpart_map seems to be constructed separately for each
sub-List of nested partitioned_rels list, so while subplan_map of each
PartitionedRelPruneInfo contains indexes into a global array of leaf
partition sub-plans, subpart_map contains indexes into local array of
PartitionedRelPruneInfo for that partitioned table.  But, I think there is
not a big hurdle in making even the latter contain indexes into global
array of PartitionedRelPruneInfos of *all* partitioned tables.

On the executor side, instead of having PartitionedRelPruningData be
nested under PartitionPruningData, which in turn are stored in the
top-level PartitionPruneState, store them directly in PartitionPruneState,
since we're making planner put global indexes into subpart_map.  Slight
adjustment seems to be needed to make ExecInitFindMatchingSubPlans and
ExecFindMatchingSubPlans skip the PartitionedRelPruningData of non-root
tables, because find_matching_subplans_recurse takes care of recursing to
non-root ones.  Actually, not skipping them seems to cause wrong result.

To verify that such an approach would actually work, I modified the
relevant parts of your patch and confirmed that it does.  See attached a
delta patch.

Thanks,
Amit

PS: Other than the main patch, I think it would be nice to add a RT index
field to PartitionedRelPruneInfo in addition to the existing Oid field.
It would help to identify and fetch the Relation from a hypothetical
executor-local array of Relation pointers which is addressable by RT indexes.
diff --git a/src/backend/executor/execPartition.c 
b/src/backend/executor/execPartition.c
index dac789d414..f81ff672ca 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -48,7 +48,7 @@ static char *ExecBuildSlotPartitionKeyDescription(Relation 
rel,
                                                                         bool 
*isnull,
                                                                         int 
maxfieldlen);
 static List *adjust_partition_tlist(List *tlist, TupleConversionMap *map);
-static void find_matching_subplans_recurse(PartitionPruningData *pprune,
+static void find_matching_subplans_recurse(PartitionPruneState *prunestate,
                                                           
PartitionedRelPruningData *prelprune,
                                                           bool initial_prune,
                                                           Bitmapset 
**validsubplans);
@@ -1396,14 +1396,10 @@ adjust_partition_tlist(List *tlist, TupleConversionMap 
*map)
  *
  * 'partitionpruneinfo' is a PartitionPruneInfo as generated by
  * make_partition_pruneinfo.  Here we build a PartitionPruneState containing a
- * PartitionPruningData for each partitionpruneinfo->prune_infos, in
- * turn, a PartitionedRelPruningData is created for each
- * PartitionedRelPruneInfo stored in each 'prune_infos'.  This two-level system
- * is required in order to support run-time pruning with UNION ALL parents
- * containing one or more partitioned tables as children.  The data stored in
- * each PartitionedRelPruningData can be re-used each time we re-evaluate
- * which partitions match the pruning steps provided in each
- * PartitionedRelPruneInfo.
+ * PartitionedRelPruningData for each PartitionedRelPruneInfo
+ * in partitionpruneinfo->prune_infos.  The data stored in each
+ * PartitionedRelPruningData can be re-used each time we re-evaluate which
+ * partitions match the pruning steps provided in each PartitionedRelPruneInfo.
  */
 PartitionPruneState *
 ExecCreatePartitionPruneState(PlanState *planstate,
@@ -1422,8 +1418,8 @@ ExecCreatePartitionPruneState(PlanState *planstate,
         * Allocate the data structure
         */
        prunestate = (PartitionPruneState *)
-               palloc(offsetof(PartitionPruneState, partprunedata) +
-                          sizeof(PartitionPruningData *) * n_part_hierarchies);
+               palloc(offsetof(PartitionPruneState, partrelprunedata) +
+                          sizeof(PartitionedRelPruningData) * 
n_part_hierarchies);
 
        prunestate->num_partprunedata = n_part_hierarchies;
        prunestate->do_initial_prune = false;   /* may be set below */
@@ -1445,125 +1441,109 @@ ExecCreatePartitionPruneState(PlanState *planstate,
        i = 0;
        foreach(lc, partitionpruneinfo->prune_infos)
        {
-               ListCell   *lc2;
-               List       *partrelpruneinfos = lfirst_node(List, lc);
-               PartitionPruningData *prunedata;
-               int                     npartrelpruneinfos = 
list_length(partrelpruneinfos);
-               int                     j;
+               PartitionedRelPruneInfo *pinfo = 
castNode(PartitionedRelPruneInfo, lfirst(lc));
+               PartitionedRelPruningData *prelprune = 
&prunestate->partrelprunedata[i];
+               PartitionPruneContext *context = &prelprune->context;
+               PartitionDesc partdesc;
+               PartitionKey partkey;
+               int                     partnatts;
+               int                     n_steps;
+               ListCell   *lc3;
 
-               prunedata = palloc(offsetof(PartitionPruningData, 
partrelprunedata) +
-                                                  npartrelpruneinfos * 
sizeof(PartitionedRelPruningData));
-               prunestate->partprunedata[i] = prunedata;
-               prunedata->num_partrelprunedata = npartrelpruneinfos;
+               /*
+                * We must copy the subplan_map rather than pointing directly to
+                * the plan's version, as we may end up making modifications to 
it
+                * later.
+                */
+               prelprune->subplan_map = palloc(sizeof(int) * pinfo->nparts);
+               memcpy(prelprune->subplan_map, pinfo->subplan_map,
+                          sizeof(int) * pinfo->nparts);
 
-               j = 0;
-               foreach(lc2, partrelpruneinfos)
+               /* We can use the subpart_map verbatim, since we never modify 
it */
+               prelprune->subpart_map = pinfo->subpart_map;
+
+               /* present_parts is also subject to later modification */
+               prelprune->present_parts = bms_copy(pinfo->present_parts);
+
+               /*
+                * We need to hold a pin on the partitioned table's relcache 
entry
+                * so that we can rely on its copies of the table's partition 
key
+                * and partition descriptor.  We need not get a lock though; one
+                * should have been acquired already by InitPlan or
+                * ExecLockNonLeafAppendTables.
+                */
+               context->partrel = relation_open(pinfo->reloid, NoLock);
+
+               partkey = RelationGetPartitionKey(context->partrel);
+               partdesc = RelationGetPartitionDesc(context->partrel);
+               n_steps = list_length(pinfo->pruning_steps);
+
+               context->strategy = partkey->strategy;
+               context->partnatts = partnatts = partkey->partnatts;
+               context->nparts = pinfo->nparts;
+               context->boundinfo = partdesc->boundinfo;
+               context->partcollation = partkey->partcollation;
+               context->partsupfunc = partkey->partsupfunc;
+
+               /* We'll look up type-specific support functions as needed */
+               context->stepcmpfuncs = (FmgrInfo *)
+                       palloc0(sizeof(FmgrInfo) * n_steps * partnatts);
+
+               context->ppccontext = CurrentMemoryContext;
+               context->planstate = planstate;
+
+               /* Initialize expression state for each expression we need */
+               context->exprstates = (ExprState **)
+                       palloc0(sizeof(ExprState *) * n_steps * partnatts);
+               foreach(lc3, pinfo->pruning_steps)
                {
-                       PartitionedRelPruneInfo *pinfo = 
castNode(PartitionedRelPruneInfo, lfirst(lc2));
-                       PartitionedRelPruningData *prelprune = 
&prunedata->partrelprunedata[j];
-                       PartitionPruneContext *context = &prelprune->context;
-                       PartitionDesc partdesc;
-                       PartitionKey partkey;
-                       int                     partnatts;
-                       int                     n_steps;
-                       ListCell   *lc3;
+                       PartitionPruneStepOp *step = (PartitionPruneStepOp *) 
lfirst(lc3);
+                       ListCell   *lc4;
+                       int                     keyno;
 
-                       /*
-                        * We must copy the subplan_map rather than pointing 
directly to
-                        * the plan's version, as we may end up making 
modifications to it
-                        * later.
-                        */
-                       prelprune->subplan_map = palloc(sizeof(int) * 
pinfo->nparts);
-                       memcpy(prelprune->subplan_map, pinfo->subplan_map,
-                                  sizeof(int) * pinfo->nparts);
+                       /* not needed for other step kinds */
+                       if (!IsA(step, PartitionPruneStepOp))
+                               continue;
 
-                       /* We can use the subpart_map verbatim, since we never 
modify it */
-                       prelprune->subpart_map = pinfo->subpart_map;
+                       Assert(list_length(step->exprs) <= partnatts);
 
-                       /* present_parts is also subject to later modification 
*/
-                       prelprune->present_parts = 
bms_copy(pinfo->present_parts);
-
-                       /*
-                        * We need to hold a pin on the partitioned table's 
relcache entry
-                        * so that we can rely on its copies of the table's 
partition key
-                        * and partition descriptor.  We need not get a lock 
though; one
-                        * should have been acquired already by InitPlan or
-                        * ExecLockNonLeafAppendTables.
-                        */
-                       context->partrel = relation_open(pinfo->reloid, NoLock);
-
-                       partkey = RelationGetPartitionKey(context->partrel);
-                       partdesc = RelationGetPartitionDesc(context->partrel);
-                       n_steps = list_length(pinfo->pruning_steps);
-
-                       context->strategy = partkey->strategy;
-                       context->partnatts = partnatts = partkey->partnatts;
-                       context->nparts = pinfo->nparts;
-                       context->boundinfo = partdesc->boundinfo;
-                       context->partcollation = partkey->partcollation;
-                       context->partsupfunc = partkey->partsupfunc;
-
-                       /* We'll look up type-specific support functions as 
needed */
-                       context->stepcmpfuncs = (FmgrInfo *)
-                               palloc0(sizeof(FmgrInfo) * n_steps * partnatts);
-
-                       context->ppccontext = CurrentMemoryContext;
-                       context->planstate = planstate;
-
-                       /* Initialize expression state for each expression we 
need */
-                       context->exprstates = (ExprState **)
-                               palloc0(sizeof(ExprState *) * n_steps * 
partnatts);
-                       foreach(lc3, pinfo->pruning_steps)
+                       keyno = 0;
+                       foreach(lc4, step->exprs)
                        {
-                               PartitionPruneStepOp *step = 
(PartitionPruneStepOp *) lfirst(lc3);
-                               ListCell   *lc4;
-                               int                     keyno;
+                               Expr       *expr = (Expr *) lfirst(lc4);
 
-                               /* not needed for other step kinds */
-                               if (!IsA(step, PartitionPruneStepOp))
-                                       continue;
-
-                               Assert(list_length(step->exprs) <= partnatts);
-
-                               keyno = 0;
-                               foreach(lc4, step->exprs)
+                               /* not needed for Consts */
+                               if (!IsA(expr, Const))
                                {
-                                       Expr       *expr = (Expr *) lfirst(lc4);
+                                       int                     stateidx = 
PruneCxtStateIdx(partnatts,
+                                                                               
                                        step->step.step_id,
+                                                                               
                                        keyno);
 
-                                       /* not needed for Consts */
-                                       if (!IsA(expr, Const))
-                                       {
-                                               int                     
stateidx = PruneCxtStateIdx(partnatts,
-                                                                               
                                                step->step.step_id,
-                                                                               
                                                keyno);
-
-                                               context->exprstates[stateidx] =
-                                                       ExecInitExpr(expr, 
context->planstate);
-                                       }
-                                       keyno++;
+                                       context->exprstates[stateidx] =
+                                               ExecInitExpr(expr, 
context->planstate);
                                }
+                               keyno++;
                        }
-
-                       /* Array is not modified at runtime, so just point to 
plan's copy */
-                       context->exprhasexecparam = pinfo->hasexecparam;
-
-                       prelprune->pruning_steps = pinfo->pruning_steps;
-                       prelprune->do_initial_prune = pinfo->do_initial_prune;
-                       prelprune->do_exec_prune = pinfo->do_exec_prune;
-
-                       /* Record if pruning would be useful at any level */
-                       prunestate->do_initial_prune |= pinfo->do_initial_prune;
-                       prunestate->do_exec_prune |= pinfo->do_exec_prune;
-
-                       /*
-                        * Accumulate the IDs of all PARAM_EXEC Params 
affecting the
-                        * partitioning decisions at this plan node.
-                        */
-                       prunestate->execparamids = 
bms_add_members(prunestate->execparamids,
-                                                                               
                           pinfo->execparamids);
-
-                       j++;
                }
+
+               /* Array is not modified at runtime, so just point to plan's 
copy */
+               context->exprhasexecparam = pinfo->hasexecparam;
+
+               prelprune->pruning_steps = pinfo->pruning_steps;
+               prelprune->do_initial_prune = pinfo->do_initial_prune;
+               prelprune->do_exec_prune = pinfo->do_exec_prune;
+
+               /* Record if pruning would be useful at any level */
+               prunestate->do_initial_prune |= pinfo->do_initial_prune;
+               prunestate->do_exec_prune |= pinfo->do_exec_prune;
+
+               /*
+                * Accumulate the IDs of all PARAM_EXEC Params affecting the
+                * partitioning decisions at this plan node.
+                */
+               prunestate->execparamids = 
bms_add_members(prunestate->execparamids,
+                                                                               
                   pinfo->execparamids);
+
                i++;
        }
        return prunestate;
@@ -1579,17 +1559,14 @@ ExecCreatePartitionPruneState(PlanState *planstate,
 void
 ExecDestroyPartitionPruneState(PartitionPruneState *prunestate)
 {
-       PartitionPruningData **partprunedata = prunestate->partprunedata;
+       PartitionedRelPruningData *partrelprunedata = 
prunestate->partrelprunedata;
        int                     i;
 
        for (i = 0; i < prunestate->num_partprunedata; i++)
        {
-               PartitionPruningData *pprune = partprunedata[i];
-               PartitionedRelPruningData *prunedata = pprune->partrelprunedata;
-               int                     j;
+               PartitionedRelPruningData prunedata = partrelprunedata[i];
 
-               for (j = 0; j < pprune->num_partrelprunedata; j++)
-                       relation_close(prunedata[j].context.partrel, NoLock);
+               relation_close(prunedata.context.partrel, NoLock);
        }
 }
 
@@ -1623,14 +1600,16 @@ ExecFindInitialMatchingSubPlans(PartitionPruneState 
*prunestate, int nsubplans)
 
        for (i = 0; i < prunestate->num_partprunedata; i++)
        {
-               PartitionPruningData *pprune;
                PartitionedRelPruningData *prelprune;
 
-               pprune = prunestate->partprunedata[i];
-               prelprune = &pprune->partrelprunedata[0];
+               prelprune = &prunestate->partrelprunedata[i];
+
+               /* Only call find_matching_subplans_recurse on root table. */
+               if (prelprune->context.partrel->rd_rel->relispartition)
+                       continue;
 
                /* Perform pruning without using PARAM_EXEC Params */
-               find_matching_subplans_recurse(pprune, prelprune, true, 
&result);
+               find_matching_subplans_recurse(prunestate, prelprune, true, 
&result);
 
                /* Expression eval may have used space in node's ps_ExprContext 
too */
                ResetExprContext(prelprune->context.planstate->ps_ExprContext);
@@ -1681,58 +1660,50 @@ ExecFindInitialMatchingSubPlans(PartitionPruneState 
*prunestate, int nsubplans)
                 * 'present_parts'.
                 */
 
-               for (i = 0; i < prunestate->num_partprunedata; i++)
+               for (i = prunestate->num_partprunedata - 1; i >= 0; i--)
                {
-                       int                     j;
-                       PartitionPruningData *prunedata;
+                       PartitionedRelPruningData *pprune;
+                       int                     nparts;
+                       int                     k;
 
-                       prunedata = prunestate->partprunedata[i];
+                       pprune = &prunestate->partrelprunedata[i];
+                       nparts = pprune->context.nparts;
+                       /* We just rebuild present_parts from scratch */
+                       bms_free(pprune->present_parts);
+                       pprune->present_parts = NULL;
 
-                       for (j = prunedata->num_partrelprunedata - 1; j >= 0; 
j--)
+                       for (k = 0; k < nparts; k++)
                        {
-                               PartitionedRelPruningData *pprune;
-                               int                     nparts;
-                               int                     k;
+                               int                     oldidx = 
pprune->subplan_map[k];
+                               int                     subidx;
 
-                               pprune = &prunedata->partrelprunedata[j];
-                               nparts = pprune->context.nparts;
-                               /* We just rebuild present_parts from scratch */
-                               bms_free(pprune->present_parts);
-                               pprune->present_parts = NULL;
-
-                               for (k = 0; k < nparts; k++)
+                               /*
+                                * If this partition existed as a subplan then 
change the
+                                * old subplan index to the new subplan index.  
The new
+                                * index may become -1 if the partition was 
pruned above,
+                                * or it may just come earlier in the subplan 
list due to
+                                * some subplans being removed earlier in the 
list.  If
+                                * it's a subpartition, add it to present_parts 
unless
+                                * it's entirely pruned.
+                                */
+                               if (oldidx >= 0)
                                {
-                                       int                     oldidx = 
pprune->subplan_map[k];
-                                       int                     subidx;
+                                       Assert(oldidx < nsubplans);
+                                       pprune->subplan_map[k] = 
new_subplan_indexes[oldidx];
 
-                                       /*
-                                        * If this partition existed as a 
subplan then change the
-                                        * old subplan index to the new subplan 
index.  The new
-                                        * index may become -1 if the partition 
was pruned above,
-                                        * or it may just come earlier in the 
subplan list due to
-                                        * some subplans being removed earlier 
in the list.  If
-                                        * it's a subpartition, add it to 
present_parts unless
-                                        * it's entirely pruned.
-                                        */
-                                       if (oldidx >= 0)
-                                       {
-                                               Assert(oldidx < nsubplans);
-                                               pprune->subplan_map[k] = 
new_subplan_indexes[oldidx];
+                                       if (new_subplan_indexes[oldidx] >= 0)
+                                               pprune->present_parts =
+                                                       
bms_add_member(pprune->present_parts, k);
+                               }
+                               else if ((subidx = pprune->subpart_map[k]) >= 0)
+                               {
+                                       PartitionedRelPruningData *subprune;
 
-                                               if (new_subplan_indexes[oldidx] 
>= 0)
-                                                       pprune->present_parts =
-                                                               
bms_add_member(pprune->present_parts, k);
-                                       }
-                                       else if ((subidx = 
pprune->subpart_map[k]) >= 0)
-                                       {
-                                               PartitionedRelPruningData 
*subprune;
+                                       subprune = 
&prunestate->partrelprunedata[subidx];
 
-                                               subprune = 
&prunedata->partrelprunedata[subidx];
-
-                                               if 
(!bms_is_empty(subprune->present_parts))
-                                                       pprune->present_parts =
-                                                               
bms_add_member(pprune->present_parts, k);
-                                       }
+                                       if 
(!bms_is_empty(subprune->present_parts))
+                                               pprune->present_parts =
+                                                       
bms_add_member(pprune->present_parts, k);
                                }
                        }
                }
@@ -1764,18 +1735,21 @@ ExecFindMatchingSubPlans(PartitionPruneState 
*prunestate)
 
        for (i = 0; i < prunestate->num_partprunedata; i++)
        {
-               PartitionPruningData *pprune;
                PartitionedRelPruningData *prelprune;
 
-               pprune = prunestate->partprunedata[i];
-               prelprune = &pprune->partrelprunedata[0];
+               prelprune = &prunestate->partrelprunedata[i];
 
-               find_matching_subplans_recurse(pprune, prelprune, false, 
&result);
+               /* Only call find_matching_subplans_recurse on root table. */
+               if (prelprune->context.partrel->rd_rel->relispartition)
+                       continue;
+
+               find_matching_subplans_recurse(prunestate, prelprune, false, 
&result);
 
                /* Expression eval may have used space in node's ps_ExprContext 
too */
                ResetExprContext(prelprune->context.planstate->ps_ExprContext);
        }
 
+
        MemoryContextSwitchTo(oldcontext);
 
        /* Copy result out of the temp context before we reset it */
@@ -1797,7 +1771,7 @@ ExecFindMatchingSubPlans(PartitionPruneState *prunestate)
  * Adds valid (non-prunable) subplan IDs to *validsubplans
  */
 static void
-find_matching_subplans_recurse(PartitionPruningData *pprune,
+find_matching_subplans_recurse(PartitionPruneState *prunestate,
                                                           
PartitionedRelPruningData *prelprune,
                                                           bool initial_prune,
                                                           Bitmapset 
**validsubplans)
@@ -1841,8 +1815,8 @@ find_matching_subplans_recurse(PartitionPruningData 
*pprune,
                        int                     partidx = 
prelprune->subpart_map[i];
 
                        if (partidx >= 0)
-                               find_matching_subplans_recurse(pprune,
-                                                                               
           &pprune->partrelprunedata[partidx],
+                               find_matching_subplans_recurse(prunestate,
+                                                                               
           &prunestate->partrelprunedata[partidx],
                                                                                
           initial_prune, validsubplans);
                        else
                        {
diff --git a/src/backend/optimizer/plan/createplan.c 
b/src/backend/optimizer/plan/createplan.c
index f9e6ad3ab7..c7872661c4 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -1033,6 +1033,7 @@ create_append_plan(PlannerInfo *root, AppendPath 
*best_path)
        ListCell   *subpaths;
        RelOptInfo *rel = best_path->path.parent;
        PartitionPruneInfo *partpruneinfo = NULL;
+       List       *flattened_partitioned_rels = NIL;
 
        /*
         * The subpaths list could be empty, if every child was proven empty by
@@ -1083,6 +1084,9 @@ create_append_plan(PlannerInfo *root, AppendPath 
*best_path)
 
                prunequal = extract_actual_clauses(rel->baserestrictinfo, 
false);
 
+               flattened_partitioned_rels =
+                                       
flatten_partitioned_rels(best_path->partitioned_rels);
+
                if (best_path->path.param_info)
                {
                        List       *prmquals = 
best_path->path.param_info->ppi_clauses;
@@ -1098,6 +1102,7 @@ create_append_plan(PlannerInfo *root, AppendPath 
*best_path)
                        partpruneinfo =
                                make_partition_pruneinfo(root, rel,
                                                                                
 best_path->partitioned_rels,
+                                                                               
 flattened_partitioned_rels,
                                                                                
 best_path->subpaths, prunequal);
        }
 
@@ -1109,7 +1114,7 @@ create_append_plan(PlannerInfo *root, AppendPath 
*best_path)
         */
 
        plan = make_append(subplans, best_path->first_partial_path,
-                                          tlist, best_path->partitioned_rels,
+                                          tlist, flattened_partitioned_rels,
                                           partpruneinfo);
 
        copy_generic_path_info(&plan->plan, (Path *) best_path);
@@ -1135,6 +1140,7 @@ create_merge_append_plan(PlannerInfo *root, 
MergeAppendPath *best_path)
        ListCell   *subpaths;
        RelOptInfo *rel = best_path->path.parent;
        PartitionPruneInfo *partpruneinfo = NULL;
+       List       *flattened_partitioned_rels = NIL;
 
        /*
         * We don't have the actual creation of the MergeAppend node split out
@@ -1233,6 +1239,9 @@ create_merge_append_plan(PlannerInfo *root, 
MergeAppendPath *best_path)
 
                prunequal = extract_actual_clauses(rel->baserestrictinfo, 
false);
 
+               flattened_partitioned_rels =
+                                       
flatten_partitioned_rels(best_path->partitioned_rels);
+
                if (best_path->path.param_info)
                {
 
@@ -1247,12 +1256,12 @@ create_merge_append_plan(PlannerInfo *root, 
MergeAppendPath *best_path)
 
                if (prunequal != NIL)
                        partpruneinfo = make_partition_pruneinfo(root, rel,
-                                                                               
                          best_path->partitioned_rels,
-                                                                               
                          best_path->subpaths, prunequal);
+                                                                               
                         best_path->partitioned_rels,
+                                                                               
                         flattened_partitioned_rels,
+                                                                               
                         best_path->subpaths, prunequal);
        }
 
-       node->partitioned_rels =
-               flatten_partitioned_rels(best_path->partitioned_rels);
+       node->partitioned_rels = flattened_partitioned_rels;
        node->mergeplans = subplans;
        node->part_prune_info = partpruneinfo;
 
@@ -5006,7 +5015,7 @@ bitmap_subplan_mark_shared(Plan *plan)
 /*
  * flatten_partitioned_rels
  *             Convert List of Lists into a single List with all elements from 
the
-*              sub-lists.
+ *             sub-lists.
  */
 static List *
 flatten_partitioned_rels(List *partitioned_rels)
@@ -5380,8 +5389,9 @@ make_append(List *appendplans, int first_partial_plan,
        plan->righttree = NULL;
        node->appendplans = appendplans;
        node->first_partial_plan = first_partial_plan;
-       node->partitioned_rels = flatten_partitioned_rels(partitioned_rels);
+       node->partitioned_rels = partitioned_rels;
        node->part_prune_info = partpruneinfo;
+
        return node;
 }
 
diff --git a/src/backend/partitioning/partprune.c 
b/src/backend/partitioning/partprune.c
index 9ce216c28b..490eb4090d 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -114,6 +114,7 @@ typedef struct PruneStepResult
 static List *make_partitionedrel_pruneinfo(PlannerInfo *root,
                                                          RelOptInfo *parentrel,
                                                          int 
*relid_subplan_map,
+                                                         int 
*relid_subpart_map,
                                                          List 
*partitioned_rels, List *prunequal,
                                                          Bitmapset 
**matchedsubplans);
 static List *gen_partprune_steps(RelOptInfo *rel, List *clauses,
@@ -195,12 +196,15 @@ static bool partkey_datum_from_expr(PartitionPruneContext 
*context,
  */
 PartitionPruneInfo *
 make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
-                                                List *partitioned_rels, List 
*subpaths,
+                                                List *partitioned_rels,
+                                                List 
*flattened_partitioned_rels,
+                                                List *subpaths,
                                                 List *prunequal)
 {
        PartitionPruneInfo *pruneinfo;
        Bitmapset  *allmatchedsubplans = NULL;
        int                *relid_subplan_map;
+       int                *relid_subpart_map;
        ListCell   *lc;
        List       *prunerelinfos;
        int                     i;
@@ -230,6 +234,38 @@ make_partition_pruneinfo(PlannerInfo *root, RelOptInfo 
*parentrel,
                relid_subplan_map[pathrel->relid] = i++;
        }
 
+       /*
+        * Construct a temporary array to map from planner relids to index of 
the
+        * partitioned_rel.  For convenience, we use 1-based indexes here, so 
that
+        * zero can represent an un-filled array entry.
+        *
+        * Also, since we're going to flatten the list before putting it into 
the
+        * plan, use indexes into the flattened list in the mapping arrays of
+        * resulting PartitionedRelPruneInfo nodes, instead of indexes into
+        * individual sub-lists.
+        */
+       relid_subpart_map = palloc0(sizeof(int) * root->simple_rel_array_size);
+
+       /*
+        * relid_subpart_map maps relid of a non-leaf partition to the index in
+        * 'partitioned_rels' of that rel (which will also be the index in the
+        * returned PartitionedRelPruneInfo list of the info for that 
partition).
+        */
+       i = 1;
+       foreach(lc, flattened_partitioned_rels)
+       {
+               Index           rti = lfirst_int(lc);
+
+               Assert(rti < root->simple_rel_array_size);
+               /* No duplicates please */
+               Assert(relid_subpart_map[rti] == 0);
+               /* Same rel cannot be both leaf and non-leaf */
+               Assert(relid_subplan_map[rti] == 0);
+
+               relid_subpart_map[rti] = i++;
+       }
+
+
        Assert(partitioned_rels->type == T_List);
 
        prunerelinfos = NIL;
@@ -243,19 +279,22 @@ make_partition_pruneinfo(PlannerInfo *root, RelOptInfo 
*parentrel,
 
                prelinfolist = make_partitionedrel_pruneinfo(root, parentrel,
                                                                                
                         relid_subplan_map,
+                                                                               
                         relid_subpart_map,
                                                                                
                         rels, prunequal,
                                                                                
                         &matchedsubplans);
 
                /* When pruning is possible, record the matched subplans */
                if (prelinfolist != NIL)
                {
-                       prunerelinfos = lappend(prunerelinfos, prelinfolist);
+                       prunerelinfos = list_concat(prunerelinfos,
+                                                                               
list_copy(prelinfolist));
                        allmatchedsubplans = bms_join(matchedsubplans,
                                                                                
  allmatchedsubplans);
                }
        }
 
        pfree(relid_subplan_map);
+       pfree(relid_subpart_map);
 
        /*
         * if none of the partition hierarchies had any useful run-time pruning
@@ -310,45 +349,17 @@ make_partition_pruneinfo(PlannerInfo *root, RelOptInfo 
*parentrel,
  */
 static List *
 make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
-                                                         int 
*relid_subplan_map,
+                                                         int 
*relid_subplan_map, int *relid_subpart_map,
                                                          List 
*partitioned_rels, List *prunequal,
                                                          Bitmapset 
**matchedsubplans)
 {
        RelOptInfo *targetpart = NULL;
        List       *prelinfolist = NIL;
        bool            doruntimeprune = false;
-       bool            hascontradictingquals = false;
        ListCell   *lc;
-       int                *relid_subpart_map;
        Bitmapset  *subplansfound = NULL;
        int                     i;
 
-       /*
-        * Construct a temporary array to map from planner relids to index of 
the
-        * partitioned_rel.  For convenience, we use 1-based indexes here, so 
that
-        * zero can represent an un-filled array entry.
-        */
-       relid_subpart_map = palloc0(sizeof(int) * root->simple_rel_array_size);
-
-       /*
-        * relid_subpart_map maps relid of a non-leaf partition to the index in
-        * 'partitioned_rels' of that rel (which will also be the index in the
-        * returned PartitionedRelPruneInfo list of the info for that 
partition).
-        */
-       i = 1;
-       foreach(lc, partitioned_rels)
-       {
-               Index           rti = lfirst_int(lc);
-
-               Assert(rti < root->simple_rel_array_size);
-               /* No duplicates please */
-               Assert(relid_subpart_map[rti] == 0);
-               /* Same rel cannot be both leaf and non-leaf */
-               Assert(relid_subplan_map[rti] == 0);
-
-               relid_subpart_map[rti] = i++;
-       }
-
        /* We now build a PartitionedRelPruneInfo for each partitioned rel */
        foreach(lc, partitioned_rels)
        {
@@ -477,8 +488,6 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo 
*parentrel,
                prelinfolist = lappend(prelinfolist, prelinfo);
        }
 
-       pfree(relid_subpart_map);
-
        if (!doruntimeprune)
                return NIL;
 
diff --git a/src/include/executor/execPartition.h 
b/src/include/executor/execPartition.h
index 4327fd4cb1..5b6acac4f0 100644
--- a/src/include/executor/execPartition.h
+++ b/src/include/executor/execPartition.h
@@ -147,17 +147,6 @@ typedef struct PartitionedRelPruningData
        bool            do_exec_prune;
 } PartitionedRelPruningData;
 
-/*
- * PartitionPruningData - Encapsulates an array of PartitionedRelPruningData
- * which belong to a single partition hierarchy containing 1 or more
- * partitions.
- */
-typedef struct PartitionPruningData
-{
-       int                     num_partrelprunedata;
-       PartitionedRelPruningData partrelprunedata[FLEXIBLE_ARRAY_MEMBER];
-} PartitionPruningData;
-
 /*-----------------------
  * PartitionPruneState - State object required for plan nodes to perform
  * run-time partition pruning.
@@ -198,7 +187,7 @@ typedef struct PartitionPruneState
        Bitmapset  *execparamids;
        Bitmapset  *other_subplans;
        MemoryContext prune_context;
-       PartitionPruningData *partprunedata[FLEXIBLE_ARRAY_MEMBER];
+       PartitionedRelPruningData partrelprunedata[FLEXIBLE_ARRAY_MEMBER];
 } PartitionPruneState;
 
 extern PartitionTupleRouting *ExecSetupPartitionTupleRouting(ModifyTableState 
*mtstate,
diff --git a/src/include/partitioning/partprune.h 
b/src/include/partitioning/partprune.h
index df3bcb737d..79398d1cc1 100644
--- a/src/include/partitioning/partprune.h
+++ b/src/include/partitioning/partprune.h
@@ -77,6 +77,7 @@ typedef struct PartitionPruneContext
 extern PartitionPruneInfo *make_partition_pruneinfo(PlannerInfo *root,
                                                 RelOptInfo *parentrel,
                                                 List *partitioned_rels,
+                                                List 
*flattened_partitioned_rels,
                                                 List *subpaths, List 
*prunequal);
 extern Relids prune_append_rel_partitions(RelOptInfo *rel);
 extern Bitmapset *get_matching_partitions(PartitionPruneContext *context,

Reply via email to