diff options
author | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
---|---|---|
committer | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
commit | d31084e9d1118b25fd16580d9d8c2924b5740dff (patch) | |
tree | 3179e66307d54df9c7b966543550e601eb55e668 /src/backend/commands/explain.c | |
download | postgresql-PG95-1_01.tar.gz postgresql-PG95-1_01.zip |
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/backend/commands/explain.c')
-rw-r--r-- | src/backend/commands/explain.c | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c new file mode 100644 index 00000000000..a37f0f9cf4b --- /dev/null +++ b/src/backend/commands/explain.c @@ -0,0 +1,219 @@ +/*------------------------------------------------------------------------- + * + * explain.c-- + * Explain the query execution plan + * + * Copyright (c) 1994-5, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.1.1.1 1996/07/09 06:21:21 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" +#include "parser/catalog_utils.h" +#include "parser/parse_query.h" /* for MakeTimeRange() */ +#include "nodes/plannodes.h" +#include "tcop/tcopprot.h" +#include "utils/elog.h" +#include "utils/palloc.h" +#include "lib/stringinfo.h" +#include "commands/explain.h" +#include "optimizer/planner.h" +#include "access/xact.h" + +typedef struct ExplainState { + /* options */ + int printCost; /* print cost */ + int printNodes; /* do nodeToString() instead */ + /* other states */ + List *rtable; /* range table */ +} ExplainState; + +static char *Explain_PlanToString(Plan *plan, ExplainState *es); + +/* + * ExplainQuery - + * print out the execution plan for a given query + * + */ +void +ExplainQuery(Query *query, List *options, CommandDest dest) +{ + char *s; + Plan *plan; + ExplainState *es; + int len; + + if (IsAbortedTransactionBlockState()) { + char *tag = "*ABORT STATE*"; + EndCommand(tag, dest); + + elog(NOTICE, "(transaction aborted): %s", + "queries ignored until END"); + + return; + } + + /* plan the queries (XXX we've ignored rewrite!!) */ + plan = planner(query); + + /* pg_plan could have failed */ + if (plan == NULL) + return; + + es = (ExplainState*)malloc(sizeof(ExplainState)); + memset(es, 0, sizeof(ExplainState)); + + /* parse options */ + while (options) { + char *ostr = strVal(lfirst(options)); + if (!strcasecmp(ostr, "cost")) + es->printCost = 1; + else if (!strcasecmp(ostr, "full_plan")) + es->printNodes = 1; + + options = lnext(options); + } + es->rtable = query->rtable; + + if (es->printNodes) { + s = nodeToString(plan); + } else { + s = Explain_PlanToString(plan, es); + } + + /* output the plan */ + len = strlen(s); + elog(NOTICE, "QUERY PLAN:\n\n%.*s", ELOG_MAXLEN-64, s); + len -= ELOG_MAXLEN-64; + while (len > 0) { + s += ELOG_MAXLEN-64; + elog(NOTICE, "%.*s", ELOG_MAXLEN-64, s); + len -= ELOG_MAXLEN-64; + } + free(es); +} + +/***************************************************************************** + * + *****************************************************************************/ + +/* + * explain_outNode - + * converts a Node into ascii string and append it to 'str' + */ +static void +explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es) +{ + char *pname; + char buf[1000]; + int i; + + if (plan==NULL) { + appendStringInfo(str, "\n"); + return; + } + + switch(nodeTag(plan)) { + case T_Result: + pname = "Result"; + break; + case T_Append: + pname = "Append"; + break; + case T_NestLoop: + pname = "Nested Loop"; + break; + case T_MergeJoin: + pname = "Merge Join"; + break; + case T_HashJoin: + pname = "Hash Join"; + break; + case T_SeqScan: + pname = "Seq Scan"; + break; + case T_IndexScan: + pname = "Index Scan"; + break; + case T_Temp: + pname = "Temp Scan"; + break; + case T_Sort: + pname = "Sort"; + break; + case T_Agg: + pname = "Aggregate"; + break; + case T_Unique: + pname = "Unique"; + break; + case T_Hash: + pname = "Hash"; + break; + case T_Tee: + pname = "Tee"; + break; + default: + break; + } + + for(i=0; i < indent; i++) + appendStringInfo(str, " "); + + appendStringInfo(str, pname); + switch(nodeTag(plan)) { + case T_SeqScan: + case T_IndexScan: + if (((Scan*)plan)->scanrelid > 0) { + RangeTblEntry *rte = nth(((Scan*)plan)->scanrelid-1, es->rtable); + sprintf(buf, " on %.*s", NAMEDATALEN, rte->refname); + appendStringInfo(str, buf); + } + break; + default: + break; + } + if (es->printCost) { + sprintf(buf, " (cost=%.2f size=%d width=%d)", + plan->cost, plan->plan_size, plan->plan_width); + appendStringInfo(str, buf); + } + appendStringInfo(str, "\n"); + + /* lefttree */ + if (outerPlan(plan)) { + for(i=0; i < indent; i++) + appendStringInfo(str, " "); + appendStringInfo(str, " -> "); + explain_outNode(str, outerPlan(plan), indent+1, es); + } + + /* righttree */ + if (innerPlan(plan)) { + for(i=0; i < indent; i++) + appendStringInfo(str, " "); + appendStringInfo(str, " -> "); + explain_outNode(str, innerPlan(plan), indent+1, es); + } + return; +} + +static char * +Explain_PlanToString(Plan *plan, ExplainState *es) +{ + StringInfo str; + char *s; + + if (plan==NULL) + return ""; + Assert(plan!=NULL); + str = makeStringInfo(); + explain_outNode(str, plan, 0, es); + s = str->data; + pfree(str); + + return s; +} |