aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/explain.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/explain.c')
-rw-r--r--src/backend/commands/explain.c248
1 files changed, 116 insertions, 132 deletions
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index e8dba94e218..c8fa693a60e 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.206 2010/06/10 01:26:30 rhaas Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.207 2010/07/13 20:57:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -54,27 +54,30 @@ static void ExplainOneQuery(Query *query, ExplainState *es,
static void report_triggers(ResultRelInfo *rInfo, bool show_relname,
ExplainState *es);
static double elapsed_time(instr_time *starttime);
-static void ExplainNode(Plan *plan, PlanState *planstate,
- Plan *outer_plan,
+static void ExplainNode(PlanState *planstate, List *ancestors,
const char *relationship, const char *plan_name,
ExplainState *es);
-static void show_plan_tlist(Plan *plan, ExplainState *es);
-static void show_qual(List *qual, const char *qlabel, Plan *plan,
- Plan *outer_plan, bool useprefix, ExplainState *es);
+static void show_plan_tlist(PlanState *planstate, List *ancestors,
+ ExplainState *es);
+static void show_qual(List *qual, const char *qlabel,
+ PlanState *planstate, List *ancestors,
+ bool useprefix, ExplainState *es);
static void show_scan_qual(List *qual, const char *qlabel,
- Plan *scan_plan, Plan *outer_plan,
- ExplainState *es);
-static void show_upper_qual(List *qual, const char *qlabel, Plan *plan,
- ExplainState *es);
-static void show_sort_keys(Plan *sortplan, ExplainState *es);
+ PlanState *planstate, List *ancestors,
+ ExplainState *es);
+static void show_upper_qual(List *qual, const char *qlabel,
+ PlanState *planstate, List *ancestors,
+ ExplainState *es);
+static void show_sort_keys(SortState *sortstate, List *ancestors,
+ ExplainState *es);
static void show_sort_info(SortState *sortstate, ExplainState *es);
static void show_hash_info(HashState *hashstate, ExplainState *es);
static const char *explain_get_index_name(Oid indexId);
static void ExplainScanTarget(Scan *plan, ExplainState *es);
-static void ExplainMemberNodes(List *plans, PlanState **planstate,
- Plan *outer_plan, ExplainState *es);
-static void ExplainSubPlans(List *plans, const char *relationship,
- ExplainState *es);
+static void ExplainMemberNodes(List *plans, PlanState **planstates,
+ List *ancestors, ExplainState *es);
+static void ExplainSubPlans(List *plans, List *ancestors,
+ const char *relationship, ExplainState *es);
static void ExplainPropertyList(const char *qlabel, List *data,
ExplainState *es);
static void ExplainProperty(const char *qlabel, const char *value,
@@ -484,8 +487,7 @@ ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
Assert(queryDesc->plannedstmt != NULL);
es->pstmt = queryDesc->plannedstmt;
es->rtable = queryDesc->plannedstmt->rtable;
- ExplainNode(queryDesc->plannedstmt->planTree, queryDesc->planstate,
- NULL, NULL, NULL, es);
+ ExplainNode(queryDesc->planstate, NIL, NULL, NULL, es);
}
/*
@@ -585,31 +587,30 @@ elapsed_time(instr_time *starttime)
/*
* ExplainNode -
- * Appends a description of the Plan node to es->str
+ * Appends a description of a plan tree to es->str
*
- * planstate points to the executor state node corresponding to the plan node.
- * We need this to get at the instrumentation data (if any) as well as the
- * list of subplans.
+ * planstate points to the executor state node for the current plan node.
+ * 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.
*
- * outer_plan, if not null, references another plan node that is the outer
- * side of a join with the current node. This is only interesting for
- * deciphering runtime keys of an inner indexscan.
+ * ancestors is a list of parent PlanState 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
* optional name to be attached to the node.
*
* In text format, es->indent is controlled in this function since we only
- * want it to change at Plan-node boundaries. In non-text formats, es->indent
+ * want it to change at plan-node boundaries. In non-text formats, es->indent
* corresponds to the nesting depth of logical output groups, and therefore
* is controlled by ExplainOpenGroup/ExplainCloseGroup.
*/
static void
-ExplainNode(Plan *plan, PlanState *planstate,
- Plan *outer_plan,
+ExplainNode(PlanState *planstate, List *ancestors,
const char *relationship, const char *plan_name,
ExplainState *es)
{
+ Plan *plan = planstate->plan;
const char *pname; /* node type name for text output */
const char *sname; /* node type name for non-text output */
const char *strategy = NULL;
@@ -617,8 +618,6 @@ ExplainNode(Plan *plan, PlanState *planstate,
int save_indent = es->indent;
bool haschildren;
- Assert(plan);
-
switch (nodeTag(plan))
{
case T_Result:
@@ -999,23 +998,23 @@ ExplainNode(Plan *plan, PlanState *planstate,
/* target list */
if (es->verbose)
- show_plan_tlist(plan, es);
+ show_plan_tlist(planstate, ancestors, es);
/* quals, sort keys, etc */
switch (nodeTag(plan))
{
case T_IndexScan:
show_scan_qual(((IndexScan *) plan)->indexqualorig,
- "Index Cond", plan, outer_plan, es);
- show_scan_qual(plan->qual, "Filter", plan, outer_plan, es);
+ "Index Cond", planstate, ancestors, es);
+ show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
break;
case T_BitmapIndexScan:
show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig,
- "Index Cond", plan, outer_plan, es);
+ "Index Cond", planstate, ancestors, es);
break;
case T_BitmapHeapScan:
show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig,
- "Recheck Cond", plan, outer_plan, es);
+ "Recheck Cond", planstate, ancestors, es);
/* FALL THRU */
case T_SeqScan:
case T_FunctionScan:
@@ -1023,7 +1022,7 @@ ExplainNode(Plan *plan, PlanState *planstate,
case T_CteScan:
case T_WorkTableScan:
case T_SubqueryScan:
- show_scan_qual(plan->qual, "Filter", plan, outer_plan, es);
+ show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
break;
case T_TidScan:
{
@@ -1035,41 +1034,41 @@ ExplainNode(Plan *plan, PlanState *planstate,
if (list_length(tidquals) > 1)
tidquals = list_make1(make_orclause(tidquals));
- show_scan_qual(tidquals, "TID Cond", plan, outer_plan, es);
- show_scan_qual(plan->qual, "Filter", plan, outer_plan, es);
+ show_scan_qual(tidquals, "TID Cond", planstate, ancestors, es);
+ show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
}
break;
case T_NestLoop:
show_upper_qual(((NestLoop *) plan)->join.joinqual,
- "Join Filter", plan, es);
- show_upper_qual(plan->qual, "Filter", plan, es);
+ "Join Filter", planstate, ancestors, es);
+ show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
break;
case T_MergeJoin:
show_upper_qual(((MergeJoin *) plan)->mergeclauses,
- "Merge Cond", plan, es);
+ "Merge Cond", planstate, ancestors, es);
show_upper_qual(((MergeJoin *) plan)->join.joinqual,
- "Join Filter", plan, es);
- show_upper_qual(plan->qual, "Filter", plan, es);
+ "Join Filter", planstate, ancestors, es);
+ show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
break;
case T_HashJoin:
show_upper_qual(((HashJoin *) plan)->hashclauses,
- "Hash Cond", plan, es);
+ "Hash Cond", planstate, ancestors, es);
show_upper_qual(((HashJoin *) plan)->join.joinqual,
- "Join Filter", plan, es);
- show_upper_qual(plan->qual, "Filter", plan, es);
+ "Join Filter", planstate, ancestors, es);
+ show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
break;
case T_Agg:
case T_Group:
- show_upper_qual(plan->qual, "Filter", plan, es);
+ show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
break;
case T_Sort:
- show_sort_keys(plan, es);
+ show_sort_keys((SortState *) planstate, ancestors, es);
show_sort_info((SortState *) planstate, es);
break;
case T_Result:
show_upper_qual((List *) ((Result *) plan)->resconstantqual,
- "One-Time Filter", plan, es);
- show_upper_qual(plan->qual, "Filter", plan, es);
+ "One-Time Filter", planstate, ancestors, es);
+ show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
break;
case T_Hash:
show_hash_info((HashState *) planstate, es);
@@ -1157,9 +1156,9 @@ ExplainNode(Plan *plan, PlanState *planstate,
}
/* Get ready to display the child plans */
- haschildren = plan->initPlan ||
- outerPlan(plan) ||
- innerPlan(plan) ||
+ haschildren = planstate->initPlan ||
+ outerPlanState(planstate) ||
+ innerPlanState(planstate) ||
IsA(plan, ModifyTable) ||
IsA(plan, Append) ||
IsA(plan, BitmapAnd) ||
@@ -1167,32 +1166,25 @@ ExplainNode(Plan *plan, PlanState *planstate,
IsA(plan, SubqueryScan) ||
planstate->subPlan;
if (haschildren)
+ {
ExplainOpenGroup("Plans", "Plans", false, es);
+ /* Pass current PlanState as head of ancestors list for children */
+ ancestors = lcons(planstate, ancestors);
+ }
/* initPlan-s */
- if (plan->initPlan)
- ExplainSubPlans(planstate->initPlan, "InitPlan", es);
+ if (planstate->initPlan)
+ ExplainSubPlans(planstate->initPlan, ancestors, "InitPlan", es);
/* lefttree */
- if (outerPlan(plan))
- {
- /*
- * Ordinarily we don't pass down our own outer_plan value to our child
- * nodes, but in bitmap scan trees we must, since the bottom
- * BitmapIndexScan nodes may have outer references.
- */
- ExplainNode(outerPlan(plan), outerPlanState(planstate),
- IsA(plan, BitmapHeapScan) ? outer_plan : NULL,
+ if (outerPlanState(planstate))
+ ExplainNode(outerPlanState(planstate), ancestors,
"Outer", NULL, es);
- }
/* righttree */
- if (innerPlan(plan))
- {
- ExplainNode(innerPlan(plan), innerPlanState(planstate),
- outerPlan(plan),
+ if (innerPlanState(planstate))
+ ExplainNode(innerPlanState(planstate), ancestors,
"Inner", NULL, es);
- }
/* special child plans */
switch (nodeTag(plan))
@@ -1200,32 +1192,26 @@ ExplainNode(Plan *plan, PlanState *planstate,
case T_ModifyTable:
ExplainMemberNodes(((ModifyTable *) plan)->plans,
((ModifyTableState *) planstate)->mt_plans,
- outer_plan, es);
+ ancestors, es);
break;
case T_Append:
ExplainMemberNodes(((Append *) plan)->appendplans,
((AppendState *) planstate)->appendplans,
- outer_plan, es);
+ ancestors, es);
break;
case T_BitmapAnd:
ExplainMemberNodes(((BitmapAnd *) plan)->bitmapplans,
((BitmapAndState *) planstate)->bitmapplans,
- outer_plan, es);
+ ancestors, es);
break;
case T_BitmapOr:
ExplainMemberNodes(((BitmapOr *) plan)->bitmapplans,
((BitmapOrState *) planstate)->bitmapplans,
- outer_plan, es);
+ ancestors, es);
break;
case T_SubqueryScan:
- {
- SubqueryScan *subqueryscan = (SubqueryScan *) plan;
- SubqueryScanState *subquerystate = (SubqueryScanState *) planstate;
-
- ExplainNode(subqueryscan->subplan, subquerystate->subplan,
- NULL,
- "Subquery", NULL, es);
- }
+ ExplainNode(((SubqueryScanState *) planstate)->subplan, ancestors,
+ "Subquery", NULL, es);
break;
default:
break;
@@ -1233,11 +1219,14 @@ ExplainNode(Plan *plan, PlanState *planstate,
/* subPlan-s */
if (planstate->subPlan)
- ExplainSubPlans(planstate->subPlan, "SubPlan", es);
+ ExplainSubPlans(planstate->subPlan, ancestors, "SubPlan", es);
/* end of child plans */
if (haschildren)
+ {
+ ancestors = list_delete_first(ancestors);
ExplainCloseGroup("Plans", "Plans", false, es);
+ }
/* in text format, undo whatever indentation we added */
if (es->format == EXPLAIN_FORMAT_TEXT)
@@ -1252,8 +1241,9 @@ ExplainNode(Plan *plan, PlanState *planstate,
* Show the targetlist of a plan node
*/
static void
-show_plan_tlist(Plan *plan, ExplainState *es)
+show_plan_tlist(PlanState *planstate, List *ancestors, ExplainState *es)
{
+ Plan *plan = planstate->plan;
List *context;
List *result = NIL;
bool useprefix;
@@ -1271,10 +1261,9 @@ show_plan_tlist(Plan *plan, ExplainState *es)
return;
/* Set up deparsing context */
- context = deparse_context_for_plan((Node *) plan,
- NULL,
- es->rtable,
- es->pstmt->subplans);
+ context = deparse_context_for_planstate((Node *) planstate,
+ ancestors,
+ es->rtable);
useprefix = list_length(es->rtable) > 1;
/* Deparse each result column (we now include resjunk ones) */
@@ -1294,12 +1283,10 @@ show_plan_tlist(Plan *plan, ExplainState *es)
/*
* Show a qualifier expression
- *
- * Note: outer_plan is the referent for any OUTER vars in the scan qual;
- * this would be the outer side of a nestloop plan. Pass NULL if none.
*/
static void
-show_qual(List *qual, const char *qlabel, Plan *plan, Plan *outer_plan,
+show_qual(List *qual, const char *qlabel,
+ PlanState *planstate, List *ancestors,
bool useprefix, ExplainState *es)
{
List *context;
@@ -1314,10 +1301,9 @@ show_qual(List *qual, const char *qlabel, Plan *plan, Plan *outer_plan,
node = (Node *) make_ands_explicit(qual);
/* Set up deparsing context */
- context = deparse_context_for_plan((Node *) plan,
- (Node *) outer_plan,
- es->rtable,
- es->pstmt->subplans);
+ context = deparse_context_for_planstate((Node *) planstate,
+ ancestors,
+ es->rtable);
/* Deparse the expression */
exprstr = deparse_expression(node, context, useprefix, false);
@@ -1331,36 +1317,38 @@ show_qual(List *qual, const char *qlabel, Plan *plan, Plan *outer_plan,
*/
static void
show_scan_qual(List *qual, const char *qlabel,
- Plan *scan_plan, Plan *outer_plan,
+ PlanState *planstate, List *ancestors,
ExplainState *es)
{
bool useprefix;
- useprefix = (outer_plan != NULL || IsA(scan_plan, SubqueryScan) ||
- es->verbose);
- show_qual(qual, qlabel, scan_plan, outer_plan, useprefix, es);
+ useprefix = (IsA(planstate->plan, SubqueryScan) || es->verbose);
+ show_qual(qual, qlabel, planstate, ancestors, useprefix, es);
}
/*
* Show a qualifier expression for an upper-level plan node
*/
static void
-show_upper_qual(List *qual, const char *qlabel, Plan *plan, ExplainState *es)
+show_upper_qual(List *qual, const char *qlabel,
+ PlanState *planstate, List *ancestors,
+ ExplainState *es)
{
bool useprefix;
useprefix = (list_length(es->rtable) > 1 || es->verbose);
- show_qual(qual, qlabel, plan, NULL, useprefix, es);
+ show_qual(qual, qlabel, planstate, ancestors, useprefix, es);
}
/*
* Show the sort keys for a Sort node.
*/
static void
-show_sort_keys(Plan *sortplan, ExplainState *es)
+show_sort_keys(SortState *sortstate, List *ancestors, ExplainState *es)
{
- int nkeys = ((Sort *) sortplan)->numCols;
- AttrNumber *keycols = ((Sort *) sortplan)->sortColIdx;
+ Sort *plan = (Sort *) sortstate->ss.ps.plan;
+ int nkeys = plan->numCols;
+ AttrNumber *keycols = plan->sortColIdx;
List *context;
List *result = NIL;
bool useprefix;
@@ -1371,17 +1359,17 @@ show_sort_keys(Plan *sortplan, ExplainState *es)
return;
/* Set up deparsing context */
- context = deparse_context_for_plan((Node *) sortplan,
- NULL,
- es->rtable,
- es->pstmt->subplans);
+ context = deparse_context_for_planstate((Node *) sortstate,
+ ancestors,
+ es->rtable);
useprefix = (list_length(es->rtable) > 1 || es->verbose);
for (keyno = 0; keyno < nkeys; keyno++)
{
/* find key expression in tlist */
AttrNumber keyresno = keycols[keyno];
- TargetEntry *target = get_tle_by_resno(sortplan->targetlist, keyresno);
+ TargetEntry *target = get_tle_by_resno(plan->plan.targetlist,
+ keyresno);
if (!target)
elog(ERROR, "no tlist entry for key %d", keyresno);
@@ -1596,34 +1584,33 @@ ExplainScanTarget(Scan *plan, ExplainState *es)
* Explain the constituent plans of a ModifyTable, Append, BitmapAnd,
* or BitmapOr node.
*
- * Ordinarily we don't pass down outer_plan to our child nodes, but in these
- * cases we must, since the node could be an "inner indexscan" in which case
- * outer references can appear in the child nodes.
+ * The ancestors list should already contain the immediate parent of these
+ * plans.
+ *
+ * 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
-ExplainMemberNodes(List *plans, PlanState **planstate, Plan *outer_plan,
- ExplainState *es)
+ExplainMemberNodes(List *plans, PlanState **planstates,
+ List *ancestors, ExplainState *es)
{
- ListCell *lst;
- int j = 0;
-
- foreach(lst, plans)
- {
- Plan *subnode = (Plan *) lfirst(lst);
+ int nplans = list_length(plans);
+ int j;
- ExplainNode(subnode, planstate[j],
- outer_plan,
- "Member", NULL,
- es);
- j++;
- }
+ for (j = 0; j < nplans; j++)
+ ExplainNode(planstates[j], ancestors,
+ "Member", NULL, es);
}
/*
* Explain a list of SubPlans (or initPlans, which also use SubPlan nodes).
+ *
+ * The ancestors list should already contain the immediate parent of these
+ * SubPlanStates.
*/
static void
-ExplainSubPlans(List *plans, const char *relationship, ExplainState *es)
+ExplainSubPlans(List *plans, List *ancestors,
+ const char *relationship, ExplainState *es)
{
ListCell *lst;
@@ -1632,11 +1619,8 @@ ExplainSubPlans(List *plans, const char *relationship, ExplainState *es)
SubPlanState *sps = (SubPlanState *) lfirst(lst);
SubPlan *sp = (SubPlan *) sps->xprstate.expr;
- ExplainNode(exec_subplan_get_plan(es->pstmt, sp),
- sps->planstate,
- NULL,
- relationship, sp->plan_name,
- es);
+ ExplainNode(sps->planstate, ancestors,
+ relationship, sp->plan_name, es);
}
}