Header And Logo

PostgreSQL
| The world's most advanced open source database.

explain.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * explain.c
00004  *    Explain query execution plans
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994-5, Regents of the University of California
00008  *
00009  * IDENTIFICATION
00010  *    src/backend/commands/explain.c
00011  *
00012  *-------------------------------------------------------------------------
00013  */
00014 #include "postgres.h"
00015 
00016 #include "access/xact.h"
00017 #include "catalog/pg_type.h"
00018 #include "commands/createas.h"
00019 #include "commands/defrem.h"
00020 #include "commands/prepare.h"
00021 #include "executor/hashjoin.h"
00022 #include "foreign/fdwapi.h"
00023 #include "optimizer/clauses.h"
00024 #include "parser/parsetree.h"
00025 #include "rewrite/rewriteHandler.h"
00026 #include "tcop/tcopprot.h"
00027 #include "utils/builtins.h"
00028 #include "utils/json.h"
00029 #include "utils/lsyscache.h"
00030 #include "utils/rel.h"
00031 #include "utils/snapmgr.h"
00032 #include "utils/tuplesort.h"
00033 #include "utils/xml.h"
00034 
00035 
00036 /* Hook for plugins to get control in ExplainOneQuery() */
00037 ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL;
00038 
00039 /* Hook for plugins to get control in explain_get_index_name() */
00040 explain_get_index_name_hook_type explain_get_index_name_hook = NULL;
00041 
00042 
00043 /* OR-able flags for ExplainXMLTag() */
00044 #define X_OPENING 0
00045 #define X_CLOSING 1
00046 #define X_CLOSE_IMMEDIATE 2
00047 #define X_NOWHITESPACE 4
00048 
00049 static void ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es,
00050                 const char *queryString, ParamListInfo params);
00051 static void report_triggers(ResultRelInfo *rInfo, bool show_relname,
00052                 ExplainState *es);
00053 static double elapsed_time(instr_time *starttime);
00054 static void ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used);
00055 static void ExplainPreScanMemberNodes(List *plans, PlanState **planstates,
00056                           Bitmapset **rels_used);
00057 static void ExplainPreScanSubPlans(List *plans, Bitmapset **rels_used);
00058 static void ExplainNode(PlanState *planstate, List *ancestors,
00059             const char *relationship, const char *plan_name,
00060             ExplainState *es);
00061 static void show_plan_tlist(PlanState *planstate, List *ancestors,
00062                 ExplainState *es);
00063 static void show_expression(Node *node, const char *qlabel,
00064                 PlanState *planstate, List *ancestors,
00065                 bool useprefix, ExplainState *es);
00066 static void show_qual(List *qual, const char *qlabel,
00067           PlanState *planstate, List *ancestors,
00068           bool useprefix, ExplainState *es);
00069 static void show_scan_qual(List *qual, const char *qlabel,
00070                PlanState *planstate, List *ancestors,
00071                ExplainState *es);
00072 static void show_upper_qual(List *qual, const char *qlabel,
00073                 PlanState *planstate, List *ancestors,
00074                 ExplainState *es);
00075 static void show_sort_keys(SortState *sortstate, List *ancestors,
00076                ExplainState *es);
00077 static void show_merge_append_keys(MergeAppendState *mstate, List *ancestors,
00078                        ExplainState *es);
00079 static void show_sort_keys_common(PlanState *planstate,
00080                       int nkeys, AttrNumber *keycols,
00081                       List *ancestors, ExplainState *es);
00082 static void show_sort_info(SortState *sortstate, ExplainState *es);
00083 static void show_hash_info(HashState *hashstate, ExplainState *es);
00084 static void show_instrumentation_count(const char *qlabel, int which,
00085                            PlanState *planstate, ExplainState *es);
00086 static void show_foreignscan_info(ForeignScanState *fsstate, ExplainState *es);
00087 static const char *explain_get_index_name(Oid indexId);
00088 static void ExplainIndexScanDetails(Oid indexid, ScanDirection indexorderdir,
00089                         ExplainState *es);
00090 static void ExplainScanTarget(Scan *plan, ExplainState *es);
00091 static void ExplainModifyTarget(ModifyTable *plan, ExplainState *es);
00092 static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es);
00093 static void show_modifytable_info(ModifyTableState *mtstate, ExplainState *es);
00094 static void ExplainMemberNodes(List *plans, PlanState **planstates,
00095                    List *ancestors, ExplainState *es);
00096 static void ExplainSubPlans(List *plans, List *ancestors,
00097                 const char *relationship, ExplainState *es);
00098 static void ExplainProperty(const char *qlabel, const char *value,
00099                 bool numeric, ExplainState *es);
00100 static void ExplainOpenGroup(const char *objtype, const char *labelname,
00101                  bool labeled, ExplainState *es);
00102 static void ExplainCloseGroup(const char *objtype, const char *labelname,
00103                   bool labeled, ExplainState *es);
00104 static void ExplainDummyGroup(const char *objtype, const char *labelname,
00105                   ExplainState *es);
00106 static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es);
00107 static void ExplainJSONLineEnding(ExplainState *es);
00108 static void ExplainYAMLLineStarting(ExplainState *es);
00109 static void escape_yaml(StringInfo buf, const char *str);
00110 
00111 
00112 
00113 /*
00114  * ExplainQuery -
00115  *    execute an EXPLAIN command
00116  */
00117 void
00118 ExplainQuery(ExplainStmt *stmt, const char *queryString,
00119              ParamListInfo params, DestReceiver *dest)
00120 {
00121     ExplainState es;
00122     TupOutputState *tstate;
00123     List       *rewritten;
00124     ListCell   *lc;
00125     bool        timing_set = false;
00126 
00127     /* Initialize ExplainState. */
00128     ExplainInitState(&es);
00129 
00130     /* Parse options list. */
00131     foreach(lc, stmt->options)
00132     {
00133         DefElem    *opt = (DefElem *) lfirst(lc);
00134 
00135         if (strcmp(opt->defname, "analyze") == 0)
00136             es.analyze = defGetBoolean(opt);
00137         else if (strcmp(opt->defname, "verbose") == 0)
00138             es.verbose = defGetBoolean(opt);
00139         else if (strcmp(opt->defname, "costs") == 0)
00140             es.costs = defGetBoolean(opt);
00141         else if (strcmp(opt->defname, "buffers") == 0)
00142             es.buffers = defGetBoolean(opt);
00143         else if (strcmp(opt->defname, "timing") == 0)
00144         {
00145             timing_set = true;
00146             es.timing = defGetBoolean(opt);
00147         }
00148         else if (strcmp(opt->defname, "format") == 0)
00149         {
00150             char       *p = defGetString(opt);
00151 
00152             if (strcmp(p, "text") == 0)
00153                 es.format = EXPLAIN_FORMAT_TEXT;
00154             else if (strcmp(p, "xml") == 0)
00155                 es.format = EXPLAIN_FORMAT_XML;
00156             else if (strcmp(p, "json") == 0)
00157                 es.format = EXPLAIN_FORMAT_JSON;
00158             else if (strcmp(p, "yaml") == 0)
00159                 es.format = EXPLAIN_FORMAT_YAML;
00160             else
00161                 ereport(ERROR,
00162                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00163                 errmsg("unrecognized value for EXPLAIN option \"%s\": \"%s\"",
00164                        opt->defname, p)));
00165         }
00166         else
00167             ereport(ERROR,
00168                     (errcode(ERRCODE_SYNTAX_ERROR),
00169                      errmsg("unrecognized EXPLAIN option \"%s\"",
00170                             opt->defname)));
00171     }
00172 
00173     if (es.buffers && !es.analyze)
00174         ereport(ERROR,
00175                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00176                  errmsg("EXPLAIN option BUFFERS requires ANALYZE")));
00177 
00178     /* if the timing was not set explicitly, set default value */
00179     es.timing = (timing_set) ? es.timing : es.analyze;
00180 
00181     /* check that timing is used with EXPLAIN ANALYZE */
00182     if (es.timing && !es.analyze)
00183         ereport(ERROR,
00184                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00185                  errmsg("EXPLAIN option TIMING requires ANALYZE")));
00186 
00187     /*
00188      * Parse analysis was done already, but we still have to run the rule
00189      * rewriter.  We do not do AcquireRewriteLocks: we assume the query either
00190      * came straight from the parser, or suitable locks were acquired by
00191      * plancache.c.
00192      *
00193      * Because the rewriter and planner tend to scribble on the input, we make
00194      * a preliminary copy of the source querytree.  This prevents problems in
00195      * the case that the EXPLAIN is in a portal or plpgsql function and is
00196      * executed repeatedly.  (See also the same hack in DECLARE CURSOR and
00197      * PREPARE.)  XXX FIXME someday.
00198      */
00199     Assert(IsA(stmt->query, Query));
00200     rewritten = QueryRewrite((Query *) copyObject(stmt->query));
00201 
00202     /* emit opening boilerplate */
00203     ExplainBeginOutput(&es);
00204 
00205     if (rewritten == NIL)
00206     {
00207         /*
00208          * In the case of an INSTEAD NOTHING, tell at least that.  But in
00209          * non-text format, the output is delimited, so this isn't necessary.
00210          */
00211         if (es.format == EXPLAIN_FORMAT_TEXT)
00212             appendStringInfoString(es.str, "Query rewrites to nothing\n");
00213     }
00214     else
00215     {
00216         ListCell   *l;
00217 
00218         /* Explain every plan */
00219         foreach(l, rewritten)
00220         {
00221             ExplainOneQuery((Query *) lfirst(l), NULL, &es,
00222                             queryString, params);
00223 
00224             /* Separate plans with an appropriate separator */
00225             if (lnext(l) != NULL)
00226                 ExplainSeparatePlans(&es);
00227         }
00228     }
00229 
00230     /* emit closing boilerplate */
00231     ExplainEndOutput(&es);
00232     Assert(es.indent == 0);
00233 
00234     /* output tuples */
00235     tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt));
00236     if (es.format == EXPLAIN_FORMAT_TEXT)
00237         do_text_output_multiline(tstate, es.str->data);
00238     else
00239         do_text_output_oneline(tstate, es.str->data);
00240     end_tup_output(tstate);
00241 
00242     pfree(es.str->data);
00243 }
00244 
00245 /*
00246  * Initialize ExplainState.
00247  */
00248 void
00249 ExplainInitState(ExplainState *es)
00250 {
00251     /* Set default options. */
00252     memset(es, 0, sizeof(ExplainState));
00253     es->costs = true;
00254     /* Prepare output buffer. */
00255     es->str = makeStringInfo();
00256 }
00257 
00258 /*
00259  * ExplainResultDesc -
00260  *    construct the result tupledesc for an EXPLAIN
00261  */
00262 TupleDesc
00263 ExplainResultDesc(ExplainStmt *stmt)
00264 {
00265     TupleDesc   tupdesc;
00266     ListCell   *lc;
00267     Oid         result_type = TEXTOID;
00268 
00269     /* Check for XML format option */
00270     foreach(lc, stmt->options)
00271     {
00272         DefElem    *opt = (DefElem *) lfirst(lc);
00273 
00274         if (strcmp(opt->defname, "format") == 0)
00275         {
00276             char       *p = defGetString(opt);
00277 
00278             if (strcmp(p, "xml") == 0)
00279                 result_type = XMLOID;
00280             else if (strcmp(p, "json") == 0)
00281                 result_type = JSONOID;
00282             else
00283                 result_type = TEXTOID;
00284             /* don't "break", as ExplainQuery will use the last value */
00285         }
00286     }
00287 
00288     /* Need a tuple descriptor representing a single TEXT or XML column */
00289     tupdesc = CreateTemplateTupleDesc(1, false);
00290     TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
00291                        result_type, -1, 0);
00292     return tupdesc;
00293 }
00294 
00295 /*
00296  * ExplainOneQuery -
00297  *    print out the execution plan for one Query
00298  *
00299  * "into" is NULL unless we are explaining the contents of a CreateTableAsStmt.
00300  */
00301 static void
00302 ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es,
00303                 const char *queryString, ParamListInfo params)
00304 {
00305     /* planner will not cope with utility statements */
00306     if (query->commandType == CMD_UTILITY)
00307     {
00308         ExplainOneUtility(query->utilityStmt, into, es, queryString, params);
00309         return;
00310     }
00311 
00312     /* if an advisor plugin is present, let it manage things */
00313     if (ExplainOneQuery_hook)
00314         (*ExplainOneQuery_hook) (query, into, es, queryString, params);
00315     else
00316     {
00317         PlannedStmt *plan;
00318 
00319         /* plan the query */
00320         plan = pg_plan_query(query, 0, params);
00321 
00322         /* run it (if needed) and produce output */
00323         ExplainOnePlan(plan, into, es, queryString, params);
00324     }
00325 }
00326 
00327 /*
00328  * ExplainOneUtility -
00329  *    print out the execution plan for one utility statement
00330  *    (In general, utility statements don't have plans, but there are some
00331  *    we treat as special cases)
00332  *
00333  * "into" is NULL unless we are explaining the contents of a CreateTableAsStmt.
00334  *
00335  * This is exported because it's called back from prepare.c in the
00336  * EXPLAIN EXECUTE case.
00337  */
00338 void
00339 ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es,
00340                   const char *queryString, ParamListInfo params)
00341 {
00342     if (utilityStmt == NULL)
00343         return;
00344 
00345     if (IsA(utilityStmt, CreateTableAsStmt))
00346     {
00347         /*
00348          * We have to rewrite the contained SELECT and then pass it back to
00349          * ExplainOneQuery.  It's probably not really necessary to copy the
00350          * contained parsetree another time, but let's be safe.
00351          */
00352         CreateTableAsStmt *ctas = (CreateTableAsStmt *) utilityStmt;
00353         List       *rewritten;
00354 
00355         Assert(IsA(ctas->query, Query));
00356         rewritten = QueryRewrite((Query *) copyObject(ctas->query));
00357         Assert(list_length(rewritten) == 1);
00358         ExplainOneQuery((Query *) linitial(rewritten), ctas->into, es,
00359                         queryString, params);
00360     }
00361     else if (IsA(utilityStmt, ExecuteStmt))
00362         ExplainExecuteQuery((ExecuteStmt *) utilityStmt, into, es,
00363                             queryString, params);
00364     else if (IsA(utilityStmt, NotifyStmt))
00365     {
00366         if (es->format == EXPLAIN_FORMAT_TEXT)
00367             appendStringInfoString(es->str, "NOTIFY\n");
00368         else
00369             ExplainDummyGroup("Notify", NULL, es);
00370     }
00371     else
00372     {
00373         if (es->format == EXPLAIN_FORMAT_TEXT)
00374             appendStringInfoString(es->str,
00375                               "Utility statements have no plan structure\n");
00376         else
00377             ExplainDummyGroup("Utility Statement", NULL, es);
00378     }
00379 }
00380 
00381 /*
00382  * ExplainOnePlan -
00383  *      given a planned query, execute it if needed, and then print
00384  *      EXPLAIN output
00385  *
00386  * "into" is NULL unless we are explaining the contents of a CreateTableAsStmt,
00387  * in which case executing the query should result in creating that table.
00388  *
00389  * Since we ignore any DeclareCursorStmt that might be attached to the query,
00390  * if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll actually run the
00391  * query.  This is different from pre-8.3 behavior but seems more useful than
00392  * not running the query.  No cursor will be created, however.
00393  *
00394  * This is exported because it's called back from prepare.c in the
00395  * EXPLAIN EXECUTE case, and because an index advisor plugin would need
00396  * to call it.
00397  */
00398 void
00399 ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
00400                const char *queryString, ParamListInfo params)
00401 {
00402     DestReceiver *dest;
00403     QueryDesc  *queryDesc;
00404     instr_time  starttime;
00405     double      totaltime = 0;
00406     int         eflags;
00407     int         instrument_option = 0;
00408 
00409     if (es->analyze && es->timing)
00410         instrument_option |= INSTRUMENT_TIMER;
00411     else if (es->analyze)
00412         instrument_option |= INSTRUMENT_ROWS;
00413 
00414     if (es->buffers)
00415         instrument_option |= INSTRUMENT_BUFFERS;
00416 
00417     INSTR_TIME_SET_CURRENT(starttime);
00418 
00419     /*
00420      * Use a snapshot with an updated command ID to ensure this query sees
00421      * results of any previously executed queries.
00422      */
00423     PushCopiedSnapshot(GetActiveSnapshot());
00424     UpdateActiveSnapshotCommandId();
00425 
00426     /*
00427      * Normally we discard the query's output, but if explaining CREATE TABLE
00428      * AS, we'd better use the appropriate tuple receiver.
00429      */
00430     if (into)
00431         dest = CreateIntoRelDestReceiver(into);
00432     else
00433         dest = None_Receiver;
00434 
00435     /* Create a QueryDesc for the query */
00436     queryDesc = CreateQueryDesc(plannedstmt, queryString,
00437                                 GetActiveSnapshot(), InvalidSnapshot,
00438                                 dest, params, instrument_option);
00439 
00440     /* Select execution options */
00441     if (es->analyze)
00442         eflags = 0;             /* default run-to-completion flags */
00443     else
00444         eflags = EXEC_FLAG_EXPLAIN_ONLY;
00445     if (into)
00446         eflags |= GetIntoRelEFlags(into);
00447 
00448     /* call ExecutorStart to prepare the plan for execution */
00449     ExecutorStart(queryDesc, eflags);
00450 
00451     /* Execute the plan for statistics if asked for */
00452     if (es->analyze)
00453     {
00454         ScanDirection dir;
00455 
00456         /* EXPLAIN ANALYZE CREATE TABLE AS WITH NO DATA is weird */
00457         if (into && into->skipData)
00458             dir = NoMovementScanDirection;
00459         else
00460             dir = ForwardScanDirection;
00461 
00462         /* run the plan */
00463         ExecutorRun(queryDesc, dir, 0L);
00464 
00465         /* run cleanup too */
00466         ExecutorFinish(queryDesc);
00467 
00468         /* We can't run ExecutorEnd 'till we're done printing the stats... */
00469         totaltime += elapsed_time(&starttime);
00470     }
00471 
00472     ExplainOpenGroup("Query", NULL, true, es);
00473 
00474     /* Create textual dump of plan tree */
00475     ExplainPrintPlan(es, queryDesc);
00476 
00477     /* Print info about runtime of triggers */
00478     if (es->analyze)
00479     {
00480         ResultRelInfo *rInfo;
00481         bool        show_relname;
00482         int         numrels = queryDesc->estate->es_num_result_relations;
00483         List       *targrels = queryDesc->estate->es_trig_target_relations;
00484         int         nr;
00485         ListCell   *l;
00486 
00487         ExplainOpenGroup("Triggers", "Triggers", false, es);
00488 
00489         show_relname = (numrels > 1 || targrels != NIL);
00490         rInfo = queryDesc->estate->es_result_relations;
00491         for (nr = 0; nr < numrels; rInfo++, nr++)
00492             report_triggers(rInfo, show_relname, es);
00493 
00494         foreach(l, targrels)
00495         {
00496             rInfo = (ResultRelInfo *) lfirst(l);
00497             report_triggers(rInfo, show_relname, es);
00498         }
00499 
00500         ExplainCloseGroup("Triggers", "Triggers", false, es);
00501     }
00502 
00503     /*
00504      * Close down the query and free resources.  Include time for this in the
00505      * total runtime (although it should be pretty minimal).
00506      */
00507     INSTR_TIME_SET_CURRENT(starttime);
00508 
00509     ExecutorEnd(queryDesc);
00510 
00511     FreeQueryDesc(queryDesc);
00512 
00513     PopActiveSnapshot();
00514 
00515     /* We need a CCI just in case query expanded to multiple plans */
00516     if (es->analyze)
00517         CommandCounterIncrement();
00518 
00519     totaltime += elapsed_time(&starttime);
00520 
00521     if (es->analyze)
00522     {
00523         if (es->format == EXPLAIN_FORMAT_TEXT)
00524             appendStringInfo(es->str, "Total runtime: %.3f ms\n",
00525                              1000.0 * totaltime);
00526         else
00527             ExplainPropertyFloat("Total Runtime", 1000.0 * totaltime,
00528                                  3, es);
00529     }
00530 
00531     ExplainCloseGroup("Query", NULL, true, es);
00532 }
00533 
00534 /*
00535  * ExplainPrintPlan -
00536  *    convert a QueryDesc's plan tree to text and append it to es->str
00537  *
00538  * The caller should have set up the options fields of *es, as well as
00539  * initializing the output buffer es->str.  Other fields in *es are
00540  * initialized here.
00541  *
00542  * NB: will not work on utility statements
00543  */
00544 void
00545 ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
00546 {
00547     Bitmapset  *rels_used = NULL;
00548 
00549     Assert(queryDesc->plannedstmt != NULL);
00550     es->pstmt = queryDesc->plannedstmt;
00551     es->rtable = queryDesc->plannedstmt->rtable;
00552     ExplainPreScanNode(queryDesc->planstate, &rels_used);
00553     es->rtable_names = select_rtable_names_for_explain(es->rtable, rels_used);
00554     ExplainNode(queryDesc->planstate, NIL, NULL, NULL, es);
00555 }
00556 
00557 /*
00558  * ExplainQueryText -
00559  *    add a "Query Text" node that contains the actual text of the query
00560  *
00561  * The caller should have set up the options fields of *es, as well as
00562  * initializing the output buffer es->str.
00563  *
00564  */
00565 void
00566 ExplainQueryText(ExplainState *es, QueryDesc *queryDesc)
00567 {
00568     if (queryDesc->sourceText)
00569         ExplainPropertyText("Query Text", queryDesc->sourceText, es);
00570 }
00571 
00572 /*
00573  * report_triggers -
00574  *      report execution stats for a single relation's triggers
00575  */
00576 static void
00577 report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
00578 {
00579     int         nt;
00580 
00581     if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
00582         return;
00583     for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
00584     {
00585         Trigger    *trig = rInfo->ri_TrigDesc->triggers + nt;
00586         Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
00587         char       *relname;
00588         char       *conname = NULL;
00589 
00590         /* Must clean up instrumentation state */
00591         InstrEndLoop(instr);
00592 
00593         /*
00594          * We ignore triggers that were never invoked; they likely aren't
00595          * relevant to the current query type.
00596          */
00597         if (instr->ntuples == 0)
00598             continue;
00599 
00600         ExplainOpenGroup("Trigger", NULL, true, es);
00601 
00602         relname = RelationGetRelationName(rInfo->ri_RelationDesc);
00603         if (OidIsValid(trig->tgconstraint))
00604             conname = get_constraint_name(trig->tgconstraint);
00605 
00606         /*
00607          * In text format, we avoid printing both the trigger name and the
00608          * constraint name unless VERBOSE is specified.  In non-text formats
00609          * we just print everything.
00610          */
00611         if (es->format == EXPLAIN_FORMAT_TEXT)
00612         {
00613             if (es->verbose || conname == NULL)
00614                 appendStringInfo(es->str, "Trigger %s", trig->tgname);
00615             else
00616                 appendStringInfoString(es->str, "Trigger");
00617             if (conname)
00618                 appendStringInfo(es->str, " for constraint %s", conname);
00619             if (show_relname)
00620                 appendStringInfo(es->str, " on %s", relname);
00621             appendStringInfo(es->str, ": time=%.3f calls=%.0f\n",
00622                              1000.0 * instr->total, instr->ntuples);
00623         }
00624         else
00625         {
00626             ExplainPropertyText("Trigger Name", trig->tgname, es);
00627             if (conname)
00628                 ExplainPropertyText("Constraint Name", conname, es);
00629             ExplainPropertyText("Relation", relname, es);
00630             ExplainPropertyFloat("Time", 1000.0 * instr->total, 3, es);
00631             ExplainPropertyFloat("Calls", instr->ntuples, 0, es);
00632         }
00633 
00634         if (conname)
00635             pfree(conname);
00636 
00637         ExplainCloseGroup("Trigger", NULL, true, es);
00638     }
00639 }
00640 
00641 /* Compute elapsed time in seconds since given timestamp */
00642 static double
00643 elapsed_time(instr_time *starttime)
00644 {
00645     instr_time  endtime;
00646 
00647     INSTR_TIME_SET_CURRENT(endtime);
00648     INSTR_TIME_SUBTRACT(endtime, *starttime);
00649     return INSTR_TIME_GET_DOUBLE(endtime);
00650 }
00651 
00652 /*
00653  * ExplainPreScanNode -
00654  *    Prescan the planstate tree to identify which RTEs are referenced
00655  *
00656  * Adds the relid of each referenced RTE to *rels_used.  The result controls
00657  * which RTEs are assigned aliases by select_rtable_names_for_explain.
00658  * This ensures that we don't confusingly assign un-suffixed aliases to RTEs
00659  * that never appear in the EXPLAIN output (such as inheritance parents).
00660  */
00661 static void
00662 ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
00663 {
00664     Plan       *plan = planstate->plan;
00665 
00666     switch (nodeTag(plan))
00667     {
00668         case T_SeqScan:
00669         case T_IndexScan:
00670         case T_IndexOnlyScan:
00671         case T_BitmapHeapScan:
00672         case T_TidScan:
00673         case T_SubqueryScan:
00674         case T_FunctionScan:
00675         case T_ValuesScan:
00676         case T_CteScan:
00677         case T_WorkTableScan:
00678         case T_ForeignScan:
00679             *rels_used = bms_add_member(*rels_used,
00680                                         ((Scan *) plan)->scanrelid);
00681             break;
00682         case T_ModifyTable:
00683             /* cf ExplainModifyTarget */
00684             *rels_used = bms_add_member(*rels_used,
00685                       linitial_int(((ModifyTable *) plan)->resultRelations));
00686             break;
00687         default:
00688             break;
00689     }
00690 
00691     /* initPlan-s */
00692     if (planstate->initPlan)
00693         ExplainPreScanSubPlans(planstate->initPlan, rels_used);
00694 
00695     /* lefttree */
00696     if (outerPlanState(planstate))
00697         ExplainPreScanNode(outerPlanState(planstate), rels_used);
00698 
00699     /* righttree */
00700     if (innerPlanState(planstate))
00701         ExplainPreScanNode(innerPlanState(planstate), rels_used);
00702 
00703     /* special child plans */
00704     switch (nodeTag(plan))
00705     {
00706         case T_ModifyTable:
00707             ExplainPreScanMemberNodes(((ModifyTable *) plan)->plans,
00708                                   ((ModifyTableState *) planstate)->mt_plans,
00709                                       rels_used);
00710             break;
00711         case T_Append:
00712             ExplainPreScanMemberNodes(((Append *) plan)->appendplans,
00713                                     ((AppendState *) planstate)->appendplans,
00714                                       rels_used);
00715             break;
00716         case T_MergeAppend:
00717             ExplainPreScanMemberNodes(((MergeAppend *) plan)->mergeplans,
00718                                 ((MergeAppendState *) planstate)->mergeplans,
00719                                       rels_used);
00720             break;
00721         case T_BitmapAnd:
00722             ExplainPreScanMemberNodes(((BitmapAnd *) plan)->bitmapplans,
00723                                  ((BitmapAndState *) planstate)->bitmapplans,
00724                                       rels_used);
00725             break;
00726         case T_BitmapOr:
00727             ExplainPreScanMemberNodes(((BitmapOr *) plan)->bitmapplans,
00728                                   ((BitmapOrState *) planstate)->bitmapplans,
00729                                       rels_used);
00730             break;
00731         case T_SubqueryScan:
00732             ExplainPreScanNode(((SubqueryScanState *) planstate)->subplan,
00733                                rels_used);
00734             break;
00735         default:
00736             break;
00737     }
00738 
00739     /* subPlan-s */
00740     if (planstate->subPlan)
00741         ExplainPreScanSubPlans(planstate->subPlan, rels_used);
00742 }
00743 
00744 /*
00745  * Prescan the constituent plans of a ModifyTable, Append, MergeAppend,
00746  * BitmapAnd, or BitmapOr node.
00747  *
00748  * Note: we don't actually need to examine the Plan list members, but
00749  * we need the list in order to determine the length of the PlanState array.
00750  */
00751 static void
00752 ExplainPreScanMemberNodes(List *plans, PlanState **planstates,
00753                           Bitmapset **rels_used)
00754 {
00755     int         nplans = list_length(plans);
00756     int         j;
00757 
00758     for (j = 0; j < nplans; j++)
00759         ExplainPreScanNode(planstates[j], rels_used);
00760 }
00761 
00762 /*
00763  * Prescan a list of SubPlans (or initPlans, which also use SubPlan nodes).
00764  */
00765 static void
00766 ExplainPreScanSubPlans(List *plans, Bitmapset **rels_used)
00767 {
00768     ListCell   *lst;
00769 
00770     foreach(lst, plans)
00771     {
00772         SubPlanState *sps = (SubPlanState *) lfirst(lst);
00773 
00774         ExplainPreScanNode(sps->planstate, rels_used);
00775     }
00776 }
00777 
00778 /*
00779  * ExplainNode -
00780  *    Appends a description of a plan tree to es->str
00781  *
00782  * planstate points to the executor state node for the current plan node.
00783  * We need to work from a PlanState node, not just a Plan node, in order to
00784  * get at the instrumentation data (if any) as well as the list of subplans.
00785  *
00786  * ancestors is a list of parent PlanState nodes, most-closely-nested first.
00787  * These are needed in order to interpret PARAM_EXEC Params.
00788  *
00789  * relationship describes the relationship of this plan node to its parent
00790  * (eg, "Outer", "Inner"); it can be null at top level.  plan_name is an
00791  * optional name to be attached to the node.
00792  *
00793  * In text format, es->indent is controlled in this function since we only
00794  * want it to change at plan-node boundaries.  In non-text formats, es->indent
00795  * corresponds to the nesting depth of logical output groups, and therefore
00796  * is controlled by ExplainOpenGroup/ExplainCloseGroup.
00797  */
00798 static void
00799 ExplainNode(PlanState *planstate, List *ancestors,
00800             const char *relationship, const char *plan_name,
00801             ExplainState *es)
00802 {
00803     Plan       *plan = planstate->plan;
00804     const char *pname;          /* node type name for text output */
00805     const char *sname;          /* node type name for non-text output */
00806     const char *strategy = NULL;
00807     const char *operation = NULL;
00808     int         save_indent = es->indent;
00809     bool        haschildren;
00810 
00811     switch (nodeTag(plan))
00812     {
00813         case T_Result:
00814             pname = sname = "Result";
00815             break;
00816         case T_ModifyTable:
00817             sname = "ModifyTable";
00818             switch (((ModifyTable *) plan)->operation)
00819             {
00820                 case CMD_INSERT:
00821                     pname = operation = "Insert";
00822                     break;
00823                 case CMD_UPDATE:
00824                     pname = operation = "Update";
00825                     break;
00826                 case CMD_DELETE:
00827                     pname = operation = "Delete";
00828                     break;
00829                 default:
00830                     pname = "???";
00831                     break;
00832             }
00833             break;
00834         case T_Append:
00835             pname = sname = "Append";
00836             break;
00837         case T_MergeAppend:
00838             pname = sname = "Merge Append";
00839             break;
00840         case T_RecursiveUnion:
00841             pname = sname = "Recursive Union";
00842             break;
00843         case T_BitmapAnd:
00844             pname = sname = "BitmapAnd";
00845             break;
00846         case T_BitmapOr:
00847             pname = sname = "BitmapOr";
00848             break;
00849         case T_NestLoop:
00850             pname = sname = "Nested Loop";
00851             break;
00852         case T_MergeJoin:
00853             pname = "Merge";    /* "Join" gets added by jointype switch */
00854             sname = "Merge Join";
00855             break;
00856         case T_HashJoin:
00857             pname = "Hash";     /* "Join" gets added by jointype switch */
00858             sname = "Hash Join";
00859             break;
00860         case T_SeqScan:
00861             pname = sname = "Seq Scan";
00862             break;
00863         case T_IndexScan:
00864             pname = sname = "Index Scan";
00865             break;
00866         case T_IndexOnlyScan:
00867             pname = sname = "Index Only Scan";
00868             break;
00869         case T_BitmapIndexScan:
00870             pname = sname = "Bitmap Index Scan";
00871             break;
00872         case T_BitmapHeapScan:
00873             pname = sname = "Bitmap Heap Scan";
00874             break;
00875         case T_TidScan:
00876             pname = sname = "Tid Scan";
00877             break;
00878         case T_SubqueryScan:
00879             pname = sname = "Subquery Scan";
00880             break;
00881         case T_FunctionScan:
00882             pname = sname = "Function Scan";
00883             break;
00884         case T_ValuesScan:
00885             pname = sname = "Values Scan";
00886             break;
00887         case T_CteScan:
00888             pname = sname = "CTE Scan";
00889             break;
00890         case T_WorkTableScan:
00891             pname = sname = "WorkTable Scan";
00892             break;
00893         case T_ForeignScan:
00894             pname = sname = "Foreign Scan";
00895             break;
00896         case T_Material:
00897             pname = sname = "Materialize";
00898             break;
00899         case T_Sort:
00900             pname = sname = "Sort";
00901             break;
00902         case T_Group:
00903             pname = sname = "Group";
00904             break;
00905         case T_Agg:
00906             sname = "Aggregate";
00907             switch (((Agg *) plan)->aggstrategy)
00908             {
00909                 case AGG_PLAIN:
00910                     pname = "Aggregate";
00911                     strategy = "Plain";
00912                     break;
00913                 case AGG_SORTED:
00914                     pname = "GroupAggregate";
00915                     strategy = "Sorted";
00916                     break;
00917                 case AGG_HASHED:
00918                     pname = "HashAggregate";
00919                     strategy = "Hashed";
00920                     break;
00921                 default:
00922                     pname = "Aggregate ???";
00923                     strategy = "???";
00924                     break;
00925             }
00926             break;
00927         case T_WindowAgg:
00928             pname = sname = "WindowAgg";
00929             break;
00930         case T_Unique:
00931             pname = sname = "Unique";
00932             break;
00933         case T_SetOp:
00934             sname = "SetOp";
00935             switch (((SetOp *) plan)->strategy)
00936             {
00937                 case SETOP_SORTED:
00938                     pname = "SetOp";
00939                     strategy = "Sorted";
00940                     break;
00941                 case SETOP_HASHED:
00942                     pname = "HashSetOp";
00943                     strategy = "Hashed";
00944                     break;
00945                 default:
00946                     pname = "SetOp ???";
00947                     strategy = "???";
00948                     break;
00949             }
00950             break;
00951         case T_LockRows:
00952             pname = sname = "LockRows";
00953             break;
00954         case T_Limit:
00955             pname = sname = "Limit";
00956             break;
00957         case T_Hash:
00958             pname = sname = "Hash";
00959             break;
00960         default:
00961             pname = sname = "???";
00962             break;
00963     }
00964 
00965     ExplainOpenGroup("Plan",
00966                      relationship ? NULL : "Plan",
00967                      true, es);
00968 
00969     if (es->format == EXPLAIN_FORMAT_TEXT)
00970     {
00971         if (plan_name)
00972         {
00973             appendStringInfoSpaces(es->str, es->indent * 2);
00974             appendStringInfo(es->str, "%s\n", plan_name);
00975             es->indent++;
00976         }
00977         if (es->indent)
00978         {
00979             appendStringInfoSpaces(es->str, es->indent * 2);
00980             appendStringInfoString(es->str, "->  ");
00981             es->indent += 2;
00982         }
00983         appendStringInfoString(es->str, pname);
00984         es->indent++;
00985     }
00986     else
00987     {
00988         ExplainPropertyText("Node Type", sname, es);
00989         if (strategy)
00990             ExplainPropertyText("Strategy", strategy, es);
00991         if (operation)
00992             ExplainPropertyText("Operation", operation, es);
00993         if (relationship)
00994             ExplainPropertyText("Parent Relationship", relationship, es);
00995         if (plan_name)
00996             ExplainPropertyText("Subplan Name", plan_name, es);
00997     }
00998 
00999     switch (nodeTag(plan))
01000     {
01001         case T_SeqScan:
01002         case T_BitmapHeapScan:
01003         case T_TidScan:
01004         case T_SubqueryScan:
01005         case T_FunctionScan:
01006         case T_ValuesScan:
01007         case T_CteScan:
01008         case T_WorkTableScan:
01009         case T_ForeignScan:
01010             ExplainScanTarget((Scan *) plan, es);
01011             break;
01012         case T_IndexScan:
01013             {
01014                 IndexScan  *indexscan = (IndexScan *) plan;
01015 
01016                 ExplainIndexScanDetails(indexscan->indexid,
01017                                         indexscan->indexorderdir,
01018                                         es);
01019                 ExplainScanTarget((Scan *) indexscan, es);
01020             }
01021             break;
01022         case T_IndexOnlyScan:
01023             {
01024                 IndexOnlyScan *indexonlyscan = (IndexOnlyScan *) plan;
01025 
01026                 ExplainIndexScanDetails(indexonlyscan->indexid,
01027                                         indexonlyscan->indexorderdir,
01028                                         es);
01029                 ExplainScanTarget((Scan *) indexonlyscan, es);
01030             }
01031             break;
01032         case T_BitmapIndexScan:
01033             {
01034                 BitmapIndexScan *bitmapindexscan = (BitmapIndexScan *) plan;
01035                 const char *indexname =
01036                 explain_get_index_name(bitmapindexscan->indexid);
01037 
01038                 if (es->format == EXPLAIN_FORMAT_TEXT)
01039                     appendStringInfo(es->str, " on %s", indexname);
01040                 else
01041                     ExplainPropertyText("Index Name", indexname, es);
01042             }
01043             break;
01044         case T_ModifyTable:
01045             ExplainModifyTarget((ModifyTable *) plan, es);
01046             break;
01047         case T_NestLoop:
01048         case T_MergeJoin:
01049         case T_HashJoin:
01050             {
01051                 const char *jointype;
01052 
01053                 switch (((Join *) plan)->jointype)
01054                 {
01055                     case JOIN_INNER:
01056                         jointype = "Inner";
01057                         break;
01058                     case JOIN_LEFT:
01059                         jointype = "Left";
01060                         break;
01061                     case JOIN_FULL:
01062                         jointype = "Full";
01063                         break;
01064                     case JOIN_RIGHT:
01065                         jointype = "Right";
01066                         break;
01067                     case JOIN_SEMI:
01068                         jointype = "Semi";
01069                         break;
01070                     case JOIN_ANTI:
01071                         jointype = "Anti";
01072                         break;
01073                     default:
01074                         jointype = "???";
01075                         break;
01076                 }
01077                 if (es->format == EXPLAIN_FORMAT_TEXT)
01078                 {
01079                     /*
01080                      * For historical reasons, the join type is interpolated
01081                      * into the node type name...
01082                      */
01083                     if (((Join *) plan)->jointype != JOIN_INNER)
01084                         appendStringInfo(es->str, " %s Join", jointype);
01085                     else if (!IsA(plan, NestLoop))
01086                         appendStringInfo(es->str, " Join");
01087                 }
01088                 else
01089                     ExplainPropertyText("Join Type", jointype, es);
01090             }
01091             break;
01092         case T_SetOp:
01093             {
01094                 const char *setopcmd;
01095 
01096                 switch (((SetOp *) plan)->cmd)
01097                 {
01098                     case SETOPCMD_INTERSECT:
01099                         setopcmd = "Intersect";
01100                         break;
01101                     case SETOPCMD_INTERSECT_ALL:
01102                         setopcmd = "Intersect All";
01103                         break;
01104                     case SETOPCMD_EXCEPT:
01105                         setopcmd = "Except";
01106                         break;
01107                     case SETOPCMD_EXCEPT_ALL:
01108                         setopcmd = "Except All";
01109                         break;
01110                     default:
01111                         setopcmd = "???";
01112                         break;
01113                 }
01114                 if (es->format == EXPLAIN_FORMAT_TEXT)
01115                     appendStringInfo(es->str, " %s", setopcmd);
01116                 else
01117                     ExplainPropertyText("Command", setopcmd, es);
01118             }
01119             break;
01120         default:
01121             break;
01122     }
01123 
01124     if (es->costs)
01125     {
01126         if (es->format == EXPLAIN_FORMAT_TEXT)
01127         {
01128             appendStringInfo(es->str, "  (cost=%.2f..%.2f rows=%.0f width=%d)",
01129                              plan->startup_cost, plan->total_cost,
01130                              plan->plan_rows, plan->plan_width);
01131         }
01132         else
01133         {
01134             ExplainPropertyFloat("Startup Cost", plan->startup_cost, 2, es);
01135             ExplainPropertyFloat("Total Cost", plan->total_cost, 2, es);
01136             ExplainPropertyFloat("Plan Rows", plan->plan_rows, 0, es);
01137             ExplainPropertyInteger("Plan Width", plan->plan_width, es);
01138         }
01139     }
01140 
01141     /*
01142      * We have to forcibly clean up the instrumentation state because we
01143      * haven't done ExecutorEnd yet.  This is pretty grotty ...
01144      */
01145     if (planstate->instrument)
01146         InstrEndLoop(planstate->instrument);
01147 
01148     if (planstate->instrument && planstate->instrument->nloops > 0)
01149     {
01150         double      nloops = planstate->instrument->nloops;
01151         double      startup_sec = 1000.0 * planstate->instrument->startup / nloops;
01152         double      total_sec = 1000.0 * planstate->instrument->total / nloops;
01153         double      rows = planstate->instrument->ntuples / nloops;
01154 
01155         if (es->format == EXPLAIN_FORMAT_TEXT)
01156         {
01157             if (planstate->instrument->need_timer)
01158                 appendStringInfo(es->str,
01159                             " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",
01160                                  startup_sec, total_sec, rows, nloops);
01161             else
01162                 appendStringInfo(es->str,
01163                                  " (actual rows=%.0f loops=%.0f)",
01164                                  rows, nloops);
01165         }
01166         else
01167         {
01168             if (planstate->instrument->need_timer)
01169             {
01170                 ExplainPropertyFloat("Actual Startup Time", startup_sec, 3, es);
01171                 ExplainPropertyFloat("Actual Total Time", total_sec, 3, es);
01172             }
01173             ExplainPropertyFloat("Actual Rows", rows, 0, es);
01174             ExplainPropertyFloat("Actual Loops", nloops, 0, es);
01175         }
01176     }
01177     else if (es->analyze)
01178     {
01179 
01180         if (es->format == EXPLAIN_FORMAT_TEXT)
01181             appendStringInfo(es->str, " (never executed)");
01182         else if (planstate->instrument->need_timer)
01183         {
01184             ExplainPropertyFloat("Actual Startup Time", 0.0, 3, es);
01185             ExplainPropertyFloat("Actual Total Time", 0.0, 3, es);
01186         }
01187         else
01188         {
01189             ExplainPropertyFloat("Actual Rows", 0.0, 0, es);
01190             ExplainPropertyFloat("Actual Loops", 0.0, 0, es);
01191         }
01192 
01193     }
01194 
01195     /* in text format, first line ends here */
01196     if (es->format == EXPLAIN_FORMAT_TEXT)
01197         appendStringInfoChar(es->str, '\n');
01198 
01199     /* target list */
01200     if (es->verbose)
01201         show_plan_tlist(planstate, ancestors, es);
01202 
01203     /* quals, sort keys, etc */
01204     switch (nodeTag(plan))
01205     {
01206         case T_IndexScan:
01207             show_scan_qual(((IndexScan *) plan)->indexqualorig,
01208                            "Index Cond", planstate, ancestors, es);
01209             if (((IndexScan *) plan)->indexqualorig)
01210                 show_instrumentation_count("Rows Removed by Index Recheck", 2,
01211                                            planstate, es);
01212             show_scan_qual(((IndexScan *) plan)->indexorderbyorig,
01213                            "Order By", planstate, ancestors, es);
01214             show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
01215             if (plan->qual)
01216                 show_instrumentation_count("Rows Removed by Filter", 1,
01217                                            planstate, es);
01218             break;
01219         case T_IndexOnlyScan:
01220             show_scan_qual(((IndexOnlyScan *) plan)->indexqual,
01221                            "Index Cond", planstate, ancestors, es);
01222             if (((IndexOnlyScan *) plan)->indexqual)
01223                 show_instrumentation_count("Rows Removed by Index Recheck", 2,
01224                                            planstate, es);
01225             show_scan_qual(((IndexOnlyScan *) plan)->indexorderby,
01226                            "Order By", planstate, ancestors, es);
01227             show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
01228             if (plan->qual)
01229                 show_instrumentation_count("Rows Removed by Filter", 1,
01230                                            planstate, es);
01231             if (es->analyze)
01232                 ExplainPropertyLong("Heap Fetches",
01233                    ((IndexOnlyScanState *) planstate)->ioss_HeapFetches, es);
01234             break;
01235         case T_BitmapIndexScan:
01236             show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig,
01237                            "Index Cond", planstate, ancestors, es);
01238             break;
01239         case T_BitmapHeapScan:
01240             show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig,
01241                            "Recheck Cond", planstate, ancestors, es);
01242             if (((BitmapHeapScan *) plan)->bitmapqualorig)
01243                 show_instrumentation_count("Rows Removed by Index Recheck", 2,
01244                                            planstate, es);
01245             /* FALL THRU */
01246         case T_SeqScan:
01247         case T_ValuesScan:
01248         case T_CteScan:
01249         case T_WorkTableScan:
01250         case T_SubqueryScan:
01251             show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
01252             if (plan->qual)
01253                 show_instrumentation_count("Rows Removed by Filter", 1,
01254                                            planstate, es);
01255             break;
01256         case T_FunctionScan:
01257             if (es->verbose)
01258                 show_expression(((FunctionScan *) plan)->funcexpr,
01259                                 "Function Call", planstate, ancestors,
01260                                 es->verbose, es);
01261             show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
01262             if (plan->qual)
01263                 show_instrumentation_count("Rows Removed by Filter", 1,
01264                                            planstate, es);
01265             break;
01266         case T_TidScan:
01267             {
01268                 /*
01269                  * The tidquals list has OR semantics, so be sure to show it
01270                  * as an OR condition.
01271                  */
01272                 List       *tidquals = ((TidScan *) plan)->tidquals;
01273 
01274                 if (list_length(tidquals) > 1)
01275                     tidquals = list_make1(make_orclause(tidquals));
01276                 show_scan_qual(tidquals, "TID Cond", planstate, ancestors, es);
01277                 show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
01278                 if (plan->qual)
01279                     show_instrumentation_count("Rows Removed by Filter", 1,
01280                                                planstate, es);
01281             }
01282             break;
01283         case T_ForeignScan:
01284             show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
01285             if (plan->qual)
01286                 show_instrumentation_count("Rows Removed by Filter", 1,
01287                                            planstate, es);
01288             show_foreignscan_info((ForeignScanState *) planstate, es);
01289             break;
01290         case T_NestLoop:
01291             show_upper_qual(((NestLoop *) plan)->join.joinqual,
01292                             "Join Filter", planstate, ancestors, es);
01293             if (((NestLoop *) plan)->join.joinqual)
01294                 show_instrumentation_count("Rows Removed by Join Filter", 1,
01295                                            planstate, es);
01296             show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
01297             if (plan->qual)
01298                 show_instrumentation_count("Rows Removed by Filter", 2,
01299                                            planstate, es);
01300             break;
01301         case T_MergeJoin:
01302             show_upper_qual(((MergeJoin *) plan)->mergeclauses,
01303                             "Merge Cond", planstate, ancestors, es);
01304             show_upper_qual(((MergeJoin *) plan)->join.joinqual,
01305                             "Join Filter", planstate, ancestors, es);
01306             if (((MergeJoin *) plan)->join.joinqual)
01307                 show_instrumentation_count("Rows Removed by Join Filter", 1,
01308                                            planstate, es);
01309             show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
01310             if (plan->qual)
01311                 show_instrumentation_count("Rows Removed by Filter", 2,
01312                                            planstate, es);
01313             break;
01314         case T_HashJoin:
01315             show_upper_qual(((HashJoin *) plan)->hashclauses,
01316                             "Hash Cond", planstate, ancestors, es);
01317             show_upper_qual(((HashJoin *) plan)->join.joinqual,
01318                             "Join Filter", planstate, ancestors, es);
01319             if (((HashJoin *) plan)->join.joinqual)
01320                 show_instrumentation_count("Rows Removed by Join Filter", 1,
01321                                            planstate, es);
01322             show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
01323             if (plan->qual)
01324                 show_instrumentation_count("Rows Removed by Filter", 2,
01325                                            planstate, es);
01326             break;
01327         case T_Agg:
01328         case T_Group:
01329             show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
01330             if (plan->qual)
01331                 show_instrumentation_count("Rows Removed by Filter", 1,
01332                                            planstate, es);
01333             break;
01334         case T_Sort:
01335             show_sort_keys((SortState *) planstate, ancestors, es);
01336             show_sort_info((SortState *) planstate, es);
01337             break;
01338         case T_MergeAppend:
01339             show_merge_append_keys((MergeAppendState *) planstate,
01340                                    ancestors, es);
01341             break;
01342         case T_Result:
01343             show_upper_qual((List *) ((Result *) plan)->resconstantqual,
01344                             "One-Time Filter", planstate, ancestors, es);
01345             show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
01346             if (plan->qual)
01347                 show_instrumentation_count("Rows Removed by Filter", 1,
01348                                            planstate, es);
01349             break;
01350         case T_ModifyTable:
01351             show_modifytable_info((ModifyTableState *) planstate, es);
01352             break;
01353         case T_Hash:
01354             show_hash_info((HashState *) planstate, es);
01355             break;
01356         default:
01357             break;
01358     }
01359 
01360     /* Show buffer usage */
01361     if (es->buffers)
01362     {
01363         const BufferUsage *usage = &planstate->instrument->bufusage;
01364 
01365         if (es->format == EXPLAIN_FORMAT_TEXT)
01366         {
01367             bool        has_shared = (usage->shared_blks_hit > 0 ||
01368                                       usage->shared_blks_read > 0 ||
01369                                       usage->shared_blks_dirtied > 0 ||
01370                                       usage->shared_blks_written > 0);
01371             bool        has_local = (usage->local_blks_hit > 0 ||
01372                                      usage->local_blks_read > 0 ||
01373                                      usage->local_blks_dirtied > 0 ||
01374                                      usage->local_blks_written > 0);
01375             bool        has_temp = (usage->temp_blks_read > 0 ||
01376                                     usage->temp_blks_written > 0);
01377             bool        has_timing = (!INSTR_TIME_IS_ZERO(usage->blk_read_time) ||
01378                                  !INSTR_TIME_IS_ZERO(usage->blk_write_time));
01379 
01380             /* Show only positive counter values. */
01381             if (has_shared || has_local || has_temp)
01382             {
01383                 appendStringInfoSpaces(es->str, es->indent * 2);
01384                 appendStringInfoString(es->str, "Buffers:");
01385 
01386                 if (has_shared)
01387                 {
01388                     appendStringInfoString(es->str, " shared");
01389                     if (usage->shared_blks_hit > 0)
01390                         appendStringInfo(es->str, " hit=%ld",
01391                                          usage->shared_blks_hit);
01392                     if (usage->shared_blks_read > 0)
01393                         appendStringInfo(es->str, " read=%ld",
01394                                          usage->shared_blks_read);
01395                     if (usage->shared_blks_dirtied > 0)
01396                         appendStringInfo(es->str, " dirtied=%ld",
01397                                          usage->shared_blks_dirtied);
01398                     if (usage->shared_blks_written > 0)
01399                         appendStringInfo(es->str, " written=%ld",
01400                                          usage->shared_blks_written);
01401                     if (has_local || has_temp)
01402                         appendStringInfoChar(es->str, ',');
01403                 }
01404                 if (has_local)
01405                 {
01406                     appendStringInfoString(es->str, " local");
01407                     if (usage->local_blks_hit > 0)
01408                         appendStringInfo(es->str, " hit=%ld",
01409                                          usage->local_blks_hit);
01410                     if (usage->local_blks_read > 0)
01411                         appendStringInfo(es->str, " read=%ld",
01412                                          usage->local_blks_read);
01413                     if (usage->local_blks_dirtied > 0)
01414                         appendStringInfo(es->str, " dirtied=%ld",
01415                                          usage->local_blks_dirtied);
01416                     if (usage->local_blks_written > 0)
01417                         appendStringInfo(es->str, " written=%ld",
01418                                          usage->local_blks_written);
01419                     if (has_temp)
01420                         appendStringInfoChar(es->str, ',');
01421                 }
01422                 if (has_temp)
01423                 {
01424                     appendStringInfoString(es->str, " temp");
01425                     if (usage->temp_blks_read > 0)
01426                         appendStringInfo(es->str, " read=%ld",
01427                                          usage->temp_blks_read);
01428                     if (usage->temp_blks_written > 0)
01429                         appendStringInfo(es->str, " written=%ld",
01430                                          usage->temp_blks_written);
01431                 }
01432                 appendStringInfoChar(es->str, '\n');
01433             }
01434 
01435             /* As above, show only positive counter values. */
01436             if (has_timing)
01437             {
01438                 appendStringInfoSpaces(es->str, es->indent * 2);
01439                 appendStringInfoString(es->str, "I/O Timings:");
01440                 if (!INSTR_TIME_IS_ZERO(usage->blk_read_time))
01441                     appendStringInfo(es->str, " read=%0.3f",
01442                               INSTR_TIME_GET_MILLISEC(usage->blk_read_time));
01443                 if (!INSTR_TIME_IS_ZERO(usage->blk_write_time))
01444                     appendStringInfo(es->str, " write=%0.3f",
01445                              INSTR_TIME_GET_MILLISEC(usage->blk_write_time));
01446                 appendStringInfoChar(es->str, '\n');
01447             }
01448         }
01449         else
01450         {
01451             ExplainPropertyLong("Shared Hit Blocks", usage->shared_blks_hit, es);
01452             ExplainPropertyLong("Shared Read Blocks", usage->shared_blks_read, es);
01453             ExplainPropertyLong("Shared Dirtied Blocks", usage->shared_blks_dirtied, es);
01454             ExplainPropertyLong("Shared Written Blocks", usage->shared_blks_written, es);
01455             ExplainPropertyLong("Local Hit Blocks", usage->local_blks_hit, es);
01456             ExplainPropertyLong("Local Read Blocks", usage->local_blks_read, es);
01457             ExplainPropertyLong("Local Dirtied Blocks", usage->local_blks_dirtied, es);
01458             ExplainPropertyLong("Local Written Blocks", usage->local_blks_written, es);
01459             ExplainPropertyLong("Temp Read Blocks", usage->temp_blks_read, es);
01460             ExplainPropertyLong("Temp Written Blocks", usage->temp_blks_written, es);
01461             ExplainPropertyFloat("I/O Read Time", INSTR_TIME_GET_MILLISEC(usage->blk_read_time), 3, es);
01462             ExplainPropertyFloat("I/O Write Time", INSTR_TIME_GET_MILLISEC(usage->blk_write_time), 3, es);
01463         }
01464     }
01465 
01466     /* Get ready to display the child plans */
01467     haschildren = planstate->initPlan ||
01468         outerPlanState(planstate) ||
01469         innerPlanState(planstate) ||
01470         IsA(plan, ModifyTable) ||
01471         IsA(plan, Append) ||
01472         IsA(plan, MergeAppend) ||
01473         IsA(plan, BitmapAnd) ||
01474         IsA(plan, BitmapOr) ||
01475         IsA(plan, SubqueryScan) ||
01476         planstate->subPlan;
01477     if (haschildren)
01478     {
01479         ExplainOpenGroup("Plans", "Plans", false, es);
01480         /* Pass current PlanState as head of ancestors list for children */
01481         ancestors = lcons(planstate, ancestors);
01482     }
01483 
01484     /* initPlan-s */
01485     if (planstate->initPlan)
01486         ExplainSubPlans(planstate->initPlan, ancestors, "InitPlan", es);
01487 
01488     /* lefttree */
01489     if (outerPlanState(planstate))
01490         ExplainNode(outerPlanState(planstate), ancestors,
01491                     "Outer", NULL, es);
01492 
01493     /* righttree */
01494     if (innerPlanState(planstate))
01495         ExplainNode(innerPlanState(planstate), ancestors,
01496                     "Inner", NULL, es);
01497 
01498     /* special child plans */
01499     switch (nodeTag(plan))
01500     {
01501         case T_ModifyTable:
01502             ExplainMemberNodes(((ModifyTable *) plan)->plans,
01503                                ((ModifyTableState *) planstate)->mt_plans,
01504                                ancestors, es);
01505             break;
01506         case T_Append:
01507             ExplainMemberNodes(((Append *) plan)->appendplans,
01508                                ((AppendState *) planstate)->appendplans,
01509                                ancestors, es);
01510             break;
01511         case T_MergeAppend:
01512             ExplainMemberNodes(((MergeAppend *) plan)->mergeplans,
01513                                ((MergeAppendState *) planstate)->mergeplans,
01514                                ancestors, es);
01515             break;
01516         case T_BitmapAnd:
01517             ExplainMemberNodes(((BitmapAnd *) plan)->bitmapplans,
01518                                ((BitmapAndState *) planstate)->bitmapplans,
01519                                ancestors, es);
01520             break;
01521         case T_BitmapOr:
01522             ExplainMemberNodes(((BitmapOr *) plan)->bitmapplans,
01523                                ((BitmapOrState *) planstate)->bitmapplans,
01524                                ancestors, es);
01525             break;
01526         case T_SubqueryScan:
01527             ExplainNode(((SubqueryScanState *) planstate)->subplan, ancestors,
01528                         "Subquery", NULL, es);
01529             break;
01530         default:
01531             break;
01532     }
01533 
01534     /* subPlan-s */
01535     if (planstate->subPlan)
01536         ExplainSubPlans(planstate->subPlan, ancestors, "SubPlan", es);
01537 
01538     /* end of child plans */
01539     if (haschildren)
01540     {
01541         ancestors = list_delete_first(ancestors);
01542         ExplainCloseGroup("Plans", "Plans", false, es);
01543     }
01544 
01545     /* in text format, undo whatever indentation we added */
01546     if (es->format == EXPLAIN_FORMAT_TEXT)
01547         es->indent = save_indent;
01548 
01549     ExplainCloseGroup("Plan",
01550                       relationship ? NULL : "Plan",
01551                       true, es);
01552 }
01553 
01554 /*
01555  * Show the targetlist of a plan node
01556  */
01557 static void
01558 show_plan_tlist(PlanState *planstate, List *ancestors, ExplainState *es)
01559 {
01560     Plan       *plan = planstate->plan;
01561     List       *context;
01562     List       *result = NIL;
01563     bool        useprefix;
01564     ListCell   *lc;
01565 
01566     /* No work if empty tlist (this occurs eg in bitmap indexscans) */
01567     if (plan->targetlist == NIL)
01568         return;
01569     /* The tlist of an Append isn't real helpful, so suppress it */
01570     if (IsA(plan, Append))
01571         return;
01572     /* Likewise for MergeAppend and RecursiveUnion */
01573     if (IsA(plan, MergeAppend))
01574         return;
01575     if (IsA(plan, RecursiveUnion))
01576         return;
01577 
01578     /* Set up deparsing context */
01579     context = deparse_context_for_planstate((Node *) planstate,
01580                                             ancestors,
01581                                             es->rtable,
01582                                             es->rtable_names);
01583     useprefix = list_length(es->rtable) > 1;
01584 
01585     /* Deparse each result column (we now include resjunk ones) */
01586     foreach(lc, plan->targetlist)
01587     {
01588         TargetEntry *tle = (TargetEntry *) lfirst(lc);
01589 
01590         result = lappend(result,
01591                          deparse_expression((Node *) tle->expr, context,
01592                                             useprefix, false));
01593     }
01594 
01595     /* Print results */
01596     ExplainPropertyList("Output", result, es);
01597 }
01598 
01599 /*
01600  * Show a generic expression
01601  */
01602 static void
01603 show_expression(Node *node, const char *qlabel,
01604                 PlanState *planstate, List *ancestors,
01605                 bool useprefix, ExplainState *es)
01606 {
01607     List       *context;
01608     char       *exprstr;
01609 
01610     /* Set up deparsing context */
01611     context = deparse_context_for_planstate((Node *) planstate,
01612                                             ancestors,
01613                                             es->rtable,
01614                                             es->rtable_names);
01615 
01616     /* Deparse the expression */
01617     exprstr = deparse_expression(node, context, useprefix, false);
01618 
01619     /* And add to es->str */
01620     ExplainPropertyText(qlabel, exprstr, es);
01621 }
01622 
01623 /*
01624  * Show a qualifier expression (which is a List with implicit AND semantics)
01625  */
01626 static void
01627 show_qual(List *qual, const char *qlabel,
01628           PlanState *planstate, List *ancestors,
01629           bool useprefix, ExplainState *es)
01630 {
01631     Node       *node;
01632 
01633     /* No work if empty qual */
01634     if (qual == NIL)
01635         return;
01636 
01637     /* Convert AND list to explicit AND */
01638     node = (Node *) make_ands_explicit(qual);
01639 
01640     /* And show it */
01641     show_expression(node, qlabel, planstate, ancestors, useprefix, es);
01642 }
01643 
01644 /*
01645  * Show a qualifier expression for a scan plan node
01646  */
01647 static void
01648 show_scan_qual(List *qual, const char *qlabel,
01649                PlanState *planstate, List *ancestors,
01650                ExplainState *es)
01651 {
01652     bool        useprefix;
01653 
01654     useprefix = (IsA(planstate->plan, SubqueryScan) ||es->verbose);
01655     show_qual(qual, qlabel, planstate, ancestors, useprefix, es);
01656 }
01657 
01658 /*
01659  * Show a qualifier expression for an upper-level plan node
01660  */
01661 static void
01662 show_upper_qual(List *qual, const char *qlabel,
01663                 PlanState *planstate, List *ancestors,
01664                 ExplainState *es)
01665 {
01666     bool        useprefix;
01667 
01668     useprefix = (list_length(es->rtable) > 1 || es->verbose);
01669     show_qual(qual, qlabel, planstate, ancestors, useprefix, es);
01670 }
01671 
01672 /*
01673  * Show the sort keys for a Sort node.
01674  */
01675 static void
01676 show_sort_keys(SortState *sortstate, List *ancestors, ExplainState *es)
01677 {
01678     Sort       *plan = (Sort *) sortstate->ss.ps.plan;
01679 
01680     show_sort_keys_common((PlanState *) sortstate,
01681                           plan->numCols, plan->sortColIdx,
01682                           ancestors, es);
01683 }
01684 
01685 /*
01686  * Likewise, for a MergeAppend node.
01687  */
01688 static void
01689 show_merge_append_keys(MergeAppendState *mstate, List *ancestors,
01690                        ExplainState *es)
01691 {
01692     MergeAppend *plan = (MergeAppend *) mstate->ps.plan;
01693 
01694     show_sort_keys_common((PlanState *) mstate,
01695                           plan->numCols, plan->sortColIdx,
01696                           ancestors, es);
01697 }
01698 
01699 static void
01700 show_sort_keys_common(PlanState *planstate, int nkeys, AttrNumber *keycols,
01701                       List *ancestors, ExplainState *es)
01702 {
01703     Plan       *plan = planstate->plan;
01704     List       *context;
01705     List       *result = NIL;
01706     bool        useprefix;
01707     int         keyno;
01708     char       *exprstr;
01709 
01710     if (nkeys <= 0)
01711         return;
01712 
01713     /* Set up deparsing context */
01714     context = deparse_context_for_planstate((Node *) planstate,
01715                                             ancestors,
01716                                             es->rtable,
01717                                             es->rtable_names);
01718     useprefix = (list_length(es->rtable) > 1 || es->verbose);
01719 
01720     for (keyno = 0; keyno < nkeys; keyno++)
01721     {
01722         /* find key expression in tlist */
01723         AttrNumber  keyresno = keycols[keyno];
01724         TargetEntry *target = get_tle_by_resno(plan->targetlist,
01725                                                keyresno);
01726 
01727         if (!target)
01728             elog(ERROR, "no tlist entry for key %d", keyresno);
01729         /* Deparse the expression, showing any top-level cast */
01730         exprstr = deparse_expression((Node *) target->expr, context,
01731                                      useprefix, true);
01732         result = lappend(result, exprstr);
01733     }
01734 
01735     ExplainPropertyList("Sort Key", result, es);
01736 }
01737 
01738 /*
01739  * If it's EXPLAIN ANALYZE, show tuplesort stats for a sort node
01740  */
01741 static void
01742 show_sort_info(SortState *sortstate, ExplainState *es)
01743 {
01744     Assert(IsA(sortstate, SortState));
01745     if (es->analyze && sortstate->sort_Done &&
01746         sortstate->tuplesortstate != NULL)
01747     {
01748         Tuplesortstate *state = (Tuplesortstate *) sortstate->tuplesortstate;
01749         const char *sortMethod;
01750         const char *spaceType;
01751         long        spaceUsed;
01752 
01753         tuplesort_get_stats(state, &sortMethod, &spaceType, &spaceUsed);
01754 
01755         if (es->format == EXPLAIN_FORMAT_TEXT)
01756         {
01757             appendStringInfoSpaces(es->str, es->indent * 2);
01758             appendStringInfo(es->str, "Sort Method: %s  %s: %ldkB\n",
01759                              sortMethod, spaceType, spaceUsed);
01760         }
01761         else
01762         {
01763             ExplainPropertyText("Sort Method", sortMethod, es);
01764             ExplainPropertyLong("Sort Space Used", spaceUsed, es);
01765             ExplainPropertyText("Sort Space Type", spaceType, es);
01766         }
01767     }
01768 }
01769 
01770 /*
01771  * Show information on hash buckets/batches.
01772  */
01773 static void
01774 show_hash_info(HashState *hashstate, ExplainState *es)
01775 {
01776     HashJoinTable hashtable;
01777 
01778     Assert(IsA(hashstate, HashState));
01779     hashtable = hashstate->hashtable;
01780 
01781     if (hashtable)
01782     {
01783         long        spacePeakKb = (hashtable->spacePeak + 1023) / 1024;
01784 
01785         if (es->format != EXPLAIN_FORMAT_TEXT)
01786         {
01787             ExplainPropertyLong("Hash Buckets", hashtable->nbuckets, es);
01788             ExplainPropertyLong("Hash Batches", hashtable->nbatch, es);
01789             ExplainPropertyLong("Original Hash Batches",
01790                                 hashtable->nbatch_original, es);
01791             ExplainPropertyLong("Peak Memory Usage", spacePeakKb, es);
01792         }
01793         else if (hashtable->nbatch_original != hashtable->nbatch)
01794         {
01795             appendStringInfoSpaces(es->str, es->indent * 2);
01796             appendStringInfo(es->str,
01797             "Buckets: %d  Batches: %d (originally %d)  Memory Usage: %ldkB\n",
01798                              hashtable->nbuckets, hashtable->nbatch,
01799                              hashtable->nbatch_original, spacePeakKb);
01800         }
01801         else
01802         {
01803             appendStringInfoSpaces(es->str, es->indent * 2);
01804             appendStringInfo(es->str,
01805                            "Buckets: %d  Batches: %d  Memory Usage: %ldkB\n",
01806                              hashtable->nbuckets, hashtable->nbatch,
01807                              spacePeakKb);
01808         }
01809     }
01810 }
01811 
01812 /*
01813  * If it's EXPLAIN ANALYZE, show instrumentation information for a plan node
01814  *
01815  * "which" identifies which instrumentation counter to print
01816  */
01817 static void
01818 show_instrumentation_count(const char *qlabel, int which,
01819                            PlanState *planstate, ExplainState *es)
01820 {
01821     double      nfiltered;
01822     double      nloops;
01823 
01824     if (!es->analyze || !planstate->instrument)
01825         return;
01826 
01827     if (which == 2)
01828         nfiltered = planstate->instrument->nfiltered2;
01829     else
01830         nfiltered = planstate->instrument->nfiltered1;
01831     nloops = planstate->instrument->nloops;
01832 
01833     /* In text mode, suppress zero counts; they're not interesting enough */
01834     if (nfiltered > 0 || es->format != EXPLAIN_FORMAT_TEXT)
01835     {
01836         if (nloops > 0)
01837             ExplainPropertyFloat(qlabel, nfiltered / nloops, 0, es);
01838         else
01839             ExplainPropertyFloat(qlabel, 0.0, 0, es);
01840     }
01841 }
01842 
01843 /*
01844  * Show extra information for a ForeignScan node.
01845  */
01846 static void
01847 show_foreignscan_info(ForeignScanState *fsstate, ExplainState *es)
01848 {
01849     FdwRoutine *fdwroutine = fsstate->fdwroutine;
01850 
01851     /* Let the FDW emit whatever fields it wants */
01852     if (fdwroutine->ExplainForeignScan != NULL)
01853         fdwroutine->ExplainForeignScan(fsstate, es);
01854 }
01855 
01856 /*
01857  * Fetch the name of an index in an EXPLAIN
01858  *
01859  * We allow plugins to get control here so that plans involving hypothetical
01860  * indexes can be explained.
01861  */
01862 static const char *
01863 explain_get_index_name(Oid indexId)
01864 {
01865     const char *result;
01866 
01867     if (explain_get_index_name_hook)
01868         result = (*explain_get_index_name_hook) (indexId);
01869     else
01870         result = NULL;
01871     if (result == NULL)
01872     {
01873         /* default behavior: look in the catalogs and quote it */
01874         result = get_rel_name(indexId);
01875         if (result == NULL)
01876             elog(ERROR, "cache lookup failed for index %u", indexId);
01877         result = quote_identifier(result);
01878     }
01879     return result;
01880 }
01881 
01882 /*
01883  * Add some additional details about an IndexScan or IndexOnlyScan
01884  */
01885 static void
01886 ExplainIndexScanDetails(Oid indexid, ScanDirection indexorderdir,
01887                         ExplainState *es)
01888 {
01889     const char *indexname = explain_get_index_name(indexid);
01890 
01891     if (es->format == EXPLAIN_FORMAT_TEXT)
01892     {
01893         if (ScanDirectionIsBackward(indexorderdir))
01894             appendStringInfoString(es->str, " Backward");
01895         appendStringInfo(es->str, " using %s", indexname);
01896     }
01897     else
01898     {
01899         const char *scandir;
01900 
01901         switch (indexorderdir)
01902         {
01903             case BackwardScanDirection:
01904                 scandir = "Backward";
01905                 break;
01906             case NoMovementScanDirection:
01907                 scandir = "NoMovement";
01908                 break;
01909             case ForwardScanDirection:
01910                 scandir = "Forward";
01911                 break;
01912             default:
01913                 scandir = "???";
01914                 break;
01915         }
01916         ExplainPropertyText("Scan Direction", scandir, es);
01917         ExplainPropertyText("Index Name", indexname, es);
01918     }
01919 }
01920 
01921 /*
01922  * Show the target of a Scan node
01923  */
01924 static void
01925 ExplainScanTarget(Scan *plan, ExplainState *es)
01926 {
01927     ExplainTargetRel((Plan *) plan, plan->scanrelid, es);
01928 }
01929 
01930 /*
01931  * Show the target of a ModifyTable node
01932  */
01933 static void
01934 ExplainModifyTarget(ModifyTable *plan, ExplainState *es)
01935 {
01936     Index       rti;
01937 
01938     /*
01939      * We show the name of the first target relation.  In multi-target-table
01940      * cases this should always be the parent of the inheritance tree.
01941      */
01942     Assert(plan->resultRelations != NIL);
01943     rti = linitial_int(plan->resultRelations);
01944 
01945     ExplainTargetRel((Plan *) plan, rti, es);
01946 }
01947 
01948 /*
01949  * Show the target relation of a scan or modify node
01950  */
01951 static void
01952 ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
01953 {
01954     char       *objectname = NULL;
01955     char       *namespace = NULL;
01956     const char *objecttag = NULL;
01957     RangeTblEntry *rte;
01958     char       *refname;
01959 
01960     rte = rt_fetch(rti, es->rtable);
01961     refname = (char *) list_nth(es->rtable_names, rti - 1);
01962     if (refname == NULL)
01963         refname = rte->eref->aliasname;
01964 
01965     switch (nodeTag(plan))
01966     {
01967         case T_SeqScan:
01968         case T_IndexScan:
01969         case T_IndexOnlyScan:
01970         case T_BitmapHeapScan:
01971         case T_TidScan:
01972         case T_ForeignScan:
01973         case T_ModifyTable:
01974             /* Assert it's on a real relation */
01975             Assert(rte->rtekind == RTE_RELATION);
01976             objectname = get_rel_name(rte->relid);
01977             if (es->verbose)
01978                 namespace = get_namespace_name(get_rel_namespace(rte->relid));
01979             objecttag = "Relation Name";
01980             break;
01981         case T_FunctionScan:
01982             {
01983                 Node       *funcexpr;
01984 
01985                 /* Assert it's on a RangeFunction */
01986                 Assert(rte->rtekind == RTE_FUNCTION);
01987 
01988                 /*
01989                  * If the expression is still a function call, we can get the
01990                  * real name of the function.  Otherwise, punt (this can
01991                  * happen if the optimizer simplified away the function call,
01992                  * for example).
01993                  */
01994                 funcexpr = ((FunctionScan *) plan)->funcexpr;
01995                 if (funcexpr && IsA(funcexpr, FuncExpr))
01996                 {
01997                     Oid         funcid = ((FuncExpr *) funcexpr)->funcid;
01998 
01999                     objectname = get_func_name(funcid);
02000                     if (es->verbose)
02001                         namespace =
02002                             get_namespace_name(get_func_namespace(funcid));
02003                 }
02004                 objecttag = "Function Name";
02005             }
02006             break;
02007         case T_ValuesScan:
02008             Assert(rte->rtekind == RTE_VALUES);
02009             break;
02010         case T_CteScan:
02011             /* Assert it's on a non-self-reference CTE */
02012             Assert(rte->rtekind == RTE_CTE);
02013             Assert(!rte->self_reference);
02014             objectname = rte->ctename;
02015             objecttag = "CTE Name";
02016             break;
02017         case T_WorkTableScan:
02018             /* Assert it's on a self-reference CTE */
02019             Assert(rte->rtekind == RTE_CTE);
02020             Assert(rte->self_reference);
02021             objectname = rte->ctename;
02022             objecttag = "CTE Name";
02023             break;
02024         default:
02025             break;
02026     }
02027 
02028     if (es->format == EXPLAIN_FORMAT_TEXT)
02029     {
02030         appendStringInfoString(es->str, " on");
02031         if (namespace != NULL)
02032             appendStringInfo(es->str, " %s.%s", quote_identifier(namespace),
02033                              quote_identifier(objectname));
02034         else if (objectname != NULL)
02035             appendStringInfo(es->str, " %s", quote_identifier(objectname));
02036         if (objectname == NULL || strcmp(refname, objectname) != 0)
02037             appendStringInfo(es->str, " %s", quote_identifier(refname));
02038     }
02039     else
02040     {
02041         if (objecttag != NULL && objectname != NULL)
02042             ExplainPropertyText(objecttag, objectname, es);
02043         if (namespace != NULL)
02044             ExplainPropertyText("Schema", namespace, es);
02045         ExplainPropertyText("Alias", refname, es);
02046     }
02047 }
02048 
02049 /*
02050  * Show extra information for a ModifyTable node
02051  */
02052 static void
02053 show_modifytable_info(ModifyTableState *mtstate, ExplainState *es)
02054 {
02055     FdwRoutine *fdwroutine = mtstate->resultRelInfo->ri_FdwRoutine;
02056 
02057     /*
02058      * If the first target relation is a foreign table, call its FDW to
02059      * display whatever additional fields it wants to.  For now, we ignore the
02060      * possibility of other targets being foreign tables, although the API for
02061      * ExplainForeignModify is designed to allow them to be processed.
02062      */
02063     if (fdwroutine != NULL &&
02064         fdwroutine->ExplainForeignModify != NULL)
02065     {
02066         ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
02067         List       *fdw_private = (List *) linitial(node->fdwPrivLists);
02068 
02069         fdwroutine->ExplainForeignModify(mtstate,
02070                                          mtstate->resultRelInfo,
02071                                          fdw_private,
02072                                          0,
02073                                          es);
02074     }
02075 }
02076 
02077 /*
02078  * Explain the constituent plans of a ModifyTable, Append, MergeAppend,
02079  * BitmapAnd, or BitmapOr node.
02080  *
02081  * The ancestors list should already contain the immediate parent of these
02082  * plans.
02083  *
02084  * Note: we don't actually need to examine the Plan list members, but
02085  * we need the list in order to determine the length of the PlanState array.
02086  */
02087 static void
02088 ExplainMemberNodes(List *plans, PlanState **planstates,
02089                    List *ancestors, ExplainState *es)
02090 {
02091     int         nplans = list_length(plans);
02092     int         j;
02093 
02094     for (j = 0; j < nplans; j++)
02095         ExplainNode(planstates[j], ancestors,
02096                     "Member", NULL, es);
02097 }
02098 
02099 /*
02100  * Explain a list of SubPlans (or initPlans, which also use SubPlan nodes).
02101  *
02102  * The ancestors list should already contain the immediate parent of these
02103  * SubPlanStates.
02104  */
02105 static void
02106 ExplainSubPlans(List *plans, List *ancestors,
02107                 const char *relationship, ExplainState *es)
02108 {
02109     ListCell   *lst;
02110 
02111     foreach(lst, plans)
02112     {
02113         SubPlanState *sps = (SubPlanState *) lfirst(lst);
02114         SubPlan    *sp = (SubPlan *) sps->xprstate.expr;
02115 
02116         ExplainNode(sps->planstate, ancestors,
02117                     relationship, sp->plan_name, es);
02118     }
02119 }
02120 
02121 /*
02122  * Explain a property, such as sort keys or targets, that takes the form of
02123  * a list of unlabeled items.  "data" is a list of C strings.
02124  */
02125 void
02126 ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
02127 {
02128     ListCell   *lc;
02129     bool        first = true;
02130 
02131     switch (es->format)
02132     {
02133         case EXPLAIN_FORMAT_TEXT:
02134             appendStringInfoSpaces(es->str, es->indent * 2);
02135             appendStringInfo(es->str, "%s: ", qlabel);
02136             foreach(lc, data)
02137             {
02138                 if (!first)
02139                     appendStringInfoString(es->str, ", ");
02140                 appendStringInfoString(es->str, (const char *) lfirst(lc));
02141                 first = false;
02142             }
02143             appendStringInfoChar(es->str, '\n');
02144             break;
02145 
02146         case EXPLAIN_FORMAT_XML:
02147             ExplainXMLTag(qlabel, X_OPENING, es);
02148             foreach(lc, data)
02149             {
02150                 char       *str;
02151 
02152                 appendStringInfoSpaces(es->str, es->indent * 2 + 2);
02153                 appendStringInfoString(es->str, "<Item>");
02154                 str = escape_xml((const char *) lfirst(lc));
02155                 appendStringInfoString(es->str, str);
02156                 pfree(str);
02157                 appendStringInfoString(es->str, "</Item>\n");
02158             }
02159             ExplainXMLTag(qlabel, X_CLOSING, es);
02160             break;
02161 
02162         case EXPLAIN_FORMAT_JSON:
02163             ExplainJSONLineEnding(es);
02164             appendStringInfoSpaces(es->str, es->indent * 2);
02165             escape_json(es->str, qlabel);
02166             appendStringInfoString(es->str, ": [");
02167             foreach(lc, data)
02168             {
02169                 if (!first)
02170                     appendStringInfoString(es->str, ", ");
02171                 escape_json(es->str, (const char *) lfirst(lc));
02172                 first = false;
02173             }
02174             appendStringInfoChar(es->str, ']');
02175             break;
02176 
02177         case EXPLAIN_FORMAT_YAML:
02178             ExplainYAMLLineStarting(es);
02179             appendStringInfo(es->str, "%s: ", qlabel);
02180             foreach(lc, data)
02181             {
02182                 appendStringInfoChar(es->str, '\n');
02183                 appendStringInfoSpaces(es->str, es->indent * 2 + 2);
02184                 appendStringInfoString(es->str, "- ");
02185                 escape_yaml(es->str, (const char *) lfirst(lc));
02186             }
02187             break;
02188     }
02189 }
02190 
02191 /*
02192  * Explain a simple property.
02193  *
02194  * If "numeric" is true, the value is a number (or other value that
02195  * doesn't need quoting in JSON).
02196  *
02197  * This usually should not be invoked directly, but via one of the datatype
02198  * specific routines ExplainPropertyText, ExplainPropertyInteger, etc.
02199  */
02200 static void
02201 ExplainProperty(const char *qlabel, const char *value, bool numeric,
02202                 ExplainState *es)
02203 {
02204     switch (es->format)
02205     {
02206         case EXPLAIN_FORMAT_TEXT:
02207             appendStringInfoSpaces(es->str, es->indent * 2);
02208             appendStringInfo(es->str, "%s: %s\n", qlabel, value);
02209             break;
02210 
02211         case EXPLAIN_FORMAT_XML:
02212             {
02213                 char       *str;
02214 
02215                 appendStringInfoSpaces(es->str, es->indent * 2);
02216                 ExplainXMLTag(qlabel, X_OPENING | X_NOWHITESPACE, es);
02217                 str = escape_xml(value);
02218                 appendStringInfoString(es->str, str);
02219                 pfree(str);
02220                 ExplainXMLTag(qlabel, X_CLOSING | X_NOWHITESPACE, es);
02221                 appendStringInfoChar(es->str, '\n');
02222             }
02223             break;
02224 
02225         case EXPLAIN_FORMAT_JSON:
02226             ExplainJSONLineEnding(es);
02227             appendStringInfoSpaces(es->str, es->indent * 2);
02228             escape_json(es->str, qlabel);
02229             appendStringInfoString(es->str, ": ");
02230             if (numeric)
02231                 appendStringInfoString(es->str, value);
02232             else
02233                 escape_json(es->str, value);
02234             break;
02235 
02236         case EXPLAIN_FORMAT_YAML:
02237             ExplainYAMLLineStarting(es);
02238             appendStringInfo(es->str, "%s: ", qlabel);
02239             if (numeric)
02240                 appendStringInfoString(es->str, value);
02241             else
02242                 escape_yaml(es->str, value);
02243             break;
02244     }
02245 }
02246 
02247 /*
02248  * Explain a string-valued property.
02249  */
02250 void
02251 ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
02252 {
02253     ExplainProperty(qlabel, value, false, es);
02254 }
02255 
02256 /*
02257  * Explain an integer-valued property.
02258  */
02259 void
02260 ExplainPropertyInteger(const char *qlabel, int value, ExplainState *es)
02261 {
02262     char        buf[32];
02263 
02264     snprintf(buf, sizeof(buf), "%d", value);
02265     ExplainProperty(qlabel, buf, true, es);
02266 }
02267 
02268 /*
02269  * Explain a long-integer-valued property.
02270  */
02271 void
02272 ExplainPropertyLong(const char *qlabel, long value, ExplainState *es)
02273 {
02274     char        buf[32];
02275 
02276     snprintf(buf, sizeof(buf), "%ld", value);
02277     ExplainProperty(qlabel, buf, true, es);
02278 }
02279 
02280 /*
02281  * Explain a float-valued property, using the specified number of
02282  * fractional digits.
02283  */
02284 void
02285 ExplainPropertyFloat(const char *qlabel, double value, int ndigits,
02286                      ExplainState *es)
02287 {
02288     char        buf[256];
02289 
02290     snprintf(buf, sizeof(buf), "%.*f", ndigits, value);
02291     ExplainProperty(qlabel, buf, true, es);
02292 }
02293 
02294 /*
02295  * Open a group of related objects.
02296  *
02297  * objtype is the type of the group object, labelname is its label within
02298  * a containing object (if any).
02299  *
02300  * If labeled is true, the group members will be labeled properties,
02301  * while if it's false, they'll be unlabeled objects.
02302  */
02303 static void
02304 ExplainOpenGroup(const char *objtype, const char *labelname,
02305                  bool labeled, ExplainState *es)
02306 {
02307     switch (es->format)
02308     {
02309         case EXPLAIN_FORMAT_TEXT:
02310             /* nothing to do */
02311             break;
02312 
02313         case EXPLAIN_FORMAT_XML:
02314             ExplainXMLTag(objtype, X_OPENING, es);
02315             es->indent++;
02316             break;
02317 
02318         case EXPLAIN_FORMAT_JSON:
02319             ExplainJSONLineEnding(es);
02320             appendStringInfoSpaces(es->str, 2 * es->indent);
02321             if (labelname)
02322             {
02323                 escape_json(es->str, labelname);
02324                 appendStringInfoString(es->str, ": ");
02325             }
02326             appendStringInfoChar(es->str, labeled ? '{' : '[');
02327 
02328             /*
02329              * In JSON format, the grouping_stack is an integer list.  0 means
02330              * we've emitted nothing at this grouping level, 1 means we've
02331              * emitted something (and so the next item needs a comma). See
02332              * ExplainJSONLineEnding().
02333              */
02334             es->grouping_stack = lcons_int(0, es->grouping_stack);
02335             es->indent++;
02336             break;
02337 
02338         case EXPLAIN_FORMAT_YAML:
02339 
02340             /*
02341              * In YAML format, the grouping stack is an integer list.  0 means
02342              * we've emitted nothing at this grouping level AND this grouping
02343              * level is unlabelled and must be marked with "- ".  See
02344              * ExplainYAMLLineStarting().
02345              */
02346             ExplainYAMLLineStarting(es);
02347             if (labelname)
02348             {
02349                 appendStringInfo(es->str, "%s: ", labelname);
02350                 es->grouping_stack = lcons_int(1, es->grouping_stack);
02351             }
02352             else
02353             {
02354                 appendStringInfoString(es->str, "- ");
02355                 es->grouping_stack = lcons_int(0, es->grouping_stack);
02356             }
02357             es->indent++;
02358             break;
02359     }
02360 }
02361 
02362 /*
02363  * Close a group of related objects.
02364  * Parameters must match the corresponding ExplainOpenGroup call.
02365  */
02366 static void
02367 ExplainCloseGroup(const char *objtype, const char *labelname,
02368                   bool labeled, ExplainState *es)
02369 {
02370     switch (es->format)
02371     {
02372         case EXPLAIN_FORMAT_TEXT:
02373             /* nothing to do */
02374             break;
02375 
02376         case EXPLAIN_FORMAT_XML:
02377             es->indent--;
02378             ExplainXMLTag(objtype, X_CLOSING, es);
02379             break;
02380 
02381         case EXPLAIN_FORMAT_JSON:
02382             es->indent--;
02383             appendStringInfoChar(es->str, '\n');
02384             appendStringInfoSpaces(es->str, 2 * es->indent);
02385             appendStringInfoChar(es->str, labeled ? '}' : ']');
02386             es->grouping_stack = list_delete_first(es->grouping_stack);
02387             break;
02388 
02389         case EXPLAIN_FORMAT_YAML:
02390             es->indent--;
02391             es->grouping_stack = list_delete_first(es->grouping_stack);
02392             break;
02393     }
02394 }
02395 
02396 /*
02397  * Emit a "dummy" group that never has any members.
02398  *
02399  * objtype is the type of the group object, labelname is its label within
02400  * a containing object (if any).
02401  */
02402 static void
02403 ExplainDummyGroup(const char *objtype, const char *labelname, ExplainState *es)
02404 {
02405     switch (es->format)
02406     {
02407         case EXPLAIN_FORMAT_TEXT:
02408             /* nothing to do */
02409             break;
02410 
02411         case EXPLAIN_FORMAT_XML:
02412             ExplainXMLTag(objtype, X_CLOSE_IMMEDIATE, es);
02413             break;
02414 
02415         case EXPLAIN_FORMAT_JSON:
02416             ExplainJSONLineEnding(es);
02417             appendStringInfoSpaces(es->str, 2 * es->indent);
02418             if (labelname)
02419             {
02420                 escape_json(es->str, labelname);
02421                 appendStringInfoString(es->str, ": ");
02422             }
02423             escape_json(es->str, objtype);
02424             break;
02425 
02426         case EXPLAIN_FORMAT_YAML:
02427             ExplainYAMLLineStarting(es);
02428             if (labelname)
02429             {
02430                 escape_yaml(es->str, labelname);
02431                 appendStringInfoString(es->str, ": ");
02432             }
02433             else
02434             {
02435                 appendStringInfoString(es->str, "- ");
02436             }
02437             escape_yaml(es->str, objtype);
02438             break;
02439     }
02440 }
02441 
02442 /*
02443  * Emit the start-of-output boilerplate.
02444  *
02445  * This is just enough different from processing a subgroup that we need
02446  * a separate pair of subroutines.
02447  */
02448 void
02449 ExplainBeginOutput(ExplainState *es)
02450 {
02451     switch (es->format)
02452     {
02453         case EXPLAIN_FORMAT_TEXT:
02454             /* nothing to do */
02455             break;
02456 
02457         case EXPLAIN_FORMAT_XML:
02458             appendStringInfoString(es->str,
02459              "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
02460             es->indent++;
02461             break;
02462 
02463         case EXPLAIN_FORMAT_JSON:
02464             /* top-level structure is an array of plans */
02465             appendStringInfoChar(es->str, '[');
02466             es->grouping_stack = lcons_int(0, es->grouping_stack);
02467             es->indent++;
02468             break;
02469 
02470         case EXPLAIN_FORMAT_YAML:
02471             es->grouping_stack = lcons_int(0, es->grouping_stack);
02472             break;
02473     }
02474 }
02475 
02476 /*
02477  * Emit the end-of-output boilerplate.
02478  */
02479 void
02480 ExplainEndOutput(ExplainState *es)
02481 {
02482     switch (es->format)
02483     {
02484         case EXPLAIN_FORMAT_TEXT:
02485             /* nothing to do */
02486             break;
02487 
02488         case EXPLAIN_FORMAT_XML:
02489             es->indent--;
02490             appendStringInfoString(es->str, "</explain>");
02491             break;
02492 
02493         case EXPLAIN_FORMAT_JSON:
02494             es->indent--;
02495             appendStringInfoString(es->str, "\n]");
02496             es->grouping_stack = list_delete_first(es->grouping_stack);
02497             break;
02498 
02499         case EXPLAIN_FORMAT_YAML:
02500             es->grouping_stack = list_delete_first(es->grouping_stack);
02501             break;
02502     }
02503 }
02504 
02505 /*
02506  * Put an appropriate separator between multiple plans
02507  */
02508 void
02509 ExplainSeparatePlans(ExplainState *es)
02510 {
02511     switch (es->format)
02512     {
02513         case EXPLAIN_FORMAT_TEXT:
02514             /* add a blank line */
02515             appendStringInfoChar(es->str, '\n');
02516             break;
02517 
02518         case EXPLAIN_FORMAT_XML:
02519         case EXPLAIN_FORMAT_JSON:
02520         case EXPLAIN_FORMAT_YAML:
02521             /* nothing to do */
02522             break;
02523     }
02524 }
02525 
02526 /*
02527  * Emit opening or closing XML tag.
02528  *
02529  * "flags" must contain X_OPENING, X_CLOSING, or X_CLOSE_IMMEDIATE.
02530  * Optionally, OR in X_NOWHITESPACE to suppress the whitespace we'd normally
02531  * add.
02532  *
02533  * XML tag names can't contain white space, so we replace any spaces in
02534  * "tagname" with dashes.
02535  */
02536 static void
02537 ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
02538 {
02539     const char *s;
02540 
02541     if ((flags & X_NOWHITESPACE) == 0)
02542         appendStringInfoSpaces(es->str, 2 * es->indent);
02543     appendStringInfoCharMacro(es->str, '<');
02544     if ((flags & X_CLOSING) != 0)
02545         appendStringInfoCharMacro(es->str, '/');
02546     for (s = tagname; *s; s++)
02547         appendStringInfoCharMacro(es->str, (*s == ' ') ? '-' : *s);
02548     if ((flags & X_CLOSE_IMMEDIATE) != 0)
02549         appendStringInfoString(es->str, " /");
02550     appendStringInfoCharMacro(es->str, '>');
02551     if ((flags & X_NOWHITESPACE) == 0)
02552         appendStringInfoCharMacro(es->str, '\n');
02553 }
02554 
02555 /*
02556  * Emit a JSON line ending.
02557  *
02558  * JSON requires a comma after each property but the last.  To facilitate this,
02559  * in JSON format, the text emitted for each property begins just prior to the
02560  * preceding line-break (and comma, if applicable).
02561  */
02562 static void
02563 ExplainJSONLineEnding(ExplainState *es)
02564 {
02565     Assert(es->format == EXPLAIN_FORMAT_JSON);
02566     if (linitial_int(es->grouping_stack) != 0)
02567         appendStringInfoChar(es->str, ',');
02568     else
02569         linitial_int(es->grouping_stack) = 1;
02570     appendStringInfoChar(es->str, '\n');
02571 }
02572 
02573 /*
02574  * Indent a YAML line.
02575  *
02576  * YAML lines are ordinarily indented by two spaces per indentation level.
02577  * The text emitted for each property begins just prior to the preceding
02578  * line-break, except for the first property in an unlabelled group, for which
02579  * it begins immediately after the "- " that introduces the group.  The first
02580  * property of the group appears on the same line as the opening "- ".
02581  */
02582 static void
02583 ExplainYAMLLineStarting(ExplainState *es)
02584 {
02585     Assert(es->format == EXPLAIN_FORMAT_YAML);
02586     if (linitial_int(es->grouping_stack) == 0)
02587     {
02588         linitial_int(es->grouping_stack) = 1;
02589     }
02590     else
02591     {
02592         appendStringInfoChar(es->str, '\n');
02593         appendStringInfoSpaces(es->str, es->indent * 2);
02594     }
02595 }
02596 
02597 /*
02598  * YAML is a superset of JSON; unfortuantely, the YAML quoting rules are
02599  * ridiculously complicated -- as documented in sections 5.3 and 7.3.3 of
02600  * http://yaml.org/spec/1.2/spec.html -- so we chose to just quote everything.
02601  * Empty strings, strings with leading or trailing whitespace, and strings
02602  * containing a variety of special characters must certainly be quoted or the
02603  * output is invalid; and other seemingly harmless strings like "0xa" or
02604  * "true" must be quoted, lest they be interpreted as a hexadecimal or Boolean
02605  * constant rather than a string.
02606  */
02607 static void
02608 escape_yaml(StringInfo buf, const char *str)
02609 {
02610     escape_json(buf, str);
02611 }