PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
explain.c File Reference
#include "postgres.h"
#include "access/xact.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "commands/createas.h"
#include "commands/defrem.h"
#include "commands/prepare.h"
#include "executor/hashjoin.h"
#include "foreign/fdwapi.h"
#include "nodes/extensible.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteHandler.h"
#include "storage/bufmgr.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/json.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/ruleutils.h"
#include "utils/snapmgr.h"
#include "utils/tuplesort.h"
#include "utils/typcache.h"
#include "utils/xml.h"
Include dependency graph for explain.c:

Go to the source code of this file.

Macros

#define X_OPENING   0
 
#define X_CLOSING   1
 
#define X_CLOSE_IMMEDIATE   2
 
#define X_NOWHITESPACE   4
 

Functions

static void ExplainOneQuery (Query *query, int cursorOptions, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
 
static void report_triggers (ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
 
static double elapsed_time (instr_time *starttime)
 
static bool ExplainPreScanNode (PlanState *planstate, Bitmapset **rels_used)
 
static void ExplainNode (PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
 
static void show_plan_tlist (PlanState *planstate, List *ancestors, ExplainState *es)
 
static void show_expression (Node *node, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
 
static void show_qual (List *qual, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
 
static void show_scan_qual (List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
 
static void show_upper_qual (List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
 
static void show_sort_keys (SortState *sortstate, List *ancestors, ExplainState *es)
 
static void show_merge_append_keys (MergeAppendState *mstate, List *ancestors, ExplainState *es)
 
static void show_agg_keys (AggState *astate, List *ancestors, ExplainState *es)
 
static void show_grouping_sets (PlanState *planstate, Agg *agg, List *ancestors, ExplainState *es)
 
static void show_grouping_set_keys (PlanState *planstate, Agg *aggnode, Sort *sortnode, List *context, bool useprefix, List *ancestors, ExplainState *es)
 
static void show_group_keys (GroupState *gstate, List *ancestors, ExplainState *es)
 
static void show_sort_group_keys (PlanState *planstate, const char *qlabel, int nkeys, AttrNumber *keycols, Oid *sortOperators, Oid *collations, bool *nullsFirst, List *ancestors, ExplainState *es)
 
static void show_sortorder_options (StringInfo buf, Node *sortexpr, Oid sortOperator, Oid collation, bool nullsFirst)
 
static void show_tablesample (TableSampleClause *tsc, PlanState *planstate, List *ancestors, ExplainState *es)
 
static void show_sort_info (SortState *sortstate, ExplainState *es)
 
static void show_hash_info (HashState *hashstate, ExplainState *es)
 
static void show_tidbitmap_info (BitmapHeapScanState *planstate, ExplainState *es)
 
static void show_instrumentation_count (const char *qlabel, int which, PlanState *planstate, ExplainState *es)
 
static void show_foreignscan_info (ForeignScanState *fsstate, ExplainState *es)
 
static const char * explain_get_index_name (Oid indexId)
 
static void show_buffer_usage (ExplainState *es, const BufferUsage *usage)
 
static void ExplainIndexScanDetails (Oid indexid, ScanDirection indexorderdir, ExplainState *es)
 
static void ExplainScanTarget (Scan *plan, ExplainState *es)
 
static void ExplainModifyTarget (ModifyTable *plan, ExplainState *es)
 
static void ExplainTargetRel (Plan *plan, Index rti, ExplainState *es)
 
static void show_modifytable_info (ModifyTableState *mtstate, List *ancestors, ExplainState *es)
 
static void ExplainMemberNodes (List *plans, PlanState **planstates, List *ancestors, ExplainState *es)
 
static void ExplainSubPlans (List *plans, List *ancestors, const char *relationship, ExplainState *es)
 
static void ExplainCustomChildren (CustomScanState *css, List *ancestors, ExplainState *es)
 
static void ExplainProperty (const char *qlabel, const char *value, bool numeric, ExplainState *es)
 
static void ExplainDummyGroup (const char *objtype, const char *labelname, ExplainState *es)
 
static void ExplainXMLTag (const char *tagname, int flags, ExplainState *es)
 
static void ExplainJSONLineEnding (ExplainState *es)
 
static void ExplainYAMLLineStarting (ExplainState *es)
 
static void escape_yaml (StringInfo buf, const char *str)
 
void ExplainQuery (ParseState *pstate, ExplainStmt *stmt, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest)
 
ExplainStateNewExplainState (void)
 
TupleDesc ExplainResultDesc (ExplainStmt *stmt)
 
void ExplainOneUtility (Node *utilityStmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
 
void ExplainOnePlan (PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv, const instr_time *planduration)
 
void ExplainPrintPlan (ExplainState *es, QueryDesc *queryDesc)
 
void ExplainPrintTriggers (ExplainState *es, QueryDesc *queryDesc)
 
void ExplainQueryText (ExplainState *es, QueryDesc *queryDesc)
 
void ExplainPropertyList (const char *qlabel, List *data, ExplainState *es)
 
void ExplainPropertyListNested (const char *qlabel, List *data, ExplainState *es)
 
void ExplainPropertyText (const char *qlabel, const char *value, ExplainState *es)
 
void ExplainPropertyInteger (const char *qlabel, int value, ExplainState *es)
 
void ExplainPropertyLong (const char *qlabel, long value, ExplainState *es)
 
void ExplainPropertyFloat (const char *qlabel, double value, int ndigits, ExplainState *es)
 
void ExplainPropertyBool (const char *qlabel, bool value, ExplainState *es)
 
void ExplainOpenGroup (const char *objtype, const char *labelname, bool labeled, ExplainState *es)
 
void ExplainCloseGroup (const char *objtype, const char *labelname, bool labeled, ExplainState *es)
 
void ExplainBeginOutput (ExplainState *es)
 
void ExplainEndOutput (ExplainState *es)
 
void ExplainSeparatePlans (ExplainState *es)
 

Variables

ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL
 
explain_get_index_name_hook_type explain_get_index_name_hook = NULL
 

Macro Definition Documentation

#define X_CLOSE_IMMEDIATE   2

Definition at line 53 of file explain.c.

Referenced by ExplainDummyGroup(), and ExplainXMLTag().

#define X_CLOSING   1

Definition at line 52 of file explain.c.

Referenced by ExplainCloseGroup(), ExplainProperty(), ExplainPropertyList(), and ExplainXMLTag().

#define X_NOWHITESPACE   4

Definition at line 54 of file explain.c.

Referenced by ExplainProperty(), and ExplainXMLTag().

#define X_OPENING   0

Definition at line 51 of file explain.c.

Referenced by ExplainOpenGroup(), ExplainProperty(), and ExplainPropertyList().

Function Documentation

static double elapsed_time ( instr_time starttime)
static

Definition at line 778 of file explain.c.

References INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, and INSTR_TIME_SUBTRACT.

Referenced by ExplainOnePlan(), and IsCheckpointOnSchedule().

779 {
780  instr_time endtime;
781 
782  INSTR_TIME_SET_CURRENT(endtime);
783  INSTR_TIME_SUBTRACT(endtime, *starttime);
784  return INSTR_TIME_GET_DOUBLE(endtime);
785 }
struct timeval instr_time
Definition: instr_time.h:147
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:196
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:167
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153
static void escape_yaml ( StringInfo  buf,
const char *  str 
)
static

Definition at line 3583 of file explain.c.

References escape_json().

Referenced by ExplainDummyGroup(), ExplainProperty(), ExplainPropertyList(), and ExplainPropertyListNested().

3584 {
3585  escape_json(buf, str);
3586 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2433
static const char * explain_get_index_name ( Oid  indexId)
static

Definition at line 2499 of file explain.c.

References elog, ERROR, explain_get_index_name_hook, get_rel_name(), and quote_identifier().

Referenced by ExplainIndexScanDetails(), and ExplainNode().

2500 {
2501  const char *result;
2502 
2504  result = (*explain_get_index_name_hook) (indexId);
2505  else
2506  result = NULL;
2507  if (result == NULL)
2508  {
2509  /* default behavior: look in the catalogs and quote it */
2510  result = get_rel_name(indexId);
2511  if (result == NULL)
2512  elog(ERROR, "cache lookup failed for index %u", indexId);
2513  result = quote_identifier(result);
2514  }
2515  return result;
2516 }
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10390
#define ERROR
Definition: elog.h:43
explain_get_index_name_hook_type explain_get_index_name_hook
Definition: explain.c:47
#define elog
Definition: elog.h:219
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
void ExplainBeginOutput ( ExplainState es)

Definition at line 3422 of file explain.c.

References appendStringInfoChar(), appendStringInfoString(), EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainState::format, ExplainState::grouping_stack, ExplainState::indent, lcons_int(), and ExplainState::str.

Referenced by explain_ExecutorEnd(), and ExplainQuery().

3423 {
3424  switch (es->format)
3425  {
3426  case EXPLAIN_FORMAT_TEXT:
3427  /* nothing to do */
3428  break;
3429 
3430  case EXPLAIN_FORMAT_XML:
3432  "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
3433  es->indent++;
3434  break;
3435 
3436  case EXPLAIN_FORMAT_JSON:
3437  /* top-level structure is an array of plans */
3438  appendStringInfoChar(es->str, '[');
3439  es->grouping_stack = lcons_int(0, es->grouping_stack);
3440  es->indent++;
3441  break;
3442 
3443  case EXPLAIN_FORMAT_YAML:
3444  es->grouping_stack = lcons_int(0, es->grouping_stack);
3445  break;
3446  }
3447 }
List * lcons_int(int datum, List *list)
Definition: list.c:277
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
void ExplainCloseGroup ( const char *  objtype,
const char *  labelname,
bool  labeled,
ExplainState es 
)

Definition at line 3340 of file explain.c.

References appendStringInfoChar(), appendStringInfoSpaces(), EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainXMLTag(), ExplainState::format, ExplainState::grouping_stack, ExplainState::indent, list_delete_first(), ExplainState::str, and X_CLOSING.

Referenced by ExplainNode(), ExplainOnePlan(), ExplainPrintTriggers(), report_triggers(), show_grouping_set_keys(), show_grouping_sets(), show_modifytable_info(), and show_sort_info().

3342 {
3343  switch (es->format)
3344  {
3345  case EXPLAIN_FORMAT_TEXT:
3346  /* nothing to do */
3347  break;
3348 
3349  case EXPLAIN_FORMAT_XML:
3350  es->indent--;
3351  ExplainXMLTag(objtype, X_CLOSING, es);
3352  break;
3353 
3354  case EXPLAIN_FORMAT_JSON:
3355  es->indent--;
3356  appendStringInfoChar(es->str, '\n');
3357  appendStringInfoSpaces(es->str, 2 * es->indent);
3358  appendStringInfoChar(es->str, labeled ? '}' : ']');
3360  break;
3361 
3362  case EXPLAIN_FORMAT_YAML:
3363  es->indent--;
3365  break;
3366  }
3367 }
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3511
#define X_CLOSING
Definition: explain.c:52
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
List * list_delete_first(List *list)
Definition: list.c:666
static void ExplainCustomChildren ( CustomScanState css,
List ancestors,
ExplainState es 
)
static

Definition at line 3029 of file explain.c.

References CustomScanState::custom_ps, ExplainNode(), label, lfirst, and list_length().

Referenced by ExplainNode().

3030 {
3031  ListCell *cell;
3032  const char *label =
3033  (list_length(css->custom_ps) != 1 ? "children" : "child");
3034 
3035  foreach(cell, css->custom_ps)
3036  ExplainNode((PlanState *) lfirst(cell), ancestors, label, NULL, es);
3037 }
List * custom_ps
Definition: execnodes.h:1571
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:862
static char * label
Definition: pg_basebackup.c:82
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
static void ExplainDummyGroup ( const char *  objtype,
const char *  labelname,
ExplainState es 
)
static

Definition at line 3376 of file explain.c.

References appendStringInfoSpaces(), appendStringInfoString(), escape_json(), escape_yaml(), EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainJSONLineEnding(), ExplainXMLTag(), ExplainYAMLLineStarting(), ExplainState::format, ExplainState::indent, ExplainState::str, and X_CLOSE_IMMEDIATE.

Referenced by ExplainOneUtility().

3377 {
3378  switch (es->format)
3379  {
3380  case EXPLAIN_FORMAT_TEXT:
3381  /* nothing to do */
3382  break;
3383 
3384  case EXPLAIN_FORMAT_XML:
3385  ExplainXMLTag(objtype, X_CLOSE_IMMEDIATE, es);
3386  break;
3387 
3388  case EXPLAIN_FORMAT_JSON:
3390  appendStringInfoSpaces(es->str, 2 * es->indent);
3391  if (labelname)
3392  {
3393  escape_json(es->str, labelname);
3394  appendStringInfoString(es->str, ": ");
3395  }
3396  escape_json(es->str, objtype);
3397  break;
3398 
3399  case EXPLAIN_FORMAT_YAML:
3401  if (labelname)
3402  {
3403  escape_yaml(es->str, labelname);
3404  appendStringInfoString(es->str, ": ");
3405  }
3406  else
3407  {
3408  appendStringInfoString(es->str, "- ");
3409  }
3410  escape_yaml(es->str, objtype);
3411  break;
3412  }
3413 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2433
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3511
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3558
int indent
Definition: explain.h:40
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3583
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3538
ExplainFormat format
Definition: explain.h:38
#define X_CLOSE_IMMEDIATE
Definition: explain.c:53
StringInfo str
Definition: explain.h:30
void ExplainEndOutput ( ExplainState es)

Definition at line 3453 of file explain.c.

References appendStringInfoString(), EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainState::format, ExplainState::grouping_stack, ExplainState::indent, list_delete_first(), and ExplainState::str.

Referenced by explain_ExecutorEnd(), and ExplainQuery().

3454 {
3455  switch (es->format)
3456  {
3457  case EXPLAIN_FORMAT_TEXT:
3458  /* nothing to do */
3459  break;
3460 
3461  case EXPLAIN_FORMAT_XML:
3462  es->indent--;
3463  appendStringInfoString(es->str, "</explain>");
3464  break;
3465 
3466  case EXPLAIN_FORMAT_JSON:
3467  es->indent--;
3468  appendStringInfoString(es->str, "\n]");
3470  break;
3471 
3472  case EXPLAIN_FORMAT_YAML:
3474  break;
3475  }
3476 }
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
List * list_delete_first(List *list)
Definition: list.c:666
static void ExplainIndexScanDetails ( Oid  indexid,
ScanDirection  indexorderdir,
ExplainState es 
)
static

Definition at line 2632 of file explain.c.

References appendStringInfo(), appendStringInfoString(), BackwardScanDirection, EXPLAIN_FORMAT_TEXT, explain_get_index_name(), ExplainPropertyText(), ExplainState::format, ForwardScanDirection, NoMovementScanDirection, ScanDirectionIsBackward, and ExplainState::str.

Referenced by ExplainNode().

2634 {
2635  const char *indexname = explain_get_index_name(indexid);
2636 
2637  if (es->format == EXPLAIN_FORMAT_TEXT)
2638  {
2639  if (ScanDirectionIsBackward(indexorderdir))
2640  appendStringInfoString(es->str, " Backward");
2641  appendStringInfo(es->str, " using %s", indexname);
2642  }
2643  else
2644  {
2645  const char *scandir;
2646 
2647  switch (indexorderdir)
2648  {
2649  case BackwardScanDirection:
2650  scandir = "Backward";
2651  break;
2653  scandir = "NoMovement";
2654  break;
2655  case ForwardScanDirection:
2656  scandir = "Forward";
2657  break;
2658  default:
2659  scandir = "???";
2660  break;
2661  }
2662  ExplainPropertyText("Scan Direction", scandir, es);
2663  ExplainPropertyText("Index Name", indexname, es);
2664  }
2665 }
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3215
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
ExplainFormat format
Definition: explain.h:38
static const char * explain_get_index_name(Oid indexId)
Definition: explain.c:2499
StringInfo str
Definition: explain.h:30
static void ExplainJSONLineEnding ( ExplainState es)
static

Definition at line 3538 of file explain.c.

References appendStringInfoChar(), Assert, EXPLAIN_FORMAT_JSON, ExplainState::format, ExplainState::grouping_stack, linitial_int, and ExplainState::str.

Referenced by ExplainDummyGroup(), ExplainOpenGroup(), ExplainProperty(), ExplainPropertyList(), and ExplainPropertyListNested().

3539 {
3541  if (linitial_int(es->grouping_stack) != 0)
3542  appendStringInfoChar(es->str, ',');
3543  else
3544  linitial_int(es->grouping_stack) = 1;
3545  appendStringInfoChar(es->str, '\n');
3546 }
#define linitial_int(l)
Definition: pg_list.h:112
List * grouping_stack
Definition: explain.h:41
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
#define Assert(condition)
Definition: c.h:664
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
static void ExplainMemberNodes ( List plans,
PlanState **  planstates,
List ancestors,
ExplainState es 
)
static

Definition at line 2977 of file explain.c.

References ExplainNode(), and list_length().

Referenced by ExplainNode().

2979 {
2980  int nplans = list_length(plans);
2981  int j;
2982 
2983  for (j = 0; j < nplans; j++)
2984  ExplainNode(planstates[j], ancestors,
2985  "Member", NULL, es);
2986 }
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:862
static int list_length(const List *l)
Definition: pg_list.h:89
static void ExplainModifyTarget ( ModifyTable plan,
ExplainState es 
)
static

Definition at line 2684 of file explain.c.

References ExplainTargetRel(), and ModifyTable::nominalRelation.

Referenced by ExplainNode().

2685 {
2686  ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
2687 }
Index nominalRelation
Definition: plannodes.h:219
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:2693
static void ExplainNode ( PlanState planstate,
List ancestors,
const char *  relationship,
const char *  plan_name,
ExplainState es 
)
static

Definition at line 862 of file explain.c.

References AGG_HASHED, AGG_MIXED, AGG_PLAIN, AGG_SORTED, Agg::aggsplit, Agg::aggstrategy, ExplainState::analyze, appendStringInfo(), appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), ExplainState::buffers, Instrumentation::bufusage, castNode, CMD_DELETE, CMD_INSERT, CMD_SELECT, CMD_UPDATE, ExplainState::costs, DO_AGGSPLIT_COMBINE, DO_AGGSPLIT_SKIPFINAL, EXPLAIN_FORMAT_TEXT, explain_get_index_name(), ExplainCloseGroup(), ExplainCustomChildren(), CustomExecMethods::ExplainCustomScan, ExplainIndexScanDetails(), ExplainMemberNodes(), ExplainModifyTarget(), ExplainOpenGroup(), ExplainPropertyBool(), ExplainPropertyFloat(), ExplainPropertyInteger(), ExplainPropertyLong(), ExplainPropertyText(), ExplainScanTarget(), ExplainSubPlans(), ExplainState::format, RangeTblFunction::funcexpr, functions, ExplainState::indent, IndexScan::indexid, IndexOnlyScan::indexid, BitmapIndexScan::indexid, IndexScan::indexorderdir, IndexOnlyScan::indexorderdir, PlanState::initPlan, innerPlanState, InstrEndLoop(), WorkerInstrumentation::instrument, PlanState::instrument, IsA, JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, JOIN_SEMI, lappend(), lcons(), lfirst, list_delete_first(), list_length(), list_make1, make_orclause(), CustomScanState::methods, NIL, Instrumentation::nloops, nodeTag, Instrumentation::ntuples, WorkerInstrumentation::num_workers, Gather::num_workers, GatherMerge::num_workers, outerPlanState, Plan::parallel_aware, PlanState::plan, Plan::plan_rows, Plan::plan_width, psprintf(), Plan::qual, SETOP_HASHED, SETOP_SORTED, SETOPCMD_EXCEPT, SETOPCMD_EXCEPT_ALL, SETOPCMD_INTERSECT, SETOPCMD_INTERSECT_ALL, show_agg_keys(), show_buffer_usage(), show_expression(), show_foreignscan_info(), show_group_keys(), show_hash_info(), show_instrumentation_count(), show_merge_append_keys(), show_modifytable_info(), show_plan_tlist(), show_scan_qual(), show_sort_info(), show_sort_keys(), show_tablesample(), show_tidbitmap_info(), show_upper_qual(), Gather::single_copy, Instrumentation::startup, Plan::startup_cost, ExplainState::str, PlanState::subPlan, T_Agg, T_Append, T_BitmapAnd, T_BitmapHeapScan, T_BitmapIndexScan, T_BitmapOr, T_CteScan, T_CustomScan, T_ForeignScan, T_FunctionScan, T_Gather, T_GatherMerge, T_Group, T_Hash, T_HashJoin, T_IndexOnlyScan, T_IndexScan, T_Limit, T_LockRows, T_Material, T_MergeAppend, T_MergeJoin, T_ModifyTable, T_NamedTuplestoreScan, T_NestLoop, T_ProjectSet, T_RecursiveUnion, T_Result, T_SampleScan, T_SeqScan, T_SetOp, T_Sort, T_SubqueryScan, T_TableFuncScan, T_TidScan, T_Unique, T_ValuesScan, T_WindowAgg, T_WorkTableScan, ExplainState::timing, Instrumentation::total, Plan::total_cost, ExplainState::verbose, and PlanState::worker_instrument.

Referenced by ExplainCustomChildren(), ExplainMemberNodes(), ExplainPrintPlan(), and ExplainSubPlans().

865 {
866  Plan *plan = planstate->plan;
867  const char *pname; /* node type name for text output */
868  const char *sname; /* node type name for non-text output */
869  const char *strategy = NULL;
870  const char *partialmode = NULL;
871  const char *operation = NULL;
872  const char *custom_name = NULL;
873  int save_indent = es->indent;
874  bool haschildren;
875 
876  switch (nodeTag(plan))
877  {
878  case T_Result:
879  pname = sname = "Result";
880  break;
881  case T_ProjectSet:
882  pname = sname = "ProjectSet";
883  break;
884  case T_ModifyTable:
885  sname = "ModifyTable";
886  switch (((ModifyTable *) plan)->operation)
887  {
888  case CMD_INSERT:
889  pname = operation = "Insert";
890  break;
891  case CMD_UPDATE:
892  pname = operation = "Update";
893  break;
894  case CMD_DELETE:
895  pname = operation = "Delete";
896  break;
897  default:
898  pname = "???";
899  break;
900  }
901  break;
902  case T_Append:
903  pname = sname = "Append";
904  break;
905  case T_MergeAppend:
906  pname = sname = "Merge Append";
907  break;
908  case T_RecursiveUnion:
909  pname = sname = "Recursive Union";
910  break;
911  case T_BitmapAnd:
912  pname = sname = "BitmapAnd";
913  break;
914  case T_BitmapOr:
915  pname = sname = "BitmapOr";
916  break;
917  case T_NestLoop:
918  pname = sname = "Nested Loop";
919  break;
920  case T_MergeJoin:
921  pname = "Merge"; /* "Join" gets added by jointype switch */
922  sname = "Merge Join";
923  break;
924  case T_HashJoin:
925  pname = "Hash"; /* "Join" gets added by jointype switch */
926  sname = "Hash Join";
927  break;
928  case T_SeqScan:
929  pname = sname = "Seq Scan";
930  break;
931  case T_SampleScan:
932  pname = sname = "Sample Scan";
933  break;
934  case T_Gather:
935  pname = sname = "Gather";
936  break;
937  case T_GatherMerge:
938  pname = sname = "Gather Merge";
939  break;
940  case T_IndexScan:
941  pname = sname = "Index Scan";
942  break;
943  case T_IndexOnlyScan:
944  pname = sname = "Index Only Scan";
945  break;
946  case T_BitmapIndexScan:
947  pname = sname = "Bitmap Index Scan";
948  break;
949  case T_BitmapHeapScan:
950  pname = sname = "Bitmap Heap Scan";
951  break;
952  case T_TidScan:
953  pname = sname = "Tid Scan";
954  break;
955  case T_SubqueryScan:
956  pname = sname = "Subquery Scan";
957  break;
958  case T_FunctionScan:
959  pname = sname = "Function Scan";
960  break;
961  case T_TableFuncScan:
962  pname = sname = "Table Function Scan";
963  break;
964  case T_ValuesScan:
965  pname = sname = "Values Scan";
966  break;
967  case T_CteScan:
968  pname = sname = "CTE Scan";
969  break;
971  pname = sname = "Named Tuplestore Scan";
972  break;
973  case T_WorkTableScan:
974  pname = sname = "WorkTable Scan";
975  break;
976  case T_ForeignScan:
977  sname = "Foreign Scan";
978  switch (((ForeignScan *) plan)->operation)
979  {
980  case CMD_SELECT:
981  pname = "Foreign Scan";
982  operation = "Select";
983  break;
984  case CMD_INSERT:
985  pname = "Foreign Insert";
986  operation = "Insert";
987  break;
988  case CMD_UPDATE:
989  pname = "Foreign Update";
990  operation = "Update";
991  break;
992  case CMD_DELETE:
993  pname = "Foreign Delete";
994  operation = "Delete";
995  break;
996  default:
997  pname = "???";
998  break;
999  }
1000  break;
1001  case T_CustomScan:
1002  sname = "Custom Scan";
1003  custom_name = ((CustomScan *) plan)->methods->CustomName;
1004  if (custom_name)
1005  pname = psprintf("Custom Scan (%s)", custom_name);
1006  else
1007  pname = sname;
1008  break;
1009  case T_Material:
1010  pname = sname = "Materialize";
1011  break;
1012  case T_Sort:
1013  pname = sname = "Sort";
1014  break;
1015  case T_Group:
1016  pname = sname = "Group";
1017  break;
1018  case T_Agg:
1019  {
1020  Agg *agg = (Agg *) plan;
1021 
1022  sname = "Aggregate";
1023  switch (agg->aggstrategy)
1024  {
1025  case AGG_PLAIN:
1026  pname = "Aggregate";
1027  strategy = "Plain";
1028  break;
1029  case AGG_SORTED:
1030  pname = "GroupAggregate";
1031  strategy = "Sorted";
1032  break;
1033  case AGG_HASHED:
1034  pname = "HashAggregate";
1035  strategy = "Hashed";
1036  break;
1037  case AGG_MIXED:
1038  pname = "MixedAggregate";
1039  strategy = "Mixed";
1040  break;
1041  default:
1042  pname = "Aggregate ???";
1043  strategy = "???";
1044  break;
1045  }
1046 
1047  if (DO_AGGSPLIT_SKIPFINAL(agg->aggsplit))
1048  {
1049  partialmode = "Partial";
1050  pname = psprintf("%s %s", partialmode, pname);
1051  }
1052  else if (DO_AGGSPLIT_COMBINE(agg->aggsplit))
1053  {
1054  partialmode = "Finalize";
1055  pname = psprintf("%s %s", partialmode, pname);
1056  }
1057  else
1058  partialmode = "Simple";
1059  }
1060  break;
1061  case T_WindowAgg:
1062  pname = sname = "WindowAgg";
1063  break;
1064  case T_Unique:
1065  pname = sname = "Unique";
1066  break;
1067  case T_SetOp:
1068  sname = "SetOp";
1069  switch (((SetOp *) plan)->strategy)
1070  {
1071  case SETOP_SORTED:
1072  pname = "SetOp";
1073  strategy = "Sorted";
1074  break;
1075  case SETOP_HASHED:
1076  pname = "HashSetOp";
1077  strategy = "Hashed";
1078  break;
1079  default:
1080  pname = "SetOp ???";
1081  strategy = "???";
1082  break;
1083  }
1084  break;
1085  case T_LockRows:
1086  pname = sname = "LockRows";
1087  break;
1088  case T_Limit:
1089  pname = sname = "Limit";
1090  break;
1091  case T_Hash:
1092  pname = sname = "Hash";
1093  break;
1094  default:
1095  pname = sname = "???";
1096  break;
1097  }
1098 
1099  ExplainOpenGroup("Plan",
1100  relationship ? NULL : "Plan",
1101  true, es);
1102 
1103  if (es->format == EXPLAIN_FORMAT_TEXT)
1104  {
1105  if (plan_name)
1106  {
1107  appendStringInfoSpaces(es->str, es->indent * 2);
1108  appendStringInfo(es->str, "%s\n", plan_name);
1109  es->indent++;
1110  }
1111  if (es->indent)
1112  {
1113  appendStringInfoSpaces(es->str, es->indent * 2);
1114  appendStringInfoString(es->str, "-> ");
1115  es->indent += 2;
1116  }
1117  if (plan->parallel_aware)
1118  appendStringInfoString(es->str, "Parallel ");
1119  appendStringInfoString(es->str, pname);
1120  es->indent++;
1121  }
1122  else
1123  {
1124  ExplainPropertyText("Node Type", sname, es);
1125  if (strategy)
1126  ExplainPropertyText("Strategy", strategy, es);
1127  if (partialmode)
1128  ExplainPropertyText("Partial Mode", partialmode, es);
1129  if (operation)
1130  ExplainPropertyText("Operation", operation, es);
1131  if (relationship)
1132  ExplainPropertyText("Parent Relationship", relationship, es);
1133  if (plan_name)
1134  ExplainPropertyText("Subplan Name", plan_name, es);
1135  if (custom_name)
1136  ExplainPropertyText("Custom Plan Provider", custom_name, es);
1137  ExplainPropertyBool("Parallel Aware", plan->parallel_aware, es);
1138  }
1139 
1140  switch (nodeTag(plan))
1141  {
1142  case T_SeqScan:
1143  case T_SampleScan:
1144  case T_BitmapHeapScan:
1145  case T_TidScan:
1146  case T_SubqueryScan:
1147  case T_FunctionScan:
1148  case T_TableFuncScan:
1149  case T_ValuesScan:
1150  case T_CteScan:
1151  case T_WorkTableScan:
1152  ExplainScanTarget((Scan *) plan, es);
1153  break;
1154  case T_ForeignScan:
1155  case T_CustomScan:
1156  if (((Scan *) plan)->scanrelid > 0)
1157  ExplainScanTarget((Scan *) plan, es);
1158  break;
1159  case T_IndexScan:
1160  {
1161  IndexScan *indexscan = (IndexScan *) plan;
1162 
1163  ExplainIndexScanDetails(indexscan->indexid,
1164  indexscan->indexorderdir,
1165  es);
1166  ExplainScanTarget((Scan *) indexscan, es);
1167  }
1168  break;
1169  case T_IndexOnlyScan:
1170  {
1171  IndexOnlyScan *indexonlyscan = (IndexOnlyScan *) plan;
1172 
1173  ExplainIndexScanDetails(indexonlyscan->indexid,
1174  indexonlyscan->indexorderdir,
1175  es);
1176  ExplainScanTarget((Scan *) indexonlyscan, es);
1177  }
1178  break;
1179  case T_BitmapIndexScan:
1180  {
1181  BitmapIndexScan *bitmapindexscan = (BitmapIndexScan *) plan;
1182  const char *indexname =
1183  explain_get_index_name(bitmapindexscan->indexid);
1184 
1185  if (es->format == EXPLAIN_FORMAT_TEXT)
1186  appendStringInfo(es->str, " on %s", indexname);
1187  else
1188  ExplainPropertyText("Index Name", indexname, es);
1189  }
1190  break;
1191  case T_ModifyTable:
1192  ExplainModifyTarget((ModifyTable *) plan, es);
1193  break;
1194  case T_NestLoop:
1195  case T_MergeJoin:
1196  case T_HashJoin:
1197  {
1198  const char *jointype;
1199 
1200  switch (((Join *) plan)->jointype)
1201  {
1202  case JOIN_INNER:
1203  jointype = "Inner";
1204  break;
1205  case JOIN_LEFT:
1206  jointype = "Left";
1207  break;
1208  case JOIN_FULL:
1209  jointype = "Full";
1210  break;
1211  case JOIN_RIGHT:
1212  jointype = "Right";
1213  break;
1214  case JOIN_SEMI:
1215  jointype = "Semi";
1216  break;
1217  case JOIN_ANTI:
1218  jointype = "Anti";
1219  break;
1220  default:
1221  jointype = "???";
1222  break;
1223  }
1224  if (es->format == EXPLAIN_FORMAT_TEXT)
1225  {
1226  /*
1227  * For historical reasons, the join type is interpolated
1228  * into the node type name...
1229  */
1230  if (((Join *) plan)->jointype != JOIN_INNER)
1231  appendStringInfo(es->str, " %s Join", jointype);
1232  else if (!IsA(plan, NestLoop))
1233  appendStringInfoString(es->str, " Join");
1234  }
1235  else
1236  ExplainPropertyText("Join Type", jointype, es);
1237  }
1238  break;
1239  case T_SetOp:
1240  {
1241  const char *setopcmd;
1242 
1243  switch (((SetOp *) plan)->cmd)
1244  {
1245  case SETOPCMD_INTERSECT:
1246  setopcmd = "Intersect";
1247  break;
1249  setopcmd = "Intersect All";
1250  break;
1251  case SETOPCMD_EXCEPT:
1252  setopcmd = "Except";
1253  break;
1254  case SETOPCMD_EXCEPT_ALL:
1255  setopcmd = "Except All";
1256  break;
1257  default:
1258  setopcmd = "???";
1259  break;
1260  }
1261  if (es->format == EXPLAIN_FORMAT_TEXT)
1262  appendStringInfo(es->str, " %s", setopcmd);
1263  else
1264  ExplainPropertyText("Command", setopcmd, es);
1265  }
1266  break;
1267  default:
1268  break;
1269  }
1270 
1271  if (es->costs)
1272  {
1273  if (es->format == EXPLAIN_FORMAT_TEXT)
1274  {
1275  appendStringInfo(es->str, " (cost=%.2f..%.2f rows=%.0f width=%d)",
1276  plan->startup_cost, plan->total_cost,
1277  plan->plan_rows, plan->plan_width);
1278  }
1279  else
1280  {
1281  ExplainPropertyFloat("Startup Cost", plan->startup_cost, 2, es);
1282  ExplainPropertyFloat("Total Cost", plan->total_cost, 2, es);
1283  ExplainPropertyFloat("Plan Rows", plan->plan_rows, 0, es);
1284  ExplainPropertyInteger("Plan Width", plan->plan_width, es);
1285  }
1286  }
1287 
1288  /*
1289  * We have to forcibly clean up the instrumentation state because we
1290  * haven't done ExecutorEnd yet. This is pretty grotty ...
1291  *
1292  * Note: contrib/auto_explain could cause instrumentation to be set up
1293  * even though we didn't ask for it here. Be careful not to print any
1294  * instrumentation results the user didn't ask for. But we do the
1295  * InstrEndLoop call anyway, if possible, to reduce the number of cases
1296  * auto_explain has to contend with.
1297  */
1298  if (planstate->instrument)
1299  InstrEndLoop(planstate->instrument);
1300 
1301  if (es->analyze &&
1302  planstate->instrument && planstate->instrument->nloops > 0)
1303  {
1304  double nloops = planstate->instrument->nloops;
1305  double startup_sec = 1000.0 * planstate->instrument->startup / nloops;
1306  double total_sec = 1000.0 * planstate->instrument->total / nloops;
1307  double rows = planstate->instrument->ntuples / nloops;
1308 
1309  if (es->format == EXPLAIN_FORMAT_TEXT)
1310  {
1311  if (es->timing)
1312  appendStringInfo(es->str,
1313  " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",
1314  startup_sec, total_sec, rows, nloops);
1315  else
1316  appendStringInfo(es->str,
1317  " (actual rows=%.0f loops=%.0f)",
1318  rows, nloops);
1319  }
1320  else
1321  {
1322  if (es->timing)
1323  {
1324  ExplainPropertyFloat("Actual Startup Time", startup_sec, 3, es);
1325  ExplainPropertyFloat("Actual Total Time", total_sec, 3, es);
1326  }
1327  ExplainPropertyFloat("Actual Rows", rows, 0, es);
1328  ExplainPropertyFloat("Actual Loops", nloops, 0, es);
1329  }
1330  }
1331  else if (es->analyze)
1332  {
1333  if (es->format == EXPLAIN_FORMAT_TEXT)
1334  appendStringInfoString(es->str, " (never executed)");
1335  else
1336  {
1337  if (es->timing)
1338  {
1339  ExplainPropertyFloat("Actual Startup Time", 0.0, 3, es);
1340  ExplainPropertyFloat("Actual Total Time", 0.0, 3, es);
1341  }
1342  ExplainPropertyFloat("Actual Rows", 0.0, 0, es);
1343  ExplainPropertyFloat("Actual Loops", 0.0, 0, es);
1344  }
1345  }
1346 
1347  /* in text format, first line ends here */
1348  if (es->format == EXPLAIN_FORMAT_TEXT)
1349  appendStringInfoChar(es->str, '\n');
1350 
1351  /* target list */
1352  if (es->verbose)
1353  show_plan_tlist(planstate, ancestors, es);
1354 
1355  /* unique join */
1356  switch (nodeTag(plan))
1357  {
1358  case T_NestLoop:
1359  case T_MergeJoin:
1360  case T_HashJoin:
1361  /* try not to be too chatty about this in text mode */
1362  if (es->format != EXPLAIN_FORMAT_TEXT ||
1363  (es->verbose && ((Join *) plan)->inner_unique))
1364  ExplainPropertyBool("Inner Unique",
1365  ((Join *) plan)->inner_unique,
1366  es);
1367  break;
1368  default:
1369  break;
1370  }
1371 
1372  /* quals, sort keys, etc */
1373  switch (nodeTag(plan))
1374  {
1375  case T_IndexScan:
1376  show_scan_qual(((IndexScan *) plan)->indexqualorig,
1377  "Index Cond", planstate, ancestors, es);
1378  if (((IndexScan *) plan)->indexqualorig)
1379  show_instrumentation_count("Rows Removed by Index Recheck", 2,
1380  planstate, es);
1381  show_scan_qual(((IndexScan *) plan)->indexorderbyorig,
1382  "Order By", planstate, ancestors, es);
1383  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1384  if (plan->qual)
1385  show_instrumentation_count("Rows Removed by Filter", 1,
1386  planstate, es);
1387  break;
1388  case T_IndexOnlyScan:
1389  show_scan_qual(((IndexOnlyScan *) plan)->indexqual,
1390  "Index Cond", planstate, ancestors, es);
1391  if (((IndexOnlyScan *) plan)->indexqual)
1392  show_instrumentation_count("Rows Removed by Index Recheck", 2,
1393  planstate, es);
1394  show_scan_qual(((IndexOnlyScan *) plan)->indexorderby,
1395  "Order By", planstate, ancestors, es);
1396  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1397  if (plan->qual)
1398  show_instrumentation_count("Rows Removed by Filter", 1,
1399  planstate, es);
1400  if (es->analyze)
1401  ExplainPropertyLong("Heap Fetches",
1402  ((IndexOnlyScanState *) planstate)->ioss_HeapFetches, es);
1403  break;
1404  case T_BitmapIndexScan:
1405  show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig,
1406  "Index Cond", planstate, ancestors, es);
1407  break;
1408  case T_BitmapHeapScan:
1409  show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig,
1410  "Recheck Cond", planstate, ancestors, es);
1411  if (((BitmapHeapScan *) plan)->bitmapqualorig)
1412  show_instrumentation_count("Rows Removed by Index Recheck", 2,
1413  planstate, es);
1414  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1415  if (plan->qual)
1416  show_instrumentation_count("Rows Removed by Filter", 1,
1417  planstate, es);
1418  if (es->analyze)
1419  show_tidbitmap_info((BitmapHeapScanState *) planstate, es);
1420  break;
1421  case T_SampleScan:
1422  show_tablesample(((SampleScan *) plan)->tablesample,
1423  planstate, ancestors, es);
1424  /* FALL THRU to print additional fields the same as SeqScan */
1425  case T_SeqScan:
1426  case T_ValuesScan:
1427  case T_CteScan:
1428  case T_NamedTuplestoreScan:
1429  case T_WorkTableScan:
1430  case T_SubqueryScan:
1431  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1432  if (plan->qual)
1433  show_instrumentation_count("Rows Removed by Filter", 1,
1434  planstate, es);
1435  break;
1436  case T_Gather:
1437  {
1438  Gather *gather = (Gather *) plan;
1439 
1440  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1441  if (plan->qual)
1442  show_instrumentation_count("Rows Removed by Filter", 1,
1443  planstate, es);
1444  ExplainPropertyInteger("Workers Planned",
1445  gather->num_workers, es);
1446  if (es->analyze)
1447  {
1448  int nworkers;
1449 
1450  nworkers = ((GatherState *) planstate)->nworkers_launched;
1451  ExplainPropertyInteger("Workers Launched",
1452  nworkers, es);
1453  }
1454  if (gather->single_copy || es->format != EXPLAIN_FORMAT_TEXT)
1455  ExplainPropertyBool("Single Copy", gather->single_copy, es);
1456  }
1457  break;
1458  case T_GatherMerge:
1459  {
1460  GatherMerge *gm = (GatherMerge *) plan;
1461 
1462  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1463  if (plan->qual)
1464  show_instrumentation_count("Rows Removed by Filter", 1,
1465  planstate, es);
1466  ExplainPropertyInteger("Workers Planned",
1467  gm->num_workers, es);
1468  if (es->analyze)
1469  {
1470  int nworkers;
1471 
1472  nworkers = ((GatherMergeState *) planstate)->nworkers_launched;
1473  ExplainPropertyInteger("Workers Launched",
1474  nworkers, es);
1475  }
1476  }
1477  break;
1478  case T_FunctionScan:
1479  if (es->verbose)
1480  {
1481  List *fexprs = NIL;
1482  ListCell *lc;
1483 
1484  foreach(lc, ((FunctionScan *) plan)->functions)
1485  {
1486  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
1487 
1488  fexprs = lappend(fexprs, rtfunc->funcexpr);
1489  }
1490  /* We rely on show_expression to insert commas as needed */
1491  show_expression((Node *) fexprs,
1492  "Function Call", planstate, ancestors,
1493  es->verbose, es);
1494  }
1495  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1496  if (plan->qual)
1497  show_instrumentation_count("Rows Removed by Filter", 1,
1498  planstate, es);
1499  break;
1500  case T_TableFuncScan:
1501  if (es->verbose)
1502  {
1503  TableFunc *tablefunc = ((TableFuncScan *) plan)->tablefunc;
1504 
1505  show_expression((Node *) tablefunc,
1506  "Table Function Call", planstate, ancestors,
1507  es->verbose, es);
1508  }
1509  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1510  if (plan->qual)
1511  show_instrumentation_count("Rows Removed by Filter", 1,
1512  planstate, es);
1513  break;
1514  case T_TidScan:
1515  {
1516  /*
1517  * The tidquals list has OR semantics, so be sure to show it
1518  * as an OR condition.
1519  */
1520  List *tidquals = ((TidScan *) plan)->tidquals;
1521 
1522  if (list_length(tidquals) > 1)
1523  tidquals = list_make1(make_orclause(tidquals));
1524  show_scan_qual(tidquals, "TID Cond", planstate, ancestors, es);
1525  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1526  if (plan->qual)
1527  show_instrumentation_count("Rows Removed by Filter", 1,
1528  planstate, es);
1529  }
1530  break;
1531  case T_ForeignScan:
1532  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1533  if (plan->qual)
1534  show_instrumentation_count("Rows Removed by Filter", 1,
1535  planstate, es);
1536  show_foreignscan_info((ForeignScanState *) planstate, es);
1537  break;
1538  case T_CustomScan:
1539  {
1540  CustomScanState *css = (CustomScanState *) planstate;
1541 
1542  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1543  if (plan->qual)
1544  show_instrumentation_count("Rows Removed by Filter", 1,
1545  planstate, es);
1546  if (css->methods->ExplainCustomScan)
1547  css->methods->ExplainCustomScan(css, ancestors, es);
1548  }
1549  break;
1550  case T_NestLoop:
1551  show_upper_qual(((NestLoop *) plan)->join.joinqual,
1552  "Join Filter", planstate, ancestors, es);
1553  if (((NestLoop *) plan)->join.joinqual)
1554  show_instrumentation_count("Rows Removed by Join Filter", 1,
1555  planstate, es);
1556  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
1557  if (plan->qual)
1558  show_instrumentation_count("Rows Removed by Filter", 2,
1559  planstate, es);
1560  break;
1561  case T_MergeJoin:
1562  show_upper_qual(((MergeJoin *) plan)->mergeclauses,
1563  "Merge Cond", planstate, ancestors, es);
1564  show_upper_qual(((MergeJoin *) plan)->join.joinqual,
1565  "Join Filter", planstate, ancestors, es);
1566  if (((MergeJoin *) plan)->join.joinqual)
1567  show_instrumentation_count("Rows Removed by Join Filter", 1,
1568  planstate, es);
1569  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
1570  if (plan->qual)
1571  show_instrumentation_count("Rows Removed by Filter", 2,
1572  planstate, es);
1573  break;
1574  case T_HashJoin:
1575  show_upper_qual(((HashJoin *) plan)->hashclauses,
1576  "Hash Cond", planstate, ancestors, es);
1577  show_upper_qual(((HashJoin *) plan)->join.joinqual,
1578  "Join Filter", planstate, ancestors, es);
1579  if (((HashJoin *) plan)->join.joinqual)
1580  show_instrumentation_count("Rows Removed by Join Filter", 1,
1581  planstate, es);
1582  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
1583  if (plan->qual)
1584  show_instrumentation_count("Rows Removed by Filter", 2,
1585  planstate, es);
1586  break;
1587  case T_Agg:
1588  show_agg_keys(castNode(AggState, planstate), ancestors, es);
1589  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
1590  if (plan->qual)
1591  show_instrumentation_count("Rows Removed by Filter", 1,
1592  planstate, es);
1593  break;
1594  case T_Group:
1595  show_group_keys(castNode(GroupState, planstate), ancestors, es);
1596  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
1597  if (plan->qual)
1598  show_instrumentation_count("Rows Removed by Filter", 1,
1599  planstate, es);
1600  break;
1601  case T_Sort:
1602  show_sort_keys(castNode(SortState, planstate), ancestors, es);
1603  show_sort_info(castNode(SortState, planstate), es);
1604  break;
1605  case T_MergeAppend:
1607  ancestors, es);
1608  break;
1609  case T_Result:
1610  show_upper_qual((List *) ((Result *) plan)->resconstantqual,
1611  "One-Time Filter", planstate, ancestors, es);
1612  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
1613  if (plan->qual)
1614  show_instrumentation_count("Rows Removed by Filter", 1,
1615  planstate, es);
1616  break;
1617  case T_ModifyTable:
1618  show_modifytable_info(castNode(ModifyTableState, planstate), ancestors,
1619  es);
1620  break;
1621  case T_Hash:
1622  show_hash_info(castNode(HashState, planstate), es);
1623  break;
1624  default:
1625  break;
1626  }
1627 
1628  /* Show buffer usage */
1629  if (es->buffers && planstate->instrument)
1630  show_buffer_usage(es, &planstate->instrument->bufusage);
1631 
1632  /* Show worker detail */
1633  if (es->analyze && es->verbose && planstate->worker_instrument)
1634  {
1635  WorkerInstrumentation *w = planstate->worker_instrument;
1636  bool opened_group = false;
1637  int n;
1638 
1639  for (n = 0; n < w->num_workers; ++n)
1640  {
1641  Instrumentation *instrument = &w->instrument[n];
1642  double nloops = instrument->nloops;
1643  double startup_sec;
1644  double total_sec;
1645  double rows;
1646 
1647  if (nloops <= 0)
1648  continue;
1649  startup_sec = 1000.0 * instrument->startup / nloops;
1650  total_sec = 1000.0 * instrument->total / nloops;
1651  rows = instrument->ntuples / nloops;
1652 
1653  if (es->format == EXPLAIN_FORMAT_TEXT)
1654  {
1655  appendStringInfoSpaces(es->str, es->indent * 2);
1656  appendStringInfo(es->str, "Worker %d: ", n);
1657  if (es->timing)
1658  appendStringInfo(es->str,
1659  "actual time=%.3f..%.3f rows=%.0f loops=%.0f\n",
1660  startup_sec, total_sec, rows, nloops);
1661  else
1662  appendStringInfo(es->str,
1663  "actual rows=%.0f loops=%.0f\n",
1664  rows, nloops);
1665  es->indent++;
1666  if (es->buffers)
1667  show_buffer_usage(es, &instrument->bufusage);
1668  es->indent--;
1669  }
1670  else
1671  {
1672  if (!opened_group)
1673  {
1674  ExplainOpenGroup("Workers", "Workers", false, es);
1675  opened_group = true;
1676  }
1677  ExplainOpenGroup("Worker", NULL, true, es);
1678  ExplainPropertyInteger("Worker Number", n, es);
1679 
1680  if (es->timing)
1681  {
1682  ExplainPropertyFloat("Actual Startup Time", startup_sec, 3, es);
1683  ExplainPropertyFloat("Actual Total Time", total_sec, 3, es);
1684  }
1685  ExplainPropertyFloat("Actual Rows", rows, 0, es);
1686  ExplainPropertyFloat("Actual Loops", nloops, 0, es);
1687 
1688  if (es->buffers)
1689  show_buffer_usage(es, &instrument->bufusage);
1690 
1691  ExplainCloseGroup("Worker", NULL, true, es);
1692  }
1693  }
1694 
1695  if (opened_group)
1696  ExplainCloseGroup("Workers", "Workers", false, es);
1697  }
1698 
1699  /* Get ready to display the child plans */
1700  haschildren = planstate->initPlan ||
1701  outerPlanState(planstate) ||
1702  innerPlanState(planstate) ||
1703  IsA(plan, ModifyTable) ||
1704  IsA(plan, Append) ||
1705  IsA(plan, MergeAppend) ||
1706  IsA(plan, BitmapAnd) ||
1707  IsA(plan, BitmapOr) ||
1708  IsA(plan, SubqueryScan) ||
1709  (IsA(planstate, CustomScanState) &&
1710  ((CustomScanState *) planstate)->custom_ps != NIL) ||
1711  planstate->subPlan;
1712  if (haschildren)
1713  {
1714  ExplainOpenGroup("Plans", "Plans", false, es);
1715  /* Pass current PlanState as head of ancestors list for children */
1716  ancestors = lcons(planstate, ancestors);
1717  }
1718 
1719  /* initPlan-s */
1720  if (planstate->initPlan)
1721  ExplainSubPlans(planstate->initPlan, ancestors, "InitPlan", es);
1722 
1723  /* lefttree */
1724  if (outerPlanState(planstate))
1725  ExplainNode(outerPlanState(planstate), ancestors,
1726  "Outer", NULL, es);
1727 
1728  /* righttree */
1729  if (innerPlanState(planstate))
1730  ExplainNode(innerPlanState(planstate), ancestors,
1731  "Inner", NULL, es);
1732 
1733  /* special child plans */
1734  switch (nodeTag(plan))
1735  {
1736  case T_ModifyTable:
1737  ExplainMemberNodes(((ModifyTable *) plan)->plans,
1738  ((ModifyTableState *) planstate)->mt_plans,
1739  ancestors, es);
1740  break;
1741  case T_Append:
1742  ExplainMemberNodes(((Append *) plan)->appendplans,
1743  ((AppendState *) planstate)->appendplans,
1744  ancestors, es);
1745  break;
1746  case T_MergeAppend:
1747  ExplainMemberNodes(((MergeAppend *) plan)->mergeplans,
1748  ((MergeAppendState *) planstate)->mergeplans,
1749  ancestors, es);
1750  break;
1751  case T_BitmapAnd:
1752  ExplainMemberNodes(((BitmapAnd *) plan)->bitmapplans,
1753  ((BitmapAndState *) planstate)->bitmapplans,
1754  ancestors, es);
1755  break;
1756  case T_BitmapOr:
1757  ExplainMemberNodes(((BitmapOr *) plan)->bitmapplans,
1758  ((BitmapOrState *) planstate)->bitmapplans,
1759  ancestors, es);
1760  break;
1761  case T_SubqueryScan:
1762  ExplainNode(((SubqueryScanState *) planstate)->subplan, ancestors,
1763  "Subquery", NULL, es);
1764  break;
1765  case T_CustomScan:
1766  ExplainCustomChildren((CustomScanState *) planstate,
1767  ancestors, es);
1768  break;
1769  default:
1770  break;
1771  }
1772 
1773  /* subPlan-s */
1774  if (planstate->subPlan)
1775  ExplainSubPlans(planstate->subPlan, ancestors, "SubPlan", es);
1776 
1777  /* end of child plans */
1778  if (haschildren)
1779  {
1780  ancestors = list_delete_first(ancestors);
1781  ExplainCloseGroup("Plans", "Plans", false, es);
1782  }
1783 
1784  /* in text format, undo whatever indentation we added */
1785  if (es->format == EXPLAIN_FORMAT_TEXT)
1786  es->indent = save_indent;
1787 
1788  ExplainCloseGroup("Plan",
1789  relationship ? NULL : "Plan",
1790  true, es);
1791 }
static void ExplainMemberNodes(List *plans, PlanState **planstates, List *ancestors, ExplainState *es)
Definition: explain.c:2977
#define NIL
Definition: pg_list.h:69
List * qual
Definition: plannodes.h:145
double plan_rows
Definition: plannodes.h:131
Definition: nodes.h:77
void ExplainPropertyBool(const char *qlabel, bool value, ExplainState *es)
Definition: explain.c:3262
ScanDirection indexorderdir
Definition: plannodes.h:395
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
WorkerInstrumentation * worker_instrument
Definition: execnodes.h:858
Definition: nodes.h:79
Instrumentation * instrument
Definition: execnodes.h:857
static void show_modifytable_info(ModifyTableState *mtstate, List *ancestors, ExplainState *es)
Definition: explain.c:2816
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
void ExplainPropertyLong(const char *qlabel, long value, ExplainState *es)
Definition: explain.c:3236
List * initPlan
Definition: execnodes.h:868
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
double startup
Definition: instrument.h:57
void(* ExplainCustomScan)(CustomScanState *node, List *ancestors, ExplainState *es)
Definition: extensible.h:148
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3249
List * subPlan
Definition: execnodes.h:870
Definition: nodes.h:509
Definition: nodes.h:48
Definition: nodes.h:75
bool costs
Definition: explain.h:34
static void show_scan_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:1899
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:768
bool analyze
Definition: explain.h:33
void ExplainPropertyInteger(const char *qlabel, int value, ExplainState *es)
Definition: explain.c:3224
static void show_sort_info(SortState *sortstate, ExplainState *es)
Definition: explain.c:2289
Oid indexid
Definition: plannodes.h:389
static void show_upper_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:1913
static void show_instrumentation_count(const char *qlabel, int which, PlanState *planstate, ExplainState *es)
Definition: explain.c:2446
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:114
const struct CustomExecMethods * methods
Definition: execnodes.h:1573
#define list_make1(x1)
Definition: pg_list.h:139
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3215
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:862
AggStrategy aggstrategy
Definition: plannodes.h:783
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
Definition: nodes.h:45
bool single_copy
Definition: plannodes.h:842
Definition: nodes.h:76
#define outerPlanState(node)
Definition: execnodes.h:893
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
Cost startup_cost
Definition: plannodes.h:125
static void show_tablesample(TableSampleClause *tsc, PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:2223
bool parallel_aware
Definition: plannodes.h:137
ScanDirection indexorderdir
Definition: plannodes.h:422
double ntuples
Definition: instrument.h:59
int indent
Definition: explain.h:40
static void show_tidbitmap_info(BitmapHeapScanState *planstate, ExplainState *es)
Definition: explain.c:2418
static void ExplainModifyTarget(ModifyTable *plan, ExplainState *es)
Definition: explain.c:2684
static void ExplainIndexScanDetails(Oid indexid, ScanDirection indexorderdir, ExplainState *es)
Definition: explain.c:2632
static void show_group_keys(GroupState *gstate, List *ancestors, ExplainState *es)
Definition: explain.c:2090
static void show_buffer_usage(ExplainState *es, const BufferUsage *usage)
Definition: explain.c:2522
static void show_plan_tlist(PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:1797
List * lappend(List *list, void *datum)
Definition: list.c:128
bool timing
Definition: explain.h:36
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
Instrumentation instrument[FLEXIBLE_ARRAY_MEMBER]
Definition: instrument.h:69
bool verbose
Definition: explain.h:32
BufferUsage bufusage
Definition: instrument.h:63
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainCustomChildren(CustomScanState *css, List *ancestors, ExplainState *es)
Definition: explain.c:3029
Definition: nodes.h:82
Plan * plan
Definition: execnodes.h:847
int num_workers
Definition: plannodes.h:840
static void show_merge_append_keys(MergeAppendState *mstate, List *ancestors, ExplainState *es)
Definition: explain.c:1942
List * lcons(void *datum, List *list)
Definition: list.c:259
int plan_width
Definition: plannodes.h:132
#define lfirst(lc)
Definition: pg_list.h:106
AggSplit aggsplit
Definition: plannodes.h:784
static void ExplainSubPlans(List *plans, List *ancestors, const char *relationship, ExplainState *es)
Definition: explain.c:2995
static void show_hash_info(HashState *hashstate, ExplainState *es)
Definition: explain.c:2371
static void show_sort_keys(SortState *sortstate, List *ancestors, ExplainState *es)
Definition: explain.c:1927
static int list_length(const List *l)
Definition: pg_list.h:89
ExplainFormat format
Definition: explain.h:38
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:769
static const struct fns functions
Definition: regcomp.c:299
static const char * explain_get_index_name(Oid indexId)
Definition: explain.c:2499
#define nodeTag(nodeptr)
Definition: nodes.h:514
static void show_expression(Node *node, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
Definition: explain.c:1855
Definition: nodes.h:83
int num_workers
Definition: plannodes.h:853
Definition: nodes.h:80
Cost total_cost
Definition: plannodes.h:126
bool buffers
Definition: explain.h:35
static void show_foreignscan_info(ForeignScanState *fsstate, ExplainState *es)
Definition: explain.c:2475
static void ExplainScanTarget(Scan *plan, ExplainState *es)
Definition: explain.c:2671
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3340
Definition: plannodes.h:780
#define innerPlanState(node)
Definition: execnodes.h:892
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3277
Definition: pg_list.h:45
StringInfo str
Definition: explain.h:30
Expr * make_orclause(List *orclauses)
Definition: clauses.c:293
static void show_agg_keys(AggState *astate, List *ancestors, ExplainState *es)
Definition: explain.c:1958
List * list_delete_first(List *list)
Definition: list.c:666
Definition: nodes.h:85
void ExplainOnePlan ( PlannedStmt plannedstmt,
IntoClause into,
ExplainState es,
const char *  queryString,
ParamListInfo  params,
QueryEnvironment queryEnv,
const instr_time planduration 
)

Definition at line 463 of file explain.c.

References ExplainState::analyze, appendStringInfo(), Assert, ExplainState::buffers, CMD_UTILITY, CommandCounterIncrement(), PlannedStmt::commandType, CreateIntoRelDestReceiver(), CreateQueryDesc(), elapsed_time(), EXEC_FLAG_EXPLAIN_ONLY, ExecutorEnd(), ExecutorFinish(), ExecutorRun(), ExecutorStart(), EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), ExplainOpenGroup(), ExplainPrintPlan(), ExplainPrintTriggers(), ExplainPropertyFloat(), ExplainState::format, ForwardScanDirection, FreeQueryDesc(), GetActiveSnapshot(), GetIntoRelEFlags(), INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, INSTRUMENT_BUFFERS, INSTRUMENT_ROWS, INSTRUMENT_TIMER, InvalidSnapshot, NoMovementScanDirection, None_Receiver, PopActiveSnapshot(), PushCopiedSnapshot(), IntoClause::skipData, ExplainState::str, ExplainState::summary, ExplainState::timing, and UpdateActiveSnapshotCommandId().

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

466 {
467  DestReceiver *dest;
468  QueryDesc *queryDesc;
469  instr_time starttime;
470  double totaltime = 0;
471  int eflags;
472  int instrument_option = 0;
473 
474  Assert(plannedstmt->commandType != CMD_UTILITY);
475 
476  if (es->analyze && es->timing)
477  instrument_option |= INSTRUMENT_TIMER;
478  else if (es->analyze)
479  instrument_option |= INSTRUMENT_ROWS;
480 
481  if (es->buffers)
482  instrument_option |= INSTRUMENT_BUFFERS;
483 
484  /*
485  * We always collect timing for the entire statement, even when node-level
486  * timing is off, so we don't look at es->timing here. (We could skip
487  * this if !es->summary, but it's hardly worth the complication.)
488  */
489  INSTR_TIME_SET_CURRENT(starttime);
490 
491  /*
492  * Use a snapshot with an updated command ID to ensure this query sees
493  * results of any previously executed queries.
494  */
497 
498  /*
499  * Normally we discard the query's output, but if explaining CREATE TABLE
500  * AS, we'd better use the appropriate tuple receiver.
501  */
502  if (into)
503  dest = CreateIntoRelDestReceiver(into);
504  else
505  dest = None_Receiver;
506 
507  /* Create a QueryDesc for the query */
508  queryDesc = CreateQueryDesc(plannedstmt, queryString,
510  dest, params, queryEnv, instrument_option);
511 
512  /* Select execution options */
513  if (es->analyze)
514  eflags = 0; /* default run-to-completion flags */
515  else
516  eflags = EXEC_FLAG_EXPLAIN_ONLY;
517  if (into)
518  eflags |= GetIntoRelEFlags(into);
519 
520  /* call ExecutorStart to prepare the plan for execution */
521  ExecutorStart(queryDesc, eflags);
522 
523  /* Execute the plan for statistics if asked for */
524  if (es->analyze)
525  {
526  ScanDirection dir;
527 
528  /* EXPLAIN ANALYZE CREATE TABLE AS WITH NO DATA is weird */
529  if (into && into->skipData)
531  else
532  dir = ForwardScanDirection;
533 
534  /* run the plan */
535  ExecutorRun(queryDesc, dir, 0L, true);
536 
537  /* run cleanup too */
538  ExecutorFinish(queryDesc);
539 
540  /* We can't run ExecutorEnd 'till we're done printing the stats... */
541  totaltime += elapsed_time(&starttime);
542  }
543 
544  ExplainOpenGroup("Query", NULL, true, es);
545 
546  /* Create textual dump of plan tree */
547  ExplainPrintPlan(es, queryDesc);
548 
549  if (es->summary && planduration)
550  {
551  double plantime = INSTR_TIME_GET_DOUBLE(*planduration);
552 
553  if (es->format == EXPLAIN_FORMAT_TEXT)
554  appendStringInfo(es->str, "Planning time: %.3f ms\n",
555  1000.0 * plantime);
556  else
557  ExplainPropertyFloat("Planning Time", 1000.0 * plantime, 3, es);
558  }
559 
560  /* Print info about runtime of triggers */
561  if (es->analyze)
562  ExplainPrintTriggers(es, queryDesc);
563 
564  /*
565  * Close down the query and free resources. Include time for this in the
566  * total execution time (although it should be pretty minimal).
567  */
568  INSTR_TIME_SET_CURRENT(starttime);
569 
570  ExecutorEnd(queryDesc);
571 
572  FreeQueryDesc(queryDesc);
573 
575 
576  /* We need a CCI just in case query expanded to multiple plans */
577  if (es->analyze)
579 
580  totaltime += elapsed_time(&starttime);
581 
582  /*
583  * We only report execution time if we actually ran the query (that is,
584  * the user specified ANALYZE), and if summary reporting is enabled (the
585  * user can set SUMMARY OFF to not have the timing information included in
586  * the output). By default, ANALYZE sets SUMMARY to true.
587  */
588  if (es->summary && es->analyze)
589  {
590  if (es->format == EXPLAIN_FORMAT_TEXT)
591  appendStringInfo(es->str, "Execution time: %.3f ms\n",
592  1000.0 * totaltime);
593  else
594  ExplainPropertyFloat("Execution Time", 1000.0 * totaltime,
595  3, es);
596  }
597 
598  ExplainCloseGroup("Query", NULL, true, es);
599 }
bool summary
Definition: explain.h:37
void UpdateActiveSnapshotCommandId(void)
Definition: snapmgr.c:781
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
struct timeval instr_time
Definition: instr_time.h:147
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3249
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:147
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:839
void PopActiveSnapshot(void)
Definition: snapmgr.c:812
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:196
bool skipData
Definition: primnodes.h:115
DestReceiver * None_Receiver
Definition: dest.c:91
bool analyze
Definition: explain.h:33
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:461
int GetIntoRelEFlags(IntoClause *intoClause)
Definition: createas.c:392
void ExplainPrintTriggers(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:650
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
void ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:613
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:299
void PushCopiedSnapshot(Snapshot snapshot)
Definition: snapmgr.c:769
QueryDesc * CreateQueryDesc(PlannedStmt *plannedstmt, const char *sourceText, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, QueryEnvironment *queryEnv, int instrument_options)
Definition: pquery.c:67
ScanDirection
Definition: sdir.h:22
DestReceiver * CreateIntoRelDestReceiver(IntoClause *intoClause)
Definition: createas.c:423
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:401
bool timing
Definition: explain.h:36
#define InvalidSnapshot
Definition: snapshot.h:25
void CommandCounterIncrement(void)
Definition: xact.c:923
CmdType commandType
Definition: plannodes.h:45
#define Assert(condition)
Definition: c.h:664
ExplainFormat format
Definition: explain.h:38
static double elapsed_time(instr_time *starttime)
Definition: explain.c:778
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153
bool buffers
Definition: explain.h:35
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3340
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3277
StringInfo str
Definition: explain.h:30
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:58
static void ExplainOneQuery ( Query query,
int  cursorOptions,
IntoClause into,
ExplainState es,
const char *  queryString,
ParamListInfo  params,
QueryEnvironment queryEnv 
)
static

Definition at line 337 of file explain.c.

References CMD_UTILITY, Query::commandType, ExplainOnePlan(), ExplainOneQuery_hook, ExplainOneUtility(), INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, pg_plan_query(), and Query::utilityStmt.

Referenced by ExplainOneUtility(), and ExplainQuery().

341 {
342  /* planner will not cope with utility statements */
343  if (query->commandType == CMD_UTILITY)
344  {
345  ExplainOneUtility(query->utilityStmt, into, es, queryString, params,
346  queryEnv);
347  return;
348  }
349 
350  /* if an advisor plugin is present, let it manage things */
352  (*ExplainOneQuery_hook) (query, cursorOptions, into, es,
353  queryString, params);
354  else
355  {
356  PlannedStmt *plan;
357  instr_time planstart,
358  planduration;
359 
360  INSTR_TIME_SET_CURRENT(planstart);
361 
362  /* plan the query */
363  plan = pg_plan_query(query, cursorOptions, params);
364 
365  INSTR_TIME_SET_CURRENT(planduration);
366  INSTR_TIME_SUBTRACT(planduration, planstart);
367 
368  /* run it (if needed) and produce output */
369  ExplainOnePlan(plan, into, es, queryString, params, queryEnv,
370  &planduration);
371  }
372 }
void ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv, const instr_time *planduration)
Definition: explain.c:463
struct timeval instr_time
Definition: instr_time.h:147
Node * utilityStmt
Definition: parsenodes.h:118
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:167
ExplainOneQuery_hook_type ExplainOneQuery_hook
Definition: explain.c:44
CmdType commandType
Definition: parsenodes.h:110
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153
void ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: explain.c:386
PlannedStmt * pg_plan_query(Query *querytree, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:786
void ExplainOneUtility ( Node utilityStmt,
IntoClause into,
ExplainState es,
const char *  queryString,
ParamListInfo  params,
QueryEnvironment queryEnv 
)

Definition at line 386 of file explain.c.

References appendStringInfoString(), Assert, castNode, copyObject, EXPLAIN_FORMAT_TEXT, ExplainDummyGroup(), ExplainExecuteQuery(), ExplainOneQuery(), ExplainState::format, CreateTableAsStmt::into, IsA, linitial_node, list_length(), DeclareCursorStmt::options, DeclareCursorStmt::query, CreateTableAsStmt::query, QueryRewrite(), and ExplainState::str.

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

389 {
390  if (utilityStmt == NULL)
391  return;
392 
393  if (IsA(utilityStmt, CreateTableAsStmt))
394  {
395  /*
396  * We have to rewrite the contained SELECT and then pass it back to
397  * ExplainOneQuery. It's probably not really necessary to copy the
398  * contained parsetree another time, but let's be safe.
399  *
400  * Like ExecCreateTableAs, disallow parallelism in the plan.
401  */
402  CreateTableAsStmt *ctas = (CreateTableAsStmt *) utilityStmt;
403  List *rewritten;
404 
405  rewritten = QueryRewrite(castNode(Query, copyObject(ctas->query)));
406  Assert(list_length(rewritten) == 1);
407  ExplainOneQuery(linitial_node(Query, rewritten),
408  0, ctas->into, es,
409  queryString, params, queryEnv);
410  }
411  else if (IsA(utilityStmt, DeclareCursorStmt))
412  {
413  /*
414  * Likewise for DECLARE CURSOR.
415  *
416  * Notice that if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll
417  * actually run the query. This is different from pre-8.3 behavior
418  * but seems more useful than not running the query. No cursor will
419  * be created, however.
420  */
421  DeclareCursorStmt *dcs = (DeclareCursorStmt *) utilityStmt;
422  List *rewritten;
423 
424  rewritten = QueryRewrite(castNode(Query, copyObject(dcs->query)));
425  Assert(list_length(rewritten) == 1);
426  ExplainOneQuery(linitial_node(Query, rewritten),
427  dcs->options, NULL, es,
428  queryString, params, queryEnv);
429  }
430  else if (IsA(utilityStmt, ExecuteStmt))
431  ExplainExecuteQuery((ExecuteStmt *) utilityStmt, into, es,
432  queryString, params, queryEnv);
433  else if (IsA(utilityStmt, NotifyStmt))
434  {
435  if (es->format == EXPLAIN_FORMAT_TEXT)
436  appendStringInfoString(es->str, "NOTIFY\n");
437  else
438  ExplainDummyGroup("Notify", NULL, es);
439  }
440  else
441  {
442  if (es->format == EXPLAIN_FORMAT_TEXT)
444  "Utility statements have no plan structure\n");
445  else
446  ExplainDummyGroup("Utility Statement", NULL, es);
447  }
448 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
List * QueryRewrite(Query *parsetree)
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
#define linitial_node(type, l)
Definition: pg_list.h:114
static void ExplainDummyGroup(const char *objtype, const char *labelname, ExplainState *es)
Definition: explain.c:3376
void ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: prepare.c:631
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static void ExplainOneQuery(Query *query, int cursorOptions, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: explain.c:337
IntoClause * into
Definition: parsenodes.h:3141
#define Assert(condition)
Definition: c.h:664
static int list_length(const List *l)
Definition: pg_list.h:89
ExplainFormat format
Definition: explain.h:38
#define copyObject(obj)
Definition: nodes.h:622
Definition: pg_list.h:45
StringInfo str
Definition: explain.h:30
void ExplainOpenGroup ( const char *  objtype,
const char *  labelname,
bool  labeled,
ExplainState es 
)

Definition at line 3277 of file explain.c.

References appendStringInfo(), appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), escape_json(), EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainJSONLineEnding(), ExplainXMLTag(), ExplainYAMLLineStarting(), ExplainState::format, ExplainState::grouping_stack, ExplainState::indent, lcons_int(), ExplainState::str, and X_OPENING.

Referenced by ExplainNode(), ExplainOnePlan(), ExplainPrintTriggers(), report_triggers(), show_grouping_set_keys(), show_grouping_sets(), show_modifytable_info(), and show_sort_info().

3279 {
3280  switch (es->format)
3281  {
3282  case EXPLAIN_FORMAT_TEXT:
3283  /* nothing to do */
3284  break;
3285 
3286  case EXPLAIN_FORMAT_XML:
3287  ExplainXMLTag(objtype, X_OPENING, es);
3288  es->indent++;
3289  break;
3290 
3291  case EXPLAIN_FORMAT_JSON:
3293  appendStringInfoSpaces(es->str, 2 * es->indent);
3294  if (labelname)
3295  {
3296  escape_json(es->str, labelname);
3297  appendStringInfoString(es->str, ": ");
3298  }
3299  appendStringInfoChar(es->str, labeled ? '{' : '[');
3300 
3301  /*
3302  * In JSON format, the grouping_stack is an integer list. 0 means
3303  * we've emitted nothing at this grouping level, 1 means we've
3304  * emitted something (and so the next item needs a comma). See
3305  * ExplainJSONLineEnding().
3306  */
3307  es->grouping_stack = lcons_int(0, es->grouping_stack);
3308  es->indent++;
3309  break;
3310 
3311  case EXPLAIN_FORMAT_YAML:
3312 
3313  /*
3314  * In YAML format, the grouping stack is an integer list. 0 means
3315  * we've emitted nothing at this grouping level AND this grouping
3316  * level is unlabelled and must be marked with "- ". See
3317  * ExplainYAMLLineStarting().
3318  */
3320  if (labelname)
3321  {
3322  appendStringInfo(es->str, "%s: ", labelname);
3323  es->grouping_stack = lcons_int(1, es->grouping_stack);
3324  }
3325  else
3326  {
3327  appendStringInfoString(es->str, "- ");
3328  es->grouping_stack = lcons_int(0, es->grouping_stack);
3329  }
3330  es->indent++;
3331  break;
3332  }
3333 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2433
List * lcons_int(int datum, List *list)
Definition: list.c:277
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3511
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3558
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3538
#define X_OPENING
Definition: explain.c:51
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
static bool ExplainPreScanNode ( PlanState planstate,
Bitmapset **  rels_used 
)
static

Definition at line 797 of file explain.c.

References bms_add_member(), bms_add_members(), nodeTag, PlanState::plan, planstate_tree_walker(), T_BitmapHeapScan, T_CteScan, T_CustomScan, T_ForeignScan, T_FunctionScan, T_IndexOnlyScan, T_IndexScan, T_ModifyTable, T_NamedTuplestoreScan, T_SampleScan, T_SeqScan, T_SubqueryScan, T_TableFuncScan, T_TidScan, T_ValuesScan, and T_WorkTableScan.

Referenced by ExplainPrintPlan().

798 {
799  Plan *plan = planstate->plan;
800 
801  switch (nodeTag(plan))
802  {
803  case T_SeqScan:
804  case T_SampleScan:
805  case T_IndexScan:
806  case T_IndexOnlyScan:
807  case T_BitmapHeapScan:
808  case T_TidScan:
809  case T_SubqueryScan:
810  case T_FunctionScan:
811  case T_TableFuncScan:
812  case T_ValuesScan:
813  case T_CteScan:
815  case T_WorkTableScan:
816  *rels_used = bms_add_member(*rels_used,
817  ((Scan *) plan)->scanrelid);
818  break;
819  case T_ForeignScan:
820  *rels_used = bms_add_members(*rels_used,
821  ((ForeignScan *) plan)->fs_relids);
822  break;
823  case T_CustomScan:
824  *rels_used = bms_add_members(*rels_used,
825  ((CustomScan *) plan)->custom_relids);
826  break;
827  case T_ModifyTable:
828  *rels_used = bms_add_member(*rels_used,
829  ((ModifyTable *) plan)->nominalRelation);
830  if (((ModifyTable *) plan)->exclRelRTI)
831  *rels_used = bms_add_member(*rels_used,
832  ((ModifyTable *) plan)->exclRelRTI);
833  break;
834  default:
835  break;
836  }
837 
838  return planstate_tree_walker(planstate, ExplainPreScanNode, rels_used);
839 }
Plan * plan
Definition: execnodes.h:847
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
#define nodeTag(nodeptr)
Definition: nodes.h:514
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
Definition: explain.c:797
bool planstate_tree_walker(PlanState *planstate, bool(*walker)(), void *context)
Definition: nodeFuncs.c:3697
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:755
void ExplainPrintPlan ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 613 of file explain.c.

References Assert, deparse_context_for_plan_rtable(), ExplainState::deparse_cxt, ExplainNode(), ExplainPreScanNode(), IsA, NIL, outerPlanState, PlanState::plan, QueryDesc::plannedstmt, QueryDesc::planstate, ExplainState::printed_subplans, ExplainState::pstmt, ExplainState::rtable, PlannedStmt::rtable, ExplainState::rtable_names, and select_rtable_names_for_explain().

Referenced by explain_ExecutorEnd(), and ExplainOnePlan().

614 {
615  Bitmapset *rels_used = NULL;
616  PlanState *ps;
617 
618  /* Set up ExplainState fields associated with this plan tree */
619  Assert(queryDesc->plannedstmt != NULL);
620  es->pstmt = queryDesc->plannedstmt;
621  es->rtable = queryDesc->plannedstmt->rtable;
622  ExplainPreScanNode(queryDesc->planstate, &rels_used);
625  es->rtable_names);
626  es->printed_subplans = NULL;
627 
628  /*
629  * Sometimes we mark a Gather node as "invisible", which means that it's
630  * not displayed in EXPLAIN output. The purpose of this is to allow
631  * running regression tests with force_parallel_mode=regress to get the
632  * same results as running the same tests with force_parallel_mode=off.
633  */
634  ps = queryDesc->planstate;
635  if (IsA(ps, GatherState) &&((Gather *) ps->plan)->invisible)
636  ps = outerPlanState(ps);
637  ExplainNode(ps, NIL, NULL, NULL, es);
638 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
Bitmapset * printed_subplans
Definition: explain.h:47
List * deparse_cxt
Definition: explain.h:46
PlannedStmt * pstmt
Definition: explain.h:43
List * rtable_names
Definition: explain.h:45
List * select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
Definition: ruleutils.c:3161
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:862
PlanState * planstate
Definition: execdesc.h:49
#define outerPlanState(node)
Definition: execnodes.h:893
Plan * plan
Definition: execnodes.h:847
#define Assert(condition)
Definition: c.h:664
List * rtable
Definition: plannodes.h:63
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
Definition: explain.c:797
PlannedStmt * plannedstmt
Definition: execdesc.h:37
List * deparse_context_for_plan_rtable(List *rtable, List *rtable_names)
Definition: ruleutils.c:3086
List * rtable
Definition: explain.h:44
void ExplainPrintTriggers ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 650 of file explain.c.

References EState::es_leaf_result_relations, EState::es_num_result_relations, EState::es_num_root_result_relations, EState::es_result_relations, EState::es_root_result_relations, EState::es_trig_target_relations, QueryDesc::estate, ExplainCloseGroup(), ExplainOpenGroup(), lfirst, NIL, and report_triggers().

Referenced by explain_ExecutorEnd(), and ExplainOnePlan().

651 {
652  ResultRelInfo *rInfo;
653  bool show_relname;
654  int numrels = queryDesc->estate->es_num_result_relations;
655  int numrootrels = queryDesc->estate->es_num_root_result_relations;
656  List *leafrels = queryDesc->estate->es_leaf_result_relations;
657  List *targrels = queryDesc->estate->es_trig_target_relations;
658  int nr;
659  ListCell *l;
660 
661  ExplainOpenGroup("Triggers", "Triggers", false, es);
662 
663  show_relname = (numrels > 1 || numrootrels > 0 ||
664  leafrels != NIL || targrels != NIL);
665  rInfo = queryDesc->estate->es_result_relations;
666  for (nr = 0; nr < numrels; rInfo++, nr++)
667  report_triggers(rInfo, show_relname, es);
668 
669  rInfo = queryDesc->estate->es_root_result_relations;
670  for (nr = 0; nr < numrootrels; rInfo++, nr++)
671  report_triggers(rInfo, show_relname, es);
672 
673  foreach(l, leafrels)
674  {
675  rInfo = (ResultRelInfo *) lfirst(l);
676  report_triggers(rInfo, show_relname, es);
677  }
678 
679  foreach(l, targrels)
680  {
681  rInfo = (ResultRelInfo *) lfirst(l);
682  report_triggers(rInfo, show_relname, es);
683  }
684 
685  ExplainCloseGroup("Triggers", "Triggers", false, es);
686 }
#define NIL
Definition: pg_list.h:69
EState * estate
Definition: execdesc.h:48
ResultRelInfo * es_result_relations
Definition: execnodes.h:441
List * es_leaf_result_relations
Definition: execnodes.h:456
static void report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
Definition: explain.c:708
int es_num_root_result_relations
Definition: execnodes.h:453
List * es_trig_target_relations
Definition: execnodes.h:459
int es_num_result_relations
Definition: execnodes.h:442
#define lfirst(lc)
Definition: pg_list.h:106
ResultRelInfo * es_root_result_relations
Definition: execnodes.h:452
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3340
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3277
Definition: pg_list.h:45
static void ExplainProperty ( const char *  qlabel,
const char *  value,
bool  numeric,
ExplainState es 
)
static

Definition at line 3165 of file explain.c.

References appendStringInfo(), appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), escape_json(), escape_xml(), escape_yaml(), EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainJSONLineEnding(), ExplainXMLTag(), ExplainYAMLLineStarting(), ExplainState::format, ExplainState::indent, pfree(), ExplainState::str, X_CLOSING, X_NOWHITESPACE, and X_OPENING.

Referenced by ExplainPropertyBool(), ExplainPropertyFloat(), ExplainPropertyInteger(), ExplainPropertyLong(), ExplainPropertyText(), and show_modifytable_info().

3167 {
3168  switch (es->format)
3169  {
3170  case EXPLAIN_FORMAT_TEXT:
3171  appendStringInfoSpaces(es->str, es->indent * 2);
3172  appendStringInfo(es->str, "%s: %s\n", qlabel, value);
3173  break;
3174 
3175  case EXPLAIN_FORMAT_XML:
3176  {
3177  char *str;
3178 
3179  appendStringInfoSpaces(es->str, es->indent * 2);
3180  ExplainXMLTag(qlabel, X_OPENING | X_NOWHITESPACE, es);
3181  str = escape_xml(value);
3182  appendStringInfoString(es->str, str);
3183  pfree(str);
3184  ExplainXMLTag(qlabel, X_CLOSING | X_NOWHITESPACE, es);
3185  appendStringInfoChar(es->str, '\n');
3186  }
3187  break;
3188 
3189  case EXPLAIN_FORMAT_JSON:
3191  appendStringInfoSpaces(es->str, es->indent * 2);
3192  escape_json(es->str, qlabel);
3193  appendStringInfoString(es->str, ": ");
3194  if (numeric)
3196  else
3197  escape_json(es->str, value);
3198  break;
3199 
3200  case EXPLAIN_FORMAT_YAML:
3202  appendStringInfo(es->str, "%s: ", qlabel);
3203  if (numeric)
3205  else
3206  escape_yaml(es->str, value);
3207  break;
3208  }
3209 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2433
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3511
#define X_CLOSING
Definition: explain.c:52
void pfree(void *pointer)
Definition: mcxt.c:949
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
static struct @121 value
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3558
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3583
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3538
#define X_OPENING
Definition: explain.c:51
#define X_NOWHITESPACE
Definition: explain.c:54
ExplainFormat format
Definition: explain.h:38
char * escape_xml(const char *str)
Definition: xml.c:2232
StringInfo str
Definition: explain.h:30
void ExplainPropertyBool ( const char *  qlabel,
bool  value,
ExplainState es 
)

Definition at line 3262 of file explain.c.

References ExplainProperty().

Referenced by ExplainNode().

3263 {
3264  ExplainProperty(qlabel, value ? "true" : "false", true, es);
3265 }
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3165
static struct @121 value
void ExplainPropertyFloat ( const char *  qlabel,
double  value,
int  ndigits,
ExplainState es 
)

Definition at line 3249 of file explain.c.

References buf, ExplainProperty(), and snprintf().

Referenced by ExplainNode(), ExplainOnePlan(), report_triggers(), show_buffer_usage(), show_instrumentation_count(), and show_modifytable_info().

3251 {
3252  char buf[256];
3253 
3254  snprintf(buf, sizeof(buf), "%.*f", ndigits, value);
3255  ExplainProperty(qlabel, buf, true, es);
3256 }
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3165
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static struct @121 value
static char * buf
Definition: pg_test_fsync.c:67
void ExplainPropertyInteger ( const char *  qlabel,
int  value,
ExplainState es 
)

Definition at line 3224 of file explain.c.

References buf, ExplainProperty(), and snprintf().

Referenced by ExplainNode(), and show_sort_info().

3225 {
3226  char buf[32];
3227 
3228  snprintf(buf, sizeof(buf), "%d", value);
3229  ExplainProperty(qlabel, buf, true, es);
3230 }
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3165
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static struct @121 value
static char * buf
Definition: pg_test_fsync.c:67
void ExplainPropertyList ( const char *  qlabel,
List data,
ExplainState es 
)

Definition at line 3044 of file explain.c.

References appendStringInfo(), appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), escape_json(), escape_xml(), escape_yaml(), EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainJSONLineEnding(), ExplainXMLTag(), ExplainYAMLLineStarting(), ExplainState::format, ExplainState::indent, lfirst, pfree(), ExplainState::str, X_CLOSING, and X_OPENING.

Referenced by ExplainPropertyListNested(), show_modifytable_info(), show_plan_tlist(), show_sort_group_keys(), and show_tablesample().

3045 {
3046  ListCell *lc;
3047  bool first = true;
3048 
3049  switch (es->format)
3050  {
3051  case EXPLAIN_FORMAT_TEXT:
3052  appendStringInfoSpaces(es->str, es->indent * 2);
3053  appendStringInfo(es->str, "%s: ", qlabel);
3054  foreach(lc, data)
3055  {
3056  if (!first)
3057  appendStringInfoString(es->str, ", ");
3058  appendStringInfoString(es->str, (const char *) lfirst(lc));
3059  first = false;
3060  }
3061  appendStringInfoChar(es->str, '\n');
3062  break;
3063 
3064  case EXPLAIN_FORMAT_XML:
3065  ExplainXMLTag(qlabel, X_OPENING, es);
3066  foreach(lc, data)
3067  {
3068  char *str;
3069 
3070  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
3071  appendStringInfoString(es->str, "<Item>");
3072  str = escape_xml((const char *) lfirst(lc));
3073  appendStringInfoString(es->str, str);
3074  pfree(str);
3075  appendStringInfoString(es->str, "</Item>\n");
3076  }
3077  ExplainXMLTag(qlabel, X_CLOSING, es);
3078  break;
3079 
3080  case EXPLAIN_FORMAT_JSON:
3082  appendStringInfoSpaces(es->str, es->indent * 2);
3083  escape_json(es->str, qlabel);
3084  appendStringInfoString(es->str, ": [");
3085  foreach(lc, data)
3086  {
3087  if (!first)
3088  appendStringInfoString(es->str, ", ");
3089  escape_json(es->str, (const char *) lfirst(lc));
3090  first = false;
3091  }
3092  appendStringInfoChar(es->str, ']');
3093  break;
3094 
3095  case EXPLAIN_FORMAT_YAML:
3097  appendStringInfo(es->str, "%s: ", qlabel);
3098  foreach(lc, data)
3099  {
3100  appendStringInfoChar(es->str, '\n');
3101  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
3102  appendStringInfoString(es->str, "- ");
3103  escape_yaml(es->str, (const char *) lfirst(lc));
3104  }
3105  break;
3106  }
3107 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2433
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3511
#define X_CLOSING
Definition: explain.c:52
void pfree(void *pointer)
Definition: mcxt.c:949
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3558
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3583
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3538
#define X_OPENING
Definition: explain.c:51
#define lfirst(lc)
Definition: pg_list.h:106
ExplainFormat format
Definition: explain.h:38
char * escape_xml(const char *str)
Definition: xml.c:2232
StringInfo str
Definition: explain.h:30
void ExplainPropertyListNested ( const char *  qlabel,
List data,
ExplainState es 
)

Definition at line 3114 of file explain.c.

References appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), escape_json(), escape_yaml(), EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainJSONLineEnding(), ExplainPropertyList(), ExplainYAMLLineStarting(), ExplainState::format, ExplainState::indent, lfirst, and ExplainState::str.

Referenced by show_grouping_set_keys().

3115 {
3116  ListCell *lc;
3117  bool first = true;
3118 
3119  switch (es->format)
3120  {
3121  case EXPLAIN_FORMAT_TEXT:
3122  case EXPLAIN_FORMAT_XML:
3123  ExplainPropertyList(qlabel, data, es);
3124  return;
3125 
3126  case EXPLAIN_FORMAT_JSON:
3128  appendStringInfoSpaces(es->str, es->indent * 2);
3129  appendStringInfoChar(es->str, '[');
3130  foreach(lc, data)
3131  {
3132  if (!first)
3133  appendStringInfoString(es->str, ", ");
3134  escape_json(es->str, (const char *) lfirst(lc));
3135  first = false;
3136  }
3137  appendStringInfoChar(es->str, ']');
3138  break;
3139 
3140  case EXPLAIN_FORMAT_YAML:
3142  appendStringInfoString(es->str, "- [");
3143  foreach(lc, data)
3144  {
3145  if (!first)
3146  appendStringInfoString(es->str, ", ");
3147  escape_yaml(es->str, (const char *) lfirst(lc));
3148  first = false;
3149  }
3150  appendStringInfoChar(es->str, ']');
3151  break;
3152  }
3153 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2433
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3558
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3583
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3538
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:3044
#define lfirst(lc)
Definition: pg_list.h:106
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
void ExplainPropertyLong ( const char *  qlabel,
long  value,
ExplainState es 
)

Definition at line 3236 of file explain.c.

References buf, ExplainProperty(), and snprintf().

Referenced by ExplainNode(), fileExplainForeignScan(), show_buffer_usage(), show_hash_info(), show_sort_info(), and show_tidbitmap_info().

3237 {
3238  char buf[32];
3239 
3240  snprintf(buf, sizeof(buf), "%ld", value);
3241  ExplainProperty(qlabel, buf, true, es);
3242 }
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3165
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static struct @121 value
static char * buf
Definition: pg_test_fsync.c:67
void ExplainPropertyText ( const char *  qlabel,
const char *  value,
ExplainState es 
)

Definition at line 3215 of file explain.c.

References ExplainProperty().

Referenced by ExplainIndexScanDetails(), ExplainNode(), ExplainQueryText(), ExplainTargetRel(), fileExplainForeignScan(), postgresExplainDirectModify(), postgresExplainForeignModify(), postgresExplainForeignScan(), report_triggers(), show_expression(), show_grouping_set_keys(), show_sort_info(), and show_tablesample().

3216 {
3217  ExplainProperty(qlabel, value, false, es);
3218 }
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3165
static struct @121 value
void ExplainQuery ( ParseState pstate,
ExplainStmt stmt,
const char *  queryString,
ParamListInfo  params,
QueryEnvironment queryEnv,
DestReceiver dest 
)

Definition at line 141 of file explain.c.

References ExplainState::analyze, appendStringInfoString(), Assert, begin_tup_output_tupdesc(), ExplainState::buffers, castNode, copyObject, ExplainState::costs, CURSOR_OPT_PARALLEL_OK, StringInfoData::data, defGetBoolean(), defGetString(), DefElem::defname, do_text_output_multiline(), do_text_output_oneline, end_tup_output(), ereport, errcode(), errmsg(), ERROR, EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainBeginOutput(), ExplainEndOutput(), ExplainOneQuery(), ExplainResultDesc(), ExplainSeparatePlans(), ExplainState::format, ExplainState::indent, lfirst, lfirst_node, lnext, DefElem::location, NewExplainState(), NIL, ExplainStmt::options, parser_errposition(), pfree(), ExplainStmt::query, QueryRewrite(), ExplainState::str, ExplainState::summary, ExplainState::timing, and ExplainState::verbose.

Referenced by standard_ProcessUtility().

144 {
146  TupOutputState *tstate;
147  List *rewritten;
148  ListCell *lc;
149  bool timing_set = false;
150  bool summary_set = false;
151 
152  /* Parse options list. */
153  foreach(lc, stmt->options)
154  {
155  DefElem *opt = (DefElem *) lfirst(lc);
156 
157  if (strcmp(opt->defname, "analyze") == 0)
158  es->analyze = defGetBoolean(opt);
159  else if (strcmp(opt->defname, "verbose") == 0)
160  es->verbose = defGetBoolean(opt);
161  else if (strcmp(opt->defname, "costs") == 0)
162  es->costs = defGetBoolean(opt);
163  else if (strcmp(opt->defname, "buffers") == 0)
164  es->buffers = defGetBoolean(opt);
165  else if (strcmp(opt->defname, "timing") == 0)
166  {
167  timing_set = true;
168  es->timing = defGetBoolean(opt);
169  }
170  else if (strcmp(opt->defname, "summary") == 0)
171  {
172  summary_set = true;
173  es->summary = defGetBoolean(opt);
174  }
175  else if (strcmp(opt->defname, "format") == 0)
176  {
177  char *p = defGetString(opt);
178 
179  if (strcmp(p, "text") == 0)
181  else if (strcmp(p, "xml") == 0)
183  else if (strcmp(p, "json") == 0)
185  else if (strcmp(p, "yaml") == 0)
187  else
188  ereport(ERROR,
189  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
190  errmsg("unrecognized value for EXPLAIN option \"%s\": \"%s\"",
191  opt->defname, p),
192  parser_errposition(pstate, opt->location)));
193  }
194  else
195  ereport(ERROR,
196  (errcode(ERRCODE_SYNTAX_ERROR),
197  errmsg("unrecognized EXPLAIN option \"%s\"",
198  opt->defname),
199  parser_errposition(pstate, opt->location)));
200  }
201 
202  if (es->buffers && !es->analyze)
203  ereport(ERROR,
204  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
205  errmsg("EXPLAIN option BUFFERS requires ANALYZE")));
206 
207  /* if the timing was not set explicitly, set default value */
208  es->timing = (timing_set) ? es->timing : es->analyze;
209 
210  /* check that timing is used with EXPLAIN ANALYZE */
211  if (es->timing && !es->analyze)
212  ereport(ERROR,
213  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
214  errmsg("EXPLAIN option TIMING requires ANALYZE")));
215 
216  /* if the summary was not set explicitly, set default value */
217  es->summary = (summary_set) ? es->summary : es->analyze;
218 
219  /*
220  * Parse analysis was done already, but we still have to run the rule
221  * rewriter. We do not do AcquireRewriteLocks: we assume the query either
222  * came straight from the parser, or suitable locks were acquired by
223  * plancache.c.
224  *
225  * Because the rewriter and planner tend to scribble on the input, we make
226  * a preliminary copy of the source querytree. This prevents problems in
227  * the case that the EXPLAIN is in a portal or plpgsql function and is
228  * executed repeatedly. (See also the same hack in DECLARE CURSOR and
229  * PREPARE.) XXX FIXME someday.
230  */
231  rewritten = QueryRewrite(castNode(Query, copyObject(stmt->query)));
232 
233  /* emit opening boilerplate */
234  ExplainBeginOutput(es);
235 
236  if (rewritten == NIL)
237  {
238  /*
239  * In the case of an INSTEAD NOTHING, tell at least that. But in
240  * non-text format, the output is delimited, so this isn't necessary.
241  */
242  if (es->format == EXPLAIN_FORMAT_TEXT)
243  appendStringInfoString(es->str, "Query rewrites to nothing\n");
244  }
245  else
246  {
247  ListCell *l;
248 
249  /* Explain every plan */
250  foreach(l, rewritten)
251  {
253  CURSOR_OPT_PARALLEL_OK, NULL, es,
254  queryString, params, queryEnv);
255 
256  /* Separate plans with an appropriate separator */
257  if (lnext(l) != NULL)
259  }
260  }
261 
262  /* emit closing boilerplate */
263  ExplainEndOutput(es);
264  Assert(es->indent == 0);
265 
266  /* output tuples */
267  tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt));
268  if (es->format == EXPLAIN_FORMAT_TEXT)
269  do_text_output_multiline(tstate, es->str->data);
270  else
271  do_text_output_oneline(tstate, es->str->data);
272  end_tup_output(tstate);
273 
274  pfree(es->str->data);
275 }
#define NIL
Definition: pg_list.h:69
bool summary
Definition: explain.h:37
ExplainState * NewExplainState(void)
Definition: explain.c:281
List * QueryRewrite(Query *parsetree)
void ExplainSeparatePlans(ExplainState *es)
Definition: explain.c:3482
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
int errcode(int sqlerrcode)
Definition: elog.c:575
List * options
Definition: parsenodes.h:3121
bool costs
Definition: explain.h:34
bool analyze
Definition: explain.h:33
Node * query
Definition: parsenodes.h:3120
void ExplainEndOutput(ExplainState *es)
Definition: explain.c:3453
bool defGetBoolean(DefElem *def)
Definition: define.c:111
void pfree(void *pointer)
Definition: mcxt.c:949
void end_tup_output(TupOutputState *tstate)
Definition: execTuples.c:1311
void ExplainBeginOutput(ExplainState *es)
Definition: explain.c:3422
#define ERROR
Definition: elog.h:43
TupleDesc ExplainResultDesc(ExplainStmt *stmt)
Definition: explain.c:298
char * defGetString(DefElem *def)
Definition: define.c:49
#define lfirst_node(type, lc)
Definition: pg_list.h:109
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
int location
Definition: parsenodes.h:722
int indent
Definition: explain.h:40
#define lnext(lc)
Definition: pg_list.h:105
#define ereport(elevel, rest)
Definition: elog.h:122
bool timing
Definition: explain.h:36
TupOutputState * begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc)
Definition: execTuples.c:1235
static void ExplainOneQuery(Query *query, int cursorOptions, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: explain.c:337
void do_text_output_multiline(TupOutputState *tstate, const char *txt)
Definition: execTuples.c:1281
bool verbose
Definition: explain.h:32
#define Assert(condition)
Definition: c.h:664
#define lfirst(lc)
Definition: pg_list.h:106
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
ExplainFormat format
Definition: explain.h:38
#define do_text_output_oneline(tstate, str_to_emit)
Definition: executor.h:449
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2639
int errmsg(const char *fmt,...)
Definition: elog.c:797
bool buffers
Definition: explain.h:35
char * defname
Definition: parsenodes.h:719
#define copyObject(obj)
Definition: nodes.h:622
Definition: pg_list.h:45
StringInfo str
Definition: explain.h:30
void ExplainQueryText ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 697 of file explain.c.

References ExplainPropertyText(), and QueryDesc::sourceText.

Referenced by explain_ExecutorEnd().

698 {
699  if (queryDesc->sourceText)
700  ExplainPropertyText("Query Text", queryDesc->sourceText, es);
701 }
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3215
const char * sourceText
Definition: execdesc.h:38
TupleDesc ExplainResultDesc ( ExplainStmt stmt)

Definition at line 298 of file explain.c.

References CreateTemplateTupleDesc(), defGetString(), DefElem::defname, JSONOID, lfirst, ExplainStmt::options, TEXTOID, TupleDescInitEntry(), and XMLOID.

Referenced by ExplainQuery(), and UtilityTupleDescriptor().

299 {
300  TupleDesc tupdesc;
301  ListCell *lc;
302  Oid result_type = TEXTOID;
303 
304  /* Check for XML format option */
305  foreach(lc, stmt->options)
306  {
307  DefElem *opt = (DefElem *) lfirst(lc);
308 
309  if (strcmp(opt->defname, "format") == 0)
310  {
311  char *p = defGetString(opt);
312 
313  if (strcmp(p, "xml") == 0)
314  result_type = XMLOID;
315  else if (strcmp(p, "json") == 0)
316  result_type = JSONOID;
317  else
318  result_type = TEXTOID;
319  /* don't "break", as ExplainQuery will use the last value */
320  }
321  }
322 
323  /* Need a tuple descriptor representing a single TEXT or XML column */
324  tupdesc = CreateTemplateTupleDesc(1, false);
325  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
326  result_type, -1, 0);
327  return tupdesc;
328 }
#define TEXTOID
Definition: pg_type.h:324
#define JSONOID
Definition: pg_type.h:356
List * options
Definition: parsenodes.h:3121
unsigned int Oid
Definition: postgres_ext.h:31
char * defGetString(DefElem *def)
Definition: define.c:49
#define XMLOID
Definition: pg_type.h:359
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:505
#define lfirst(lc)
Definition: pg_list.h:106
TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid)
Definition: tupdesc.c:43
char * defname
Definition: parsenodes.h:719
int16 AttrNumber
Definition: attnum.h:21
static void ExplainScanTarget ( Scan plan,
ExplainState es 
)
static

Definition at line 2671 of file explain.c.

References ExplainTargetRel(), and Scan::scanrelid.

Referenced by ExplainNode().

2672 {
2673  ExplainTargetRel((Plan *) plan, plan->scanrelid, es);
2674 }
Index scanrelid
Definition: plannodes.h:329
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:2693
void ExplainSeparatePlans ( ExplainState es)

Definition at line 3482 of file explain.c.

References appendStringInfoChar(), EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainState::format, and ExplainState::str.

Referenced by ExplainExecuteQuery(), and ExplainQuery().

3483 {
3484  switch (es->format)
3485  {
3486  case EXPLAIN_FORMAT_TEXT:
3487  /* add a blank line */
3488  appendStringInfoChar(es->str, '\n');
3489  break;
3490 
3491  case EXPLAIN_FORMAT_XML:
3492  case EXPLAIN_FORMAT_JSON:
3493  case EXPLAIN_FORMAT_YAML:
3494  /* nothing to do */
3495  break;
3496  }
3497 }
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
static void ExplainSubPlans ( List plans,
List ancestors,
const char *  relationship,
ExplainState es 
)
static

Definition at line 2995 of file explain.c.

References bms_add_member(), bms_is_member(), ExplainNode(), lfirst, SubPlan::plan_id, SubPlan::plan_name, SubPlanState::planstate, ExplainState::printed_subplans, and SubPlanState::subplan.

Referenced by ExplainNode().

2997 {
2998  ListCell *lst;
2999 
3000  foreach(lst, plans)
3001  {
3002  SubPlanState *sps = (SubPlanState *) lfirst(lst);
3003  SubPlan *sp = sps->subplan;
3004 
3005  /*
3006  * There can be multiple SubPlan nodes referencing the same physical
3007  * subplan (same plan_id, which is its index in PlannedStmt.subplans).
3008  * We should print a subplan only once, so track which ones we already
3009  * printed. This state must be global across the plan tree, since the
3010  * duplicate nodes could be in different plan nodes, eg both a bitmap
3011  * indexscan's indexqual and its parent heapscan's recheck qual. (We
3012  * do not worry too much about which plan node we show the subplan as
3013  * attached to in such cases.)
3014  */
3015  if (bms_is_member(sp->plan_id, es->printed_subplans))
3016  continue;
3018  sp->plan_id);
3019 
3020  ExplainNode(sps->planstate, ancestors,
3021  relationship, sp->plan_name, es);
3022  }
3023 }
int plan_id
Definition: primnodes.h:689
Bitmapset * printed_subplans
Definition: explain.h:47
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:862
struct PlanState * planstate
Definition: execnodes.h:758
SubPlan * subplan
Definition: execnodes.h:757
char * plan_name
Definition: primnodes.h:691
#define lfirst(lc)
Definition: pg_list.h:106
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420
static void ExplainTargetRel ( Plan plan,
Index  rti,
ExplainState es 
)
static

Definition at line 2693 of file explain.c.

References Alias::aliasname, appendStringInfo(), appendStringInfoString(), Assert, RangeTblEntry::eref, EXPLAIN_FORMAT_TEXT, ExplainPropertyText(), ExplainState::format, RangeTblFunction::funcexpr, FuncExpr::funcid, FunctionScan::functions, get_func_name(), get_namespace_name(), get_rel_name(), IsA, linitial, list_length(), list_nth(), nodeTag, quote_identifier(), RangeTblEntry::relid, rt_fetch, ExplainState::rtable, ExplainState::rtable_names, RTE_CTE, RTE_FUNCTION, RTE_NAMEDTUPLESTORE, RTE_RELATION, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, ExplainState::str, T_BitmapHeapScan, T_CteScan, T_CustomScan, T_ForeignScan, T_FunctionScan, T_IndexOnlyScan, T_IndexScan, T_ModifyTable, T_NamedTuplestoreScan, T_SampleScan, T_SeqScan, T_TableFuncScan, T_TidScan, T_ValuesScan, T_WorkTableScan, and ExplainState::verbose.

Referenced by ExplainModifyTarget(), ExplainScanTarget(), and show_modifytable_info().

2694 {
2695  char *objectname = NULL;
2696  char *namespace = NULL;
2697  const char *objecttag = NULL;
2698  RangeTblEntry *rte;
2699  char *refname;
2700 
2701  rte = rt_fetch(rti, es->rtable);
2702  refname = (char *) list_nth(es->rtable_names, rti - 1);
2703  if (refname == NULL)
2704  refname = rte->eref->aliasname;
2705 
2706  switch (nodeTag(plan))
2707  {
2708  case T_SeqScan:
2709  case T_SampleScan:
2710  case T_IndexScan:
2711  case T_IndexOnlyScan:
2712  case T_BitmapHeapScan:
2713  case T_TidScan:
2714  case T_ForeignScan:
2715  case T_CustomScan:
2716  case T_ModifyTable:
2717  /* Assert it's on a real relation */
2718  Assert(rte->rtekind == RTE_RELATION);
2719  objectname = get_rel_name(rte->relid);
2720  if (es->verbose)
2721  namespace = get_namespace_name(get_rel_namespace(rte->relid));
2722  objecttag = "Relation Name";
2723  break;
2724  case T_FunctionScan:
2725  {
2726  FunctionScan *fscan = (FunctionScan *) plan;
2727 
2728  /* Assert it's on a RangeFunction */
2729  Assert(rte->rtekind == RTE_FUNCTION);
2730 
2731  /*
2732  * If the expression is still a function call of a single
2733  * function, we can get the real name of the function.
2734  * Otherwise, punt. (Even if it was a single function call
2735  * originally, the optimizer could have simplified it away.)
2736  */
2737  if (list_length(fscan->functions) == 1)
2738  {
2739  RangeTblFunction *rtfunc = (RangeTblFunction *) linitial(fscan->functions);
2740 
2741  if (IsA(rtfunc->funcexpr, FuncExpr))
2742  {
2743  FuncExpr *funcexpr = (FuncExpr *) rtfunc->funcexpr;
2744  Oid funcid = funcexpr->funcid;
2745 
2746  objectname = get_func_name(funcid);
2747  if (es->verbose)
2748  namespace =
2750  }
2751  }
2752  objecttag = "Function Name";
2753  }
2754  break;
2755  case T_TableFuncScan:
2756  Assert(rte->rtekind == RTE_TABLEFUNC);
2757  objectname = "xmltable";
2758  objecttag = "Table Function Name";
2759  break;
2760  case T_ValuesScan:
2761  Assert(rte->rtekind == RTE_VALUES);
2762  break;
2763  case T_CteScan:
2764  /* Assert it's on a non-self-reference CTE */
2765  Assert(rte->rtekind == RTE_CTE);
2766  Assert(!rte->self_reference);
2767  objectname = rte->ctename;
2768  objecttag = "CTE Name";
2769  break;
2770  case T_NamedTuplestoreScan:
2772  objectname = rte->enrname;
2773  objecttag = "Tuplestore Name";
2774  break;
2775  case T_WorkTableScan:
2776  /* Assert it's on a self-reference CTE */
2777  Assert(rte->rtekind == RTE_CTE);
2778  Assert(rte->self_reference);
2779  objectname = rte->ctename;
2780  objecttag = "CTE Name";
2781  break;
2782  default:
2783  break;
2784  }
2785 
2786  if (es->format == EXPLAIN_FORMAT_TEXT)
2787  {
2788  appendStringInfoString(es->str, " on");
2789  if (namespace != NULL)
2790  appendStringInfo(es->str, " %s.%s", quote_identifier(namespace),
2791  quote_identifier(objectname));
2792  else if (objectname != NULL)
2793  appendStringInfo(es->str, " %s", quote_identifier(objectname));
2794  if (objectname == NULL || strcmp(refname, objectname) != 0)
2795  appendStringInfo(es->str, " %s", quote_identifier(refname));
2796  }
2797  else
2798  {
2799  if (objecttag != NULL && objectname != NULL)
2800  ExplainPropertyText(objecttag, objectname, es);
2801  if (namespace != NULL)
2802  ExplainPropertyText("Schema", namespace, es);
2803  ExplainPropertyText("Alias", refname, es);
2804  }
2805 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10390
Oid get_func_namespace(Oid funcid)
Definition: lsyscache.c:1436
List * functions
Definition: plannodes.h:508
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1750
unsigned int Oid
Definition: postgres_ext.h:31
List * rtable_names
Definition: explain.h:45
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3215
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
#define linitial(l)
Definition: pg_list.h:111
Oid funcid
Definition: primnodes.h:449
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1412
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3033
void * list_nth(const List *list, int n)
Definition: list.c:410
char * enrname
Definition: parsenodes.h:1042
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
bool self_reference
Definition: parsenodes.h:1017
bool verbose
Definition: explain.h:32
#define Assert(condition)
Definition: c.h:664
char * aliasname
Definition: primnodes.h:42
static int list_length(const List *l)
Definition: pg_list.h:89
ExplainFormat format
Definition: explain.h:38
#define nodeTag(nodeptr)
Definition: nodes.h:514
RTEKind rtekind
Definition: parsenodes.h:945
char * ctename
Definition: parsenodes.h:1015
Alias * eref
Definition: parsenodes.h:1049
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
StringInfo str
Definition: explain.h:30
List * rtable
Definition: explain.h:44
static void ExplainXMLTag ( const char *  tagname,
int  flags,
ExplainState es 
)
static

Definition at line 3511 of file explain.c.

References appendStringInfoChar(), appendStringInfoCharMacro, appendStringInfoSpaces(), appendStringInfoString(), ExplainState::indent, ExplainState::str, X_CLOSE_IMMEDIATE, X_CLOSING, and X_NOWHITESPACE.

Referenced by ExplainCloseGroup(), ExplainDummyGroup(), ExplainOpenGroup(), ExplainProperty(), and ExplainPropertyList().

3512 {
3513  const char *s;
3514  const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
3515 
3516  if ((flags & X_NOWHITESPACE) == 0)
3517  appendStringInfoSpaces(es->str, 2 * es->indent);
3518  appendStringInfoCharMacro(es->str, '<');
3519  if ((flags & X_CLOSING) != 0)
3520  appendStringInfoCharMacro(es->str, '/');
3521  for (s = tagname; *s; s++)
3522  appendStringInfoChar(es->str, strchr(valid, *s) ? *s : '-');
3523  if ((flags & X_CLOSE_IMMEDIATE) != 0)
3524  appendStringInfoString(es->str, " /");
3525  appendStringInfoCharMacro(es->str, '>');
3526  if ((flags & X_NOWHITESPACE) == 0)
3527  appendStringInfoCharMacro(es->str, '\n');
3528 }
#define X_CLOSING
Definition: explain.c:52
#define appendStringInfoCharMacro(str, ch)
Definition: stringinfo.h:127
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
#define X_NOWHITESPACE
Definition: explain.c:54
#define X_CLOSE_IMMEDIATE
Definition: explain.c:53
StringInfo str
Definition: explain.h:30
static void ExplainYAMLLineStarting ( ExplainState es)
static

Definition at line 3558 of file explain.c.

References appendStringInfoChar(), appendStringInfoSpaces(), Assert, EXPLAIN_FORMAT_YAML, ExplainState::format, ExplainState::grouping_stack, ExplainState::indent, linitial_int, and ExplainState::str.

Referenced by ExplainDummyGroup(), ExplainOpenGroup(), ExplainProperty(), ExplainPropertyList(), and ExplainPropertyListNested().

3559 {
3561  if (linitial_int(es->grouping_stack) == 0)
3562  {
3563  linitial_int(es->grouping_stack) = 1;
3564  }
3565  else
3566  {
3567  appendStringInfoChar(es->str, '\n');
3568  appendStringInfoSpaces(es->str, es->indent * 2);
3569  }
3570 }
#define linitial_int(l)
Definition: pg_list.h:112
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
#define Assert(condition)
Definition: c.h:664
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
ExplainState* NewExplainState ( void  )

Definition at line 281 of file explain.c.

References ExplainState::costs, makeStringInfo(), palloc0(), and ExplainState::str.

Referenced by explain_ExecutorEnd(), and ExplainQuery().

282 {
283  ExplainState *es = (ExplainState *) palloc0(sizeof(ExplainState));
284 
285  /* Set default options (most fields can be left as zeroes). */
286  es->costs = true;
287  /* Prepare output buffer. */
288  es->str = makeStringInfo();
289 
290  return es;
291 }
StringInfo makeStringInfo(void)
Definition: stringinfo.c:28
bool costs
Definition: explain.h:34
void * palloc0(Size size)
Definition: mcxt.c:877
StringInfo str
Definition: explain.h:30
static void report_triggers ( ResultRelInfo rInfo,
bool  show_relname,
ExplainState es 
)
static

Definition at line 708 of file explain.c.

References appendStringInfo(), appendStringInfoString(), EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), ExplainOpenGroup(), ExplainPropertyFloat(), ExplainPropertyText(), ExplainState::format, get_constraint_name(), InstrEndLoop(), Instrumentation::ntuples, TriggerDesc::numtriggers, OidIsValid, pfree(), RelationGetRelationName, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigInstrument, ExplainState::str, Trigger::tgconstraint, Trigger::tgname, ExplainState::timing, Instrumentation::total, TriggerDesc::triggers, and ExplainState::verbose.

Referenced by ExplainPrintTriggers().

709 {
710  int nt;
711 
712  if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
713  return;
714  for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
715  {
716  Trigger *trig = rInfo->ri_TrigDesc->triggers + nt;
717  Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
718  char *relname;
719  char *conname = NULL;
720 
721  /* Must clean up instrumentation state */
722  InstrEndLoop(instr);
723 
724  /*
725  * We ignore triggers that were never invoked; they likely aren't
726  * relevant to the current query type.
727  */
728  if (instr->ntuples == 0)
729  continue;
730 
731  ExplainOpenGroup("Trigger", NULL, true, es);
732 
733  relname = RelationGetRelationName(rInfo->ri_RelationDesc);
734  if (OidIsValid(trig->tgconstraint))
735  conname = get_constraint_name(trig->tgconstraint);
736 
737  /*
738  * In text format, we avoid printing both the trigger name and the
739  * constraint name unless VERBOSE is specified. In non-text formats
740  * we just print everything.
741  */
742  if (es->format == EXPLAIN_FORMAT_TEXT)
743  {
744  if (es->verbose || conname == NULL)
745  appendStringInfo(es->str, "Trigger %s", trig->tgname);
746  else
747  appendStringInfoString(es->str, "Trigger");
748  if (conname)
749  appendStringInfo(es->str, " for constraint %s", conname);
750  if (show_relname)
751  appendStringInfo(es->str, " on %s", relname);
752  if (es->timing)
753  appendStringInfo(es->str, ": time=%.3f calls=%.0f\n",
754  1000.0 * instr->total, instr->ntuples);
755  else
756  appendStringInfo(es->str, ": calls=%.0f\n", instr->ntuples);
757  }
758  else
759  {
760  ExplainPropertyText("Trigger Name", trig->tgname, es);
761  if (conname)
762  ExplainPropertyText("Constraint Name", conname, es);
763  ExplainPropertyText("Relation", relname, es);
764  if (es->timing)
765  ExplainPropertyFloat("Time", 1000.0 * instr->total, 3, es);
766  ExplainPropertyFloat("Calls", instr->ntuples, 0, es);
767  }
768 
769  if (conname)
770  pfree(conname);
771 
772  ExplainCloseGroup("Trigger", NULL, true, es);
773  }
774 }
Relation ri_RelationDesc
Definition: execnodes.h:354
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:997
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3249
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:375
#define OidIsValid(objectId)
Definition: c.h:532
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:114
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3215
void pfree(void *pointer)
Definition: mcxt.c:949
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
Oid tgconstraint
Definition: reltrigger.h:34
char * tgname
Definition: reltrigger.h:27
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
Trigger * triggers
Definition: reltrigger.h:48
#define RelationGetRelationName(relation)
Definition: rel.h:436
double ntuples
Definition: instrument.h:59
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
bool timing
Definition: explain.h:36
int numtriggers
Definition: reltrigger.h:49
bool verbose
Definition: explain.h:32
ExplainFormat format
Definition: explain.h:38
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3340
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3277
StringInfo str
Definition: explain.h:30
static void show_agg_keys ( AggState astate,
List ancestors,
ExplainState es 
)
static

Definition at line 1958 of file explain.c.

References Agg::groupingSets, Agg::grpColIdx, lcons(), list_delete_first(), Agg::numCols, outerPlanState, PlanState::plan, ScanState::ps, show_grouping_sets(), show_sort_group_keys(), and AggState::ss.

Referenced by ExplainNode().

1960 {
1961  Agg *plan = (Agg *) astate->ss.ps.plan;
1962 
1963  if (plan->numCols > 0 || plan->groupingSets)
1964  {
1965  /* The key columns refer to the tlist of the child plan */
1966  ancestors = lcons(astate, ancestors);
1967 
1968  if (plan->groupingSets)
1969  show_grouping_sets(outerPlanState(astate), plan, ancestors, es);
1970  else
1971  show_sort_group_keys(outerPlanState(astate), "Group Key",
1972  plan->numCols, plan->grpColIdx,
1973  NULL, NULL, NULL,
1974  ancestors, es);
1975 
1976  ancestors = list_delete_first(ancestors);
1977  }
1978 }
int numCols
Definition: plannodes.h:785
AttrNumber * grpColIdx
Definition: plannodes.h:786
ScanState ss
Definition: execnodes.h:1795
PlanState ps
Definition: execnodes.h:1100
#define outerPlanState(node)
Definition: execnodes.h:893
static void show_grouping_sets(PlanState *planstate, Agg *agg, List *ancestors, ExplainState *es)
Definition: explain.c:1981
List * groupingSets
Definition: plannodes.h:791
Plan * plan
Definition: execnodes.h:847
List * lcons(void *datum, List *list)
Definition: list.c:259
Definition: plannodes.h:780
static void show_sort_group_keys(PlanState *planstate, const char *qlabel, int nkeys, AttrNumber *keycols, Oid *sortOperators, Oid *collations, bool *nullsFirst, List *ancestors, ExplainState *es)
Definition: explain.c:2110
List * list_delete_first(List *list)
Definition: list.c:666
static void show_buffer_usage ( ExplainState es,
const BufferUsage usage 
)
static

Definition at line 2522 of file explain.c.

References appendStringInfo(), appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), BufferUsage::blk_read_time, BufferUsage::blk_write_time, EXPLAIN_FORMAT_TEXT, ExplainPropertyFloat(), ExplainPropertyLong(), ExplainState::format, ExplainState::indent, INSTR_TIME_GET_MILLISEC, INSTR_TIME_IS_ZERO, BufferUsage::local_blks_dirtied, BufferUsage::local_blks_hit, BufferUsage::local_blks_read, BufferUsage::local_blks_written, BufferUsage::shared_blks_dirtied, BufferUsage::shared_blks_hit, BufferUsage::shared_blks_read, BufferUsage::shared_blks_written, ExplainState::str, BufferUsage::temp_blks_read, BufferUsage::temp_blks_written, and track_io_timing.

Referenced by ExplainNode().

2523 {
2524  if (es->format == EXPLAIN_FORMAT_TEXT)
2525  {
2526  bool has_shared = (usage->shared_blks_hit > 0 ||
2527  usage->shared_blks_read > 0 ||
2528  usage->shared_blks_dirtied > 0 ||
2529  usage->shared_blks_written > 0);
2530  bool has_local = (usage->local_blks_hit > 0 ||
2531  usage->local_blks_read > 0 ||
2532  usage->local_blks_dirtied > 0 ||
2533  usage->local_blks_written > 0);
2534  bool has_temp = (usage->temp_blks_read > 0 ||
2535  usage->temp_blks_written > 0);
2536  bool has_timing = (!INSTR_TIME_IS_ZERO(usage->blk_read_time) ||
2538 
2539  /* Show only positive counter values. */
2540  if (has_shared || has_local || has_temp)
2541  {
2542  appendStringInfoSpaces(es->str, es->indent * 2);
2543  appendStringInfoString(es->str, "Buffers:");
2544 
2545  if (has_shared)
2546  {
2547  appendStringInfoString(es->str, " shared");
2548  if (usage->shared_blks_hit > 0)
2549  appendStringInfo(es->str, " hit=%ld",
2550  usage->shared_blks_hit);
2551  if (usage->shared_blks_read > 0)
2552  appendStringInfo(es->str, " read=%ld",
2553  usage->shared_blks_read);
2554  if (usage->shared_blks_dirtied > 0)
2555  appendStringInfo(es->str, " dirtied=%ld",
2556  usage->shared_blks_dirtied);
2557  if (usage->shared_blks_written > 0)
2558  appendStringInfo(es->str, " written=%ld",
2559  usage->shared_blks_written);
2560  if (has_local || has_temp)
2561  appendStringInfoChar(es->str, ',');
2562  }
2563  if (has_local)
2564  {
2565  appendStringInfoString(es->str, " local");
2566  if (usage->local_blks_hit > 0)
2567  appendStringInfo(es->str, " hit=%ld",
2568  usage->local_blks_hit);
2569  if (usage->local_blks_read > 0)
2570  appendStringInfo(es->str, " read=%ld",
2571  usage->local_blks_read);
2572  if (usage->local_blks_dirtied > 0)
2573  appendStringInfo(es->str, " dirtied=%ld",
2574  usage->local_blks_dirtied);
2575  if (usage->local_blks_written > 0)
2576  appendStringInfo(es->str, " written=%ld",
2577  usage->local_blks_written);
2578  if (has_temp)
2579  appendStringInfoChar(es->str, ',');
2580  }
2581  if (has_temp)
2582  {
2583  appendStringInfoString(es->str, " temp");
2584  if (usage->temp_blks_read > 0)
2585  appendStringInfo(es->str, " read=%ld",
2586  usage->temp_blks_read);
2587  if (usage->temp_blks_written > 0)
2588  appendStringInfo(es->str, " written=%ld",
2589  usage->temp_blks_written);
2590  }
2591  appendStringInfoChar(es->str, '\n');
2592  }
2593 
2594  /* As above, show only positive counter values. */
2595  if (has_timing)
2596  {
2597  appendStringInfoSpaces(es->str, es->indent * 2);
2598  appendStringInfoString(es->str, "I/O Timings:");
2599  if (!INSTR_TIME_IS_ZERO(usage->blk_read_time))
2600  appendStringInfo(es->str, " read=%0.3f",
2602  if (!INSTR_TIME_IS_ZERO(usage->blk_write_time))
2603  appendStringInfo(es->str, " write=%0.3f",
2605  appendStringInfoChar(es->str, '\n');
2606  }
2607  }
2608  else
2609  {
2610  ExplainPropertyLong("Shared Hit Blocks", usage->shared_blks_hit, es);
2611  ExplainPropertyLong("Shared Read Blocks", usage->shared_blks_read, es);
2612  ExplainPropertyLong("Shared Dirtied Blocks", usage->shared_blks_dirtied, es);
2613  ExplainPropertyLong("Shared Written Blocks", usage->shared_blks_written, es);
2614  ExplainPropertyLong("Local Hit Blocks", usage->local_blks_hit, es);
2615  ExplainPropertyLong("Local Read Blocks", usage->local_blks_read, es);
2616  ExplainPropertyLong("Local Dirtied Blocks", usage->local_blks_dirtied, es);
2617  ExplainPropertyLong("Local Written Blocks", usage->local_blks_written, es);
2618  ExplainPropertyLong("Temp Read Blocks", usage->temp_blks_read, es);
2619  ExplainPropertyLong("Temp Written Blocks", usage->temp_blks_written, es);
2620  if (track_io_timing)
2621  {
2622  ExplainPropertyFloat("I/O Read Time", INSTR_TIME_GET_MILLISEC(usage->blk_read_time), 3, es);
2623  ExplainPropertyFloat("I/O Write Time", INSTR_TIME_GET_MILLISEC(usage->blk_write_time), 3, es);
2624  }
2625  }
2626 }
long local_blks_hit
Definition: instrument.h:25
long local_blks_dirtied
Definition: instrument.h:27
long local_blks_read
Definition: instrument.h:26
instr_time blk_read_time
Definition: instrument.h:31
void ExplainPropertyLong(const char *qlabel, long value, ExplainState *es)
Definition: explain.c:3236
#define INSTR_TIME_GET_MILLISEC(t)
Definition: instr_time.h:199
long shared_blks_read
Definition: instrument.h:22
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3249
long temp_blks_written
Definition: instrument.h:30
#define INSTR_TIME_IS_ZERO(t)
Definition: instr_time.h:149
long shared_blks_written
Definition: instrument.h:24
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
long shared_blks_dirtied
Definition: instrument.h:23
int indent
Definition: explain.h:40
long temp_blks_read
Definition: instrument.h:29
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
instr_time blk_write_time
Definition: instrument.h:32
ExplainFormat format
Definition: explain.h:38
long shared_blks_hit
Definition: instrument.h:21
long local_blks_written
Definition: instrument.h:28
StringInfo str
Definition: explain.h:30
bool track_io_timing
Definition: bufmgr.c:111
static void show_expression ( Node node,
const char *  qlabel,
PlanState planstate,
List ancestors,
bool  useprefix,
ExplainState es 
)
static

Definition at line 1855 of file explain.c.

References ExplainState::deparse_cxt, deparse_expression(), ExplainPropertyText(), and set_deparse_context_planstate().

Referenced by ExplainNode(), and show_qual().

1858 {
1859  List *context;
1860  char *exprstr;
1861 
1862  /* Set up deparsing context */
1864  (Node *) planstate,
1865  ancestors);
1866 
1867  /* Deparse the expression */
1868  exprstr = deparse_expression(node, context, useprefix, false);
1869 
1870  /* And add to es->str */
1871  ExplainPropertyText(qlabel, exprstr, es);
1872 }
Definition: nodes.h:509
List * deparse_cxt
Definition: explain.h:46
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3215
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:3137
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:2985
Definition: pg_list.h:45
static void show_foreignscan_info ( ForeignScanState fsstate,
ExplainState es 
)
static

Definition at line 2475 of file explain.c.

References CMD_SELECT, FdwRoutine::ExplainDirectModify, FdwRoutine::ExplainForeignScan, ForeignScanState::fdwroutine, PlanState::plan, ScanState::ps, and ForeignScanState::ss.

Referenced by ExplainNode().

2476 {
2477  FdwRoutine *fdwroutine = fsstate->fdwroutine;
2478 
2479  /* Let the FDW emit whatever fields it wants */
2480  if (((ForeignScan *) fsstate->ss.ps.plan)->operation != CMD_SELECT)
2481  {
2482  if (fdwroutine->ExplainDirectModify != NULL)
2483  fdwroutine->ExplainDirectModify(fsstate, es);
2484  }
2485  else
2486  {
2487  if (fdwroutine->ExplainForeignScan != NULL)
2488  fdwroutine->ExplainForeignScan(fsstate, es);
2489  }
2490 }
ScanState ss
Definition: execnodes.h:1543
ExplainForeignScan_function ExplainForeignScan
Definition: fdwapi.h:216
PlanState ps
Definition: execnodes.h:1100
ExplainDirectModify_function ExplainDirectModify
Definition: fdwapi.h:218
struct FdwRoutine * fdwroutine
Definition: execnodes.h:1547
Plan * plan
Definition: execnodes.h:847
static void show_group_keys ( GroupState gstate,
List ancestors,
ExplainState es 
)
static

Definition at line 2090 of file explain.c.

References Group::grpColIdx, lcons(), list_delete_first(), Group::numCols, outerPlanState, PlanState::plan, ScanState::ps, show_sort_group_keys(), and GroupState::ss.

Referenced by ExplainNode().

2092 {
2093  Group *plan = (Group *) gstate->ss.ps.plan;
2094 
2095  /* The key columns refer to the tlist of the child plan */
2096  ancestors = lcons(gstate, ancestors);
2097  show_sort_group_keys(outerPlanState(gstate), "Group Key",
2098  plan->numCols, plan->grpColIdx,
2099  NULL, NULL, NULL,
2100  ancestors, es);
2101  ancestors = list_delete_first(ancestors);
2102 }
ScanState ss
Definition: execnodes.h:1769
PlanState ps
Definition: execnodes.h:1100
#define outerPlanState(node)
Definition: execnodes.h:893
int numCols
Definition: plannodes.h:761
Plan * plan
Definition: execnodes.h:847
List * lcons(void *datum, List *list)
Definition: list.c:259
AttrNumber * grpColIdx
Definition: plannodes.h:762
static void show_sort_group_keys(PlanState *planstate, const char *qlabel, int nkeys, AttrNumber *keycols, Oid *sortOperators, Oid *collations, bool *nullsFirst, List *ancestors, ExplainState *es)
Definition: explain.c:2110
List * list_delete_first(List *list)
Definition: list.c:666
static void show_grouping_set_keys ( PlanState planstate,
Agg aggnode,
Sort sortnode,
List context,
bool  useprefix,
List ancestors,
ExplainState es 
)
static

Definition at line 2012 of file explain.c.

References AGG_HASHED, AGG_MIXED, Agg::aggstrategy, Sort::collations, deparse_expression(), elog, ERROR, EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), ExplainOpenGroup(), ExplainPropertyListNested(), ExplainPropertyText(), TargetEntry::expr, ExplainState::format, get_tle_by_resno(), Agg::groupingSets, Agg::grpColIdx, i, ExplainState::indent, lappend(), lfirst, lfirst_int, NIL, Sort::nullsFirst, Sort::numCols, PlanState::plan, show_sort_group_keys(), Sort::sortColIdx, Sort::sortOperators, and Plan::targetlist.

Referenced by show_grouping_sets().

2016 {
2017  Plan *plan = planstate->plan;
2018  char *exprstr;
2019  ListCell *lc;
2020  List *gsets = aggnode->groupingSets;
2021  AttrNumber *keycols = aggnode->grpColIdx;
2022  const char *keyname;
2023  const char *keysetname;
2024 
2025  if (aggnode->aggstrategy == AGG_HASHED || aggnode->aggstrategy == AGG_MIXED)
2026  {
2027  keyname = "Hash Key";
2028  keysetname = "Hash Keys";
2029  }
2030  else
2031  {
2032  keyname = "Group Key";
2033  keysetname = "Group Keys";
2034  }
2035 
2036  ExplainOpenGroup("Grouping Set", NULL, true, es);
2037 
2038  if (sortnode)
2039  {
2040  show_sort_group_keys(planstate, "Sort Key",
2041  sortnode->numCols, sortnode->sortColIdx,
2042  sortnode->sortOperators, sortnode->collations,
2043  sortnode->nullsFirst,
2044  ancestors, es);
2045  if (es->format == EXPLAIN_FORMAT_TEXT)
2046  es->indent++;
2047  }
2048 
2049  ExplainOpenGroup(keysetname, keysetname, false, es);
2050 
2051  foreach(lc, gsets)
2052  {
2053  List *result = NIL;
2054  ListCell *lc2;
2055 
2056  foreach(lc2, (List *) lfirst(lc))
2057  {
2058  Index i = lfirst_int(lc2);
2059  AttrNumber keyresno = keycols[i];
2060  TargetEntry *target = get_tle_by_resno(plan->targetlist,
2061  keyresno);
2062 
2063  if (!target)
2064  elog(ERROR, "no tlist entry for key %d", keyresno);
2065  /* Deparse the expression, showing any top-level cast */
2066  exprstr = deparse_expression((Node *) target->expr, context,
2067  useprefix, true);
2068 
2069  result = lappend(result, exprstr);
2070  }
2071 
2072  if (!result && es->format == EXPLAIN_FORMAT_TEXT)
2073  ExplainPropertyText(keyname, "()", es);
2074  else
2075  ExplainPropertyListNested(keyname, result, es);
2076  }
2077 
2078  ExplainCloseGroup(keysetname, keysetname, false, es);
2079 
2080  if (sortnode && es->format == EXPLAIN_FORMAT_TEXT)
2081  es->indent--;
2082 
2083  ExplainCloseGroup("Grouping Set", NULL, true, es);
2084 }
#define NIL
Definition: pg_list.h:69
AttrNumber * grpColIdx
Definition: plannodes.h:786
Definition: nodes.h:509
bool * nullsFirst
Definition: plannodes.h:749
Oid * sortOperators
Definition: plannodes.h:747
void ExplainPropertyListNested(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:3114
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3215
AggStrategy aggstrategy
Definition: plannodes.h:783
#define ERROR
Definition: elog.h:43
#define lfirst_int(lc)
Definition: pg_list.h:107
int indent
Definition: explain.h:40
List * lappend(List *list, void *datum)
Definition: list.c:128
int numCols
Definition: plannodes.h:745
List * groupingSets
Definition: plannodes.h:791
unsigned int Index
Definition: c.h:359
Plan * plan
Definition: execnodes.h:847
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1368
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:2985
ExplainFormat format
Definition: explain.h:38
List * targetlist
Definition: plannodes.h:144
AttrNumber * sortColIdx
Definition: plannodes.h:746
int i
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3340
#define elog
Definition: elog.h:219
static void show_sort_group_keys(PlanState *planstate, const char *qlabel, int nkeys, AttrNumber *keycols, Oid *sortOperators, Oid *collations, bool *nullsFirst, List *ancestors, ExplainState *es)
Definition: explain.c:2110
Oid * collations
Definition: plannodes.h:748
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3277
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
static void show_grouping_sets ( PlanState planstate,
Agg agg,
List ancestors,
ExplainState es 
)
static

Definition at line 1981 of file explain.c.

References Agg::chain, ExplainState::deparse_cxt, ExplainCloseGroup(), ExplainOpenGroup(), Plan::lefttree, lfirst, list_length(), Agg::plan, ExplainState::rtable, set_deparse_context_planstate(), show_grouping_set_keys(), and ExplainState::verbose.

Referenced by show_agg_keys().

1983 {
1984  List *context;
1985  bool useprefix;
1986  ListCell *lc;
1987 
1988  /* Set up deparsing context */
1990  (Node *) planstate,
1991  ancestors);
1992  useprefix = (list_length(es->rtable) > 1 || es->verbose);
1993 
1994  ExplainOpenGroup("Grouping Sets", "Grouping Sets", false, es);
1995 
1996  show_grouping_set_keys(planstate, agg, NULL,
1997  context, useprefix, ancestors, es);
1998 
1999  foreach(lc, agg->chain)
2000  {
2001  Agg *aggnode = lfirst(lc);
2002  Sort *sortnode = (Sort *) aggnode->plan.lefttree;
2003 
2004  show_grouping_set_keys(planstate, aggnode, sortnode,
2005  context, useprefix, ancestors, es);
2006  }
2007 
2008  ExplainCloseGroup("Grouping Sets", "Grouping Sets", false, es);
2009 }
Definition: nodes.h:509
List * deparse_cxt
Definition: explain.h:46
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:3137
Plan plan
Definition: plannodes.h:782
bool verbose
Definition: explain.h:32
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
struct Plan * lefttree
Definition: plannodes.h:146
static void show_grouping_set_keys(PlanState *planstate, Agg *aggnode, Sort *sortnode, List *context, bool useprefix, List *ancestors, ExplainState *es)
Definition: explain.c:2012
List * chain
Definition: plannodes.h:792
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3340
Definition: plannodes.h:780
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3277
Definition: pg_list.h:45
List * rtable
Definition: explain.h:44
static void show_hash_info ( HashState hashstate,
ExplainState es 
)
static

Definition at line 2371 of file explain.c.

References appendStringInfo(), appendStringInfoSpaces(), EXPLAIN_FORMAT_TEXT, ExplainPropertyLong(), ExplainState::format, HashState::hashtable, ExplainState::indent, HashJoinTableData::nbatch, HashJoinTableData::nbatch_original, HashJoinTableData::nbuckets, HashJoinTableData::nbuckets_original, HashJoinTableData::spacePeak, and ExplainState::str.

Referenced by ExplainNode().

2372 {
2373  HashJoinTable hashtable;
2374 
2375  hashtable = hashstate->hashtable;
2376 
2377  if (hashtable)
2378  {
2379  long spacePeakKb = (hashtable->spacePeak + 1023) / 1024;
2380 
2381  if (es->format != EXPLAIN_FORMAT_TEXT)
2382  {
2383  ExplainPropertyLong("Hash Buckets", hashtable->nbuckets, es);
2384  ExplainPropertyLong("Original Hash Buckets",
2385  hashtable->nbuckets_original, es);
2386  ExplainPropertyLong("Hash Batches", hashtable->nbatch, es);
2387  ExplainPropertyLong("Original Hash Batches",
2388  hashtable->nbatch_original, es);
2389  ExplainPropertyLong("Peak Memory Usage", spacePeakKb, es);
2390  }
2391  else if (hashtable->nbatch_original != hashtable->nbatch ||
2392  hashtable->nbuckets_original != hashtable->nbuckets)
2393  {
2394  appendStringInfoSpaces(es->str, es->indent * 2);
2395  appendStringInfo(es->str,
2396  "Buckets: %d (originally %d) Batches: %d (originally %d) Memory Usage: %ldkB\n",
2397  hashtable->nbuckets,
2398  hashtable->nbuckets_original,
2399  hashtable->nbatch,
2400  hashtable->nbatch_original,
2401  spacePeakKb);
2402  }
2403  else
2404  {
2405  appendStringInfoSpaces(es->str, es->indent * 2);
2406  appendStringInfo(es->str,
2407  "Buckets: %d Batches: %d Memory Usage: %ldkB\n",
2408  hashtable->nbuckets, hashtable->nbatch,
2409  spacePeakKb);
2410  }
2411  }
2412 }
void ExplainPropertyLong(const char *qlabel, long value, ExplainState *es)
Definition: explain.c:3236
HashJoinTable hashtable
Definition: execnodes.h:1980
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
int indent
Definition: explain.h:40
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
static void show_instrumentation_count ( const char *  qlabel,
int  which,
PlanState planstate,
ExplainState es 
)
static

Definition at line 2446 of file explain.c.

References ExplainState::analyze, EXPLAIN_FORMAT_TEXT, ExplainPropertyFloat(), ExplainState::format, PlanState::instrument, Instrumentation::nfiltered1, Instrumentation::nfiltered2, and Instrumentation::nloops.

Referenced by ExplainNode(), and show_modifytable_info().

2448 {
2449  double nfiltered;
2450  double nloops;
2451 
2452  if (!es->analyze || !planstate->instrument)
2453  return;
2454 
2455  if (which == 2)
2456  nfiltered = planstate->instrument->nfiltered2;
2457  else
2458  nfiltered = planstate->instrument->nfiltered1;
2459  nloops = planstate->instrument->nloops;
2460 
2461  /* In text mode, suppress zero counts; they're not interesting enough */
2462  if (nfiltered > 0 || es->format != EXPLAIN_FORMAT_TEXT)
2463  {
2464  if (nloops > 0)
2465  ExplainPropertyFloat(qlabel, nfiltered / nloops, 0, es);
2466  else
2467  ExplainPropertyFloat(qlabel, 0.0, 0, es);
2468  }
2469 }
double nfiltered1
Definition: instrument.h:61
Instrumentation * instrument
Definition: execnodes.h:857
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3249
bool analyze
Definition: explain.h:33
double nfiltered2
Definition: instrument.h:62
ExplainFormat format
Definition: explain.h:38
static void show_merge_append_keys ( MergeAppendState mstate,
List ancestors,
ExplainState es 
)
static

Definition at line 1942 of file explain.c.

References MergeAppend::collations, MergeAppend::nullsFirst, MergeAppend::numCols, PlanState::plan, MergeAppendState::ps, show_sort_group_keys(), MergeAppend::sortColIdx, and MergeAppend::sortOperators.

Referenced by ExplainNode().

1944 {
1945  MergeAppend *plan = (MergeAppend *) mstate->ps.plan;
1946 
1947  show_sort_group_keys((PlanState *) mstate, "Sort Key",
1948  plan->numCols, plan->sortColIdx,
1949  plan->sortOperators, plan->collations,
1950  plan->nullsFirst,
1951  ancestors, es);
1952 }
Oid * collations
Definition: plannodes.h:268
Plan * plan
Definition: execnodes.h:847
PlanState ps
Definition: execnodes.h:1021
AttrNumber * sortColIdx
Definition: plannodes.h:266
bool * nullsFirst
Definition: plannodes.h:269
Oid * sortOperators
Definition: plannodes.h:267
static void show_sort_group_keys(PlanState *planstate, const char *qlabel, int nkeys, AttrNumber *keycols, Oid *sortOperators, Oid *collations, bool *nullsFirst, List *ancestors, ExplainState *es)
Definition: explain.c:2110
static void show_modifytable_info ( ModifyTableState mtstate,
List ancestors,
ExplainState es 
)
static

Definition at line 2816 of file explain.c.

References ExplainState::analyze, appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), ModifyTable::arbiterIndexes, CMD_DELETE, CMD_INSERT, CMD_UPDATE, EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), FdwRoutine::ExplainForeignModify, ExplainOpenGroup(), ExplainProperty(), ExplainPropertyFloat(), ExplainPropertyList(), ExplainTargetRel(), ModifyTable::fdwPrivLists, ExplainState::format, get_rel_name(), ExplainState::indent, InstrEndLoop(), PlanState::instrument, lappend(), lfirst_oid, list_nth(), ModifyTableState::mt_nplans, ModifyTableState::mt_plans, Instrumentation::nfiltered2, NIL, ModifyTable::nominalRelation, Instrumentation::ntuples, ONCONFLICT_NONE, ONCONFLICT_NOTHING, ModifyTable::onConflictAction, ModifyTable::onConflictWhere, ModifyTable::operation, PlanState::plan, ModifyTableState::ps, ModifyTableState::resultRelInfo, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_RangeTableIndex, ResultRelInfo::ri_usesFdwDirectModify, show_instrumentation_count(), show_upper_qual(), and ExplainState::str.

Referenced by ExplainNode().

2818 {
2819  ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
2820  const char *operation;
2821  const char *foperation;
2822  bool labeltargets;
2823  int j;
2824  List *idxNames = NIL;
2825  ListCell *lst;
2826 
2827  switch (node->operation)
2828  {
2829  case CMD_INSERT:
2830  operation = "Insert";
2831  foperation = "Foreign Insert";
2832  break;
2833  case CMD_UPDATE:
2834  operation = "Update";
2835  foperation = "Foreign Update";
2836  break;
2837  case CMD_DELETE:
2838  operation = "Delete";
2839  foperation = "Foreign Delete";
2840  break;
2841  default:
2842  operation = "???";
2843  foperation = "Foreign ???";
2844  break;
2845  }
2846 
2847  /* Should we explicitly label target relations? */
2848  labeltargets = (mtstate->mt_nplans > 1 ||
2849  (mtstate->mt_nplans == 1 &&
2850  mtstate->resultRelInfo->ri_RangeTableIndex != node->nominalRelation));
2851 
2852  if (labeltargets)
2853  ExplainOpenGroup("Target Tables", "Target Tables", false, es);
2854 
2855  for (j = 0; j < mtstate->mt_nplans; j++)
2856  {
2857  ResultRelInfo *resultRelInfo = mtstate->resultRelInfo + j;
2858  FdwRoutine *fdwroutine = resultRelInfo->ri_FdwRoutine;
2859 
2860  if (labeltargets)
2861  {
2862  /* Open a group for this target */
2863  ExplainOpenGroup("Target Table", NULL, true, es);
2864 
2865  /*
2866  * In text mode, decorate each target with operation type, so that
2867  * ExplainTargetRel's output of " on foo" will read nicely.
2868  */
2869  if (es->format == EXPLAIN_FORMAT_TEXT)
2870  {
2871  appendStringInfoSpaces(es->str, es->indent * 2);
2873  fdwroutine ? foperation : operation);
2874  }
2875 
2876  /* Identify target */
2877  ExplainTargetRel((Plan *) node,
2878  resultRelInfo->ri_RangeTableIndex,
2879  es);
2880 
2881  if (es->format == EXPLAIN_FORMAT_TEXT)
2882  {
2883  appendStringInfoChar(es->str, '\n');
2884  es->indent++;
2885  }
2886  }
2887 
2888  /* Give FDW a chance if needed */
2889  if (!resultRelInfo->ri_usesFdwDirectModify &&
2890  fdwroutine != NULL &&
2891  fdwroutine->ExplainForeignModify != NULL)
2892  {
2893  List *fdw_private = (List *) list_nth(node->fdwPrivLists, j);
2894 
2895  fdwroutine->ExplainForeignModify(mtstate,
2896  resultRelInfo,
2897  fdw_private,
2898  j,
2899  es);
2900  }
2901 
2902  if (labeltargets)
2903  {
2904  /* Undo the indentation we added in text format */
2905  if (es->format == EXPLAIN_FORMAT_TEXT)
2906  es->indent--;
2907 
2908  /* Close the group */
2909  ExplainCloseGroup("Target Table", NULL, true, es);
2910  }
2911  }
2912 
2913  /* Gather names of ON CONFLICT arbiter indexes */
2914  foreach(lst, node->arbiterIndexes)
2915  {
2916  char *indexname = get_rel_name(lfirst_oid(lst));
2917 
2918  idxNames = lappend(idxNames, indexname);
2919  }
2920 
2921  if (node->onConflictAction != ONCONFLICT_NONE)
2922  {
2923  ExplainProperty("Conflict Resolution",
2925  "NOTHING" : "UPDATE",
2926  false, es);
2927 
2928  /*
2929  * Don't display arbiter indexes at all when DO NOTHING variant
2930  * implicitly ignores all conflicts
2931  */
2932  if (idxNames)
2933  ExplainPropertyList("Conflict Arbiter Indexes", idxNames, es);
2934 
2935  /* ON CONFLICT DO UPDATE WHERE qual is specially displayed */
2936  if (node->onConflictWhere)
2937  {
2938  show_upper_qual((List *) node->onConflictWhere, "Conflict Filter",
2939  &mtstate->ps, ancestors, es);
2940  show_instrumentation_count("Rows Removed by Conflict Filter", 1, &mtstate->ps, es);
2941  }
2942 
2943  /* EXPLAIN ANALYZE display of actual outcome for each tuple proposed */
2944  if (es->analyze && mtstate->ps.instrument)
2945  {
2946  double total;
2947  double insert_path;
2948  double other_path;
2949 
2950  InstrEndLoop(mtstate->mt_plans[0]->instrument);
2951 
2952  /* count the number of source rows */
2953  total = mtstate->mt_plans[0]->instrument->ntuples;
2954  other_path = mtstate->ps.instrument->nfiltered2;
2955  insert_path = total - other_path;
2956 
2957  ExplainPropertyFloat("Tuples Inserted", insert_path, 0, es);
2958  ExplainPropertyFloat("Conflicting Tuples", other_path, 0, es);
2959  }
2960  }
2961 
2962  if (labeltargets)
2963  ExplainCloseGroup("Target Tables", "Target Tables", false, es);
2964 }
#define NIL
Definition: pg_list.h:69
List * arbiterIndexes
Definition: plannodes.h:233
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3165
Index nominalRelation
Definition: plannodes.h:219
Instrumentation * instrument
Definition: execnodes.h:857
ResultRelInfo * resultRelInfo
Definition: execnodes.h:964
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3249
bool analyze
Definition: explain.h:33
static void show_upper_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:1913
Index ri_RangeTableIndex
Definition: execnodes.h:351
static void show_instrumentation_count(const char *qlabel, int which, PlanState *planstate, ExplainState *es)
Definition: explain.c:2446
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:114
PlanState ps
Definition: execnodes.h:957
double nfiltered2
Definition: instrument.h:62
bool ri_usesFdwDirectModify
Definition: execnodes.h:384
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
void * list_nth(const List *list, int n)
Definition: list.c:410
List * fdwPrivLists
Definition: plannodes.h:228
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:378
double ntuples
Definition: instrument.h:59
int indent
Definition: explain.h:40
List * lappend(List *list, void *datum)
Definition: list.c:128
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
PlanState ** mt_plans
Definition: execnodes.h:961
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:2693
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
Plan * plan
Definition: execnodes.h:847
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:3044
OnConflictAction onConflictAction
Definition: plannodes.h:232
ExplainFormat format
Definition: explain.h:38
CmdType operation
Definition: plannodes.h:217
ExplainForeignModify_function ExplainForeignModify
Definition: fdwapi.h:217
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3340
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3277
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
StringInfo str
Definition: explain.h:30
#define lfirst_oid(lc)
Definition: pg_list.h:108
Node * onConflictWhere
Definition: plannodes.h:235
static void show_plan_tlist ( PlanState planstate,
List ancestors,
ExplainState es 
)
static

Definition at line 1797 of file explain.c.

References CMD_SELECT, ExplainState::deparse_cxt, deparse_expression(), ExplainPropertyList(), TargetEntry::expr, IsA, lappend(), lfirst, list_length(), NIL, PlanState::plan, ExplainState::rtable, set_deparse_context_planstate(), and Plan::targetlist.

Referenced by ExplainNode().

1798 {
1799  Plan *plan = planstate->plan;
1800  List *context;
1801  List *result = NIL;
1802  bool useprefix;
1803  ListCell *lc;
1804 
1805  /* No work if empty tlist (this occurs eg in bitmap indexscans) */
1806  if (plan->targetlist == NIL)
1807  return;
1808  /* The tlist of an Append isn't real helpful, so suppress it */
1809  if (IsA(plan, Append))
1810  return;
1811  /* Likewise for MergeAppend and RecursiveUnion */
1812  if (IsA(plan, MergeAppend))
1813  return;
1814  if (IsA(plan, RecursiveUnion))
1815  return;
1816 
1817  /*
1818  * Likewise for ForeignScan that executes a direct INSERT/UPDATE/DELETE
1819  *
1820  * Note: the tlist for a ForeignScan that executes a direct INSERT/UPDATE
1821  * might contain subplan output expressions that are confusing in this
1822  * context. The tlist for a ForeignScan that executes a direct UPDATE/
1823  * DELETE always contains "junk" target columns to identify the exact row
1824  * to update or delete, which would be confusing in this context. So, we
1825  * suppress it in all the cases.
1826  */
1827  if (IsA(plan, ForeignScan) &&
1828  ((ForeignScan *) plan)->operation != CMD_SELECT)
1829  return;
1830 
1831  /* Set up deparsing context */
1833  (Node *) planstate,
1834  ancestors);
1835  useprefix = list_length(es->rtable) > 1;
1836 
1837  /* Deparse each result column (we now include resjunk ones) */
1838  foreach(lc, plan->targetlist)
1839  {
1840  TargetEntry *tle = (TargetEntry *) lfirst(lc);
1841 
1842  result = lappend(result,
1843  deparse_expression((Node *) tle->expr, context,
1844  useprefix, false));
1845  }
1846 
1847  /* Print results */
1848  ExplainPropertyList("Output", result, es);
1849 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
Definition: nodes.h:509
List * deparse_cxt
Definition: explain.h:46
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:3137
List * lappend(List *list, void *datum)
Definition: list.c:128
Plan * plan
Definition: execnodes.h:847
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:3044
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1368
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:2985
static int list_length(const List *l)
Definition: pg_list.h:89
List * targetlist
Definition: plannodes.h:144
Definition: pg_list.h:45
List * rtable
Definition: explain.h:44
static void show_qual ( List qual,
const char *  qlabel,
PlanState planstate,
List ancestors,
bool  useprefix,
ExplainState es 
)
static

Definition at line 1878 of file explain.c.

References make_ands_explicit(), NIL, and show_expression().

Referenced by show_scan_qual(), and show_upper_qual().

1881 {
1882  Node *node;
1883 
1884  /* No work if empty qual */
1885  if (qual == NIL)
1886  return;
1887 
1888  /* Convert AND list to explicit AND */
1889  node = (Node *) make_ands_explicit(qual);
1890 
1891  /* And show it */
1892  show_expression(node, qlabel, planstate, ancestors, useprefix, es);
1893 }
#define NIL
Definition: pg_list.h:69
Definition: nodes.h:509
Expr * make_ands_explicit(List *andclauses)
Definition: clauses.c:367
static void show_expression(Node *node, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
Definition: explain.c:1855
static void show_scan_qual ( List qual,
const char *  qlabel,