diff options
Diffstat (limited to 'src/backend/commands/explain.c')
-rw-r--r-- | src/backend/commands/explain.c | 248 |
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); } } |