Add new function planstate_tree_walker.
authorRobert Haas <[email protected]>
Thu, 17 Sep 2015 15:24:49 +0000 (11:24 -0400)
committerRobert Haas <[email protected]>
Thu, 17 Sep 2015 15:27:06 +0000 (11:27 -0400)
ExplainPreScanNode knows how to iterate over a generic tree of plan
states; factor that logic out into a separate walker function so that
other code, such as upcoming patches for parallel query, can also use
it.

Patch by me, reviewed by Tom Lane.

src/backend/commands/explain.c
src/backend/nodes/nodeFuncs.c
src/include/nodes/nodeFuncs.h

index 4f32400011fe4cfbfb04ce36129e5de1a6fb378b..f0d9e94eed2d19a14a22b43eef935b050212690d 100644 (file)
@@ -55,10 +55,7 @@ static void ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es,
 static void report_triggers(ResultRelInfo *rInfo, bool show_relname,
                                ExplainState *es);
 static double elapsed_time(instr_time *starttime);
-static void ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used);
-static void ExplainPreScanMemberNodes(List *plans, PlanState **planstates,
-                                                 Bitmapset **rels_used);
-static void ExplainPreScanSubPlans(List *plans, Bitmapset **rels_used);
+static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used);
 static void ExplainNode(PlanState *planstate, List *ancestors,
                        const char *relationship, const char *plan_name,
                        ExplainState *es);
@@ -724,7 +721,7 @@ elapsed_time(instr_time *starttime)
  * This ensures that we don't confusingly assign un-suffixed aliases to RTEs
  * that never appear in the EXPLAIN output (such as inheritance parents).
  */
-static void
+static bool
 ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
 {
        Plan       *plan = planstate->plan;
@@ -764,91 +761,7 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
                        break;
        }
 
-       /* initPlan-s */
-       if (planstate->initPlan)
-               ExplainPreScanSubPlans(planstate->initPlan, rels_used);
-
-       /* lefttree */
-       if (outerPlanState(planstate))
-               ExplainPreScanNode(outerPlanState(planstate), rels_used);
-
-       /* righttree */
-       if (innerPlanState(planstate))
-               ExplainPreScanNode(innerPlanState(planstate), rels_used);
-
-       /* special child plans */
-       switch (nodeTag(plan))
-       {
-               case T_ModifyTable:
-                       ExplainPreScanMemberNodes(((ModifyTable *) plan)->plans,
-                                                                 ((ModifyTableState *) planstate)->mt_plans,
-                                                                         rels_used);
-                       break;
-               case T_Append:
-                       ExplainPreScanMemberNodes(((Append *) plan)->appendplans,
-                                                                       ((AppendState *) planstate)->appendplans,
-                                                                         rels_used);
-                       break;
-               case T_MergeAppend:
-                       ExplainPreScanMemberNodes(((MergeAppend *) plan)->mergeplans,
-                                                               ((MergeAppendState *) planstate)->mergeplans,
-                                                                         rels_used);
-                       break;
-               case T_BitmapAnd:
-                       ExplainPreScanMemberNodes(((BitmapAnd *) plan)->bitmapplans,
-                                                                ((BitmapAndState *) planstate)->bitmapplans,
-                                                                         rels_used);
-                       break;
-               case T_BitmapOr:
-                       ExplainPreScanMemberNodes(((BitmapOr *) plan)->bitmapplans,
-                                                                 ((BitmapOrState *) planstate)->bitmapplans,
-                                                                         rels_used);
-                       break;
-               case T_SubqueryScan:
-                       ExplainPreScanNode(((SubqueryScanState *) planstate)->subplan,
-                                                          rels_used);
-                       break;
-               default:
-                       break;
-       }
-
-       /* subPlan-s */
-       if (planstate->subPlan)
-               ExplainPreScanSubPlans(planstate->subPlan, rels_used);
-}
-
-/*
- * Prescan the constituent plans of a ModifyTable, Append, MergeAppend,
- * BitmapAnd, or BitmapOr node.
- *
- * Note: we don't actually need to examine the Plan list members, but
- * we need the list in order to determine the length of the PlanState array.
- */
-static void
-ExplainPreScanMemberNodes(List *plans, PlanState **planstates,
-                                                 Bitmapset **rels_used)
-{
-       int                     nplans = list_length(plans);
-       int                     j;
-
-       for (j = 0; j < nplans; j++)
-               ExplainPreScanNode(planstates[j], rels_used);
-}
-
-/*
- * Prescan a list of SubPlans (or initPlans, which also use SubPlan nodes).
- */
-static void
-ExplainPreScanSubPlans(List *plans, Bitmapset **rels_used)
-{
-       ListCell   *lst;
-
-       foreach(lst, plans)
-       {
-               SubPlanState *sps = (SubPlanState *) lfirst(lst);
-
-               ExplainPreScanNode(sps->planstate, rels_used);
-       }
+       return planstate_tree_walker(planstate, ExplainPreScanNode, rels_used);
 }
 
 /*
index c517dfd9d69c6264ecdd0c4904b8b8337ccea099..4a2447409a9e7c84678e14746c65fdf45eedd036 100644 (file)
@@ -18,6 +18,7 @@
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "nodes/execnodes.h"
 #include "nodes/nodeFuncs.h"
 #include "nodes/relation.h"
 #include "utils/builtins.h"
 
 static bool expression_returns_set_walker(Node *node, void *context);
 static int     leftmostLoc(int loc1, int loc2);
+static bool planstate_walk_subplans(List *plans, bool (*walker) (),
+                                                                                               void *context);
+static bool planstate_walk_members(List *plans, PlanState **planstates,
+                                          bool (*walker) (), void *context);
 
 
 /*
@@ -3412,3 +3417,123 @@ raw_expression_tree_walker(Node *node,
        }
        return false;
 }
+
+/*
+ * planstate_tree_walker --- walk plan state trees
+ *
+ * The walker has already visited the current node, and so we need only
+ * recurse into any sub-nodes it has.
+ */
+bool
+planstate_tree_walker(PlanState *planstate, bool (*walker) (), void *context)
+{
+       Plan       *plan = planstate->plan;
+
+       /* initPlan-s */
+       if (planstate_walk_subplans(planstate->initPlan, walker, context))
+               return true;
+
+       /* lefttree */
+       if (outerPlanState(planstate))
+       {
+               if (walker(outerPlanState(planstate), context))
+                       return true;
+       }
+
+       /* righttree */
+       if (innerPlanState(planstate))
+       {
+               if (walker(innerPlanState(planstate), context))
+                       return true;
+       }
+
+       /* special child plans */
+       switch (nodeTag(plan))
+       {
+               case T_ModifyTable:
+                       if (planstate_walk_members(((ModifyTable *) plan)->plans,
+                                                                 ((ModifyTableState *) planstate)->mt_plans,
+                                                                          walker, context))
+                               return true;
+                       break;
+               case T_Append:
+                       if (planstate_walk_members(((Append *) plan)->appendplans,
+                                                                       ((AppendState *) planstate)->appendplans,
+                                                                          walker, context))
+                               return true;
+                       break;
+               case T_MergeAppend:
+                       if (planstate_walk_members(((MergeAppend *) plan)->mergeplans,
+                                                               ((MergeAppendState *) planstate)->mergeplans,
+                                                                          walker, context))
+                               return true;
+                       break;
+               case T_BitmapAnd:
+                       if (planstate_walk_members(((BitmapAnd *) plan)->bitmapplans,
+                                                                ((BitmapAndState *) planstate)->bitmapplans,
+                                                                          walker, context))
+                               return true;
+                       break;
+               case T_BitmapOr:
+                       if (planstate_walk_members(((BitmapOr *) plan)->bitmapplans,
+                                                                 ((BitmapOrState *) planstate)->bitmapplans,
+                                                                          walker, context))
+                               return true;
+                       break;
+               case T_SubqueryScan:
+                       if (walker(((SubqueryScanState *) planstate)->subplan, context))
+                               return true;
+                       break;
+               default:
+                       break;
+       }
+
+       /* subPlan-s */
+       if (planstate_walk_subplans(planstate->subPlan, walker, context))
+               return true;
+
+       return false;
+}
+
+/*
+ * Walk a list of SubPlans (or initPlans, which also use SubPlan nodes).
+ */
+static bool
+planstate_walk_subplans(List *plans, bool (*walker) (), void *context)
+{
+       ListCell   *lc;
+
+       foreach(lc, plans)
+       {
+               SubPlanState *sps = (SubPlanState *) lfirst(lc);
+
+               Assert(IsA(sps, SubPlanState));
+               if (walker(sps->planstate, context))
+                       return true;
+       }
+
+       return false;
+}
+
+/*
+ * Walk the constituent plans of a ModifyTable, Append, MergeAppend,
+ * BitmapAnd, or BitmapOr node.
+ *
+ * Note: we don't actually need to examine the Plan list members, but
+ * we need the list in order to determine the length of the PlanState array.
+ */
+static bool
+planstate_walk_members(List *plans, PlanState **planstates,
+                                          bool (*walker) (), void *context)
+{
+       int                     nplans = list_length(plans);
+       int                     j;
+
+       for (j = 0; j < nplans; j++)
+       {
+               if (walker(planstates[j], context))
+                       return true;
+       }
+
+       return false;
+}
index 7b1b1d6dca9f4c04907a1a152a13a1eadcb76457..36b5dac0c5a90b2742f1e764fdc9bcb351815a14 100644 (file)
@@ -63,4 +63,8 @@ extern Node *query_or_expression_tree_mutator(Node *node, Node *(*mutator) (),
 extern bool raw_expression_tree_walker(Node *node, bool (*walker) (),
                                                                                                   void *context);
 
+struct PlanState;
+extern bool planstate_tree_walker(struct PlanState *planstate, bool (*walker) (),
+                                                                                         void *context);
+
 #endif   /* NODEFUNCS_H */