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/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_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)
 
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 53 of file explain.c.

Referenced by ExplainDummyGroup(), and ExplainXMLTag().

◆ X_CLOSING

#define X_CLOSING   1

Definition at line 52 of file explain.c.

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

◆ X_NOWHITESPACE

#define X_NOWHITESPACE   4

Definition at line 54 of file explain.c.

Referenced by ExplainProperty(), and ExplainXMLTag().

◆ X_OPENING

#define X_OPENING   0

Definition at line 51 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 1028 of file explain.c.

References INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, and INSTR_TIME_SUBTRACT.

Referenced by ExplainOnePlan(), and IsCheckpointOnSchedule().

1029 {
1030  instr_time endtime;
1031 
1032  INSTR_TIME_SET_CURRENT(endtime);
1033  INSTR_TIME_SUBTRACT(endtime, *starttime);
1034  return INSTR_TIME_GET_DOUBLE(endtime);
1035 }
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 4634 of file explain.c.

References escape_json().

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

4635 {
4636  escape_json(buf, str);
4637 }
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 3190 of file explain.c.

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

Referenced by ExplainIndexScanDetails(), and ExplainNode().

3191 {
3192  const char *result;
3193 
3195  result = (*explain_get_index_name_hook) (indexId);
3196  else
3197  result = NULL;
3198  if (result == NULL)
3199  {
3200  /* default behavior: look in the catalogs and quote it */
3201  result = get_rel_name(indexId);
3202  if (result == NULL)
3203  elog(ERROR, "cache lookup failed for index %u", indexId);
3204  result = quote_identifier(result);
3205  }
3206  return result;
3207 }
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10737
#define ERROR
Definition: elog.h:43
explain_get_index_name_hook_type explain_get_index_name_hook
Definition: explain.c:47
#define elog(elevel,...)
Definition: elog.h:214
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1840

◆ ExplainBeginOutput()

void ExplainBeginOutput ( ExplainState es)

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

4459 {
4460  switch (es->format)
4461  {
4462  case EXPLAIN_FORMAT_TEXT:
4463  /* nothing to do */
4464  break;
4465 
4466  case EXPLAIN_FORMAT_XML:
4468  "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
4469  es->indent++;
4470  break;
4471 
4472  case EXPLAIN_FORMAT_JSON:
4473  /* top-level structure is an array of plans */
4474  appendStringInfoChar(es->str, '[');
4475  es->grouping_stack = lcons_int(0, es->grouping_stack);
4476  es->indent++;
4477  break;
4478 
4479  case EXPLAIN_FORMAT_YAML:
4480  es->grouping_stack = lcons_int(0, es->grouping_stack);
4481  break;
4482  }
4483 }
List * lcons_int(int datum, List *list)
Definition: list.c:471
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 4265 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().

4267 {
4268  switch (es->format)
4269  {
4270  case EXPLAIN_FORMAT_TEXT:
4271  /* nothing to do */
4272  break;
4273 
4274  case EXPLAIN_FORMAT_XML:
4275  es->indent--;
4276  ExplainXMLTag(objtype, X_CLOSING, es);
4277  break;
4278 
4279  case EXPLAIN_FORMAT_JSON:
4280  es->indent--;
4281  appendStringInfoChar(es->str, '\n');
4282  appendStringInfoSpaces(es->str, 2 * es->indent);
4283  appendStringInfoChar(es->str, labeled ? '}' : ']');
4285  break;
4286 
4287  case EXPLAIN_FORMAT_YAML:
4288  es->indent--;
4290  break;
4291  }
4292 }
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:4547
#define X_CLOSING
Definition: explain.c:52
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:860

◆ ExplainCloseWorker()

static void ExplainCloseWorker ( int  n,
ExplainState es 
)
static

Definition at line 3895 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_incremental_sort_info(), and show_sort_info().

3896 {
3897  ExplainWorkersState *wstate = es->workers_state;
3898 
3899  Assert(wstate);
3900  Assert(n >= 0 && n < wstate->num_workers);
3901  Assert(wstate->worker_inited[n]);
3902 
3903  /*
3904  * Save formatting state in case we do another ExplainOpenWorker(), then
3905  * pop the formatting stack.
3906  */
3907  ExplainSaveGroup(es, 2, &wstate->worker_state_save[n]);
3908 
3909  /*
3910  * In TEXT format, if we didn't actually produce any output line(s) then
3911  * truncate off the partial line emitted by ExplainOpenWorker. (This is
3912  * to avoid bogus output if, say, show_buffer_usage chooses not to print
3913  * anything for the worker.) Also fix up the indent level.
3914  */
3915  if (es->format == EXPLAIN_FORMAT_TEXT)
3916  {
3917  while (es->str->len > 0 && es->str->data[es->str->len - 1] != '\n')
3918  es->str->data[--(es->str->len)] = '\0';
3919 
3920  es->indent--;
3921  }
3922 
3923  /* Restore prior output buffer pointer */
3924  es->str = wstate->prev_str;
3925 }
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:738
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:4351
StringInfo str
Definition: explain.h:39

◆ ExplainCreateWorkersState()

static ExplainWorkersState * ExplainCreateWorkersState ( int  num_workers)
static

Definition at line 3816 of file explain.c.

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

Referenced by ExplainNode().

3817 {
3818  ExplainWorkersState *wstate;
3819 
3820  wstate = (ExplainWorkersState *) palloc(sizeof(ExplainWorkersState));
3821  wstate->num_workers = num_workers;
3822  wstate->worker_inited = (bool *) palloc0(num_workers * sizeof(bool));
3823  wstate->worker_str = (StringInfoData *)
3824  palloc0(num_workers * sizeof(StringInfoData));
3825  wstate->worker_state_save = (int *) palloc(num_workers * sizeof(int));
3826  return wstate;
3827 }
int * worker_state_save
Definition: explain.h:33
StringInfoData * worker_str
Definition: explain.h:32
void * palloc0(Size size)
Definition: mcxt.c:980
bool * worker_inited
Definition: explain.h:31
void * palloc(Size size)
Definition: mcxt.c:949

◆ ExplainCustomChildren()

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

Definition at line 3794 of file explain.c.

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

Referenced by ExplainNode().

3795 {
3796  ListCell *cell;
3797  const char *label =
3798  (list_length(css->custom_ps) != 1 ? "children" : "child");
3799 
3800  foreach(cell, css->custom_ps)
3801  ExplainNode((PlanState *) lfirst(cell), ancestors, label, NULL, es);
3802 }
List * custom_ps
Definition: execnodes.h:1822
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1121
static char * label
#define lfirst(lc)
Definition: pg_list.h:190
static int list_length(const List *l)
Definition: pg_list.h:169

◆ ExplainDummyGroup()

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

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

4413 {
4414  switch (es->format)
4415  {
4416  case EXPLAIN_FORMAT_TEXT:
4417  /* nothing to do */
4418  break;
4419 
4420  case EXPLAIN_FORMAT_XML:
4421  ExplainXMLTag(objtype, X_CLOSE_IMMEDIATE, es);
4422  break;
4423 
4424  case EXPLAIN_FORMAT_JSON:
4426  appendStringInfoSpaces(es->str, 2 * es->indent);
4427  if (labelname)
4428  {
4429  escape_json(es->str, labelname);
4430  appendStringInfoString(es->str, ": ");
4431  }
4432  escape_json(es->str, objtype);
4433  break;
4434 
4435  case EXPLAIN_FORMAT_YAML:
4437  if (labelname)
4438  {
4439  escape_yaml(es->str, labelname);
4440  appendStringInfoString(es->str, ": ");
4441  }
4442  else
4443  {
4444  appendStringInfoString(es->str, "- ");
4445  }
4446  escape_yaml(es->str, objtype);
4447  break;
4448  }
4449 }
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:4547
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:4609
int indent
Definition: explain.h:51
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:4634
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:4589
ExplainFormat format
Definition: explain.h:49
#define X_CLOSE_IMMEDIATE
Definition: explain.c:53
StringInfo str
Definition: explain.h:39

◆ ExplainEndOutput()

void ExplainEndOutput ( ExplainState es)

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

4490 {
4491  switch (es->format)
4492  {
4493  case EXPLAIN_FORMAT_TEXT:
4494  /* nothing to do */
4495  break;
4496 
4497  case EXPLAIN_FORMAT_XML:
4498  es->indent--;
4499  appendStringInfoString(es->str, "</explain>");
4500  break;
4501 
4502  case EXPLAIN_FORMAT_JSON:
4503  es->indent--;
4504  appendStringInfoString(es->str, "\n]");
4506  break;
4507 
4508  case EXPLAIN_FORMAT_YAML:
4510  break;
4511  }
4512 }
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:860

◆ ExplainFlushWorkersState()

static void ExplainFlushWorkersState ( ExplainState es)
static

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

3932 {
3933  ExplainWorkersState *wstate = es->workers_state;
3934 
3935  ExplainOpenGroup("Workers", "Workers", false, es);
3936  for (int i = 0; i < wstate->num_workers; i++)
3937  {
3938  if (wstate->worker_inited[i])
3939  {
3940  /* This must match previous ExplainOpenSetAsideGroup call */
3941  ExplainOpenGroup("Worker", NULL, true, es);
3942  appendStringInfoString(es->str, wstate->worker_str[i].data);
3943  ExplainCloseGroup("Worker", NULL, true, es);
3944 
3945  pfree(wstate->worker_str[i].data);
3946  }
3947  }
3948  ExplainCloseGroup("Workers", "Workers", false, es);
3949 
3950  pfree(wstate->worker_inited);
3951  pfree(wstate->worker_str);
3952  pfree(wstate->worker_state_save);
3953  pfree(wstate);
3954 }
int * worker_state_save
Definition: explain.h:33
void pfree(void *pointer)
Definition: mcxt.c:1056
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:4265
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4202
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 3375 of file explain.c.

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

Referenced by ExplainNode().

3377 {
3378  const char *indexname = explain_get_index_name(indexid);
3379 
3380  if (es->format == EXPLAIN_FORMAT_TEXT)
3381  {
3382  if (ScanDirectionIsBackward(indexorderdir))
3383  appendStringInfoString(es->str, " Backward");
3384  appendStringInfo(es->str, " using %s", indexname);
3385  }
3386  else
3387  {
3388  const char *scandir;
3389 
3390  switch (indexorderdir)
3391  {
3392  case BackwardScanDirection:
3393  scandir = "Backward";
3394  break;
3396  scandir = "NoMovement";
3397  break;
3398  case ForwardScanDirection:
3399  scandir = "Forward";
3400  break;
3401  default:
3402  scandir = "???";
3403  break;
3404  }
3405  ExplainPropertyText("Scan Direction", scandir, es);
3406  ExplainPropertyText("Index Name", indexname, es);
3407  }
3408 }
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:4137
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:3190
StringInfo str
Definition: explain.h:39

◆ ExplainJSONLineEnding()

static void ExplainJSONLineEnding ( ExplainState es)
static

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

4590 {
4592  if (linitial_int(es->grouping_stack) != 0)
4593  appendStringInfoChar(es->str, ',');
4594  else
4595  linitial_int(es->grouping_stack) = 1;
4596  appendStringInfoChar(es->str, '\n');
4597 }
#define linitial_int(l)
Definition: pg_list.h:196
List * grouping_stack
Definition: explain.h:52
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
#define Assert(condition)
Definition: c.h:738
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 3719 of file explain.c.

References ExplainNode().

Referenced by ExplainNode().

3721 {
3722  int j;
3723 
3724  for (j = 0; j < nplans; j++)
3725  ExplainNode(planstates[j], ancestors,
3726  "Member", NULL, es);
3727 }
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1121

◆ ExplainMissingMembers()

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

Definition at line 3737 of file explain.c.

References EXPLAIN_FORMAT_TEXT, ExplainPropertyInteger(), and format.

Referenced by ExplainNode().

3738 {
3739  if (nplans < nchildren || es->format != EXPLAIN_FORMAT_TEXT)
3740  ExplainPropertyInteger("Subplans Removed", NULL,
3741  nchildren - nplans, es);
3742 }
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:4146
static char format

◆ ExplainModifyTarget()

static void ExplainModifyTarget ( ModifyTable plan,
ExplainState es 
)
static

Definition at line 3427 of file explain.c.

References ExplainTargetRel().

Referenced by ExplainNode().

3428 {
3429  ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
3430 }
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:3436

◆ ExplainNode()

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

Definition at line 1121 of file explain.c.

References AGG_HASHED, AGG_MIXED, AGG_PLAIN, AGG_SORTED, Agg::aggsplit, Agg::aggstrategy, ExplainState::analyze, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), 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_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(), 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_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_MergeAppend, T_MergeJoin, T_ModifyTable, T_NamedTuplestoreScan, T_NestLoop, T_ProjectSet, T_RecursiveUnion, T_Result, T_SampleScan, T_SeqScan, T_SetOp, T_Sort, T_SubqueryScan, T_TableFuncScan, T_TidScan, T_Unique, T_ValuesScan, T_WindowAgg, T_WorkTableScan, ExplainState::timing, Instrumentation::total, Plan::total_cost, ExplainState::verbose, ExplainState::wal, Instrumentation::walusage, PlanState::worker_instrument, PlanState::worker_jit_instrument, and ExplainState::workers_state.

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

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

◆ 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 500 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(), EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), ExplainOpenGroup(), ExplainPrintJITSummary(), ExplainPrintPlan(), ExplainPrintTriggers(), ExplainPropertyFloat(), ExplainState::format, ForwardScanDirection, FreeQueryDesc(), GetActiveSnapshot(), GetIntoRelEFlags(), ExplainState::indent, INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, INSTRUMENT_BUFFERS, INSTRUMENT_ROWS, INSTRUMENT_TIMER, INSTRUMENT_WAL, InvalidSnapshot, NoMovementScanDirection, None_Receiver, PopActiveSnapshot(), PushCopiedSnapshot(), show_buffer_usage(), IntoClause::skipData, ExplainState::summary, ExplainState::timing, UpdateActiveSnapshotCommandId(), and ExplainState::wal.

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

504 {
506  QueryDesc *queryDesc;
507  instr_time starttime;
508  double totaltime = 0;
509  int eflags;
510  int instrument_option = 0;
511 
512  Assert(plannedstmt->commandType != CMD_UTILITY);
513 
514  if (es->analyze && es->timing)
515  instrument_option |= INSTRUMENT_TIMER;
516  else if (es->analyze)
517  instrument_option |= INSTRUMENT_ROWS;
518 
519  if (es->buffers)
520  instrument_option |= INSTRUMENT_BUFFERS;
521  if (es->wal)
522  instrument_option |= INSTRUMENT_WAL;
523 
524  /*
525  * We always collect timing for the entire statement, even when node-level
526  * timing is off, so we don't look at es->timing here. (We could skip
527  * this if !es->summary, but it's hardly worth the complication.)
528  */
529  INSTR_TIME_SET_CURRENT(starttime);
530 
531  /*
532  * Use a snapshot with an updated command ID to ensure this query sees
533  * results of any previously executed queries.
534  */
537 
538  /*
539  * Normally we discard the query's output, but if explaining CREATE TABLE
540  * AS, we'd better use the appropriate tuple receiver.
541  */
542  if (into)
543  dest = CreateIntoRelDestReceiver(into);
544  else
545  dest = None_Receiver;
546 
547  /* Create a QueryDesc for the query */
548  queryDesc = CreateQueryDesc(plannedstmt, queryString,
550  dest, params, queryEnv, instrument_option);
551 
552  /* Select execution options */
553  if (es->analyze)
554  eflags = 0; /* default run-to-completion flags */
555  else
556  eflags = EXEC_FLAG_EXPLAIN_ONLY;
557  if (into)
558  eflags |= GetIntoRelEFlags(into);
559 
560  /* call ExecutorStart to prepare the plan for execution */
561  ExecutorStart(queryDesc, eflags);
562 
563  /* Execute the plan for statistics if asked for */
564  if (es->analyze)
565  {
566  ScanDirection dir;
567 
568  /* EXPLAIN ANALYZE CREATE TABLE AS WITH NO DATA is weird */
569  if (into && into->skipData)
571  else
572  dir = ForwardScanDirection;
573 
574  /* run the plan */
575  ExecutorRun(queryDesc, dir, 0L, true);
576 
577  /* run cleanup too */
578  ExecutorFinish(queryDesc);
579 
580  /* We can't run ExecutorEnd 'till we're done printing the stats... */
581  totaltime += elapsed_time(&starttime);
582  }
583 
584  ExplainOpenGroup("Query", NULL, true, es);
585 
586  /* Create textual dump of plan tree */
587  ExplainPrintPlan(es, queryDesc);
588 
589  if (es->summary && (planduration || bufusage))
590  ExplainOpenGroup("Planning", "Planning", true, es);
591 
592  if (es->summary && planduration)
593  {
594  double plantime = INSTR_TIME_GET_DOUBLE(*planduration);
595 
596  ExplainPropertyFloat("Planning Time", "ms", 1000.0 * plantime, 3, es);
597  }
598 
599  /* Show buffer usage */
600  if (es->summary && bufusage)
601  {
602  if (es->format == EXPLAIN_FORMAT_TEXT)
603  es->indent++;
604  show_buffer_usage(es, bufusage);
605  if (es->format == EXPLAIN_FORMAT_TEXT)
606  es->indent--;
607  }
608 
609  if (es->summary && (planduration || bufusage))
610  ExplainCloseGroup("Planning", "Planning", true, es);
611 
612  /* Print info about runtime of triggers */
613  if (es->analyze)
614  ExplainPrintTriggers(es, queryDesc);
615 
616  /*
617  * Print info about JITing. Tied to es->costs because we don't want to
618  * display this in regression tests, as it'd cause output differences
619  * depending on build options. Might want to separate that out from COSTS
620  * at a later stage.
621  */
622  if (es->costs)
623  ExplainPrintJITSummary(es, queryDesc);
624 
625  /*
626  * Close down the query and free resources. Include time for this in the
627  * total execution time (although it should be pretty minimal).
628  */
629  INSTR_TIME_SET_CURRENT(starttime);
630 
631  ExecutorEnd(queryDesc);
632 
633  FreeQueryDesc(queryDesc);
634 
636 
637  /* We need a CCI just in case query expanded to multiple plans */
638  if (es->analyze)
640 
641  totaltime += elapsed_time(&starttime);
642 
643  /*
644  * We only report execution time if we actually ran the query (that is,
645  * the user specified ANALYZE), and if summary reporting is enabled (the
646  * user can set SUMMARY OFF to not have the timing information included in
647  * the output). By default, ANALYZE sets SUMMARY to true.
648  */
649  if (es->summary && es->analyze)
650  ExplainPropertyFloat("Execution Time", "ms", 1000.0 * totaltime, 3,
651  es);
652 
653  ExplainCloseGroup("Query", NULL, true, es);
654 }
bool summary
Definition: explain.h:47
void UpdateActiveSnapshotCommandId(void)
Definition: snapmgr.c:783
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:4173
struct timeval instr_time
Definition: instr_time.h:150
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:143
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:841
void PopActiveSnapshot(void)
Definition: snapmgr.c:814
#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:462
int GetIntoRelEFlags(IntoClause *intoClause)
Definition: createas.c:393
void ExplainPrintTriggers(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:780
void ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:731
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:301
void PushCopiedSnapshot(Snapshot snapshot)
Definition: snapmgr.c:771
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:411
int indent
Definition: explain.h:51
static void show_buffer_usage(ExplainState *es, const BufferUsage *usage)
Definition: explain.c:3213
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:402
bool timing
Definition: explain.h:46
#define InvalidSnapshot
Definition: snapshot.h:123
void CommandCounterIncrement(void)
Definition: xact.c:1006
CmdType commandType
Definition: plannodes.h:46
#define Assert(condition)
Definition: c.h:738
bool wal
Definition: explain.h:45
ExplainFormat format
Definition: explain.h:49
static double elapsed_time(instr_time *starttime)
Definition: explain.c:1028
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
bool buffers
Definition: explain.h:44
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4265
void ExplainPrintJITSummary(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:826
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4202
#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 365 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().

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

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

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

428 {
429  if (utilityStmt == NULL)
430  return;
431 
432  if (IsA(utilityStmt, CreateTableAsStmt))
433  {
434  /*
435  * We have to rewrite the contained SELECT and then pass it back to
436  * ExplainOneQuery. It's probably not really necessary to copy the
437  * contained parsetree another time, but let's be safe.
438  */
439  CreateTableAsStmt *ctas = (CreateTableAsStmt *) utilityStmt;
440  List *rewritten;
441 
442  rewritten = QueryRewrite(castNode(Query, copyObject(ctas->query)));
443  Assert(list_length(rewritten) == 1);
444  ExplainOneQuery(linitial_node(Query, rewritten),
445  CURSOR_OPT_PARALLEL_OK, ctas->into, es,
446  queryString, params, queryEnv);
447  }
448  else if (IsA(utilityStmt, DeclareCursorStmt))
449  {
450  /*
451  * Likewise for DECLARE CURSOR.
452  *
453  * Notice that if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll
454  * actually run the query. This is different from pre-8.3 behavior
455  * but seems more useful than not running the query. No cursor will
456  * be created, however.
457  */
458  DeclareCursorStmt *dcs = (DeclareCursorStmt *) utilityStmt;
459  List *rewritten;
460 
461  rewritten = QueryRewrite(castNode(Query, copyObject(dcs->query)));
462  Assert(list_length(rewritten) == 1);
463  ExplainOneQuery(linitial_node(Query, rewritten),
464  dcs->options, NULL, es,
465  queryString, params, queryEnv);
466  }
467  else if (IsA(utilityStmt, ExecuteStmt))
468  ExplainExecuteQuery((ExecuteStmt *) utilityStmt, into, es,
469  queryString, params, queryEnv);
470  else if (IsA(utilityStmt, NotifyStmt))
471  {
472  if (es->format == EXPLAIN_FORMAT_TEXT)
473  appendStringInfoString(es->str, "NOTIFY\n");
474  else
475  ExplainDummyGroup("Notify", NULL, es);
476  }
477  else
478  {
479  if (es->format == EXPLAIN_FORMAT_TEXT)
481  "Utility statements have no plan structure\n");
482  else
483  ExplainDummyGroup("Utility Statement", NULL, es);
484  }
485 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
List * QueryRewrite(Query *parsetree)
#define castNode(_type_, nodeptr)
Definition: nodes.h:598
#define linitial_node(type, l)
Definition: pg_list.h:198
static void ExplainDummyGroup(const char *objtype, const char *labelname, ExplainState *es)
Definition: explain.c:4412
void ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: prepare.c:606
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
static void ExplainOneQuery(Query *query, int cursorOptions, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: explain.c:365
IntoClause * into
Definition: parsenodes.h:3277
#define Assert(condition)
Definition: c.h:738
static int list_length(const List *l)
Definition: pg_list.h:169
ExplainFormat format
Definition: explain.h:49
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2715
#define copyObject(obj)
Definition: nodes.h:645
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 4202 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().

4204 {
4205  switch (es->format)
4206  {
4207  case EXPLAIN_FORMAT_TEXT:
4208  /* nothing to do */
4209  break;
4210 
4211  case EXPLAIN_FORMAT_XML:
4212  ExplainXMLTag(objtype, X_OPENING, es);
4213  es->indent++;
4214  break;
4215 
4216  case EXPLAIN_FORMAT_JSON:
4218  appendStringInfoSpaces(es->str, 2 * es->indent);
4219  if (labelname)
4220  {
4221  escape_json(es->str, labelname);
4222  appendStringInfoString(es->str, ": ");
4223  }
4224  appendStringInfoChar(es->str, labeled ? '{' : '[');
4225 
4226  /*
4227  * In JSON format, the grouping_stack is an integer list. 0 means
4228  * we've emitted nothing at this grouping level, 1 means we've
4229  * emitted something (and so the next item needs a comma). See
4230  * ExplainJSONLineEnding().
4231  */
4232  es->grouping_stack = lcons_int(0, es->grouping_stack);
4233  es->indent++;
4234  break;
4235 
4236  case EXPLAIN_FORMAT_YAML:
4237 
4238  /*
4239  * In YAML format, the grouping stack is an integer list. 0 means
4240  * we've emitted nothing at this grouping level AND this grouping
4241  * level is unlabelled and must be marked with "- ". See
4242  * ExplainYAMLLineStarting().
4243  */
4245  if (labelname)
4246  {
4247  appendStringInfo(es->str, "%s: ", labelname);
4248  es->grouping_stack = lcons_int(1, es->grouping_stack);
4249  }
4250  else
4251  {
4252  appendStringInfoString(es->str, "- ");
4253  es->grouping_stack = lcons_int(0, es->grouping_stack);
4254  }
4255  es->indent++;
4256  break;
4257  }
4258 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:1279
List * lcons_int(int datum, List *list)
Definition: list.c:471
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:4547
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:4609
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:4589
#define X_OPENING
Definition: explain.c:51
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 4312 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().

4314 {
4315  switch (es->format)
4316  {
4317  case EXPLAIN_FORMAT_TEXT:
4318  /* nothing to do */
4319  break;
4320 
4321  case EXPLAIN_FORMAT_XML:
4322  es->indent += depth;
4323  break;
4324 
4325  case EXPLAIN_FORMAT_JSON:
4326  es->grouping_stack = lcons_int(0, es->grouping_stack);
4327  es->indent += depth;
4328  break;
4329 
4330  case EXPLAIN_FORMAT_YAML:
4331  if (labelname)
4332  es->grouping_stack = lcons_int(1, es->grouping_stack);
4333  else
4334  es->grouping_stack = lcons_int(0, es->grouping_stack);
4335  es->indent += depth;
4336  break;
4337  }
4338 }
List * lcons_int(int datum, List *list)
Definition: list.c:471
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 3833 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_incremental_sort_info(), and show_sort_info().

3834 {
3835  ExplainWorkersState *wstate = es->workers_state;
3836 
3837  Assert(wstate);
3838  Assert(n >= 0 && n < wstate->num_workers);
3839 
3840  /* Save prior output buffer pointer */
3841  wstate->prev_str = es->str;
3842 
3843  if (!wstate->worker_inited[n])
3844  {
3845  /* First time through, so create the buffer for this worker */
3846  initStringInfo(&wstate->worker_str[n]);
3847  es->str = &wstate->worker_str[n];
3848 
3849  /*
3850  * Push suitable initial formatting state for this worker's field
3851  * group. We allow one extra logical nesting level, since this group
3852  * will eventually be wrapped in an outer "Workers" group.
3853  */
3854  ExplainOpenSetAsideGroup("Worker", NULL, true, 2, es);
3855 
3856  /*
3857  * In non-TEXT formats we always emit a "Worker Number" field, even if
3858  * there's no other data for this worker.
3859  */
3860  if (es->format != EXPLAIN_FORMAT_TEXT)
3861  ExplainPropertyInteger("Worker Number", NULL, n, es);
3862 
3863  wstate->worker_inited[n] = true;
3864  }
3865  else
3866  {
3867  /* Resuming output for a worker we've already emitted some data for */
3868  es->str = &wstate->worker_str[n];
3869 
3870  /* Restore formatting state saved by last ExplainCloseWorker() */
3871  ExplainRestoreGroup(es, 2, &wstate->worker_state_save[n]);
3872  }
3873 
3874  /*
3875  * In TEXT format, prefix the first output line for this worker with
3876  * "Worker N:". Then, any additional lines should be indented one more
3877  * stop than the "Worker N" line is.
3878  */
3879  if (es->format == EXPLAIN_FORMAT_TEXT)
3880  {
3881  if (es->str->len == 0)
3882  {
3883  ExplainIndentText(es);
3884  appendStringInfo(es->str, "Worker %d: ", n);
3885  }
3886 
3887  es->indent++;
3888  }
3889 }
int * worker_state_save
Definition: explain.h:33
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:4146
static void ExplainRestoreGroup(ExplainState *es, int depth, int *state_save)
Definition: explain.c:4381
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:4574
#define Assert(condition)
Definition: c.h:738
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:4312

◆ ExplainPreScanNode()

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

Definition at line 1047 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_TidScan, T_ValuesScan, and T_WorkTableScan.

Referenced by ExplainPrintPlan().

1048 {
1049  Plan *plan = planstate->plan;
1050 
1051  switch (nodeTag(plan))
1052  {
1053  case T_SeqScan:
1054  case T_SampleScan:
1055  case T_IndexScan:
1056  case T_IndexOnlyScan:
1057  case T_BitmapHeapScan:
1058  case T_TidScan:
1059  case T_SubqueryScan:
1060  case T_FunctionScan:
1061  case T_TableFuncScan:
1062  case T_ValuesScan:
1063  case T_CteScan:
1064  case T_NamedTuplestoreScan:
1065  case T_WorkTableScan:
1066  *rels_used = bms_add_member(*rels_used,
1067  ((Scan *) plan)->scanrelid);
1068  break;
1069  case T_ForeignScan:
1070  *rels_used = bms_add_members(*rels_used,
1071  ((ForeignScan *) plan)->fs_relids);
1072  break;
1073  case T_CustomScan:
1074  *rels_used = bms_add_members(*rels_used,
1075  ((CustomScan *) plan)->custom_relids);
1076  break;
1077  case T_ModifyTable:
1078  *rels_used = bms_add_member(*rels_used,
1079  ((ModifyTable *) plan)->nominalRelation);
1080  if (((ModifyTable *) plan)->exclRelRTI)
1081  *rels_used = bms_add_member(*rels_used,
1082  ((ModifyTable *) plan)->exclRelRTI);
1083  break;
1084  case T_Append:
1085  *rels_used = bms_add_members(*rels_used,
1086  ((Append *) plan)->apprelids);
1087  break;
1088  case T_MergeAppend:
1089  *rels_used = bms_add_members(*rels_used,
1090  ((MergeAppend *) plan)->apprelids);
1091  break;
1092  default:
1093  break;
1094  }
1095 
1096  return planstate_tree_walker(planstate, ExplainPreScanNode, rels_used);
1097 }
Definition: nodes.h:49
Plan * plan
Definition: execnodes.h:945
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define nodeTag(nodeptr)
Definition: nodes.h:534
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
Definition: explain.c:1047
bool planstate_tree_walker(PlanState *planstate, bool(*walker)(), void *context)
Definition: nodeFuncs.c:3882
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 852 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().

853 {
854  instr_time total_time;
855 
856  /* don't print information if no JITing happened */
857  if (!ji || ji->created_functions == 0)
858  return;
859 
860  /* calculate total time */
861  INSTR_TIME_SET_ZERO(total_time);
862  INSTR_TIME_ADD(total_time, ji->generation_counter);
863  INSTR_TIME_ADD(total_time, ji->inlining_counter);
864  INSTR_TIME_ADD(total_time, ji->optimization_counter);
865  INSTR_TIME_ADD(total_time, ji->emission_counter);
866 
867  ExplainOpenGroup("JIT", "JIT", true, es);
868 
869  /* for higher density, open code the text output format */
870  if (es->format == EXPLAIN_FORMAT_TEXT)
871  {
872  ExplainIndentText(es);
873  appendStringInfoString(es->str, "JIT:\n");
874  es->indent++;
875 
876  ExplainPropertyInteger("Functions", NULL, ji->created_functions, es);
877 
878  ExplainIndentText(es);
879  appendStringInfo(es->str, "Options: %s %s, %s %s, %s %s, %s %s\n",
880  "Inlining", jit_flags & PGJIT_INLINE ? "true" : "false",
881  "Optimization", jit_flags & PGJIT_OPT3 ? "true" : "false",
882  "Expressions", jit_flags & PGJIT_EXPR ? "true" : "false",
883  "Deforming", jit_flags & PGJIT_DEFORM ? "true" : "false");
884 
885  if (es->analyze && es->timing)
886  {
887  ExplainIndentText(es);
888  appendStringInfo(es->str,
889  "Timing: %s %.3f ms, %s %.3f ms, %s %.3f ms, %s %.3f ms, %s %.3f ms\n",
890  "Generation", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->generation_counter),
891  "Inlining", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->inlining_counter),
892  "Optimization", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->optimization_counter),
893  "Emission", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->emission_counter),
894  "Total", 1000.0 * INSTR_TIME_GET_DOUBLE(total_time));
895  }
896 
897  es->indent--;
898  }
899  else
900  {
901  ExplainPropertyInteger("Functions", NULL, ji->created_functions, es);
902 
903  ExplainOpenGroup("Options", "Options", true, es);
904  ExplainPropertyBool("Inlining", jit_flags & PGJIT_INLINE, es);
905  ExplainPropertyBool("Optimization", jit_flags & PGJIT_OPT3, es);
906  ExplainPropertyBool("Expressions", jit_flags & PGJIT_EXPR, es);
907  ExplainPropertyBool("Deforming", jit_flags & PGJIT_DEFORM, es);
908  ExplainCloseGroup("Options", "Options", true, es);
909 
910  if (es->analyze && es->timing)
911  {
912  ExplainOpenGroup("Timing", "Timing", true, es);
913 
914  ExplainPropertyFloat("Generation", "ms",
916  3, es);
917  ExplainPropertyFloat("Inlining", "ms",
919  3, es);
920  ExplainPropertyFloat("Optimization", "ms",
922  3, es);
923  ExplainPropertyFloat("Emission", "ms",
925  3, es);
926  ExplainPropertyFloat("Total", "ms",
927  1000.0 * INSTR_TIME_GET_DOUBLE(total_time),
928  3, es);
929 
930  ExplainCloseGroup("Timing", "Timing", true, es);
931  }
932  }
933 
934  ExplainCloseGroup("JIT", "JIT", true, es);
935 }
void ExplainPropertyBool(const char *qlabel, bool value, ExplainState *es)
Definition: explain.c:4187
#define PGJIT_EXPR
Definition: jit.h:23
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:4146
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:4173
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:4574
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:4265
#define PGJIT_DEFORM
Definition: jit.h:24
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4202
StringInfo str
Definition: explain.h:39

◆ ExplainPrintJITSummary()

void ExplainPrintJITSummary ( ExplainState es,
QueryDesc queryDesc 
)

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

827 {
828  JitInstrumentation ji = {0};
829 
830  if (!(queryDesc->estate->es_jit_flags & PGJIT_PERFORM))
831  return;
832 
833  /*
834  * Work with a copy instead of modifying the leader state, since this
835  * function may be called twice
836  */
837  if (queryDesc->estate->es_jit)
838  InstrJitAgg(&ji, &queryDesc->estate->es_jit->instr);
839 
840  /* If this process has done JIT in parallel workers, merge stats */
841  if (queryDesc->estate->es_jit_worker_instr)
842  InstrJitAgg(&ji, queryDesc->estate->es_jit_worker_instr);
843 
844  ExplainPrintJIT(es, queryDesc->estate->es_jit_flags, &ji);
845 }
EState * estate
Definition: execdesc.h:48
struct JitContext * es_jit
Definition: execnodes.h:601
struct JitInstrumentation * es_jit_worker_instr
Definition: execnodes.h:602
static void ExplainPrintJIT(ExplainState *es, int jit_flags, JitInstrumentation *ji)
Definition: explain.c:852
JitInstrumentation instr
Definition: jit.h:61
int es_jit_flags
Definition: execnodes.h:600
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 731 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().

732 {
733  Bitmapset *rels_used = NULL;
734  PlanState *ps;
735 
736  /* Set up ExplainState fields associated with this plan tree */
737  Assert(queryDesc->plannedstmt != NULL);
738  es->pstmt = queryDesc->plannedstmt;
739  es->rtable = queryDesc->plannedstmt->rtable;
740  ExplainPreScanNode(queryDesc->planstate, &rels_used);
743  es->rtable_names);
744  es->printed_subplans = NULL;
745 
746  /*
747  * Sometimes we mark a Gather node as "invisible", which means that it's
748  * not to be displayed in EXPLAIN output. The purpose of this is to allow
749  * running regression tests with force_parallel_mode=regress to get the
750  * same results as running the same tests with force_parallel_mode=off.
751  * Such marking is currently only supported on a Gather at the top of the
752  * plan. We skip that node, and we must also hide per-worker detail data
753  * further down in the plan tree.
754  */
755  ps = queryDesc->planstate;
756  if (IsA(ps, GatherState) && ((Gather *) ps->plan)->invisible)
757  {
758  ps = outerPlanState(ps);
759  es->hide_workers = true;
760  }
761  ExplainNode(ps, NIL, NULL, NULL, es);
762 
763  /*
764  * If requested, include information about GUC parameters with values that
765  * don't match the built-in defaults.
766  */
768 }
#define NIL
Definition: pg_list.h:65
static void ExplainPrintSettings(ExplainState *es)
Definition: explain.c:661
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
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:3420
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1121
PlanState * planstate
Definition: execdesc.h:49
#define outerPlanState(node)
Definition: execnodes.h:1039
List * deparse_context_for_plan_tree(PlannedStmt *pstmt, List *rtable_names)
Definition: ruleutils.c:3328
Plan * plan
Definition: execnodes.h:945
#define Assert(condition)
Definition: c.h:738
List * rtable
Definition: plannodes.h:66
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
Definition: explain.c:1047
PlannedStmt * plannedstmt
Definition: execdesc.h:37
List * rtable
Definition: explain.h:55

◆ ExplainPrintSettings()

static void ExplainPrintSettings ( ExplainState es)
static

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

662 {
663  int num;
664  struct config_generic **gucs;
665 
666  /* bail out if information about settings not requested */
667  if (!es->settings)
668  return;
669 
670  /* request an array of relevant settings */
671  gucs = get_explain_guc_options(&num);
672 
673  if (es->format != EXPLAIN_FORMAT_TEXT)
674  {
675  ExplainOpenGroup("Settings", "Settings", true, es);
676 
677  for (int i = 0; i < num; i++)
678  {
679  char *setting;
680  struct config_generic *conf = gucs[i];
681 
682  setting = GetConfigOptionByName(conf->name, NULL, true);
683 
684  ExplainPropertyText(conf->name, setting, es);
685  }
686 
687  ExplainCloseGroup("Settings", "Settings", true, es);
688  }
689  else
690  {
692 
693  /* In TEXT mode, print nothing if there are no options */
694  if (num <= 0)
695  return;
696 
697  initStringInfo(&str);
698 
699  for (int i = 0; i < num; i++)
700  {
701  char *setting;
702  struct config_generic *conf = gucs[i];
703 
704  if (i > 0)
705  appendStringInfoString(&str, ", ");
706 
707  setting = GetConfigOptionByName(conf->name, NULL, true);
708 
709  if (setting)
710  appendStringInfo(&str, "%s = '%s'", conf->name, setting);
711  else
712  appendStringInfo(&str, "%s = NULL", conf->name);
713  }
714 
715  ExplainPropertyText("Settings", str.data, es);
716  }
717 }
const char * name
Definition: guc_tables.h:149
struct config_generic ** get_explain_guc_options(int *num)
Definition: guc.c:9099
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:4137
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:9192
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:4265
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4202
bool settings
Definition: explain.h:48

◆ ExplainPrintTriggers()

void ExplainPrintTriggers ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 780 of file explain.c.

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

Referenced by explain_ExecutorEnd(), and ExplainOnePlan().

781 {
782  ResultRelInfo *rInfo;
783  bool show_relname;
784  int numrels = queryDesc->estate->es_num_result_relations;
785  int numrootrels = queryDesc->estate->es_num_root_result_relations;
786  List *routerels;
787  List *targrels;
788  int nr;
789  ListCell *l;
790 
791  routerels = queryDesc->estate->es_tuple_routing_result_relations;
792  targrels = queryDesc->estate->es_trig_target_relations;
793 
794  ExplainOpenGroup("Triggers", "Triggers", false, es);
795 
796  show_relname = (numrels > 1 || numrootrels > 0 ||
797  routerels != NIL || targrels != NIL);
798  rInfo = queryDesc->estate->es_result_relations;
799  for (nr = 0; nr < numrels; rInfo++, nr++)
800  report_triggers(rInfo, show_relname, es);
801 
802  rInfo = queryDesc->estate->es_root_result_relations;
803  for (nr = 0; nr < numrootrels; rInfo++, nr++)
804  report_triggers(rInfo, show_relname, es);
805 
806  foreach(l, routerels)
807  {
808  rInfo = (ResultRelInfo *) lfirst(l);
809  report_triggers(rInfo, show_relname, es);
810  }
811 
812  foreach(l, targrels)
813  {
814  rInfo = (ResultRelInfo *) lfirst(l);
815  report_triggers(rInfo, show_relname, es);
816  }
817 
818  ExplainCloseGroup("Triggers", "Triggers", false, es);
819 }
#define NIL
Definition: pg_list.h:65
EState * estate
Definition: execdesc.h:48
ResultRelInfo * es_result_relations
Definition: execnodes.h:525
static void report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
Definition: explain.c:957
int es_num_root_result_relations
Definition: execnodes.h:536
List * es_trig_target_relations
Definition: execnodes.h:546
int es_num_result_relations
Definition: execnodes.h:526
List * es_tuple_routing_result_relations
Definition: execnodes.h:543
#define lfirst(lc)
Definition: pg_list.h:190
ResultRelInfo * es_root_result_relations
Definition: execnodes.h:535
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4265
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4202
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 4084 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().

4086 {
4087  switch (es->format)
4088  {
4089  case EXPLAIN_FORMAT_TEXT:
4090  ExplainIndentText(es);
4091  if (unit)
4092  appendStringInfo(es->str, "%s: %s %s\n", qlabel, value, unit);
4093  else
4094  appendStringInfo(es->str, "%s: %s\n", qlabel, value);
4095  break;
4096 
4097  case EXPLAIN_FORMAT_XML:
4098  {
4099  char *str;
4100 
4101  appendStringInfoSpaces(es->str, es->indent * 2);
4102  ExplainXMLTag(qlabel, X_OPENING | X_NOWHITESPACE, es);
4103  str = escape_xml(value);
4104  appendStringInfoString(es->str, str);
4105  pfree(str);
4106  ExplainXMLTag(qlabel, X_CLOSING | X_NOWHITESPACE, es);
4107  appendStringInfoChar(es->str, '\n');
4108  }
4109  break;
4110 
4111  case EXPLAIN_FORMAT_JSON:
4113  appendStringInfoSpaces(es->str, es->indent * 2);
4114  escape_json(es->str, qlabel);
4115  appendStringInfoString(es->str, ": ");
4116  if (numeric)
4118  else
4119  escape_json(es->str, value);
4120  break;
4121 
4122  case EXPLAIN_FORMAT_YAML:
4124  appendStringInfo(es->str, "%s: ", qlabel);
4125  if (numeric)
4127  else
4128  escape_yaml(es->str, value);
4129  break;
4130  }
4131 }
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:4547
#define X_CLOSING
Definition: explain.c:52
void pfree(void *pointer)
Definition: mcxt.c:1056
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:4609
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:4634
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:4589
static struct @143 value
#define X_OPENING
Definition: explain.c:51
static void ExplainIndentText(ExplainState *es)
Definition: explain.c:4574
#define X_NOWHITESPACE
Definition: explain.c:54
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 4187 of file explain.c.

References ExplainProperty().

Referenced by ExplainNode(), and ExplainPrintJIT().

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

◆ ExplainPropertyFloat()

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

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

4175 {
4176  char *buf;
4177 
4178  buf = psprintf("%.*f", ndigits, value);
4179  ExplainProperty(qlabel, unit, buf, true, es);
4180  pfree(buf);
4181 }
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
void pfree(void *pointer)
Definition: mcxt.c:1056
static char * buf
Definition: pg_test_fsync.c:67
static struct @143 value
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:4084

◆ ExplainPropertyInteger()

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

Definition at line 4146 of file explain.c.

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

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

4148 {
4149  char buf[32];
4150 
4151  snprintf(buf, sizeof(buf), INT64_FORMAT, value);
4152  ExplainProperty(qlabel, unit, buf, true, es);
4153 }
static char * buf
Definition: pg_test_fsync.c:67
static struct @143 value
#define INT64_FORMAT
Definition: c.h:409
#define snprintf
Definition: port.h:193
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:4084

◆ ExplainPropertyList()

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

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

3962 {
3963  ListCell *lc;
3964  bool first = true;
3965 
3966  switch (es->format)
3967  {
3968  case EXPLAIN_FORMAT_TEXT:
3969  ExplainIndentText(es);
3970  appendStringInfo(es->str, "%s: ", qlabel);
3971  foreach(lc, data)
3972  {
3973  if (!first)
3974  appendStringInfoString(es->str, ", ");
3975  appendStringInfoString(es->str, (const char *) lfirst(lc));
3976  first = false;
3977  }
3978  appendStringInfoChar(es->str, '\n');
3979  break;
3980 
3981  case EXPLAIN_FORMAT_XML:
3982  ExplainXMLTag(qlabel, X_OPENING, es);
3983  foreach(lc, data)
3984  {
3985  char *str;
3986 
3987  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
3988  appendStringInfoString(es->str, "<Item>");
3989  str = escape_xml((const char *) lfirst(lc));
3990  appendStringInfoString(es->str, str);
3991  pfree(str);
3992  appendStringInfoString(es->str, "</Item>\n");
3993  }
3994  ExplainXMLTag(qlabel, X_CLOSING, es);
3995  break;
3996 
3997  case EXPLAIN_FORMAT_JSON:
3999  appendStringInfoSpaces(es->str, es->indent * 2);
4000  escape_json(es->str, qlabel);
4001  appendStringInfoString(es->str, ": [");
4002  foreach(lc, data)
4003  {
4004  if (!first)
4005  appendStringInfoString(es->str, ", ");
4006  escape_json(es->str, (const char *) lfirst(lc));
4007  first = false;
4008  }
4009  appendStringInfoChar(es->str, ']');
4010  break;
4011 
4012  case EXPLAIN_FORMAT_YAML:
4014  appendStringInfo(es->str, "%s: ", qlabel);
4015  foreach(lc, data)
4016  {
4017  appendStringInfoChar(es->str, '\n');
4018  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
4019  appendStringInfoString(es->str, "- ");
4020  escape_yaml(es->str, (const char *) lfirst(lc));
4021  }
4022  break;
4023  }
4024 }
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:4547
#define X_CLOSING
Definition: explain.c:52
void pfree(void *pointer)
Definition: mcxt.c:1056
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:4609
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:4634
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:4589
#define X_OPENING
Definition: explain.c:51
static void ExplainIndentText(ExplainState *es)
Definition: explain.c:4574
#define lfirst(lc)
Definition: pg_list.h:190
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 4031 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().

4032 {
4033  ListCell *lc;
4034  bool first = true;
4035 
4036  switch (es->format)
4037  {
4038  case EXPLAIN_FORMAT_TEXT:
4039  case EXPLAIN_FORMAT_XML:
4040  ExplainPropertyList(qlabel, data, es);
4041  return;
4042 
4043  case EXPLAIN_FORMAT_JSON:
4045  appendStringInfoSpaces(es->str, es->indent * 2);
4046  appendStringInfoChar(es->str, '[');
4047  foreach(lc, data)
4048  {
4049  if (!first)
4050  appendStringInfoString(es->str, ", ");
4051  escape_json(es->str, (const char *) lfirst(lc));
4052  first = false;
4053  }
4054  appendStringInfoChar(es->str, ']');
4055  break;
4056 
4057  case EXPLAIN_FORMAT_YAML:
4059  appendStringInfoString(es->str, "- [");
4060  foreach(lc, data)
4061  {
4062  if (!first)
4063  appendStringInfoString(es->str, ", ");
4064  escape_yaml(es->str, (const char *) lfirst(lc));
4065  first = false;
4066  }
4067  appendStringInfoChar(es->str, ']');
4068  break;
4069  }
4070 }
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:4609
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:4634
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:4589
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:3961
#define lfirst(lc)
Definition: pg_list.h:190
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 4137 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_modifytable_info(), show_sort_info(), and show_tablesample().

4138 {
4139  ExplainProperty(qlabel, NULL, value, false, es);
4140 }
static struct @143 value
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:4084

◆ ExplainPropertyUInteger()

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

Definition at line 4159 of file explain.c.

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

Referenced by show_wal_usage().

4161 {
4162  char buf[32];
4163 
4164  snprintf(buf, sizeof(buf), UINT64_FORMAT, value);
4165  ExplainProperty(qlabel, unit, buf, true, es);
4166 }
static char * buf
Definition: pg_test_fsync.c:67
static struct @143 value
#define snprintf
Definition: port.h:193
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:4084
#define UINT64_FORMAT
Definition: c.h:410

◆ ExplainQuery()

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

Definition at line 160 of file explain.c.

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

Referenced by standard_ProcessUtility().

162 {
164  TupOutputState *tstate;
165  List *rewritten;
166  ListCell *lc;
167  bool timing_set = false;
168  bool summary_set = false;
169 
170  /* Parse options list. */
171  foreach(lc, stmt->options)
172  {
173  DefElem *opt = (DefElem *) lfirst(lc);
174 
175  if (strcmp(opt->defname, "analyze") == 0)
176  es->analyze = defGetBoolean(opt);
177  else if (strcmp(opt->defname, "verbose") == 0)
178  es->verbose = defGetBoolean(opt);
179  else if (strcmp(opt->defname, "costs") == 0)
180  es->costs = defGetBoolean(opt);
181  else if (strcmp(opt->defname, "buffers") == 0)
182  es->buffers = defGetBoolean(opt);
183  else if (strcmp(opt->defname, "wal") == 0)
184  es->wal = defGetBoolean(opt);
185  else if (strcmp(opt->defname, "settings") == 0)
186  es->settings = defGetBoolean(opt);
187  else if (strcmp(opt->defname, "timing") == 0)
188  {
189  timing_set = true;
190  es->timing = defGetBoolean(opt);
191  }
192  else if (strcmp(opt->defname, "summary") == 0)
193  {
194  summary_set = true;
195  es->summary = defGetBoolean(opt);
196  }
197  else if (strcmp(opt->defname, "format") == 0)
198  {
199  char *p = defGetString(opt);
200 
201  if (strcmp(p, "text") == 0)
203  else if (strcmp(p, "xml") == 0)
205  else if (strcmp(p, "json") == 0)
207  else if (strcmp(p, "yaml") == 0)
209  else
210  ereport(ERROR,
211  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
212  errmsg("unrecognized value for EXPLAIN option \"%s\": \"%s\"",
213  opt->defname, p),
214  parser_errposition(pstate, opt->location)));
215  }
216  else
217  ereport(ERROR,
218  (errcode(ERRCODE_SYNTAX_ERROR),
219  errmsg("unrecognized EXPLAIN option \"%s\"",
220  opt->defname),
221  parser_errposition(pstate, opt->location)));
222  }
223 
224  if (es->buffers && !es->analyze)
225  ereport(ERROR,
226  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
227  errmsg("EXPLAIN option BUFFERS requires ANALYZE")));
228 
229  if (es->wal && !es->analyze)
230  ereport(ERROR,
231  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
232  errmsg("EXPLAIN option WAL requires ANALYZE")));
233 
234  /* if the timing was not set explicitly, set default value */
235  es->timing = (timing_set) ? es->timing : es->analyze;
236 
237  /* check that timing is used with EXPLAIN ANALYZE */
238  if (es->timing && !es->analyze)
239  ereport(ERROR,
240  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
241  errmsg("EXPLAIN option TIMING requires ANALYZE")));
242 
243  /* if the summary was not set explicitly, set default value */
244  es->summary = (summary_set) ? es->summary : es->analyze;
245 
246  /*
247  * Parse analysis was done already, but we still have to run the rule
248  * rewriter. We do not do AcquireRewriteLocks: we assume the query either
249  * came straight from the parser, or suitable locks were acquired by
250  * plancache.c.
251  *
252  * Because the rewriter and planner tend to scribble on the input, we make
253  * a preliminary copy of the source querytree. This prevents problems in
254  * the case that the EXPLAIN is in a portal or plpgsql function and is
255  * executed repeatedly. (See also the same hack in DECLARE CURSOR and
256  * PREPARE.) XXX FIXME someday.
257  */
258  rewritten = QueryRewrite(castNode(Query, copyObject(stmt->query)));
259 
260  /* emit opening boilerplate */
261  ExplainBeginOutput(es);
262 
263  if (rewritten == NIL)
264  {
265  /*
266  * In the case of an INSTEAD NOTHING, tell at least that. But in
267  * non-text format, the output is delimited, so this isn't necessary.
268  */
269  if (es->format == EXPLAIN_FORMAT_TEXT)
270  appendStringInfoString(es->str, "Query rewrites to nothing\n");
271  }
272  else
273  {
274  ListCell *l;
275 
276  /* Explain every plan */
277  foreach(l, rewritten)
278  {
280  CURSOR_OPT_PARALLEL_OK, NULL, es,
281  pstate->p_sourcetext, params, pstate->p_queryEnv);
282 
283  /* Separate plans with an appropriate separator */
284  if (lnext(rewritten, l) != NULL)
286  }
287  }
288 
289  /* emit closing boilerplate */
290  ExplainEndOutput(es);
291  Assert(es->indent == 0);
292 
293  /* output tuples */
294  tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt),
295  &TTSOpsVirtual);
296  if (es->format == EXPLAIN_FORMAT_TEXT)
297  do_text_output_multiline(tstate, es->str->data);
298  else
299  do_text_output_oneline(tstate, es->str->data);
300  end_tup_output(tstate);
301 
302  pfree(es->str->data);
303 }
#define NIL
Definition: pg_list.h:65
bool summary
Definition: explain.h:47
ExplainState * NewExplainState(void)
Definition: explain.c:309
List * QueryRewrite(Query *parsetree)
void ExplainSeparatePlans(ExplainState *es)
Definition: explain.c:4518
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:321
#define castNode(_type_, nodeptr)
Definition: nodes.h:598
QueryEnvironment * p_queryEnv
Definition: parse_node.h:203
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
int errcode(int sqlerrcode)
Definition: elog.c:610
List * options
Definition: parsenodes.h:3257
bool costs
Definition: explain.h:43
bool analyze
Definition: explain.h:42
Node * query
Definition: parsenodes.h:3256
void ExplainEndOutput(ExplainState *es)
Definition: explain.c:4489
bool defGetBoolean(DefElem *def)
Definition: define.c:111
void pfree(void *pointer)
Definition: mcxt.c:1056
void end_tup_output(TupOutputState *tstate)
Definition: execTuples.c:2314
void ExplainBeginOutput(ExplainState *es)
Definition: explain.c:4458
#define ERROR
Definition: elog.h:43
TupleDesc ExplainResultDesc(ExplainStmt *stmt)
Definition: explain.c:326
char * defGetString(DefElem *def)
Definition: define.c:49
TupOutputState * begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:2236
#define lfirst_node(type, lc)
Definition: pg_list.h:193
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
int location
Definition: parsenodes.h:735
int indent
Definition: explain.h:51
const char * p_sourcetext
Definition: parse_node.h:179
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:365
void do_text_output_multiline(TupOutputState *tstate, const char *txt)
Definition: execTuples.c:2284
bool verbose
Definition: explain.h:41
#define ereport(elevel,...)
Definition: elog.h:144
#define Assert(condition)
Definition: c.h:738
#define lfirst(lc)
Definition: pg_list.h:190
bool wal
Definition: explain.h:45
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:110
ExplainFormat format
Definition: explain.h:49
#define do_text_output_oneline(tstate, str_to_emit)
Definition: executor.h:479
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2715
int errmsg(const char *fmt,...)
Definition: elog.c:824
bool buffers
Definition: explain.h:44
char * defname
Definition: parsenodes.h:732
#define copyObject(obj)
Definition: nodes.h:645
Definition: pg_list.h:50
StringInfo str
Definition: explain.h:39
bool settings
Definition: explain.h:48

◆ ExplainQueryText()

void ExplainQueryText ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 946 of file explain.c.

References ExplainPropertyText(), and QueryDesc::sourceText.

Referenced by explain_ExecutorEnd().

947 {
948  if (queryDesc->sourceText)
949  ExplainPropertyText("Query Text", queryDesc->sourceText, es);
950 }
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:4137
const char * sourceText
Definition: execdesc.h:38

◆ ExplainRestoreGroup()

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

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

4382 {
4383  switch (es->format)
4384  {
4385  case EXPLAIN_FORMAT_TEXT:
4386  /* nothing to do */
4387  break;
4388 
4389  case EXPLAIN_FORMAT_XML:
4390  es->indent += depth;
4391  break;
4392 
4393  case EXPLAIN_FORMAT_JSON:
4394  es->grouping_stack = lcons_int(*state_save, es->grouping_stack);
4395  es->indent += depth;
4396  break;
4397 
4398  case EXPLAIN_FORMAT_YAML:
4399  es->grouping_stack = lcons_int(*state_save, es->grouping_stack);
4400  es->indent += depth;
4401  break;
4402  }
4403 }
List * lcons_int(int datum, List *list)
Definition: list.c:471
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 326 of file explain.c.

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

Referenced by ExplainQuery(), and UtilityTupleDescriptor().

327 {
328  TupleDesc tupdesc;
329  ListCell *lc;
330  Oid result_type = TEXTOID;
331 
332  /* Check for XML format option */
333  foreach(lc, stmt->options)
334  {
335  DefElem *opt = (DefElem *) lfirst(lc);
336 
337  if (strcmp(opt->defname, "format") == 0)
338  {
339  char *p = defGetString(opt);
340 
341  if (strcmp(p, "xml") == 0)
342  result_type = XMLOID;
343  else if (strcmp(p, "json") == 0)
344  result_type = JSONOID;
345  else
346  result_type = TEXTOID;
347  /* don't "break", as ExplainQuery will use the last value */
348  }
349  }
350 
351  /* Need a tuple descriptor representing a single TEXT or XML column */
352  tupdesc = CreateTemplateTupleDesc(1);
353  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
354  result_type, -1, 0);
355  return tupdesc;
356 }
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
List * options
Definition: parsenodes.h:3257
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:603
#define lfirst(lc)
Definition: pg_list.h:190
char * defname
Definition: parsenodes.h:732
int16 AttrNumber
Definition: attnum.h:21

◆ ExplainSaveGroup()

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

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

4352 {
4353  switch (es->format)
4354  {
4355  case EXPLAIN_FORMAT_TEXT:
4356  /* nothing to do */
4357  break;
4358 
4359  case EXPLAIN_FORMAT_XML:
4360  es->indent -= depth;
4361  break;
4362 
4363  case EXPLAIN_FORMAT_JSON:
4364  es->indent -= depth;
4365  *state_save = linitial_int(es->grouping_stack);
4367  break;
4368 
4369  case EXPLAIN_FORMAT_YAML:
4370  es->indent -= depth;
4371  *state_save = linitial_int(es->grouping_stack);
4373  break;
4374  }
4375 }
#define linitial_int(l)
Definition: pg_list.h:196
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:860

◆ ExplainScanTarget()

static void ExplainScanTarget ( Scan plan,
ExplainState es 
)
static

Definition at line 3414 of file explain.c.

References ExplainTargetRel().

Referenced by ExplainNode().

3415 {
3416  ExplainTargetRel((Plan *) plan, plan->scanrelid, es);
3417 }
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:3436

◆ ExplainSeparatePlans()

void ExplainSeparatePlans ( ExplainState es)

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

4519 {
4520  switch (es->format)
4521  {
4522  case EXPLAIN_FORMAT_TEXT:
4523  /* add a blank line */
4524  appendStringInfoChar(es->str, '\n');
4525  break;
4526 
4527  case EXPLAIN_FORMAT_XML:
4528  case EXPLAIN_FORMAT_JSON:
4529  case EXPLAIN_FORMAT_YAML:
4530  /* nothing to do */
4531  break;
4532  }
4533 }
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 3751 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().

3753 {
3754  ListCell *lst;
3755 
3756  foreach(lst, plans)
3757  {
3758  SubPlanState *sps = (SubPlanState *) lfirst(lst);
3759  SubPlan *sp = sps->subplan;
3760 
3761  /*
3762  * There can be multiple SubPlan nodes referencing the same physical
3763  * subplan (same plan_id, which is its index in PlannedStmt.subplans).
3764  * We should print a subplan only once, so track which ones we already
3765  * printed. This state must be global across the plan tree, since the
3766  * duplicate nodes could be in different plan nodes, eg both a bitmap
3767  * indexscan's indexqual and its parent heapscan's recheck qual. (We
3768  * do not worry too much about which plan node we show the subplan as
3769  * attached to in such cases.)
3770  */
3771  if (bms_is_member(sp->plan_id, es->printed_subplans))
3772  continue;
3774  sp->plan_id);
3775 
3776  /*
3777  * Treat the SubPlan node as an ancestor of the plan node(s) within
3778  * it, so that ruleutils.c can find the referents of subplan
3779  * parameters.
3780  */
3781  ancestors = lcons(sp, ancestors);
3782 
3783  ExplainNode(sps->planstate, ancestors,
3784  relationship, sp->plan_name, es);
3785 
3786  ancestors = list_delete_first(ancestors);
3787  }
3788 }
int plan_id
Definition: primnodes.h:709
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:1121
struct PlanState * planstate
Definition: execnodes.h:853
SubPlan * subplan
Definition: execnodes.h:852
List * lcons(void *datum, List *list)
Definition: list.c:453
char * plan_name
Definition: primnodes.h:711
#define lfirst(lc)
Definition: pg_list.h:190
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:860

◆ ExplainTargetRel()

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

Definition at line 3436 of file explain.c.

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

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

3437 {
3438  char *objectname = NULL;
3439  char *namespace = NULL;
3440  const char *objecttag = NULL;
3441  RangeTblEntry *rte;
3442  char *refname;
3443 
3444  rte = rt_fetch(rti, es->rtable);
3445  refname = (char *) list_nth(es->rtable_names, rti - 1);
3446  if (refname == NULL)
3447  refname = rte->eref->aliasname;
3448 
3449  switch (nodeTag(plan))
3450  {
3451  case T_SeqScan:
3452  case T_SampleScan:
3453  case T_IndexScan:
3454  case T_IndexOnlyScan:
3455  case T_BitmapHeapScan:
3456  case T_TidScan:
3457  case T_ForeignScan:
3458  case T_CustomScan:
3459  case T_ModifyTable:
3460  /* Assert it's on a real relation */
3461  Assert(rte->rtekind == RTE_RELATION);
3462  objectname = get_rel_name(rte->relid);
3463  if (es->verbose)
3464  namespace = get_namespace_name(get_rel_namespace(rte->relid));
3465  objecttag = "Relation Name";
3466  break;
3467  case T_FunctionScan:
3468  {
3469  FunctionScan *fscan = (FunctionScan *) plan;
3470 
3471  /* Assert it's on a RangeFunction */
3472  Assert(rte->rtekind == RTE_FUNCTION);
3473 
3474  /*
3475  * If the expression is still a function call of a single
3476  * function, we can get the real name of the function.
3477  * Otherwise, punt. (Even if it was a single function call
3478  * originally, the optimizer could have simplified it away.)
3479  */
3480  if (list_length(fscan->functions) == 1)
3481  {
3482  RangeTblFunction *rtfunc = (RangeTblFunction *) linitial(fscan->functions);
3483 
3484  if (IsA(rtfunc->funcexpr, FuncExpr))
3485  {
3486  FuncExpr *funcexpr = (FuncExpr *) rtfunc->funcexpr;
3487  Oid funcid = funcexpr->funcid;
3488 
3489  objectname = get_func_name(funcid);
3490  if (es->verbose)
3491  namespace =
3493  }
3494  }
3495  objecttag = "Function Name";
3496  }
3497  break;
3498  case T_TableFuncScan:
3499  Assert(rte->rtekind == RTE_TABLEFUNC);
3500  objectname = "xmltable";
3501  objecttag = "Table Function Name";
3502  break;
3503  case T_ValuesScan:
3504  Assert(rte->rtekind == RTE_VALUES);
3505  break;
3506  case T_CteScan:
3507  /* Assert it's on a non-self-reference CTE */
3508  Assert(rte->rtekind == RTE_CTE);
3509  Assert(!rte->self_reference);
3510  objectname = rte->ctename;
3511  objecttag = "CTE Name";
3512  break;
3513  case T_NamedTuplestoreScan:
3515  objectname = rte->enrname;
3516  objecttag = "Tuplestore Name";
3517  break;
3518  case T_WorkTableScan:
3519  /* Assert it's on a self-reference CTE */
3520  Assert(rte->rtekind == RTE_CTE);
3521  Assert(rte->self_reference);
3522  objectname = rte->ctename;
3523  objecttag = "CTE Name";
3524  break;
3525  default:
3526  break;
3527  }
3528 
3529  if (es->format == EXPLAIN_FORMAT_TEXT)
3530  {
3531  appendStringInfoString(es->str, " on");
3532  if (namespace != NULL)
3533  appendStringInfo(es->str, " %s.%s", quote_identifier(namespace),
3534  quote_identifier(objectname));
3535  else if (objectname != NULL)
3536  appendStringInfo(es->str, " %s", quote_identifier(objectname));
3537  if (objectname == NULL || strcmp(refname, objectname) != 0)
3538  appendStringInfo(es->str, " %s", quote_identifier(refname));
3539  }
3540  else
3541  {
3542  if (objecttag != NULL && objectname != NULL)
3543  ExplainPropertyText(objecttag, objectname, es);
3544  if (namespace != NULL)
3545  ExplainPropertyText("Schema", namespace, es);
3546  ExplainPropertyText("Alias", refname, es);
3547  }
3548 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10737
Oid get_func_namespace(Oid funcid)
Definition: lsyscache.c:1544
List * functions
Definition: plannodes.h:525
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1864
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:4137
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
#define linitial(l)
Definition: pg_list.h:195
Oid funcid
Definition: primnodes.h:469
static void * list_nth(const List *list, int n)
Definition: pg_list.h:277
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1520
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
char * enrname
Definition: parsenodes.h:1108
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
bool self_reference
Definition: parsenodes.h:1081
bool verbose
Definition: explain.h:41
#define Assert(condition)
Definition: c.h:738
char * aliasname
Definition: primnodes.h:42
static int list_length(const List *l)
Definition: pg_list.h:169
ExplainFormat format
Definition: explain.h:49
#define nodeTag(nodeptr)
Definition: nodes.h:534
RTEKind rtekind
Definition: parsenodes.h:976
char * ctename
Definition: parsenodes.h:1079
Alias * eref
Definition: parsenodes.h:1115
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1840
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 4547 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().

4548 {
4549  const char *s;
4550  const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
4551 
4552  if ((flags & X_NOWHITESPACE) == 0)
4553  appendStringInfoSpaces(es->str, 2 * es->indent);
4554  appendStringInfoCharMacro(es->str, '<');
4555  if ((flags & X_CLOSING) != 0)
4556  appendStringInfoCharMacro(es->str, '/');
4557  for (s = tagname; *s; s++)
4558  appendStringInfoChar(es->str, strchr(valid, *s) ? *s : '-');
4559  if ((flags & X_CLOSE_IMMEDIATE) != 0)
4560  appendStringInfoString(es->str, " /");
4561  appendStringInfoCharMacro(es->str, '>');
4562  if ((flags & X_NOWHITESPACE) == 0)
4563  appendStringInfoCharMacro(es->str, '\n');
4564 }
#define X_CLOSING
Definition: explain.c:52
#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:54
#define X_CLOSE_IMMEDIATE
Definition: explain.c:53
StringInfo str
Definition: explain.h:39

◆ ExplainYAMLLineStarting()

static void ExplainYAMLLineStarting ( ExplainState es)
static

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

4610 {
4612  if (linitial_int(es->grouping_stack) == 0)
4613  {
4614  linitial_int(es->grouping_stack) = 1;
4615  }
4616  else
4617  {
4618  appendStringInfoChar(es->str, '\n');
4619  appendStringInfoSpaces(es->str, es->indent * 2);
4620  }
4621 }
#define linitial_int(l)
Definition: pg_list.h:196
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:738
ExplainFormat format
Definition: explain.h:49
StringInfo str
Definition: explain.h:39

◆ NewExplainState()

ExplainState* NewExplainState ( void  )

Definition at line 309 of file explain.c.

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

Referenced by explain_ExecutorEnd(), and ExplainQuery().

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

◆ report_triggers()

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

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

958 {
959  int nt;
960 
961  if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
962  return;
963  for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
964  {
965  Trigger *trig = rInfo->ri_TrigDesc->triggers + nt;
966  Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
967  char *relname;
968  char *conname = NULL;
969 
970  /* Must clean up instrumentation state */
971  InstrEndLoop(instr);
972 
973  /*
974  * We ignore triggers that were never invoked; they likely aren't
975  * relevant to the current query type.
976  */
977  if (instr->ntuples == 0)
978  continue;
979 
980  ExplainOpenGroup("Trigger", NULL, true, es);
981 
982  relname = RelationGetRelationName(rInfo->ri_RelationDesc);
983  if (OidIsValid(trig->tgconstraint))
984  conname = get_constraint_name(trig->tgconstraint);
985 
986  /*
987  * In text format, we avoid printing both the trigger name and the
988  * constraint name unless VERBOSE is specified. In non-text formats
989  * we just print everything.
990  */
991  if (es->format == EXPLAIN_FORMAT_TEXT)
992  {
993  if (es->verbose || conname == NULL)
994  appendStringInfo(es->str, "Trigger %s", trig->tgname);
995  else
996  appendStringInfoString(es->str, "Trigger");
997  if (conname)
998  appendStringInfo(es->str, " for constraint %s", conname);
999  if (show_relname)
1000  appendStringInfo(es->str, " on %s", relname);
1001  if (es->timing)
1002  appendStringInfo(es->str, ": time=%.3f calls=%.0f\n",
1003  1000.0 * instr->total, instr->ntuples);
1004  else
1005  appendStringInfo(es->str, ": calls=%.0f\n", instr->ntuples);
1006  }
1007  else
1008  {
1009  ExplainPropertyText("Trigger Name", trig->tgname, es);
1010  if (conname)
1011  ExplainPropertyText("Constraint Name", conname, es);
1012  ExplainPropertyText("Relation", relname, es);
1013  if (es->timing)
1014  ExplainPropertyFloat("Time", "ms", 1000.0 * instr->total, 3,
1015  es);
1016  ExplainPropertyFloat("Calls", NULL, instr->ntuples, 0, es);
1017  }
1018 
1019  if (conname)
1020  pfree(conname);
1021 
1022  ExplainCloseGroup("Trigger", NULL, true, es);
1023  }
1024 }
Relation ri_RelationDesc
Definition: execnodes.h:413
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:1079
void ExplainPropertyFloat(const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
Definition: explain.c:4173
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:434
NameData relname
Definition: pg_class.h:38
#define OidIsValid(objectId)
Definition: c.h:644
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:121
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:4137
void pfree(void *pointer)
Definition: mcxt.c:1056
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
Oid tgconstraint
Definition: reltrigger.h:35
char * tgname
Definition: reltrigger.h:27
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
Trigger * triggers
Definition: reltrigger.h:49
#define RelationGetRelationName(relation)
Definition: rel.h:490
double ntuples
Definition: instrument.h:69
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:425
bool timing
Definition: explain.h:46
int numtriggers
Definition: reltrigger.h:50
bool verbose
Definition: explain.h:41
ExplainFormat format
Definition: explain.h:49
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4265
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4202
StringInfo str
Definition: explain.h:39

◆ show_agg_keys()

static void show_agg_keys ( AggState astate,
List ancestors,
ExplainState es 
)
static

Definition at line 2329 of file explain.c.

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

Referenced by ExplainNode().

2331 {
2332  Agg *plan = (Agg *) astate->ss.ps.plan;
2333 
2334  if (plan->numCols > 0 || plan->groupingSets)
2335  {
2336  /* The key columns refer to the tlist of the child plan */
2337  ancestors = lcons(plan, ancestors);
2338 
2339  if (plan->groupingSets)
2340  show_grouping_sets(outerPlanState(astate), plan, ancestors, es);
2341  else
2342  show_sort_group_keys(outerPlanState(astate), "Group Key",
2343  plan->numCols, 0, plan->grpColIdx,
2344  NULL, NULL, NULL,
2345  ancestors, es);
2346 
2347  ancestors = list_delete_first(ancestors);
2348  }
2349 }
int numCols
Definition: plannodes.h:821
AttrNumber * grpColIdx
Definition: plannodes.h:822
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)
Definition: explain.c:2481
ScanState ss
Definition: execnodes.h:2125
PlanState ps
Definition: execnodes.h:1332
#define outerPlanState(node)
Definition: execnodes.h:1039
static void show_grouping_sets(PlanState *planstate, Agg *agg, List *ancestors, ExplainState *es)