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_merge_append_keys (MergeAppendState *mstate, List *ancestors, ExplainState *es)
 
static void show_agg_keys (AggState *astate, List *ancestors, ExplainState *es)
 
static void show_grouping_sets (PlanState *planstate, Agg *agg, List *ancestors, ExplainState *es)
 
static void show_grouping_set_keys (PlanState *planstate, Agg *aggnode, Sort *sortnode, List *context, bool useprefix, List *ancestors, ExplainState *es)
 
static void show_group_keys (GroupState *gstate, List *ancestors, ExplainState *es)
 
static void show_sort_group_keys (PlanState *planstate, const char *qlabel, int nkeys, AttrNumber *keycols, Oid *sortOperators, Oid *collations, bool *nullsFirst, List *ancestors, ExplainState *es)
 
static void show_sortorder_options (StringInfo buf, Node *sortexpr, Oid sortOperator, Oid collation, bool nullsFirst)
 
static void show_tablesample (TableSampleClause *tsc, PlanState *planstate, List *ancestors, ExplainState *es)
 
static void show_sort_info (SortState *sortstate, ExplainState *es)
 
static void show_hash_info (HashState *hashstate, ExplainState *es)
 
static void show_tidbitmap_info (BitmapHeapScanState *planstate, ExplainState *es)
 
static void show_instrumentation_count (const char *qlabel, int which, PlanState *planstate, ExplainState *es)
 
static void show_foreignscan_info (ForeignScanState *fsstate, ExplainState *es)
 
static 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 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 nsubnodes, int nplans, List *ancestors, ExplainState *es)
 
static void ExplainSubPlans (List *plans, List *ancestors, const char *relationship, ExplainState *es)
 
static void ExplainCustomChildren (CustomScanState *css, List *ancestors, ExplainState *es)
 
static 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)
 
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)
 
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 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 984 of file explain.c.

References INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, and INSTR_TIME_SUBTRACT.

Referenced by ExplainOnePlan(), and IsCheckpointOnSchedule().

985 {
986  instr_time endtime;
987 
988  INSTR_TIME_SET_CURRENT(endtime);
989  INSTR_TIME_SUBTRACT(endtime, *starttime);
990  return INSTR_TIME_GET_DOUBLE(endtime);
991 }
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 4254 of file explain.c.

References escape_json().

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

4255 {
4256  escape_json(buf, str);
4257 }
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 2862 of file explain.c.

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

Referenced by ExplainIndexScanDetails(), and ExplainNode().

2863 {
2864  const char *result;
2865 
2867  result = (*explain_get_index_name_hook) (indexId);
2868  else
2869  result = NULL;
2870  if (result == NULL)
2871  {
2872  /* default behavior: look in the catalogs and quote it */
2873  result = get_rel_name(indexId);
2874  if (result == NULL)
2875  elog(ERROR, "cache lookup failed for index %u", indexId);
2876  result = quote_identifier(result);
2877  }
2878  return result;
2879 }
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10697
#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:228
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730

◆ ExplainBeginOutput()

void ExplainBeginOutput ( ExplainState es)

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

4079 {
4080  switch (es->format)
4081  {
4082  case EXPLAIN_FORMAT_TEXT:
4083  /* nothing to do */
4084  break;
4085 
4086  case EXPLAIN_FORMAT_XML:
4088  "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
4089  es->indent++;
4090  break;
4091 
4092  case EXPLAIN_FORMAT_JSON:
4093  /* top-level structure is an array of plans */
4094  appendStringInfoChar(es->str, '[');
4095  es->grouping_stack = lcons_int(0, es->grouping_stack);
4096  es->indent++;
4097  break;
4098 
4099  case EXPLAIN_FORMAT_YAML:
4100  es->grouping_stack = lcons_int(0, es->grouping_stack);
4101  break;
4102  }
4103 }
List * lcons_int(int datum, List *list)
Definition: list.c:472
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
List * grouping_stack
Definition: explain.h:51
int indent
Definition: explain.h:50
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
ExplainFormat format
Definition: explain.h:48
StringInfo str
Definition: explain.h:39

◆ ExplainCloseGroup()

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

Definition at line 3885 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(), and show_modifytable_info().

3887 {
3888  switch (es->format)
3889  {
3890  case EXPLAIN_FORMAT_TEXT:
3891  /* nothing to do */
3892  break;
3893 
3894  case EXPLAIN_FORMAT_XML:
3895  es->indent--;
3896  ExplainXMLTag(objtype, X_CLOSING, es);
3897  break;
3898 
3899  case EXPLAIN_FORMAT_JSON:
3900  es->indent--;
3901  appendStringInfoChar(es->str, '\n');
3902  appendStringInfoSpaces(es->str, 2 * es->indent);
3903  appendStringInfoChar(es->str, labeled ? '}' : ']');
3905  break;
3906 
3907  case EXPLAIN_FORMAT_YAML:
3908  es->indent--;
3910  break;
3911  }
3912 }
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:4167
#define X_CLOSING
Definition: explain.c:52
List * grouping_stack
Definition: explain.h:51
int indent
Definition: explain.h:50
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:48
StringInfo str
Definition: explain.h:39
List * list_delete_first(List *list)
Definition: list.c:861

◆ ExplainCloseWorker()

static void ExplainCloseWorker ( int  n,
ExplainState es 
)
static

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

3529 {
3530  ExplainWorkersState *wstate = es->workers_state;
3531 
3532  Assert(wstate);
3533  Assert(n >= 0 && n < wstate->num_workers);
3534  Assert(wstate->worker_inited[n]);
3535 
3536  /*
3537  * Save formatting state in case we do another ExplainOpenWorker(), then
3538  * pop the formatting stack.
3539  */
3540  ExplainSaveGroup(es, 2, &wstate->worker_state_save[n]);
3541 
3542  /*
3543  * In TEXT format, if we didn't actually produce any output line(s) then
3544  * truncate off the partial line emitted by ExplainOpenWorker. (This is
3545  * to avoid bogus output if, say, show_buffer_usage chooses not to print
3546  * anything for the worker.) Also fix up the indent level.
3547  */
3548  if (es->format == EXPLAIN_FORMAT_TEXT)
3549  {
3550  while (es->str->len > 0 && es->str->data[es->str->len - 1] != '\n')
3551  es->str->data[--(es->str->len)] = '\0';
3552 
3553  es->indent--;
3554  }
3555 
3556  /* Restore prior output buffer pointer */
3557  es->str = wstate->prev_str;
3558 }
int * worker_state_save
Definition: explain.h:33
int indent
Definition: explain.h:50
bool * worker_inited
Definition: explain.h:31
#define Assert(condition)
Definition: c.h:739
ExplainWorkersState * workers_state
Definition: explain.h:60
ExplainFormat format
Definition: explain.h:48
StringInfo prev_str
Definition: explain.h:34
static void ExplainSaveGroup(ExplainState *es, int depth, int *state_save)
Definition: explain.c:3971
StringInfo str
Definition: explain.h:39

◆ ExplainCreateWorkersState()

static ExplainWorkersState * ExplainCreateWorkersState ( int  num_workers)
static

Definition at line 3449 of file explain.c.

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

Referenced by ExplainNode().

3450 {
3451  ExplainWorkersState *wstate;
3452 
3453  wstate = (ExplainWorkersState *) palloc(sizeof(ExplainWorkersState));
3454  wstate->num_workers = num_workers;
3455  wstate->worker_inited = (bool *) palloc0(num_workers * sizeof(bool));
3456  wstate->worker_str = (StringInfoData *)
3457  palloc0(num_workers * sizeof(StringInfoData));
3458  wstate->worker_state_save = (int *) palloc(num_workers * sizeof(int));
3459  return wstate;
3460 }
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 3427 of file explain.c.

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

Referenced by ExplainNode().

3428 {
3429  ListCell *cell;
3430  const char *label =
3431  (list_length(css->custom_ps) != 1 ? "children" : "child");
3432 
3433  foreach(cell, css->custom_ps)
3434  ExplainNode((PlanState *) lfirst(cell), ancestors, label, NULL, es);
3435 }
List * custom_ps
Definition: execnodes.h:1816
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1077
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 4032 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().

4033 {
4034  switch (es->format)
4035  {
4036  case EXPLAIN_FORMAT_TEXT:
4037  /* nothing to do */
4038  break;
4039 
4040  case EXPLAIN_FORMAT_XML:
4041  ExplainXMLTag(objtype, X_CLOSE_IMMEDIATE, es);
4042  break;
4043 
4044  case EXPLAIN_FORMAT_JSON:
4046  appendStringInfoSpaces(es->str, 2 * es->indent);
4047  if (labelname)
4048  {
4049  escape_json(es->str, labelname);
4050  appendStringInfoString(es->str, ": ");
4051  }
4052  escape_json(es->str, objtype);
4053  break;
4054 
4055  case EXPLAIN_FORMAT_YAML:
4057  if (labelname)
4058  {
4059  escape_yaml(es->str, labelname);
4060  appendStringInfoString(es->str, ": ");
4061  }
4062  else
4063  {
4064  appendStringInfoString(es->str, "- ");
4065  }
4066  escape_yaml(es->str, objtype);
4067  break;
4068  }
4069 }
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:4167
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:4229
int indent
Definition: explain.h:50
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:4254
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:4209
ExplainFormat format
Definition: explain.h:48
#define X_CLOSE_IMMEDIATE
Definition: explain.c:53
StringInfo str
Definition: explain.h:39

◆ ExplainEndOutput()

void ExplainEndOutput ( ExplainState es)

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

4110 {
4111  switch (es->format)
4112  {
4113  case EXPLAIN_FORMAT_TEXT:
4114  /* nothing to do */
4115  break;
4116 
4117  case EXPLAIN_FORMAT_XML:
4118  es->indent--;
4119  appendStringInfoString(es->str, "</explain>");
4120  break;
4121 
4122  case EXPLAIN_FORMAT_JSON:
4123  es->indent--;
4124  appendStringInfoString(es->str, "\n]");
4126  break;
4127 
4128  case EXPLAIN_FORMAT_YAML:
4130  break;
4131  }
4132 }
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
List * grouping_stack
Definition: explain.h:51
int indent
Definition: explain.h:50
ExplainFormat format
Definition: explain.h:48
StringInfo str
Definition: explain.h:39
List * list_delete_first(List *list)
Definition: list.c:861

◆ ExplainFlushWorkersState()

static void ExplainFlushWorkersState ( ExplainState es)
static

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

3565 {
3566  ExplainWorkersState *wstate = es->workers_state;
3567 
3568  ExplainOpenGroup("Workers", "Workers", false, es);
3569  for (int i = 0; i < wstate->num_workers; i++)
3570  {
3571  if (wstate->worker_inited[i])
3572  {
3573  /* This must match previous ExplainOpenSetAsideGroup call */
3574  ExplainOpenGroup("Worker", NULL, true, es);
3575  appendStringInfoString(es->str, wstate->worker_str[i].data);
3576  ExplainCloseGroup("Worker", NULL, true, es);
3577 
3578  pfree(wstate->worker_str[i].data);
3579  }
3580  }
3581  ExplainCloseGroup("Workers", "Workers", false, es);
3582 
3583  pfree(wstate->worker_inited);
3584  pfree(wstate->worker_str);
3585  pfree(wstate->worker_state_save);
3586  pfree(wstate);
3587 }
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:60
int i
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3885
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3822
StringInfo str
Definition: explain.h:39

◆ ExplainIndentText()

static void ExplainIndentText ( ExplainState es)
static

Definition at line 4194 of file explain.c.

References appendStringInfoSpaces(), Assert, StringInfoData::data, EXPLAIN_FORMAT_TEXT, ExplainState::format, ExplainState::indent, StringInfoData::len, and ExplainState::str.

Referenced by ExplainNode(), ExplainOpenWorker(), ExplainPrintJIT(), ExplainProperty(), ExplainPropertyList(), show_buffer_usage(), show_hash_info(), show_modifytable_info(), show_sort_info(), show_tablesample(), and show_tidbitmap_info().

4195 {
4197  if (es->str->len == 0 || es->str->data[es->str->len - 1] == '\n')
4198  appendStringInfoSpaces(es->str, es->indent * 2);
4199 }
int indent
Definition: explain.h:50
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
#define Assert(condition)
Definition: c.h:739
ExplainFormat format
Definition: explain.h:48
StringInfo str
Definition: explain.h:39

◆ ExplainIndexScanDetails()

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

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

3011 {
3012  const char *indexname = explain_get_index_name(indexid);
3013 
3014  if (es->format == EXPLAIN_FORMAT_TEXT)
3015  {
3016  if (ScanDirectionIsBackward(indexorderdir))
3017  appendStringInfoString(es->str, " Backward");
3018  appendStringInfo(es->str, " using %s", indexname);
3019  }
3020  else
3021  {
3022  const char *scandir;
3023 
3024  switch (indexorderdir)
3025  {
3026  case BackwardScanDirection:
3027  scandir = "Backward";
3028  break;
3030  scandir = "NoMovement";
3031  break;
3032  case ForwardScanDirection:
3033  scandir = "Forward";
3034  break;
3035  default:
3036  scandir = "???";
3037  break;
3038  }
3039  ExplainPropertyText("Scan Direction", scandir, es);
3040  ExplainPropertyText("Index Name", indexname, es);
3041  }
3042 }
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3770
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:48
static const char * explain_get_index_name(Oid indexId)
Definition: explain.c:2862
StringInfo str
Definition: explain.h:39

◆ ExplainJSONLineEnding()

static void ExplainJSONLineEnding ( ExplainState es)
static

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

4210 {
4212  if (linitial_int(es->grouping_stack) != 0)
4213  appendStringInfoChar(es->str, ',');
4214  else
4215  linitial_int(es->grouping_stack) = 1;
4216  appendStringInfoChar(es->str, '\n');
4217 }
#define linitial_int(l)
Definition: pg_list.h:196
List * grouping_stack
Definition: explain.h:51
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
#define Assert(condition)
Definition: c.h:739
ExplainFormat format
Definition: explain.h:48
StringInfo str
Definition: explain.h:39

◆ ExplainMemberNodes()

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

Definition at line 3357 of file explain.c.

References ExplainNode(), and ExplainPropertyInteger().

Referenced by ExplainNode().

3359 {
3360  int j;
3361 
3362  /*
3363  * The number of subnodes being lower than the number of subplans that was
3364  * specified in the plan means that some subnodes have been ignored per
3365  * instruction for the partition pruning code during the executor
3366  * initialization. To make this a bit less mysterious, we'll indicate
3367  * here that this has happened.
3368  */
3369  if (nsubnodes < nplans)
3370  ExplainPropertyInteger("Subplans Removed", NULL, nplans - nsubnodes, es);
3371 
3372  for (j = 0; j < nsubnodes; j++)
3373  ExplainNode(planstates[j], ancestors,
3374  "Member", NULL, es);
3375 }
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:3779
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1077

◆ ExplainModifyTarget()

static void ExplainModifyTarget ( ModifyTable plan,
ExplainState es 
)
static

Definition at line 3061 of file explain.c.

References ExplainTargetRel().

Referenced by ExplainNode().

3062 {
3063  ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
3064 }
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:3070

◆ ExplainNode()

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

Definition at line 1077 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(), 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_instrumentation_count(), show_merge_append_keys(), show_modifytable_info(), show_plan_tlist(), show_scan_qual(), show_sort_info(), show_sort_keys(), show_tablesample(), show_tidbitmap_info(), show_upper_qual(), Gather::single_copy, Instrumentation::startup, Plan::startup_cost, 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_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, PlanState::worker_instrument, PlanState::worker_jit_instrument, and ExplainState::workers_state.

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

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

◆ ExplainOnePlan()

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

Definition at line 475 of file explain.c.

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

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

478 {
480  QueryDesc *queryDesc;
481  instr_time starttime;
482  double totaltime = 0;
483  int eflags;
484  int instrument_option = 0;
485 
486  Assert(plannedstmt->commandType != CMD_UTILITY);
487 
488  if (es->analyze && es->timing)
489  instrument_option |= INSTRUMENT_TIMER;
490  else if (es->analyze)
491  instrument_option |= INSTRUMENT_ROWS;
492 
493  if (es->buffers)
494  instrument_option |= INSTRUMENT_BUFFERS;
495 
496  /*
497  * We always collect timing for the entire statement, even when node-level
498  * timing is off, so we don't look at es->timing here. (We could skip
499  * this if !es->summary, but it's hardly worth the complication.)
500  */
501  INSTR_TIME_SET_CURRENT(starttime);
502 
503  /*
504  * Use a snapshot with an updated command ID to ensure this query sees
505  * results of any previously executed queries.
506  */
509 
510  /*
511  * Normally we discard the query's output, but if explaining CREATE TABLE
512  * AS, we'd better use the appropriate tuple receiver.
513  */
514  if (into)
515  dest = CreateIntoRelDestReceiver(into);
516  else
517  dest = None_Receiver;
518 
519  /* Create a QueryDesc for the query */
520  queryDesc = CreateQueryDesc(plannedstmt, queryString,
522  dest, params, queryEnv, instrument_option);
523 
524  /* Select execution options */
525  if (es->analyze)
526  eflags = 0; /* default run-to-completion flags */
527  else
528  eflags = EXEC_FLAG_EXPLAIN_ONLY;
529  if (into)
530  eflags |= GetIntoRelEFlags(into);
531 
532  /* call ExecutorStart to prepare the plan for execution */
533  ExecutorStart(queryDesc, eflags);
534 
535  /* Execute the plan for statistics if asked for */
536  if (es->analyze)
537  {
538  ScanDirection dir;
539 
540  /* EXPLAIN ANALYZE CREATE TABLE AS WITH NO DATA is weird */
541  if (into && into->skipData)
543  else
544  dir = ForwardScanDirection;
545 
546  /* run the plan */
547  ExecutorRun(queryDesc, dir, 0L, true);
548 
549  /* run cleanup too */
550  ExecutorFinish(queryDesc);
551 
552  /* We can't run ExecutorEnd 'till we're done printing the stats... */
553  totaltime += elapsed_time(&starttime);
554  }
555 
556  ExplainOpenGroup("Query", NULL, true, es);
557 
558  /* Create textual dump of plan tree */
559  ExplainPrintPlan(es, queryDesc);
560 
561  if (es->summary && planduration)
562  {
563  double plantime = INSTR_TIME_GET_DOUBLE(*planduration);
564 
565  ExplainPropertyFloat("Planning Time", "ms", 1000.0 * plantime, 3, es);
566  }
567 
568  /* Print info about runtime of triggers */
569  if (es->analyze)
570  ExplainPrintTriggers(es, queryDesc);
571 
572  /*
573  * Print info about JITing. Tied to es->costs because we don't want to
574  * display this in regression tests, as it'd cause output differences
575  * depending on build options. Might want to separate that out from COSTS
576  * at a later stage.
577  */
578  if (es->costs)
579  ExplainPrintJITSummary(es, queryDesc);
580 
581  /*
582  * Close down the query and free resources. Include time for this in the
583  * total execution time (although it should be pretty minimal).
584  */
585  INSTR_TIME_SET_CURRENT(starttime);
586 
587  ExecutorEnd(queryDesc);
588 
589  FreeQueryDesc(queryDesc);
590 
592 
593  /* We need a CCI just in case query expanded to multiple plans */
594  if (es->analyze)
596 
597  totaltime += elapsed_time(&starttime);
598 
599  /*
600  * We only report execution time if we actually ran the query (that is,
601  * the user specified ANALYZE), and if summary reporting is enabled (the
602  * user can set SUMMARY OFF to not have the timing information included in
603  * the output). By default, ANALYZE sets SUMMARY to true.
604  */
605  if (es->summary && es->analyze)
606  ExplainPropertyFloat("Execution Time", "ms", 1000.0 * totaltime, 3,
607  es);
608 
609  ExplainCloseGroup("Query", NULL, true, es);
610 }
bool summary
Definition: explain.h:46
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:3793
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:394
void ExplainPrintTriggers(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:736
void ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:687
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:412
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:402
bool timing
Definition: explain.h:45
#define InvalidSnapshot
Definition: snapshot.h:123
void CommandCounterIncrement(void)
Definition: xact.c:1005
CmdType commandType
Definition: plannodes.h:46
#define Assert(condition)
Definition: c.h:739
static double elapsed_time(instr_time *starttime)
Definition: explain.c:984
#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:3885
void ExplainPrintJITSummary(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:782
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3822
#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 351 of file explain.c.

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

Referenced by ExplainOneUtility(), and ExplainQuery().

355 {
356  /* planner will not cope with utility statements */
357  if (query->commandType == CMD_UTILITY)
358  {
359  ExplainOneUtility(query->utilityStmt, into, es, queryString, params,
360  queryEnv);
361  return;
362  }
363 
364  /* if an advisor plugin is present, let it manage things */
366  (*ExplainOneQuery_hook) (query, cursorOptions, into, es,
367  queryString, params, queryEnv);
368  else
369  {
370  PlannedStmt *plan;
371  instr_time planstart,
372  planduration;
373 
374  INSTR_TIME_SET_CURRENT(planstart);
375 
376  /* plan the query */
377  plan = pg_plan_query(query, cursorOptions, params);
378 
379  INSTR_TIME_SET_CURRENT(planduration);
380  INSTR_TIME_SUBTRACT(planduration, planstart);
381 
382  /* run it (if needed) and produce output */
383  ExplainOnePlan(plan, into, es, queryString, params, queryEnv,
384  &planduration);
385  }
386 }
void ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv, const instr_time *planduration)
Definition: explain.c:475
struct timeval instr_time
Definition: instr_time.h:150
Node * utilityStmt
Definition: parsenodes.h:120
#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
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
void ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: explain.c:400
PlannedStmt * pg_plan_query(Query *querytree, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:857

◆ ExplainOneUtility()

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

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

403 {
404  if (utilityStmt == NULL)
405  return;
406 
407  if (IsA(utilityStmt, CreateTableAsStmt))
408  {
409  /*
410  * We have to rewrite the contained SELECT and then pass it back to
411  * ExplainOneQuery. It's probably not really necessary to copy the
412  * contained parsetree another time, but let's be safe.
413  */
414  CreateTableAsStmt *ctas = (CreateTableAsStmt *) utilityStmt;
415  List *rewritten;
416 
417  rewritten = QueryRewrite(castNode(Query, copyObject(ctas->query)));
418  Assert(list_length(rewritten) == 1);
419  ExplainOneQuery(linitial_node(Query, rewritten),
420  CURSOR_OPT_PARALLEL_OK, ctas->into, es,
421  queryString, params, queryEnv);
422  }
423  else if (IsA(utilityStmt, DeclareCursorStmt))
424  {
425  /*
426  * Likewise for DECLARE CURSOR.
427  *
428  * Notice that if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll
429  * actually run the query. This is different from pre-8.3 behavior
430  * but seems more useful than not running the query. No cursor will
431  * be created, however.
432  */
433  DeclareCursorStmt *dcs = (DeclareCursorStmt *) utilityStmt;
434  List *rewritten;
435 
436  rewritten = QueryRewrite(castNode(Query, copyObject(dcs->query)));
437  Assert(list_length(rewritten) == 1);
438  ExplainOneQuery(linitial_node(Query, rewritten),
439  dcs->options, NULL, es,
440  queryString, params, queryEnv);
441  }
442  else if (IsA(utilityStmt, ExecuteStmt))
443  ExplainExecuteQuery((ExecuteStmt *) utilityStmt, into, es,
444  queryString, params, queryEnv);
445  else if (IsA(utilityStmt, NotifyStmt))
446  {
447  if (es->format == EXPLAIN_FORMAT_TEXT)
448  appendStringInfoString(es->str, "NOTIFY\n");
449  else
450  ExplainDummyGroup("Notify", NULL, es);
451  }
452  else
453  {
454  if (es->format == EXPLAIN_FORMAT_TEXT)
456  "Utility statements have no plan structure\n");
457  else
458  ExplainDummyGroup("Utility Statement", NULL, es);
459  }
460 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
List * QueryRewrite(Query *parsetree)
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
#define linitial_node(type, l)
Definition: pg_list.h:198
static void ExplainDummyGroup(const char *objtype, const char *labelname, ExplainState *es)
Definition: explain.c:4032
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:351
IntoClause * into
Definition: parsenodes.h:3261
#define Assert(condition)
Definition: c.h:739
static int list_length(const List *l)
Definition: pg_list.h:169
ExplainFormat format
Definition: explain.h:48
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2712
#define copyObject(obj)
Definition: nodes.h:641
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 3822 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(), and show_modifytable_info().

3824 {
3825  switch (es->format)
3826  {
3827  case EXPLAIN_FORMAT_TEXT:
3828  /* nothing to do */
3829  break;
3830 
3831  case EXPLAIN_FORMAT_XML:
3832  ExplainXMLTag(objtype, X_OPENING, es);
3833  es->indent++;
3834  break;
3835 
3836  case EXPLAIN_FORMAT_JSON:
3838  appendStringInfoSpaces(es->str, 2 * es->indent);
3839  if (labelname)
3840  {
3841  escape_json(es->str, labelname);
3842  appendStringInfoString(es->str, ": ");
3843  }
3844  appendStringInfoChar(es->str, labeled ? '{' : '[');
3845 
3846  /*
3847  * In JSON format, the grouping_stack is an integer list. 0 means
3848  * we've emitted nothing at this grouping level, 1 means we've
3849  * emitted something (and so the next item needs a comma). See
3850  * ExplainJSONLineEnding().
3851  */
3852  es->grouping_stack = lcons_int(0, es->grouping_stack);
3853  es->indent++;
3854  break;
3855 
3856  case EXPLAIN_FORMAT_YAML:
3857 
3858  /*
3859  * In YAML format, the grouping stack is an integer list. 0 means
3860  * we've emitted nothing at this grouping level AND this grouping
3861  * level is unlabelled and must be marked with "- ". See
3862  * ExplainYAMLLineStarting().
3863  */
3865  if (labelname)
3866  {
3867  appendStringInfo(es->str, "%s: ", labelname);
3868  es->grouping_stack = lcons_int(1, es->grouping_stack);
3869  }
3870  else
3871  {
3872  appendStringInfoString(es->str, "- ");
3873  es->grouping_stack = lcons_int(0, es->grouping_stack);
3874  }
3875  es->indent++;
3876  break;
3877  }
3878 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:1279
List * lcons_int(int datum, List *list)
Definition: list.c:472
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:4167
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:4229
List * grouping_stack
Definition: explain.h:51
int indent
Definition: explain.h:50
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:4209
#define X_OPENING
Definition: explain.c:51
ExplainFormat format
Definition: explain.h:48
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 3932 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().

3934 {
3935  switch (es->format)
3936  {
3937  case EXPLAIN_FORMAT_TEXT:
3938  /* nothing to do */
3939  break;
3940 
3941  case EXPLAIN_FORMAT_XML:
3942  es->indent += depth;
3943  break;
3944 
3945  case EXPLAIN_FORMAT_JSON:
3946  es->grouping_stack = lcons_int(0, es->grouping_stack);
3947  es->indent += depth;
3948  break;
3949 
3950  case EXPLAIN_FORMAT_YAML:
3951  if (labelname)
3952  es->grouping_stack = lcons_int(1, es->grouping_stack);
3953  else
3954  es->grouping_stack = lcons_int(0, es->grouping_stack);
3955  es->indent += depth;
3956  break;
3957  }
3958 }
List * lcons_int(int datum, List *list)
Definition: list.c:472
List * grouping_stack
Definition: explain.h:51
int indent
Definition: explain.h:50
ExplainFormat format
Definition: explain.h:48

◆ ExplainOpenWorker()

static void ExplainOpenWorker ( int  n,
ExplainState es 
)
static

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

3467 {
3468  ExplainWorkersState *wstate = es->workers_state;
3469 
3470  Assert(wstate);
3471  Assert(n >= 0 && n < wstate->num_workers);
3472 
3473  /* Save prior output buffer pointer */
3474  wstate->prev_str = es->str;
3475 
3476  if (!wstate->worker_inited[n])
3477  {
3478  /* First time through, so create the buffer for this worker */
3479  initStringInfo(&wstate->worker_str[n]);
3480  es->str = &wstate->worker_str[n];
3481 
3482  /*
3483  * Push suitable initial formatting state for this worker's field
3484  * group. We allow one extra logical nesting level, since this group
3485  * will eventually be wrapped in an outer "Workers" group.
3486  */
3487  ExplainOpenSetAsideGroup("Worker", NULL, true, 2, es);
3488 
3489  /*
3490  * In non-TEXT formats we always emit a "Worker Number" field, even if
3491  * there's no other data for this worker.
3492  */
3493  if (es->format != EXPLAIN_FORMAT_TEXT)
3494  ExplainPropertyInteger("Worker Number", NULL, n, es);
3495 
3496  wstate->worker_inited[n] = true;
3497  }
3498  else
3499  {
3500  /* Resuming output for a worker we've already emitted some data for */
3501  es->str = &wstate->worker_str[n];
3502 
3503  /* Restore formatting state saved by last ExplainCloseWorker() */
3504  ExplainRestoreGroup(es, 2, &wstate->worker_state_save[n]);
3505  }
3506 
3507  /*
3508  * In TEXT format, prefix the first output line for this worker with
3509  * "Worker N:". Then, any additional lines should be indented one more
3510  * stop than the "Worker N" line is.
3511  */
3512  if (es->format == EXPLAIN_FORMAT_TEXT)
3513  {
3514  if (es->str->len == 0)
3515  {
3516  ExplainIndentText(es);
3517  appendStringInfo(es->str, "Worker %d: ", n);
3518  }
3519 
3520  es->indent++;
3521  }
3522 }
int * worker_state_save
Definition: explain.h:33
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:3779
static void ExplainRestoreGroup(ExplainState *es, int depth, int *state_save)
Definition: explain.c:4001
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
StringInfoData * worker_str
Definition: explain.h:32
int indent
Definition: explain.h:50
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
bool * worker_inited
Definition: explain.h:31
static void ExplainIndentText(ExplainState *es)
Definition: explain.c:4194
#define Assert(condition)
Definition: c.h:739
ExplainWorkersState * workers_state
Definition: explain.h:60
ExplainFormat format
Definition: explain.h:48
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:3932

◆ ExplainPreScanNode()

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

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

1004 {
1005  Plan *plan = planstate->plan;
1006 
1007  switch (nodeTag(plan))
1008  {
1009  case T_SeqScan:
1010  case T_SampleScan:
1011  case T_IndexScan:
1012  case T_IndexOnlyScan:
1013  case T_BitmapHeapScan:
1014  case T_TidScan:
1015  case T_SubqueryScan:
1016  case T_FunctionScan:
1017  case T_TableFuncScan:
1018  case T_ValuesScan:
1019  case T_CteScan:
1020  case T_NamedTuplestoreScan:
1021  case T_WorkTableScan:
1022  *rels_used = bms_add_member(*rels_used,
1023  ((Scan *) plan)->scanrelid);
1024  break;
1025  case T_ForeignScan:
1026  *rels_used = bms_add_members(*rels_used,
1027  ((ForeignScan *) plan)->fs_relids);
1028  break;
1029  case T_CustomScan:
1030  *rels_used = bms_add_members(*rels_used,
1031  ((CustomScan *) plan)->custom_relids);
1032  break;
1033  case T_ModifyTable:
1034  *rels_used = bms_add_member(*rels_used,
1035  ((ModifyTable *) plan)->nominalRelation);
1036  if (((ModifyTable *) plan)->exclRelRTI)
1037  *rels_used = bms_add_member(*rels_used,
1038  ((ModifyTable *) plan)->exclRelRTI);
1039  break;
1040  case T_Append:
1041  *rels_used = bms_add_members(*rels_used,
1042  ((Append *) plan)->apprelids);
1043  break;
1044  case T_MergeAppend:
1045  *rels_used = bms_add_members(*rels_used,
1046  ((MergeAppend *) plan)->apprelids);
1047  break;
1048  default:
1049  break;
1050  }
1051 
1052  return planstate_tree_walker(planstate, ExplainPreScanNode, rels_used);
1053 }
Definition: nodes.h:49
Plan * plan
Definition: execnodes.h:939
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define nodeTag(nodeptr)
Definition: nodes.h:530
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
Definition: explain.c:1003
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 808 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().

809 {
810  instr_time total_time;
811 
812  /* don't print information if no JITing happened */
813  if (!ji || ji->created_functions == 0)
814  return;
815 
816  /* calculate total time */
817  INSTR_TIME_SET_ZERO(total_time);
818  INSTR_TIME_ADD(total_time, ji->generation_counter);
819  INSTR_TIME_ADD(total_time, ji->inlining_counter);
820  INSTR_TIME_ADD(total_time, ji->optimization_counter);
821  INSTR_TIME_ADD(total_time, ji->emission_counter);
822 
823  ExplainOpenGroup("JIT", "JIT", true, es);
824 
825  /* for higher density, open code the text output format */
826  if (es->format == EXPLAIN_FORMAT_TEXT)
827  {
828  ExplainIndentText(es);
829  appendStringInfoString(es->str, "JIT:\n");
830  es->indent++;
831 
832  ExplainPropertyInteger("Functions", NULL, ji->created_functions, es);
833 
834  ExplainIndentText(es);
835  appendStringInfo(es->str, "Options: %s %s, %s %s, %s %s, %s %s\n",
836  "Inlining", jit_flags & PGJIT_INLINE ? "true" : "false",
837  "Optimization", jit_flags & PGJIT_OPT3 ? "true" : "false",
838  "Expressions", jit_flags & PGJIT_EXPR ? "true" : "false",
839  "Deforming", jit_flags & PGJIT_DEFORM ? "true" : "false");
840 
841  if (es->analyze && es->timing)
842  {
843  ExplainIndentText(es);
844  appendStringInfo(es->str,
845  "Timing: %s %.3f ms, %s %.3f ms, %s %.3f ms, %s %.3f ms, %s %.3f ms\n",
846  "Generation", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->generation_counter),
847  "Inlining", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->inlining_counter),
848  "Optimization", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->optimization_counter),
849  "Emission", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->emission_counter),
850  "Total", 1000.0 * INSTR_TIME_GET_DOUBLE(total_time));
851  }
852 
853  es->indent--;
854  }
855  else
856  {
857  ExplainPropertyInteger("Functions", NULL, ji->created_functions, es);
858 
859  ExplainOpenGroup("Options", "Options", true, es);
860  ExplainPropertyBool("Inlining", jit_flags & PGJIT_INLINE, es);
861  ExplainPropertyBool("Optimization", jit_flags & PGJIT_OPT3, es);
862  ExplainPropertyBool("Expressions", jit_flags & PGJIT_EXPR, es);
863  ExplainPropertyBool("Deforming", jit_flags & PGJIT_DEFORM, es);
864  ExplainCloseGroup("Options", "Options", true, es);
865 
866  if (es->analyze && es->timing)
867  {
868  ExplainOpenGroup("Timing", "Timing", true, es);
869 
870  ExplainPropertyFloat("Generation", "ms",
872  3, es);
873  ExplainPropertyFloat("Inlining", "ms",
875  3, es);
876  ExplainPropertyFloat("Optimization", "ms",
878  3, es);
879  ExplainPropertyFloat("Emission", "ms",
881  3, es);
882  ExplainPropertyFloat("Total", "ms",
883  1000.0 * INSTR_TIME_GET_DOUBLE(total_time),
884  3, es);
885 
886  ExplainCloseGroup("Timing", "Timing", true, es);
887  }
888  }
889 
890  ExplainCloseGroup("JIT", "JIT", true, es);
891 }
void ExplainPropertyBool(const char *qlabel, bool value, ExplainState *es)
Definition: explain.c:3807
#define PGJIT_EXPR
Definition: jit.h:23
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:3779
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:3793
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:50
bool timing
Definition: explain.h:45
instr_time inlining_counter
Definition: jit.h:36
#define PGJIT_INLINE
Definition: jit.h:22
static void ExplainIndentText(ExplainState *es)
Definition: explain.c:4194
instr_time emission_counter
Definition: jit.h:42
ExplainFormat format
Definition: explain.h:48
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3885
#define PGJIT_DEFORM
Definition: jit.h:24
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3822
StringInfo str
Definition: explain.h:39

◆ ExplainPrintJITSummary()

void ExplainPrintJITSummary ( ExplainState es,
QueryDesc queryDesc 
)

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

783 {
784  JitInstrumentation ji = {0};
785 
786  if (!(queryDesc->estate->es_jit_flags & PGJIT_PERFORM))
787  return;
788 
789  /*
790  * Work with a copy instead of modifying the leader state, since this
791  * function may be called twice
792  */
793  if (queryDesc->estate->es_jit)
794  InstrJitAgg(&ji, &queryDesc->estate->es_jit->instr);
795 
796  /* If this process has done JIT in parallel workers, merge stats */
797  if (queryDesc->estate->es_jit_worker_instr)
798  InstrJitAgg(&ji, queryDesc->estate->es_jit_worker_instr);
799 
800  ExplainPrintJIT(es, queryDesc->estate->es_jit_flags, &ji);
801 }
EState * estate
Definition: execdesc.h:48
struct JitContext * es_jit
Definition: execnodes.h:595
struct JitInstrumentation * es_jit_worker_instr
Definition: execnodes.h:596
static void ExplainPrintJIT(ExplainState *es, int jit_flags, JitInstrumentation *ji)
Definition: explain.c:808
JitInstrumentation instr
Definition: jit.h:61
int es_jit_flags
Definition: execnodes.h:594
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 687 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().

688 {
689  Bitmapset *rels_used = NULL;
690  PlanState *ps;
691 
692  /* Set up ExplainState fields associated with this plan tree */
693  Assert(queryDesc->plannedstmt != NULL);
694  es->pstmt = queryDesc->plannedstmt;
695  es->rtable = queryDesc->plannedstmt->rtable;
696  ExplainPreScanNode(queryDesc->planstate, &rels_used);
699  es->rtable_names);
700  es->printed_subplans = NULL;
701 
702  /*
703  * Sometimes we mark a Gather node as "invisible", which means that it's
704  * not to be displayed in EXPLAIN output. The purpose of this is to allow
705  * running regression tests with force_parallel_mode=regress to get the
706  * same results as running the same tests with force_parallel_mode=off.
707  * Such marking is currently only supported on a Gather at the top of the
708  * plan. We skip that node, and we must also hide per-worker detail data
709  * further down in the plan tree.
710  */
711  ps = queryDesc->planstate;
712  if (IsA(ps, GatherState) &&((Gather *) ps->plan)->invisible)
713  {
714  ps = outerPlanState(ps);
715  es->hide_workers = true;
716  }
717  ExplainNode(ps, NIL, NULL, NULL, es);
718 
719  /*
720  * If requested, include information about GUC parameters with values that
721  * don't match the built-in defaults.
722  */
724 }
#define NIL
Definition: pg_list.h:65
static void ExplainPrintSettings(ExplainState *es)
Definition: explain.c:617
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
bool hide_workers
Definition: explain.h:58
Bitmapset * printed_subplans
Definition: explain.h:57
List * deparse_cxt
Definition: explain.h:56
PlannedStmt * pstmt
Definition: explain.h:53
List * rtable_names
Definition: explain.h:55
List * select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
Definition: ruleutils.c:3409
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1077
PlanState * planstate
Definition: execdesc.h:49
#define outerPlanState(node)
Definition: execnodes.h:1033
List * deparse_context_for_plan_tree(PlannedStmt *pstmt, List *rtable_names)
Definition: ruleutils.c:3317
Plan * plan
Definition: execnodes.h:939
#define Assert(condition)
Definition: c.h:739
List * rtable
Definition: plannodes.h:66
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
Definition: explain.c:1003
PlannedStmt * plannedstmt
Definition: execdesc.h:37
List * rtable
Definition: explain.h:54

◆ ExplainPrintSettings()

static void ExplainPrintSettings ( ExplainState es)
static

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

618 {
619  int num;
620  struct config_generic **gucs;
621 
622  /* bail out if information about settings not requested */
623  if (!es->settings)
624  return;
625 
626  /* request an array of relevant settings */
627  gucs = get_explain_guc_options(&num);
628 
629  if (es->format != EXPLAIN_FORMAT_TEXT)
630  {
631  ExplainOpenGroup("Settings", "Settings", true, es);
632 
633  for (int i = 0; i < num; i++)
634  {
635  char *setting;
636  struct config_generic *conf = gucs[i];
637 
638  setting = GetConfigOptionByName(conf->name, NULL, true);
639 
640  ExplainPropertyText(conf->name, setting, es);
641  }
642 
643  ExplainCloseGroup("Settings", "Settings", true, es);
644  }
645  else
646  {
648 
649  /* In TEXT mode, print nothing if there are no options */
650  if (num <= 0)
651  return;
652 
653  initStringInfo(&str);
654 
655  for (int i = 0; i < num; i++)
656  {
657  char *setting;
658  struct config_generic *conf = gucs[i];
659 
660  if (i > 0)
661  appendStringInfoString(&str, ", ");
662 
663  setting = GetConfigOptionByName(conf->name, NULL, true);
664 
665  if (setting)
666  appendStringInfo(&str, "%s = '%s'", conf->name, setting);
667  else
668  appendStringInfo(&str, "%s = NULL", conf->name);
669  }
670 
671  ExplainPropertyText("Settings", str.data, es);
672  }
673 }
const char * name
Definition: guc_tables.h:149
struct config_generic ** get_explain_guc_options(int *num)
Definition: guc.c:8956
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3770
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:9049
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
ExplainFormat format
Definition: explain.h:48
int i
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3885
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3822
bool settings
Definition: explain.h:47

◆ ExplainPrintTriggers()

void ExplainPrintTriggers ( ExplainState es,
QueryDesc queryDesc 
)

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

737 {
738  ResultRelInfo *rInfo;
739  bool show_relname;
740  int numrels = queryDesc->estate->es_num_result_relations;
741  int numrootrels = queryDesc->estate->es_num_root_result_relations;
742  List *routerels;
743  List *targrels;
744  int nr;
745  ListCell *l;
746 
747  routerels = queryDesc->estate->es_tuple_routing_result_relations;
748  targrels = queryDesc->estate->es_trig_target_relations;
749 
750  ExplainOpenGroup("Triggers", "Triggers", false, es);
751 
752  show_relname = (numrels > 1 || numrootrels > 0 ||
753  routerels != NIL || targrels != NIL);
754  rInfo = queryDesc->estate->es_result_relations;
755  for (nr = 0; nr < numrels; rInfo++, nr++)
756  report_triggers(rInfo, show_relname, es);
757 
758  rInfo = queryDesc->estate->es_root_result_relations;
759  for (nr = 0; nr < numrootrels; rInfo++, nr++)
760  report_triggers(rInfo, show_relname, es);
761 
762  foreach(l, routerels)
763  {
764  rInfo = (ResultRelInfo *) lfirst(l);
765  report_triggers(rInfo, show_relname, es);
766  }
767 
768  foreach(l, targrels)
769  {
770  rInfo = (ResultRelInfo *) lfirst(l);
771  report_triggers(rInfo, show_relname, es);
772  }
773 
774  ExplainCloseGroup("Triggers", "Triggers", false, es);
775 }
#define NIL
Definition: pg_list.h:65
EState * estate
Definition: execdesc.h:48
ResultRelInfo * es_result_relations
Definition: execnodes.h:519
static void report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
Definition: explain.c:913
int es_num_root_result_relations
Definition: execnodes.h:530
List * es_trig_target_relations
Definition: execnodes.h:540
int es_num_result_relations
Definition: execnodes.h:520
List * es_tuple_routing_result_relations
Definition: execnodes.h:537
#define lfirst(lc)
Definition: pg_list.h:190
ResultRelInfo * es_root_result_relations
Definition: execnodes.h:529
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3885
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3822
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 3717 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(), and ExplainPropertyText().

3719 {
3720  switch (es->format)
3721  {
3722  case EXPLAIN_FORMAT_TEXT:
3723  ExplainIndentText(es);
3724  if (unit)
3725  appendStringInfo(es->str, "%s: %s %s\n", qlabel, value, unit);
3726  else
3727  appendStringInfo(es->str, "%s: %s\n", qlabel, value);
3728  break;
3729 
3730  case EXPLAIN_FORMAT_XML:
3731  {
3732  char *str;
3733 
3734  appendStringInfoSpaces(es->str, es->indent * 2);
3735  ExplainXMLTag(qlabel, X_OPENING | X_NOWHITESPACE, es);
3736  str = escape_xml(value);
3737  appendStringInfoString(es->str, str);
3738  pfree(str);
3739  ExplainXMLTag(qlabel, X_CLOSING | X_NOWHITESPACE, es);
3740  appendStringInfoChar(es->str, '\n');
3741  }
3742  break;
3743 
3744  case EXPLAIN_FORMAT_JSON:
3746  appendStringInfoSpaces(es->str, es->indent * 2);
3747  escape_json(es->str, qlabel);
3748  appendStringInfoString(es->str, ": ");
3749  if (numeric)
3751  else
3752  escape_json(es->str, value);
3753  break;
3754 
3755  case EXPLAIN_FORMAT_YAML:
3757  appendStringInfo(es->str, "%s: ", qlabel);
3758  if (numeric)
3760  else
3761  escape_yaml(es->str, value);
3762  break;
3763  }
3764 }
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:4167
static struct @145 value
#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:4229
int indent
Definition: explain.h:50
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:4254
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:4209
#define X_OPENING
Definition: explain.c:51
static void ExplainIndentText(ExplainState *es)
Definition: explain.c:4194
#define X_NOWHITESPACE
Definition: explain.c:54
ExplainFormat format
Definition: explain.h:48
char * escape_xml(const char *str)
Definition: xml.c:2371
StringInfo str
Definition: explain.h:39

◆ ExplainPropertyBool()

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

Definition at line 3807 of file explain.c.

References ExplainProperty().

Referenced by ExplainNode(), and ExplainPrintJIT().

3808 {
3809  ExplainProperty(qlabel, NULL, value ? "true" : "false", true, es);
3810 }
static struct @145 value
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3717

◆ ExplainPropertyFloat()

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

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

3795 {
3796  char *buf;
3797 
3798  buf = psprintf("%.*f", ndigits, value);
3799  ExplainProperty(qlabel, unit, buf, true, es);
3800  pfree(buf);
3801 }
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
static struct @145 value
void pfree(void *pointer)
Definition: mcxt.c:1056
static char * buf
Definition: pg_test_fsync.c:67
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3717

◆ ExplainPropertyInteger()

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

Definition at line 3779 of file explain.c.

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

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

3781 {
3782  char buf[32];
3783 
3784  snprintf(buf, sizeof(buf), INT64_FORMAT, value);
3785  ExplainProperty(qlabel, unit, buf, true, es);
3786 }
static struct @145 value
static char * buf
Definition: pg_test_fsync.c:67
#define INT64_FORMAT
Definition: c.h:401
#define snprintf
Definition: port.h:192
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3717

◆ ExplainPropertyList()

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

Definition at line 3594 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_modifytable_info(), show_plan_tlist(), show_sort_group_keys(), and show_tablesample().

3595 {
3596  ListCell *lc;
3597  bool first = true;
3598 
3599  switch (es->format)
3600  {
3601  case EXPLAIN_FORMAT_TEXT:
3602  ExplainIndentText(es);
3603  appendStringInfo(es->str, "%s: ", qlabel);
3604  foreach(lc, data)
3605  {
3606  if (!first)
3607  appendStringInfoString(es->str, ", ");
3608  appendStringInfoString(es->str, (const char *) lfirst(lc));
3609  first = false;
3610  }
3611  appendStringInfoChar(es->str, '\n');
3612  break;
3613 
3614  case EXPLAIN_FORMAT_XML:
3615  ExplainXMLTag(qlabel, X_OPENING, es);
3616  foreach(lc, data)
3617  {
3618  char *str;
3619 
3620  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
3621  appendStringInfoString(es->str, "<Item>");
3622  str = escape_xml((const char *) lfirst(lc));
3623  appendStringInfoString(es->str, str);
3624  pfree(str);
3625  appendStringInfoString(es->str, "</Item>\n");
3626  }
3627  ExplainXMLTag(qlabel, X_CLOSING, es);
3628  break;
3629 
3630  case EXPLAIN_FORMAT_JSON:
3632  appendStringInfoSpaces(es->str, es->indent * 2);
3633  escape_json(es->str, qlabel);
3634  appendStringInfoString(es->str, ": [");
3635  foreach(lc, data)
3636  {
3637  if (!first)
3638  appendStringInfoString(es->str, ", ");
3639  escape_json(es->str, (const char *) lfirst(lc));
3640  first = false;
3641  }
3642  appendStringInfoChar(es->str, ']');
3643  break;
3644 
3645  case EXPLAIN_FORMAT_YAML:
3647  appendStringInfo(es->str, "%s: ", qlabel);
3648  foreach(lc, data)
3649  {
3650  appendStringInfoChar(es->str, '\n');
3651  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
3652  appendStringInfoString(es->str, "- ");
3653  escape_yaml(es->str, (const char *) lfirst(lc));
3654  }
3655  break;
3656  }
3657 }
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:4167
#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:4229
int indent
Definition: explain.h:50
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:4254
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:4209
#define X_OPENING
Definition: explain.c:51
static void ExplainIndentText(ExplainState *es)
Definition: explain.c:4194
#define lfirst(lc)
Definition: pg_list.h:190
ExplainFormat format
Definition: explain.h:48
char * escape_xml(const char *str)
Definition: xml.c:2371
StringInfo str
Definition: explain.h:39

◆ ExplainPropertyListNested()

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

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

3665 {
3666  ListCell *lc;
3667  bool first = true;
3668 
3669  switch (es->format)
3670  {
3671  case EXPLAIN_FORMAT_TEXT:
3672  case EXPLAIN_FORMAT_XML:
3673  ExplainPropertyList(qlabel, data, es);
3674  return;
3675 
3676  case EXPLAIN_FORMAT_JSON:
3678  appendStringInfoSpaces(es->str, es->indent * 2);
3679  appendStringInfoChar(es->str, '[');
3680  foreach(lc, data)
3681  {
3682  if (!first)
3683  appendStringInfoString(es->str, ", ");
3684  escape_json(es->str, (const char *) lfirst(lc));
3685  first = false;
3686  }
3687  appendStringInfoChar(es->str, ']');
3688  break;
3689 
3690  case EXPLAIN_FORMAT_YAML:
3692  appendStringInfoString(es->str, "- [");
3693  foreach(lc, data)
3694  {
3695  if (!first)
3696  appendStringInfoString(es->str, ", ");
3697  escape_yaml(es->str, (const char *) lfirst(lc));
3698  first = false;
3699  }
3700  appendStringInfoChar(es->str, ']');
3701  break;
3702  }
3703 }
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:4229
int indent
Definition: explain.h:50
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:4254
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:4209
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:3594
#define lfirst(lc)
Definition: pg_list.h:190
ExplainFormat format
Definition: explain.h:48
StringInfo str
Definition: explain.h:39

◆ ExplainPropertyText()

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

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

3771 {
3772  ExplainProperty(qlabel, NULL, value, false, es);
3773 }
static struct @145 value
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3717

◆ ExplainQuery()

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

Definition at line 153 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, and ExplainState::verbose.

Referenced by standard_ProcessUtility().

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

◆ ExplainQueryText()

void ExplainQueryText ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 902 of file explain.c.

References ExplainPropertyText(), and QueryDesc::sourceText.

Referenced by explain_ExecutorEnd().

903 {
904  if (queryDesc->sourceText)
905  ExplainPropertyText("Query Text", queryDesc->sourceText, es);
906 }
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3770
const char * sourceText
Definition: execdesc.h:38

◆ ExplainRestoreGroup()

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

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

4002 {
4003  switch (es->format)
4004  {
4005  case EXPLAIN_FORMAT_TEXT:
4006  /* nothing to do */
4007  break;
4008 
4009  case EXPLAIN_FORMAT_XML:
4010  es->indent += depth;
4011  break;
4012 
4013  case EXPLAIN_FORMAT_JSON:
4014  es->grouping_stack = lcons_int(*state_save, es->grouping_stack);
4015  es->indent += depth;
4016  break;
4017 
4018  case EXPLAIN_FORMAT_YAML:
4019  es->grouping_stack = lcons_int(*state_save, es->grouping_stack);
4020  es->indent += depth;
4021  break;
4022  }
4023 }
List * lcons_int(int datum, List *list)
Definition: list.c:472
List * grouping_stack
Definition: explain.h:51
int indent
Definition: explain.h:50
ExplainFormat format
Definition: explain.h:48

◆ ExplainResultDesc()

TupleDesc ExplainResultDesc ( ExplainStmt stmt)

Definition at line 312 of file explain.c.

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

Referenced by ExplainQuery(), and UtilityTupleDescriptor().

313 {
314  TupleDesc tupdesc;
315  ListCell *lc;
316  Oid result_type = TEXTOID;
317 
318  /* Check for XML format option */
319  foreach(lc, stmt->options)
320  {
321  DefElem *opt = (DefElem *) lfirst(lc);
322 
323  if (strcmp(opt->defname, "format") == 0)
324  {
325  char *p = defGetString(opt);
326 
327  if (strcmp(p, "xml") == 0)
328  result_type = XMLOID;
329  else if (strcmp(p, "json") == 0)
330  result_type = JSONOID;
331  else
332  result_type = TEXTOID;
333  /* don't "break", as ExplainQuery will use the last value */
334  }
335  }
336 
337  /* Need a tuple descriptor representing a single TEXT or XML column */
338  tupdesc = CreateTemplateTupleDesc(1);
339  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
340  result_type, -1, 0);
341  return tupdesc;
342 }
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
List * options
Definition: parsenodes.h:3241
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:730
int16 AttrNumber
Definition: attnum.h:21

◆ ExplainSaveGroup()

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

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

3972 {
3973  switch (es->format)
3974  {
3975  case EXPLAIN_FORMAT_TEXT:
3976  /* nothing to do */
3977  break;
3978 
3979  case EXPLAIN_FORMAT_XML:
3980  es->indent -= depth;
3981  break;
3982 
3983  case EXPLAIN_FORMAT_JSON:
3984  es->indent -= depth;
3985  *state_save = linitial_int(es->grouping_stack);
3987  break;
3988 
3989  case EXPLAIN_FORMAT_YAML:
3990  es->indent -= depth;
3991  *state_save = linitial_int(es->grouping_stack);
3993  break;
3994  }
3995 }
#define linitial_int(l)
Definition: pg_list.h:196
List * grouping_stack
Definition: explain.h:51
int indent
Definition: explain.h:50
ExplainFormat format
Definition: explain.h:48
List * list_delete_first(List *list)
Definition: list.c:861

◆ ExplainScanTarget()

static void ExplainScanTarget ( Scan plan,
ExplainState es 
)
static

Definition at line 3048 of file explain.c.

References ExplainTargetRel().

Referenced by ExplainNode().

3049 {
3050  ExplainTargetRel((Plan *) plan, plan->scanrelid, es);
3051 }
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:3070

◆ ExplainSeparatePlans()

void ExplainSeparatePlans ( ExplainState es)

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

4139 {
4140  switch (es->format)
4141  {
4142  case EXPLAIN_FORMAT_TEXT:
4143  /* add a blank line */
4144  appendStringInfoChar(es->str, '\n');
4145  break;
4146 
4147  case EXPLAIN_FORMAT_XML:
4148  case EXPLAIN_FORMAT_JSON:
4149  case EXPLAIN_FORMAT_YAML:
4150  /* nothing to do */
4151  break;
4152  }
4153 }
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
ExplainFormat format
Definition: explain.h:48
StringInfo str
Definition: explain.h:39

◆ ExplainSubPlans()

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

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

3386 {
3387  ListCell *lst;
3388 
3389  foreach(lst, plans)
3390  {
3391  SubPlanState *sps = (SubPlanState *) lfirst(lst);
3392  SubPlan *sp = sps->subplan;
3393 
3394  /*
3395  * There can be multiple SubPlan nodes referencing the same physical
3396  * subplan (same plan_id, which is its index in PlannedStmt.subplans).
3397  * We should print a subplan only once, so track which ones we already
3398  * printed. This state must be global across the plan tree, since the
3399  * duplicate nodes could be in different plan nodes, eg both a bitmap
3400  * indexscan's indexqual and its parent heapscan's recheck qual. (We
3401  * do not worry too much about which plan node we show the subplan as
3402  * attached to in such cases.)
3403  */
3404  if (bms_is_member(sp->plan_id, es->printed_subplans))
3405  continue;
3407  sp->plan_id);
3408 
3409  /*
3410  * Treat the SubPlan node as an ancestor of the plan node(s) within
3411  * it, so that ruleutils.c can find the referents of subplan
3412  * parameters.
3413  */
3414  ancestors = lcons(sp, ancestors);
3415 
3416  ExplainNode(sps->planstate, ancestors,
3417  relationship, sp->plan_name, es);
3418 
3419  ancestors = list_delete_first(ancestors);
3420  }
3421 }
int plan_id
Definition: primnodes.h:709
Bitmapset * printed_subplans
Definition: explain.h:57
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1077
struct PlanState * planstate
Definition: execnodes.h:847
SubPlan * subplan
Definition: execnodes.h:846
List * lcons(void *datum, List *list)
Definition: list.c:454
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:861

◆ ExplainTargetRel()

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

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

3071 {
3072  char *objectname = NULL;
3073  char *namespace = NULL;
3074  const char *objecttag = NULL;
3075  RangeTblEntry *rte;
3076  char *refname;
3077 
3078  rte = rt_fetch(rti, es->rtable);
3079  refname = (char *) list_nth(es->rtable_names, rti - 1);
3080  if (refname == NULL)
3081  refname = rte->eref->aliasname;
3082 
3083  switch (nodeTag(plan))
3084  {
3085  case T_SeqScan:
3086  case T_SampleScan:
3087  case T_IndexScan:
3088  case T_IndexOnlyScan:
3089  case T_BitmapHeapScan:
3090  case T_TidScan:
3091  case T_ForeignScan:
3092  case T_CustomScan:
3093  case T_ModifyTable:
3094  /* Assert it's on a real relation */
3095  Assert(rte->rtekind == RTE_RELATION);
3096  objectname = get_rel_name(rte->relid);
3097  if (es->verbose)
3098  namespace = get_namespace_name(get_rel_namespace(rte->relid));
3099  objecttag = "Relation Name";
3100  break;
3101  case T_FunctionScan:
3102  {
3103  FunctionScan *fscan = (FunctionScan *) plan;
3104 
3105  /* Assert it's on a RangeFunction */
3106  Assert(rte->rtekind == RTE_FUNCTION);
3107 
3108  /*
3109  * If the expression is still a function call of a single
3110  * function, we can get the real name of the function.
3111  * Otherwise, punt. (Even if it was a single function call
3112  * originally, the optimizer could have simplified it away.)
3113  */
3114  if (list_length(fscan->functions) == 1)
3115  {
3116  RangeTblFunction *rtfunc = (RangeTblFunction *) linitial(fscan->functions);
3117 
3118  if (IsA(rtfunc->funcexpr, FuncExpr))
3119  {
3120  FuncExpr *funcexpr = (FuncExpr *) rtfunc->funcexpr;
3121  Oid funcid = funcexpr->funcid;
3122 
3123  objectname = get_func_name(funcid);
3124  if (es->verbose)
3125  namespace =
3127  }
3128  }
3129  objecttag = "Function Name";
3130  }
3131  break;
3132  case T_TableFuncScan:
3133  Assert(rte->rtekind == RTE_TABLEFUNC);
3134  objectname = "xmltable";
3135  objecttag = "Table Function Name";
3136  break;
3137  case T_ValuesScan:
3138  Assert(rte->rtekind == RTE_VALUES);
3139  break;
3140  case T_CteScan:
3141  /* Assert it's on a non-self-reference CTE */
3142  Assert(rte->rtekind == RTE_CTE);
3143  Assert(!rte->self_reference);
3144  objectname = rte->ctename;
3145  objecttag = "CTE Name";
3146  break;
3147  case T_NamedTuplestoreScan:
3149  objectname = rte->enrname;
3150  objecttag = "Tuplestore Name";
3151  break;
3152  case T_WorkTableScan:
3153  /* Assert it's on a self-reference CTE */
3154  Assert(rte->rtekind == RTE_CTE);
3155  Assert(rte->self_reference);
3156  objectname = rte->ctename;
3157  objecttag = "CTE Name";
3158  break;
3159  default:
3160  break;
3161  }
3162 
3163  if (es->format == EXPLAIN_FORMAT_TEXT)
3164  {
3165  appendStringInfoString(es->str, " on");
3166  if (namespace != NULL)
3167  appendStringInfo(es->str, " %s.%s", quote_identifier(namespace),
3168  quote_identifier(objectname));
3169  else if (objectname != NULL)
3170  appendStringInfo(es->str, " %s", quote_identifier(objectname));
3171  if (objectname == NULL || strcmp(refname, objectname) != 0)
3172  appendStringInfo(es->str, " %s", quote_identifier(refname));
3173  }
3174  else
3175  {
3176  if (objecttag != NULL && objectname != NULL)
3177  ExplainPropertyText(objecttag, objectname, es);
3178  if (namespace != NULL)
3179  ExplainPropertyText("Schema", namespace, es);
3180  ExplainPropertyText("Alias", refname, es);
3181  }
3182 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10697
Oid get_func_namespace(Oid funcid)
Definition: lsyscache.c:1434
List * functions
Definition: plannodes.h:525
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1754
unsigned int Oid
Definition: postgres_ext.h:31
List * rtable_names
Definition: explain.h:55
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3770
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:1410
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3094
char * enrname
Definition: parsenodes.h:1106
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
bool self_reference
Definition: parsenodes.h:1079
bool verbose
Definition: explain.h:41
#define Assert(condition)
Definition: c.h:739
char * aliasname
Definition: primnodes.h:42
static int list_length(const List *l)
Definition: pg_list.h:169
ExplainFormat format
Definition: explain.h:48
#define nodeTag(nodeptr)
Definition: nodes.h:530
RTEKind rtekind
Definition: parsenodes.h:974
char * ctename
Definition: parsenodes.h:1077
Alias * eref
Definition: parsenodes.h:1113
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
StringInfo str
Definition: explain.h:39
List * rtable
Definition: explain.h:54

◆ ExplainXMLTag()

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

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

4168 {
4169  const char *s;
4170  const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
4171 
4172  if ((flags & X_NOWHITESPACE) == 0)
4173  appendStringInfoSpaces(es->str, 2 * es->indent);
4174  appendStringInfoCharMacro(es->str, '<');
4175  if ((flags & X_CLOSING) != 0)
4176  appendStringInfoCharMacro(es->str, '/');
4177  for (s = tagname; *s; s++)
4178  appendStringInfoChar(es->str, strchr(valid, *s) ? *s : '-');
4179  if ((flags & X_CLOSE_IMMEDIATE) != 0)
4180  appendStringInfoString(es->str, " /");
4181  appendStringInfoCharMacro(es->str, '>');
4182  if ((flags & X_NOWHITESPACE) == 0)
4183  appendStringInfoCharMacro(es->str, '\n');
4184 }
#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:50
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 4229 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().

4230 {
4232  if (linitial_int(es->grouping_stack) == 0)
4233  {
4234  linitial_int(es->grouping_stack) = 1;
4235  }
4236  else
4237  {
4238  appendStringInfoChar(es->str, '\n');
4239  appendStringInfoSpaces(es->str, es->indent * 2);
4240  }
4241 }
#define linitial_int(l)
Definition: pg_list.h:196
List * grouping_stack
Definition: explain.h:51
int indent
Definition: explain.h:50
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:739
ExplainFormat format
Definition: explain.h:48
StringInfo str
Definition: explain.h:39

◆ NewExplainState()

ExplainState* NewExplainState ( void  )

Definition at line 295 of file explain.c.

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

Referenced by explain_ExecutorEnd(), and ExplainQuery().

296 {
297  ExplainState *es = (ExplainState *) palloc0(sizeof(ExplainState));
298 
299  /* Set default options (most fields can be left as zeroes). */
300  es->costs = true;
301  /* Prepare output buffer. */
302  es->str = makeStringInfo();
303 
304  return es;
305 }
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 913 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().

914 {
915  int nt;
916 
917  if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
918  return;
919  for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
920  {
921  Trigger *trig = rInfo->ri_TrigDesc->triggers + nt;
922  Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
923  char *relname;
924  char *conname = NULL;
925 
926  /* Must clean up instrumentation state */
927  InstrEndLoop(instr);
928 
929  /*
930  * We ignore triggers that were never invoked; they likely aren't
931  * relevant to the current query type.
932  */
933  if (instr->ntuples == 0)
934  continue;
935 
936  ExplainOpenGroup("Trigger", NULL, true, es);
937 
938  relname = RelationGetRelationName(rInfo->ri_RelationDesc);
939  if (OidIsValid(trig->tgconstraint))
940  conname = get_constraint_name(trig->tgconstraint);
941 
942  /*
943  * In text format, we avoid printing both the trigger name and the
944  * constraint name unless VERBOSE is specified. In non-text formats
945  * we just print everything.
946  */
947  if (es->format == EXPLAIN_FORMAT_TEXT)
948  {
949  if (es->verbose || conname == NULL)
950  appendStringInfo(es->str, "Trigger %s", trig->tgname);
951  else
952  appendStringInfoString(es->str, "Trigger");
953  if (conname)
954  appendStringInfo(es->str, " for constraint %s", conname);
955  if (show_relname)
956  appendStringInfo(es->str, " on %s", relname);
957  if (es->timing)
958  appendStringInfo(es->str, ": time=%.3f calls=%.0f\n",
959  1000.0 * instr->total, instr->ntuples);
960  else
961  appendStringInfo(es->str, ": calls=%.0f\n", instr->ntuples);
962  }
963  else
964  {
965  ExplainPropertyText("Trigger Name", trig->tgname, es);
966  if (conname)
967  ExplainPropertyText("Constraint Name", conname, es);
968  ExplainPropertyText("Relation", relname, es);
969  if (es->timing)
970  ExplainPropertyFloat("Time", "ms", 1000.0 * instr->total, 3,
971  es);
972  ExplainPropertyFloat("Calls", NULL, instr->ntuples, 0, es);
973  }
974 
975  if (conname)
976  pfree(conname);
977 
978  ExplainCloseGroup("Trigger", NULL, true, es);
979  }
980 }
Relation ri_RelationDesc
Definition: execnodes.h:410
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:969
void ExplainPropertyFloat(const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
Definition: explain.c:3793
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:431
NameData relname
Definition: pg_class.h:35
#define OidIsValid(objectId)
Definition: c.h:645
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:110
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3770
void pfree(void *pointer)
Definition: mcxt.c:1056
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
Oid tgconstraint
Definition: reltrigger.h:34
char * tgname
Definition: reltrigger.h:27
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
Trigger * triggers
Definition: reltrigger.h:48
#define RelationGetRelationName(relation)
Definition: rel.h:462
double ntuples
Definition: instrument.h:59
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:422
bool timing
Definition: explain.h:45
int numtriggers
Definition: reltrigger.h:49
bool verbose
Definition: explain.h:41
ExplainFormat format
Definition: explain.h:48
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3885
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3822
StringInfo str
Definition: explain.h:39

◆ show_agg_keys()

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

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

2236 {
2237  Agg *plan = (Agg *) astate->ss.ps.plan;
2238 
2239  if (plan->numCols > 0 || plan->groupingSets)
2240  {
2241  /* The key columns refer to the tlist of the child plan */
2242  ancestors = lcons(plan, ancestors);
2243 
2244  if (plan->groupingSets)
2245  show_grouping_sets(outerPlanState(astate), plan, ancestors, es);
2246  else
2247  show_sort_group_keys(outerPlanState(astate), "Group Key",
2248  plan->numCols, plan->grpColIdx,
2249  NULL, NULL, NULL,
2250  ancestors, es);
2251 
2252  ancestors = list_delete_first(ancestors);
2253  }
2254 }
int numCols
Definition: plannodes.h:811
AttrNumber * grpColIdx
Definition: plannodes.h:812
ScanState ss
Definition: execnodes.h:2039
PlanState ps
Definition: execnodes.h:1326
#define outerPlanState(node)
Definition: execnodes.h:1033
static void show_grouping_sets(PlanState *planstate, Agg *agg, List *ancestors, ExplainState *es)
Definition: explain.c:2257
List * groupingSets
Definition: plannodes.h:818
Plan * plan
Definition: execnodes.h:939
List * lcons(void *datum, List *list)
Definition: list.c:454
Definition: plannodes.h:806
static void show_sort_group_keys(PlanState *planstate, const char *qlabel, int nkeys, AttrNumber *keycols, Oid *sortOperators, Oid *collations, bool *nullsFirst, List *ancestors, ExplainState *es)
Definition: explain.c:2386
List * list_delete_first(List *list)
Definition: list.c:861

◆ show_buffer_usage()

static void show_buffer_usage ( ExplainState es,
const BufferUsage usage 
)
static

Definition at line 2885 of file explain.c.

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

Referenced by ExplainNode().

2886 {
2887  if (es->format == EXPLAIN_FORMAT_TEXT)
2888  {
2889  bool has_shared = (usage->shared_blks_hit > 0 ||
2890  usage->shared_blks_read > 0 ||
2891  usage->shared_blks_dirtied > 0 ||
2892  usage->shared_blks_written > 0);
2893  bool has_local = (usage->local_blks_hit > 0 ||
2894  usage->local_blks_read > 0 ||
2895  usage->local_blks_dirtied > 0 ||
2896  usage->local_blks_written > 0);
2897  bool has_temp = (usage->temp_blks_read > 0 ||
2898  usage->temp_blks_written > 0);
2899  bool has_timing = (!INSTR_TIME_IS_ZERO(usage->blk_read_time) ||
2901 
2902  /* Show only positive counter values. */
2903  if (has_shared || has_local || has_temp)
2904  {
2905  ExplainIndentText(es);
2906  appendStringInfoString(es->str, "Buffers:");
2907 
2908  if (has_shared)
2909  {
2910  appendStringInfoString(es->str, " shared");
2911  if (usage->shared_blks_hit > 0)
2912  appendStringInfo(es->str, " hit=%ld",
2913  usage->shared_blks_hit);
2914  if (usage->shared_blks_read > 0)
2915  appendStringInfo(es->str, " read=%ld",
2916  usage->shared_blks_read);
2917  if (usage->shared_blks_dirtied > 0)
2918  appendStringInfo(es->str, " dirtied=%ld",
2919  usage->shared_blks_dirtied);
2920  if (usage->shared_blks_written > 0)
2921  appendStringInfo(es->str, " written=%ld",
2922  usage->shared_blks_written);
2923  if (has_local || has_temp)
2924  appendStringInfoChar(es->str, ',');
2925  }
2926  if (has_local)
2927  {
2928  appendStringInfoString(es->str, " local");
2929  if (usage->local_blks_hit > 0)
2930  appendStringInfo(es->str, " hit=%ld",
2931  usage->local_blks_hit);
2932  if (usage->local_blks_read > 0)
2933  appendStringInfo(es->str, " read=%ld",
2934  usage->local_blks_read);
2935  if (usage->local_blks_dirtied > 0)
2936  appendStringInfo(es->str, " dirtied=%ld",
2937  usage->local_blks_dirtied);
2938  if (usage->local_blks_written > 0)
2939  appendStringInfo(es->str, " written=%ld",
2940  usage->local_blks_written);
2941  if (has_temp)
2942  appendStringInfoChar(es->str, ',');
2943  }
2944  if (has_temp)
2945  {
2946  appendStringInfoString(es->str, " temp");
2947  if (usage->temp_blks_read > 0)
2948  appendStringInfo(es->str, " read=%ld",
2949  usage->temp_blks_read);
2950  if (usage->temp_blks_written > 0)
2951  appendStringInfo(es->str, " written=%ld",
2952  usage->temp_blks_written);
2953  }
2954  appendStringInfoChar(es->str, '\n');
2955  }
2956 
2957  /* As above, show only positive counter values. */
2958  if (has_timing)
2959  {
2960  ExplainIndentText(es);
2961  appendStringInfoString(es->str, "I/O Timings:");
2962  if (!INSTR_TIME_IS_ZERO(usage->blk_read_time))
2963  appendStringInfo(es->str, " read=%0.3f",
2965  if (!INSTR_TIME_IS_ZERO(usage->blk_write_time))
2966  appendStringInfo(es->str, " write=%0.3f",
2968  appendStringInfoChar(es->str, '\n');
2969  }
2970  }
2971  else
2972  {
2973  ExplainPropertyInteger("Shared Hit Blocks", NULL,
2974  usage->shared_blks_hit, es);
2975  ExplainPropertyInteger("Shared Read Blocks", NULL,
2976  usage->shared_blks_read, es);
2977  ExplainPropertyInteger("Shared Dirtied Blocks", NULL,
2978  usage->shared_blks_dirtied, es);
2979  ExplainPropertyInteger("Shared Written Blocks", NULL,
2980  usage->shared_blks_written, es);
2981  ExplainPropertyInteger("Local Hit Blocks", NULL,
2982  usage->local_blks_hit, es);
2983  ExplainPropertyInteger("Local Read Blocks", NULL,
2984  usage->local_blks_read, es);
2985  ExplainPropertyInteger("Local Dirtied Blocks", NULL,
2986  usage->local_blks_dirtied, es);
2987  ExplainPropertyInteger("Local Written Blocks", NULL,
2988  usage->local_blks_written, es);
2989  ExplainPropertyInteger("Temp Read Blocks", NULL,
2990  usage->temp_blks_read, es);
2991  ExplainPropertyInteger("Temp Written Blocks", NULL,
2992  usage->temp_blks_written, es);
2993  if (track_io_timing)
2994  {
2995  ExplainPropertyFloat("I/O Read Time", "ms",
2997  3, es);
2998  ExplainPropertyFloat("I/O Write Time", "ms",
3000  3, es);