explain.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:7k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*
  2.  * explain.c
  3.  *   Explain the query execution plan
  4.  *
  5.  * Copyright (c) 1994-5, Regents of the University of California
  6.  *
  7.  *   $Id: explain.c,v 1.38.2.1 1999/08/02 05:56:58 scrappy Exp $
  8.  *
  9.  */
  10. #include "postgres.h"
  11. #include "commands/explain.h"
  12. #include "lib/stringinfo.h"
  13. #include "nodes/print.h"
  14. #include "optimizer/planner.h"
  15. #include "parser/parsetree.h"
  16. #include "rewrite/rewriteHandler.h"
  17. #include "utils/relcache.h"
  18. typedef struct ExplainState
  19. {
  20. /* options */
  21. bool printCost; /* print cost */
  22. bool printNodes; /* do nodeToString() instead */
  23. /* other states */
  24. List    *rtable; /* range table */
  25. } ExplainState;
  26. static char *Explain_PlanToString(Plan *plan, ExplainState *es);
  27. static void printLongNotice(const char *header, const char *message);
  28. static void ExplainOneQuery(Query *query, bool verbose, CommandDest dest);
  29. /*
  30.  * ExplainQuery -
  31.  *   print out the execution plan for a given query
  32.  *
  33.  */
  34. void
  35. ExplainQuery(Query *query, bool verbose, CommandDest dest)
  36. {
  37. List    *rewritten;
  38. List    *l;
  39. /* rewriter and planner may not work in aborted state? */
  40. if (IsAbortedTransactionBlockState())
  41. {
  42. elog(NOTICE, "(transaction aborted): %s",
  43.  "queries ignored until END");
  44. return;
  45. }
  46. /* rewriter and planner will not cope with utility statements */
  47. if (query->commandType == CMD_UTILITY)
  48. {
  49. elog(NOTICE, "Utility statements have no plan structure");
  50. return;
  51. }
  52. /* Rewrite through rule system */
  53. rewritten = QueryRewrite(query);
  54. /* In the case of an INSTEAD NOTHING, tell at least that */
  55. if (rewritten == NIL)
  56. {
  57. elog(NOTICE, "Query rewrites to nothing");
  58. return;
  59. }
  60. /* Explain every plan */
  61. foreach(l, rewritten)
  62. ExplainOneQuery(lfirst(l), verbose, dest);
  63. }
  64. /*
  65.  * ExplainOneQuery -
  66.  *   print out the execution plan for one query
  67.  *
  68.  */
  69. static void
  70. ExplainOneQuery(Query *query, bool verbose, CommandDest dest)
  71. {
  72. char    *s;
  73. Plan    *plan;
  74. ExplainState *es;
  75. /* plan the query */
  76. plan = planner(query);
  77. /* pg_plan could have failed */
  78. if (plan == NULL)
  79. return;
  80. es = (ExplainState *) palloc(sizeof(ExplainState));
  81. MemSet(es, 0, sizeof(ExplainState));
  82. es->printCost = true; /* default */
  83. if (verbose)
  84. es->printNodes = true;
  85. es->rtable = query->rtable;
  86. if (es->printNodes)
  87. {
  88. s = nodeToString(plan);
  89. if (s)
  90. {
  91. printLongNotice("QUERY DUMP:nn", s);
  92. pfree(s);
  93. }
  94. }
  95. if (es->printCost)
  96. {
  97. s = Explain_PlanToString(plan, es);
  98. if (s)
  99. {
  100. printLongNotice("QUERY PLAN:nn", s);
  101. pfree(s);
  102. }
  103. }
  104. if (es->printNodes)
  105. pprint(plan); /* display in postmaster log file */
  106. pfree(es);
  107. }
  108. /*****************************************************************************
  109.  *
  110.  *****************************************************************************/
  111. /*
  112.  * explain_outNode -
  113.  *   converts a Node into ascii string and append it to 'str'
  114.  */
  115. static void
  116. explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
  117. {
  118. List    *l;
  119. Relation relation;
  120. char    *pname;
  121. int i;
  122. if (plan == NULL)
  123. {
  124. appendStringInfo(str, "n");
  125. return;
  126. }
  127. switch (nodeTag(plan))
  128. {
  129. case T_Result:
  130. pname = "Result";
  131. break;
  132. case T_Append:
  133. pname = "Append";
  134. break;
  135. case T_NestLoop:
  136. pname = "Nested Loop";
  137. break;
  138. case T_MergeJoin:
  139. pname = "Merge Join";
  140. break;
  141. case T_HashJoin:
  142. pname = "Hash Join";
  143. break;
  144. case T_SeqScan:
  145. pname = "Seq Scan";
  146. break;
  147. case T_IndexScan:
  148. pname = "Index Scan";
  149. break;
  150. case T_Noname:
  151. pname = "Noname Scan";
  152. break;
  153. case T_Sort:
  154. pname = "Sort";
  155. break;
  156. case T_Group:
  157. pname = "Group";
  158. break;
  159. case T_Agg:
  160. pname = "Aggregate";
  161. break;
  162. case T_Unique:
  163. pname = "Unique";
  164. break;
  165. case T_Hash:
  166. pname = "Hash";
  167. break;
  168. default:
  169. pname = "???";
  170. break;
  171. }
  172. appendStringInfo(str, pname);
  173. switch (nodeTag(plan))
  174. {
  175. case T_IndexScan:
  176. appendStringInfo(str, " using ");
  177. i = 0;
  178. foreach(l, ((IndexScan *) plan)->indxid)
  179. {
  180. relation = RelationIdCacheGetRelation((int) lfirst(l));
  181. if (++i > 1)
  182. appendStringInfo(str, ", ");
  183. appendStringInfo(str,
  184.  stringStringInfo((RelationGetRelationName(relation))->data));
  185. }
  186. case T_SeqScan:
  187. if (((Scan *) plan)->scanrelid > 0)
  188. {
  189. RangeTblEntry *rte = nth(((Scan *) plan)->scanrelid - 1, es->rtable);
  190. appendStringInfo(str, " on ");
  191. if (strcmp(rte->refname, rte->relname) != 0)
  192. {
  193. appendStringInfo(str, "%s ",
  194.  stringStringInfo(rte->relname));
  195. }
  196. appendStringInfo(str, stringStringInfo(rte->refname));
  197. }
  198. break;
  199. default:
  200. break;
  201. }
  202. if (es->printCost)
  203. {
  204. appendStringInfo(str, "  (cost=%.2f rows=%d width=%d)",
  205.  plan->cost, plan->plan_size, plan->plan_width);
  206. }
  207. appendStringInfo(str, "n");
  208. /* initPlan-s */
  209. if (plan->initPlan)
  210. {
  211. List    *saved_rtable = es->rtable;
  212. List    *lst;
  213. for (i = 0; i < indent; i++)
  214. appendStringInfo(str, "  ");
  215. appendStringInfo(str, "  InitPlann");
  216. foreach(lst, plan->initPlan)
  217. {
  218. es->rtable = ((SubPlan *) lfirst(lst))->rtable;
  219. for (i = 0; i < indent; i++)
  220. appendStringInfo(str, "  ");
  221. appendStringInfo(str, "    ->  ");
  222. explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, indent + 2, es);
  223. }
  224. es->rtable = saved_rtable;
  225. }
  226. /* lefttree */
  227. if (outerPlan(plan))
  228. {
  229. for (i = 0; i < indent; i++)
  230. appendStringInfo(str, "  ");
  231. appendStringInfo(str, "  ->  ");
  232. explain_outNode(str, outerPlan(plan), indent + 3, es);
  233. }
  234. /* righttree */
  235. if (innerPlan(plan))
  236. {
  237. for (i = 0; i < indent; i++)
  238. appendStringInfo(str, "  ");
  239. appendStringInfo(str, "  ->  ");
  240. explain_outNode(str, innerPlan(plan), indent + 3, es);
  241. }
  242. /* subPlan-s */
  243. if (plan->subPlan)
  244. {
  245. List    *saved_rtable = es->rtable;
  246. List    *lst;
  247. for (i = 0; i < indent; i++)
  248. appendStringInfo(str, "  ");
  249. appendStringInfo(str, "  SubPlann");
  250. foreach(lst, plan->subPlan)
  251. {
  252. es->rtable = ((SubPlan *) lfirst(lst))->rtable;
  253. for (i = 0; i < indent; i++)
  254. appendStringInfo(str, "  ");
  255. appendStringInfo(str, "    ->  ");
  256. explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, indent + 4, es);
  257. }
  258. es->rtable = saved_rtable;
  259. }
  260. if (nodeTag(plan) == T_Append)
  261. {
  262. List    *saved_rtable = es->rtable;
  263. List    *lst;
  264. int whichplan = 0;
  265. Append    *appendplan = (Append *) plan;
  266. foreach(lst, appendplan->appendplans)
  267. {
  268. Plan    *subnode = (Plan *) lfirst(lst);
  269. if (appendplan->inheritrelid > 0)
  270. {
  271. ResTarget  *rtentry;
  272. rtentry = nth(whichplan, appendplan->inheritrtable);
  273. Assert(rtentry != NULL);
  274. rt_store(appendplan->inheritrelid, es->rtable, rtentry);
  275. }
  276. else
  277. es->rtable = nth(whichplan, appendplan->unionrtables);
  278. for (i = 0; i < indent; i++)
  279. appendStringInfo(str, "  ");
  280. appendStringInfo(str, "    ->  ");
  281. explain_outNode(str, subnode, indent + 4, es);
  282. whichplan++;
  283. }
  284. es->rtable = saved_rtable;
  285. }
  286. return;
  287. }
  288. static char *
  289. Explain_PlanToString(Plan *plan, ExplainState *es)
  290. {
  291. StringInfoData str;
  292. /* see stringinfo.h for an explanation of this maneuver */
  293. initStringInfo(&str);
  294. if (plan != NULL)
  295. explain_outNode(&str, plan, 0, es);
  296. return str.data;
  297. }
  298. /*
  299.  * Print a message that might exceed the size of the elog message buffer.
  300.  * This is a crock ... there shouldn't be an upper limit to what you can elog().
  301.  */
  302. static void
  303. printLongNotice(const char *header, const char *message)
  304. {
  305. int len = strlen(message);
  306. elog(NOTICE, "%.20s%.*s", header, ELOG_MAXLEN - 64, message);
  307. len -= ELOG_MAXLEN - 64;
  308. while (len > 0)
  309. {
  310. message += ELOG_MAXLEN - 64;
  311. elog(NOTICE, "%.*s", ELOG_MAXLEN - 64, message);
  312. len -= ELOG_MAXLEN - 64;
  313. }
  314. }