Disallow empty passwords in LDAP authentication, the same way
[PostgreSQL.git] / src / backend / commands / explain.c
blob950a2f1d75fe4820a31eb6fb6dd8ea32bfdcaecc
1 /*-------------------------------------------------------------------------
3 * explain.c
4 * Explain query execution plans
6 * Portions Copyright (c) 1996-2009, 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, stmt, queryString, params, 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, ExplainStmt *stmt,
222 const char *queryString, ParamListInfo params,
223 TupOutputState *tstate)
225 QueryDesc *queryDesc;
226 instr_time starttime;
227 double totaltime = 0;
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, queryString,
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 /* Create textual dump of plan tree */
269 initStringInfo(&buf);
270 ExplainPrintPlan(&buf, queryDesc, stmt->analyze, stmt->verbose);
273 * If we ran the command, run any AFTER triggers it queued. (Note this
274 * will not include DEFERRED triggers; since those don't run until end of
275 * transaction, we can't measure them.) Include into total runtime.
277 if (stmt->analyze)
279 INSTR_TIME_SET_CURRENT(starttime);
280 AfterTriggerEndQuery(queryDesc->estate);
281 totaltime += elapsed_time(&starttime);
284 /* Print info about runtime of triggers */
285 if (stmt->analyze)
287 ResultRelInfo *rInfo;
288 bool show_relname;
289 int numrels = queryDesc->estate->es_num_result_relations;
290 List *targrels = queryDesc->estate->es_trig_target_relations;
291 int nr;
292 ListCell *l;
294 show_relname = (numrels > 1 || targrels != NIL);
295 rInfo = queryDesc->estate->es_result_relations;
296 for (nr = 0; nr < numrels; rInfo++, nr++)
297 report_triggers(rInfo, show_relname, &buf);
299 foreach(l, targrels)
301 rInfo = (ResultRelInfo *) lfirst(l);
302 report_triggers(rInfo, show_relname, &buf);
307 * Close down the query and free resources. Include time for this in the
308 * total runtime (although it should be pretty minimal).
310 INSTR_TIME_SET_CURRENT(starttime);
312 ExecutorEnd(queryDesc);
314 FreeQueryDesc(queryDesc);
316 PopActiveSnapshot();
318 /* We need a CCI just in case query expanded to multiple plans */
319 if (stmt->analyze)
320 CommandCounterIncrement();
322 totaltime += elapsed_time(&starttime);
324 if (stmt->analyze)
325 appendStringInfo(&buf, "Total runtime: %.3f ms\n",
326 1000.0 * totaltime);
327 do_text_output_multiline(tstate, buf.data);
329 pfree(buf.data);
333 * ExplainPrintPlan -
334 * convert a QueryDesc's plan tree to text and append it to 'str'
336 * 'analyze' means to include runtime instrumentation results
337 * 'verbose' means a verbose printout (currently, it shows targetlists)
339 * NB: will not work on utility statements
341 void
342 ExplainPrintPlan(StringInfo str, QueryDesc *queryDesc,
343 bool analyze, bool verbose)
345 ExplainState es;
347 Assert(queryDesc->plannedstmt != NULL);
349 memset(&es, 0, sizeof(es));
350 es.printTList = verbose;
351 es.printAnalyze = analyze;
352 es.pstmt = queryDesc->plannedstmt;
353 es.rtable = queryDesc->plannedstmt->rtable;
355 explain_outNode(str,
356 queryDesc->plannedstmt->planTree, queryDesc->planstate,
357 NULL, 0, &es);
361 * report_triggers -
362 * report execution stats for a single relation's triggers
364 static void
365 report_triggers(ResultRelInfo *rInfo, bool show_relname, StringInfo buf)
367 int nt;
369 if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
370 return;
371 for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
373 Trigger *trig = rInfo->ri_TrigDesc->triggers + nt;
374 Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
375 char *conname;
377 /* Must clean up instrumentation state */
378 InstrEndLoop(instr);
381 * We ignore triggers that were never invoked; they likely aren't
382 * relevant to the current query type.
384 if (instr->ntuples == 0)
385 continue;
387 if (OidIsValid(trig->tgconstraint) &&
388 (conname = get_constraint_name(trig->tgconstraint)) != NULL)
390 appendStringInfo(buf, "Trigger for constraint %s", conname);
391 pfree(conname);
393 else
394 appendStringInfo(buf, "Trigger %s", trig->tgname);
396 if (show_relname)
397 appendStringInfo(buf, " on %s",
398 RelationGetRelationName(rInfo->ri_RelationDesc));
400 appendStringInfo(buf, ": time=%.3f calls=%.0f\n",
401 1000.0 * instr->total, instr->ntuples);
405 /* Compute elapsed time in seconds since given timestamp */
406 static double
407 elapsed_time(instr_time *starttime)
409 instr_time endtime;
411 INSTR_TIME_SET_CURRENT(endtime);
412 INSTR_TIME_SUBTRACT(endtime, *starttime);
413 return INSTR_TIME_GET_DOUBLE(endtime);
417 * explain_outNode -
418 * converts a Plan node into ascii string and appends it to 'str'
420 * planstate points to the executor state node corresponding to the plan node.
421 * We need this to get at the instrumentation data (if any) as well as the
422 * list of subplans.
424 * outer_plan, if not null, references another plan node that is the outer
425 * side of a join with the current node. This is only interesting for
426 * deciphering runtime keys of an inner indexscan.
428 static void
429 explain_outNode(StringInfo str,
430 Plan *plan, PlanState *planstate,
431 Plan *outer_plan,
432 int indent, ExplainState *es)
434 const char *pname;
435 int i;
437 if (plan == NULL)
439 appendStringInfoChar(str, '\n');
440 return;
443 switch (nodeTag(plan))
445 case T_Result:
446 pname = "Result";
447 break;
448 case T_Append:
449 pname = "Append";
450 break;
451 case T_RecursiveUnion:
452 pname = "Recursive Union";
453 break;
454 case T_BitmapAnd:
455 pname = "BitmapAnd";
456 break;
457 case T_BitmapOr:
458 pname = "BitmapOr";
459 break;
460 case T_NestLoop:
461 switch (((NestLoop *) plan)->join.jointype)
463 case JOIN_INNER:
464 pname = "Nested Loop";
465 break;
466 case JOIN_LEFT:
467 pname = "Nested Loop Left Join";
468 break;
469 case JOIN_FULL:
470 pname = "Nested Loop Full Join";
471 break;
472 case JOIN_RIGHT:
473 pname = "Nested Loop Right Join";
474 break;
475 case JOIN_SEMI:
476 pname = "Nested Loop Semi Join";
477 break;
478 case JOIN_ANTI:
479 pname = "Nested Loop Anti Join";
480 break;
481 default:
482 pname = "Nested Loop ??? Join";
483 break;
485 break;
486 case T_MergeJoin:
487 switch (((MergeJoin *) plan)->join.jointype)
489 case JOIN_INNER:
490 pname = "Merge Join";
491 break;
492 case JOIN_LEFT:
493 pname = "Merge Left Join";
494 break;
495 case JOIN_FULL:
496 pname = "Merge Full Join";
497 break;
498 case JOIN_RIGHT:
499 pname = "Merge Right Join";
500 break;
501 case JOIN_SEMI:
502 pname = "Merge Semi Join";
503 break;
504 case JOIN_ANTI:
505 pname = "Merge Anti Join";
506 break;
507 default:
508 pname = "Merge ??? Join";
509 break;
511 break;
512 case T_HashJoin:
513 switch (((HashJoin *) plan)->join.jointype)
515 case JOIN_INNER:
516 pname = "Hash Join";
517 break;
518 case JOIN_LEFT:
519 pname = "Hash Left Join";
520 break;
521 case JOIN_FULL:
522 pname = "Hash Full Join";
523 break;
524 case JOIN_RIGHT:
525 pname = "Hash Right Join";
526 break;
527 case JOIN_SEMI:
528 pname = "Hash Semi Join";
529 break;
530 case JOIN_ANTI:
531 pname = "Hash Anti Join";
532 break;
533 default:
534 pname = "Hash ??? Join";
535 break;
537 break;
538 case T_SeqScan:
539 pname = "Seq Scan";
540 break;
541 case T_IndexScan:
542 pname = "Index Scan";
543 break;
544 case T_BitmapIndexScan:
545 pname = "Bitmap Index Scan";
546 break;
547 case T_BitmapHeapScan:
548 pname = "Bitmap Heap Scan";
549 break;
550 case T_TidScan:
551 pname = "Tid Scan";
552 break;
553 case T_SubqueryScan:
554 pname = "Subquery Scan";
555 break;
556 case T_FunctionScan:
557 pname = "Function Scan";
558 break;
559 case T_ValuesScan:
560 pname = "Values Scan";
561 break;
562 case T_CteScan:
563 pname = "CTE Scan";
564 break;
565 case T_WorkTableScan:
566 pname = "WorkTable Scan";
567 break;
568 case T_Material:
569 pname = "Materialize";
570 break;
571 case T_Sort:
572 pname = "Sort";
573 break;
574 case T_Group:
575 pname = "Group";
576 break;
577 case T_Agg:
578 switch (((Agg *) plan)->aggstrategy)
580 case AGG_PLAIN:
581 pname = "Aggregate";
582 break;
583 case AGG_SORTED:
584 pname = "GroupAggregate";
585 break;
586 case AGG_HASHED:
587 pname = "HashAggregate";
588 break;
589 default:
590 pname = "Aggregate ???";
591 break;
593 break;
594 case T_WindowAgg:
595 pname = "WindowAgg";
596 break;
597 case T_Unique:
598 pname = "Unique";
599 break;
600 case T_SetOp:
601 switch (((SetOp *) plan)->strategy)
603 case SETOP_SORTED:
604 switch (((SetOp *) plan)->cmd)
606 case SETOPCMD_INTERSECT:
607 pname = "SetOp Intersect";
608 break;
609 case SETOPCMD_INTERSECT_ALL:
610 pname = "SetOp Intersect All";
611 break;
612 case SETOPCMD_EXCEPT:
613 pname = "SetOp Except";
614 break;
615 case SETOPCMD_EXCEPT_ALL:
616 pname = "SetOp Except All";
617 break;
618 default:
619 pname = "SetOp ???";
620 break;
622 break;
623 case SETOP_HASHED:
624 switch (((SetOp *) plan)->cmd)
626 case SETOPCMD_INTERSECT:
627 pname = "HashSetOp Intersect";
628 break;
629 case SETOPCMD_INTERSECT_ALL:
630 pname = "HashSetOp Intersect All";
631 break;
632 case SETOPCMD_EXCEPT:
633 pname = "HashSetOp Except";
634 break;
635 case SETOPCMD_EXCEPT_ALL:
636 pname = "HashSetOp Except All";
637 break;
638 default:
639 pname = "HashSetOp ???";
640 break;
642 break;
643 default:
644 pname = "SetOp ???";
645 break;
647 break;
648 case T_Limit:
649 pname = "Limit";
650 break;
651 case T_Hash:
652 pname = "Hash";
653 break;
654 default:
655 pname = "???";
656 break;
659 appendStringInfoString(str, pname);
660 switch (nodeTag(plan))
662 case T_IndexScan:
663 if (ScanDirectionIsBackward(((IndexScan *) plan)->indexorderdir))
664 appendStringInfoString(str, " Backward");
665 appendStringInfo(str, " using %s",
666 explain_get_index_name(((IndexScan *) plan)->indexid));
667 /* FALL THRU */
668 case T_SeqScan:
669 case T_BitmapHeapScan:
670 case T_TidScan:
671 if (((Scan *) plan)->scanrelid > 0)
673 RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
674 es->rtable);
675 char *relname;
677 /* Assume it's on a real relation */
678 Assert(rte->rtekind == RTE_RELATION);
680 /* We only show the rel name, not schema name */
681 relname = get_rel_name(rte->relid);
683 appendStringInfo(str, " on %s",
684 quote_identifier(relname));
685 if (strcmp(rte->eref->aliasname, relname) != 0)
686 appendStringInfo(str, " %s",
687 quote_identifier(rte->eref->aliasname));
689 break;
690 case T_BitmapIndexScan:
691 appendStringInfo(str, " on %s",
692 explain_get_index_name(((BitmapIndexScan *) plan)->indexid));
693 break;
694 case T_SubqueryScan:
695 if (((Scan *) plan)->scanrelid > 0)
697 RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
698 es->rtable);
700 appendStringInfo(str, " %s",
701 quote_identifier(rte->eref->aliasname));
703 break;
704 case T_FunctionScan:
705 if (((Scan *) plan)->scanrelid > 0)
707 RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
708 es->rtable);
709 Node *funcexpr;
710 char *proname;
712 /* Assert it's on a RangeFunction */
713 Assert(rte->rtekind == RTE_FUNCTION);
716 * If the expression is still a function call, we can get the
717 * real name of the function. Otherwise, punt (this can
718 * happen if the optimizer simplified away the function call,
719 * for example).
721 funcexpr = ((FunctionScan *) plan)->funcexpr;
722 if (funcexpr && IsA(funcexpr, FuncExpr))
724 Oid funcid = ((FuncExpr *) funcexpr)->funcid;
726 /* We only show the func name, not schema name */
727 proname = get_func_name(funcid);
729 else
730 proname = rte->eref->aliasname;
732 appendStringInfo(str, " on %s",
733 quote_identifier(proname));
734 if (strcmp(rte->eref->aliasname, proname) != 0)
735 appendStringInfo(str, " %s",
736 quote_identifier(rte->eref->aliasname));
738 break;
739 case T_ValuesScan:
740 if (((Scan *) plan)->scanrelid > 0)
742 RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
743 es->rtable);
744 char *valsname;
746 /* Assert it's on a values rte */
747 Assert(rte->rtekind == RTE_VALUES);
749 valsname = rte->eref->aliasname;
751 appendStringInfo(str, " on %s",
752 quote_identifier(valsname));
754 break;
755 case T_CteScan:
756 if (((Scan *) plan)->scanrelid > 0)
758 RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
759 es->rtable);
761 /* Assert it's on a non-self-reference CTE */
762 Assert(rte->rtekind == RTE_CTE);
763 Assert(!rte->self_reference);
765 appendStringInfo(str, " on %s",
766 quote_identifier(rte->ctename));
767 if (strcmp(rte->eref->aliasname, rte->ctename) != 0)
768 appendStringInfo(str, " %s",
769 quote_identifier(rte->eref->aliasname));
771 break;
772 case T_WorkTableScan:
773 if (((Scan *) plan)->scanrelid > 0)
775 RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
776 es->rtable);
778 /* Assert it's on a self-reference CTE */
779 Assert(rte->rtekind == RTE_CTE);
780 Assert(rte->self_reference);
782 appendStringInfo(str, " on %s",
783 quote_identifier(rte->ctename));
784 if (strcmp(rte->eref->aliasname, rte->ctename) != 0)
785 appendStringInfo(str, " %s",
786 quote_identifier(rte->eref->aliasname));
788 break;
789 default:
790 break;
793 appendStringInfo(str, " (cost=%.2f..%.2f rows=%.0f width=%d)",
794 plan->startup_cost, plan->total_cost,
795 plan->plan_rows, plan->plan_width);
798 * We have to forcibly clean up the instrumentation state because we
799 * haven't done ExecutorEnd yet. This is pretty grotty ...
801 if (planstate->instrument)
802 InstrEndLoop(planstate->instrument);
804 if (planstate->instrument && planstate->instrument->nloops > 0)
806 double nloops = planstate->instrument->nloops;
808 appendStringInfo(str, " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",
809 1000.0 * planstate->instrument->startup / nloops,
810 1000.0 * planstate->instrument->total / nloops,
811 planstate->instrument->ntuples / nloops,
812 planstate->instrument->nloops);
814 else if (es->printAnalyze)
815 appendStringInfo(str, " (never executed)");
816 appendStringInfoChar(str, '\n');
818 /* target list */
819 if (es->printTList)
820 show_plan_tlist(plan, str, indent, es);
822 /* quals, sort keys, etc */
823 switch (nodeTag(plan))
825 case T_IndexScan:
826 show_scan_qual(((IndexScan *) plan)->indexqualorig,
827 "Index Cond",
828 ((Scan *) plan)->scanrelid,
829 plan, outer_plan,
830 str, indent, es);
831 show_scan_qual(plan->qual,
832 "Filter",
833 ((Scan *) plan)->scanrelid,
834 plan, outer_plan,
835 str, indent, es);
836 break;
837 case T_BitmapIndexScan:
838 show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig,
839 "Index Cond",
840 ((Scan *) plan)->scanrelid,
841 plan, outer_plan,
842 str, indent, es);
843 break;
844 case T_BitmapHeapScan:
845 /* XXX do we want to show this in production? */
846 show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig,
847 "Recheck Cond",
848 ((Scan *) plan)->scanrelid,
849 plan, outer_plan,
850 str, indent, es);
851 /* FALL THRU */
852 case T_SeqScan:
853 case T_FunctionScan:
854 case T_ValuesScan:
855 case T_CteScan:
856 case T_WorkTableScan:
857 show_scan_qual(plan->qual,
858 "Filter",
859 ((Scan *) plan)->scanrelid,
860 plan, outer_plan,
861 str, indent, es);
862 break;
863 case T_SubqueryScan:
864 show_scan_qual(plan->qual,
865 "Filter",
866 ((Scan *) plan)->scanrelid,
867 plan, outer_plan,
868 str, indent, es);
869 break;
870 case T_TidScan:
873 * The tidquals list has OR semantics, so be sure to show it
874 * as an OR condition.
876 List *tidquals = ((TidScan *) plan)->tidquals;
878 if (list_length(tidquals) > 1)
879 tidquals = list_make1(make_orclause(tidquals));
880 show_scan_qual(tidquals,
881 "TID Cond",
882 ((Scan *) plan)->scanrelid,
883 plan, outer_plan,
884 str, indent, es);
885 show_scan_qual(plan->qual,
886 "Filter",
887 ((Scan *) plan)->scanrelid,
888 plan, outer_plan,
889 str, indent, es);
891 break;
892 case T_NestLoop:
893 show_upper_qual(((NestLoop *) 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_MergeJoin:
901 show_upper_qual(((MergeJoin *) plan)->mergeclauses,
902 "Merge Cond", plan,
903 str, indent, es);
904 show_upper_qual(((MergeJoin *) plan)->join.joinqual,
905 "Join Filter", plan,
906 str, indent, es);
907 show_upper_qual(plan->qual,
908 "Filter", plan,
909 str, indent, es);
910 break;
911 case T_HashJoin:
912 show_upper_qual(((HashJoin *) plan)->hashclauses,
913 "Hash Cond", plan,
914 str, indent, es);
915 show_upper_qual(((HashJoin *) plan)->join.joinqual,
916 "Join Filter", plan,
917 str, indent, es);
918 show_upper_qual(plan->qual,
919 "Filter", plan,
920 str, indent, es);
921 break;
922 case T_Agg:
923 case T_Group:
924 show_upper_qual(plan->qual,
925 "Filter", plan,
926 str, indent, es);
927 break;
928 case T_Sort:
929 show_sort_keys(plan,
930 ((Sort *) plan)->numCols,
931 ((Sort *) plan)->sortColIdx,
932 "Sort Key",
933 str, indent, es);
934 show_sort_info((SortState *) planstate,
935 str, indent, es);
936 break;
937 case T_Result:
938 show_upper_qual((List *) ((Result *) plan)->resconstantqual,
939 "One-Time Filter", plan,
940 str, indent, es);
941 show_upper_qual(plan->qual,
942 "Filter", plan,
943 str, indent, es);
944 break;
945 default:
946 break;
949 /* initPlan-s */
950 if (plan->initPlan)
952 ListCell *lst;
954 foreach(lst, planstate->initPlan)
956 SubPlanState *sps = (SubPlanState *) lfirst(lst);
957 SubPlan *sp = (SubPlan *) sps->xprstate.expr;
959 for (i = 0; i < indent; i++)
960 appendStringInfo(str, " ");
961 appendStringInfo(str, " %s\n", sp->plan_name);
962 for (i = 0; i < indent; i++)
963 appendStringInfo(str, " ");
964 appendStringInfo(str, " -> ");
965 explain_outNode(str,
966 exec_subplan_get_plan(es->pstmt, sp),
967 sps->planstate,
968 NULL,
969 indent + 4, es);
973 /* lefttree */
974 if (outerPlan(plan))
976 for (i = 0; i < indent; i++)
977 appendStringInfo(str, " ");
978 appendStringInfo(str, " -> ");
981 * Ordinarily we don't pass down our own outer_plan value to our child
982 * nodes, but in bitmap scan trees we must, since the bottom
983 * BitmapIndexScan nodes may have outer references.
985 explain_outNode(str, outerPlan(plan),
986 outerPlanState(planstate),
987 IsA(plan, BitmapHeapScan) ? outer_plan : NULL,
988 indent + 3, es);
991 /* righttree */
992 if (innerPlan(plan))
994 for (i = 0; i < indent; i++)
995 appendStringInfo(str, " ");
996 appendStringInfo(str, " -> ");
997 explain_outNode(str, innerPlan(plan),
998 innerPlanState(planstate),
999 outerPlan(plan),
1000 indent + 3, es);
1003 if (IsA(plan, Append))
1005 Append *appendplan = (Append *) plan;
1006 AppendState *appendstate = (AppendState *) planstate;
1007 ListCell *lst;
1008 int j;
1010 j = 0;
1011 foreach(lst, appendplan->appendplans)
1013 Plan *subnode = (Plan *) lfirst(lst);
1015 for (i = 0; i < indent; i++)
1016 appendStringInfo(str, " ");
1017 appendStringInfo(str, " -> ");
1020 * Ordinarily we don't pass down our own outer_plan value to our
1021 * child nodes, but in an Append we must, since we might be
1022 * looking at an appendrel indexscan with outer references from
1023 * the member scans.
1025 explain_outNode(str, subnode,
1026 appendstate->appendplans[j],
1027 outer_plan,
1028 indent + 3, es);
1029 j++;
1033 if (IsA(plan, BitmapAnd))
1035 BitmapAnd *bitmapandplan = (BitmapAnd *) plan;
1036 BitmapAndState *bitmapandstate = (BitmapAndState *) planstate;
1037 ListCell *lst;
1038 int j;
1040 j = 0;
1041 foreach(lst, bitmapandplan->bitmapplans)
1043 Plan *subnode = (Plan *) lfirst(lst);
1045 for (i = 0; i < indent; i++)
1046 appendStringInfo(str, " ");
1047 appendStringInfo(str, " -> ");
1049 explain_outNode(str, subnode,
1050 bitmapandstate->bitmapplans[j],
1051 outer_plan, /* pass down same outer plan */
1052 indent + 3, es);
1053 j++;
1057 if (IsA(plan, BitmapOr))
1059 BitmapOr *bitmaporplan = (BitmapOr *) plan;
1060 BitmapOrState *bitmaporstate = (BitmapOrState *) planstate;
1061 ListCell *lst;
1062 int j;
1064 j = 0;
1065 foreach(lst, bitmaporplan->bitmapplans)
1067 Plan *subnode = (Plan *) lfirst(lst);
1069 for (i = 0; i < indent; i++)
1070 appendStringInfo(str, " ");
1071 appendStringInfo(str, " -> ");
1073 explain_outNode(str, subnode,
1074 bitmaporstate->bitmapplans[j],
1075 outer_plan, /* pass down same outer plan */
1076 indent + 3, es);
1077 j++;
1081 if (IsA(plan, SubqueryScan))
1083 SubqueryScan *subqueryscan = (SubqueryScan *) plan;
1084 SubqueryScanState *subquerystate = (SubqueryScanState *) planstate;
1085 Plan *subnode = subqueryscan->subplan;
1087 for (i = 0; i < indent; i++)
1088 appendStringInfo(str, " ");
1089 appendStringInfo(str, " -> ");
1091 explain_outNode(str, subnode,
1092 subquerystate->subplan,
1093 NULL,
1094 indent + 3, es);
1097 /* subPlan-s */
1098 if (planstate->subPlan)
1100 ListCell *lst;
1102 foreach(lst, planstate->subPlan)
1104 SubPlanState *sps = (SubPlanState *) lfirst(lst);
1105 SubPlan *sp = (SubPlan *) sps->xprstate.expr;
1107 for (i = 0; i < indent; i++)
1108 appendStringInfo(str, " ");
1109 appendStringInfo(str, " %s\n", sp->plan_name);
1110 for (i = 0; i < indent; i++)
1111 appendStringInfo(str, " ");
1112 appendStringInfo(str, " -> ");
1113 explain_outNode(str,
1114 exec_subplan_get_plan(es->pstmt, sp),
1115 sps->planstate,
1116 NULL,
1117 indent + 4, es);
1123 * Show the targetlist of a plan node
1125 static void
1126 show_plan_tlist(Plan *plan,
1127 StringInfo str, int indent, ExplainState *es)
1129 List *context;
1130 bool useprefix;
1131 ListCell *lc;
1132 int i;
1134 /* No work if empty tlist (this occurs eg in bitmap indexscans) */
1135 if (plan->targetlist == NIL)
1136 return;
1137 /* The tlist of an Append isn't real helpful, so suppress it */
1138 if (IsA(plan, Append))
1139 return;
1140 /* Likewise for RecursiveUnion */
1141 if (IsA(plan, RecursiveUnion))
1142 return;
1144 /* Set up deparsing context */
1145 context = deparse_context_for_plan((Node *) plan,
1146 NULL,
1147 es->rtable,
1148 es->pstmt->subplans);
1149 useprefix = list_length(es->rtable) > 1;
1151 /* Emit line prefix */
1152 for (i = 0; i < indent; i++)
1153 appendStringInfo(str, " ");
1154 appendStringInfo(str, " Output: ");
1156 /* Deparse each non-junk result column */
1157 i = 0;
1158 foreach(lc, plan->targetlist)
1160 TargetEntry *tle = (TargetEntry *) lfirst(lc);
1162 if (tle->resjunk)
1163 continue;
1164 if (i++ > 0)
1165 appendStringInfo(str, ", ");
1166 appendStringInfoString(str,
1167 deparse_expression((Node *) tle->expr, context,
1168 useprefix, false));
1171 appendStringInfoChar(str, '\n');
1175 * Show a qualifier expression for a scan plan node
1177 * Note: outer_plan is the referent for any OUTER vars in the scan qual;
1178 * this would be the outer side of a nestloop plan. Pass NULL if none.
1180 static void
1181 show_scan_qual(List *qual, const char *qlabel,
1182 int scanrelid, Plan *scan_plan, Plan *outer_plan,
1183 StringInfo str, int indent, ExplainState *es)
1185 List *context;
1186 bool useprefix;
1187 Node *node;
1188 char *exprstr;
1189 int i;
1191 /* No work if empty qual */
1192 if (qual == NIL)
1193 return;
1195 /* Convert AND list to explicit AND */
1196 node = (Node *) make_ands_explicit(qual);
1198 /* Set up deparsing context */
1199 context = deparse_context_for_plan((Node *) scan_plan,
1200 (Node *) outer_plan,
1201 es->rtable,
1202 es->pstmt->subplans);
1203 useprefix = (outer_plan != NULL || IsA(scan_plan, SubqueryScan));
1205 /* Deparse the expression */
1206 exprstr = deparse_expression(node, context, useprefix, false);
1208 /* And add to str */
1209 for (i = 0; i < indent; i++)
1210 appendStringInfo(str, " ");
1211 appendStringInfo(str, " %s: %s\n", qlabel, exprstr);
1215 * Show a qualifier expression for an upper-level plan node
1217 static void
1218 show_upper_qual(List *qual, const char *qlabel, Plan *plan,
1219 StringInfo str, int indent, ExplainState *es)
1221 List *context;
1222 bool useprefix;
1223 Node *node;
1224 char *exprstr;
1225 int i;
1227 /* No work if empty qual */
1228 if (qual == NIL)
1229 return;
1231 /* Set up deparsing context */
1232 context = deparse_context_for_plan((Node *) plan,
1233 NULL,
1234 es->rtable,
1235 es->pstmt->subplans);
1236 useprefix = list_length(es->rtable) > 1;
1238 /* Deparse the expression */
1239 node = (Node *) make_ands_explicit(qual);
1240 exprstr = deparse_expression(node, context, useprefix, false);
1242 /* And add to str */
1243 for (i = 0; i < indent; i++)
1244 appendStringInfo(str, " ");
1245 appendStringInfo(str, " %s: %s\n", qlabel, exprstr);
1249 * Show the sort keys for a Sort node.
1251 static void
1252 show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
1253 const char *qlabel,
1254 StringInfo str, int indent, ExplainState *es)
1256 List *context;
1257 bool useprefix;
1258 int keyno;
1259 char *exprstr;
1260 int i;
1262 if (nkeys <= 0)
1263 return;
1265 for (i = 0; i < indent; i++)
1266 appendStringInfo(str, " ");
1267 appendStringInfo(str, " %s: ", qlabel);
1269 /* Set up deparsing context */
1270 context = deparse_context_for_plan((Node *) sortplan,
1271 NULL,
1272 es->rtable,
1273 es->pstmt->subplans);
1274 useprefix = list_length(es->rtable) > 1;
1276 for (keyno = 0; keyno < nkeys; keyno++)
1278 /* find key expression in tlist */
1279 AttrNumber keyresno = keycols[keyno];
1280 TargetEntry *target = get_tle_by_resno(sortplan->targetlist, keyresno);
1282 if (!target)
1283 elog(ERROR, "no tlist entry for key %d", keyresno);
1284 /* Deparse the expression, showing any top-level cast */
1285 exprstr = deparse_expression((Node *) target->expr, context,
1286 useprefix, true);
1287 /* And add to str */
1288 if (keyno > 0)
1289 appendStringInfo(str, ", ");
1290 appendStringInfoString(str, exprstr);
1293 appendStringInfo(str, "\n");
1297 * If it's EXPLAIN ANALYZE, show tuplesort explain info for a sort node
1299 static void
1300 show_sort_info(SortState *sortstate,
1301 StringInfo str, int indent, ExplainState *es)
1303 Assert(IsA(sortstate, SortState));
1304 if (es->printAnalyze && sortstate->sort_Done &&
1305 sortstate->tuplesortstate != NULL)
1307 char *sortinfo;
1308 int i;
1310 sortinfo = tuplesort_explain((Tuplesortstate *) sortstate->tuplesortstate);
1311 for (i = 0; i < indent; i++)
1312 appendStringInfo(str, " ");
1313 appendStringInfo(str, " %s\n", sortinfo);
1314 pfree(sortinfo);
1319 * Fetch the name of an index in an EXPLAIN
1321 * We allow plugins to get control here so that plans involving hypothetical
1322 * indexes can be explained.
1324 static const char *
1325 explain_get_index_name(Oid indexId)
1327 const char *result;
1329 if (explain_get_index_name_hook)
1330 result = (*explain_get_index_name_hook) (indexId);
1331 else
1332 result = NULL;
1333 if (result == NULL)
1335 /* default behavior: look in the catalogs and quote it */
1336 result = get_rel_name(indexId);
1337 if (result == NULL)
1338 elog(ERROR, "cache lookup failed for index %u", indexId);
1339 result = quote_identifier(result);
1341 return result;