diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 4f32400011..f0d9e94eed 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -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); } /* diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index c517dfd9d6..4a2447409a 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -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" @@ -26,6 +27,10 @@ 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; +} diff --git a/src/include/nodes/nodeFuncs.h b/src/include/nodes/nodeFuncs.h index 7b1b1d6dca..36b5dac0c5 100644 --- a/src/include/nodes/nodeFuncs.h +++ b/src/include/nodes/nodeFuncs.h @@ -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 */