1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-26 12:21:12 +03:00

Add new function planstate_tree_walker.

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.
This commit is contained in:
Robert Haas
2015-09-17 11:24:49 -04:00
parent 293fd7c77e
commit 8dd401aa07
3 changed files with 132 additions and 90 deletions

View 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"
@ -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;
}