ExecInitRangeTable(estate, rangeTable, plannedstmt->permInfos);
 
    estate->es_plannedstmt = plannedstmt;
+   estate->es_part_prune_infos = plannedstmt->partPruneInfos;
 
    /*
     * Next, build the ExecRowMark array from the PlanRowMark(s), if any.
 
    pstmt->dependsOnRole = false;
    pstmt->parallelModeNeeded = false;
    pstmt->planTree = plan;
+   pstmt->partPruneInfos = estate->es_part_prune_infos;
    pstmt->rtable = estate->es_range_table;
    pstmt->permInfos = estate->es_rteperminfos;
    pstmt->resultRelations = NIL;
 
  *     Initialize data structure needed for run-time partition pruning and
  *     do initial pruning if needed
  *
+ * 'relids' identifies the relation to which both the parent plan and the
+ * PartitionPruneInfo given by 'part_prune_index' belong.
+ *
  * On return, *initially_valid_subplans is assigned the set of indexes of
  * child subplans that must be initialized along with the parent plan node.
  * Initial pruning is performed here if needed and in that case only the
 PartitionPruneState *
 ExecInitPartitionPruning(PlanState *planstate,
                         int n_total_subplans,
-                        PartitionPruneInfo *pruneinfo,
+                        int part_prune_index,
+                        Bitmapset *relids,
                         Bitmapset **initially_valid_subplans)
 {
    PartitionPruneState *prunestate;
    EState     *estate = planstate->state;
+   PartitionPruneInfo *pruneinfo;
+
+   /* Obtain the pruneinfo we need. */
+   pruneinfo = list_nth_node(PartitionPruneInfo, estate->es_part_prune_infos,
+                             part_prune_index);
+
+   /* Its relids better match the plan node's or the planner messed up. */
+   if (!bms_equal(relids, pruneinfo->relids))
+       elog(ERROR, "wrong pruneinfo with relids=%s found at part_prune_index=%d contained in plan node with relids=%s",
+            bmsToString(pruneinfo->relids), part_prune_index,
+            bmsToString(relids));
 
    /* We may need an expression context to evaluate partition exprs */
    ExecAssignExprContext(estate, planstate);
 
    estate->es_rowmarks = NULL;
    estate->es_rteperminfos = NIL;
    estate->es_plannedstmt = NULL;
+   estate->es_part_prune_infos = NIL;
 
    estate->es_junkFilter = NULL;
 
 
    appendstate->as_begun = false;
 
    /* If run-time partition pruning is enabled, then set that up now */
-   if (node->part_prune_info != NULL)
+   if (node->part_prune_index >= 0)
    {
        PartitionPruneState *prunestate;
 
         */
        prunestate = ExecInitPartitionPruning(&appendstate->ps,
                                              list_length(node->appendplans),
-                                             node->part_prune_info,
+                                             node->part_prune_index,
+                                             node->apprelids,
                                              &validsubplans);
        appendstate->as_prune_state = prunestate;
        nplans = bms_num_members(validsubplans);
 
    mergestate->ps.ExecProcNode = ExecMergeAppend;
 
    /* If run-time partition pruning is enabled, then set that up now */
-   if (node->part_prune_info != NULL)
+   if (node->part_prune_index >= 0)
    {
        PartitionPruneState *prunestate;
 
         */
        prunestate = ExecInitPartitionPruning(&mergestate->ps,
                                              list_length(node->mergeplans),
-                                             node->part_prune_info,
+                                             node->part_prune_index,
+                                             node->apprelids,
                                              &validsubplans);
        mergestate->ms_prune_state = prunestate;
        nplans = bms_num_members(validsubplans);
 
    ListCell   *subpaths;
    int         nasyncplans = 0;
    RelOptInfo *rel = best_path->path.parent;
-   PartitionPruneInfo *partpruneinfo = NULL;
    int         nodenumsortkeys = 0;
    AttrNumber *nodeSortColIdx = NULL;
    Oid        *nodeSortOperators = NULL;
        subplans = lappend(subplans, subplan);
    }
 
+   /* Set below if we find quals that we can use to run-time prune */
+   plan->part_prune_index = -1;
+
    /*
     * If any quals exist, they may be useful to perform further partition
     * pruning during execution.  Gather information needed by the executor to
        }
 
        if (prunequal != NIL)
-           partpruneinfo =
-               make_partition_pruneinfo(root, rel,
-                                        best_path->subpaths,
-                                        prunequal);
+           plan->part_prune_index = make_partition_pruneinfo(root, rel,
+                                                             best_path->subpaths,
+                                                             prunequal);
    }
 
    plan->appendplans = subplans;
    plan->nasyncplans = nasyncplans;
    plan->first_partial_plan = best_path->first_partial_path;
-   plan->part_prune_info = partpruneinfo;
 
    copy_generic_path_info(&plan->plan, (Path *) best_path);
 
    List       *subplans = NIL;
    ListCell   *subpaths;
    RelOptInfo *rel = best_path->path.parent;
-   PartitionPruneInfo *partpruneinfo = NULL;
 
    /*
     * We don't have the actual creation of the MergeAppend node split out
        subplans = lappend(subplans, subplan);
    }
 
+   /* Set below if we find quals that we can use to run-time prune */
+   node->part_prune_index = -1;
+
    /*
     * If any quals exist, they may be useful to perform further partition
     * pruning during execution.  Gather information needed by the executor to
        Assert(best_path->path.param_info == NULL);
 
        if (prunequal != NIL)
-           partpruneinfo = make_partition_pruneinfo(root, rel,
-                                                    best_path->subpaths,
-                                                    prunequal);
+           node->part_prune_index = make_partition_pruneinfo(root, rel,
+                                                             best_path->subpaths,
+                                                             prunequal);
    }
 
    node->mergeplans = subplans;
-   node->part_prune_info = partpruneinfo;
 
    /*
     * If prepare_sort_from_pathkeys added sort columns, but we were told to
 
    result->dependsOnRole = glob->dependsOnRole;
    result->parallelModeNeeded = glob->parallelModeNeeded;
    result->planTree = top_plan;
+   result->partPruneInfos = glob->partPruneInfos;
    result->rtable = glob->finalrtable;
    result->permInfos = glob->finalrteperminfos;
    result->resultRelations = glob->resultRelations;
 
    cscan->custom_relids = offset_relid_set(cscan->custom_relids, rtoffset);
 }
 
+/*
+ * register_partpruneinfo
+ *     Subroutine for set_append_references and set_mergeappend_references
+ *
+ * Add the PartitionPruneInfo from root->partPruneInfos at the given index
+ * into PlannerGlobal->partPruneInfos and return its index there.
+ *
+ * Also update the RT indexes present in PartitionedRelPruneInfos to add the
+ * offset.
+ */
+static int
+register_partpruneinfo(PlannerInfo *root, int part_prune_index, int rtoffset)
+{
+   PlannerGlobal *glob = root->glob;
+   PartitionPruneInfo *pinfo;
+   ListCell   *l;
+
+   Assert(part_prune_index >= 0 &&
+          part_prune_index < list_length(root->partPruneInfos));
+   pinfo = list_nth_node(PartitionPruneInfo, root->partPruneInfos,
+                         part_prune_index);
+
+   pinfo->relids = offset_relid_set(pinfo->relids, rtoffset);
+   foreach(l, pinfo->prune_infos)
+   {
+       List       *prune_infos = lfirst(l);
+       ListCell   *l2;
+
+       foreach(l2, prune_infos)
+       {
+           PartitionedRelPruneInfo *prelinfo = lfirst(l2);
+
+           prelinfo->rtindex += rtoffset;
+           prelinfo->initial_pruning_steps =
+               fix_scan_list(root, prelinfo->initial_pruning_steps,
+                             rtoffset, 1);
+           prelinfo->exec_pruning_steps =
+               fix_scan_list(root, prelinfo->exec_pruning_steps,
+                             rtoffset, 1);
+       }
+   }
+
+   glob->partPruneInfos = lappend(glob->partPruneInfos, pinfo);
+
+   return list_length(glob->partPruneInfos) - 1;
+}
+
 /*
  * set_append_references
  *     Do set_plan_references processing on an Append
 
    aplan->apprelids = offset_relid_set(aplan->apprelids, rtoffset);
 
-   if (aplan->part_prune_info)
-   {
-       foreach(l, aplan->part_prune_info->prune_infos)
-       {
-           List       *prune_infos = lfirst(l);
-           ListCell   *l2;
-
-           foreach(l2, prune_infos)
-           {
-               PartitionedRelPruneInfo *pinfo = lfirst(l2);
-
-               pinfo->rtindex += rtoffset;
-               pinfo->initial_pruning_steps =
-                   fix_scan_list(root, pinfo->initial_pruning_steps,
-                                 rtoffset, 1);
-               pinfo->exec_pruning_steps =
-                   fix_scan_list(root, pinfo->exec_pruning_steps,
-                                 rtoffset, 1);
-           }
-       }
-   }
+   /*
+    * Add PartitionPruneInfo, if any, to PlannerGlobal and update the index.
+    * Also update the RT indexes present in it to add the offset.
+    */
+   if (aplan->part_prune_index >= 0)
+       aplan->part_prune_index =
+           register_partpruneinfo(root, aplan->part_prune_index, rtoffset);
 
    /* We don't need to recurse to lefttree or righttree ... */
    Assert(aplan->plan.lefttree == NULL);
 
    mplan->apprelids = offset_relid_set(mplan->apprelids, rtoffset);
 
-   if (mplan->part_prune_info)
-   {
-       foreach(l, mplan->part_prune_info->prune_infos)
-       {
-           List       *prune_infos = lfirst(l);
-           ListCell   *l2;
-
-           foreach(l2, prune_infos)
-           {
-               PartitionedRelPruneInfo *pinfo = lfirst(l2);
-
-               pinfo->rtindex += rtoffset;
-               pinfo->initial_pruning_steps =
-                   fix_scan_list(root, pinfo->initial_pruning_steps,
-                                 rtoffset, 1);
-               pinfo->exec_pruning_steps =
-                   fix_scan_list(root, pinfo->exec_pruning_steps,
-                                 rtoffset, 1);
-           }
-       }
-   }
+   /*
+    * Add PartitionPruneInfo, if any, to PlannerGlobal and update the index.
+    * Also update the RT indexes present in it to add the offset.
+    */
+   if (mplan->part_prune_index >= 0)
+       mplan->part_prune_index =
+           register_partpruneinfo(root, mplan->part_prune_index, rtoffset);
 
    /* We don't need to recurse to lefttree or righttree ... */
    Assert(mplan->plan.lefttree == NULL);
 
 
 /*
  * make_partition_pruneinfo
- *     Builds a PartitionPruneInfo which can be used in the executor to allow
- *     additional partition pruning to take place.  Returns NULL when
- *     partition pruning would be useless.
+ *     Checks if the given set of quals can be used to build pruning steps
+ *     that the executor can use to prune away unneeded partitions.  If
+ *     suitable quals are found then a PartitionPruneInfo is built and tagged
+ *     onto the PlannerInfo's partPruneInfos list.
+ *
+ * The return value is the 0-based index of the item added to the
+ * partPruneInfos list or -1 if nothing was added.
  *
  * 'parentrel' is the RelOptInfo for an appendrel, and 'subpaths' is the list
  * of scan paths for its child rels.
  * 'prunequal' is a list of potential pruning quals (i.e., restriction
  * clauses that are applicable to the appendrel).
  */
-PartitionPruneInfo *
+int
 make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
                         List *subpaths,
                         List *prunequal)
     * quals, then we can just not bother with run-time pruning.
     */
    if (prunerelinfos == NIL)
-       return NULL;
+       return -1;
 
    /* Else build the result data structure */
    pruneinfo = makeNode(PartitionPruneInfo);
+   pruneinfo->relids = bms_copy(parentrel->relids);
    pruneinfo->prune_infos = prunerelinfos;
 
    /*
    else
        pruneinfo->other_subplans = NULL;
 
-   return pruneinfo;
+   root->partPruneInfos = lappend(root->partPruneInfos, pruneinfo);
+
+   return list_length(root->partPruneInfos) - 1;
 }
 
 /*
 
 
 extern PartitionPruneState *ExecInitPartitionPruning(PlanState *planstate,
                                                     int n_total_subplans,
-                                                    PartitionPruneInfo *pruneinfo,
+                                                    int part_prune_index,
+                                                    Bitmapset *relids,
                                                     Bitmapset **initially_valid_subplans);
 extern Bitmapset *ExecFindMatchingSubPlans(PartitionPruneState *prunestate,
                                           bool initial_prune);
 
                                         * ExecRowMarks, or NULL if none */
    List       *es_rteperminfos;    /* List of RTEPermissionInfo */
    PlannedStmt *es_plannedstmt;    /* link to top of plan tree */
+   List       *es_part_prune_infos;    /* List of PartitionPruneInfo */
    const char *es_sourceText;  /* Source text from QueryDesc */
 
    JunkFilter *es_junkFilter;  /* top-level junk filter, if any */
 
    /* "flat" list of AppendRelInfos */
    List       *appendRelations;
 
+   /* "flat" list of PartitionPruneInfos */
+   List       *partPruneInfos;
+
    /* OIDs of relations the plan depends on */
    List       *relationOids;
 
 
    /* Does this query modify any partition key columns? */
    bool        partColsUpdated;
+
+   /* PartitionPruneInfos added in this query's plan. */
+   List       *partPruneInfos;
 };
 
 
 
 
    struct Plan *planTree;      /* tree of Plan nodes */
 
+   List       *partPruneInfos; /* List of PartitionPruneInfo contained in the
+                                * plan */
+
    List       *rtable;         /* list of RangeTblEntry nodes */
 
    List       *permInfos;      /* list of RTEPermissionInfo nodes for rtable
     */
    int         first_partial_plan;
 
-   /* Info for run-time subplan pruning; NULL if we're not doing that */
-   struct PartitionPruneInfo *part_prune_info;
+   /* Index to PlannerInfo.partPruneInfos or -1 if no run-time pruning */
+   int         part_prune_index;
 } Append;
 
 /* ----------------
    /* NULLS FIRST/LAST directions */
    bool       *nullsFirst pg_node_attr(array_size(numCols));
 
-   /* Info for run-time subplan pruning; NULL if we're not doing that */
-   struct PartitionPruneInfo *part_prune_info;
+   /* Index to PlannerInfo.partPruneInfos or -1 if no run-time pruning */
+   int         part_prune_index;
 } MergeAppend;
 
 /* ----------------
  * Then, since an Append-type node could have multiple partitioning
  * hierarchies among its children, we have an unordered List of those Lists.
  *
+ * relids              RelOptInfo.relids of the parent plan node (e.g. Append
+ *                     or MergeAppend) to which this PartitionPruneInfo node
+ *                     belongs.  The pruning logic ensures that this matches
+ *                     the parent plan node's apprelids.
  * prune_infos         List of Lists containing PartitionedRelPruneInfo nodes,
  *                     one sublist per run-time-prunable partition hierarchy
  *                     appearing in the parent plan node's subplans.
    pg_node_attr(no_equal, no_query_jumble)
 
    NodeTag     type;
+   Bitmapset  *relids;
    List       *prune_infos;
    Bitmapset  *other_subplans;
 } PartitionPruneInfo;
 
 #define PruneCxtStateIdx(partnatts, step_id, keyno) \
    ((partnatts) * (step_id) + (keyno))
 
-extern PartitionPruneInfo *make_partition_pruneinfo(struct PlannerInfo *root,
-                                                   struct RelOptInfo *parentrel,
-                                                   List *subpaths,
-                                                   List *prunequal);
+extern int make_partition_pruneinfo(struct PlannerInfo *root,
+                                    struct RelOptInfo *parentrel,
+                                    List *subpaths,
+                                    List *prunequal);
 extern Bitmapset *prune_append_rel_partitions(struct RelOptInfo *rel);
 extern Bitmapset *get_matching_partitions(PartitionPruneContext *context,
                                          List *pruning_steps);