diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2007-02-23 21:59:45 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2007-02-23 21:59:45 +0000 |
commit | 655aa5b33026182f13b141a8ae4009bc7583b508 (patch) | |
tree | b1d548e8326f6d1bb61251da716d8f5809460292 /src/backend/commands/explain.c | |
parent | 9cc2a71c3818f9670be989435c2021af407e87ce (diff) | |
download | postgresql-655aa5b33026182f13b141a8ae4009bc7583b508.tar.gz postgresql-655aa5b33026182f13b141a8ae4009bc7583b508.zip |
Now that plans have flat rangetable lists, it's a lot easier to get EXPLAIN to
drill down into subplan targetlists to print the referent expression for an
OUTER or INNER var in an upper plan node. Hence, make it do that always, and
banish the old hack of showing "?columnN?" when things got too complicated.
Along the way, fix an EXPLAIN bug I introduced by suppressing subqueries from
execution-time range tables: get_name_for_var_field() assumed it could look at
rte->subquery to find out the real type of a RECORD var. That doesn't work
anymore, but instead we can look at the input plan of the SubqueryScan plan
node.
Diffstat (limited to 'src/backend/commands/explain.c')
-rw-r--r-- | src/backend/commands/explain.c | 181 |
1 files changed, 51 insertions, 130 deletions
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 6a97b01ec3c..835b1ef6ade 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.158 2007/02/22 23:44:24 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.159 2007/02/23 21:59:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -49,11 +49,9 @@ static void explain_outNode(StringInfo str, Plan *outer_plan, int indent, ExplainState *es); static void show_scan_qual(List *qual, const char *qlabel, - int scanrelid, Plan *outer_plan, + int scanrelid, Plan *outer_plan, Plan *inner_plan, StringInfo str, int indent, ExplainState *es); -static void show_upper_qual(List *qual, const char *qlabel, - const char *outer_name, Plan *outer_plan, - const char *inner_name, Plan *inner_plan, +static void show_upper_qual(List *qual, const char *qlabel, Plan *plan, StringInfo str, int indent, ExplainState *es); static void show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols, const char *qlabel, @@ -725,19 +723,19 @@ explain_outNode(StringInfo str, show_scan_qual(((IndexScan *) plan)->indexqualorig, "Index Cond", ((Scan *) plan)->scanrelid, - outer_plan, + outer_plan, NULL, str, indent, es); show_scan_qual(plan->qual, "Filter", ((Scan *) plan)->scanrelid, - outer_plan, + outer_plan, NULL, str, indent, es); break; case T_BitmapIndexScan: show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig, "Index Cond", ((Scan *) plan)->scanrelid, - outer_plan, + outer_plan, NULL, str, indent, es); break; case T_BitmapHeapScan: @@ -745,17 +743,24 @@ explain_outNode(StringInfo str, show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig, "Recheck Cond", ((Scan *) plan)->scanrelid, - outer_plan, + outer_plan, NULL, str, indent, es); /* FALL THRU */ case T_SeqScan: - case T_SubqueryScan: case T_FunctionScan: case T_ValuesScan: show_scan_qual(plan->qual, "Filter", ((Scan *) plan)->scanrelid, + outer_plan, NULL, + str, indent, es); + break; + case T_SubqueryScan: + show_scan_qual(plan->qual, + "Filter", + ((Scan *) plan)->scanrelid, outer_plan, + ((SubqueryScan *) plan)->subplan, str, indent, es); break; case T_TidScan: @@ -771,67 +776,49 @@ explain_outNode(StringInfo str, show_scan_qual(tidquals, "TID Cond", ((Scan *) plan)->scanrelid, - outer_plan, + outer_plan, NULL, str, indent, es); show_scan_qual(plan->qual, "Filter", ((Scan *) plan)->scanrelid, - outer_plan, + outer_plan, NULL, str, indent, es); } break; case T_NestLoop: show_upper_qual(((NestLoop *) plan)->join.joinqual, - "Join Filter", - "outer", outerPlan(plan), - "inner", innerPlan(plan), + "Join Filter", plan, str, indent, es); show_upper_qual(plan->qual, - "Filter", - "outer", outerPlan(plan), - "inner", innerPlan(plan), + "Filter", plan, str, indent, es); break; case T_MergeJoin: show_upper_qual(((MergeJoin *) plan)->mergeclauses, - "Merge Cond", - "outer", outerPlan(plan), - "inner", innerPlan(plan), + "Merge Cond", plan, str, indent, es); show_upper_qual(((MergeJoin *) plan)->join.joinqual, - "Join Filter", - "outer", outerPlan(plan), - "inner", innerPlan(plan), + "Join Filter", plan, str, indent, es); show_upper_qual(plan->qual, - "Filter", - "outer", outerPlan(plan), - "inner", innerPlan(plan), + "Filter", plan, str, indent, es); break; case T_HashJoin: show_upper_qual(((HashJoin *) plan)->hashclauses, - "Hash Cond", - "outer", outerPlan(plan), - "inner", innerPlan(plan), + "Hash Cond", plan, str, indent, es); show_upper_qual(((HashJoin *) plan)->join.joinqual, - "Join Filter", - "outer", outerPlan(plan), - "inner", innerPlan(plan), + "Join Filter", plan, str, indent, es); show_upper_qual(plan->qual, - "Filter", - "outer", outerPlan(plan), - "inner", innerPlan(plan), + "Filter", plan, str, indent, es); break; case T_Agg: case T_Group: show_upper_qual(plan->qual, - "Filter", - "subplan", outerPlan(plan), - "", NULL, + "Filter", plan, str, indent, es); break; case T_Sort: @@ -843,14 +830,10 @@ explain_outNode(StringInfo str, break; case T_Result: show_upper_qual((List *) ((Result *) plan)->resconstantqual, - "One-Time Filter", - "subplan", outerPlan(plan), - "", NULL, + "One-Time Filter", plan, str, indent, es); show_upper_qual(plan->qual, - "Filter", - "subplan", outerPlan(plan), - "", NULL, + "Filter", plan, str, indent, es); break; default: @@ -1032,14 +1015,18 @@ explain_outNode(StringInfo str, /* * Show a qualifier expression for a scan plan node + * + * Note: outer_plan is the referent for any OUTER vars in the scan qual; + * this would be the outer side of a nestloop plan. inner_plan should be + * NULL except for a SubqueryScan plan node, where it should be the subplan. */ static void show_scan_qual(List *qual, const char *qlabel, - int scanrelid, Plan *outer_plan, + int scanrelid, Plan *outer_plan, Plan *inner_plan, StringInfo str, int indent, ExplainState *es) { - Node *outercontext; List *context; + bool useprefix; Node *node; char *exprstr; int i; @@ -1051,31 +1038,14 @@ show_scan_qual(List *qual, const char *qlabel, /* Convert AND list to explicit AND */ node = (Node *) make_ands_explicit(qual); - /* - * If we have an outer plan that is referenced by the qual, add it to the - * deparse context. If not, don't (so that we don't force prefixes - * unnecessarily). - */ - if (outer_plan) - { - Relids varnos = pull_varnos(node); - - if (bms_is_member(OUTER, varnos)) - outercontext = deparse_context_for_subplan("outer", - (Node *) outer_plan); - else - outercontext = NULL; - bms_free(varnos); - } - else - outercontext = NULL; - - context = deparse_context_for_plan(OUTER, outercontext, - 0, NULL, + /* Set up deparsing context */ + context = deparse_context_for_plan((Node *) outer_plan, + (Node *) inner_plan, es->rtable); + useprefix = (outer_plan != NULL || inner_plan != NULL); /* Deparse the expression */ - exprstr = deparse_expression(node, context, (outercontext != NULL), false); + exprstr = deparse_expression(node, context, useprefix, false); /* And add to str */ for (i = 0; i < indent; i++) @@ -1087,16 +1057,11 @@ show_scan_qual(List *qual, const char *qlabel, * Show a qualifier expression for an upper-level plan node */ static void -show_upper_qual(List *qual, const char *qlabel, - const char *outer_name, Plan *outer_plan, - const char *inner_name, Plan *inner_plan, +show_upper_qual(List *qual, const char *qlabel, Plan *plan, StringInfo str, int indent, ExplainState *es) { List *context; - Node *outercontext; - Node *innercontext; - int outer_varno; - int inner_varno; + bool useprefix; Node *node; char *exprstr; int i; @@ -1105,36 +1070,15 @@ show_upper_qual(List *qual, const char *qlabel, if (qual == NIL) return; - /* Generate deparse context */ - if (outer_plan) - { - outercontext = deparse_context_for_subplan(outer_name, - (Node *) outer_plan); - outer_varno = OUTER; - } - else - { - outercontext = NULL; - outer_varno = 0; - } - if (inner_plan) - { - innercontext = deparse_context_for_subplan(inner_name, - (Node *) inner_plan); - inner_varno = INNER; - } - else - { - innercontext = NULL; - inner_varno = 0; - } - context = deparse_context_for_plan(outer_varno, outercontext, - inner_varno, innercontext, + /* Set up deparsing context */ + context = deparse_context_for_plan((Node *) outerPlan(plan), + (Node *) innerPlan(plan), es->rtable); + useprefix = list_length(es->rtable) > 1; /* Deparse the expression */ node = (Node *) make_ands_explicit(qual); - exprstr = deparse_expression(node, context, (inner_plan != NULL), false); + exprstr = deparse_expression(node, context, useprefix, false); /* And add to str */ for (i = 0; i < indent; i++) @@ -1154,7 +1098,6 @@ show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols, bool useprefix; int keyno; char *exprstr; - Relids varnos; int i; if (nkeys <= 0) @@ -1164,33 +1107,11 @@ show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols, appendStringInfo(str, " "); appendStringInfo(str, " %s: ", qlabel); - /* - * In this routine we expect that the plan node's tlist has not been - * processed by set_plan_references(). Normally, any Vars will contain - * valid varnos referencing the actual rtable. But we might instead be - * looking at a dummy tlist generated by prepunion.c; if there are Vars - * with zero varno, use the tlist itself to determine their names. - */ - varnos = pull_varnos((Node *) sortplan->targetlist); - if (bms_is_member(0, varnos)) - { - Node *outercontext; - - outercontext = deparse_context_for_subplan("sort", - (Node *) sortplan); - context = deparse_context_for_plan(0, outercontext, - 0, NULL, - es->rtable); - useprefix = false; - } - else - { - context = deparse_context_for_plan(0, NULL, - 0, NULL, - es->rtable); - useprefix = list_length(es->rtable) > 1; - } - bms_free(varnos); + /* Set up deparsing context */ + context = deparse_context_for_plan((Node *) outerPlan(sortplan), + NULL, /* Sort has no innerPlan */ + es->rtable); + useprefix = list_length(es->rtable) > 1; for (keyno = 0; keyno < nkeys; keyno++) { |