Commit 655aa5b3 authored by Tom Lane's avatar Tom Lane

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.
parent 9cc2a71c
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California * Portions Copyright (c) 1994-5, Regents of the University of California
* *
* IDENTIFICATION * 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, ...@@ -49,11 +49,9 @@ static void explain_outNode(StringInfo str,
Plan *outer_plan, Plan *outer_plan,
int indent, ExplainState *es); int indent, ExplainState *es);
static void show_scan_qual(List *qual, const char *qlabel, 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); StringInfo str, int indent, ExplainState *es);
static void show_upper_qual(List *qual, const char *qlabel, static void show_upper_qual(List *qual, const char *qlabel, Plan *plan,
const char *outer_name, Plan *outer_plan,
const char *inner_name, Plan *inner_plan,
StringInfo str, int indent, ExplainState *es); StringInfo str, int indent, ExplainState *es);
static void show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols, static void show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
const char *qlabel, const char *qlabel,
...@@ -725,19 +723,19 @@ explain_outNode(StringInfo str, ...@@ -725,19 +723,19 @@ explain_outNode(StringInfo str,
show_scan_qual(((IndexScan *) plan)->indexqualorig, show_scan_qual(((IndexScan *) plan)->indexqualorig,
"Index Cond", "Index Cond",
((Scan *) plan)->scanrelid, ((Scan *) plan)->scanrelid,
outer_plan, outer_plan, NULL,
str, indent, es); str, indent, es);
show_scan_qual(plan->qual, show_scan_qual(plan->qual,
"Filter", "Filter",
((Scan *) plan)->scanrelid, ((Scan *) plan)->scanrelid,
outer_plan, outer_plan, NULL,
str, indent, es); str, indent, es);
break; break;
case T_BitmapIndexScan: case T_BitmapIndexScan:
show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig, show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig,
"Index Cond", "Index Cond",
((Scan *) plan)->scanrelid, ((Scan *) plan)->scanrelid,
outer_plan, outer_plan, NULL,
str, indent, es); str, indent, es);
break; break;
case T_BitmapHeapScan: case T_BitmapHeapScan:
...@@ -745,17 +743,24 @@ explain_outNode(StringInfo str, ...@@ -745,17 +743,24 @@ explain_outNode(StringInfo str,
show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig, show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig,
"Recheck Cond", "Recheck Cond",
((Scan *) plan)->scanrelid, ((Scan *) plan)->scanrelid,
outer_plan, outer_plan, NULL,
str, indent, es); str, indent, es);
/* FALL THRU */ /* FALL THRU */
case T_SeqScan: case T_SeqScan:
case T_SubqueryScan:
case T_FunctionScan: case T_FunctionScan:
case T_ValuesScan: 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, show_scan_qual(plan->qual,
"Filter", "Filter",
((Scan *) plan)->scanrelid, ((Scan *) plan)->scanrelid,
outer_plan, outer_plan,
((SubqueryScan *) plan)->subplan,
str, indent, es); str, indent, es);
break; break;
case T_TidScan: case T_TidScan:
...@@ -771,67 +776,49 @@ explain_outNode(StringInfo str, ...@@ -771,67 +776,49 @@ explain_outNode(StringInfo str,
show_scan_qual(tidquals, show_scan_qual(tidquals,
"TID Cond", "TID Cond",
((Scan *) plan)->scanrelid, ((Scan *) plan)->scanrelid,
outer_plan, outer_plan, NULL,
str, indent, es); str, indent, es);
show_scan_qual(plan->qual, show_scan_qual(plan->qual,
"Filter", "Filter",
((Scan *) plan)->scanrelid, ((Scan *) plan)->scanrelid,
outer_plan, outer_plan, NULL,
str, indent, es); str, indent, es);
} }
break; break;
case T_NestLoop: case T_NestLoop:
show_upper_qual(((NestLoop *) plan)->join.joinqual, show_upper_qual(((NestLoop *) plan)->join.joinqual,
"Join Filter", "Join Filter", plan,
"outer", outerPlan(plan),
"inner", innerPlan(plan),
str, indent, es); str, indent, es);
show_upper_qual(plan->qual, show_upper_qual(plan->qual,
"Filter", "Filter", plan,
"outer", outerPlan(plan),
"inner", innerPlan(plan),
str, indent, es); str, indent, es);
break; break;
case T_MergeJoin: case T_MergeJoin:
show_upper_qual(((MergeJoin *) plan)->mergeclauses, show_upper_qual(((MergeJoin *) plan)->mergeclauses,
"Merge Cond", "Merge Cond", plan,
"outer", outerPlan(plan),
"inner", innerPlan(plan),
str, indent, es); str, indent, es);
show_upper_qual(((MergeJoin *) plan)->join.joinqual, show_upper_qual(((MergeJoin *) plan)->join.joinqual,
"Join Filter", "Join Filter", plan,
"outer", outerPlan(plan),
"inner", innerPlan(plan),
str, indent, es); str, indent, es);
show_upper_qual(plan->qual, show_upper_qual(plan->qual,
"Filter", "Filter", plan,
"outer", outerPlan(plan),
"inner", innerPlan(plan),
str, indent, es); str, indent, es);
break; break;
case T_HashJoin: case T_HashJoin:
show_upper_qual(((HashJoin *) plan)->hashclauses, show_upper_qual(((HashJoin *) plan)->hashclauses,
"Hash Cond", "Hash Cond", plan,
"outer", outerPlan(plan),
"inner", innerPlan(plan),
str, indent, es); str, indent, es);
show_upper_qual(((HashJoin *) plan)->join.joinqual, show_upper_qual(((HashJoin *) plan)->join.joinqual,
"Join Filter", "Join Filter", plan,
"outer", outerPlan(plan),
"inner", innerPlan(plan),
str, indent, es); str, indent, es);
show_upper_qual(plan->qual, show_upper_qual(plan->qual,
"Filter", "Filter", plan,
"outer", outerPlan(plan),
"inner", innerPlan(plan),
str, indent, es); str, indent, es);
break; break;
case T_Agg: case T_Agg:
case T_Group: case T_Group:
show_upper_qual(plan->qual, show_upper_qual(plan->qual,
"Filter", "Filter", plan,
"subplan", outerPlan(plan),
"", NULL,
str, indent, es); str, indent, es);
break; break;
case T_Sort: case T_Sort:
...@@ -843,14 +830,10 @@ explain_outNode(StringInfo str, ...@@ -843,14 +830,10 @@ explain_outNode(StringInfo str,
break; break;
case T_Result: case T_Result:
show_upper_qual((List *) ((Result *) plan)->resconstantqual, show_upper_qual((List *) ((Result *) plan)->resconstantqual,
"One-Time Filter", "One-Time Filter", plan,
"subplan", outerPlan(plan),
"", NULL,
str, indent, es); str, indent, es);
show_upper_qual(plan->qual, show_upper_qual(plan->qual,
"Filter", "Filter", plan,
"subplan", outerPlan(plan),
"", NULL,
str, indent, es); str, indent, es);
break; break;
default: default:
...@@ -1032,14 +1015,18 @@ explain_outNode(StringInfo str, ...@@ -1032,14 +1015,18 @@ explain_outNode(StringInfo str,
/* /*
* Show a qualifier expression for a scan plan node * 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 static void
show_scan_qual(List *qual, const char *qlabel, 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) StringInfo str, int indent, ExplainState *es)
{ {
Node *outercontext;
List *context; List *context;
bool useprefix;
Node *node; Node *node;
char *exprstr; char *exprstr;
int i; int i;
...@@ -1051,31 +1038,14 @@ show_scan_qual(List *qual, const char *qlabel, ...@@ -1051,31 +1038,14 @@ show_scan_qual(List *qual, const char *qlabel,
/* Convert AND list to explicit AND */ /* Convert AND list to explicit AND */
node = (Node *) make_ands_explicit(qual); node = (Node *) make_ands_explicit(qual);
/* /* Set up deparsing context */
* If we have an outer plan that is referenced by the qual, add it to the context = deparse_context_for_plan((Node *) outer_plan,
* deparse context. If not, don't (so that we don't force prefixes (Node *) inner_plan,
* 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,
es->rtable); es->rtable);
useprefix = (outer_plan != NULL || inner_plan != NULL);
/* Deparse the expression */ /* Deparse the expression */
exprstr = deparse_expression(node, context, (outercontext != NULL), false); exprstr = deparse_expression(node, context, useprefix, false);
/* And add to str */ /* And add to str */
for (i = 0; i < indent; i++) for (i = 0; i < indent; i++)
...@@ -1087,16 +1057,11 @@ show_scan_qual(List *qual, const char *qlabel, ...@@ -1087,16 +1057,11 @@ show_scan_qual(List *qual, const char *qlabel,
* Show a qualifier expression for an upper-level plan node * Show a qualifier expression for an upper-level plan node
*/ */
static void static void
show_upper_qual(List *qual, const char *qlabel, show_upper_qual(List *qual, const char *qlabel, Plan *plan,
const char *outer_name, Plan *outer_plan,
const char *inner_name, Plan *inner_plan,
StringInfo str, int indent, ExplainState *es) StringInfo str, int indent, ExplainState *es)
{ {
List *context; List *context;
Node *outercontext; bool useprefix;
Node *innercontext;
int outer_varno;
int inner_varno;
Node *node; Node *node;
char *exprstr; char *exprstr;
int i; int i;
...@@ -1105,36 +1070,15 @@ show_upper_qual(List *qual, const char *qlabel, ...@@ -1105,36 +1070,15 @@ show_upper_qual(List *qual, const char *qlabel,
if (qual == NIL) if (qual == NIL)
return; return;
/* Generate deparse context */ /* Set up deparsing context */
if (outer_plan) context = deparse_context_for_plan((Node *) outerPlan(plan),
{ (Node *) innerPlan(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,
es->rtable); es->rtable);
useprefix = list_length(es->rtable) > 1;
/* Deparse the expression */ /* Deparse the expression */
node = (Node *) make_ands_explicit(qual); 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 */ /* And add to str */
for (i = 0; i < indent; i++) for (i = 0; i < indent; i++)
...@@ -1154,7 +1098,6 @@ show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols, ...@@ -1154,7 +1098,6 @@ show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
bool useprefix; bool useprefix;
int keyno; int keyno;
char *exprstr; char *exprstr;
Relids varnos;
int i; int i;
if (nkeys <= 0) if (nkeys <= 0)
...@@ -1164,33 +1107,11 @@ show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols, ...@@ -1164,33 +1107,11 @@ show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
appendStringInfo(str, " "); appendStringInfo(str, " ");
appendStringInfo(str, " %s: ", qlabel); appendStringInfo(str, " %s: ", qlabel);
/* /* Set up deparsing context */
* In this routine we expect that the plan node's tlist has not been context = deparse_context_for_plan((Node *) outerPlan(sortplan),
* processed by set_plan_references(). Normally, any Vars will contain NULL, /* Sort has no innerPlan */
* 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); es->rtable);
useprefix = list_length(es->rtable) > 1; useprefix = list_length(es->rtable) > 1;
}
bms_free(varnos);
for (keyno = 0; keyno < nkeys; keyno++) for (keyno = 0; keyno < nkeys; keyno++)
{ {
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.132 2007/02/22 23:44:25 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.133 2007/02/23 21:59:44 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -73,6 +73,7 @@ static void set_join_references(Join *join, int rtoffset); ...@@ -73,6 +73,7 @@ static void set_join_references(Join *join, int rtoffset);
static void set_inner_join_references(Plan *inner_plan, static void set_inner_join_references(Plan *inner_plan,
indexed_tlist *outer_itlist); indexed_tlist *outer_itlist);
static void set_upper_references(Plan *plan, int rtoffset); static void set_upper_references(Plan *plan, int rtoffset);
static void set_dummy_tlist_references(Plan *plan, int rtoffset);
static indexed_tlist *build_tlist_index(List *tlist); static indexed_tlist *build_tlist_index(List *tlist);
static Var *search_indexed_tlist_for_var(Var *var, static Var *search_indexed_tlist_for_var(Var *var,
indexed_tlist *itlist, indexed_tlist *itlist,
...@@ -315,8 +316,7 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) ...@@ -315,8 +316,7 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
* executor, we fix it up for possible use by EXPLAIN (not to * executor, we fix it up for possible use by EXPLAIN (not to
* mention ease of debugging --- wrong varnos are very confusing). * mention ease of debugging --- wrong varnos are very confusing).
*/ */
plan->targetlist = set_dummy_tlist_references(plan, rtoffset);
fix_scan_list(plan->targetlist, rtoffset);
/* /*
* Since these plan types don't check quals either, we should not * Since these plan types don't check quals either, we should not
* find any qual expression attached to them. * find any qual expression attached to them.
...@@ -330,11 +330,12 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) ...@@ -330,11 +330,12 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
/* /*
* Like the plan types above, Limit doesn't evaluate its tlist * Like the plan types above, Limit doesn't evaluate its tlist
* or quals. It does have live expressions for limit/offset, * or quals. It does have live expressions for limit/offset,
* however. * however; and those cannot contain subplan variable refs,
* so fix_scan_expr works for them.
*/ */
splan->plan.targetlist = set_dummy_tlist_references(plan, rtoffset);
fix_scan_list(splan->plan.targetlist, rtoffset);
Assert(splan->plan.qual == NIL); Assert(splan->plan.qual == NIL);
splan->limitOffset = splan->limitOffset =
fix_scan_expr(splan->limitOffset, rtoffset); fix_scan_expr(splan->limitOffset, rtoffset);
splan->limitCount = splan->limitCount =
...@@ -375,8 +376,7 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) ...@@ -375,8 +376,7 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
* Append, like Sort et al, doesn't actually evaluate its * Append, like Sort et al, doesn't actually evaluate its
* targetlist or check quals. * targetlist or check quals.
*/ */
splan->plan.targetlist = set_dummy_tlist_references(plan, rtoffset);
fix_scan_list(splan->plan.targetlist, rtoffset);
Assert(splan->plan.qual == NIL); Assert(splan->plan.qual == NIL);
foreach(l, splan->appendplans) foreach(l, splan->appendplans)
{ {
...@@ -892,10 +892,7 @@ set_upper_references(Plan *plan, int rtoffset) ...@@ -892,10 +892,7 @@ set_upper_references(Plan *plan, int rtoffset)
List *output_targetlist; List *output_targetlist;
ListCell *l; ListCell *l;
if (subplan != NULL)
subplan_itlist = build_tlist_index(subplan->targetlist); subplan_itlist = build_tlist_index(subplan->targetlist);
else
subplan_itlist = build_tlist_index(NIL);
output_targetlist = NIL; output_targetlist = NIL;
foreach(l, plan->targetlist) foreach(l, plan->targetlist)
...@@ -920,6 +917,58 @@ set_upper_references(Plan *plan, int rtoffset) ...@@ -920,6 +917,58 @@ set_upper_references(Plan *plan, int rtoffset)
pfree(subplan_itlist); pfree(subplan_itlist);
} }
/*
* set_dummy_tlist_references
* Replace the targetlist of an upper-level plan node with a simple
* list of OUTER references to its child.
*
* This is used for plan types like Sort and Append that don't evaluate
* their targetlists. Although the executor doesn't care at all what's in
* the tlist, EXPLAIN needs it to be realistic.
*
* Note: we could almost use set_upper_references() here, but it fails for
* Append for lack of a lefttree subplan. Single-purpose code is faster
* anyway.
*/
static void
set_dummy_tlist_references(Plan *plan, int rtoffset)
{
List *output_targetlist;
ListCell *l;
output_targetlist = NIL;
foreach(l, plan->targetlist)
{
TargetEntry *tle = (TargetEntry *) lfirst(l);
Var *oldvar = (Var *) tle->expr;
Var *newvar;
newvar = makeVar(OUTER,
tle->resno,
exprType((Node *) oldvar),
exprTypmod((Node *) oldvar),
0);
if (IsA(oldvar, Var))
{
newvar->varnoold = oldvar->varno + rtoffset;
newvar->varoattno = oldvar->varattno;
}
else
{
newvar->varnoold = 0; /* wasn't ever a plain Var */
newvar->varoattno = 0;
}
tle = flatCopyTargetEntry(tle);
tle->expr = (Expr *) newvar;
output_targetlist = lappend(output_targetlist, tle);
}
plan->targetlist = output_targetlist;
/* We don't touch plan->qual here */
}
/* /*
* build_tlist_index --- build an index data structure for a child tlist * build_tlist_index --- build an index data structure for a child tlist
* *
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.288 2007/02/17 00:55:58 momjian Exp $ * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.289 2007/02/23 21:59:45 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -537,10 +537,8 @@ extern Datum pg_get_serial_sequence(PG_FUNCTION_ARGS); ...@@ -537,10 +537,8 @@ extern Datum pg_get_serial_sequence(PG_FUNCTION_ARGS);
extern char *deparse_expression(Node *expr, List *dpcontext, extern char *deparse_expression(Node *expr, List *dpcontext,
bool forceprefix, bool showimplicit); bool forceprefix, bool showimplicit);
extern List *deparse_context_for(const char *aliasname, Oid relid); extern List *deparse_context_for(const char *aliasname, Oid relid);
extern List *deparse_context_for_plan(int outer_varno, Node *outercontext, extern List *deparse_context_for_plan(Node *outer_plan, Node *inner_plan,
int inner_varno, Node *innercontext,
List *rtable); List *rtable);
extern Node *deparse_context_for_subplan(const char *name, Node *subplan);
extern const char *quote_identifier(const char *ident); extern const char *quote_identifier(const char *ident);
extern char *quote_qualified_identifier(const char *namespace, extern char *quote_qualified_identifier(const char *namespace,
const char *ident); const char *ident);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment