PostgreSQL Source Code  git master
explain.c File Reference
#include "postgres.h"
#include "access/xact.h"
#include "catalog/pg_type.h"
#include "commands/createas.h"
#include "commands/defrem.h"
#include "commands/prepare.h"
#include "executor/nodeHash.h"
#include "foreign/fdwapi.h"
#include "jit/jit.h"
#include "nodes/extensible.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "parser/analyze.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteHandler.h"
#include "storage/bufmgr.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/guc_tables.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 ExplainPrintJIT (ExplainState *es, int jit_flags, JitInstrumentation *ji)
 
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_incremental_sort_keys (IncrementalSortState *incrsortstate, 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, int nPresortedKeys, 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_incremental_sort_info (IncrementalSortState *incrsortstate, ExplainState *es)
 
static void show_hash_info (HashState *hashstate, ExplainState *es)
 
static void show_memoize_info (MemoizeState *mstate, List *ancestors, ExplainState *es)
 
static void show_hashagg_info (AggState *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 void show_eval_params (Bitmapset *bms_params, ExplainState *es)
 
static const char * explain_get_index_name (Oid indexId)
 
static void show_buffer_usage (ExplainState *es, const BufferUsage *usage, bool planning)
 
static void show_wal_usage (ExplainState *es, const WalUsage *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 (PlanState **planstates, int nplans, List *ancestors, ExplainState *es)
 
static void ExplainMissingMembers (int nplans, int nchildren, ExplainState *es)
 
static void ExplainSubPlans (List *plans, List *ancestors, const char *relationship, ExplainState *es)
 
static void ExplainCustomChildren (CustomScanState *css, List *ancestors, ExplainState *es)
 
static ExplainWorkersStateExplainCreateWorkersState (int num_workers)
 
static void ExplainOpenWorker (int n, ExplainState *es)
 
static void ExplainCloseWorker (int n, ExplainState *es)
 
static void ExplainFlushWorkersState (ExplainState *es)
 
static void ExplainProperty (const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
 
static void ExplainOpenSetAsideGroup (const char *objtype, const char *labelname, bool labeled, int depth, ExplainState *es)
 
static void ExplainSaveGroup (ExplainState *es, int depth, int *state_save)
 
static void ExplainRestoreGroup (ExplainState *es, int depth, int *state_save)
 
static void ExplainDummyGroup (const char *objtype, const char *labelname, ExplainState *es)
 
static void ExplainXMLTag (const char *tagname, int flags, ExplainState *es)
 
static void ExplainIndentText (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, ParamListInfo params, 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, const BufferUsage *bufusage)
 
static void ExplainPrintSettings (ExplainState *es)
 
void ExplainPrintPlan (ExplainState *es, QueryDesc *queryDesc)
 
void ExplainPrintTriggers (ExplainState *es, QueryDesc *queryDesc)
 
void ExplainPrintJITSummary (ExplainState *es, QueryDesc *queryDesc)
 
void ExplainQueryText (ExplainState *es, QueryDesc *queryDesc)
 
static void show_incremental_sort_group_info (IncrementalSortGroupInfo *groupInfo, const char *groupLabel, bool indent, ExplainState *es)
 
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, const char *unit, int64 value, ExplainState *es)
 
void ExplainPropertyUInteger (const char *qlabel, const char *unit, uint64 value, ExplainState *es)
 
void ExplainPropertyFloat (const char *qlabel, const char *unit, 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

◆ X_CLOSE_IMMEDIATE

#define X_CLOSE_IMMEDIATE   2

Definition at line 54 of file explain.c.

Referenced by ExplainDummyGroup(), and ExplainXMLTag().

◆ X_CLOSING

#define X_CLOSING   1

Definition at line 53 of file explain.c.

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

◆ X_NOWHITESPACE

#define X_NOWHITESPACE   4

Definition at line 55 of file explain.c.

Referenced by ExplainProperty(), and ExplainXMLTag().

◆ X_OPENING

#define X_OPENING   0

Definition at line 52 of file explain.c.

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

Function Documentation

◆ elapsed_time()

static double elapsed_time ( instr_time starttime)
static

Definition at line 1045 of file explain.c.

References INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, and INSTR_TIME_SUBTRACT.

Referenced by ExplainOnePlan(), and IsCheckpointOnSchedule().

1046 {
1047  instr_time endtime;
1048 
1049  INSTR_TIME_SET_CURRENT(endtime);
1050  INSTR_TIME_SUBTRACT(endtime, *starttime);
1051  return INSTR_TIME_GET_DOUBLE(endtime);
1052 }
struct timeval instr_time
Definition: instr_time.h:150
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:199
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:170
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156

◆ escape_yaml()

static void escape_yaml ( StringInfo  buf,
const char *  str 
)
static

Definition at line 4921 of file explain.c.

References escape_json().

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

4922 {
4923  escape_json(buf, str);
4924 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:1279

◆ explain_get_index_name()

static const char * explain_get_index_name ( Oid  indexId)
static

Definition at line 3466 of file explain.c.

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

Referenced by ExplainIndexScanDetails(), and ExplainNode().

3467 {
3468  const char *result;
3469 
3471  result = (*explain_get_index_name_hook) (indexId);
3472  else
3473  result = NULL;
3474  if (result == NULL)
3475  {
3476  /* default behavior: look it up in the catalogs */
3477  result = get_rel_name(indexId);
3478  if (result == NULL)
3479  elog(ERROR, "cache lookup failed for index %u", indexId);
3480  }
3481  return result;
3482 }
#define ERROR
Definition: elog.h:46
explain_get_index_name_hook_type explain_get_index_name_hook
Definition: explain.c:48
#define elog(elevel,...)
Definition: elog.h:232
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1899

◆ ExplainBeginOutput()

void ExplainBeginOutput ( ExplainState es)

Definition at line 4745 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().

4746 {
4747  switch (es->format)
4748  {
4749  case EXPLAIN_FORMAT_TEXT:
4750  /* nothing to do */
4751  break;
4752 
4753  case EXPLAIN_FORMAT_XML:
4755  "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
4756  es->indent++;
4757  break;
4758 
4759  case EXPLAIN_FORMAT_JSON:
4760  /* top-level structure is an array of plans */
4761  appendStringInfoChar(es->str, '[');
4762  es->grouping_stack = lcons_int(0, es->grouping_stack);
4763  es->indent++;
4764  break;
4765 
4766  case EXPLAIN_FORMAT_YAML:
4767  es->grouping_stack = lcons_int(0, es->grouping_stack);
4768  break;
4769  }
4770 }
List * lcons_int(int datum, List *list)
Definition: list.c:486
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
List * grouping_stack
Definition: explain.h:52
int indent
Definition: explain.h:51
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
ExplainFormat format
Definition: explain.h:49
StringInfo str
Definition: explain.h:39

◆ ExplainCloseGroup()

void ExplainCloseGroup ( const char *  objtype,
const char *  labelname,
bool  labeled,
ExplainState es 
)

Definition at line 4552 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 ExplainFlushWorkersState(), ExplainNode(), ExplainOnePlan(), ExplainPrintJIT(), ExplainPrintSettings(), ExplainPrintTriggers(), report_triggers(), show_grouping_set_keys(), show_grouping_sets(), show_incremental_sort_group_info(), and show_modifytable_info().

4554 {
4555  switch (es->format)
4556  {
4557  case EXPLAIN_FORMAT_TEXT:
4558  /* nothing to do */
4559  break;
4560 
4561  case EXPLAIN_FORMAT_XML:
4562  es->indent--;
4563  ExplainXMLTag(objtype, X_CLOSING, es);
4564  break;
4565 
4566  case EXPLAIN_FORMAT_JSON:
4567  es->indent--;
4568  appendStringInfoChar(es->str, '\n');
4569  appendStringInfoSpaces(es->str, 2 * es->indent);
4570  appendStringInfoChar(es->str, labeled ? '}' : ']');
4572  break;
4573 
4574  case EXPLAIN_FORMAT_YAML:
4575  es->indent--;
4577  break;
4578  }
4579 }
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:4834
#define X_CLOSING
Definition: explain.c:53
List * grouping_stack
Definition: explain.h:52
int indent
Definition: explain.h:51
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
ExplainFormat format
Definition: explain.h:49
StringInfo str
Definition: explain.h:39
List * list_delete_first(List *list)
Definition: list.c:875

◆ ExplainCloseWorker()

static void ExplainCloseWorker ( int  n,
ExplainState es 
)
static

Definition at line 4182 of file explain.c.

References Assert, StringInfoData::data, EXPLAIN_FORMAT_TEXT, ExplainSaveGroup(), ExplainState::format, ExplainState::indent, StringInfoData::len, ExplainWorkersState::prev_str, ExplainState::str, ExplainWorkersState::worker_inited, ExplainWorkersState::worker_state_save, and ExplainState::workers_state.

Referenced by ExplainNode(), show_hashagg_info(), show_incremental_sort_info(), show_memoize_info(), and show_sort_info().

4183 {
4184  ExplainWorkersState *wstate = es->workers_state;
4185 
4186  Assert(wstate);
4187  Assert(n >= 0 && n < wstate->num_workers);
4188  Assert(wstate->worker_inited[n]);
4189 
4190  /*
4191  * Save formatting state in case we do another ExplainOpenWorker(), then
4192  * pop the formatting stack.
4193  */
4194  ExplainSaveGroup(es, 2, &wstate->worker_state_save[n]);
4195 
4196  /*
4197  * In TEXT format, if we didn't actually produce any output line(s) then
4198  * truncate off the partial line emitted by ExplainOpenWorker. (This is
4199  * to avoid bogus output if, say, show_buffer_usage chooses not to print
4200  * anything for the worker.) Also fix up the indent level.
4201  */
4202  if (es->format == EXPLAIN_FORMAT_TEXT)
4203  {
4204  while (es->str->len > 0 && es->str->data[es->str->len - 1] != '\n')
4205  es->str->data[--(es->str->len)] = '\0';
4206 
4207  es->indent--;
4208  }
4209 
4210  /* Restore prior output buffer pointer */
4211  es->str = wstate->prev_str;
4212 }
int * worker_state_save
Definition: explain.h:33
int indent
Definition: explain.h:51
bool * worker_inited
Definition: explain.h:31
#define Assert(condition)
Definition: c.h:804
ExplainWorkersState * workers_state
Definition: explain.h:61
ExplainFormat format
Definition: explain.h:49
StringInfo prev_str
Definition: explain.h:34
static void ExplainSaveGroup(ExplainState *es, int depth, int *state_save)
Definition: explain.c:4638
StringInfo str
Definition: explain.h:39

◆ ExplainCreateWorkersState()

static ExplainWorkersState * ExplainCreateWorkersState ( int  num_workers)
static

Definition at line 4103 of file explain.c.

References ExplainWorkersState::num_workers, palloc(), palloc0(), ExplainWorkersState::worker_inited, ExplainWorkersState::worker_state_save, and ExplainWorkersState::worker_str.

Referenced by ExplainNode().

4104 {
4105  ExplainWorkersState *wstate;
4106 
4107  wstate = (ExplainWorkersState *) palloc(sizeof(ExplainWorkersState));
4108  wstate->num_workers = num_workers;
4109  wstate->worker_inited = (bool *) palloc0(num_workers * sizeof(bool));
4110  wstate->worker_str = (StringInfoData *)
4111  palloc0(num_workers * sizeof(StringInfoData));
4112  wstate->worker_state_save = (int *) palloc(num_workers * sizeof(int));
4113  return wstate;
4114 }
int * worker_state_save
Definition: explain.h:33
StringInfoData * worker_str
Definition: explain.h:32
void * palloc0(Size size)
Definition: mcxt.c:1093
bool * worker_inited
Definition: explain.h:31
void * palloc(Size size)
Definition: mcxt.c:1062

◆ ExplainCustomChildren()

static void ExplainCustomChildren ( CustomScanState css,
List ancestors,
ExplainState es 
)
static

Definition at line 4081 of file explain.c.

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

Referenced by ExplainNode().

4082 {
4083  ListCell *cell;
4084  const char *label =
4085  (list_length(css->custom_ps) != 1 ? "children" : "child");
4086 
4087  foreach(cell, css->custom_ps)
4088  ExplainNode((PlanState *) lfirst(cell), ancestors, label, NULL, es);
4089 }
List * custom_ps
Definition: execnodes.h:1886
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1139
static char * label
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149

◆ ExplainDummyGroup()

static void ExplainDummyGroup ( const char *  objtype,
const char *  labelname,
ExplainState es 
)
static

Definition at line 4699 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().

4700 {
4701  switch (es->format)
4702  {
4703  case EXPLAIN_FORMAT_TEXT:
4704  /* nothing to do */
4705  break;
4706 
4707  case EXPLAIN_FORMAT_XML:
4708  ExplainXMLTag(objtype, X_CLOSE_IMMEDIATE, es);
4709  break;
4710 
4711  case EXPLAIN_FORMAT_JSON:
4713  appendStringInfoSpaces(es->str, 2 * es->indent);
4714  if (labelname)
4715  {
4716  escape_json(es->str, labelname);
4717  appendStringInfoString(es->str, ": ");
4718  }
4719  escape_json(es->str, objtype);
4720  break;
4721 
4722  case EXPLAIN_FORMAT_YAML:
4724  if (labelname)
4725  {
4726  escape_yaml(es->str, labelname);
4727  appendStringInfoString(es->str, ": ");
4728  }
4729  else
4730  {
4731  appendStringInfoString(es->str, "- ");
4732  }
4733  escape_yaml(es->str, objtype);
4734  break;
4735  }
4736 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:1279
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:4834
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:4896
int indent
Definition: explain.h:51
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:4921
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:4876
ExplainFormat format
Definition: explain.h:49
#define X_CLOSE_IMMEDIATE
Definition: explain.c:54
StringInfo str
Definition: explain.h:39

◆ ExplainEndOutput()

void ExplainEndOutput ( ExplainState es)

Definition at line 4776 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().

4777 {
4778  switch (es->format)
4779  {
4780  case EXPLAIN_FORMAT_TEXT:
4781  /* nothing to do */
4782  break;
4783 
4784  case EXPLAIN_FORMAT_XML:
4785  es->indent--;
4786  appendStringInfoString(es->str, "</explain>");
4787  break;
4788 
4789  case EXPLAIN_FORMAT_JSON:
4790  es->indent--;
4791  appendStringInfoString(es->str, "\n]");
4793  break;
4794 
4795  case EXPLAIN_FORMAT_YAML:
4797  break;
4798  }
4799 }
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
List * grouping_stack
Definition: explain.h:52
int indent
Definition: explain.h:51
ExplainFormat format
Definition: explain.h:49
StringInfo str
Definition: explain.h:39
List * list_delete_first(List *list)
Definition: list.c:875

◆ ExplainFlushWorkersState()

static void ExplainFlushWorkersState ( ExplainState es)
static

Definition at line 4218 of file explain.c.

References appendStringInfoString(), StringInfoData::data, ExplainCloseGroup(), ExplainOpenGroup(), i, ExplainWorkersState::num_workers, pfree(), ExplainState::str, ExplainWorkersState::worker_inited, ExplainWorkersState::worker_state_save, ExplainWorkersState::worker_str, and ExplainState::workers_state.

Referenced by ExplainNode().

4219 {
4220  ExplainWorkersState *wstate = es->workers_state;
4221 
4222  ExplainOpenGroup("Workers", "Workers", false, es);
4223  for (int i = 0; i < wstate->num_workers; i++)
4224  {
4225  if (wstate->worker_inited[i])
4226  {
4227  /* This must match previous ExplainOpenSetAsideGroup call */
4228  ExplainOpenGroup("Worker", NULL, true, es);
4229  appendStringInfoString(es->str, wstate->worker_str[i].data);
4230  ExplainCloseGroup("Worker", NULL, true, es);
4231 
4232  pfree(wstate->worker_str[i].data);
4233  }
4234  }
4235  ExplainCloseGroup("Workers", "Workers", false, es);
4236 
4237  pfree(wstate->worker_inited);
4238  pfree(wstate->worker_str);
4239  pfree(wstate->worker_state_save);
4240  pfree(wstate);
4241 }
int * worker_state_save
Definition: explain.h:33
void pfree(void *pointer)
Definition: mcxt.c:1169
StringInfoData * worker_str
Definition: explain.h:32
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
bool * worker_inited
Definition: explain.h:31
ExplainWorkersState * workers_state
Definition: explain.h:61
int i
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4552
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4489
StringInfo str
Definition: explain.h:39

◆ ExplainIndentText()

static void ExplainIndentText ( ExplainState es)
static

◆ ExplainIndexScanDetails()

static void ExplainIndexScanDetails ( Oid  indexid,
ScanDirection  indexorderdir,
ExplainState es 
)
static

Definition at line 3662 of file explain.c.

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

Referenced by ExplainNode().

3664 {
3665  const char *indexname = explain_get_index_name(indexid);
3666 
3667  if (es->format == EXPLAIN_FORMAT_TEXT)
3668  {
3669  if (ScanDirectionIsBackward(indexorderdir))
3670  appendStringInfoString(es->str, " Backward");
3671  appendStringInfo(es->str, " using %s", quote_identifier(indexname));
3672  }
3673  else
3674  {
3675  const char *scandir;
3676 
3677  switch (indexorderdir)
3678  {
3679  case BackwardScanDirection:
3680  scandir = "Backward";
3681  break;
3683  scandir = "NoMovement";
3684  break;
3685  case ForwardScanDirection:
3686  scandir = "Forward";
3687  break;
3688  default:
3689  scandir = "???";
3690  break;
3691  }
3692  ExplainPropertyText("Scan Direction", scandir, es);
3693  ExplainPropertyText("Index Name", indexname, es);
3694  }
3695 }
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:11374
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:4424
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
ExplainFormat format
Definition: explain.h:49
static const char * explain_get_index_name(Oid indexId)
Definition: explain.c:3466
StringInfo str
Definition: explain.h:39

◆ ExplainJSONLineEnding()

static void ExplainJSONLineEnding ( ExplainState es)
static

Definition at line 4876 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().

4877 {
4879  if (linitial_int(es->grouping_stack) != 0)
4880  appendStringInfoChar(es->str, ',');
4881  else
4882  linitial_int(es->grouping_stack) = 1;
4883  appendStringInfoChar(es->str, '\n');
4884 }
#define linitial_int(l)
Definition: pg_list.h:175
List * grouping_stack
Definition: explain.h:52
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
#define Assert(condition)
Definition: c.h:804
ExplainFormat format
Definition: explain.h:49
StringInfo str
Definition: explain.h:39

◆ ExplainMemberNodes()

static void ExplainMemberNodes ( PlanState **  planstates,
int  nplans,
List ancestors,
ExplainState es 
)
static

Definition at line 4006 of file explain.c.

References ExplainNode().

Referenced by ExplainNode().

4008 {
4009  int j;
4010 
4011  for (j = 0; j < nplans; j++)
4012  ExplainNode(planstates[j], ancestors,
4013  "Member", NULL, es);
4014 }
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1139

◆ ExplainMissingMembers()

static void ExplainMissingMembers ( int  nplans,
int  nchildren,
ExplainState es 
)
static

Definition at line 4024 of file explain.c.

References EXPLAIN_FORMAT_TEXT, ExplainPropertyInteger(), and format.

Referenced by ExplainNode().

4025 {
4026  if (nplans < nchildren || es->format != EXPLAIN_FORMAT_TEXT)
4027  ExplainPropertyInteger("Subplans Removed", NULL,
4028  nchildren - nplans, es);
4029 }
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:4433
static char format

◆ ExplainModifyTarget()

static void ExplainModifyTarget ( ModifyTable plan,
ExplainState es 
)
static

Definition at line 3714 of file explain.c.

References ExplainTargetRel().

Referenced by ExplainNode().

3715 {
3716  ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
3717 }
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:3723

◆ ExplainNode()

static void ExplainNode ( PlanState planstate,
List ancestors,
const char *  relationship,
const char *  plan_name,
ExplainState es 
)
static

Definition at line 1139 of file explain.c.

References AGG_HASHED, AGG_MIXED, AGG_PLAIN, AGG_SORTED, Agg::aggsplit, Agg::aggstrategy, ExplainState::analyze, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Plan::async_capable, ExplainState::buffers, Instrumentation::bufusage, castNode, CMD_DELETE, CMD_INSERT, CMD_SELECT, CMD_UPDATE, ExplainState::costs, DO_AGGSPLIT_COMBINE, DO_AGGSPLIT_SKIPFINAL, EState::es_jit_flags, EXPLAIN_FORMAT_TEXT, explain_get_index_name(), ExplainCloseGroup(), ExplainCloseWorker(), ExplainCreateWorkersState(), ExplainCustomChildren(), CustomExecMethods::ExplainCustomScan, ExplainFlushWorkersState(), ExplainIndentText(), ExplainIndexScanDetails(), ExplainMemberNodes(), ExplainMissingMembers(), ExplainModifyTarget(), ExplainOpenGroup(), ExplainOpenWorker(), ExplainPrintJIT(), ExplainPropertyBool(), ExplainPropertyFloat(), ExplainPropertyInteger(), ExplainPropertyText(), ExplainScanTarget(), ExplainSubPlans(), ExplainState::format, RangeTblFunction::funcexpr, functions, ExplainState::hide_workers, ExplainState::indent, IndexScan::indexid, IndexOnlyScan::indexid, BitmapIndexScan::indexid, IndexScan::indexorderdir, IndexOnlyScan::indexorderdir, Gather::initParam, GatherMerge::initParam, PlanState::initPlan, innerPlanState, InstrEndLoop(), WorkerInstrumentation::instrument, PlanState::instrument, IsA, SharedJitInstrumentation::jit_instr, JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, JOIN_SEMI, lappend(), lcons(), lfirst, list_delete_first(), list_length(), list_make1, make_andclause(), make_orclause(), CustomScanState::methods, NIL, Instrumentation::nloops, nodeTag, Instrumentation::ntuples, Instrumentation::ntuples2, SharedJitInstrumentation::num_workers, WorkerInstrumentation::num_workers, Gather::num_workers, GatherMerge::num_workers, outerPlanState, Plan::parallel_aware, PlanState::plan, Plan::plan_rows, Plan::plan_width, psprintf(), quote_identifier(), SETOP_HASHED, SETOP_SORTED, SETOPCMD_EXCEPT, SETOPCMD_EXCEPT_ALL, SETOPCMD_INTERSECT, SETOPCMD_INTERSECT_ALL, show_agg_keys(), show_buffer_usage(), show_eval_params(), show_expression(), show_foreignscan_info(), show_group_keys(), show_hash_info(), show_hashagg_info(), show_incremental_sort_info(), show_incremental_sort_keys(), show_instrumentation_count(), show_memoize_info(), 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(), show_wal_usage(), Gather::single_copy, Instrumentation::startup, Plan::startup_cost, PlanState::state, 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_IncrementalSort, T_IndexOnlyScan, T_IndexScan, T_Limit, T_LockRows, T_Material, T_Memoize, 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_TidRangeScan, T_TidScan, T_Unique, T_ValuesScan, T_WindowAgg, T_WorkTableScan, ExplainState::timing, Instrumentation::total, Plan::total_cost, ExplainState::verbose, ExplainState::wal, Instrumentation::walusage, PlanState::worker_instrument, PlanState::worker_jit_instrument, and ExplainState::workers_state.

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

1142 {
1143  Plan *plan = planstate->plan;
1144  const char *pname; /* node type name for text output */
1145  const char *sname; /* node type name for non-text output */
1146  const char *strategy = NULL;
1147  const char *partialmode = NULL;
1148  const char *operation = NULL;
1149  const char *custom_name = NULL;
1150  ExplainWorkersState *save_workers_state = es->workers_state;
1151  int save_indent = es->indent;
1152  bool haschildren;
1153 
1154  /*
1155  * Prepare per-worker output buffers, if needed. We'll append the data in
1156  * these to the main output string further down.
1157  */
1158  if (planstate->worker_instrument && es->analyze && !es->hide_workers)
1160  else
1161  es->workers_state = NULL;
1162 
1163  /* Identify plan node type, and print generic details */
1164  switch (nodeTag(plan))
1165  {
1166  case T_Result:
1167  pname = sname = "Result";
1168  break;
1169  case T_ProjectSet:
1170  pname = sname = "ProjectSet";
1171  break;
1172  case T_ModifyTable:
1173  sname = "ModifyTable";
1174  switch (((ModifyTable *) plan)->operation)
1175  {
1176  case CMD_INSERT:
1177  pname = operation = "Insert";
1178  break;
1179  case CMD_UPDATE:
1180  pname = operation = "Update";
1181  break;
1182  case CMD_DELETE:
1183  pname = operation = "Delete";
1184  break;
1185  default:
1186  pname = "???";
1187  break;
1188  }
1189  break;
1190  case T_Append:
1191  pname = sname = "Append";
1192  break;
1193  case T_MergeAppend:
1194  pname = sname = "Merge Append";
1195  break;
1196  case T_RecursiveUnion:
1197  pname = sname = "Recursive Union";
1198  break;
1199  case T_BitmapAnd:
1200  pname = sname = "BitmapAnd";
1201  break;
1202  case T_BitmapOr:
1203  pname = sname = "BitmapOr";
1204  break;
1205  case T_NestLoop:
1206  pname = sname = "Nested Loop";
1207  break;
1208  case T_MergeJoin:
1209  pname = "Merge"; /* "Join" gets added by jointype switch */
1210  sname = "Merge Join";
1211  break;
1212  case T_HashJoin:
1213  pname = "Hash"; /* "Join" gets added by jointype switch */
1214  sname = "Hash Join";
1215  break;
1216  case T_SeqScan:
1217  pname = sname = "Seq Scan";
1218  break;
1219  case T_SampleScan:
1220  pname = sname = "Sample Scan";
1221  break;
1222  case T_Gather:
1223  pname = sname = "Gather";
1224  break;
1225  case T_GatherMerge:
1226  pname = sname = "Gather Merge";
1227  break;
1228  case T_IndexScan:
1229  pname = sname = "Index Scan";
1230  break;
1231  case T_IndexOnlyScan:
1232  pname = sname = "Index Only Scan";
1233  break;
1234  case T_BitmapIndexScan:
1235  pname = sname = "Bitmap Index Scan";
1236  break;
1237  case T_BitmapHeapScan:
1238  pname = sname = "Bitmap Heap Scan";
1239  break;
1240  case T_TidScan:
1241  pname = sname = "Tid Scan";
1242  break;
1243  case T_TidRangeScan:
1244  pname = sname = "Tid Range Scan";
1245  break;
1246  case T_SubqueryScan:
1247  pname = sname = "Subquery Scan";
1248  break;
1249  case T_FunctionScan:
1250  pname = sname = "Function Scan";
1251  break;
1252  case T_TableFuncScan:
1253  pname = sname = "Table Function Scan";
1254  break;
1255  case T_ValuesScan:
1256  pname = sname = "Values Scan";
1257  break;
1258  case T_CteScan:
1259  pname = sname = "CTE Scan";
1260  break;
1261  case T_NamedTuplestoreScan:
1262  pname = sname = "Named Tuplestore Scan";
1263  break;
1264  case T_WorkTableScan:
1265  pname = sname = "WorkTable Scan";
1266  break;
1267  case T_ForeignScan:
1268  sname = "Foreign Scan";
1269  switch (((ForeignScan *) plan)->operation)
1270  {
1271  case CMD_SELECT:
1272  pname = "Foreign Scan";
1273  operation = "Select";
1274  break;
1275  case CMD_INSERT:
1276  pname = "Foreign Insert";
1277  operation = "Insert";
1278  break;
1279  case CMD_UPDATE:
1280  pname = "Foreign Update";
1281  operation = "Update";
1282  break;
1283  case CMD_DELETE:
1284  pname = "Foreign Delete";
1285  operation = "Delete";
1286  break;
1287  default:
1288  pname = "???";
1289  break;
1290  }
1291  break;
1292  case T_CustomScan:
1293  sname = "Custom Scan";
1294  custom_name = ((CustomScan *) plan)->methods->CustomName;
1295  if (custom_name)
1296  pname = psprintf("Custom Scan (%s)", custom_name);
1297  else
1298  pname = sname;
1299  break;
1300  case T_Material:
1301  pname = sname = "Materialize";
1302  break;
1303  case T_Memoize:
1304  pname = sname = "Memoize";
1305  break;
1306  case T_Sort:
1307  pname = sname = "Sort";
1308  break;
1309  case T_IncrementalSort:
1310  pname = sname = "Incremental Sort";
1311  break;
1312  case T_Group:
1313  pname = sname = "Group";
1314  break;
1315  case T_Agg:
1316  {
1317  Agg *agg = (Agg *) plan;
1318 
1319  sname = "Aggregate";
1320  switch (agg->aggstrategy)
1321  {
1322  case AGG_PLAIN:
1323  pname = "Aggregate";
1324  strategy = "Plain";
1325  break;
1326  case AGG_SORTED:
1327  pname = "GroupAggregate";
1328  strategy = "Sorted";
1329  break;
1330  case AGG_HASHED:
1331  pname = "HashAggregate";
1332  strategy = "Hashed";
1333  break;
1334  case AGG_MIXED:
1335  pname = "MixedAggregate";
1336  strategy = "Mixed";
1337  break;
1338  default:
1339  pname = "Aggregate ???";
1340  strategy = "???";
1341  break;
1342  }
1343 
1344  if (DO_AGGSPLIT_SKIPFINAL(agg->aggsplit))
1345  {
1346  partialmode = "Partial";
1347  pname = psprintf("%s %s", partialmode, pname);
1348  }
1349  else if (DO_AGGSPLIT_COMBINE(agg->aggsplit))
1350  {
1351  partialmode = "Finalize";
1352  pname = psprintf("%s %s", partialmode, pname);
1353  }
1354  else
1355  partialmode = "Simple";
1356  }
1357  break;
1358  case T_WindowAgg:
1359  pname = sname = "WindowAgg";
1360  break;
1361  case T_Unique:
1362  pname = sname = "Unique";
1363  break;
1364  case T_SetOp:
1365  sname = "SetOp";
1366  switch (((SetOp *) plan)->strategy)
1367  {
1368  case SETOP_SORTED:
1369  pname = "SetOp";
1370  strategy = "Sorted";
1371  break;
1372  case SETOP_HASHED:
1373  pname = "HashSetOp";
1374  strategy = "Hashed";
1375  break;
1376  default:
1377  pname = "SetOp ???";
1378  strategy = "???";
1379  break;
1380  }
1381  break;
1382  case T_LockRows:
1383  pname = sname = "LockRows";
1384  break;
1385  case T_Limit:
1386  pname = sname = "Limit";
1387  break;
1388  case T_Hash:
1389  pname = sname = "Hash";
1390  break;
1391  default:
1392  pname = sname = "???";
1393  break;
1394  }
1395 
1396  ExplainOpenGroup("Plan",
1397  relationship ? NULL : "Plan",
1398  true, es);
1399 
1400  if (es->format == EXPLAIN_FORMAT_TEXT)
1401  {
1402  if (plan_name)
1403  {
1404  ExplainIndentText(es);
1405  appendStringInfo(es->str, "%s\n", plan_name);
1406  es->indent++;
1407  }
1408  if (es->indent)
1409  {
1410  ExplainIndentText(es);
1411  appendStringInfoString(es->str, "-> ");
1412  es->indent += 2;
1413  }
1414  if (plan->parallel_aware)
1415  appendStringInfoString(es->str, "Parallel ");
1416  if (plan->async_capable)
1417  appendStringInfoString(es->str, "Async ");
1418  appendStringInfoString(es->str, pname);
1419  es->indent++;
1420  }
1421  else
1422  {
1423  ExplainPropertyText("Node Type", sname, es);
1424  if (strategy)
1425  ExplainPropertyText("Strategy", strategy, es);
1426  if (partialmode)
1427  ExplainPropertyText("Partial Mode", partialmode, es);
1428  if (operation)
1429  ExplainPropertyText("Operation", operation, es);
1430  if (relationship)
1431  ExplainPropertyText("Parent Relationship", relationship, es);
1432  if (plan_name)
1433  ExplainPropertyText("Subplan Name", plan_name, es);
1434  if (custom_name)
1435  ExplainPropertyText("Custom Plan Provider", custom_name, es);
1436  ExplainPropertyBool("Parallel Aware", plan->parallel_aware, es);
1437  ExplainPropertyBool("Async Capable", plan->async_capable, es);
1438  }
1439 
1440  switch (nodeTag(plan))
1441  {
1442  case T_SeqScan:
1443  case T_SampleScan:
1444  case T_BitmapHeapScan:
1445  case T_TidScan:
1446  case T_TidRangeScan:
1447  case T_SubqueryScan:
1448  case T_FunctionScan:
1449  case T_TableFuncScan:
1450  case T_ValuesScan:
1451  case T_CteScan:
1452  case T_WorkTableScan:
1453  ExplainScanTarget((Scan *) plan, es);
1454  break;
1455  case T_ForeignScan:
1456  case T_CustomScan:
1457  if (((Scan *) plan)->scanrelid > 0)
1458  ExplainScanTarget((Scan *) plan, es);
1459  break;
1460  case T_IndexScan:
1461  {
1462  IndexScan *indexscan = (IndexScan *) plan;
1463 
1464  ExplainIndexScanDetails(indexscan->indexid,
1465  indexscan->indexorderdir,
1466  es);
1467  ExplainScanTarget((Scan *) indexscan, es);
1468  }
1469  break;
1470  case T_IndexOnlyScan:
1471  {
1472  IndexOnlyScan *indexonlyscan = (IndexOnlyScan *) plan;
1473 
1474  ExplainIndexScanDetails(indexonlyscan->indexid,
1475  indexonlyscan->indexorderdir,
1476  es);
1477  ExplainScanTarget((Scan *) indexonlyscan, es);
1478  }
1479  break;
1480  case T_BitmapIndexScan:
1481  {
1482  BitmapIndexScan *bitmapindexscan = (BitmapIndexScan *) plan;
1483  const char *indexname =
1484  explain_get_index_name(bitmapindexscan->indexid);
1485 
1486  if (es->format == EXPLAIN_FORMAT_TEXT)
1487  appendStringInfo(es->str, " on %s",
1488  quote_identifier(indexname));
1489  else
1490  ExplainPropertyText("Index Name", indexname, es);
1491  }
1492  break;
1493  case T_ModifyTable:
1494  ExplainModifyTarget((ModifyTable *) plan, es);
1495  break;
1496  case T_NestLoop:
1497  case T_MergeJoin:
1498  case T_HashJoin:
1499  {
1500  const char *jointype;
1501 
1502  switch (((Join *) plan)->jointype)
1503  {
1504  case JOIN_INNER:
1505  jointype = "Inner";
1506  break;
1507  case JOIN_LEFT:
1508  jointype = "Left";
1509  break;
1510  case JOIN_FULL:
1511  jointype = "Full";
1512  break;
1513  case JOIN_RIGHT:
1514  jointype = "Right";
1515  break;
1516  case JOIN_SEMI:
1517  jointype = "Semi";
1518  break;
1519  case JOIN_ANTI:
1520  jointype = "Anti";
1521  break;
1522  default:
1523  jointype = "???";
1524  break;
1525  }
1526  if (es->format == EXPLAIN_FORMAT_TEXT)
1527  {
1528  /*
1529  * For historical reasons, the join type is interpolated
1530  * into the node type name...
1531  */
1532  if (((Join *) plan)->jointype != JOIN_INNER)
1533  appendStringInfo(es->str, " %s Join", jointype);
1534  else if (!IsA(plan, NestLoop))
1535  appendStringInfoString(es->str, " Join");
1536  }
1537  else
1538  ExplainPropertyText("Join Type", jointype, es);
1539  }
1540  break;
1541  case T_SetOp:
1542  {
1543  const char *setopcmd;
1544 
1545  switch (((SetOp *) plan)->cmd)
1546  {
1547  case SETOPCMD_INTERSECT:
1548  setopcmd = "Intersect";
1549  break;
1551  setopcmd = "Intersect All";
1552  break;
1553  case SETOPCMD_EXCEPT:
1554  setopcmd = "Except";
1555  break;
1556  case SETOPCMD_EXCEPT_ALL:
1557  setopcmd = "Except All";
1558  break;
1559  default:
1560  setopcmd = "???";
1561  break;
1562  }
1563  if (es->format == EXPLAIN_FORMAT_TEXT)
1564  appendStringInfo(es->str, " %s", setopcmd);
1565  else
1566  ExplainPropertyText("Command", setopcmd, es);
1567  }
1568  break;
1569  default:
1570  break;
1571  }
1572 
1573  if (es->costs)
1574  {
1575  if (es->format == EXPLAIN_FORMAT_TEXT)
1576  {
1577  appendStringInfo(es->str, " (cost=%.2f..%.2f rows=%.0f width=%d)",
1578  plan->startup_cost, plan->total_cost,
1579  plan->plan_rows, plan->plan_width);
1580  }
1581  else
1582  {
1583  ExplainPropertyFloat("Startup Cost", NULL, plan->startup_cost,
1584  2, es);
1585  ExplainPropertyFloat("Total Cost", NULL, plan->total_cost,
1586  2, es);
1587  ExplainPropertyFloat("Plan Rows", NULL, plan->plan_rows,
1588  0, es);
1589  ExplainPropertyInteger("Plan Width", NULL, plan->plan_width,
1590  es);
1591  }
1592  }
1593 
1594  /*
1595  * We have to forcibly clean up the instrumentation state because we
1596  * haven't done ExecutorEnd yet. This is pretty grotty ...
1597  *
1598  * Note: contrib/auto_explain could cause instrumentation to be set up
1599  * even though we didn't ask for it here. Be careful not to print any
1600  * instrumentation results the user didn't ask for. But we do the
1601  * InstrEndLoop call anyway, if possible, to reduce the number of cases
1602  * auto_explain has to contend with.
1603  */
1604  if (planstate->instrument)
1605  InstrEndLoop(planstate->instrument);
1606 
1607  if (es->analyze &&
1608  planstate->instrument && planstate->instrument->nloops > 0)
1609  {
1610  double nloops = planstate->instrument->nloops;
1611  double startup_ms = 1000.0 * planstate->instrument->startup / nloops;
1612  double total_ms = 1000.0 * planstate->instrument->total / nloops;
1613  double rows = planstate->instrument->ntuples / nloops;
1614 
1615  if (es->format == EXPLAIN_FORMAT_TEXT)
1616  {
1617  if (es->timing)
1618  appendStringInfo(es->str,
1619  " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",
1620  startup_ms, total_ms, rows, nloops);
1621  else
1622  appendStringInfo(es->str,
1623  " (actual rows=%.0f loops=%.0f)",
1624  rows, nloops);
1625  }
1626  else
1627  {
1628  if (es->timing)
1629  {
1630  ExplainPropertyFloat("Actual Startup Time", "ms", startup_ms,
1631  3, es);
1632  ExplainPropertyFloat("Actual Total Time", "ms", total_ms,
1633  3, es);
1634  }
1635  ExplainPropertyFloat("Actual Rows", NULL, rows, 0, es);
1636  ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es);
1637  }
1638  }
1639  else if (es->analyze)
1640  {
1641  if (es->format == EXPLAIN_FORMAT_TEXT)
1642  appendStringInfoString(es->str, " (never executed)");
1643  else
1644  {
1645  if (es->timing)
1646  {
1647  ExplainPropertyFloat("Actual Startup Time", "ms", 0.0, 3, es);
1648  ExplainPropertyFloat("Actual Total Time", "ms", 0.0, 3, es);
1649  }
1650  ExplainPropertyFloat("Actual Rows", NULL, 0.0, 0, es);
1651  ExplainPropertyFloat("Actual Loops", NULL, 0.0, 0, es);
1652  }
1653  }
1654 
1655  /* in text format, first line ends here */
1656  if (es->format == EXPLAIN_FORMAT_TEXT)
1657  appendStringInfoChar(es->str, '\n');
1658 
1659  /* prepare per-worker general execution details */
1660  if (es->workers_state && es->verbose)
1661  {
1662  WorkerInstrumentation *w = planstate->worker_instrument;
1663 
1664  for (int n = 0; n < w->num_workers; n++)
1665  {
1666  Instrumentation *instrument = &w->instrument[n];
1667  double nloops = instrument->nloops;
1668  double startup_ms;
1669  double total_ms;
1670  double rows;
1671 
1672  if (nloops <= 0)
1673  continue;
1674  startup_ms = 1000.0 * instrument->startup / nloops;
1675  total_ms = 1000.0 * instrument->total / nloops;
1676  rows = instrument->ntuples / nloops;
1677 
1678  ExplainOpenWorker(n, es);
1679 
1680  if (es->format == EXPLAIN_FORMAT_TEXT)
1681  {
1682  ExplainIndentText(es);
1683  if (es->timing)
1684  appendStringInfo(es->str,
1685  "actual time=%.3f..%.3f rows=%.0f loops=%.0f\n",
1686  startup_ms, total_ms, rows, nloops);
1687  else
1688  appendStringInfo(es->str,
1689  "actual rows=%.0f loops=%.0f\n",
1690  rows, nloops);
1691  }
1692  else
1693  {
1694  if (es->timing)
1695  {
1696  ExplainPropertyFloat("Actual Startup Time", "ms",
1697  startup_ms, 3, es);
1698  ExplainPropertyFloat("Actual Total Time", "ms",
1699  total_ms, 3, es);
1700  }
1701  ExplainPropertyFloat("Actual Rows", NULL, rows, 0, es);
1702  ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es);
1703  }
1704 
1705  ExplainCloseWorker(n, es);
1706  }
1707  }
1708 
1709  /* target list */
1710  if (es->verbose)
1711  show_plan_tlist(planstate, ancestors, es);
1712 
1713  /* unique join */
1714  switch (nodeTag(plan))
1715  {
1716  case T_NestLoop:
1717  case T_MergeJoin:
1718  case T_HashJoin:
1719  /* try not to be too chatty about this in text mode */
1720  if (es->format != EXPLAIN_FORMAT_TEXT ||
1721  (es->verbose && ((Join *) plan)->inner_unique))
1722  ExplainPropertyBool("Inner Unique",
1723  ((Join *) plan)->inner_unique,
1724  es);
1725  break;
1726  default:
1727  break;
1728  }
1729 
1730  /* quals, sort keys, etc */
1731  switch (nodeTag(plan))
1732  {
1733  case T_IndexScan:
1734  show_scan_qual(((IndexScan *) plan)->indexqualorig,
1735  "Index Cond", planstate, ancestors, es);
1736  if (((IndexScan *) plan)->indexqualorig)
1737  show_instrumentation_count("Rows Removed by Index Recheck", 2,
1738  planstate, es);
1739  show_scan_qual(((IndexScan *) plan)->indexorderbyorig,
1740  "Order By", planstate, ancestors, es);
1741  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1742  if (plan->qual)
1743  show_instrumentation_count("Rows Removed by Filter", 1,
1744  planstate, es);
1745  break;
1746  case T_IndexOnlyScan:
1747  show_scan_qual(((IndexOnlyScan *) plan)->indexqual,
1748  "Index Cond", planstate, ancestors, es);
1749  if (((IndexOnlyScan *) plan)->indexqual)
1750  show_instrumentation_count("Rows Removed by Index Recheck", 2,
1751  planstate, es);
1752  show_scan_qual(((IndexOnlyScan *) plan)->indexorderby,
1753  "Order By", planstate, ancestors, es);
1754  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1755  if (plan->qual)
1756  show_instrumentation_count("Rows Removed by Filter", 1,
1757  planstate, es);
1758  if (es->analyze)
1759  ExplainPropertyFloat("Heap Fetches", NULL,
1760  planstate->instrument->ntuples2, 0, es);
1761  break;
1762  case T_BitmapIndexScan:
1763  show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig,
1764  "Index Cond", planstate, ancestors, es);
1765  break;
1766  case T_BitmapHeapScan:
1767  show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig,
1768  "Recheck Cond", planstate, ancestors, es);
1769  if (((BitmapHeapScan *) plan)->bitmapqualorig)
1770  show_instrumentation_count("Rows Removed by Index Recheck", 2,
1771  planstate, es);
1772  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1773  if (plan->qual)
1774  show_instrumentation_count("Rows Removed by Filter", 1,
1775  planstate, es);
1776  if (es->analyze)
1777  show_tidbitmap_info((BitmapHeapScanState *) planstate, es);
1778  break;
1779  case T_SampleScan:
1780  show_tablesample(((SampleScan *) plan)->tablesample,
1781  planstate, ancestors, es);
1782  /* fall through to print additional fields the same as SeqScan */
1783  /* FALLTHROUGH */
1784  case T_SeqScan:
1785  case T_ValuesScan:
1786  case T_CteScan:
1787  case T_NamedTuplestoreScan:
1788  case T_WorkTableScan:
1789  case T_SubqueryScan:
1790  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1791  if (plan->qual)
1792  show_instrumentation_count("Rows Removed by Filter", 1,
1793  planstate, es);
1794  break;
1795  case T_Gather:
1796  {
1797  Gather *gather = (Gather *) plan;
1798 
1799  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1800  if (plan->qual)
1801  show_instrumentation_count("Rows Removed by Filter", 1,
1802  planstate, es);
1803  ExplainPropertyInteger("Workers Planned", NULL,
1804  gather->num_workers, es);
1805 
1806  /* Show params evaluated at gather node */
1807  if (gather->initParam)
1808  show_eval_params(gather->initParam, es);
1809 
1810  if (es->analyze)
1811  {
1812  int nworkers;
1813 
1814  nworkers = ((GatherState *) planstate)->nworkers_launched;
1815  ExplainPropertyInteger("Workers Launched", NULL,
1816  nworkers, es);
1817  }
1818 
1819  if (gather->single_copy || es->format != EXPLAIN_FORMAT_TEXT)
1820  ExplainPropertyBool("Single Copy", gather->single_copy, es);
1821  }
1822  break;
1823  case T_GatherMerge:
1824  {
1825  GatherMerge *gm = (GatherMerge *) plan;
1826 
1827  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1828  if (plan->qual)
1829  show_instrumentation_count("Rows Removed by Filter", 1,
1830  planstate, es);
1831  ExplainPropertyInteger("Workers Planned", NULL,
1832  gm->num_workers, es);
1833 
1834  /* Show params evaluated at gather-merge node */
1835  if (gm->initParam)
1836  show_eval_params(gm->initParam, es);
1837 
1838  if (es->analyze)
1839  {
1840  int nworkers;
1841 
1842  nworkers = ((GatherMergeState *) planstate)->nworkers_launched;
1843  ExplainPropertyInteger("Workers Launched", NULL,
1844  nworkers, es);
1845  }
1846  }
1847  break;
1848  case T_FunctionScan:
1849  if (es->verbose)
1850  {
1851  List *fexprs = NIL;
1852  ListCell *lc;
1853 
1854  foreach(lc, ((FunctionScan *) plan)->functions)
1855  {
1856  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
1857 
1858  fexprs = lappend(fexprs, rtfunc->funcexpr);
1859  }
1860  /* We rely on show_expression to insert commas as needed */
1861  show_expression((Node *) fexprs,
1862  "Function Call", planstate, ancestors,
1863  es->verbose, es);
1864  }
1865  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1866  if (plan->qual)
1867  show_instrumentation_count("Rows Removed by Filter", 1,
1868  planstate, es);
1869  break;
1870  case T_TableFuncScan:
1871  if (es->verbose)
1872  {
1873  TableFunc *tablefunc = ((TableFuncScan *) plan)->tablefunc;
1874 
1875  show_expression((Node *) tablefunc,
1876  "Table Function Call", planstate, ancestors,
1877  es->verbose, es);
1878  }
1879  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1880  if (plan->qual)
1881  show_instrumentation_count("Rows Removed by Filter", 1,
1882  planstate, es);
1883  break;
1884  case T_TidScan:
1885  {
1886  /*
1887  * The tidquals list has OR semantics, so be sure to show it
1888  * as an OR condition.
1889  */
1890  List *tidquals = ((TidScan *) plan)->tidquals;
1891 
1892  if (list_length(tidquals) > 1)
1893  tidquals = list_make1(make_orclause(tidquals));
1894  show_scan_qual(tidquals, "TID Cond", planstate, ancestors, es);
1895  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1896  if (plan->qual)
1897  show_instrumentation_count("Rows Removed by Filter", 1,
1898  planstate, es);
1899  }
1900  break;
1901  case T_TidRangeScan:
1902  {
1903  /*
1904  * The tidrangequals list has AND semantics, so be sure to
1905  * show it as an AND condition.
1906  */
1907  List *tidquals = ((TidRangeScan *) plan)->tidrangequals;
1908 
1909  if (list_length(tidquals) > 1)
1910  tidquals = list_make1(make_andclause(tidquals));
1911  show_scan_qual(tidquals, "TID Cond", planstate, ancestors, es);
1912  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1913  if (plan->qual)
1914  show_instrumentation_count("Rows Removed by Filter", 1,
1915  planstate, es);
1916  }
1917  break;
1918  case T_ForeignScan:
1919  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1920  if (plan->qual)
1921  show_instrumentation_count("Rows Removed by Filter", 1,
1922  planstate, es);
1923  show_foreignscan_info((ForeignScanState *) planstate, es);
1924  break;
1925  case T_CustomScan:
1926  {
1927  CustomScanState *css = (CustomScanState *) planstate;
1928 
1929  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1930  if (plan->qual)
1931  show_instrumentation_count("Rows Removed by Filter", 1,
1932  planstate, es);
1933  if (css->methods->ExplainCustomScan)
1934  css->methods->ExplainCustomScan(css, ancestors, es);
1935  }
1936  break;
1937  case T_NestLoop:
1938  show_upper_qual(((NestLoop *) plan)->join.joinqual,
1939  "Join Filter", planstate, ancestors, es);
1940  if (((NestLoop *) plan)->join.joinqual)
1941  show_instrumentation_count("Rows Removed by Join Filter", 1,
1942  planstate, es);
1943  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
1944  if (plan->qual)
1945  show_instrumentation_count("Rows Removed by Filter", 2,
1946  planstate, es);
1947  break;
1948  case T_MergeJoin:
1949  show_upper_qual(((MergeJoin *) plan)->mergeclauses,
1950  "Merge Cond", planstate, ancestors, es);
1951  show_upper_qual(((MergeJoin *) plan)->join.joinqual,
1952  "Join Filter", planstate, ancestors, es);
1953  if (((MergeJoin *) plan)->join.joinqual)
1954  show_instrumentation_count("Rows Removed by Join Filter", 1,
1955  planstate, es);
1956  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
1957  if (plan->qual)
1958  show_instrumentation_count("Rows Removed by Filter", 2,
1959  planstate, es);
1960  break;
1961  case T_HashJoin:
1962  show_upper_qual(((HashJoin *) plan)->hashclauses,
1963  "Hash Cond", planstate, ancestors, es);
1964  show_upper_qual(((HashJoin *) plan)->join.joinqual,
1965  "Join Filter", planstate, ancestors, es);
1966  if (((HashJoin *) plan)->join.joinqual)
1967  show_instrumentation_count("Rows Removed by Join Filter", 1,
1968  planstate, es);
1969  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
1970  if (plan->qual)
1971  show_instrumentation_count("Rows Removed by Filter", 2,
1972  planstate, es);
1973  break;
1974  case T_Agg:
1975  show_agg_keys(castNode(AggState, planstate), ancestors, es);
1976  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
1977  show_hashagg_info((AggState *) planstate, es);
1978  if (plan->qual)
1979  show_instrumentation_count("Rows Removed by Filter", 1,
1980  planstate, es);
1981  break;
1982  case T_Group:
1983  show_group_keys(castNode(GroupState, planstate), ancestors, es);
1984  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
1985  if (plan->qual)
1986  show_instrumentation_count("Rows Removed by Filter", 1,
1987  planstate, es);
1988  break;
1989  case T_Sort:
1990  show_sort_keys(castNode(SortState, planstate), ancestors, es);
1991  show_sort_info(castNode(SortState, planstate), es);
1992  break;
1993  case T_IncrementalSort:
1995  ancestors, es);
1997  es);
1998  break;
1999  case T_MergeAppend:
2001  ancestors, es);
2002  break;
2003  case T_Result:
2004  show_upper_qual((List *) ((Result *) plan)->resconstantqual,
2005  "One-Time Filter", planstate, ancestors, es);
2006  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
2007  if (plan->qual)
2008  show_instrumentation_count("Rows Removed by Filter", 1,
2009  planstate, es);
2010  break;
2011  case T_ModifyTable:
2012  show_modifytable_info(castNode(ModifyTableState, planstate), ancestors,
2013  es);
2014  break;
2015  case T_Hash:
2016  show_hash_info(castNode(HashState, planstate), es);
2017  break;
2018  case T_Memoize:
2019  show_memoize_info(castNode(MemoizeState, planstate), ancestors,
2020  es);
2021  break;
2022  default:
2023  break;
2024  }
2025 
2026  /*
2027  * Prepare per-worker JIT instrumentation. As with the overall JIT
2028  * summary, this is printed only if printing costs is enabled.
2029  */
2030  if (es->workers_state && es->costs && es->verbose)
2031  {
2033 
2034  if (w)
2035  {
2036  for (int n = 0; n < w->num_workers; n++)
2037  {
2038  ExplainOpenWorker(n, es);
2039  ExplainPrintJIT(es, planstate->state->es_jit_flags,
2040  &w->jit_instr[n]);
2041  ExplainCloseWorker(n, es);
2042  }
2043  }
2044  }
2045 
2046  /* Show buffer/WAL usage */
2047  if (es->buffers && planstate->instrument)
2048  show_buffer_usage(es, &planstate->instrument->bufusage, false);
2049  if (es->wal && planstate->instrument)
2050  show_wal_usage(es, &planstate->instrument->walusage);
2051 
2052  /* Prepare per-worker buffer/WAL usage */
2053  if (es->workers_state && (es->buffers || es->wal) && es->verbose)
2054  {
2055  WorkerInstrumentation *w = planstate->worker_instrument;
2056 
2057  for (int n = 0; n < w->num_workers; n++)
2058  {
2059  Instrumentation *instrument = &w->instrument[n];
2060  double nloops = instrument->nloops;
2061 
2062  if (nloops <= 0)
2063  continue;
2064 
2065  ExplainOpenWorker(n, es);
2066  if (es->buffers)
2067  show_buffer_usage(es, &instrument->bufusage, false);
2068  if (es->wal)
2069  show_wal_usage(es, &instrument->walusage);
2070  ExplainCloseWorker(n, es);
2071  }
2072  }
2073 
2074  /* Show per-worker details for this plan node, then pop that stack */
2075  if (es->workers_state)
2077  es->workers_state = save_workers_state;
2078 
2079  /*
2080  * If partition pruning was done during executor initialization, the
2081  * number of child plans we'll display below will be less than the number
2082  * of subplans that was specified in the plan. To make this a bit less
2083  * mysterious, emit an indication that this happened. Note that this
2084  * field is emitted now because we want it to be a property of the parent
2085  * node; it *cannot* be emitted within the Plans sub-node we'll open next.
2086  */
2087  switch (nodeTag(plan))
2088  {
2089  case T_Append:
2090  ExplainMissingMembers(((AppendState *) planstate)->as_nplans,
2091  list_length(((Append *) plan)->appendplans),
2092  es);
2093  break;
2094  case T_MergeAppend:
2095  ExplainMissingMembers(((MergeAppendState *) planstate)->ms_nplans,
2096  list_length(((MergeAppend *) plan)->mergeplans),
2097  es);
2098  break;
2099  default:
2100  break;
2101  }
2102 
2103  /* Get ready to display the child plans */
2104  haschildren = planstate->initPlan ||
2105  outerPlanState(planstate) ||
2106  innerPlanState(planstate) ||
2107  IsA(plan, Append) ||
2108  IsA(plan, MergeAppend) ||
2109  IsA(plan, BitmapAnd) ||
2110  IsA(plan, BitmapOr) ||
2111  IsA(plan, SubqueryScan) ||
2112  (IsA(planstate, CustomScanState) &&
2113  ((CustomScanState *) planstate)->custom_ps != NIL) ||
2114  planstate->subPlan;
2115  if (haschildren)
2116  {
2117  ExplainOpenGroup("Plans", "Plans", false, es);
2118  /* Pass current Plan as head of ancestors list for children */
2119  ancestors = lcons(plan, ancestors);
2120  }
2121 
2122  /* initPlan-s */
2123  if (planstate->initPlan)
2124  ExplainSubPlans(planstate->initPlan, ancestors, "InitPlan", es);
2125 
2126  /* lefttree */
2127  if (outerPlanState(planstate))
2128  ExplainNode(outerPlanState(planstate), ancestors,
2129  "Outer", NULL, es);
2130 
2131  /* righttree */
2132  if (innerPlanState(planstate))
2133  ExplainNode(innerPlanState(planstate), ancestors,
2134  "Inner", NULL, es);
2135 
2136  /* special child plans */
2137  switch (nodeTag(plan))
2138  {
2139  case T_Append:
2140  ExplainMemberNodes(((AppendState *) planstate)->appendplans,
2141  ((AppendState *) planstate)->as_nplans,
2142  ancestors, es);
2143  break;
2144  case T_MergeAppend:
2145  ExplainMemberNodes(((MergeAppendState *) planstate)->mergeplans,
2146  ((MergeAppendState *) planstate)->ms_nplans,
2147  ancestors, es);
2148  break;
2149  case T_BitmapAnd:
2150  ExplainMemberNodes(((BitmapAndState *) planstate)->bitmapplans,
2151  ((BitmapAndState *) planstate)->nplans,
2152  ancestors, es);
2153  break;
2154  case T_BitmapOr:
2155  ExplainMemberNodes(((BitmapOrState *) planstate)->bitmapplans,
2156  ((BitmapOrState *) planstate)->nplans,
2157  ancestors, es);
2158  break;
2159  case T_SubqueryScan:
2160  ExplainNode(((SubqueryScanState *) planstate)->subplan, ancestors,
2161  "Subquery", NULL, es);
2162  break;
2163  case T_CustomScan:
2164  ExplainCustomChildren((CustomScanState *) planstate,
2165  ancestors, es);
2166  break;
2167  default:
2168  break;
2169  }
2170 
2171  /* subPlan-s */
2172  if (planstate->subPlan)
2173  ExplainSubPlans(planstate->subPlan, ancestors, "SubPlan", es);
2174 
2175  /* end of child plans */
2176  if (haschildren)
2177  {
2178  ancestors = list_delete_first(ancestors);
2179  ExplainCloseGroup("Plans", "Plans", false, es);
2180  }
2181 
2182  /* in text format, undo whatever indentation we added */
2183  if (es->format == EXPLAIN_FORMAT_TEXT)
2184  es->indent = save_indent;
2185 
2186  ExplainCloseGroup("Plan",
2187  relationship ? NULL : "Plan",
2188  true, es);
2189 }
#define NIL
Definition: pg_list.h:65
static ExplainWorkersState * ExplainCreateWorkersState(int num_workers)
Definition: explain.c:4103
static void show_memoize_info(MemoizeState *mstate, List *ancestors, ExplainState *es)
Definition: explain.c:3093
Definition: nodes.h:81
void ExplainPropertyBool(const char *qlabel, bool value, ExplainState *es)
Definition: explain.c:4474
ScanDirection indexorderdir
Definition: plannodes.h:413
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
Bitmapset * initParam
Definition: plannodes.h:954
WorkerInstrumentation * worker_instrument
Definition: execnodes.h:977
WalUsage walusage
Definition: instrument.h:88
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:4433
Definition: nodes.h:83
bool hide_workers
Definition: explain.h:59
Instrumentation * instrument
Definition: execnodes.h:976
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:11374
static void show_modifytable_info(ModifyTableState *mtstate, List *ancestors, ExplainState *es)
Definition: explain.c:3846
#define castNode(_type_, nodeptr)
Definition: nodes.h:605
void ExplainPropertyFloat(const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
Definition: explain.c:4460
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
double startup
Definition: instrument.h:80
Definition: nodes.h:536
Definition: nodes.h:49
static void show_incremental_sort_info(IncrementalSortState *incrsortstate, ExplainState *es)
Definition: explain.c:2916
static void ExplainOpenWorker(int n, ExplainState *es)
Definition: explain.c:4120
static void ExplainCloseWorker(int n, ExplainState *es)
Definition: explain.c:4182
static void ExplainPrintJIT(ExplainState *es, int jit_flags, JitInstrumentation *ji)
Definition: explain.c:869
Definition: nodes.h:78
EState * state
Definition: execnodes.h:968
Expr * make_orclause(List *orclauses)
Definition: makefuncs.c:652
bool costs
Definition: explain.h:43
JitInstrumentation jit_instr[FLEXIBLE_ARRAY_MEMBER]
Definition: jit.h:51
static void show_scan_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:2297
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:799
bool analyze
Definition: explain.h:42
static void show_sort_info(SortState *sortstate, ExplainState *es)
Definition: explain.c:2711
Oid indexid
Definition: plannodes.h:407
static void show_upper_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:2311
static void show_instrumentation_count(const char *qlabel, int which, PlanState *planstate, ExplainState *es)
Definition: explain.c:3386
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:140
const struct CustomExecMethods * methods
Definition: execnodes.h:1888
#define list_make1(x1)
Definition: pg_list.h:206
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:4424
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1139
AggStrategy aggstrategy
Definition: plannodes.h:863
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
Definition: nodes.h:46
bool single_copy
Definition: plannodes.h:933
Definition: nodes.h:80
#define outerPlanState(node)
Definition: execnodes.h:1062
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
Expr * make_andclause(List *andclauses)
Definition: makefuncs.c:636
int es_jit_flags
Definition: execnodes.h:645
static void show_tablesample(TableSampleClause *tsc, PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:2645
ScanDirection indexorderdir
Definition: plannodes.h:440
double ntuples
Definition: instrument.h:82
int indent
Definition: explain.h:51
static void show_wal_usage(ExplainState *es, const WalUsage *usage)
Definition: explain.c:3624
static void show_tidbitmap_info(BitmapHeapScanState *planstate, ExplainState *es)
Definition: explain.c:3356
static void ExplainModifyTarget(ModifyTable *plan, ExplainState *es)
Definition: explain.c:3714
static void ExplainMissingMembers(int nplans, int nchildren, ExplainState *es)
Definition: explain.c:4024
static void ExplainIndexScanDetails(Oid indexid, ScanDirection indexorderdir, ExplainState *es)
Definition: explain.c:3662
static void show_group_keys(GroupState *gstate, List *ancestors, ExplainState *es)
Definition: explain.c:2505
struct SharedJitInstrumentation * worker_jit_instrument
Definition: execnodes.h:980
static void show_plan_tlist(PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:2195
List * lappend(List *list, void *datum)
Definition: list.c:336
bool timing
Definition: explain.h:46
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
Instrumentation instrument[FLEXIBLE_ARRAY_MEMBER]
Definition: instrument.h:94
bool verbose
Definition: explain.h:41
BufferUsage bufusage
Definition: instrument.h:87
static void ExplainCustomChildren(CustomScanState *css, List *ancestors, ExplainState *es)
Definition: explain.c:4081
Definition: nodes.h:86
Plan * plan
Definition: execnodes.h:966
int num_workers
Definition: plannodes.h:931
void(* ExplainCustomScan)(CustomScanState *node, List *ancestors, ExplainState *es)
Definition: extensible.h:153
static void show_merge_append_keys(MergeAppendState *mstate, List *ancestors, ExplainState *es)
Definition: explain.c:2357
static void ExplainIndentText(ExplainState *es)
Definition: explain.c:4861
List * lcons(void *datum, List *list)
Definition: list.c:468
#define lfirst(lc)
Definition: pg_list.h:169
AggSplit aggsplit
Definition: plannodes.h:864
static void ExplainSubPlans(List *plans, List *ancestors, const char *relationship, ExplainState *es)
Definition: explain.c:4038
bool wal
Definition: explain.h:45
static void show_hash_info(HashState *hashstate, ExplainState *es)
Definition: explain.c:3002
ExplainWorkersState * workers_state
Definition: explain.h:61
static void show_eval_params(Bitmapset *bms_params, ExplainState *es)
Definition: explain.c:3436
static void show_sort_keys(SortState *sortstate, List *ancestors, ExplainState *es)
Definition: explain.c:2325
static int list_length(const List *l)
Definition: pg_list.h:149
ExplainFormat format
Definition: explain.h:49
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:800
static const struct fns functions
Definition: regcomp.c:313
static const char * explain_get_index_name(Oid indexId)
Definition: explain.c:3466
double ntuples2
Definition: instrument.h:83
#define nodeTag(nodeptr)
Definition: nodes.h:541
static void show_expression(Node *node, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
Definition: explain.c:2253
Bitmapset * initParam
Definition: plannodes.h:935
static void show_incremental_sort_keys(IncrementalSortState *incrsortstate, List *ancestors, ExplainState *es)
Definition: explain.c:2340
static void show_buffer_usage(ExplainState *es, const BufferUsage *usage, bool planning)
Definition: explain.c:3488
Definition: nodes.h:87
int num_workers
Definition: plannodes.h:946
static void ExplainFlushWorkersState(ExplainState *es)
Definition: explain.c:4218
Definition: nodes.h:84
bool buffers
Definition: explain.h:44
static void show_foreignscan_info(ForeignScanState *fsstate, ExplainState *es)
Definition: explain.c:3415
static void ExplainScanTarget(Scan *plan, ExplainState *es)
Definition: explain.c:3701
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4552
Definition: plannodes.h:860
#define innerPlanState(node)
Definition: execnodes.h:1061
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4489
Definition: pg_list.h:50
StringInfo str
Definition: explain.h:39
static void show_agg_keys(AggState *astate, List *ancestors, ExplainState *es)
Definition: explain.c:2373
static void ExplainMemberNodes(PlanState **planstates, int nplans, List *ancestors, ExplainState *es)
Definition: explain.c:4006
List * list_delete_first(List *list)
Definition: list.c:875
static void show_hashagg_info(AggState *hashstate, ExplainState *es)
Definition: explain.c:3234
Definition: nodes.h:89

◆ ExplainOnePlan()

void ExplainOnePlan ( PlannedStmt plannedstmt,
IntoClause into,
ExplainState es,
const char *  queryString,
ParamListInfo  params,
QueryEnvironment queryEnv,
const instr_time planduration,
const BufferUsage bufusage 
)

Definition at line 518 of file explain.c.

References ExplainState::analyze, Assert, ExplainState::buffers, CMD_UTILITY, CommandCounterIncrement(), PlannedStmt::commandType, ExplainState::costs, CreateIntoRelDestReceiver(), CreateQueryDesc(), generate_unaccent_rules::dest, elapsed_time(), EXEC_FLAG_EXPLAIN_ONLY, ExecutorEnd(), ExecutorFinish(), ExecutorRun(), ExecutorStart(), ExplainCloseGroup(), ExplainOpenGroup(), ExplainPrintJITSummary(), ExplainPrintPlan(), ExplainPrintTriggers(), ExplainPropertyFloat(), ExplainPropertyInteger(), ForwardScanDirection, FreeQueryDesc(), GetActiveSnapshot(), GetIntoRelEFlags(), INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, INSTRUMENT_BUFFERS, INSTRUMENT_ROWS, INSTRUMENT_TIMER, INSTRUMENT_WAL, InvalidSnapshot, NoMovementScanDirection, None_Receiver, PopActiveSnapshot(), PushCopiedSnapshot(), PlannedStmt::queryId, show_buffer_usage(), IntoClause::skipData, ExplainState::summary, ExplainState::timing, UpdateActiveSnapshotCommandId(), ExplainState::verbose, and ExplainState::wal.

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

522 {
524  QueryDesc *queryDesc;
525  instr_time starttime;
526  double totaltime = 0;
527  int eflags;
528  int instrument_option = 0;
529 
530  Assert(plannedstmt->commandType != CMD_UTILITY);
531 
532  if (es->analyze && es->timing)
533  instrument_option |= INSTRUMENT_TIMER;
534  else if (es->analyze)
535  instrument_option |= INSTRUMENT_ROWS;
536 
537  if (es->buffers)
538  instrument_option |= INSTRUMENT_BUFFERS;
539  if (es->wal)
540  instrument_option |= INSTRUMENT_WAL;
541 
542  /*
543  * We always collect timing for the entire statement, even when node-level
544  * timing is off, so we don't look at es->timing here. (We could skip
545  * this if !es->summary, but it's hardly worth the complication.)
546  */
547  INSTR_TIME_SET_CURRENT(starttime);
548 
549  /*
550  * Use a snapshot with an updated command ID to ensure this query sees
551  * results of any previously executed queries.
552  */
555 
556  /*
557  * Normally we discard the query's output, but if explaining CREATE TABLE
558  * AS, we'd better use the appropriate tuple receiver.
559  */
560  if (into)
561  dest = CreateIntoRelDestReceiver(into);
562  else
563  dest = None_Receiver;
564 
565  /* Create a QueryDesc for the query */
566  queryDesc = CreateQueryDesc(plannedstmt, queryString,
568  dest, params, queryEnv, instrument_option);
569 
570  /* Select execution options */
571  if (es->analyze)
572  eflags = 0; /* default run-to-completion flags */
573  else
574  eflags = EXEC_FLAG_EXPLAIN_ONLY;
575  if (into)
576  eflags |= GetIntoRelEFlags(into);
577 
578  /* call ExecutorStart to prepare the plan for execution */
579  ExecutorStart(queryDesc, eflags);
580 
581  /* Execute the plan for statistics if asked for */
582  if (es->analyze)
583  {
584  ScanDirection dir;
585 
586  /* EXPLAIN ANALYZE CREATE TABLE AS WITH NO DATA is weird */
587  if (into && into->skipData)
589  else
590  dir = ForwardScanDirection;
591 
592  /* run the plan */
593  ExecutorRun(queryDesc, dir, 0L, true);
594 
595  /* run cleanup too */
596  ExecutorFinish(queryDesc);
597 
598  /* We can't run ExecutorEnd 'till we're done printing the stats... */
599  totaltime += elapsed_time(&starttime);
600  }
601 
602  ExplainOpenGroup("Query", NULL, true, es);
603 
604  /* Create textual dump of plan tree */
605  ExplainPrintPlan(es, queryDesc);
606 
607  if (es->verbose && plannedstmt->queryId != UINT64CONST(0))
608  {
609  /*
610  * Output the queryid as an int64 rather than a uint64 so we match
611  * what would be seen in the BIGINT pg_stat_statements.queryid column.
612  */
613  ExplainPropertyInteger("Query Identifier", NULL, (int64)
614  plannedstmt->queryId, es);
615  }
616 
617  /* Show buffer usage in planning */
618  if (bufusage)
619  {
620  ExplainOpenGroup("Planning", "Planning", true, es);
621  show_buffer_usage(es, bufusage, true);
622  ExplainCloseGroup("Planning", "Planning", true, es);
623  }
624 
625  if (es->summary && planduration)
626  {
627  double plantime = INSTR_TIME_GET_DOUBLE(*planduration);
628 
629  ExplainPropertyFloat("Planning Time", "ms", 1000.0 * plantime, 3, es);
630  }
631 
632  /* Print info about runtime of triggers */
633  if (es->analyze)
634  ExplainPrintTriggers(es, queryDesc);
635 
636  /*
637  * Print info about JITing. Tied to es->costs because we don't want to
638  * display this in regression tests, as it'd cause output differences
639  * depending on build options. Might want to separate that out from COSTS
640  * at a later stage.
641  */
642  if (es->costs)
643  ExplainPrintJITSummary(es, queryDesc);
644 
645  /*
646  * Close down the query and free resources. Include time for this in the
647  * total execution time (although it should be pretty minimal).
648  */
649  INSTR_TIME_SET_CURRENT(starttime);
650 
651  ExecutorEnd(queryDesc);
652 
653  FreeQueryDesc(queryDesc);
654 
656 
657  /* We need a CCI just in case query expanded to multiple plans */
658  if (es->analyze)
660 
661  totaltime += elapsed_time(&starttime);
662 
663  /*
664  * We only report execution time if we actually ran the query (that is,
665  * the user specified ANALYZE), and if summary reporting is enabled (the
666  * user can set SUMMARY OFF to not have the timing information included in
667  * the output). By default, ANALYZE sets SUMMARY to true.
668  */
669  if (es->summary && es->analyze)
670  ExplainPropertyFloat("Execution Time", "ms", 1000.0 * totaltime, 3,
671  es);
672 
673  ExplainCloseGroup("Query", NULL, true, es);
674 }
bool summary
Definition: explain.h:47
void UpdateActiveSnapshotCommandId(void)
Definition: snapmgr.c:728
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:4433
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
void ExplainPropertyFloat(const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
Definition: explain.c:4460
struct timeval instr_time
Definition: instr_time.h:150
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:130
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:786
void PopActiveSnapshot(void)
Definition: snapmgr.c:759
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:199
bool skipData
Definition: primnodes.h:119
bool costs
Definition: explain.h:43
DestReceiver * None_Receiver
Definition: dest.c:96
bool analyze
Definition: explain.h:42
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:459
int GetIntoRelEFlags(IntoClause *intoClause)
Definition: createas.c:375
void ExplainPrintTriggers(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:800
void ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:751
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:298
void PushCopiedSnapshot(Snapshot snapshot)
Definition: snapmgr.c:716
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:428
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:399
bool timing
Definition: explain.h:46
#define InvalidSnapshot
Definition: snapshot.h:123
void CommandCounterIncrement(void)
Definition: xact.c:1021
CmdType commandType
Definition: plannodes.h:46
bool verbose
Definition: explain.h:41
#define Assert(condition)
Definition: c.h:804
bool wal
Definition: explain.h:45
static double elapsed_time(instr_time *starttime)
Definition: explain.c:1045
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
static void show_buffer_usage(ExplainState *es, const BufferUsage *usage, bool planning)
Definition: explain.c:3488
uint64 queryId
Definition: plannodes.h:48
bool buffers
Definition: explain.h:44
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4552
void ExplainPrintJITSummary(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:843
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4489
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:56

◆ ExplainOneQuery()

static void ExplainOneQuery ( Query query,
int  cursorOptions,
IntoClause into,
ExplainState es,
const char *  queryString,
ParamListInfo  params,
QueryEnvironment queryEnv 
)
static

Definition at line 367 of file explain.c.

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

Referenced by ExplainOneUtility(), and ExplainQuery().

371 {
372  /* planner will not cope with utility statements */
373  if (query->commandType == CMD_UTILITY)
374  {
375  ExplainOneUtility(query->utilityStmt, into, es, queryString, params,
376  queryEnv);
377  return;
378  }
379 
380  /* if an advisor plugin is present, let it manage things */
382  (*ExplainOneQuery_hook) (query, cursorOptions, into, es,
383  queryString, params, queryEnv);
384  else
385  {
386  PlannedStmt *plan;
387  instr_time planstart,
388  planduration;
389  BufferUsage bufusage_start,
390  bufusage;
391 
392  if (es->buffers)
393  bufusage_start = pgBufferUsage;
394  INSTR_TIME_SET_CURRENT(planstart);
395 
396  /* plan the query */
397  plan = pg_plan_query(query, queryString, cursorOptions, params);
398 
399  INSTR_TIME_SET_CURRENT(planduration);
400  INSTR_TIME_SUBTRACT(planduration, planstart);
401 
402  /* calc differences of buffer counters. */
403  if (es->buffers)
404  {
405  memset(&bufusage, 0, sizeof(BufferUsage));
406  BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
407  }
408 
409  /* run it (if needed) and produce output */
410  ExplainOnePlan(plan, into, es, queryString, params, queryEnv,
411  &planduration, (es->buffers ? &bufusage : NULL));
412  }
413 }
struct timeval instr_time
Definition: instr_time.h:150
Node * utilityStmt
Definition: parsenodes.h:128
void BufferUsageAccumDiff(BufferUsage *dst, const BufferUsage *add, const BufferUsage *sub)
Definition: instrument.c:244
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:170
ExplainOneQuery_hook_type ExplainOneQuery_hook
Definition: explain.c:45
CmdType commandType
Definition: parsenodes.h:120
void ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv, const instr_time *planduration, const BufferUsage *bufusage)
Definition: explain.c:518
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
PlannedStmt * pg_plan_query(Query *querytree, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:829
void ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: explain.c:428
BufferUsage pgBufferUsage
Definition: instrument.c:20

◆ ExplainOneUtility()

void ExplainOneUtility ( Node utilityStmt,
IntoClause into,
ExplainState es,
const char *  queryString,
ParamListInfo  params,
QueryEnvironment queryEnv 
)

Definition at line 428 of file explain.c.

References appendStringInfoString(), Assert, castNode, copyObject, CreateTableAsRelExists(), CURSOR_OPT_PARALLEL_OK, elog, ERROR, EXPLAIN_FORMAT_TEXT, ExplainDummyGroup(), ExplainExecuteQuery(), ExplainOneQuery(), ExplainState::format, CreateTableAsStmt::into, IsA, linitial_node, list_length(), OBJECT_MATVIEW, OBJECT_TABLE, CreateTableAsStmt::objtype, DeclareCursorStmt::options, DeclareCursorStmt::query, CreateTableAsStmt::query, QueryRewrite(), and ExplainState::str.

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

431 {
432  if (utilityStmt == NULL)
433  return;
434 
435  if (IsA(utilityStmt, CreateTableAsStmt))
436  {
437  /*
438  * We have to rewrite the contained SELECT and then pass it back to
439  * ExplainOneQuery. Copy to be safe in the EXPLAIN EXECUTE case.
440  */
441  CreateTableAsStmt *ctas = (CreateTableAsStmt *) utilityStmt;
442  List *rewritten;
443 
444  /*
445  * Check if the relation exists or not. This is done at this stage to
446  * avoid query planning or execution.
447  */
448  if (CreateTableAsRelExists(ctas))
449  {
450  if (ctas->objtype == OBJECT_TABLE)
451  ExplainDummyGroup("CREATE TABLE AS", NULL, es);
452  else if (ctas->objtype == OBJECT_MATVIEW)
453  ExplainDummyGroup("CREATE MATERIALIZED VIEW", NULL, es);
454  else
455  elog(ERROR, "unexpected object type: %d",
456  (int) ctas->objtype);
457  return;
458  }
459 
460  rewritten = QueryRewrite(castNode(Query, copyObject(ctas->query)));
461  Assert(list_length(rewritten) == 1);
462  ExplainOneQuery(linitial_node(Query, rewritten),
463  CURSOR_OPT_PARALLEL_OK, ctas->into, es,
464  queryString, params, queryEnv);
465  }
466  else if (IsA(utilityStmt, DeclareCursorStmt))
467  {
468  /*
469  * Likewise for DECLARE CURSOR.
470  *
471  * Notice that if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll
472  * actually run the query. This is different from pre-8.3 behavior
473  * but seems more useful than not running the query. No cursor will
474  * be created, however.
475  */
476  DeclareCursorStmt *dcs = (DeclareCursorStmt *) utilityStmt;
477  List *rewritten;
478 
479  rewritten = QueryRewrite(castNode(Query, copyObject(dcs->query)));
480  Assert(list_length(rewritten) == 1);
481  ExplainOneQuery(linitial_node(Query, rewritten),
482  dcs->options, NULL, es,
483  queryString, params, queryEnv);
484  }
485  else if (IsA(utilityStmt, ExecuteStmt))
486  ExplainExecuteQuery((ExecuteStmt *) utilityStmt, into, es,
487  queryString, params, queryEnv);
488  else if (IsA(utilityStmt, NotifyStmt))
489  {
490  if (es->format == EXPLAIN_FORMAT_TEXT)
491  appendStringInfoString(es->str, "NOTIFY\n");
492  else
493  ExplainDummyGroup("Notify", NULL, es);
494  }
495  else
496  {
497  if (es->format == EXPLAIN_FORMAT_TEXT)
499  "Utility statements have no plan structure\n");
500  else
501  ExplainDummyGroup("Utility Statement", NULL, es);
502  }
503 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
List * QueryRewrite(Query *parsetree)
#define castNode(_type_, nodeptr)
Definition: nodes.h:605
#define linitial_node(type, l)
Definition: pg_list.h:177
ObjectType objtype
Definition: parsenodes.h:3410
static void ExplainDummyGroup(const char *objtype, const char *labelname, ExplainState *es)
Definition: explain.c:4699
#define ERROR
Definition: elog.h:46
void ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: prepare.c:605
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
bool CreateTableAsRelExists(CreateTableAsStmt *ctas)
Definition: createas.c:393
static void ExplainOneQuery(Query *query, int cursorOptions, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: explain.c:367
IntoClause * into
Definition: parsenodes.h:3409
#define Assert(condition)
Definition: c.h:804
static int list_length(const List *l)
Definition: pg_list.h:149
ExplainFormat format
Definition: explain.h:49
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2828
#define elog(elevel,...)
Definition: elog.h:232
#define copyObject(obj)
Definition: nodes.h:652
Definition: pg_list.h:50
StringInfo str
Definition: explain.h:39

◆ ExplainOpenGroup()

void ExplainOpenGroup ( const char *  objtype,
const char *  labelname,
bool  labeled,
ExplainState es 
)

Definition at line 4489 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 ExplainFlushWorkersState(), ExplainNode(), ExplainOnePlan(), ExplainPrintJIT(), ExplainPrintSettings(), ExplainPrintTriggers(), report_triggers(), show_grouping_set_keys(), show_grouping_sets(), show_incremental_sort_group_info(), and show_modifytable_info().

4491 {
4492  switch (es->format)
4493  {
4494  case EXPLAIN_FORMAT_TEXT:
4495  /* nothing to do */
4496  break;
4497 
4498  case EXPLAIN_FORMAT_XML:
4499  ExplainXMLTag(objtype, X_OPENING, es);
4500  es->indent++;
4501  break;
4502 
4503  case EXPLAIN_FORMAT_JSON:
4505  appendStringInfoSpaces(es->str, 2 * es->indent);
4506  if (labelname)
4507  {
4508  escape_json(es->str, labelname);
4509  appendStringInfoString(es->str, ": ");
4510  }
4511  appendStringInfoChar(es->str, labeled ? '{' : '[');
4512 
4513  /*
4514  * In JSON format, the grouping_stack is an integer list. 0 means
4515  * we've emitted nothing at this grouping level, 1 means we've
4516  * emitted something (and so the next item needs a comma). See
4517  * ExplainJSONLineEnding().
4518  */
4519  es->grouping_stack = lcons_int(0, es->grouping_stack);
4520  es->indent++;
4521  break;
4522 
4523  case EXPLAIN_FORMAT_YAML:
4524 
4525  /*
4526  * In YAML format, the grouping stack is an integer list. 0 means
4527  * we've emitted nothing at this grouping level AND this grouping
4528  * level is unlabeled and must be marked with "- ". See
4529  * ExplainYAMLLineStarting().
4530  */
4532  if (labelname)
4533  {
4534  appendStringInfo(es->str, "%s: ", labelname);
4535  es->grouping_stack = lcons_int(1, es->grouping_stack);
4536  }
4537  else
4538  {
4539  appendStringInfoString(es->str, "- ");
4540  es->grouping_stack = lcons_int(0, es->grouping_stack);
4541  }
4542  es->indent++;
4543  break;
4544  }
4545 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:1279
List * lcons_int(int datum, List *list)
Definition: list.c:486
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:4834
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:4896
List * grouping_stack
Definition: explain.h:52
int indent
Definition: explain.h:51
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:4876
#define X_OPENING
Definition: explain.c:52
ExplainFormat format
Definition: explain.h:49
StringInfo str
Definition: explain.h:39

◆ ExplainOpenSetAsideGroup()

static void ExplainOpenSetAsideGroup ( const char *  objtype,
const char *  labelname,
bool  labeled,
int  depth,
ExplainState es 
)
static

Definition at line 4599 of file explain.c.

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

Referenced by ExplainOpenWorker().

4601 {
4602  switch (es->format)
4603  {
4604  case EXPLAIN_FORMAT_TEXT:
4605  /* nothing to do */
4606  break;
4607 
4608  case EXPLAIN_FORMAT_XML:
4609  es->indent += depth;
4610  break;
4611 
4612  case EXPLAIN_FORMAT_JSON:
4613  es->grouping_stack = lcons_int(0, es->grouping_stack);
4614  es->indent += depth;
4615  break;
4616 
4617  case EXPLAIN_FORMAT_YAML:
4618  if (labelname)
4619  es->grouping_stack = lcons_int(1, es->grouping_stack);
4620  else
4621  es->grouping_stack = lcons_int(0, es->grouping_stack);
4622  es->indent += depth;
4623  break;
4624  }
4625 }
List * lcons_int(int datum, List *list)
Definition: list.c:486
List * grouping_stack
Definition: explain.h:52
int indent
Definition: explain.h:51
ExplainFormat format
Definition: explain.h:49

◆ ExplainOpenWorker()

static void ExplainOpenWorker ( int  n,
ExplainState es 
)
static

Definition at line 4120 of file explain.c.

References appendStringInfo(), Assert, EXPLAIN_FORMAT_TEXT, ExplainIndentText(), ExplainOpenSetAsideGroup(), ExplainPropertyInteger(), ExplainRestoreGroup(), ExplainState::format, ExplainState::indent, initStringInfo(), StringInfoData::len, ExplainWorkersState::prev_str, ExplainState::str, ExplainWorkersState::worker_inited, ExplainWorkersState::worker_state_save, ExplainWorkersState::worker_str, and ExplainState::workers_state.

Referenced by ExplainNode(), show_hashagg_info(), show_incremental_sort_info(), show_memoize_info(), and show_sort_info().

4121 {
4122  ExplainWorkersState *wstate = es->workers_state;
4123 
4124  Assert(wstate);
4125  Assert(n >= 0 && n < wstate->num_workers);
4126 
4127  /* Save prior output buffer pointer */
4128  wstate->prev_str = es->str;
4129 
4130  if (!wstate->worker_inited[n])
4131  {
4132  /* First time through, so create the buffer for this worker */
4133  initStringInfo(&wstate->worker_str[n]);
4134  es->str = &wstate->worker_str[n];
4135 
4136  /*
4137  * Push suitable initial formatting state for this worker's field
4138  * group. We allow one extra logical nesting level, since this group
4139  * will eventually be wrapped in an outer "Workers" group.
4140  */
4141  ExplainOpenSetAsideGroup("Worker", NULL, true, 2, es);
4142 
4143  /*
4144  * In non-TEXT formats we always emit a "Worker Number" field, even if
4145  * there's no other data for this worker.
4146  */
4147  if (es->format != EXPLAIN_FORMAT_TEXT)
4148  ExplainPropertyInteger("Worker Number", NULL, n, es);
4149 
4150  wstate->worker_inited[n] = true;
4151  }
4152  else
4153  {
4154  /* Resuming output for a worker we've already emitted some data for */
4155  es->str = &wstate->worker_str[n];
4156 
4157  /* Restore formatting state saved by last ExplainCloseWorker() */
4158  ExplainRestoreGroup(es, 2, &wstate->worker_state_save[n]);
4159  }
4160 
4161  /*
4162  * In TEXT format, prefix the first output line for this worker with
4163  * "Worker N:". Then, any additional lines should be indented one more
4164  * stop than the "Worker N" line is.
4165  */
4166  if (es->format == EXPLAIN_FORMAT_TEXT)
4167  {
4168  if (es->str->len == 0)
4169  {
4170  ExplainIndentText(es);
4171  appendStringInfo(es->str, "Worker %d: ", n);
4172  }
4173 
4174  es->indent++;
4175  }
4176 }
int * worker_state_save
Definition: explain.h:33
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:4433
static void ExplainRestoreGroup(ExplainState *es, int depth, int *state_save)
Definition: explain.c:4668
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
StringInfoData * worker_str
Definition: explain.h:32
int indent
Definition: explain.h:51
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
bool * worker_inited
Definition: explain.h:31
static void ExplainIndentText(ExplainState *es)
Definition: explain.c:4861
#define Assert(condition)
Definition: c.h:804
ExplainWorkersState * workers_state
Definition: explain.h:61
ExplainFormat format
Definition: explain.h:49
StringInfo prev_str
Definition: explain.h:34
StringInfo str
Definition: explain.h:39
static void ExplainOpenSetAsideGroup(const char *objtype, const char *labelname, bool labeled, int depth, ExplainState *es)
Definition: explain.c:4599

◆ ExplainPreScanNode()

static bool ExplainPreScanNode ( PlanState planstate,
Bitmapset **  rels_used 
)
static

Definition at line 1064 of file explain.c.

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

Referenced by ExplainPrintPlan().

1065 {
1066  Plan *plan = planstate->plan;
1067 
1068  switch (nodeTag(plan))
1069  {
1070  case T_SeqScan:
1071  case T_SampleScan:
1072  case T_IndexScan:
1073  case T_IndexOnlyScan:
1074  case T_BitmapHeapScan:
1075  case T_TidScan:
1076  case T_TidRangeScan:
1077  case T_SubqueryScan:
1078  case T_FunctionScan:
1079  case T_TableFuncScan:
1080  case T_ValuesScan:
1081  case T_CteScan:
1082  case T_NamedTuplestoreScan:
1083  case T_WorkTableScan:
1084  *rels_used = bms_add_member(*rels_used,
1085  ((Scan *) plan)->scanrelid);
1086  break;
1087  case T_ForeignScan:
1088  *rels_used = bms_add_members(*rels_used,
1089  ((ForeignScan *) plan)->fs_relids);
1090  break;
1091  case T_CustomScan:
1092  *rels_used = bms_add_members(*rels_used,
1093  ((CustomScan *) plan)->custom_relids);
1094  break;
1095  case T_ModifyTable:
1096  *rels_used = bms_add_member(*rels_used,
1097  ((ModifyTable *) plan)->nominalRelation);
1098  if (((ModifyTable *) plan)->exclRelRTI)
1099  *rels_used = bms_add_member(*rels_used,
1100  ((ModifyTable *) plan)->exclRelRTI);
1101  break;
1102  case T_Append:
1103  *rels_used = bms_add_members(*rels_used,
1104  ((Append *) plan)->apprelids);
1105  break;
1106  case T_MergeAppend:
1107  *rels_used = bms_add_members(*rels_used,
1108  ((MergeAppend *) plan)->apprelids);
1109  break;
1110  default:
1111  break;
1112  }
1113 
1114  return planstate_tree_walker(planstate, ExplainPreScanNode, rels_used);
1115 }
Definition: nodes.h:49
Plan * plan
Definition: execnodes.h:966
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define nodeTag(nodeptr)
Definition: nodes.h:541
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
Definition: explain.c:1064
bool planstate_tree_walker(PlanState *planstate, bool(*walker)(), void *context)
Definition: nodeFuncs.c:3992
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793

◆ ExplainPrintJIT()

static void ExplainPrintJIT ( ExplainState es,
int  jit_flags,
JitInstrumentation ji 
)
static

Definition at line 869 of file explain.c.

References ExplainState::analyze, appendStringInfo(), appendStringInfoString(), JitInstrumentation::created_functions, JitInstrumentation::emission_counter, EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), ExplainIndentText(), ExplainOpenGroup(), ExplainPropertyBool(), ExplainPropertyFloat(), ExplainPropertyInteger(), ExplainState::format, JitInstrumentation::generation_counter, ExplainState::indent, JitInstrumentation::inlining_counter, INSTR_TIME_ADD, INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_ZERO, JitInstrumentation::optimization_counter, PGJIT_DEFORM, PGJIT_EXPR, PGJIT_INLINE, PGJIT_OPT3, ExplainState::str, and ExplainState::timing.

Referenced by ExplainNode(), and ExplainPrintJITSummary().

870 {
871  instr_time total_time;
872 
873  /* don't print information if no JITing happened */
874  if (!ji || ji->created_functions == 0)
875  return;
876 
877  /* calculate total time */
878  INSTR_TIME_SET_ZERO(total_time);
879  INSTR_TIME_ADD(total_time, ji->generation_counter);
880  INSTR_TIME_ADD(total_time, ji->inlining_counter);
881  INSTR_TIME_ADD(total_time, ji->optimization_counter);
882  INSTR_TIME_ADD(total_time, ji->emission_counter);
883 
884  ExplainOpenGroup("JIT", "JIT", true, es);
885 
886  /* for higher density, open code the text output format */
887  if (es->format == EXPLAIN_FORMAT_TEXT)
888  {
889  ExplainIndentText(es);
890  appendStringInfoString(es->str, "JIT:\n");
891  es->indent++;
892 
893  ExplainPropertyInteger("Functions", NULL, ji->created_functions, es);
894 
895  ExplainIndentText(es);
896  appendStringInfo(es->str, "Options: %s %s, %s %s, %s %s, %s %s\n",
897  "Inlining", jit_flags & PGJIT_INLINE ? "true" : "false",
898  "Optimization", jit_flags & PGJIT_OPT3 ? "true" : "false",
899  "Expressions", jit_flags & PGJIT_EXPR ? "true" : "false",
900  "Deforming", jit_flags & PGJIT_DEFORM ? "true" : "false");
901 
902  if (es->analyze && es->timing)
903  {
904  ExplainIndentText(es);
905  appendStringInfo(es->str,
906  "Timing: %s %.3f ms, %s %.3f ms, %s %.3f ms, %s %.3f ms, %s %.3f ms\n",
907  "Generation", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->generation_counter),
908  "Inlining", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->inlining_counter),
909  "Optimization", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->optimization_counter),
910  "Emission", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->emission_counter),
911  "Total", 1000.0 * INSTR_TIME_GET_DOUBLE(total_time));
912  }
913 
914  es->indent--;
915  }
916  else
917  {
918  ExplainPropertyInteger("Functions", NULL, ji->created_functions, es);
919 
920  ExplainOpenGroup("Options", "Options", true, es);
921  ExplainPropertyBool("Inlining", jit_flags & PGJIT_INLINE, es);
922  ExplainPropertyBool("Optimization", jit_flags & PGJIT_OPT3, es);
923  ExplainPropertyBool("Expressions", jit_flags & PGJIT_EXPR, es);
924  ExplainPropertyBool("Deforming", jit_flags & PGJIT_DEFORM, es);
925  ExplainCloseGroup("Options", "Options", true, es);
926 
927  if (es->analyze && es->timing)
928  {
929  ExplainOpenGroup("Timing", "Timing", true, es);
930 
931  ExplainPropertyFloat("Generation", "ms",
933  3, es);
934  ExplainPropertyFloat("Inlining", "ms",
936  3, es);
937  ExplainPropertyFloat("Optimization", "ms",
939  3, es);
940  ExplainPropertyFloat("Emission", "ms",
942  3, es);
943  ExplainPropertyFloat("Total", "ms",
944  1000.0 * INSTR_TIME_GET_DOUBLE(total_time),
945  3, es);
946 
947  ExplainCloseGroup("Timing", "Timing", true, es);
948  }
949  }
950 
951  ExplainCloseGroup("JIT", "JIT", true, es);
952 }
void ExplainPropertyBool(const char *qlabel, bool value, ExplainState *es)
Definition: explain.c:4474
#define PGJIT_EXPR
Definition: jit.h:23
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:4433
instr_time generation_counter
Definition: jit.h:33
void ExplainPropertyFloat(const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
Definition: explain.c:4460
struct timeval instr_time
Definition: instr_time.h:150
#define INSTR_TIME_SET_ZERO(t)
Definition: instr_time.h:154
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:199
bool analyze
Definition: explain.h:42
#define PGJIT_OPT3
Definition: jit.h:21
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
size_t created_functions
Definition: jit.h:30
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
#define INSTR_TIME_ADD(x, y)
Definition: instr_time.h:158
instr_time optimization_counter
Definition: jit.h:39
int indent
Definition: explain.h:51
bool timing
Definition: explain.h:46
instr_time inlining_counter
Definition: jit.h:36
#define PGJIT_INLINE
Definition: jit.h:22
static void ExplainIndentText(ExplainState *es)
Definition: explain.c:4861
instr_time emission_counter
Definition: jit.h:42
ExplainFormat format
Definition: explain.h:49
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4552
#define PGJIT_DEFORM
Definition: jit.h:24
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4489
StringInfo str
Definition: explain.h:39

◆ ExplainPrintJITSummary()

void ExplainPrintJITSummary ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 843 of file explain.c.

References EState::es_jit, EState::es_jit_flags, EState::es_jit_worker_instr, QueryDesc::estate, ExplainPrintJIT(), JitContext::instr, InstrJitAgg(), and PGJIT_PERFORM.

Referenced by explain_ExecutorEnd(), and ExplainOnePlan().

844 {
845  JitInstrumentation ji = {0};
846 
847  if (!(queryDesc->estate->es_jit_flags & PGJIT_PERFORM))
848  return;
849 
850  /*
851  * Work with a copy instead of modifying the leader state, since this
852  * function may be called twice
853  */
854  if (queryDesc->estate->es_jit)
855  InstrJitAgg(&ji, &queryDesc->estate->es_jit->instr);
856 
857  /* If this process has done JIT in parallel workers, merge stats */
858  if (queryDesc->estate->es_jit_worker_instr)
859  InstrJitAgg(&ji, queryDesc->estate->es_jit_worker_instr);
860 
861  ExplainPrintJIT(es, queryDesc->estate->es_jit_flags, &ji);
862 }
EState * estate
Definition: execdesc.h:48
struct JitContext * es_jit
Definition: execnodes.h:646
struct JitInstrumentation * es_jit_worker_instr
Definition: execnodes.h:647
static void ExplainPrintJIT(ExplainState *es, int jit_flags, JitInstrumentation *ji)
Definition: explain.c:869
JitInstrumentation instr
Definition: jit.h:61
int es_jit_flags
Definition: execnodes.h:645
void InstrJitAgg(JitInstrumentation *dst, JitInstrumentation *add)
Definition: jit.c:184
#define PGJIT_PERFORM
Definition: jit.h:20

◆ ExplainPrintPlan()

void ExplainPrintPlan ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 751 of file explain.c.

References Assert, deparse_context_for_plan_tree(), ExplainState::deparse_cxt, ExplainNode(), ExplainPreScanNode(), ExplainPrintSettings(), ExplainState::hide_workers, 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().

752 {
753  Bitmapset *rels_used = NULL;
754  PlanState *ps;
755 
756  /* Set up ExplainState fields associated with this plan tree */
757  Assert(queryDesc->plannedstmt != NULL);
758  es->pstmt = queryDesc->plannedstmt;
759  es->rtable = queryDesc->plannedstmt->rtable;
760  ExplainPreScanNode(queryDesc->planstate, &rels_used);
763  es->rtable_names);
764  es->printed_subplans = NULL;
765 
766  /*
767  * Sometimes we mark a Gather node as "invisible", which means that it's
768  * not to be displayed in EXPLAIN output. The purpose of this is to allow
769  * running regression tests with force_parallel_mode=regress to get the
770  * same results as running the same tests with force_parallel_mode=off.
771  * Such marking is currently only supported on a Gather at the top of the
772  * plan. We skip that node, and we must also hide per-worker detail data
773  * further down in the plan tree.
774  */
775  ps = queryDesc->planstate;
776  if (IsA(ps, GatherState) && ((Gather *) ps->plan)->invisible)
777  {
778  ps = outerPlanState(ps);
779  es->hide_workers = true;
780  }
781  ExplainNode(ps, NIL, NULL, NULL, es);
782 
783  /*
784  * If requested, include information about GUC parameters with values that
785  * don't match the built-in defaults.
786  */
788 }
#define NIL
Definition: pg_list.h:65
static void ExplainPrintSettings(ExplainState *es)
Definition: explain.c:681
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
bool hide_workers
Definition: explain.h:59
Bitmapset * printed_subplans
Definition: explain.h:58
List * deparse_cxt
Definition: explain.h:57
PlannedStmt * pstmt
Definition: explain.h:54
List * rtable_names
Definition: explain.h:56
List * select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
Definition: ruleutils.c:3698
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1139
PlanState * planstate
Definition: execdesc.h:49
#define outerPlanState(node)
Definition: execnodes.h:1062
List * deparse_context_for_plan_tree(PlannedStmt *pstmt, List *rtable_names)
Definition: ruleutils.c:3606
Plan * plan
Definition: execnodes.h:966
#define Assert(condition)
Definition: c.h:804
List * rtable
Definition: plannodes.h:66
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
Definition: explain.c:1064
PlannedStmt * plannedstmt
Definition: execdesc.h:37
List * rtable
Definition: explain.h:55

◆ ExplainPrintSettings()

static void ExplainPrintSettings ( ExplainState es)
static

Definition at line 681 of file explain.c.

References appendStringInfo(), appendStringInfoString(), StringInfoData::data, EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), ExplainOpenGroup(), ExplainPropertyText(), ExplainState::format, get_explain_guc_options(), GetConfigOptionByName(), i, initStringInfo(), config_generic::name, ExplainState::settings, and generate_unaccent_rules::str.

Referenced by ExplainPrintPlan().

682 {
683  int num;
684  struct config_generic **gucs;
685 
686  /* bail out if information about settings not requested */
687  if (!es->settings)
688  return;
689 
690  /* request an array of relevant settings */
691  gucs = get_explain_guc_options(&num);
692 
693  if (es->format != EXPLAIN_FORMAT_TEXT)
694  {
695  ExplainOpenGroup("Settings", "Settings", true, es);
696 
697  for (int i = 0; i < num; i++)
698  {
699  char *setting;
700  struct config_generic *conf = gucs[i];
701 
702  setting = GetConfigOptionByName(conf->name, NULL, true);
703 
704  ExplainPropertyText(conf->name, setting, es);
705  }
706 
707  ExplainCloseGroup("Settings", "Settings", true, es);
708  }
709  else
710  {
712 
713  /* In TEXT mode, print nothing if there are no options */
714  if (num <= 0)
715  return;
716 
717  initStringInfo(&str);
718 
719  for (int i = 0; i < num; i++)
720  {
721  char *setting;
722  struct config_generic *conf = gucs[i];
723 
724  if (i > 0)
725  appendStringInfoString(&str, ", ");
726 
727  setting = GetConfigOptionByName(conf->name, NULL, true);
728 
729  if (setting)
730  appendStringInfo(&str, "%s = '%s'", conf->name, setting);
731  else
732  appendStringInfo(&str, "%s = NULL", conf->name);
733  }
734 
735  ExplainPropertyText("Settings", str.data, es);
736  }
737 }
const char * name
Definition: guc_tables.h:141
struct config_generic ** get_explain_guc_options(int *num)
Definition: guc.c:9481
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:4424
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
char * GetConfigOptionByName(const char *name, const char **varname, bool missing_ok)
Definition: guc.c:9574
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
ExplainFormat format
Definition: explain.h:49
int i
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4552
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4489
bool settings
Definition: explain.h:48

◆ ExplainPrintTriggers()

void ExplainPrintTriggers ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 800 of file explain.c.

References EState::es_opened_result_relations, EState::es_trig_target_relations, EState::es_tuple_routing_result_relations, QueryDesc::estate, ExplainCloseGroup(), ExplainOpenGroup(), lfirst, list_length(), NIL, and report_triggers().

Referenced by explain_ExecutorEnd(), and ExplainOnePlan().

801 {
802  ResultRelInfo *rInfo;
803  bool show_relname;
804  List *resultrels;
805  List *routerels;
806  List *targrels;
807  ListCell *l;
808 
809  resultrels = queryDesc->estate->es_opened_result_relations;
810  routerels = queryDesc->estate->es_tuple_routing_result_relations;
811  targrels = queryDesc->estate->es_trig_target_relations;
812 
813  ExplainOpenGroup("Triggers", "Triggers", false, es);
814 
815  show_relname = (list_length(resultrels) > 1 ||
816  routerels != NIL || targrels != NIL);
817  foreach(l, resultrels)
818  {
819  rInfo = (ResultRelInfo *) lfirst(l);
820  report_triggers(rInfo, show_relname, es);
821  }
822 
823  foreach(l, routerels)
824  {
825  rInfo = (ResultRelInfo *) lfirst(l);
826  report_triggers(rInfo, show_relname, es);
827  }
828 
829  foreach(l, targrels)
830  {
831  rInfo = (ResultRelInfo *) lfirst(l);
832  report_triggers(rInfo, show_relname, es);
833  }
834 
835  ExplainCloseGroup("Triggers", "Triggers", false, es);
836 }
#define NIL
Definition: pg_list.h:65
EState * estate
Definition: execdesc.h:48
List * es_opened_result_relations
Definition: execnodes.h:578
static void report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
Definition: explain.c:974
List * es_trig_target_relations
Definition: execnodes.h:591
List * es_tuple_routing_result_relations
Definition: execnodes.h:588
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4552
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4489
Definition: pg_list.h:50

◆ ExplainProperty()

static void ExplainProperty ( const char *  qlabel,
const char *  unit,
const char *  value,
bool  numeric,
ExplainState es 
)
static

Definition at line 4371 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, ExplainIndentText(), ExplainJSONLineEnding(), ExplainXMLTag(), ExplainYAMLLineStarting(), ExplainState::format, ExplainState::indent, pfree(), ExplainState::str, generate_unaccent_rules::str, X_CLOSING, X_NOWHITESPACE, and X_OPENING.

Referenced by ExplainPropertyBool(), ExplainPropertyFloat(), ExplainPropertyInteger(), ExplainPropertyText(), and ExplainPropertyUInteger().

4373 {
4374  switch (es->format)
4375  {
4376  case EXPLAIN_FORMAT_TEXT:
4377  ExplainIndentText(es);
4378  if (unit)
4379  appendStringInfo(es->str, "%s: %s %s\n", qlabel, value, unit);
4380  else
4381  appendStringInfo(es->str, "%s: %s\n", qlabel, value);
4382  break;
4383 
4384  case EXPLAIN_FORMAT_XML:
4385  {
4386  char *str;
4387 
4388  appendStringInfoSpaces(es->str, es->indent * 2);
4389  ExplainXMLTag(qlabel, X_OPENING | X_NOWHITESPACE, es);
4390  str = escape_xml(value);
4391  appendStringInfoString(es->str, str);
4392  pfree(str);
4393  ExplainXMLTag(qlabel, X_CLOSING | X_NOWHITESPACE, es);
4394  appendStringInfoChar(es->str, '\n');
4395  }
4396  break;
4397 
4398  case EXPLAIN_FORMAT_JSON:
4400  appendStringInfoSpaces(es->str, es->indent * 2);
4401  escape_json(es->str, qlabel);
4402  appendStringInfoString(es->str, ": ");
4403  if (numeric)
4405  else
4406  escape_json(es->str, value);
4407  break;
4408 
4409  case EXPLAIN_FORMAT_YAML:
4411  appendStringInfo(es->str, "%s: ", qlabel);
4412  if (numeric)
4414  else
4415  escape_yaml(es->str, value);
4416  break;
4417  }
4418 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:1279
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:4834
#define X_CLOSING
Definition: explain.c:53
void pfree(void *pointer)
Definition: mcxt.c:1169
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:4896
int indent
Definition: explain.h:51
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:4921
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:4876
static struct @143 value
#define X_OPENING
Definition: explain.c:52
static void ExplainIndentText(ExplainState *es)
Definition: explain.c:4861
#define X_NOWHITESPACE
Definition: explain.c:55
ExplainFormat format
Definition: explain.h:49
char * escape_xml(const char *str)
Definition: xml.c:2353
StringInfo str
Definition: explain.h:39

◆ ExplainPropertyBool()

void ExplainPropertyBool ( const char *  qlabel,
bool  value,
ExplainState es 
)

Definition at line 4474 of file explain.c.

References ExplainProperty().

Referenced by ExplainNode(), and ExplainPrintJIT().

4475 {
4476  ExplainProperty(qlabel, NULL, value ? "true" : "false", true, es);
4477 }
static struct @143 value
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:4371

◆ ExplainPropertyFloat()

void ExplainPropertyFloat ( const char *  qlabel,
const char *  unit,
double  value,
int  ndigits,
ExplainState es 
)

Definition at line 4460 of file explain.c.

References buf, ExplainProperty(), pfree(), and psprintf().

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

4462 {
4463  char *buf;
4464 
4465  buf = psprintf("%.*f", ndigits, value);
4466  ExplainProperty(qlabel, unit, buf, true, es);
4467  pfree(buf);
4468 }
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
void pfree(void *pointer)
Definition: mcxt.c:1169
static char * buf
Definition: pg_test_fsync.c:68
static struct @143 value
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:4371

◆ ExplainPropertyInteger()

void ExplainPropertyInteger ( const char *  qlabel,
const char *  unit,
int64  value,
ExplainState es 
)

Definition at line 4433 of file explain.c.

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

Referenced by ExplainMissingMembers(), ExplainNode(), ExplainOnePlan(), ExplainOpenWorker(), ExplainPrintJIT(), fileExplainForeignScan(), postgresExplainForeignModify(), show_buffer_usage(), show_hash_info(), show_hashagg_info(), show_incremental_sort_group_info(), show_memoize_info(), show_sort_info(), show_tidbitmap_info(), and show_wal_usage().

4435 {
4436  char buf[32];
4437 
4438  snprintf(buf, sizeof(buf), INT64_FORMAT, value);
4439  ExplainProperty(qlabel, unit, buf, true, es);
4440 }
static char * buf
Definition: pg_test_fsync.c:68
static struct @143 value
#define INT64_FORMAT
Definition: c.h:483
#define snprintf
Definition: port.h:216
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:4371

◆ ExplainPropertyList()

void ExplainPropertyList ( const char *  qlabel,
List data,
ExplainState es 
)

Definition at line 4248 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, ExplainIndentText(), ExplainJSONLineEnding(), ExplainXMLTag(), ExplainYAMLLineStarting(), ExplainState::format, ExplainState::indent, lfirst, pfree(), ExplainState::str, generate_unaccent_rules::str, X_CLOSING, and X_OPENING.

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

4249 {
4250  ListCell *lc;
4251  bool first = true;
4252 
4253  switch (es->format)
4254  {
4255  case EXPLAIN_FORMAT_TEXT:
4256  ExplainIndentText(es);
4257  appendStringInfo(es->str, "%s: ", qlabel);
4258  foreach(lc, data)
4259  {
4260  if (!first)
4261  appendStringInfoString(es->str, ", ");
4262  appendStringInfoString(es->str, (const char *) lfirst(lc));
4263  first = false;
4264  }
4265  appendStringInfoChar(es->str, '\n');
4266  break;
4267 
4268  case EXPLAIN_FORMAT_XML:
4269  ExplainXMLTag(qlabel, X_OPENING, es);
4270  foreach(lc, data)
4271  {
4272  char *str;
4273 
4274  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
4275  appendStringInfoString(es->str, "<Item>");
4276  str = escape_xml((const char *) lfirst(lc));
4277  appendStringInfoString(es->str, str);
4278  pfree(str);
4279  appendStringInfoString(es->str, "</Item>\n");
4280  }
4281  ExplainXMLTag(qlabel, X_CLOSING, es);
4282  break;
4283 
4284  case EXPLAIN_FORMAT_JSON:
4286  appendStringInfoSpaces(es->str, es->indent * 2);
4287  escape_json(es->str, qlabel);
4288  appendStringInfoString(es->str, ": [");
4289  foreach(lc, data)
4290  {
4291  if (!first)
4292  appendStringInfoString(es->str, ", ");
4293  escape_json(es->str, (const char *) lfirst(lc));
4294  first = false;
4295  }
4296  appendStringInfoChar(es->str, ']');
4297  break;
4298 
4299  case EXPLAIN_FORMAT_YAML:
4301  appendStringInfo(es->str, "%s: ", qlabel);
4302  foreach(lc, data)
4303  {
4304  appendStringInfoChar(es->str, '\n');
4305  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
4306  appendStringInfoString(es->str, "- ");
4307  escape_yaml(es->str, (const char *) lfirst(lc));
4308  }
4309  break;
4310  }
4311 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:1279
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:4834
#define X_CLOSING
Definition: explain.c:53
void pfree(void *pointer)
Definition: mcxt.c:1169
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:4896
int indent
Definition: explain.h:51
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:4921
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:4876
#define X_OPENING
Definition: explain.c:52
static void ExplainIndentText(ExplainState *es)
Definition: explain.c:4861
#define lfirst(lc)
Definition: pg_list.h:169
ExplainFormat format
Definition: explain.h:49
char * escape_xml(const char *str)
Definition: xml.c:2353
StringInfo str
Definition: explain.h:39

◆ ExplainPropertyListNested()

void ExplainPropertyListNested ( const char *  qlabel,
List data,
ExplainState es 
)

Definition at line 4318 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().

4319 {
4320  ListCell *lc;
4321  bool first = true;
4322 
4323  switch (es->format)
4324  {
4325  case EXPLAIN_FORMAT_TEXT:
4326  case EXPLAIN_FORMAT_XML:
4327  ExplainPropertyList(qlabel, data, es);
4328  return;
4329 
4330  case EXPLAIN_FORMAT_JSON:
4332  appendStringInfoSpaces(es->str, es->indent * 2);
4333  appendStringInfoChar(es->str, '[');
4334  foreach(lc, data)
4335  {
4336  if (!first)
4337  appendStringInfoString(es->str, ", ");
4338  escape_json(es->str, (const char *) lfirst(lc));
4339  first = false;
4340  }
4341  appendStringInfoChar(es->str, ']');
4342  break;
4343 
4344  case EXPLAIN_FORMAT_YAML:
4346  appendStringInfoString(es->str, "- [");
4347  foreach(lc, data)
4348  {
4349  if (!first)
4350  appendStringInfoString(es->str, ", ");
4351  escape_yaml(es->str, (const char *) lfirst(lc));
4352  first = false;
4353  }
4354  appendStringInfoChar(es->str, ']');
4355  break;
4356  }
4357 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:1279
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:4896
int indent
Definition: explain.h:51
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:4921
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:4876
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:4248
#define lfirst(lc)
Definition: pg_list.h:169
ExplainFormat format
Definition: explain.h:49
StringInfo str
Definition: explain.h:39

◆ ExplainPropertyText()

void ExplainPropertyText ( const char *  qlabel,
const char *  value,
ExplainState es 
)

Definition at line 4424 of file explain.c.

References ExplainProperty().

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

4425 {
4426  ExplainProperty(qlabel, NULL, value, false, es);
4427 }
static struct @143 value
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:4371

◆ ExplainPropertyUInteger()

void ExplainPropertyUInteger ( const char *  qlabel,
const char *  unit,
uint64  value,
ExplainState es 
)

Definition at line 4446 of file explain.c.

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

Referenced by show_wal_usage().

4448 {
4449  char buf[32];
4450 
4451  snprintf(buf, sizeof(buf), UINT64_FORMAT, value);
4452  ExplainProperty(qlabel, unit, buf, true, es);
4453 }
static char * buf
Definition: pg_test_fsync.c:68
static struct @143 value
#define snprintf
Definition: port.h:216
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:4371
#define UINT64_FORMAT
Definition: c.h:484

◆ ExplainQuery()

void ExplainQuery ( ParseState pstate,
ExplainStmt stmt,
ParamListInfo  params,
DestReceiver dest 
)

Definition at line 164 of file explain.c.

References ExplainState::analyze, appendStringInfoString(), Assert, begin_tup_output_tupdesc(), ExplainState::buffers, castNode, 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, IsQueryIdEnabled(), JumbleQuery(), lfirst, lfirst_node, lnext(), DefElem::location, NewExplainState(), NIL, ExplainStmt::options, ParseState::p_sourcetext, parser_errposition(), pfree(), post_parse_analyze_hook, ExplainStmt::query, QueryRewrite(), ExplainState::settings, ExplainState::str, ExplainState::summary, ExplainState::timing, TTSOpsVirtual, ExplainState::verbose, and ExplainState::wal.

Referenced by standard_ProcessUtility().

166 {
168  TupOutputState *tstate;
169  JumbleState *jstate = NULL;
170  Query *query;
171  List *rewritten;
172  ListCell *lc;
173  bool timing_set = false;
174  bool summary_set = false;
175 
176  /* Parse options list. */
177  foreach(lc, stmt->options)
178  {
179  DefElem *opt = (DefElem *) lfirst(lc);
180 
181  if (strcmp(opt->defname, "analyze") == 0)
182  es->analyze = defGetBoolean(opt);
183  else if (strcmp(opt->defname, "verbose") == 0)
184  es->verbose = defGetBoolean(opt);
185  else if (strcmp(opt->defname, "costs") == 0)
186  es->costs = defGetBoolean(opt);
187  else if (strcmp(opt->defname, "buffers") == 0)
188  es->buffers = defGetBoolean(opt);
189  else if (strcmp(opt->defname, "wal") == 0)
190  es->wal = defGetBoolean(opt);
191  else if (strcmp(opt->defname, "settings") == 0)
192  es->settings = defGetBoolean(opt);
193  else if (strcmp(opt->defname, "timing") == 0)
194  {
195  timing_set = true;
196  es->timing = defGetBoolean(opt);
197  }
198  else if (strcmp(opt->defname, "summary") == 0)
199  {
200  summary_set = true;
201  es->summary = defGetBoolean(opt);
202  }
203  else if (strcmp(opt->defname, "format") == 0)
204  {
205  char *p = defGetString(opt);
206 
207  if (strcmp(p, "text") == 0)
209  else if (strcmp(p, "xml") == 0)
211  else if (strcmp(p, "json") == 0)
213  else if (strcmp(p, "yaml") == 0)
215  else
216  ereport(ERROR,
217  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
218  errmsg("unrecognized value for EXPLAIN option \"%s\": \"%s\"",
219  opt->defname, p),
220  parser_errposition(pstate, opt->location)));
221  }
222  else
223  ereport(ERROR,
224  (errcode(ERRCODE_SYNTAX_ERROR),
225  errmsg("unrecognized EXPLAIN option \"%s\"",
226  opt->defname),
227  parser_errposition(pstate, opt->location)));
228  }
229 
230  if (es->wal && !es->analyze)
231  ereport(ERROR,
232  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
233  errmsg("EXPLAIN option WAL requires ANALYZE")));
234 
235  /* if the timing was not set explicitly, set default value */
236  es->timing = (timing_set) ? es->timing : es->analyze;
237 
238  /* check that timing is used with EXPLAIN ANALYZE */
239  if (es->timing && !es->analyze)
240  ereport(ERROR,
241  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
242  errmsg("EXPLAIN option TIMING requires ANALYZE")));
243 
244  /* if the summary was not set explicitly, set default value */
245  es->summary = (summary_set) ? es->summary : es->analyze;
246 
247  query = castNode(Query, stmt->query);
248  if (IsQueryIdEnabled())
249  jstate = JumbleQuery(query, pstate->p_sourcetext);
250 
252  (*post_parse_analyze_hook) (pstate, query, jstate);
253 
254  /*
255  * Parse analysis was done already, but we still have to run the rule
256  * rewriter. We do not do AcquireRewriteLocks: we assume the query either
257  * came straight from the parser, or suitable locks were acquired by
258  * plancache.c.
259  */
260  rewritten = QueryRewrite(castNode(Query, stmt->query));
261 
262  /* emit opening boilerplate */
263  ExplainBeginOutput(es);
264 
265  if (rewritten == NIL)
266  {
267  /*
268  * In the case of an INSTEAD NOTHING, tell at least that. But in
269  * non-text format, the output is delimited, so this isn't necessary.
270  */
271  if (es->format == EXPLAIN_FORMAT_TEXT)
272  appendStringInfoString(es->str, "Query rewrites to nothing\n");
273  }
274  else
275  {
276  ListCell *l;
277 
278  /* Explain every plan */
279  foreach(l, rewritten)
280  {
282  CURSOR_OPT_PARALLEL_OK, NULL, es,
283  pstate->p_sourcetext, params, pstate->p_queryEnv);
284 
285  /* Separate plans with an appropriate separator */
286  if (lnext(rewritten, l) != NULL)
288  }
289  }
290 
291  /* emit closing boilerplate */
292  ExplainEndOutput(es);
293  Assert(es->indent == 0);
294 
295  /* output tuples */
296  tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt),
297  &TTSOpsVirtual);
298  if (es->format == EXPLAIN_FORMAT_TEXT)
299  do_text_output_multiline(tstate, es->str->data);
300  else
301  do_text_output_oneline(tstate, es->str->data);
302  end_tup_output(tstate);
303 
304  pfree(es->str->data);
305 }
#define NIL
Definition: pg_list.h:65
bool summary
Definition: explain.h:47
ExplainState * NewExplainState(void)
Definition: explain.c:311
List * QueryRewrite(Query *parsetree)
static bool IsQueryIdEnabled(void)
Definition: queryjumble.h:78
void ExplainSeparatePlans(ExplainState *es)
Definition: explain.c:4805
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:322
#define castNode(_type_, nodeptr)
Definition: nodes.h:605
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
int errcode(int sqlerrcode)
Definition: elog.c:698
List * options
Definition: parsenodes.h:3389
bool costs
Definition: explain.h:43
bool analyze
Definition: explain.h:42
Node * query
Definition: parsenodes.h:3388
void ExplainEndOutput(ExplainState *es)
Definition: explain.c:4776
bool defGetBoolean(DefElem *def)
Definition: define.c:106
void pfree(void *pointer)
Definition: mcxt.c:1169
void end_tup_output(TupOutputState *tstate)
Definition: execTuples.c:2344
void ExplainBeginOutput(ExplainState *es)
Definition: explain.c:4745
#define ERROR
Definition: elog.h:46
TupleDesc ExplainResultDesc(ExplainStmt *stmt)
Definition: explain.c:328
char * defGetString(DefElem *def)
Definition: define.c:49
TupOutputState * begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:2266
#define lfirst_node(type, lc)
Definition: pg_list.h:172
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
int location
Definition: parsenodes.h:761
int indent
Definition: explain.h:51
const char * p_sourcetext
Definition: parse_node.h:181
bool timing
Definition: explain.h:46
static void ExplainOneQuery(Query *query, int cursorOptions, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: explain.c:367
void do_text_output_multiline(TupOutputState *tstate, const char *txt)
Definition: execTuples.c:2314
bool verbose
Definition: explain.h:41
#define ereport(elevel,...)
Definition: elog.h:157
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
bool wal
Definition: explain.h:45
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
ExplainFormat format
Definition: explain.h:49
#define do_text_output_oneline(tstate, str_to_emit)
Definition: executor.h:505
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2828
int errmsg(const char *fmt,...)
Definition: elog.c:909
bool buffers
Definition: explain.h:44
JumbleState * JumbleQuery(Query *query, const char *querytext)
Definition: queryjumble.c:101
char * defname
Definition: parsenodes.h:758
Definition: pg_list.h:50
StringInfo str
Definition: explain.h:39
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:58
bool settings
Definition: explain.h:48

◆ ExplainQueryText()

void ExplainQueryText ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 963 of file explain.c.

References ExplainPropertyText(), and QueryDesc::sourceText.

Referenced by explain_ExecutorEnd().

964 {
965  if (queryDesc->sourceText)
966  ExplainPropertyText("Query Text", queryDesc->sourceText, es);
967 }
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:4424
const char * sourceText
Definition: execdesc.h:38

◆ ExplainRestoreGroup()

static void ExplainRestoreGroup ( ExplainState es,
int  depth,
int *  state_save 
)
static

Definition at line 4668 of file explain.c.

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

Referenced by ExplainOpenWorker().

4669 {
4670  switch (es->format)
4671  {
4672  case EXPLAIN_FORMAT_TEXT:
4673  /* nothing to do */
4674  break;
4675 
4676  case EXPLAIN_FORMAT_XML:
4677  es->indent += depth;
4678  break;
4679 
4680  case EXPLAIN_FORMAT_JSON:
4681  es->grouping_stack = lcons_int(*state_save, es->grouping_stack);
4682  es->indent += depth;
4683  break;
4684 
4685  case EXPLAIN_FORMAT_YAML:
4686  es->grouping_stack = lcons_int(*state_save, es->grouping_stack);
4687  es->indent += depth;
4688  break;
4689  }
4690 }
List * lcons_int(int datum, List *list)
Definition: list.c:486
List * grouping_stack
Definition: explain.h:52
int indent
Definition: explain.h:51
ExplainFormat format
Definition: explain.h:49

◆ ExplainResultDesc()

TupleDesc ExplainResultDesc ( ExplainStmt stmt)

Definition at line 328 of file explain.c.

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

Referenced by ExplainQuery(), and UtilityTupleDescriptor().

329 {
330  TupleDesc tupdesc;
331  ListCell *lc;
332  Oid result_type = TEXTOID;
333 
334  /* Check for XML format option */
335  foreach(lc, stmt->options)
336  {
337  DefElem *opt = (DefElem *) lfirst(lc);
338 
339  if (strcmp(opt->defname, "format") == 0)
340  {
341  char *p = defGetString(opt);
342 
343  if (strcmp(p, "xml") == 0)
344  result_type = XMLOID;
345  else if (strcmp(p, "json") == 0)
346  result_type = JSONOID;
347  else
348  result_type = TEXTOID;
349  /* don't "break", as ExplainQuery will use the last value */
350  }
351  }
352 
353  /* Need a tuple descriptor representing a single TEXT or XML column */
354  tupdesc = CreateTemplateTupleDesc(1);
355  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
356  result_type, -1, 0);
357  return tupdesc;
358 }
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:45
List * options
Definition: parsenodes.h:3389
unsigned int Oid
Definition: postgres_ext.h:31
char * defGetString(DefElem *def)
Definition: define.c:49
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:583
#define lfirst(lc)
Definition: pg_list.h:169
char * defname
Definition: parsenodes.h:758
int16 AttrNumber
Definition: attnum.h:21

◆ ExplainSaveGroup()

static void ExplainSaveGroup ( ExplainState es,
int  depth,
int *  state_save 
)
static

Definition at line 4638 of file explain.c.

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

Referenced by ExplainCloseWorker().

4639 {
4640  switch (es->format)
4641  {
4642  case EXPLAIN_FORMAT_TEXT:
4643  /* nothing to do */
4644  break;
4645 
4646  case EXPLAIN_FORMAT_XML:
4647  es->indent -= depth;
4648  break;
4649 
4650  case EXPLAIN_FORMAT_JSON:
4651  es->indent -= depth;
4652  *state_save = linitial_int(es->grouping_stack);
4654  break;
4655 
4656  case EXPLAIN_FORMAT_YAML:
4657  es->indent -= depth;
4658  *state_save = linitial_int(es->grouping_stack);
4660  break;
4661  }
4662 }
#define linitial_int(l)
Definition: pg_list.h:175
List * grouping_stack
Definition: explain.h:52
int indent
Definition: explain.h:51
ExplainFormat format
Definition: explain.h:49
List * list_delete_first(List *list)
Definition: list.c:875

◆ ExplainScanTarget()

static void ExplainScanTarget ( Scan plan,
ExplainState es 
)
static

Definition at line 3701 of file explain.c.

References ExplainTargetRel().

Referenced by ExplainNode().

3702 {
3703  ExplainTargetRel((Plan *) plan, plan->scanrelid, es);
3704 }
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:3723

◆ ExplainSeparatePlans()

void ExplainSeparatePlans ( ExplainState es)

Definition at line 4805 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().

4806 {
4807  switch (es->format)
4808  {
4809  case EXPLAIN_FORMAT_TEXT:
4810  /* add a blank line */
4811  appendStringInfoChar(es->str, '\n');
4812  break;
4813 
4814  case EXPLAIN_FORMAT_XML:
4815  case EXPLAIN_FORMAT_JSON:
4816  case EXPLAIN_FORMAT_YAML:
4817  /* nothing to do */
4818  break;
4819  }
4820 }
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
ExplainFormat format
Definition: explain.h:49
StringInfo str
Definition: explain.h:39

◆ ExplainSubPlans()

static void ExplainSubPlans ( List plans,
List ancestors,
const char *  relationship,
ExplainState es 
)
static

Definition at line 4038 of file explain.c.

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

Referenced by ExplainNode().

4040 {
4041  ListCell *lst;
4042 
4043  foreach(lst, plans)
4044  {
4045  SubPlanState *sps = (SubPlanState *) lfirst(lst);
4046  SubPlan *sp = sps->subplan;
4047 
4048  /*
4049  * There can be multiple SubPlan nodes referencing the same physical
4050  * subplan (same plan_id, which is its index in PlannedStmt.subplans).
4051  * We should print a subplan only once, so track which ones we already
4052  * printed. This state must be global across the plan tree, since the
4053  * duplicate nodes could be in different plan nodes, eg both a bitmap
4054  * indexscan's indexqual and its parent heapscan's recheck qual. (We
4055  * do not worry too much about which plan node we show the subplan as
4056  * attached to in such cases.)
4057  */
4058  if (bms_is_member(sp->plan_id, es->printed_subplans))
4059  continue;
4061  sp->plan_id);
4062 
4063  /*
4064  * Treat the SubPlan node as an ancestor of the plan node(s) within
4065  * it, so that ruleutils.c can find the referents of subplan
4066  * parameters.
4067  */
4068  ancestors = lcons(sp, ancestors);
4069 
4070  ExplainNode(sps->planstate, ancestors,
4071  relationship, sp->plan_name, es);
4072 
4073  ancestors = list_delete_first(ancestors);
4074  }
4075 }
int plan_id
Definition: primnodes.h:752
Bitmapset * printed_subplans
Definition: explain.h:58
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1139
struct PlanState * planstate
Definition: execnodes.h:884
SubPlan * subplan
Definition: execnodes.h:883
List * lcons(void *datum, List *list)
Definition: list.c:468
char * plan_name
Definition: primnodes.h:754
#define lfirst(lc)
Definition: pg_list.h:169
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
List * list_delete_first(List *list)
Definition: list.c:875

◆ ExplainTargetRel()

static void ExplainTargetRel ( Plan plan,
Index  rti,
ExplainState es 
)
static

Definition at line 3723 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_or_temp(), 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_TidRangeScan, T_TidScan, T_ValuesScan, T_WorkTableScan, and ExplainState::verbose.

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

3724 {
3725  char *objectname = NULL;
3726  char *namespace = NULL;
3727  const char *objecttag = NULL;
3728  RangeTblEntry *rte;
3729  char *refname;
3730 
3731  rte = rt_fetch(rti, es->rtable);
3732  refname = (char *) list_nth(es->rtable_names, rti - 1);
3733  if (refname == NULL)
3734  refname = rte->eref->aliasname;
3735 
3736  switch (nodeTag(plan))
3737  {
3738  case T_SeqScan:
3739  case T_SampleScan:
3740  case T_IndexScan:
3741  case T_IndexOnlyScan:
3742  case T_BitmapHeapScan:
3743  case T_TidScan:
3744  case T_TidRangeScan:
3745  case T_ForeignScan:
3746  case T_CustomScan:
3747  case T_ModifyTable:
3748  /* Assert it's on a real relation */
3749  Assert(rte->rtekind == RTE_RELATION);
3750  objectname = get_rel_name(rte->relid);
3751  if (es->verbose)
3752  namespace = get_namespace_name_or_temp(get_rel_namespace(rte->relid));
3753  objecttag = "Relation Name";
3754  break;
3755  case T_FunctionScan:
3756  {
3757  FunctionScan *fscan = (FunctionScan *) plan;
3758 
3759  /* Assert it's on a RangeFunction */
3760  Assert(rte->rtekind == RTE_FUNCTION);
3761 
3762  /*
3763  * If the expression is still a function call of a single
3764  * function, we can get the real name of the function.
3765  * Otherwise, punt. (Even if it was a single function call
3766  * originally, the optimizer could have simplified it away.)
3767  */
3768  if (list_length(fscan->functions) == 1)
3769  {
3770  RangeTblFunction *rtfunc = (RangeTblFunction *) linitial(fscan->functions);
3771 
3772  if (IsA(rtfunc->funcexpr, FuncExpr))
3773  {
3774  FuncExpr *funcexpr = (FuncExpr *) rtfunc->funcexpr;
3775  Oid funcid = funcexpr->funcid;
3776 
3777  objectname = get_func_name(funcid);
3778  if (es->verbose)
3779  namespace = get_namespace_name_or_temp(get_func_namespace(funcid));
3780  }
3781  }
3782  objecttag = "Function Name";
3783  }
3784  break;
3785  case T_TableFuncScan:
3786  Assert(rte->rtekind == RTE_TABLEFUNC);
3787  objectname = "xmltable";
3788  objecttag = "Table Function Name";
3789  break;
3790  case T_ValuesScan:
3791  Assert(rte->rtekind == RTE_VALUES);
3792  break;
3793  case T_CteScan:
3794  /* Assert it's on a non-self-reference CTE */
3795  Assert(rte->rtekind == RTE_CTE);
3796  Assert(!rte->self_reference);
3797  objectname = rte->ctename;
3798  objecttag = "CTE Name";
3799  break;
3800  case T_NamedTuplestoreScan:
3802  objectname = rte->enrname;
3803  objecttag = "Tuplestore Name";
3804  break;
3805  case T_WorkTableScan:
3806  /* Assert it's on a self-reference CTE */
3807  Assert(rte->rtekind == RTE_CTE);
3808  Assert(rte->self_reference);
3809  objectname = rte->ctename;
3810  objecttag = "CTE Name";
3811  break;
3812  default:
3813  break;
3814  }
3815 
3816  if (es->format == EXPLAIN_FORMAT_TEXT)
3817  {
3818  appendStringInfoString(es->str, " on");
3819  if (namespace != NULL)
3820  appendStringInfo(es->str, " %s.%s", quote_identifier(namespace),
3821  quote_identifier(objectname));
3822  else if (objectname != NULL)
3823  appendStringInfo(es->str, " %s", quote_identifier(objectname));
3824  if (objectname == NULL || strcmp(refname, objectname) != 0)
3825  appendStringInfo(es->str, " %s", quote_identifier(refname));
3826  }
3827  else
3828  {
3829  if (objecttag != NULL && objectname != NULL)
3830  ExplainPropertyText(objecttag, objectname, es);
3831  if (namespace != NULL)
3832  ExplainPropertyText("Schema", namespace, es);
3833  ExplainPropertyText("Alias", refname, es);
3834  }
3835 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:11374
Oid get_func_namespace(Oid funcid)
Definition: lsyscache.c:1603
List * functions
Definition: plannodes.h:540
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1923
unsigned int Oid
Definition: postgres_ext.h:31
List * rtable_names
Definition: explain.h:56
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:4424
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
#define linitial(l)
Definition: pg_list.h:174
Oid funcid
Definition: primnodes.h:495
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1579
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
char * enrname
Definition: parsenodes.h:1146
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
bool self_reference
Definition: parsenodes.h:1119
bool verbose
Definition: explain.h:41
#define Assert(condition)
Definition: c.h:804
char * aliasname
Definition: primnodes.h:42
static int list_length(const List *l)
Definition: pg_list.h:149
ExplainFormat format
Definition: explain.h:49
#define nodeTag(nodeptr)
Definition: nodes.h:541
RTEKind rtekind
Definition: parsenodes.h:1007
char * ctename
Definition: parsenodes.h:1117
char * get_namespace_name_or_temp(Oid nspid)
Definition: lsyscache.c:3340
Alias * eref
Definition: parsenodes.h:1153
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1899
StringInfo str
Definition: explain.h:39
List * rtable
Definition: explain.h:55

◆ ExplainXMLTag()

static void ExplainXMLTag ( const char *  tagname,
int  flags,
ExplainState es 
)
static

Definition at line 4834 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().

4835 {
4836  const char *s;
4837  const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
4838 
4839  if ((flags & X_NOWHITESPACE) == 0)
4840  appendStringInfoSpaces(es->str, 2 * es->indent);
4841  appendStringInfoCharMacro(es->str, '<');
4842  if ((flags & X_CLOSING) != 0)
4843  appendStringInfoCharMacro(es->str, '/');
4844  for (s = tagname; *s; s++)
4845  appendStringInfoChar(es->str, strchr(valid, *s) ? *s : '-');
4846  if ((flags & X_CLOSE_IMMEDIATE) != 0)
4847  appendStringInfoString(es->str, " /");
4848  appendStringInfoCharMacro(es->str, '>');
4849  if ((flags & X_NOWHITESPACE) == 0)
4850  appendStringInfoCharMacro(es->str, '\n');
4851 }
#define X_CLOSING
Definition: explain.c:53
#define appendStringInfoCharMacro(str, ch)
Definition: stringinfo.h:128
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
int indent
Definition: explain.h:51
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
#define X_NOWHITESPACE
Definition: explain.c:55
#define X_CLOSE_IMMEDIATE
Definition: explain.c:54
StringInfo str
Definition: explain.h:39

◆ ExplainYAMLLineStarting()

static void ExplainYAMLLineStarting ( ExplainState es)
static

Definition at line 4896 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().

4897 {
4899  if (linitial_int(es->grouping_stack) == 0)
4900  {
4901  linitial_int(es->grouping_stack) = 1;
4902  }
4903  else
4904  {
4905  appendStringInfoChar(es->str, '\n');
4906  appendStringInfoSpaces(es->str, es->indent * 2);
4907  }
4908 }
#define linitial_int(l)
Definition: pg_list.h:175
List * grouping_stack
Definition: explain.h:52
int indent
Definition: explain.h:51
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
#define Assert(condition)
Definition: c.h:804
ExplainFormat format
Definition: explain.h:49
StringInfo str
Definition: explain.h:39

◆ NewExplainState()

ExplainState* NewExplainState ( void  )

Definition at line 311 of file explain.c.

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

Referenced by explain_ExecutorEnd(), and ExplainQuery().

312 {
313  ExplainState *es = (ExplainState *) palloc0(sizeof(ExplainState));
314 
315  /* Set default options (most fields can be left as zeroes). */
316  es->costs = true;
317  /* Prepare output buffer. */
318  es->str = makeStringInfo();
319 
320  return es;
321 }
StringInfo makeStringInfo(void)
Definition: stringinfo.c:41
bool costs
Definition: explain.h:43
void * palloc0(Size size)
Definition: mcxt.c:1093
StringInfo str
Definition: explain.h:39

◆ report_triggers()

static void report_triggers ( ResultRelInfo rInfo,
bool  show_relname,
ExplainState es 
)
static

Definition at line 974 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, relname, 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().

975 {
976  int nt;
977 
978  if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
979  return;
980  for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
981  {
982  Trigger *trig = rInfo->ri_TrigDesc->triggers + nt;
983  Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
984  char *relname;
985  char *conname = NULL;
986 
987  /* Must clean up instrumentation state */
988  InstrEndLoop(instr);
989 
990  /*
991  * We ignore triggers that were never invoked; they likely aren't
992  * relevant to the current query type.
993  */
994  if (instr->ntuples == 0)
995  continue;
996 
997  ExplainOpenGroup("Trigger", NULL, true, es);
998 
999  relname = RelationGetRelationName(rInfo->ri_RelationDesc);
1000  if (OidIsValid(trig->tgconstraint))
1001  conname = get_constraint_name(trig->tgconstraint);
1002 
1003  /*
1004  * In text format, we avoid printing both the trigger name and the
1005  * constraint name unless VERBOSE is specified. In non-text formats
1006  * we just print everything.
1007  */
1008  if (es->format == EXPLAIN_FORMAT_TEXT)
1009  {
1010  if (es->verbose || conname == NULL)
1011  appendStringInfo(es->str, "Trigger %s", trig->tgname);
1012  else
1013  appendStringInfoString(es->str, "Trigger");
1014  if (conname)
1015  appendStringInfo(es->str, " for constraint %s", conname);
1016  if (show_relname)
1017  appendStringInfo(es->str, " on %s", relname);
1018  if (es->timing)
1019  appendStringInfo(es->str, ": time=%.3f calls=%.0f\n",
1020  1000.0 * instr->total, instr->ntuples);
1021  else
1022  appendStringInfo(es->str, ": calls=%.0f\n", instr->ntuples);
1023  }
1024  else
1025  {
1026  ExplainPropertyText("Trigger Name", trig->tgname, es);
1027  if (conname)
1028  ExplainPropertyText("Constraint Name", conname, es);
1029  ExplainPropertyText("Relation", relname, es);
1030  if (es->timing)
1031  ExplainPropertyFloat("Time", "ms", 1000.0 * instr->total, 3,
1032  es);
1033  ExplainPropertyFloat("Calls", NULL, instr->ntuples, 0, es);
1034  }
1035 
1036  if (conname)
1037  pfree(conname);
1038 
1039  ExplainCloseGroup("Trigger", NULL, true, es);
1040  }
1041 }
Relation ri_RelationDesc
Definition: execnodes.h:411
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:1106
void ExplainPropertyFloat(const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
Definition: explain.c:4460
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:447
NameData relname
Definition: pg_class.h:38
#define OidIsValid(objectId)
Definition: c.h:710
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:140
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:4424
void pfree(void *pointer)
Definition: mcxt.c:1169
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
Oid tgconstraint
Definition: reltrigger.h:35