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:
parent
293fd7c77e
commit
8dd401aa07
@ -55,10 +55,7 @@ static void ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es,
|
|||||||
static void report_triggers(ResultRelInfo *rInfo, bool show_relname,
|
static void report_triggers(ResultRelInfo *rInfo, bool show_relname,
|
||||||
ExplainState *es);
|
ExplainState *es);
|
||||||
static double elapsed_time(instr_time *starttime);
|
static double elapsed_time(instr_time *starttime);
|
||||||
static void ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used);
|
static bool 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 void ExplainNode(PlanState *planstate, List *ancestors,
|
static void ExplainNode(PlanState *planstate, List *ancestors,
|
||||||
const char *relationship, const char *plan_name,
|
const char *relationship, const char *plan_name,
|
||||||
ExplainState *es);
|
ExplainState *es);
|
||||||
@ -724,7 +721,7 @@ elapsed_time(instr_time *starttime)
|
|||||||
* This ensures that we don't confusingly assign un-suffixed aliases to RTEs
|
* This ensures that we don't confusingly assign un-suffixed aliases to RTEs
|
||||||
* that never appear in the EXPLAIN output (such as inheritance parents).
|
* that never appear in the EXPLAIN output (such as inheritance parents).
|
||||||
*/
|
*/
|
||||||
static void
|
static bool
|
||||||
ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
|
ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
|
||||||
{
|
{
|
||||||
Plan *plan = planstate->plan;
|
Plan *plan = planstate->plan;
|
||||||
@ -764,91 +761,7 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* initPlan-s */
|
return planstate_tree_walker(planstate, ExplainPreScanNode, rels_used);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
|
#include "nodes/execnodes.h"
|
||||||
#include "nodes/nodeFuncs.h"
|
#include "nodes/nodeFuncs.h"
|
||||||
#include "nodes/relation.h"
|
#include "nodes/relation.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
@ -26,6 +27,10 @@
|
|||||||
|
|
||||||
static bool expression_returns_set_walker(Node *node, void *context);
|
static bool expression_returns_set_walker(Node *node, void *context);
|
||||||
static int leftmostLoc(int loc1, int loc2);
|
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;
|
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;
|
||||||
|
}
|
||||||
|
@ -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) (),
|
extern bool raw_expression_tree_walker(Node *node, bool (*walker) (),
|
||||||
void *context);
|
void *context);
|
||||||
|
|
||||||
|
struct PlanState;
|
||||||
|
extern bool planstate_tree_walker(struct PlanState *planstate, bool (*walker) (),
|
||||||
|
void *context);
|
||||||
|
|
||||||
#endif /* NODEFUNCS_H */
|
#endif /* NODEFUNCS_H */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user