Re: Runtime pruning problem

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Re: Runtime pruning problem
Дата
Msg-id 15501.1575420449@sss.pgh.pa.us
обсуждение исходный текст
Ответ на Re: Runtime pruning problem  (Alvaro Herrera <alvherre@2ndquadrant.com>)
Список pgsql-hackers
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
> On 2019-Jul-30, Tom Lane wrote:
>> The portion of this below the Append is fine, but I argue that
>> the Vars above the Append should say "part", not "part_p1".
>> In that way they'd look the same regardless of which partitions
>> have been pruned or not.

> So is anyone working on a patch to use this approach?

I spent some more time on this today, and successfully converted
ruleutils.c back to dealing only in Plan trees not PlanState trees.
The hard part of this turned out to be that in a Plan tree, it's
not so easy to identify subplans and initplans; the links that
simplify that in the existing ruleutils code get set up while
initializing the PlanState tree.  I had to do two things to make
it work:

* To cope with CTEScans and initPlans, ruleutils now needs access to the
PlannedStmt->subplans list, which can be set up along with the rtable.
I thought adding that as a separate argument wasn't very forward-looking,
so instead I changed the API of that function to pass the PlannedStmt.

* To cope with SubPlans, I changed the definition of the "ancestors"
list so that it includes SubPlans along with regular Plan nodes.
This is slightly squirrely, because SubPlan isn't a subclass of Plan,
but it seems to work well.  Notably, we don't have to search for
relevant SubPlan nodes in find_param_referent().  We'll just arrive
at them naturally while chasing up the ancestors list.

I don't think this is committable as it stands, because there are
a couple of undesirable changes in partition_prune.out.  Those test
cases are explaining queries in which the first child of a MergeAppend
gets pruned during executor start.  That results in ExplainPreScanNode
not seeing that node, so it deems the associated RTE to be unreferenced,
so select_rtable_names_for_explain doesn't assign that RTE an alias.
But then when we drill down for a referent for a Var above the
MergeAppend, we go to the first child of the MergeAppend (not the
MergeAppendState), ie exactly the RTE that was deemed unreferenced.
So we end up with no table alias to print.

That's not ruleutils.c's fault obviously: it did what it was told.
And it ties right into the question that's at the heart of this
discussion, ie what do we want to print for such Vars?  So I think
this patch is all right as a component of the full fix, but now we
have to move on to the main event.  I have some ideas about what
to do next, but they're not fully baked yet.

            regards, tom lane

diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 62fb343..4d9d668 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -689,8 +689,8 @@ ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
     es->rtable = queryDesc->plannedstmt->rtable;
     ExplainPreScanNode(queryDesc->planstate, &rels_used);
     es->rtable_names = select_rtable_names_for_explain(es->rtable, rels_used);
-    es->deparse_cxt = deparse_context_for_plan_rtable(es->rtable,
-                                                      es->rtable_names);
+    es->deparse_cxt = deparse_context_for_plan_tree(queryDesc->plannedstmt,
+                                                    es->rtable_names);
     es->printed_subplans = NULL;

     /*
@@ -1049,8 +1049,8 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
  * We need to work from a PlanState node, not just a Plan node, in order to
  * get at the instrumentation data (if any) as well as the list of subplans.
  *
- * ancestors is a list of parent PlanState nodes, most-closely-nested first.
- * These are needed in order to interpret PARAM_EXEC Params.
+ * ancestors is a list of parent Plan and SubPlan nodes, most-closely-nested
+ * first.  These are needed in order to interpret PARAM_EXEC Params.
  *
  * relationship describes the relationship of this plan node to its parent
  * (eg, "Outer", "Inner"); it can be null at top level.  plan_name is an
@@ -1953,8 +1953,8 @@ ExplainNode(PlanState *planstate, List *ancestors,
     if (haschildren)
     {
         ExplainOpenGroup("Plans", "Plans", false, es);
-        /* Pass current PlanState as head of ancestors list for children */
-        ancestors = lcons(planstate, ancestors);
+        /* Pass current Plan as head of ancestors list for children */
+        ancestors = lcons(plan, ancestors);
     }

     /* initPlan-s */
@@ -2075,9 +2075,9 @@ show_plan_tlist(PlanState *planstate, List *ancestors, ExplainState *es)
         return;

     /* Set up deparsing context */
-    context = set_deparse_context_planstate(es->deparse_cxt,
-                                            (Node *) planstate,
-                                            ancestors);
+    context = set_deparse_context_plan(es->deparse_cxt,
+                                       plan,
+                                       ancestors);
     useprefix = list_length(es->rtable) > 1;

     /* Deparse each result column (we now include resjunk ones) */
@@ -2106,9 +2106,9 @@ show_expression(Node *node, const char *qlabel,
     char       *exprstr;

     /* Set up deparsing context */
-    context = set_deparse_context_planstate(es->deparse_cxt,
-                                            (Node *) planstate,
-                                            ancestors);
+    context = set_deparse_context_plan(es->deparse_cxt,
+                                       planstate->plan,
+                                       ancestors);

     /* Deparse the expression */
     exprstr = deparse_expression(node, context, useprefix, false);
@@ -2209,7 +2209,7 @@ show_agg_keys(AggState *astate, List *ancestors,
     if (plan->numCols > 0 || plan->groupingSets)
     {
         /* The key columns refer to the tlist of the child plan */
-        ancestors = lcons(astate, ancestors);
+        ancestors = lcons(plan, ancestors);

         if (plan->groupingSets)
             show_grouping_sets(outerPlanState(astate), plan, ancestors, es);
@@ -2232,9 +2232,9 @@ show_grouping_sets(PlanState *planstate, Agg *agg,
     ListCell   *lc;

     /* Set up deparsing context */
-    context = set_deparse_context_planstate(es->deparse_cxt,
-                                            (Node *) planstate,
-                                            ancestors);
+    context = set_deparse_context_plan(es->deparse_cxt,
+                                       planstate->plan,
+                                       ancestors);
     useprefix = (list_length(es->rtable) > 1 || es->verbose);

     ExplainOpenGroup("Grouping Sets", "Grouping Sets", false, es);
@@ -2339,7 +2339,7 @@ show_group_keys(GroupState *gstate, List *ancestors,
     Group       *plan = (Group *) gstate->ss.ps.plan;

     /* The key columns refer to the tlist of the child plan */
-    ancestors = lcons(gstate, ancestors);
+    ancestors = lcons(plan, ancestors);
     show_sort_group_keys(outerPlanState(gstate), "Group Key",
                          plan->numCols, plan->grpColIdx,
                          NULL, NULL, NULL,
@@ -2371,9 +2371,9 @@ show_sort_group_keys(PlanState *planstate, const char *qlabel,
     initStringInfo(&sortkeybuf);

     /* Set up deparsing context */
-    context = set_deparse_context_planstate(es->deparse_cxt,
-                                            (Node *) planstate,
-                                            ancestors);
+    context = set_deparse_context_plan(es->deparse_cxt,
+                                       plan,
+                                       ancestors);
     useprefix = (list_length(es->rtable) > 1 || es->verbose);

     for (keyno = 0; keyno < nkeys; keyno++)
@@ -2479,9 +2479,9 @@ show_tablesample(TableSampleClause *tsc, PlanState *planstate,
     ListCell   *lc;

     /* Set up deparsing context */
-    context = set_deparse_context_planstate(es->deparse_cxt,
-                                            (Node *) planstate,
-                                            ancestors);
+    context = set_deparse_context_plan(es->deparse_cxt,
+                                       planstate->plan,
+                                       ancestors);
     useprefix = list_length(es->rtable) > 1;

     /* Get the tablesample method name */
@@ -3344,7 +3344,7 @@ ExplainMemberNodes(PlanState **planstates, int nsubnodes, int nplans,
  * Explain a list of SubPlans (or initPlans, which also use SubPlan nodes).
  *
  * The ancestors list should already contain the immediate parent of these
- * SubPlanStates.
+ * SubPlans.
  */
 static void
 ExplainSubPlans(List *plans, List *ancestors,
@@ -3372,8 +3372,17 @@ ExplainSubPlans(List *plans, List *ancestors,
         es->printed_subplans = bms_add_member(es->printed_subplans,
                                               sp->plan_id);

+        /*
+         * Treat the SubPlan node as an ancestor of the plan node(s) within
+         * it, so that ruleutils.c can find the referents of subplan
+         * parameters.
+         */
+        ancestors = lcons(sp, ancestors);
+
         ExplainNode(sps->planstate, ancestors,
                     relationship, sp->plan_name, es);
+
+        ancestors = list_delete_first(ancestors);
     }
 }

diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index c9d024e..7f3e5bf 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2527,9 +2527,6 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
         econtext = mtstate->ps.ps_ExprContext;
         relationDesc = resultRelInfo->ri_RelationDesc->rd_att;

-        /* carried forward solely for the benefit of explain */
-        mtstate->mt_excludedtlist = node->exclRelTlist;
-
         /* create state for DO UPDATE SET operation */
         resultRelInfo->ri_onConflict = makeNode(OnConflictSetState);

diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 13685a0..73a6132 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -125,13 +125,15 @@ typedef struct
  * A Var having varlevelsup=N refers to the N'th item (counting from 0) in
  * the current context's namespaces list.
  *
- * The rangetable is the list of actual RTEs from the query tree, and the
- * cte list is the list of actual CTEs.
- *
+ * rtable is the list of actual RTEs from the Query or PlannedStmt.
  * rtable_names holds the alias name to be used for each RTE (either a C
  * string, or NULL for nameless RTEs such as unnamed joins).
  * rtable_columns holds the column alias names to be used for each RTE.
  *
+ * subplans is a list of Plan trees for SubPlans and CTEs (it's only used
+ * in the PlannedStmt case).
+ * ctes is a list of CommonTableExpr nodes (only used in the Query case).
+ *
  * In some cases we need to make names of merged JOIN USING columns unique
  * across the whole query, not only per-RTE.  If so, unique_using is true
  * and using_names is a list of C strings representing names already assigned
@@ -139,28 +141,29 @@ typedef struct
  *
  * When deparsing plan trees, there is always just a single item in the
  * deparse_namespace list (since a plan tree never contains Vars with
- * varlevelsup > 0).  We store the PlanState node that is the immediate
+ * varlevelsup > 0).  We store the Plan node that is the immediate
  * parent of the expression to be deparsed, as well as a list of that
- * PlanState's ancestors.  In addition, we store its outer and inner subplan
- * state nodes, as well as their plan nodes' targetlists, and the index tlist
- * if the current plan node might contain INDEX_VAR Vars.  (These fields could
- * be derived on-the-fly from the current PlanState, but it seems notationally
- * clearer to set them up as separate fields.)
+ * Plan's ancestors.  In addition, we store its outer and inner subplan nodes,
+ * as well as their targetlists, and the index tlist if the current plan node
+ * might contain INDEX_VAR Vars.  (These fields could be derived on-the-fly
+ * from the current Plan node, but it seems notationally clearer to set them
+ * up as separate fields.)
  */
 typedef struct
 {
     List       *rtable;            /* List of RangeTblEntry nodes */
     List       *rtable_names;    /* Parallel list of names for RTEs */
     List       *rtable_columns; /* Parallel list of deparse_columns structs */
+    List       *subplans;        /* List of Plan trees for SubPlans */
     List       *ctes;            /* List of CommonTableExpr nodes */
     /* Workspace for column alias assignment: */
     bool        unique_using;    /* Are we making USING names globally unique */
     List       *using_names;    /* List of assigned names for USING columns */
     /* Remaining fields are used only when deparsing a Plan tree: */
-    PlanState  *planstate;        /* immediate parent of current expression */
-    List       *ancestors;        /* ancestors of planstate */
-    PlanState  *outer_planstate;    /* outer subplan state, or NULL if none */
-    PlanState  *inner_planstate;    /* inner subplan state, or NULL if none */
+    Plan       *plan;            /* immediate parent of current expression */
+    List       *ancestors;        /* ancestors of plan */
+    Plan       *outer_plan;        /* outer subnode, or NULL if none */
+    Plan       *inner_plan;        /* inner subnode, or NULL if none */
     List       *outer_tlist;    /* referent for OUTER_VAR Vars */
     List       *inner_tlist;    /* referent for INNER_VAR Vars */
     List       *index_tlist;    /* referent for INDEX_VAR Vars */
@@ -357,8 +360,8 @@ static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
 static void flatten_join_using_qual(Node *qual,
                                     List **leftvars, List **rightvars);
 static char *get_rtable_name(int rtindex, deparse_context *context);
-static void set_deparse_planstate(deparse_namespace *dpns, PlanState *ps);
-static void push_child_plan(deparse_namespace *dpns, PlanState *ps,
+static void set_deparse_plan(deparse_namespace *dpns, Plan *plan);
+static void push_child_plan(deparse_namespace *dpns, Plan *plan,
                             deparse_namespace *save_dpns);
 static void pop_child_plan(deparse_namespace *dpns,
                            deparse_namespace *save_dpns);
@@ -1022,6 +1025,7 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
         /* Build two-element rtable */
         memset(&dpns, 0, sizeof(dpns));
         dpns.rtable = list_make2(oldrte, newrte);
+        dpns.subplans = NIL;
         dpns.ctes = NIL;
         set_rtable_names(&dpns, NIL, NULL);
         set_simple_column_names(&dpns);
@@ -3274,6 +3278,7 @@ deparse_context_for(const char *aliasname, Oid relid)

     /* Build one-element rtable */
     dpns->rtable = list_make1(rte);
+    dpns->subplans = NIL;
     dpns->ctes = NIL;
     set_rtable_names(dpns, NIL, NULL);
     set_simple_column_names(dpns);
@@ -3283,28 +3288,29 @@ deparse_context_for(const char *aliasname, Oid relid)
 }

 /*
- * deparse_context_for_plan_rtable - Build deparse context for a plan's rtable
+ * deparse_context_for_plan_tree - Build deparse context for a Plan tree
  *
  * When deparsing an expression in a Plan tree, we use the plan's rangetable
  * to resolve names of simple Vars.  The initialization of column names for
  * this is rather expensive if the rangetable is large, and it'll be the same
  * for every expression in the Plan tree; so we do it just once and re-use
  * the result of this function for each expression.  (Note that the result
- * is not usable until set_deparse_context_planstate() is applied to it.)
+ * is not usable until set_deparse_context_plan() is applied to it.)
  *
- * In addition to the plan's rangetable list, pass the per-RTE alias names
+ * In addition to the PlannedStmt, pass the per-RTE alias names
  * assigned by a previous call to select_rtable_names_for_explain.
  */
 List *
-deparse_context_for_plan_rtable(List *rtable, List *rtable_names)
+deparse_context_for_plan_tree(PlannedStmt *pstmt, List *rtable_names)
 {
     deparse_namespace *dpns;

     dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));

     /* Initialize fields that stay the same across the whole plan tree */
-    dpns->rtable = rtable;
+    dpns->rtable = pstmt->rtable;
     dpns->rtable_names = rtable_names;
+    dpns->subplans = pstmt->subplans;
     dpns->ctes = NIL;

     /*
@@ -3319,11 +3325,11 @@ deparse_context_for_plan_rtable(List *rtable, List *rtable_names)
 }

 /*
- * set_deparse_context_planstate    - Specify Plan node containing expression
+ * set_deparse_context_plan - Specify Plan node containing expression
  *
  * When deparsing an expression in a Plan tree, we might have to resolve
  * OUTER_VAR, INNER_VAR, or INDEX_VAR references.  To do this, the caller must
- * provide the parent PlanState node.  Then OUTER_VAR and INNER_VAR references
+ * provide the parent Plan node.  Then OUTER_VAR and INNER_VAR references
  * can be resolved by drilling down into the left and right child plans.
  * Similarly, INDEX_VAR references can be resolved by reference to the
  * indextlist given in a parent IndexOnlyScan node, or to the scan tlist in
@@ -3332,23 +3338,19 @@ deparse_context_for_plan_rtable(List *rtable, List *rtable_names)
  * for those, we can only deparse the indexqualorig fields, which won't
  * contain INDEX_VAR Vars.)
  *
- * Note: planstate really ought to be declared as "PlanState *", but we use
- * "Node *" to avoid having to include execnodes.h in ruleutils.h.
- *
- * The ancestors list is a list of the PlanState's parent PlanStates, the
- * most-closely-nested first.  This is needed to resolve PARAM_EXEC Params.
- * Note we assume that all the PlanStates share the same rtable.
+ * The ancestors list is a list of the Plan's parent Plan and SubPlan nodes,
+ * the most-closely-nested first.  This is needed to resolve PARAM_EXEC
+ * Params.  Note we assume that all the Plan nodes share the same rtable.
  *
  * Once this function has been called, deparse_expression() can be called on
- * subsidiary expression(s) of the specified PlanState node.  To deparse
+ * subsidiary expression(s) of the specified Plan node.  To deparse
  * expressions of a different Plan node in the same Plan tree, re-call this
  * function to identify the new parent Plan node.
  *
  * The result is the same List passed in; this is a notational convenience.
  */
 List *
-set_deparse_context_planstate(List *dpcontext,
-                              Node *planstate, List *ancestors)
+set_deparse_context_plan(List *dpcontext, Plan *plan, List *ancestors)
 {
     deparse_namespace *dpns;

@@ -3357,7 +3359,7 @@ set_deparse_context_planstate(List *dpcontext,
     dpns = (deparse_namespace *) linitial(dpcontext);

     /* Set our attention on the specific plan node passed in */
-    set_deparse_planstate(dpns, (PlanState *) planstate);
+    set_deparse_plan(dpns, plan);
     dpns->ancestors = ancestors;

     return dpcontext;
@@ -3377,6 +3379,7 @@ select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)

     memset(&dpns, 0, sizeof(dpns));
     dpns.rtable = rtable;
+    dpns.subplans = NIL;
     dpns.ctes = NIL;
     set_rtable_names(&dpns, NIL, rels_used);
     /* We needn't bother computing column aliases yet */
@@ -3557,6 +3560,7 @@ set_deparse_for_query(deparse_namespace *dpns, Query *query,
     /* Initialize *dpns and fill rtable/ctes links */
     memset(dpns, 0, sizeof(deparse_namespace));
     dpns->rtable = query->rtable;
+    dpns->subplans = NIL;
     dpns->ctes = query->cteList;

     /* Assign a unique relation alias to each RTE */
@@ -4625,19 +4629,19 @@ get_rtable_name(int rtindex, deparse_context *context)
 }

 /*
- * set_deparse_planstate: set up deparse_namespace to parse subexpressions
- * of a given PlanState node
+ * set_deparse_plan: set up deparse_namespace to parse subexpressions
+ * of a given Plan node
  *
- * This sets the planstate, outer_planstate, inner_planstate, outer_tlist,
- * inner_tlist, and index_tlist fields.  Caller is responsible for adjusting
- * the ancestors list if necessary.  Note that the rtable and ctes fields do
+ * This sets the plan, outer_plan, inner_plan, outer_tlist, inner_tlist,
+ * and index_tlist fields.  Caller is responsible for adjusting the ancestors
+ * list if necessary.  Note that the rtable, subplans, and ctes fields do
  * not need to change when shifting attention to different plan nodes in a
  * single plan tree.
  */
 static void
-set_deparse_planstate(deparse_namespace *dpns, PlanState *ps)
+set_deparse_plan(deparse_namespace *dpns, Plan *plan)
 {
-    dpns->planstate = ps;
+    dpns->plan = plan;

     /*
      * We special-case Append and MergeAppend to pretend that the first child
@@ -4647,17 +4651,17 @@ set_deparse_planstate(deparse_namespace *dpns, PlanState *ps)
      * first child plan is the OUTER referent; this is to support RETURNING
      * lists containing references to non-target relations.
      */
-    if (IsA(ps, AppendState))
-        dpns->outer_planstate = ((AppendState *) ps)->appendplans[0];
-    else if (IsA(ps, MergeAppendState))
-        dpns->outer_planstate = ((MergeAppendState *) ps)->mergeplans[0];
-    else if (IsA(ps, ModifyTableState))
-        dpns->outer_planstate = ((ModifyTableState *) ps)->mt_plans[0];
+    if (IsA(plan, Append))
+        dpns->outer_plan = linitial(((Append *) plan)->appendplans);
+    else if (IsA(plan, MergeAppend))
+        dpns->outer_plan = linitial(((MergeAppend *) plan)->mergeplans);
+    else if (IsA(plan, ModifyTable))
+        dpns->outer_plan = linitial(((ModifyTable *) plan)->plans);
     else
-        dpns->outer_planstate = outerPlanState(ps);
+        dpns->outer_plan = outerPlan(plan);

-    if (dpns->outer_planstate)
-        dpns->outer_tlist = dpns->outer_planstate->plan->targetlist;
+    if (dpns->outer_plan)
+        dpns->outer_tlist = dpns->outer_plan->targetlist;
     else
         dpns->outer_tlist = NIL;

@@ -4670,29 +4674,30 @@ set_deparse_planstate(deparse_namespace *dpns, PlanState *ps)
      * to reuse OUTER, it's used for RETURNING in some modify table cases,
      * although not INSERT .. CONFLICT).
      */
-    if (IsA(ps, SubqueryScanState))
-        dpns->inner_planstate = ((SubqueryScanState *) ps)->subplan;
-    else if (IsA(ps, CteScanState))
-        dpns->inner_planstate = ((CteScanState *) ps)->cteplanstate;
-    else if (IsA(ps, ModifyTableState))
-        dpns->inner_planstate = ps;
+    if (IsA(plan, SubqueryScan))
+        dpns->inner_plan = ((SubqueryScan *) plan)->subplan;
+    else if (IsA(plan, CteScan))
+        dpns->inner_plan = list_nth(dpns->subplans,
+                                    ((CteScan *) plan)->ctePlanId - 1);
+    else if (IsA(plan, ModifyTable))
+        dpns->inner_plan = plan;
     else
-        dpns->inner_planstate = innerPlanState(ps);
+        dpns->inner_plan = innerPlan(plan);

-    if (IsA(ps, ModifyTableState))
-        dpns->inner_tlist = ((ModifyTableState *) ps)->mt_excludedtlist;
-    else if (dpns->inner_planstate)
-        dpns->inner_tlist = dpns->inner_planstate->plan->targetlist;
+    if (IsA(plan, ModifyTable))
+        dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
+    else if (dpns->inner_plan)
+        dpns->inner_tlist = dpns->inner_plan->targetlist;
     else
         dpns->inner_tlist = NIL;

     /* Set up referent for INDEX_VAR Vars, if needed */
-    if (IsA(ps->plan, IndexOnlyScan))
-        dpns->index_tlist = ((IndexOnlyScan *) ps->plan)->indextlist;
-    else if (IsA(ps->plan, ForeignScan))
-        dpns->index_tlist = ((ForeignScan *) ps->plan)->fdw_scan_tlist;
-    else if (IsA(ps->plan, CustomScan))
-        dpns->index_tlist = ((CustomScan *) ps->plan)->custom_scan_tlist;
+    if (IsA(plan, IndexOnlyScan))
+        dpns->index_tlist = ((IndexOnlyScan *) plan)->indextlist;
+    else if (IsA(plan, ForeignScan))
+        dpns->index_tlist = ((ForeignScan *) plan)->fdw_scan_tlist;
+    else if (IsA(plan, CustomScan))
+        dpns->index_tlist = ((CustomScan *) plan)->custom_scan_tlist;
     else
         dpns->index_tlist = NIL;
 }
@@ -4710,17 +4715,17 @@ set_deparse_planstate(deparse_namespace *dpns, PlanState *ps)
  * previous state for pop_child_plan.
  */
 static void
-push_child_plan(deparse_namespace *dpns, PlanState *ps,
+push_child_plan(deparse_namespace *dpns, Plan *plan,
                 deparse_namespace *save_dpns)
 {
     /* Save state for restoration later */
     *save_dpns = *dpns;

     /* Link current plan node into ancestors list */
-    dpns->ancestors = lcons(dpns->planstate, dpns->ancestors);
+    dpns->ancestors = lcons(dpns->plan, dpns->ancestors);

     /* Set attention on selected child */
-    set_deparse_planstate(dpns, ps);
+    set_deparse_plan(dpns, plan);
 }

 /*
@@ -4760,7 +4765,7 @@ static void
 push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
                    deparse_namespace *save_dpns)
 {
-    PlanState  *ps = (PlanState *) lfirst(ancestor_cell);
+    Plan       *plan = (Plan *) lfirst(ancestor_cell);

     /* Save state for restoration later */
     *save_dpns = *dpns;
@@ -4771,7 +4776,7 @@ push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
                        list_cell_number(dpns->ancestors, ancestor_cell) + 1);

     /* Set attention on selected ancestor */
-    set_deparse_planstate(dpns, ps);
+    set_deparse_plan(dpns, plan);
 }

 /*
@@ -6715,11 +6720,11 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
      * no alias.  So in that case, drill down to the subplan and print the
      * contents of the referenced tlist item.  This works because in a plan
      * tree, such Vars can only occur in a SubqueryScan or CteScan node, and
-     * we'll have set dpns->inner_planstate to reference the child plan node.
+     * we'll have set dpns->inner_plan to reference the child plan node.
      */
     if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) &&
         attnum > list_length(rte->eref->colnames) &&
-        dpns->inner_planstate)
+        dpns->inner_plan)
     {
         TargetEntry *tle;
         deparse_namespace save_dpns;
@@ -6730,7 +6735,7 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
                  var->varattno, rte->eref->aliasname);

         Assert(netlevelsup == 0);
-        push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
+        push_child_plan(dpns, dpns->inner_plan, &save_dpns);

         /*
          * Force parentheses because our caller probably assumed a Var is a
@@ -6880,7 +6885,7 @@ resolve_special_varno(Node *node, deparse_context *context, void *private,
         if (!tle)
             elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);

-        push_child_plan(dpns, dpns->outer_planstate, &save_dpns);
+        push_child_plan(dpns, dpns->outer_plan, &save_dpns);
         resolve_special_varno((Node *) tle->expr, context, private, callback);
         pop_child_plan(dpns, &save_dpns);
         return;
@@ -6894,7 +6899,7 @@ resolve_special_varno(Node *node, deparse_context *context, void *private,
         if (!tle)
             elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);

-        push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
+        push_child_plan(dpns, dpns->inner_plan, &save_dpns);
         resolve_special_varno((Node *) tle->expr, context, private, callback);
         pop_child_plan(dpns, &save_dpns);
         return;
@@ -7022,7 +7027,7 @@ get_name_for_var_field(Var *var, int fieldno,
             elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);

         Assert(netlevelsup == 0);
-        push_child_plan(dpns, dpns->outer_planstate, &save_dpns);
+        push_child_plan(dpns, dpns->outer_plan, &save_dpns);

         result = get_name_for_var_field((Var *) tle->expr, fieldno,
                                         levelsup, context);
@@ -7041,7 +7046,7 @@ get_name_for_var_field(Var *var, int fieldno,
             elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);

         Assert(netlevelsup == 0);
-        push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
+        push_child_plan(dpns, dpns->inner_plan, &save_dpns);

         result = get_name_for_var_field((Var *) tle->expr, fieldno,
                                         levelsup, context);
@@ -7151,7 +7156,7 @@ get_name_for_var_field(Var *var, int fieldno,
                     deparse_namespace save_dpns;
                     const char *result;

-                    if (!dpns->inner_planstate)
+                    if (!dpns->inner_plan)
                         elog(ERROR, "failed to find plan for subquery %s",
                              rte->eref->aliasname);
                     tle = get_tle_by_resno(dpns->inner_tlist, attnum);
@@ -7159,7 +7164,7 @@ get_name_for_var_field(Var *var, int fieldno,
                         elog(ERROR, "bogus varattno for subquery var: %d",
                              attnum);
                     Assert(netlevelsup == 0);
-                    push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
+                    push_child_plan(dpns, dpns->inner_plan, &save_dpns);

                     result = get_name_for_var_field((Var *) tle->expr, fieldno,
                                                     levelsup, context);
@@ -7269,7 +7274,7 @@ get_name_for_var_field(Var *var, int fieldno,
                     deparse_namespace save_dpns;
                     const char *result;

-                    if (!dpns->inner_planstate)
+                    if (!dpns->inner_plan)
                         elog(ERROR, "failed to find plan for CTE %s",
                              rte->eref->aliasname);
                     tle = get_tle_by_resno(dpns->inner_tlist, attnum);
@@ -7277,7 +7282,7 @@ get_name_for_var_field(Var *var, int fieldno,
                         elog(ERROR, "bogus varattno for subquery var: %d",
                              attnum);
                     Assert(netlevelsup == 0);
-                    push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
+                    push_child_plan(dpns, dpns->inner_plan, &save_dpns);

                     result = get_name_for_var_field((Var *) tle->expr, fieldno,
                                                     levelsup, context);
@@ -7318,22 +7323,22 @@ find_param_referent(Param *param, deparse_context *context,
     /*
      * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
      * SubPlan argument.  This will necessarily be in some ancestor of the
-     * current expression's PlanState.
+     * current expression's Plan node.
      */
     if (param->paramkind == PARAM_EXEC)
     {
         deparse_namespace *dpns;
-        PlanState  *child_ps;
+        Plan       *child_plan;
         bool        in_same_plan_level;
         ListCell   *lc;

         dpns = (deparse_namespace *) linitial(context->namespaces);
-        child_ps = dpns->planstate;
+        child_plan = dpns->plan;
         in_same_plan_level = true;

         foreach(lc, dpns->ancestors)
         {
-            PlanState  *ps = (PlanState *) lfirst(lc);
+            Node       *ancestor = (Node *) lfirst(lc);
             ListCell   *lc2;

             /*
@@ -7341,11 +7346,11 @@ find_param_referent(Param *param, deparse_context *context,
              * we've crawled up out of a subplan, this couldn't possibly be
              * the right match.
              */
-            if (IsA(ps, NestLoopState) &&
-                child_ps == innerPlanState(ps) &&
+            if (IsA(ancestor, NestLoop) &&
+                child_plan == innerPlan(ancestor) &&
                 in_same_plan_level)
             {
-                NestLoop   *nl = (NestLoop *) ps->plan;
+                NestLoop   *nl = (NestLoop *) ancestor;

                 foreach(lc2, nl->nestParams)
                 {
@@ -7362,19 +7367,14 @@ find_param_referent(Param *param, deparse_context *context,
             }

             /*
-             * Check to see if we're crawling up from a subplan.
+             * If ancestor is a SubPlan, check the arguments it provides.
              */
-            foreach(lc2, ps->subPlan)
+            if (IsA(ancestor, SubPlan))
             {
-                SubPlanState *sstate = (SubPlanState *) lfirst(lc2);
-                SubPlan    *subplan = sstate->subplan;
+                SubPlan    *subplan = (SubPlan *) ancestor;
                 ListCell   *lc3;
                 ListCell   *lc4;

-                if (child_ps != sstate->planstate)
-                    continue;
-
-                /* Matched subplan, so check its arguments */
                 forboth(lc3, subplan->parParam, lc4, subplan->args)
                 {
                     int            paramid = lfirst_int(lc3);
@@ -7382,41 +7382,61 @@ find_param_referent(Param *param, deparse_context *context,

                     if (paramid == param->paramid)
                     {
-                        /* Found a match, so return it */
-                        *dpns_p = dpns;
-                        *ancestor_cell_p = lc;
-                        return arg;
+                        /*
+                         * Found a match, so return it.  But, since Vars in
+                         * the arg are to be evaluated in the surrounding
+                         * context, we have to point to the next ancestor item
+                         * that is *not* a SubPlan.
+                         */
+                        ListCell   *rest;
+
+                        for_each_cell(rest, dpns->ancestors,
+                                      lnext(dpns->ancestors, lc))
+                        {
+                            Node       *ancestor2 = (Node *) lfirst(rest);
+
+                            if (!IsA(ancestor2, SubPlan))
+                            {
+                                *dpns_p = dpns;
+                                *ancestor_cell_p = rest;
+                                return arg;
+                            }
+                        }
+                        elog(ERROR, "SubPlan cannot be outermost ancestor");
                     }
                 }

-                /* Keep looking, but we are emerging from a subplan. */
+                /* We have emerged from a subplan. */
                 in_same_plan_level = false;
-                break;
+
+                /* SubPlan isn't a kind of Plan, so skip the rest */
+                continue;
             }

             /*
-             * Likewise check to see if we're emerging from an initplan.
-             * Initplans never have any parParams, so no need to search that
-             * list, but we need to know if we should reset
+             * Check to see if we're emerging from an initplan of the current
+             * ancestor plan.  Initplans never have any parParams, so no need
+             * to search that list, but we need to know if we should reset
              * in_same_plan_level.
              */
-            foreach(lc2, ps->initPlan)
+            foreach(lc2, ((Plan *) ancestor)->initPlan)
             {
-                SubPlanState *sstate = (SubPlanState *) lfirst(lc2);
+                SubPlan    *subplan = castNode(SubPlan, lfirst(lc2));

-                if (child_ps != sstate->planstate)
+                if (child_plan != (Plan *) list_nth(dpns->subplans,
+                                                    subplan->plan_id - 1))
                     continue;

                 /* No parameters to be had here. */
-                Assert(sstate->subplan->parParam == NIL);
+                Assert(subplan->parParam == NIL);

-                /* Keep looking, but we are emerging from an initplan. */
+                /* We have emerged from an initplan. */
                 in_same_plan_level = false;
                 break;
             }

             /* No luck, crawl up to next ancestor */
-            child_ps = ps;
+            child_plan = (Plan *) ancestor;
         }
     }

diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 6eb6472..9d1fc18 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1171,7 +1171,6 @@ typedef struct ModifyTableState
     List      **mt_arowmarks;    /* per-subplan ExecAuxRowMark lists */
     EPQState    mt_epqstate;    /* for evaluating EvalPlanQual rechecks */
     bool        fireBSTriggers; /* do we need to fire stmt triggers? */
-    List       *mt_excludedtlist;    /* the excluded pseudo relation's tlist  */

     /*
      * Slot for storing tuples in the root partitioned table's rowtype during
diff --git a/src/include/utils/ruleutils.h b/src/include/utils/ruleutils.h
index d34cad2..ac40890 100644
--- a/src/include/utils/ruleutils.h
+++ b/src/include/utils/ruleutils.h
@@ -17,6 +17,9 @@
 #include "nodes/parsenodes.h"
 #include "nodes/pg_list.h"

+struct Plan;                    /* avoid including plannodes.h here */
+struct PlannedStmt;
+

 extern char *pg_get_indexdef_string(Oid indexrelid);
 extern char *pg_get_indexdef_columns(Oid indexrelid, bool pretty);
@@ -28,9 +31,10 @@ extern char *pg_get_constraintdef_command(Oid constraintId);
 extern char *deparse_expression(Node *expr, List *dpcontext,
                                 bool forceprefix, bool showimplicit);
 extern List *deparse_context_for(const char *aliasname, Oid relid);
-extern List *deparse_context_for_plan_rtable(List *rtable, List *rtable_names);
-extern List *set_deparse_context_planstate(List *dpcontext,
-                                           Node *planstate, List *ancestors);
+extern List *deparse_context_for_plan_tree(struct PlannedStmt *pstmt,
+                                           List *rtable_names);
+extern List *set_deparse_context_plan(List *dpcontext,
+                                      struct Plan *plan, List *ancestors);
 extern List *select_rtable_names_for_explain(List *rtable,
                                              Bitmapset *rels_used);
 extern char *generate_collation_name(Oid collid);
diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out
index f9eeda6..0b4ab0d 100644
--- a/src/test/regress/expected/partition_prune.out
+++ b/src/test/regress/expected/partition_prune.out
@@ -3123,7 +3123,7 @@ explain (analyze, costs off, summary off, timing off) execute mt_q1(15);
                                        QUERY PLAN
 -----------------------------------------------------------------------------------------
  Merge Append (actual rows=2 loops=1)
-   Sort Key: ma_test.b
+   Sort Key: b
    Subplans Removed: 1
    ->  Index Scan using ma_test_p2_b_idx on ma_test_p2 ma_test (actual rows=1 loops=1)
          Filter: ((a >= $1) AND ((a % 10) = 5))
@@ -3144,7 +3144,7 @@ explain (analyze, costs off, summary off, timing off) execute mt_q1(25);
                                       QUERY PLAN
 ---------------------------------------------------------------------------------------
  Merge Append (actual rows=1 loops=1)
-   Sort Key: ma_test.b
+   Sort Key: b
    Subplans Removed: 2
    ->  Index Scan using ma_test_p3_b_idx on ma_test_p3 ma_test (actual rows=1 loops=1)
          Filter: ((a >= $1) AND ((a % 10) = 5))

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Daniel Gustafsson
Дата:
Сообщение: Re: Online checksums patch - once again
Следующее
От: Andrew Gierth
Дата:
Сообщение: Re: Protocol problem with GSSAPI encryption?