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.c135
1 files changed, 94 insertions, 41 deletions
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 95263a5da08..19df98531c5 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994-5, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.72 2002/03/21 16:00:32 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.73 2002/03/22 02:56:31 tgl Exp $
*
*/
@@ -17,10 +17,12 @@
#include "nodes/print.h"
#include "optimizer/clauses.h"
#include "optimizer/planner.h"
+#include "optimizer/var.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteHandler.h"
#include "tcop/pquery.h"
#include "utils/builtins.h"
+#include "utils/lsyscache.h"
#include "utils/relcache.h"
@@ -34,9 +36,12 @@ typedef struct ExplainState
} ExplainState;
static StringInfo Explain_PlanToString(Plan *plan, ExplainState *es);
-static void ExplainOneQuery(Query *query, bool verbose, bool analyze, CommandDest dest);
+static void ExplainOneQuery(Query *query, bool verbose, bool analyze,
+ CommandDest dest);
+static void explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
+ int indent, ExplainState *es);
static void show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
- int scanrelid,
+ int scanrelid, Plan *outer_plan,
StringInfo str, int indent, ExplainState *es);
static void show_upper_qual(List *qual, const char *qlabel,
const char *outer_name, int outer_varno, Plan *outer_plan,
@@ -188,10 +193,15 @@ ExplainOneQuery(Query *query, bool verbose, bool analyze, CommandDest dest)
/*
* explain_outNode -
- * converts a Node into ascii string and append it to 'str'
+ * converts a Plan node into ascii string and appends it to 'str'
+ *
+ * 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.
*/
static void
-explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
+explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
+ int indent, ExplainState *es)
{
List *l;
Relation relation;
@@ -304,15 +314,19 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
{
RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
es->rtable);
+ char *relname;
/* Assume it's on a real relation */
- Assert(rte->relname);
+ Assert(rte->relid);
+
+ /* We only show the rel name, not schema name */
+ relname = get_rel_name(rte->relid);
appendStringInfo(str, " on %s",
- stringStringInfo(rte->relname));
- if (strcmp(rte->eref->aliasname, rte->relname) != 0)
+ stringStringInfo(relname));
+ if (strcmp(rte->eref->aliasname, relname) != 0)
appendStringInfo(str, " %s",
- stringStringInfo(rte->eref->aliasname));
+ stringStringInfo(rte->eref->aliasname));
}
break;
case T_SubqueryScan:
@@ -352,77 +366,93 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
{
case T_IndexScan:
show_scan_qual(((IndexScan *) plan)->indxqualorig, true,
- "indxqual",
+ "Index Filter",
((Scan *) plan)->scanrelid,
+ outer_plan,
str, indent, es);
- show_scan_qual(plan->qual, false, "qual",
+ show_scan_qual(plan->qual, false,
+ "Filter",
((Scan *) plan)->scanrelid,
+ outer_plan,
str, indent, es);
break;
case T_SeqScan:
case T_TidScan:
- show_scan_qual(plan->qual, false, "qual",
+ show_scan_qual(plan->qual, false,
+ "Filter",
((Scan *) plan)->scanrelid,
+ outer_plan,
str, indent, es);
break;
case T_NestLoop:
- show_upper_qual(((NestLoop *) plan)->join.joinqual, "joinqual",
+ show_upper_qual(((NestLoop *) plan)->join.joinqual,
+ "Join Cond",
"outer", OUTER, outerPlan(plan),
"inner", INNER, innerPlan(plan),
str, indent, es);
- show_upper_qual(plan->qual, "qual",
+ show_upper_qual(plan->qual,
+ "Filter",
"outer", OUTER, outerPlan(plan),
"inner", INNER, innerPlan(plan),
str, indent, es);
break;
case T_MergeJoin:
- show_upper_qual(((MergeJoin *) plan)->mergeclauses, "merge",
+ show_upper_qual(((MergeJoin *) plan)->mergeclauses,
+ "Merge Cond",
"outer", OUTER, outerPlan(plan),
"inner", INNER, innerPlan(plan),
str, indent, es);
- show_upper_qual(((MergeJoin *) plan)->join.joinqual, "joinqual",
+ show_upper_qual(((MergeJoin *) plan)->join.joinqual,
+ "Join Cond",
"outer", OUTER, outerPlan(plan),
"inner", INNER, innerPlan(plan),
str, indent, es);
- show_upper_qual(plan->qual, "qual",
+ show_upper_qual(plan->qual,
+ "Filter",
"outer", OUTER, outerPlan(plan),
"inner", INNER, innerPlan(plan),
str, indent, es);
break;
case T_HashJoin:
- show_upper_qual(((HashJoin *) plan)->hashclauses, "hash",
+ show_upper_qual(((HashJoin *) plan)->hashclauses,
+ "Hash Cond",
"outer", OUTER, outerPlan(plan),
"inner", INNER, innerPlan(plan),
str, indent, es);
- show_upper_qual(((HashJoin *) plan)->join.joinqual, "joinqual",
+ show_upper_qual(((HashJoin *) plan)->join.joinqual,
+ "Join Cond",
"outer", OUTER, outerPlan(plan),
"inner", INNER, innerPlan(plan),
str, indent, es);
- show_upper_qual(plan->qual, "qual",
+ show_upper_qual(plan->qual,
+ "Filter",
"outer", OUTER, outerPlan(plan),
"inner", INNER, innerPlan(plan),
str, indent, es);
break;
case T_SubqueryScan:
- show_upper_qual(plan->qual, "qual",
+ show_upper_qual(plan->qual,
+ "Filter",
"subplan", 1, ((SubqueryScan *) plan)->subplan,
"", 0, NULL,
str, indent, es);
break;
case T_Agg:
case T_Group:
- show_upper_qual(plan->qual, "qual",
+ show_upper_qual(plan->qual,
+ "Filter",
"subplan", 0, outerPlan(plan),
"", 0, NULL,
str, indent, es);
break;
case T_Result:
show_upper_qual((List *) ((Result *) plan)->resconstantqual,
- "constqual",
+ "One-Time Filter",
"subplan", OUTER, outerPlan(plan),
"", 0, NULL,
str, indent, es);
- show_upper_qual(plan->qual, "qual",
+ show_upper_qual(plan->qual,
+ "Filter",
"subplan", OUTER, outerPlan(plan),
"", 0, NULL,
str, indent, es);
@@ -446,7 +476,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
- explain_outNode(str, ((SubPlan *) lfirst(lst))->plan,
+ explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, NULL,
indent + 4, es);
}
es->rtable = saved_rtable;
@@ -458,7 +488,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
- explain_outNode(str, outerPlan(plan), indent + 3, es);
+ explain_outNode(str, outerPlan(plan), NULL, indent + 3, es);
}
/* righttree */
@@ -467,7 +497,8 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
- explain_outNode(str, innerPlan(plan), indent + 3, es);
+ explain_outNode(str, innerPlan(plan), outerPlan(plan),
+ indent + 3, es);
}
if (IsA(plan, Append))
@@ -483,7 +514,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
- explain_outNode(str, subnode, indent + 3, es);
+ explain_outNode(str, subnode, NULL, indent + 3, es);
}
}
@@ -502,7 +533,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
- explain_outNode(str, subnode, indent + 3, es);
+ explain_outNode(str, subnode, NULL, indent + 3, es);
es->rtable = saved_rtable;
}
@@ -522,7 +553,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
- explain_outNode(str, ((SubPlan *) lfirst(lst))->plan,
+ explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, NULL,
indent + 4, es);
}
es->rtable = saved_rtable;
@@ -535,7 +566,7 @@ Explain_PlanToString(Plan *plan, ExplainState *es)
StringInfo str = makeStringInfo();
if (plan != NULL)
- explain_outNode(str, plan, 0, es);
+ explain_outNode(str, plan, NULL, 0, es);
return str;
}
@@ -544,10 +575,12 @@ Explain_PlanToString(Plan *plan, ExplainState *es)
*/
static void
show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
- int scanrelid,
+ int scanrelid, Plan *outer_plan,
StringInfo str, int indent, ExplainState *es)
{
RangeTblEntry *rte;
+ Node *scancontext;
+ Node *outercontext;
List *context;
Node *node;
char *exprstr;
@@ -562,23 +595,43 @@ show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
return;
}
+ /* Fix qual --- indexqual requires different processing */
+ if (is_or_qual)
+ node = make_ors_ands_explicit(qual);
+ else
+ node = (Node *) make_ands_explicit(qual);
+
/* Generate deparse context */
Assert(scanrelid > 0 && scanrelid <= length(es->rtable));
rte = rt_fetch(scanrelid, es->rtable);
/* Assume it's on a real relation */
- Assert(rte->relname);
-
- context = deparse_context_for(rte->relname, rte->relid);
-
- /* Fix qual --- indexqual requires different processing */
- if (is_or_qual)
- node = make_ors_ands_explicit(qual);
+ Assert(rte->relid);
+ scancontext = deparse_context_for_relation(rte->eref->aliasname,
+ rte->relid);
+
+ /*
+ * 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)
+ {
+ if (intMember(OUTER, pull_varnos(node)))
+ outercontext = deparse_context_for_subplan("outer",
+ outer_plan->targetlist,
+ es->rtable);
+ else
+ outercontext = NULL;
+ }
else
- node = (Node *) make_ands_explicit(qual);
+ outercontext = NULL;
+
+ context = deparse_context_for_plan(scanrelid, scancontext,
+ OUTER, outercontext);
/* Deparse the expression */
- exprstr = deparse_expression(node, context, false);
+ exprstr = deparse_expression(node, context, (outercontext != NULL));
/* And add to str */
for (i = 0; i < indent; i++)