Force a checkpoint in CREATE DATABASE before starting to copy the files,
[PostgreSQL.git] / src / backend / commands / explain.c
blobc0c53cfa6be3faaa3a32c09ff2bdb4d79db2f93e
1 /*-------------------------------------------------------------------------
3 * explain.c
4 * Explain query execution plans
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994-5, Regents of the University of California
9 * IDENTIFICATION
10 * $PostgreSQL$
12 *-------------------------------------------------------------------------
14 #include "postgres.h"
16 #include "access/xact.h"
17 #include "catalog/pg_constraint.h"
18 #include "catalog/pg_type.h"
19 #include "commands/explain.h"
20 #include "commands/prepare.h"
21 #include "commands/trigger.h"
22 #include "executor/instrument.h"
23 #include "optimizer/clauses.h"
24 #include "optimizer/planner.h"
25 #include "optimizer/var.h"
26 #include "parser/parsetree.h"
27 #include "rewrite/rewriteHandler.h"
28 #include "tcop/tcopprot.h"
29 #include "utils/builtins.h"
30 #include "utils/guc.h"
31 #include "utils/lsyscache.h"
32 #include "utils/tuplesort.h"
33 #include "utils/snapmgr.h"
36 /* Hook for plugins to get control in ExplainOneQuery() */
37 ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL;
39 /* Hook for plugins to get control in explain_get_index_name() */
40 explain_get_index_name_hook_type explain_get_index_name_hook = NULL;
43 typedef struct ExplainState
45 /* options */
46 bool printTList; /* print plan targetlists */
47 bool printAnalyze; /* print actual times */
48 /* other states */
49 PlannedStmt *pstmt; /* top of plan */
50 List *rtable; /* range table */
51 } ExplainState;
53 static void ExplainOneQuery(Query *query, ExplainStmt *stmt,
54 const char *queryString,
55 ParamListInfo params, TupOutputState *tstate);
56 static void report_triggers(ResultRelInfo *rInfo, bool show_relname,
57 StringInfo buf);
58 static double elapsed_time(instr_time *starttime);
59 static void explain_outNode(StringInfo str,
60 Plan *plan, PlanState *planstate,
61 Plan *outer_plan,
62 int indent, ExplainState *es);
63 static void show_plan_tlist(Plan *plan,
64 StringInfo str, int indent, ExplainState *es);
65 static void show_scan_qual(List *qual, const char *qlabel,
66 int scanrelid, Plan *scan_plan, Plan *outer_plan,
67 StringInfo str, int indent, ExplainState *es);
68 static void show_upper_qual(List *qual, const char *qlabel, Plan *plan,
69 StringInfo str, int indent, ExplainState *es);
70 static void show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
71 const char *qlabel,
72 StringInfo str, int indent, ExplainState *es);
73 static void show_sort_info(SortState *sortstate,
74 StringInfo str, int indent, ExplainState *es);
75 static const char *explain_get_index_name(Oid indexId);
79 * ExplainQuery -
80 * execute an EXPLAIN command
82 void
83 ExplainQuery(ExplainStmt *stmt, const char *queryString,
84 ParamListInfo params, DestReceiver *dest)
86 Oid *param_types;
87 int num_params;
88 TupOutputState *tstate;
89 List *rewritten;
90 ListCell *l;
92 /* Convert parameter type data to the form parser wants */
93 getParamListTypes(params, &param_types, &num_params);
96 * Run parse analysis and rewrite. Note this also acquires sufficient
97 * locks on the source table(s).
99 * Because the parser and planner tend to scribble on their input, we make
100 * a preliminary copy of the source querytree. This prevents problems in
101 * the case that the EXPLAIN is in a portal or plpgsql function and is
102 * executed repeatedly. (See also the same hack in DECLARE CURSOR and
103 * PREPARE.) XXX FIXME someday.
105 rewritten = pg_analyze_and_rewrite((Node *) copyObject(stmt->query),
106 queryString, param_types, num_params);
108 /* prepare for projection of tuples */
109 tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt));
111 if (rewritten == NIL)
113 /* In the case of an INSTEAD NOTHING, tell at least that */
114 do_text_output_oneline(tstate, "Query rewrites to nothing");
116 else
118 /* Explain every plan */
119 foreach(l, rewritten)
121 ExplainOneQuery((Query *) lfirst(l), stmt,
122 queryString, params, tstate);
123 /* put a blank line between plans */
124 if (lnext(l) != NULL)
125 do_text_output_oneline(tstate, "");
129 end_tup_output(tstate);
133 * ExplainResultDesc -
134 * construct the result tupledesc for an EXPLAIN
136 TupleDesc
137 ExplainResultDesc(ExplainStmt *stmt)
139 TupleDesc tupdesc;
141 /* need a tuple descriptor representing a single TEXT column */
142 tupdesc = CreateTemplateTupleDesc(1, false);
143 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
144 TEXTOID, -1, 0);
145 return tupdesc;
149 * ExplainOneQuery -
150 * print out the execution plan for one Query
152 static void
153 ExplainOneQuery(Query *query, ExplainStmt *stmt, const char *queryString,
154 ParamListInfo params, TupOutputState *tstate)
156 /* planner will not cope with utility statements */
157 if (query->commandType == CMD_UTILITY)
159 ExplainOneUtility(query->utilityStmt, stmt,
160 queryString, params, tstate);
161 return;
164 /* if an advisor plugin is present, let it manage things */
165 if (ExplainOneQuery_hook)
166 (*ExplainOneQuery_hook) (query, stmt, queryString, params, tstate);
167 else
169 PlannedStmt *plan;
171 /* plan the query */
172 plan = pg_plan_query(query, 0, params);
174 /* run it (if needed) and produce output */
175 ExplainOnePlan(plan, params, stmt, tstate);
180 * ExplainOneUtility -
181 * print out the execution plan for one utility statement
182 * (In general, utility statements don't have plans, but there are some
183 * we treat as special cases)
185 * This is exported because it's called back from prepare.c in the
186 * EXPLAIN EXECUTE case
188 void
189 ExplainOneUtility(Node *utilityStmt, ExplainStmt *stmt,
190 const char *queryString, ParamListInfo params,
191 TupOutputState *tstate)
193 if (utilityStmt == NULL)
194 return;
196 if (IsA(utilityStmt, ExecuteStmt))
197 ExplainExecuteQuery((ExecuteStmt *) utilityStmt, stmt,
198 queryString, params, tstate);
199 else if (IsA(utilityStmt, NotifyStmt))
200 do_text_output_oneline(tstate, "NOTIFY");
201 else
202 do_text_output_oneline(tstate,
203 "Utility statements have no plan structure");
207 * ExplainOnePlan -
208 * given a planned query, execute it if needed, and then print
209 * EXPLAIN output
211 * Since we ignore any DeclareCursorStmt that might be attached to the query,
212 * if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll actually run the
213 * query. This is different from pre-8.3 behavior but seems more useful than
214 * not running the query. No cursor will be created, however.
216 * This is exported because it's called back from prepare.c in the
217 * EXPLAIN EXECUTE case, and because an index advisor plugin would need
218 * to call it.
220 void
221 ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params,
222 ExplainStmt *stmt, TupOutputState *tstate)
224 QueryDesc *queryDesc;
225 instr_time starttime;
226 double totaltime = 0;
227 ExplainState *es;
228 StringInfoData buf;
229 int eflags;
232 * Use a snapshot with an updated command ID to ensure this query sees
233 * results of any previously executed queries.
235 PushUpdatedSnapshot(GetActiveSnapshot());
237 /* Create a QueryDesc requesting no output */
238 queryDesc = CreateQueryDesc(plannedstmt,
239 GetActiveSnapshot(), InvalidSnapshot,
240 None_Receiver, params,
241 stmt->analyze);
243 INSTR_TIME_SET_CURRENT(starttime);
245 /* If analyzing, we need to cope with queued triggers */
246 if (stmt->analyze)
247 AfterTriggerBeginQuery();
249 /* Select execution options */
250 if (stmt->analyze)
251 eflags = 0; /* default run-to-completion flags */
252 else
253 eflags = EXEC_FLAG_EXPLAIN_ONLY;
255 /* call ExecutorStart to prepare the plan for execution */
256 ExecutorStart(queryDesc, eflags);
258 /* Execute the plan for statistics if asked for */
259 if (stmt->analyze)
261 /* run the plan */
262 ExecutorRun(queryDesc, ForwardScanDirection, 0L);
264 /* We can't clean up 'till we're done printing the stats... */
265 totaltime += elapsed_time(&starttime);
268 es = (ExplainState *) palloc0(sizeof(ExplainState));
270 es->printTList = stmt->verbose;
271 es->printAnalyze = stmt->analyze;
272 es->pstmt = queryDesc->plannedstmt;
273 es->rtable = queryDesc->plannedstmt->rtable;
275 initStringInfo(&buf);
276 explain_outNode(&buf,
277 queryDesc->plannedstmt->planTree, queryDesc->planstate,
278 NULL, 0, es);
281 * If we ran the command, run any AFTER triggers it queued. (Note this
282 * will not include DEFERRED triggers; since those don't run until end of
283 * transaction, we can't measure them.) Include into total runtime.
285 if (stmt->analyze)
287 INSTR_TIME_SET_CURRENT(starttime);
288 AfterTriggerEndQuery(queryDesc->estate);
289 totaltime += elapsed_time(&starttime);
292 /* Print info about runtime of triggers */
293 if (es->printAnalyze)
295 ResultRelInfo *rInfo;
296 bool show_relname;
297 int numrels = queryDesc->estate->es_num_result_relations;
298 List *targrels = queryDesc->estate->es_trig_target_relations;
299 int nr;
300 ListCell *l;
302 show_relname = (numrels > 1 || targrels != NIL);
303 rInfo = queryDesc->estate->es_result_relations;
304 for (nr = 0; nr < numrels; rInfo++, nr++)
305 report_triggers(rInfo, show_relname, &buf);
307 foreach(l, targrels)
309 rInfo = (ResultRelInfo *) lfirst(l);
310 report_triggers(rInfo, show_relname, &buf);
315 * Close down the query and free resources. Include time for this in the
316 * total runtime (although it should be pretty minimal).
318 INSTR_TIME_SET_CURRENT(starttime);
320 ExecutorEnd(queryDesc);
322 FreeQueryDesc(queryDesc);
324 PopActiveSnapshot();
326 /* We need a CCI just in case query expanded to multiple plans */
327 if (stmt->analyze)
328 CommandCounterIncrement();
330 totaltime += elapsed_time(&starttime);
332 if (stmt->analyze)
333 appendStringInfo(&buf, "Total runtime: %.3f ms\n",
334 1000.0 * totaltime);
335 do_text_output_multiline(tstate, buf.data);
337 pfree(buf.data);
338 pfree(es);
342 * report_triggers -
343 * report execution stats for a single relation's triggers
345 static void
346 report_triggers(ResultRelInfo *rInfo, bool show_relname, StringInfo buf)
348 int nt;
350 if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
351 return;
352 for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
354 Trigger *trig = rInfo->ri_TrigDesc->triggers + nt;
355 Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
356 char *conname;
358 /* Must clean up instrumentation state */
359 InstrEndLoop(instr);
362 * We ignore triggers that were never invoked; they likely aren't
363 * relevant to the current query type.
365 if (instr->ntuples == 0)
366 continue;
368 if (OidIsValid(trig->tgconstraint) &&
369 (conname = get_constraint_name(trig->tgconstraint)) != NULL)
371 appendStringInfo(buf, "Trigger for constraint %s", conname);
372 pfree(conname);
374 else
375 appendStringInfo(buf, "Trigger %s", trig->tgname);
377 if (show_relname)
378 appendStringInfo(buf, " on %s",
379 RelationGetRelationName(rInfo->ri_RelationDesc));
381 appendStringInfo(buf, ": time=%.3f calls=%.0f\n",
382 1000.0 * instr->total, instr->ntuples);
386 /* Compute elapsed time in seconds since given timestamp */
387 static double
388 elapsed_time(instr_time *starttime)
390 instr_time endtime;
392 INSTR_TIME_SET_CURRENT(endtime);
393 INSTR_TIME_SUBTRACT(endtime, *starttime);
394 return INSTR_TIME_GET_DOUBLE(endtime);
398 * explain_outNode -
399 * converts a Plan node into ascii string and appends it to 'str'
401 * planstate points to the executor state node corresponding to the plan node.
402 * We need this to get at the instrumentation data (if any) as well as the
403 * list of subplans.
405 * outer_plan, if not null, references another plan node that is the outer
406 * side of a join with the current node. This is only interesting for
407 * deciphering runtime keys of an inner indexscan.
409 static void
410 explain_outNode(StringInfo str,
411 Plan *plan, PlanState *planstate,
412 Plan *outer_plan,
413 int indent, ExplainState *es)
415 const char *pname;
416 int i;
418 if (plan == NULL)
420 appendStringInfoChar(str, '\n');
421 return;
424 switch (nodeTag(plan))
426 case T_Result:
427 pname = "Result";
428 break;
429 case T_Append:
430 pname = "Append";
431 break;
432 case T_RecursiveUnion:
433 pname = "Recursive Union";
434 break;
435 case T_BitmapAnd:
436 pname = "BitmapAnd";
437 break;
438 case T_BitmapOr:
439 pname = "BitmapOr";
440 break;
441 case T_NestLoop:
442 switch (((NestLoop *) plan)->join.jointype)
444 case JOIN_INNER:
445 pname = "Nested Loop";
446 break;
447 case JOIN_LEFT:
448 pname = "Nested Loop Left Join";
449 break;
450 case JOIN_FULL:
451 pname = "Nested Loop Full Join";
452 break;
453 case JOIN_RIGHT:
454 pname = "Nested Loop Right Join";
455 break;
456 case JOIN_SEMI:
457 pname = "Nested Loop Semi Join";
458 break;
459 case JOIN_ANTI:
460 pname = "Nested Loop Anti Join";
461 break;
462 default:
463 pname = "Nested Loop ??? Join";
464 break;
466 break;
467 case T_MergeJoin:
468 switch (((MergeJoin *) plan)->join.jointype)
470 case JOIN_INNER:
471 pname = "Merge Join";
472 break;
473 case JOIN_LEFT:
474 pname = "Merge Left Join";
475 break;
476 case JOIN_FULL:
477 pname = "Merge Full Join";
478 break;
479 case JOIN_RIGHT:
480 pname = "Merge Right Join";
481 break;
482 case JOIN_SEMI:
483 pname = "Merge Semi Join";
484 break;
485 case JOIN_ANTI:
486 pname = "Merge Anti Join";
487 break;
488 default:
489 pname = "Merge ??? Join";
490 break;
492 break;
493 case T_HashJoin:
494 switch (((HashJoin *) plan)->join.jointype)
496 case JOIN_INNER:
497 pname = "Hash Join";
498 break;
499 case JOIN_LEFT:
500 pname = "Hash Left Join";
501 break;
502 case JOIN_FULL:
503 pname = "Hash Full Join";
504 break;
505 case JOIN_RIGHT:
506 pname = "Hash Right Join";
507 break;
508 case JOIN_SEMI:
509 pname = "Hash Semi Join";
510 break;
511 case JOIN_ANTI:
512 pname = "Hash Anti Join";
513 break;
514 default:
515 pname = "Hash ??? Join";
516 break;
518 break;
519 case T_SeqScan:
520 pname = "Seq Scan";
521 break;
522 case T_IndexScan:
523 pname = "Index Scan";
524 break;
525 case T_BitmapIndexScan:
526 pname = "Bitmap Index Scan";
527 break;
528 case T_BitmapHeapScan:
529 pname = "Bitmap Heap Scan";
530 break;
531 case T_TidScan:
532 pname = "Tid Scan";
533 break;
534 case T_SubqueryScan:
535 pname = "Subquery Scan";
536 break;
537 case T_FunctionScan:
538 pname = "Function Scan";
539 break;
540 case T_ValuesScan:
541 pname = "Values Scan";
542 break;
543 case T_CteScan:
544 pname = "CTE Scan";
545 break;
546 case T_WorkTableScan:
547 pname = "WorkTable Scan";
548 break;
549 case T_Material:
550 pname = "Materialize";
551 break;
552 case T_Sort:
553 pname = "Sort";
554 break;
555 case T_Group:
556 pname = "Group";
557 break;
558 case T_Agg:
559 switch (((Agg *) plan)->aggstrategy)
561 case AGG_PLAIN:
562 pname = "Aggregate";
563 break;
564 case AGG_SORTED:
565 pname = "GroupAggregate";
566 break;
567 case AGG_HASHED:
568 pname = "HashAggregate";
569 break;
570 default:
571 pname = "Aggregate ???";
572 break;
574 break;
575 case T_Unique:
576 pname = "Unique";
577 break;
578 case T_SetOp:
579 switch (((SetOp *) plan)->strategy)
581 case SETOP_SORTED:
582 switch (((SetOp *) plan)->cmd)
584 case SETOPCMD_INTERSECT:
585 pname = "SetOp Intersect";
586 break;
587 case SETOPCMD_INTERSECT_ALL:
588 pname = "SetOp Intersect All";
589 break;
590 case SETOPCMD_EXCEPT:
591 pname = "SetOp Except";
592 break;
593 case SETOPCMD_EXCEPT_ALL:
594 pname = "SetOp Except All";
595 break;
596 default:
597 pname = "SetOp ???";
598 break;
600 break;
601 case SETOP_HASHED:
602 switch (((SetOp *) plan)->cmd)
604 case SETOPCMD_INTERSECT:
605 pname = "HashSetOp Intersect";
606 break;
607 case SETOPCMD_INTERSECT_ALL:
608 pname = "HashSetOp Intersect All";
609 break;
610 case SETOPCMD_EXCEPT:
611 pname = "HashSetOp Except";
612 break;
613 case SETOPCMD_EXCEPT_ALL:
614 pname = "HashSetOp Except All";
615 break;
616 default:
617 pname = "HashSetOp ???";
618 break;
620 break;
621 default:
622 pname = "SetOp ???";
623 break;
625 break;
626 case T_Limit:
627 pname = "Limit";
628 break;
629 case T_Hash:
630 pname = "Hash";
631 break;
632 default:
633 pname = "???";
634 break;
637 appendStringInfoString(str, pname);
638 switch (nodeTag(plan))
640 case T_IndexScan:
641 if (ScanDirectionIsBackward(((IndexScan *) plan)->indexorderdir))
642 appendStringInfoString(str, " Backward");
643 appendStringInfo(str, " using %s",
644 explain_get_index_name(((IndexScan *) plan)->indexid));
645 /* FALL THRU */
646 case T_SeqScan:
647 case T_BitmapHeapScan:
648 case T_TidScan:
649 if (((Scan *) plan)->scanrelid > 0)
651 RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
652 es->rtable);
653 char *relname;
655 /* Assume it's on a real relation */
656 Assert(rte->rtekind == RTE_RELATION);
658 /* We only show the rel name, not schema name */
659 relname = get_rel_name(rte->relid);
661 appendStringInfo(str, " on %s",
662 quote_identifier(relname));
663 if (strcmp(rte->eref->aliasname, relname) != 0)
664 appendStringInfo(str, " %s",
665 quote_identifier(rte->eref->aliasname));
667 break;
668 case T_BitmapIndexScan:
669 appendStringInfo(str, " on %s",
670 explain_get_index_name(((BitmapIndexScan *) plan)->indexid));
671 break;
672 case T_SubqueryScan:
673 if (((Scan *) plan)->scanrelid > 0)
675 RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
676 es->rtable);
678 appendStringInfo(str, " %s",
679 quote_identifier(rte->eref->aliasname));
681 break;
682 case T_FunctionScan:
683 if (((Scan *) plan)->scanrelid > 0)
685 RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
686 es->rtable);
687 Node *funcexpr;
688 char *proname;
690 /* Assert it's on a RangeFunction */
691 Assert(rte->rtekind == RTE_FUNCTION);
694 * If the expression is still a function call, we can get the
695 * real name of the function. Otherwise, punt (this can
696 * happen if the optimizer simplified away the function call,
697 * for example).
699 funcexpr = ((FunctionScan *) plan)->funcexpr;
700 if (funcexpr && IsA(funcexpr, FuncExpr))
702 Oid funcid = ((FuncExpr *) funcexpr)->funcid;
704 /* We only show the func name, not schema name */
705 proname = get_func_name(funcid);
707 else
708 proname = rte->eref->aliasname;
710 appendStringInfo(str, " on %s",
711 quote_identifier(proname));
712 if (strcmp(rte->eref->aliasname, proname) != 0)
713 appendStringInfo(str, " %s",
714 quote_identifier(rte->eref->aliasname));
716 break;
717 case T_ValuesScan:
718 if (((Scan *) plan)->scanrelid > 0)
720 RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
721 es->rtable);
722 char *valsname;
724 /* Assert it's on a values rte */
725 Assert(rte->rtekind == RTE_VALUES);
727 valsname = rte->eref->aliasname;
729 appendStringInfo(str, " on %s",
730 quote_identifier(valsname));
732 break;
733 case T_CteScan:
734 if (((Scan *) plan)->scanrelid > 0)
736 RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
737 es->rtable);
739 /* Assert it's on a non-self-reference CTE */
740 Assert(rte->rtekind == RTE_CTE);
741 Assert(!rte->self_reference);
743 appendStringInfo(str, " on %s",
744 quote_identifier(rte->ctename));
745 if (strcmp(rte->eref->aliasname, rte->ctename) != 0)
746 appendStringInfo(str, " %s",
747 quote_identifier(rte->eref->aliasname));
749 break;
750 case T_WorkTableScan:
751 if (((Scan *) plan)->scanrelid > 0)
753 RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
754 es->rtable);
756 /* Assert it's on a self-reference CTE */
757 Assert(rte->rtekind == RTE_CTE);
758 Assert(rte->self_reference);
760 appendStringInfo(str, " on %s",
761 quote_identifier(rte->ctename));
762 if (strcmp(rte->eref->aliasname, rte->ctename) != 0)
763 appendStringInfo(str, " %s",
764 quote_identifier(rte->eref->aliasname));
766 break;
767 default:
768 break;
771 appendStringInfo(str, " (cost=%.2f..%.2f rows=%.0f width=%d)",
772 plan->startup_cost, plan->total_cost,
773 plan->plan_rows, plan->plan_width);
776 * We have to forcibly clean up the instrumentation state because we
777 * haven't done ExecutorEnd yet. This is pretty grotty ...
779 if (planstate->instrument)
780 InstrEndLoop(planstate->instrument);
782 if (planstate->instrument && planstate->instrument->nloops > 0)
784 double nloops = planstate->instrument->nloops;
786 appendStringInfo(str, " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",
787 1000.0 * planstate->instrument->startup / nloops,
788 1000.0 * planstate->instrument->total / nloops,
789 planstate->instrument->ntuples / nloops,
790 planstate->instrument->nloops);
792 else if (es->printAnalyze)
793 appendStringInfo(str, " (never executed)");
794 appendStringInfoChar(str, '\n');
796 /* target list */
797 if (es->printTList)
798 show_plan_tlist(plan, str, indent, es);
800 /* quals, sort keys, etc */
801 switch (nodeTag(plan))
803 case T_IndexScan:
804 show_scan_qual(((IndexScan *) plan)->indexqualorig,
805 "Index Cond",
806 ((Scan *) plan)->scanrelid,
807 plan, outer_plan,
808 str, indent, es);
809 show_scan_qual(plan->qual,
810 "Filter",
811 ((Scan *) plan)->scanrelid,
812 plan, outer_plan,
813 str, indent, es);
814 break;
815 case T_BitmapIndexScan:
816 show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig,
817 "Index Cond",
818 ((Scan *) plan)->scanrelid,
819 plan, outer_plan,
820 str, indent, es);
821 break;
822 case T_BitmapHeapScan:
823 /* XXX do we want to show this in production? */
824 show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig,
825 "Recheck Cond",
826 ((Scan *) plan)->scanrelid,
827 plan, outer_plan,
828 str, indent, es);
829 /* FALL THRU */
830 case T_SeqScan:
831 case T_FunctionScan:
832 case T_ValuesScan:
833 case T_CteScan:
834 case T_WorkTableScan:
835 show_scan_qual(plan->qual,
836 "Filter",
837 ((Scan *) plan)->scanrelid,
838 plan, outer_plan,
839 str, indent, es);
840 break;
841 case T_SubqueryScan:
842 show_scan_qual(plan->qual,
843 "Filter",
844 ((Scan *) plan)->scanrelid,
845 plan, outer_plan,
846 str, indent, es);
847 break;
848 case T_TidScan:
851 * The tidquals list has OR semantics, so be sure to show it
852 * as an OR condition.
854 List *tidquals = ((TidScan *) plan)->tidquals;
856 if (list_length(tidquals) > 1)
857 tidquals = list_make1(make_orclause(tidquals));
858 show_scan_qual(tidquals,
859 "TID Cond",
860 ((Scan *) plan)->scanrelid,
861 plan, outer_plan,
862 str, indent, es);
863 show_scan_qual(plan->qual,
864 "Filter",
865 ((Scan *) plan)->scanrelid,
866 plan, outer_plan,
867 str, indent, es);
869 break;
870 case T_NestLoop:
871 show_upper_qual(((NestLoop *) plan)->join.joinqual,
872 "Join Filter", plan,
873 str, indent, es);
874 show_upper_qual(plan->qual,
875 "Filter", plan,
876 str, indent, es);
877 break;
878 case T_MergeJoin:
879 show_upper_qual(((MergeJoin *) plan)->mergeclauses,
880 "Merge Cond", plan,
881 str, indent, es);
882 show_upper_qual(((MergeJoin *) plan)->join.joinqual,
883 "Join Filter", plan,
884 str, indent, es);
885 show_upper_qual(plan->qual,
886 "Filter", plan,
887 str, indent, es);
888 break;
889 case T_HashJoin:
890 show_upper_qual(((HashJoin *) plan)->hashclauses,
891 "Hash Cond", plan,
892 str, indent, es);
893 show_upper_qual(((HashJoin *) plan)->join.joinqual,
894 "Join Filter", plan,
895 str, indent, es);
896 show_upper_qual(plan->qual,
897 "Filter", plan,
898 str, indent, es);
899 break;
900 case T_Agg:
901 case T_Group:
902 show_upper_qual(plan->qual,
903 "Filter", plan,
904 str, indent, es);
905 break;
906 case T_Sort:
907 show_sort_keys(plan,
908 ((Sort *) plan)->numCols,
909 ((Sort *) plan)->sortColIdx,
910 "Sort Key",
911 str, indent, es);
912 show_sort_info((SortState *) planstate,
913 str, indent, es);
914 break;
915 case T_Result:
916 show_upper_qual((List *) ((Result *) plan)->resconstantqual,
917 "One-Time Filter", plan,
918 str, indent, es);
919 show_upper_qual(plan->qual,
920 "Filter", plan,
921 str, indent, es);
922 break;
923 default:
924 break;
927 /* initPlan-s */
928 if (plan->initPlan)
930 ListCell *lst;
932 for (i = 0; i < indent; i++)
933 appendStringInfo(str, " ");
934 appendStringInfo(str, " InitPlan\n");
935 foreach(lst, planstate->initPlan)
937 SubPlanState *sps = (SubPlanState *) lfirst(lst);
938 SubPlan *sp = (SubPlan *) sps->xprstate.expr;
940 for (i = 0; i < indent; i++)
941 appendStringInfo(str, " ");
942 appendStringInfo(str, " -> ");
943 explain_outNode(str,
944 exec_subplan_get_plan(es->pstmt, sp),
945 sps->planstate,
946 NULL,
947 indent + 4, es);
951 /* lefttree */
952 if (outerPlan(plan))
954 for (i = 0; i < indent; i++)
955 appendStringInfo(str, " ");
956 appendStringInfo(str, " -> ");
959 * Ordinarily we don't pass down our own outer_plan value to our child
960 * nodes, but in bitmap scan trees we must, since the bottom
961 * BitmapIndexScan nodes may have outer references.
963 explain_outNode(str, outerPlan(plan),
964 outerPlanState(planstate),
965 IsA(plan, BitmapHeapScan) ? outer_plan : NULL,
966 indent + 3, es);
969 /* righttree */
970 if (innerPlan(plan))
972 for (i = 0; i < indent; i++)
973 appendStringInfo(str, " ");
974 appendStringInfo(str, " -> ");
975 explain_outNode(str, innerPlan(plan),
976 innerPlanState(planstate),
977 outerPlan(plan),
978 indent + 3, es);
981 if (IsA(plan, Append))
983 Append *appendplan = (Append *) plan;
984 AppendState *appendstate = (AppendState *) planstate;
985 ListCell *lst;
986 int j;
988 j = 0;
989 foreach(lst, appendplan->appendplans)
991 Plan *subnode = (Plan *) lfirst(lst);
993 for (i = 0; i < indent; i++)
994 appendStringInfo(str, " ");
995 appendStringInfo(str, " -> ");
998 * Ordinarily we don't pass down our own outer_plan value to our
999 * child nodes, but in an Append we must, since we might be
1000 * looking at an appendrel indexscan with outer references from
1001 * the member scans.
1003 explain_outNode(str, subnode,
1004 appendstate->appendplans[j],
1005 outer_plan,
1006 indent + 3, es);
1007 j++;
1011 if (IsA(plan, BitmapAnd))
1013 BitmapAnd *bitmapandplan = (BitmapAnd *) plan;
1014 BitmapAndState *bitmapandstate = (BitmapAndState *) planstate;
1015 ListCell *lst;
1016 int j;
1018 j = 0;
1019 foreach(lst, bitmapandplan->bitmapplans)
1021 Plan *subnode = (Plan *) lfirst(lst);
1023 for (i = 0; i < indent; i++)
1024 appendStringInfo(str, " ");
1025 appendStringInfo(str, " -> ");
1027 explain_outNode(str, subnode,
1028 bitmapandstate->bitmapplans[j],
1029 outer_plan, /* pass down same outer plan */
1030 indent + 3, es);
1031 j++;
1035 if (IsA(plan, BitmapOr))
1037 BitmapOr *bitmaporplan = (BitmapOr *) plan;
1038 BitmapOrState *bitmaporstate = (BitmapOrState *) planstate;
1039 ListCell *lst;
1040 int j;
1042 j = 0;
1043 foreach(lst, bitmaporplan->bitmapplans)
1045 Plan *subnode = (Plan *) lfirst(lst);
1047 for (i = 0; i < indent; i++)
1048 appendStringInfo(str, " ");
1049 appendStringInfo(str, " -> ");
1051 explain_outNode(str, subnode,
1052 bitmaporstate->bitmapplans[j],
1053 outer_plan, /* pass down same outer plan */
1054 indent + 3, es);
1055 j++;
1059 if (IsA(plan, SubqueryScan))
1061 SubqueryScan *subqueryscan = (SubqueryScan *) plan;
1062 SubqueryScanState *subquerystate = (SubqueryScanState *) planstate;
1063 Plan *subnode = subqueryscan->subplan;
1065 for (i = 0; i < indent; i++)
1066 appendStringInfo(str, " ");
1067 appendStringInfo(str, " -> ");
1069 explain_outNode(str, subnode,
1070 subquerystate->subplan,
1071 NULL,
1072 indent + 3, es);
1075 /* subPlan-s */
1076 if (planstate->subPlan)
1078 ListCell *lst;
1080 for (i = 0; i < indent; i++)
1081 appendStringInfo(str, " ");
1082 appendStringInfo(str, " SubPlan\n");
1083 foreach(lst, planstate->subPlan)
1085 SubPlanState *sps = (SubPlanState *) lfirst(lst);
1086 SubPlan *sp = (SubPlan *) sps->xprstate.expr;
1088 for (i = 0; i < indent; i++)
1089 appendStringInfo(str, " ");
1090 appendStringInfo(str, " -> ");
1091 explain_outNode(str,
1092 exec_subplan_get_plan(es->pstmt, sp),
1093 sps->planstate,
1094 NULL,
1095 indent + 4, es);
1101 * Show the targetlist of a plan node
1103 static void
1104 show_plan_tlist(Plan *plan,
1105 StringInfo str, int indent, ExplainState *es)
1107 List *context;
1108 bool useprefix;
1109 ListCell *lc;
1110 int i;
1112 /* No work if empty tlist (this occurs eg in bitmap indexscans) */
1113 if (plan->targetlist == NIL)
1114 return;
1115 /* The tlist of an Append isn't real helpful, so suppress it */
1116 if (IsA(plan, Append))
1117 return;
1118 /* Likewise for RecursiveUnion */
1119 if (IsA(plan, RecursiveUnion))
1120 return;
1122 /* Set up deparsing context */
1123 context = deparse_context_for_plan((Node *) plan,
1124 NULL,
1125 es->rtable,
1126 es->pstmt->subplans);
1127 useprefix = list_length(es->rtable) > 1;
1129 /* Emit line prefix */
1130 for (i = 0; i < indent; i++)
1131 appendStringInfo(str, " ");
1132 appendStringInfo(str, " Output: ");
1134 /* Deparse each non-junk result column */
1135 i = 0;
1136 foreach(lc, plan->targetlist)
1138 TargetEntry *tle = (TargetEntry *) lfirst(lc);
1140 if (tle->resjunk)
1141 continue;
1142 if (i++ > 0)
1143 appendStringInfo(str, ", ");
1144 appendStringInfoString(str,
1145 deparse_expression((Node *) tle->expr, context,
1146 useprefix, false));
1149 appendStringInfoChar(str, '\n');
1153 * Show a qualifier expression for a scan plan node
1155 * Note: outer_plan is the referent for any OUTER vars in the scan qual;
1156 * this would be the outer side of a nestloop plan. Pass NULL if none.
1158 static void
1159 show_scan_qual(List *qual, const char *qlabel,
1160 int scanrelid, Plan *scan_plan, Plan *outer_plan,
1161 StringInfo str, int indent, ExplainState *es)
1163 List *context;
1164 bool useprefix;
1165 Node *node;
1166 char *exprstr;
1167 int i;
1169 /* No work if empty qual */
1170 if (qual == NIL)
1171 return;
1173 /* Convert AND list to explicit AND */
1174 node = (Node *) make_ands_explicit(qual);
1176 /* Set up deparsing context */
1177 context = deparse_context_for_plan((Node *) scan_plan,
1178 (Node *) outer_plan,
1179 es->rtable,
1180 es->pstmt->subplans);
1181 useprefix = (outer_plan != NULL || IsA(scan_plan, SubqueryScan));
1183 /* Deparse the expression */
1184 exprstr = deparse_expression(node, context, useprefix, false);
1186 /* And add to str */
1187 for (i = 0; i < indent; i++)
1188 appendStringInfo(str, " ");
1189 appendStringInfo(str, " %s: %s\n", qlabel, exprstr);
1193 * Show a qualifier expression for an upper-level plan node
1195 static void
1196 show_upper_qual(List *qual, const char *qlabel, Plan *plan,
1197 StringInfo str, int indent, ExplainState *es)
1199 List *context;
1200 bool useprefix;
1201 Node *node;
1202 char *exprstr;
1203 int i;
1205 /* No work if empty qual */
1206 if (qual == NIL)
1207 return;
1209 /* Set up deparsing context */
1210 context = deparse_context_for_plan((Node *) plan,
1211 NULL,
1212 es->rtable,
1213 es->pstmt->subplans);
1214 useprefix = list_length(es->rtable) > 1;
1216 /* Deparse the expression */
1217 node = (Node *) make_ands_explicit(qual);
1218 exprstr = deparse_expression(node, context, useprefix, false);
1220 /* And add to str */
1221 for (i = 0; i < indent; i++)
1222 appendStringInfo(str, " ");
1223 appendStringInfo(str, " %s: %s\n", qlabel, exprstr);
1227 * Show the sort keys for a Sort node.
1229 static void
1230 show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
1231 const char *qlabel,
1232 StringInfo str, int indent, ExplainState *es)
1234 List *context;
1235 bool useprefix;
1236 int keyno;
1237 char *exprstr;
1238 int i;
1240 if (nkeys <= 0)
1241 return;
1243 for (i = 0; i < indent; i++)
1244 appendStringInfo(str, " ");
1245 appendStringInfo(str, " %s: ", qlabel);
1247 /* Set up deparsing context */
1248 context = deparse_context_for_plan((Node *) sortplan,
1249 NULL,
1250 es->rtable,
1251 es->pstmt->subplans);
1252 useprefix = list_length(es->rtable) > 1;
1254 for (keyno = 0; keyno < nkeys; keyno++)
1256 /* find key expression in tlist */
1257 AttrNumber keyresno = keycols[keyno];
1258 TargetEntry *target = get_tle_by_resno(sortplan->targetlist, keyresno);
1260 if (!target)
1261 elog(ERROR, "no tlist entry for key %d", keyresno);
1262 /* Deparse the expression, showing any top-level cast */
1263 exprstr = deparse_expression((Node *) target->expr, context,
1264 useprefix, true);
1265 /* And add to str */
1266 if (keyno > 0)
1267 appendStringInfo(str, ", ");
1268 appendStringInfoString(str, exprstr);
1271 appendStringInfo(str, "\n");
1275 * If it's EXPLAIN ANALYZE, show tuplesort explain info for a sort node
1277 static void
1278 show_sort_info(SortState *sortstate,
1279 StringInfo str, int indent, ExplainState *es)
1281 Assert(IsA(sortstate, SortState));
1282 if (es->printAnalyze && sortstate->sort_Done &&
1283 sortstate->tuplesortstate != NULL)
1285 char *sortinfo;
1286 int i;
1288 sortinfo = tuplesort_explain((Tuplesortstate *) sortstate->tuplesortstate);
1289 for (i = 0; i < indent; i++)
1290 appendStringInfo(str, " ");
1291 appendStringInfo(str, " %s\n", sortinfo);
1292 pfree(sortinfo);
1297 * Fetch the name of an index in an EXPLAIN
1299 * We allow plugins to get control here so that plans involving hypothetical
1300 * indexes can be explained.
1302 static const char *
1303 explain_get_index_name(Oid indexId)
1305 const char *result;
1307 if (explain_get_index_name_hook)
1308 result = (*explain_get_index_name_hook) (indexId);
1309 else
1310 result = NULL;
1311 if (result == NULL)
1313 /* default behavior: look in the catalogs and quote it */
1314 result = get_rel_name(indexId);
1315 if (result == NULL)
1316 elog(ERROR, "cache lookup failed for index %u", indexId);
1317 result = quote_identifier(result);
1319 return result;