OSDN Git Service

Update copyrights to 2003.
[pg-rex/syncrep.git] / src / backend / commands / explain.c
1 /*-------------------------------------------------------------------------
2  *
3  * explain.c
4  *        Explain query execution plans
5  *
6  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994-5, Regents of the University of California
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.113 2003/08/04 02:39:58 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15
16 #include "access/genam.h"
17 #include "access/heapam.h"
18 #include "catalog/pg_type.h"
19 #include "commands/explain.h"
20 #include "commands/prepare.h"
21 #include "executor/executor.h"
22 #include "executor/instrument.h"
23 #include "lib/stringinfo.h"
24 #include "nodes/print.h"
25 #include "optimizer/clauses.h"
26 #include "optimizer/planner.h"
27 #include "optimizer/var.h"
28 #include "parser/parsetree.h"
29 #include "rewrite/rewriteHandler.h"
30 #include "tcop/pquery.h"
31 #include "utils/builtins.h"
32 #include "utils/guc.h"
33 #include "utils/lsyscache.h"
34
35
36 typedef struct ExplainState
37 {
38         /* options */
39         bool            printCost;              /* print cost */
40         bool            printNodes;             /* do nodeToString() too */
41         bool            printAnalyze;   /* print actual times */
42         /* other states */
43         List       *rtable;                     /* range table */
44 } ExplainState;
45
46 static void ExplainOneQuery(Query *query, ExplainStmt *stmt,
47                                 TupOutputState *tstate);
48 static double elapsed_time(struct timeval * starttime);
49 static void explain_outNode(StringInfo str,
50                                 Plan *plan, PlanState * planstate,
51                                 Plan *outer_plan,
52                                 int indent, ExplainState *es);
53 static void show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
54                            int scanrelid, Plan *outer_plan,
55                            StringInfo str, int indent, ExplainState *es);
56 static void show_upper_qual(List *qual, const char *qlabel,
57                                 const char *outer_name, int outer_varno, Plan *outer_plan,
58                                 const char *inner_name, int inner_varno, Plan *inner_plan,
59                                 StringInfo str, int indent, ExplainState *es);
60 static void show_sort_keys(List *tlist, int nkeys, AttrNumber *keycols,
61                            const char *qlabel,
62                            StringInfo str, int indent, ExplainState *es);
63 static Node *make_ors_ands_explicit(List *orclauses);
64
65 /*
66  * ExplainQuery -
67  *        execute an EXPLAIN command
68  */
69 void
70 ExplainQuery(ExplainStmt *stmt, DestReceiver *dest)
71 {
72         Query      *query = stmt->query;
73         TupOutputState *tstate;
74         List       *rewritten;
75         List       *l;
76
77         /* prepare for projection of tuples */
78         tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt));
79
80         if (query->commandType == CMD_UTILITY)
81         {
82                 /* Rewriter will not cope with utility statements */
83                 if (query->utilityStmt && IsA(query->utilityStmt, DeclareCursorStmt))
84                         ExplainOneQuery(query, stmt, tstate);
85                 else if (query->utilityStmt && IsA(query->utilityStmt, ExecuteStmt))
86                         ExplainExecuteQuery(stmt, tstate);
87                 else
88                         do_text_output_oneline(tstate, "Utility statements have no plan structure");
89         }
90         else
91         {
92                 /* Rewrite through rule system */
93                 rewritten = QueryRewrite(query);
94
95                 if (rewritten == NIL)
96                 {
97                         /* In the case of an INSTEAD NOTHING, tell at least that */
98                         do_text_output_oneline(tstate, "Query rewrites to nothing");
99                 }
100                 else
101                 {
102                         /* Explain every plan */
103                         foreach(l, rewritten)
104                         {
105                                 ExplainOneQuery(lfirst(l), stmt, tstate);
106                                 /* put a blank line between plans */
107                                 if (lnext(l) != NIL)
108                                         do_text_output_oneline(tstate, "");
109                         }
110                 }
111         }
112
113         end_tup_output(tstate);
114 }
115
116 /*
117  * ExplainResultDesc -
118  *        construct the result tupledesc for an EXPLAIN
119  */
120 TupleDesc
121 ExplainResultDesc(ExplainStmt *stmt)
122 {
123         TupleDesc       tupdesc;
124
125         /* need a tuple descriptor representing a single TEXT column */
126         tupdesc = CreateTemplateTupleDesc(1, false);
127         TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
128                                            TEXTOID, -1, 0, false);
129         return tupdesc;
130 }
131
132 /*
133  * ExplainOneQuery -
134  *        print out the execution plan for one query
135  */
136 static void
137 ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
138 {
139         Plan       *plan;
140         QueryDesc  *queryDesc;
141         bool            isCursor = false;
142         int                     cursorOptions = 0;
143
144         /* planner will not cope with utility statements */
145         if (query->commandType == CMD_UTILITY)
146         {
147                 if (query->utilityStmt && IsA(query->utilityStmt, DeclareCursorStmt))
148                 {
149                         DeclareCursorStmt *dcstmt;
150                         List       *rewritten;
151
152                         dcstmt = (DeclareCursorStmt *) query->utilityStmt;
153                         query = (Query *) dcstmt->query;
154                         isCursor = true;
155                         cursorOptions = dcstmt->options;
156                         /* Still need to rewrite cursor command */
157                         Assert(query->commandType == CMD_SELECT);
158                         rewritten = QueryRewrite(query);
159                         if (length(rewritten) != 1)
160                                 elog(ERROR, "unexpected rewrite result");
161                         query = (Query *) lfirst(rewritten);
162                         Assert(query->commandType == CMD_SELECT);
163                         /* do not actually execute the underlying query! */
164                         stmt->analyze = false;
165                 }
166                 else if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
167                 {
168                         do_text_output_oneline(tstate, "NOTIFY");
169                         return;
170                 }
171                 else
172                 {
173                         do_text_output_oneline(tstate, "UTILITY");
174                         return;
175                 }
176         }
177
178         /* plan the query */
179         plan = planner(query, isCursor, cursorOptions);
180
181         /* Create a QueryDesc requesting no output */
182         queryDesc = CreateQueryDesc(query, plan, None_Receiver, NULL,
183                                                                 stmt->analyze);
184
185         ExplainOnePlan(queryDesc, stmt, tstate);
186 }
187
188 /*
189  * ExplainOnePlan -
190  *              given a planned query, execute it if needed, and then print
191  *              EXPLAIN output
192  *
193  * This is exported because it's called back from prepare.c in the
194  * EXPLAIN EXECUTE case
195  *
196  * Note: the passed-in QueryDesc is freed when we're done with it
197  */
198 void
199 ExplainOnePlan(QueryDesc *queryDesc, ExplainStmt *stmt,
200                            TupOutputState *tstate)
201 {
202         struct timeval starttime;
203         double          totaltime = 0;
204         ExplainState *es;
205         StringInfo      str;
206
207         gettimeofday(&starttime, NULL);
208
209         /* call ExecutorStart to prepare the plan for execution */
210         ExecutorStart(queryDesc, !stmt->analyze);
211
212         /* Execute the plan for statistics if asked for */
213         if (stmt->analyze)
214         {
215                 /* run the plan */
216                 ExecutorRun(queryDesc, ForwardScanDirection, 0L);
217
218                 /* We can't clean up 'till we're done printing the stats... */
219                 totaltime += elapsed_time(&starttime);
220         }
221
222         es = (ExplainState *) palloc0(sizeof(ExplainState));
223
224         es->printCost = true;           /* default */
225         es->printNodes = stmt->verbose;
226         es->printAnalyze = stmt->analyze;
227         es->rtable = queryDesc->parsetree->rtable;
228
229         if (es->printNodes)
230         {
231                 char       *s;
232                 char       *f;
233
234                 s = nodeToString(queryDesc->plantree);
235                 if (s)
236                 {
237                         if (Explain_pretty_print)
238                                 f = pretty_format_node_dump(s);
239                         else
240                                 f = format_node_dump(s);
241                         pfree(s);
242                         do_text_output_multiline(tstate, f);
243                         pfree(f);
244                         if (es->printCost)
245                                 do_text_output_oneline(tstate, "");             /* separator line */
246                 }
247         }
248
249         str = makeStringInfo();
250
251         if (es->printCost)
252         {
253                 explain_outNode(str, queryDesc->plantree, queryDesc->planstate,
254                                                 NULL, 0, es);
255         }
256
257         /*
258          * Close down the query and free resources.  Include time for this in
259          * the total runtime.
260          */
261         gettimeofday(&starttime, NULL);
262
263         ExecutorEnd(queryDesc);
264         FreeQueryDesc(queryDesc);
265
266         CommandCounterIncrement();
267
268         totaltime += elapsed_time(&starttime);
269
270         if (es->printCost)
271         {
272                 if (stmt->analyze)
273                         appendStringInfo(str, "Total runtime: %.2f msec\n",
274                                                          1000.0 * totaltime);
275                 do_text_output_multiline(tstate, str->data);
276         }
277
278         pfree(str->data);
279         pfree(str);
280         pfree(es);
281 }
282
283 /* Compute elapsed time in seconds since given gettimeofday() timestamp */
284 static double
285 elapsed_time(struct timeval * starttime)
286 {
287         struct timeval endtime;
288
289         gettimeofday(&endtime, NULL);
290
291         endtime.tv_sec -= starttime->tv_sec;
292         endtime.tv_usec -= starttime->tv_usec;
293         while (endtime.tv_usec < 0)
294         {
295                 endtime.tv_usec += 1000000;
296                 endtime.tv_sec--;
297         }
298         return (double) endtime.tv_sec +
299                 (double) endtime.tv_usec / 1000000.0;
300 }
301
302 /*
303  * explain_outNode -
304  *        converts a Plan node into ascii string and appends it to 'str'
305  *
306  * planstate points to the executor state node corresponding to the plan node.
307  * We need this to get at the instrumentation data (if any) as well as the
308  * list of subplans.
309  *
310  * outer_plan, if not null, references another plan node that is the outer
311  * side of a join with the current node.  This is only interesting for
312  * deciphering runtime keys of an inner indexscan.
313  */
314 static void
315 explain_outNode(StringInfo str,
316                                 Plan *plan, PlanState * planstate,
317                                 Plan *outer_plan,
318                                 int indent, ExplainState *es)
319 {
320         List       *l;
321         char       *pname;
322         int                     i;
323
324         if (plan == NULL)
325         {
326                 appendStringInfoChar(str, '\n');
327                 return;
328         }
329
330         switch (nodeTag(plan))
331         {
332                 case T_Result:
333                         pname = "Result";
334                         break;
335                 case T_Append:
336                         pname = "Append";
337                         break;
338                 case T_NestLoop:
339                         switch (((NestLoop *) plan)->join.jointype)
340                         {
341                                 case JOIN_INNER:
342                                         pname = "Nested Loop";
343                                         break;
344                                 case JOIN_LEFT:
345                                         pname = "Nested Loop Left Join";
346                                         break;
347                                 case JOIN_FULL:
348                                         pname = "Nested Loop Full Join";
349                                         break;
350                                 case JOIN_RIGHT:
351                                         pname = "Nested Loop Right Join";
352                                         break;
353                                 case JOIN_IN:
354                                         pname = "Nested Loop IN Join";
355                                         break;
356                                 default:
357                                         pname = "Nested Loop ??? Join";
358                                         break;
359                         }
360                         break;
361                 case T_MergeJoin:
362                         switch (((MergeJoin *) plan)->join.jointype)
363                         {
364                                 case JOIN_INNER:
365                                         pname = "Merge Join";
366                                         break;
367                                 case JOIN_LEFT:
368                                         pname = "Merge Left Join";
369                                         break;
370                                 case JOIN_FULL:
371                                         pname = "Merge Full Join";
372                                         break;
373                                 case JOIN_RIGHT:
374                                         pname = "Merge Right Join";
375                                         break;
376                                 case JOIN_IN:
377                                         pname = "Merge IN Join";
378                                         break;
379                                 default:
380                                         pname = "Merge ??? Join";
381                                         break;
382                         }
383                         break;
384                 case T_HashJoin:
385                         switch (((HashJoin *) plan)->join.jointype)
386                         {
387                                 case JOIN_INNER:
388                                         pname = "Hash Join";
389                                         break;
390                                 case JOIN_LEFT:
391                                         pname = "Hash Left Join";
392                                         break;
393                                 case JOIN_FULL:
394                                         pname = "Hash Full Join";
395                                         break;
396                                 case JOIN_RIGHT:
397                                         pname = "Hash Right Join";
398                                         break;
399                                 case JOIN_IN:
400                                         pname = "Hash IN Join";
401                                         break;
402                                 default:
403                                         pname = "Hash ??? Join";
404                                         break;
405                         }
406                         break;
407                 case T_SeqScan:
408                         pname = "Seq Scan";
409                         break;
410                 case T_IndexScan:
411                         pname = "Index Scan";
412                         break;
413                 case T_TidScan:
414                         pname = "Tid Scan";
415                         break;
416                 case T_SubqueryScan:
417                         pname = "Subquery Scan";
418                         break;
419                 case T_FunctionScan:
420                         pname = "Function Scan";
421                         break;
422                 case T_Material:
423                         pname = "Materialize";
424                         break;
425                 case T_Sort:
426                         pname = "Sort";
427                         break;
428                 case T_Group:
429                         pname = "Group";
430                         break;
431                 case T_Agg:
432                         switch (((Agg *) plan)->aggstrategy)
433                         {
434                                 case AGG_PLAIN:
435                                         pname = "Aggregate";
436                                         break;
437                                 case AGG_SORTED:
438                                         pname = "GroupAggregate";
439                                         break;
440                                 case AGG_HASHED:
441                                         pname = "HashAggregate";
442                                         break;
443                                 default:
444                                         pname = "Aggregate ???";
445                                         break;
446                         }
447                         break;
448                 case T_Unique:
449                         pname = "Unique";
450                         break;
451                 case T_SetOp:
452                         switch (((SetOp *) plan)->cmd)
453                         {
454                                 case SETOPCMD_INTERSECT:
455                                         pname = "SetOp Intersect";
456                                         break;
457                                 case SETOPCMD_INTERSECT_ALL:
458                                         pname = "SetOp Intersect All";
459                                         break;
460                                 case SETOPCMD_EXCEPT:
461                                         pname = "SetOp Except";
462                                         break;
463                                 case SETOPCMD_EXCEPT_ALL:
464                                         pname = "SetOp Except All";
465                                         break;
466                                 default:
467                                         pname = "SetOp ???";
468                                         break;
469                         }
470                         break;
471                 case T_Limit:
472                         pname = "Limit";
473                         break;
474                 case T_Hash:
475                         pname = "Hash";
476                         break;
477                 default:
478                         pname = "???";
479                         break;
480         }
481
482         appendStringInfoString(str, pname);
483         switch (nodeTag(plan))
484         {
485                 case T_IndexScan:
486                         if (ScanDirectionIsBackward(((IndexScan *) plan)->indxorderdir))
487                                 appendStringInfoString(str, " Backward");
488                         appendStringInfoString(str, " using ");
489                         i = 0;
490                         foreach(l, ((IndexScan *) plan)->indxid)
491                         {
492                                 Relation        relation;
493
494                                 relation = index_open(lfirsto(l));
495                                 appendStringInfo(str, "%s%s",
496                                                                  (++i > 1) ? ", " : "",
497                                         quote_identifier(RelationGetRelationName(relation)));
498                                 index_close(relation);
499                         }
500                         /* FALL THRU */
501                 case T_SeqScan:
502                 case T_TidScan:
503                         if (((Scan *) plan)->scanrelid > 0)
504                         {
505                                 RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
506                                                                                           es->rtable);
507                                 char       *relname;
508
509                                 /* Assume it's on a real relation */
510                                 Assert(rte->rtekind == RTE_RELATION);
511
512                                 /* We only show the rel name, not schema name */
513                                 relname = get_rel_name(rte->relid);
514
515                                 appendStringInfo(str, " on %s",
516                                                                  quote_identifier(relname));
517                                 if (strcmp(rte->eref->aliasname, relname) != 0)
518                                         appendStringInfo(str, " %s",
519                                                                  quote_identifier(rte->eref->aliasname));
520                         }
521                         break;
522                 case T_SubqueryScan:
523                         if (((Scan *) plan)->scanrelid > 0)
524                         {
525                                 RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
526                                                                                           es->rtable);
527
528                                 appendStringInfo(str, " %s",
529                                                                  quote_identifier(rte->eref->aliasname));
530                         }
531                         break;
532                 case T_FunctionScan:
533                         if (((Scan *) plan)->scanrelid > 0)
534                         {
535                                 RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
536                                                                                           es->rtable);
537                                 char       *proname;
538
539                                 /* Assert it's on a RangeFunction */
540                                 Assert(rte->rtekind == RTE_FUNCTION);
541
542                                 /*
543                                  * If the expression is still a function call, we can get
544                                  * the real name of the function.  Otherwise, punt (this
545                                  * can happen if the optimizer simplified away the
546                                  * function call, for example).
547                                  */
548                                 if (rte->funcexpr && IsA(rte->funcexpr, FuncExpr))
549                                 {
550                                         FuncExpr   *funcexpr = (FuncExpr *) rte->funcexpr;
551                                         Oid                     funcid = funcexpr->funcid;
552
553                                         /* We only show the func name, not schema name */
554                                         proname = get_func_name(funcid);
555                                 }
556                                 else
557                                         proname = rte->eref->aliasname;
558
559                                 appendStringInfo(str, " on %s",
560                                                                  quote_identifier(proname));
561                                 if (strcmp(rte->eref->aliasname, proname) != 0)
562                                         appendStringInfo(str, " %s",
563                                                                  quote_identifier(rte->eref->aliasname));
564                         }
565                         break;
566                 default:
567                         break;
568         }
569         if (es->printCost)
570         {
571                 appendStringInfo(str, "  (cost=%.2f..%.2f rows=%.0f width=%d)",
572                                                  plan->startup_cost, plan->total_cost,
573                                                  plan->plan_rows, plan->plan_width);
574
575                 /*
576                  * We have to forcibly clean up the instrumentation state because
577                  * we haven't done ExecutorEnd yet.  This is pretty grotty ...
578                  */
579                 InstrEndLoop(planstate->instrument);
580
581                 if (planstate->instrument && planstate->instrument->nloops > 0)
582                 {
583                         double          nloops = planstate->instrument->nloops;
584
585                         appendStringInfo(str, " (actual time=%.2f..%.2f rows=%.0f loops=%.0f)",
586                                                 1000.0 * planstate->instrument->startup / nloops,
587                                                   1000.0 * planstate->instrument->total / nloops,
588                                                          planstate->instrument->ntuples / nloops,
589                                                          planstate->instrument->nloops);
590                 }
591                 else if (es->printAnalyze)
592                         appendStringInfo(str, " (never executed)");
593         }
594         appendStringInfoChar(str, '\n');
595
596         /* quals, sort keys, etc */
597         switch (nodeTag(plan))
598         {
599                 case T_IndexScan:
600                         show_scan_qual(((IndexScan *) plan)->indxqualorig, true,
601                                                    "Index Cond",
602                                                    ((Scan *) plan)->scanrelid,
603                                                    outer_plan,
604                                                    str, indent, es);
605                         show_scan_qual(plan->qual, false,
606                                                    "Filter",
607                                                    ((Scan *) plan)->scanrelid,
608                                                    outer_plan,
609                                                    str, indent, es);
610                         break;
611                 case T_SeqScan:
612                 case T_TidScan:
613                 case T_SubqueryScan:
614                 case T_FunctionScan:
615                         show_scan_qual(plan->qual, false,
616                                                    "Filter",
617                                                    ((Scan *) plan)->scanrelid,
618                                                    outer_plan,
619                                                    str, indent, es);
620                         break;
621                 case T_NestLoop:
622                         show_upper_qual(((NestLoop *) plan)->join.joinqual,
623                                                         "Join Filter",
624                                                         "outer", OUTER, outerPlan(plan),
625                                                         "inner", INNER, innerPlan(plan),
626                                                         str, indent, es);
627                         show_upper_qual(plan->qual,
628                                                         "Filter",
629                                                         "outer", OUTER, outerPlan(plan),
630                                                         "inner", INNER, innerPlan(plan),
631                                                         str, indent, es);
632                         break;
633                 case T_MergeJoin:
634                         show_upper_qual(((MergeJoin *) plan)->mergeclauses,
635                                                         "Merge Cond",
636                                                         "outer", OUTER, outerPlan(plan),
637                                                         "inner", INNER, innerPlan(plan),
638                                                         str, indent, es);
639                         show_upper_qual(((MergeJoin *) plan)->join.joinqual,
640                                                         "Join Filter",
641                                                         "outer", OUTER, outerPlan(plan),
642                                                         "inner", INNER, innerPlan(plan),
643                                                         str, indent, es);
644                         show_upper_qual(plan->qual,
645                                                         "Filter",
646                                                         "outer", OUTER, outerPlan(plan),
647                                                         "inner", INNER, innerPlan(plan),
648                                                         str, indent, es);
649                         break;
650                 case T_HashJoin:
651                         show_upper_qual(((HashJoin *) plan)->hashclauses,
652                                                         "Hash Cond",
653                                                         "outer", OUTER, outerPlan(plan),
654                                                         "inner", INNER, innerPlan(plan),
655                                                         str, indent, es);
656                         show_upper_qual(((HashJoin *) plan)->join.joinqual,
657                                                         "Join Filter",
658                                                         "outer", OUTER, outerPlan(plan),
659                                                         "inner", INNER, innerPlan(plan),
660                                                         str, indent, es);
661                         show_upper_qual(plan->qual,
662                                                         "Filter",
663                                                         "outer", OUTER, outerPlan(plan),
664                                                         "inner", INNER, innerPlan(plan),
665                                                         str, indent, es);
666                         break;
667                 case T_Agg:
668                 case T_Group:
669                         show_upper_qual(plan->qual,
670                                                         "Filter",
671                                                         "subplan", 0, outerPlan(plan),
672                                                         "", 0, NULL,
673                                                         str, indent, es);
674                         break;
675                 case T_Sort:
676                         show_sort_keys(plan->targetlist,
677                                                    ((Sort *) plan)->numCols,
678                                                    ((Sort *) plan)->sortColIdx,
679                                                    "Sort Key",
680                                                    str, indent, es);
681                         break;
682                 case T_Result:
683                         show_upper_qual((List *) ((Result *) plan)->resconstantqual,
684                                                         "One-Time Filter",
685                                                         "subplan", OUTER, outerPlan(plan),
686                                                         "", 0, NULL,
687                                                         str, indent, es);
688                         show_upper_qual(plan->qual,
689                                                         "Filter",
690                                                         "subplan", OUTER, outerPlan(plan),
691                                                         "", 0, NULL,
692                                                         str, indent, es);
693                         break;
694                 default:
695                         break;
696         }
697
698         /* initPlan-s */
699         if (plan->initPlan)
700         {
701                 List       *saved_rtable = es->rtable;
702                 List       *lst;
703
704                 for (i = 0; i < indent; i++)
705                         appendStringInfo(str, "  ");
706                 appendStringInfo(str, "  InitPlan\n");
707                 foreach(lst, planstate->initPlan)
708                 {
709                         SubPlanState *sps = (SubPlanState *) lfirst(lst);
710                         SubPlan    *sp = (SubPlan *) sps->xprstate.expr;
711
712                         es->rtable = sp->rtable;
713                         for (i = 0; i < indent; i++)
714                                 appendStringInfo(str, "  ");
715                         appendStringInfo(str, "    ->  ");
716                         explain_outNode(str, sp->plan,
717                                                         sps->planstate,
718                                                         NULL,
719                                                         indent + 4, es);
720                 }
721                 es->rtable = saved_rtable;
722         }
723
724         /* lefttree */
725         if (outerPlan(plan))
726         {
727                 for (i = 0; i < indent; i++)
728                         appendStringInfo(str, "  ");
729                 appendStringInfo(str, "  ->  ");
730                 explain_outNode(str, outerPlan(plan),
731                                                 outerPlanState(planstate),
732                                                 NULL,
733                                                 indent + 3, es);
734         }
735
736         /* righttree */
737         if (innerPlan(plan))
738         {
739                 for (i = 0; i < indent; i++)
740                         appendStringInfo(str, "  ");
741                 appendStringInfo(str, "  ->  ");
742                 explain_outNode(str, innerPlan(plan),
743                                                 innerPlanState(planstate),
744                                                 outerPlan(plan),
745                                                 indent + 3, es);
746         }
747
748         if (IsA(plan, Append))
749         {
750                 Append     *appendplan = (Append *) plan;
751                 AppendState *appendstate = (AppendState *) planstate;
752                 List       *lst;
753                 int                     j;
754
755                 j = 0;
756                 foreach(lst, appendplan->appendplans)
757                 {
758                         Plan       *subnode = (Plan *) lfirst(lst);
759
760                         for (i = 0; i < indent; i++)
761                                 appendStringInfo(str, "  ");
762                         appendStringInfo(str, "  ->  ");
763
764                         explain_outNode(str, subnode,
765                                                         appendstate->appendplans[j],
766                                                         NULL,
767                                                         indent + 3, es);
768                         j++;
769                 }
770         }
771
772         if (IsA(plan, SubqueryScan))
773         {
774                 SubqueryScan *subqueryscan = (SubqueryScan *) plan;
775                 SubqueryScanState *subquerystate = (SubqueryScanState *) planstate;
776                 Plan       *subnode = subqueryscan->subplan;
777                 RangeTblEntry *rte = rt_fetch(subqueryscan->scan.scanrelid,
778                                                                           es->rtable);
779                 List       *saved_rtable = es->rtable;
780
781                 Assert(rte->rtekind == RTE_SUBQUERY);
782                 es->rtable = rte->subquery->rtable;
783
784                 for (i = 0; i < indent; i++)
785                         appendStringInfo(str, "  ");
786                 appendStringInfo(str, "  ->  ");
787
788                 explain_outNode(str, subnode,
789                                                 subquerystate->subplan,
790                                                 NULL,
791                                                 indent + 3, es);
792
793                 es->rtable = saved_rtable;
794         }
795
796         /* subPlan-s */
797         if (planstate->subPlan)
798         {
799                 List       *saved_rtable = es->rtable;
800                 List       *lst;
801
802                 for (i = 0; i < indent; i++)
803                         appendStringInfo(str, "  ");
804                 appendStringInfo(str, "  SubPlan\n");
805                 foreach(lst, planstate->subPlan)
806                 {
807                         SubPlanState *sps = (SubPlanState *) lfirst(lst);
808                         SubPlan    *sp = (SubPlan *) sps->xprstate.expr;
809
810                         es->rtable = sp->rtable;
811                         for (i = 0; i < indent; i++)
812                                 appendStringInfo(str, "  ");
813                         appendStringInfo(str, "    ->  ");
814                         explain_outNode(str, sp->plan,
815                                                         sps->planstate,
816                                                         NULL,
817                                                         indent + 4, es);
818                 }
819                 es->rtable = saved_rtable;
820         }
821 }
822
823 /*
824  * Show a qualifier expression for a scan plan node
825  */
826 static void
827 show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
828                            int scanrelid, Plan *outer_plan,
829                            StringInfo str, int indent, ExplainState *es)
830 {
831         RangeTblEntry *rte;
832         Node       *scancontext;
833         Node       *outercontext;
834         List       *context;
835         Node       *node;
836         char       *exprstr;
837         int                     i;
838
839         /* No work if empty qual */
840         if (qual == NIL)
841                 return;
842         if (is_or_qual)
843         {
844                 if (lfirst(qual) == NIL && lnext(qual) == NIL)
845                         return;
846         }
847
848         /* Fix qual --- indexqual requires different processing */
849         if (is_or_qual)
850                 node = make_ors_ands_explicit(qual);
851         else
852                 node = (Node *) make_ands_explicit(qual);
853
854         /* Generate deparse context */
855         Assert(scanrelid > 0 && scanrelid <= length(es->rtable));
856         rte = rt_fetch(scanrelid, es->rtable);
857         scancontext = deparse_context_for_rte(rte);
858
859         /*
860          * If we have an outer plan that is referenced by the qual, add it to
861          * the deparse context.  If not, don't (so that we don't force
862          * prefixes unnecessarily).
863          */
864         if (outer_plan)
865         {
866                 Relids          varnos = pull_varnos(node);
867
868                 if (bms_is_member(OUTER, varnos))
869                         outercontext = deparse_context_for_subplan("outer",
870                                                                                                   outer_plan->targetlist,
871                                                                                                            es->rtable);
872                 else
873                         outercontext = NULL;
874                 bms_free(varnos);
875         }
876         else
877                 outercontext = NULL;
878
879         context = deparse_context_for_plan(scanrelid, scancontext,
880                                                                            OUTER, outercontext,
881                                                                            NIL);
882
883         /* Deparse the expression */
884         exprstr = deparse_expression(node, context, (outercontext != NULL), false);
885
886         /* And add to str */
887         for (i = 0; i < indent; i++)
888                 appendStringInfo(str, "  ");
889         appendStringInfo(str, "  %s: %s\n", qlabel, exprstr);
890 }
891
892 /*
893  * Show a qualifier expression for an upper-level plan node
894  */
895 static void
896 show_upper_qual(List *qual, const char *qlabel,
897                                 const char *outer_name, int outer_varno, Plan *outer_plan,
898                                 const char *inner_name, int inner_varno, Plan *inner_plan,
899                                 StringInfo str, int indent, ExplainState *es)
900 {
901         List       *context;
902         Node       *outercontext;
903         Node       *innercontext;
904         Node       *node;
905         char       *exprstr;
906         int                     i;
907
908         /* No work if empty qual */
909         if (qual == NIL)
910                 return;
911
912         /* Generate deparse context */
913         if (outer_plan)
914                 outercontext = deparse_context_for_subplan(outer_name,
915                                                                                                    outer_plan->targetlist,
916                                                                                                    es->rtable);
917         else
918                 outercontext = NULL;
919         if (inner_plan)
920                 innercontext = deparse_context_for_subplan(inner_name,
921                                                                                                    inner_plan->targetlist,
922                                                                                                    es->rtable);
923         else
924                 innercontext = NULL;
925         context = deparse_context_for_plan(outer_varno, outercontext,
926                                                                            inner_varno, innercontext,
927                                                                            NIL);
928
929         /* Deparse the expression */
930         node = (Node *) make_ands_explicit(qual);
931         exprstr = deparse_expression(node, context, (inner_plan != NULL), false);
932
933         /* And add to str */
934         for (i = 0; i < indent; i++)
935                 appendStringInfo(str, "  ");
936         appendStringInfo(str, "  %s: %s\n", qlabel, exprstr);
937 }
938
939 /*
940  * Show the sort keys for a Sort node.
941  */
942 static void
943 show_sort_keys(List *tlist, int nkeys, AttrNumber *keycols,
944                            const char *qlabel,
945                            StringInfo str, int indent, ExplainState *es)
946 {
947         List       *context;
948         bool            useprefix;
949         int                     keyno;
950         List       *tl;
951         char       *exprstr;
952         Relids          varnos;
953         int                     i;
954
955         if (nkeys <= 0)
956                 return;
957
958         for (i = 0; i < indent; i++)
959                 appendStringInfo(str, "  ");
960         appendStringInfo(str, "  %s: ", qlabel);
961
962         /*
963          * In this routine we expect that the plan node's tlist has not been
964          * processed by set_plan_references().  Normally, any Vars will
965          * contain valid varnos referencing the actual rtable.  But we might
966          * instead be looking at a dummy tlist generated by prepunion.c; if
967          * there are Vars with zero varno, use the tlist itself to determine
968          * their names.
969          */
970         varnos = pull_varnos((Node *) tlist);
971         if (bms_is_member(0, varnos))
972         {
973                 Node       *outercontext;
974
975                 outercontext = deparse_context_for_subplan("sort",
976                                                                                                    tlist,
977                                                                                                    es->rtable);
978                 context = deparse_context_for_plan(0, outercontext,
979                                                                                    0, NULL,
980                                                                                    NIL);
981                 useprefix = false;
982         }
983         else
984         {
985                 context = deparse_context_for_plan(0, NULL,
986                                                                                    0, NULL,
987                                                                                    es->rtable);
988                 useprefix = length(es->rtable) > 1;
989         }
990         bms_free(varnos);
991
992         for (keyno = 0; keyno < nkeys; keyno++)
993         {
994                 /* find key expression in tlist */
995                 AttrNumber      keyresno = keycols[keyno];
996
997                 foreach(tl, tlist)
998                 {
999                         TargetEntry *target = (TargetEntry *) lfirst(tl);
1000
1001                         if (target->resdom->resno == keyresno)
1002                         {
1003                                 /* Deparse the expression, showing any top-level cast */
1004                                 exprstr = deparse_expression((Node *) target->expr, context,
1005                                                                                          useprefix, true);
1006                                 /* And add to str */
1007                                 if (keyno > 0)
1008                                         appendStringInfo(str, ", ");
1009                                 appendStringInfo(str, "%s", exprstr);
1010                                 break;
1011                         }
1012                 }
1013                 if (tl == NIL)
1014                         elog(ERROR, "no tlist entry for key %d", keyresno);
1015         }
1016
1017         appendStringInfo(str, "\n");
1018 }
1019
1020 /*
1021  * Indexscan qual lists have an implicit OR-of-ANDs structure.  Make it
1022  * explicit so deparsing works properly.
1023  */
1024 static Node *
1025 make_ors_ands_explicit(List *orclauses)
1026 {
1027         if (orclauses == NIL)
1028                 return NULL;                    /* probably can't happen */
1029         else if (lnext(orclauses) == NIL)
1030                 return (Node *) make_ands_explicit(lfirst(orclauses));
1031         else
1032         {
1033                 FastList        args;
1034                 List       *orptr;
1035
1036                 FastListInit(&args);
1037                 foreach(orptr, orclauses)
1038                         FastAppend(&args, make_ands_explicit(lfirst(orptr)));
1039
1040                 return (Node *) make_orclause(FastListValue(&args));
1041         }
1042 }