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 "foreign/fdwapi.h"
#include "jit/jit.h"
#include "libpq/pqformat.h"
#include "libpq/protocol.h"
#include "nodes/extensible.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "parser/analyze.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteHandler.h"
#include "storage/bufmgr.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/guc_tables.h"
#include "utils/json.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/ruleutils.h"
#include "utils/snapmgr.h"
#include "utils/tuplesort.h"
#include "utils/typcache.h"
#include "utils/xml.h"
Include dependency graph for explain.c:

Go to the source code of this file.

Data Structures

struct  SerializeMetrics
 
struct  SerializeDestReceiver
 

Macros

#define X_OPENING   0
 
#define X_CLOSING   1
 
#define X_CLOSE_IMMEDIATE   2
 
#define X_NOWHITESPACE   4
 
#define BYTES_TO_KILOBYTES(b)   (((b) + 1023) / 1024)
 

Typedefs

typedef struct SerializeMetrics SerializeMetrics
 
typedef struct SerializeDestReceiver SerializeDestReceiver
 

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 ExplainPrintSerialize (ExplainState *es, SerializeMetrics *metrics)
 
static void report_triggers (ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
 
static double elapsed_time (instr_time *starttime)
 
static bool ExplainPreScanNode (PlanState *planstate, Bitmapset **rels_used)
 
static void ExplainNode (PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
 
static void show_plan_tlist (PlanState *planstate, List *ancestors, ExplainState *es)
 
static void show_expression (Node *node, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
 
static void show_qual (List *qual, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
 
static void show_scan_qual (List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
 
static void show_upper_qual (List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
 
static void show_sort_keys (SortState *sortstate, List *ancestors, ExplainState *es)
 
static void show_incremental_sort_keys (IncrementalSortState *incrsortstate, List *ancestors, ExplainState *es)
 
static void show_merge_append_keys (MergeAppendState *mstate, List *ancestors, ExplainState *es)
 
static void show_agg_keys (AggState *astate, List *ancestors, ExplainState *es)
 
static void show_grouping_sets (PlanState *planstate, Agg *agg, List *ancestors, ExplainState *es)
 
static void show_grouping_set_keys (PlanState *planstate, Agg *aggnode, Sort *sortnode, List *context, bool useprefix, List *ancestors, ExplainState *es)
 
static void show_group_keys (GroupState *gstate, List *ancestors, ExplainState *es)
 
static void show_sort_group_keys (PlanState *planstate, const char *qlabel, int nkeys, int nPresortedKeys, AttrNumber *keycols, Oid *sortOperators, Oid *collations, bool *nullsFirst, List *ancestors, ExplainState *es)
 
static void show_sortorder_options (StringInfo buf, Node *sortexpr, Oid sortOperator, Oid collation, bool nullsFirst)
 
static void show_tablesample (TableSampleClause *tsc, PlanState *planstate, List *ancestors, ExplainState *es)
 
static void show_sort_info (SortState *sortstate, ExplainState *es)
 
static void show_incremental_sort_info (IncrementalSortState *incrsortstate, ExplainState *es)
 
static void show_hash_info (HashState *hashstate, ExplainState *es)
 
static void show_material_info (MaterialState *mstate, ExplainState *es)
 
static void show_memoize_info (MemoizeState *mstate, List *ancestors, ExplainState *es)
 
static void show_hashagg_info (AggState *aggstate, ExplainState *es)
 
static void show_tidbitmap_info (BitmapHeapScanState *planstate, ExplainState *es)
 
static void show_instrumentation_count (const char *qlabel, int which, PlanState *planstate, ExplainState *es)
 
static void show_foreignscan_info (ForeignScanState *fsstate, ExplainState *es)
 
static const char * explain_get_index_name (Oid indexId)
 
static bool peek_buffer_usage (ExplainState *es, const BufferUsage *usage)
 
static void show_buffer_usage (ExplainState *es, const BufferUsage *usage)
 
static void show_wal_usage (ExplainState *es, const WalUsage *usage)
 
static void show_memory_counters (ExplainState *es, const MemoryContextCounters *mem_counters)
 
static void ExplainIndexScanDetails (Oid indexid, ScanDirection indexorderdir, ExplainState *es)
 
static void ExplainScanTarget (Scan *plan, ExplainState *es)
 
static void ExplainModifyTarget (ModifyTable *plan, ExplainState *es)
 
static void ExplainTargetRel (Plan *plan, Index rti, ExplainState *es)
 
static void show_modifytable_info (ModifyTableState *mtstate, List *ancestors, ExplainState *es)
 
static void ExplainMemberNodes (PlanState **planstates, int nplans, List *ancestors, ExplainState *es)
 
static void ExplainMissingMembers (int nplans, int nchildren, ExplainState *es)
 
static void ExplainSubPlans (List *plans, List *ancestors, const char *relationship, ExplainState *es)
 
static void ExplainCustomChildren (CustomScanState *css, List *ancestors, ExplainState *es)
 
static ExplainWorkersStateExplainCreateWorkersState (int num_workers)
 
static void ExplainOpenWorker (int n, ExplainState *es)
 
static void ExplainCloseWorker (int n, ExplainState *es)
 
static void ExplainFlushWorkersState (ExplainState *es)
 
static void ExplainProperty (const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
 
static void ExplainOpenSetAsideGroup (const char *objtype, const char *labelname, bool labeled, int depth, ExplainState *es)
 
static void ExplainSaveGroup (ExplainState *es, int depth, int *state_save)
 
static void ExplainRestoreGroup (ExplainState *es, int depth, int *state_save)
 
static void ExplainDummyGroup (const char *objtype, const char *labelname, ExplainState *es)
 
static void ExplainXMLTag (const char *tagname, int flags, ExplainState *es)
 
static void ExplainIndentText (ExplainState *es)
 
static void ExplainJSONLineEnding (ExplainState *es)
 
static void ExplainYAMLLineStarting (ExplainState *es)
 
static void escape_yaml (StringInfo buf, const char *str)
 
static SerializeMetrics GetSerializationMetrics (DestReceiver *dest)
 
void ExplainQuery (ParseState *pstate, ExplainStmt *stmt, ParamListInfo params, DestReceiver *dest)
 
ExplainStateNewExplainState (void)
 
TupleDesc ExplainResultDesc (ExplainStmt *stmt)
 
void standard_ExplainOneQuery (Query *query, int cursorOptions, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
 
void ExplainOneUtility (Node *utilityStmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
 
void ExplainOnePlan (PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv, const instr_time *planduration, const BufferUsage *bufusage, const MemoryContextCounters *mem_counters)
 
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 ExplainQueryParameters (ExplainState *es, ParamListInfo params, int maxlen)
 
static void show_incremental_sort_group_info (IncrementalSortGroupInfo *groupInfo, const char *groupLabel, bool indent, ExplainState *es)
 
void ExplainPropertyList (const char *qlabel, List *data, ExplainState *es)
 
void ExplainPropertyListNested (const char *qlabel, List *data, ExplainState *es)
 
void ExplainPropertyText (const char *qlabel, const char *value, ExplainState *es)
 
void ExplainPropertyInteger (const char *qlabel, const char *unit, int64 value, ExplainState *es)
 
void ExplainPropertyUInteger (const char *qlabel, const char *unit, uint64 value, ExplainState *es)
 
void ExplainPropertyFloat (const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
 
void ExplainPropertyBool (const char *qlabel, bool value, ExplainState *es)
 
void ExplainOpenGroup (const char *objtype, const char *labelname, bool labeled, ExplainState *es)
 
void ExplainCloseGroup (const char *objtype, const char *labelname, bool labeled, ExplainState *es)
 
void ExplainBeginOutput (ExplainState *es)
 
void ExplainEndOutput (ExplainState *es)
 
void ExplainSeparatePlans (ExplainState *es)
 
static void serialize_prepare_info (SerializeDestReceiver *receiver, TupleDesc typeinfo, int nattrs)
 
static bool serializeAnalyzeReceive (TupleTableSlot *slot, DestReceiver *self)
 
static void serializeAnalyzeStartup (DestReceiver *self, int operation, TupleDesc typeinfo)
 
static void serializeAnalyzeShutdown (DestReceiver *self)
 
static void serializeAnalyzeDestroy (DestReceiver *self)
 
DestReceiverCreateExplainSerializeDestReceiver (ExplainState *es)
 

Variables

ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL
 
explain_get_index_name_hook_type explain_get_index_name_hook = NULL
 

Macro Definition Documentation

◆ BYTES_TO_KILOBYTES

#define BYTES_TO_KILOBYTES (   b)    (((b) + 1023) / 1024)

Definition at line 70 of file explain.c.

◆ X_CLOSE_IMMEDIATE

#define X_CLOSE_IMMEDIATE   2

Definition at line 63 of file explain.c.

◆ X_CLOSING

#define X_CLOSING   1

Definition at line 62 of file explain.c.

◆ X_NOWHITESPACE

#define X_NOWHITESPACE   4

Definition at line 64 of file explain.c.

◆ X_OPENING

#define X_OPENING   0

Definition at line 61 of file explain.c.

Typedef Documentation

◆ SerializeDestReceiver

◆ SerializeMetrics

Function Documentation

◆ CreateExplainSerializeDestReceiver()

DestReceiver* CreateExplainSerializeDestReceiver ( ExplainState es)

Definition at line 5637 of file explain.c.

5638 {
5639  SerializeDestReceiver *self;
5640 
5642 
5643  self->pub.receiveSlot = serializeAnalyzeReceive;
5644  self->pub.rStartup = serializeAnalyzeStartup;
5645  self->pub.rShutdown = serializeAnalyzeShutdown;
5646  self->pub.rDestroy = serializeAnalyzeDestroy;
5647  self->pub.mydest = DestExplainSerialize;
5648 
5649  self->es = es;
5650 
5651  return (DestReceiver *) self;
5652 }
@ DestExplainSerialize
Definition: dest.h:99
static void serializeAnalyzeStartup(DestReceiver *self, int operation, TupleDesc typeinfo)
Definition: explain.c:5571
static void serializeAnalyzeDestroy(DestReceiver *self)
Definition: explain.c:5628
static bool serializeAnalyzeReceive(TupleTableSlot *slot, DestReceiver *self)
Definition: explain.c:5468
static void serializeAnalyzeShutdown(DestReceiver *self)
Definition: explain.c:5607
void * palloc0(Size size)
Definition: mcxt.c:1347

References DestExplainSerialize, palloc0(), serializeAnalyzeDestroy(), serializeAnalyzeReceive(), serializeAnalyzeShutdown(), and serializeAnalyzeStartup().

Referenced by CreateDestReceiver(), and ExplainOnePlan().

◆ elapsed_time()

static double elapsed_time ( instr_time starttime)
static

Definition at line 1274 of file explain.c.

1275 {
1276  instr_time endtime;
1277 
1278  INSTR_TIME_SET_CURRENT(endtime);
1279  INSTR_TIME_SUBTRACT(endtime, *starttime);
1280  return INSTR_TIME_GET_DOUBLE(endtime);
1281 }
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:122
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:188
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:181

References INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, and INSTR_TIME_SUBTRACT.

Referenced by ExplainOnePlan(), and IsCheckpointOnSchedule().

◆ escape_yaml()

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

Definition at line 5380 of file explain.c.

5381 {
5382  escape_json(buf, str);
5383 }
const char * str
void escape_json(StringInfo buf, const char *str)
Definition: json.c:1549
static char * buf
Definition: pg_test_fsync.c:73

References buf, escape_json(), and str.

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

◆ explain_get_index_name()

static const char * explain_get_index_name ( Oid  indexId)
static

Definition at line 3760 of file explain.c.

3761 {
3762  const char *result;
3763 
3765  result = (*explain_get_index_name_hook) (indexId);
3766  else
3767  result = NULL;
3768  if (result == NULL)
3769  {
3770  /* default behavior: look it up in the catalogs */
3771  result = get_rel_name(indexId);
3772  if (result == NULL)
3773  elog(ERROR, "cache lookup failed for index %u", indexId);
3774  }
3775  return result;
3776 }
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
explain_get_index_name_hook_type explain_get_index_name_hook
Definition: explain.c:49
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1928

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

Referenced by ExplainIndexScanDetails(), and ExplainNode().

◆ ExplainBeginOutput()

void ExplainBeginOutput ( ExplainState es)

Definition at line 5204 of file explain.c.

5205 {
5206  switch (es->format)
5207  {
5208  case EXPLAIN_FORMAT_TEXT:
5209  /* nothing to do */
5210  break;
5211 
5212  case EXPLAIN_FORMAT_XML:
5214  "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
5215  es->indent++;
5216  break;
5217 
5218  case EXPLAIN_FORMAT_JSON:
5219  /* top-level structure is an array of plans */
5220  appendStringInfoChar(es->str, '[');
5221  es->grouping_stack = lcons_int(0, es->grouping_stack);
5222  es->indent++;
5223  break;
5224 
5225  case EXPLAIN_FORMAT_YAML:
5226  es->grouping_stack = lcons_int(0, es->grouping_stack);
5227  break;
5228  }
5229 }
@ EXPLAIN_FORMAT_XML
Definition: explain.h:30
@ EXPLAIN_FORMAT_YAML
Definition: explain.h:32
@ EXPLAIN_FORMAT_TEXT
Definition: explain.h:29
@ EXPLAIN_FORMAT_JSON
Definition: explain.h:31
List * lcons_int(int datum, List *list)
Definition: list.c:513
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:182
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
List * grouping_stack
Definition: explain.h:62
StringInfo str
Definition: explain.h:46
ExplainFormat format
Definition: explain.h:59
int indent
Definition: explain.h:61

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().

◆ ExplainCloseGroup()

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

Definition at line 5011 of file explain.c.

5013 {
5014  switch (es->format)
5015  {
5016  case EXPLAIN_FORMAT_TEXT:
5017  /* nothing to do */
5018  break;
5019 
5020  case EXPLAIN_FORMAT_XML:
5021  es->indent--;
5022  ExplainXMLTag(objtype, X_CLOSING, es);
5023  break;
5024 
5025  case EXPLAIN_FORMAT_JSON:
5026  es->indent--;
5027  appendStringInfoChar(es->str, '\n');
5028  appendStringInfoSpaces(es->str, 2 * es->indent);
5029  appendStringInfoChar(es->str, labeled ? '}' : ']');
5031  break;
5032 
5033  case EXPLAIN_FORMAT_YAML:
5034  es->indent--;
5036  break;
5037  }
5038 }
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:5293
#define X_CLOSING
Definition: explain.c:62
List * list_delete_first(List *list)
Definition: list.c:943
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:212

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(), ExplainPrintSerialize(), ExplainPrintSettings(), ExplainPrintTriggers(), report_triggers(), show_grouping_set_keys(), show_grouping_sets(), show_incremental_sort_group_info(), and show_modifytable_info().

◆ ExplainCloseWorker()

static void ExplainCloseWorker ( int  n,
ExplainState es 
)
static

Definition at line 4641 of file explain.c.

4642 {
4643  ExplainWorkersState *wstate = es->workers_state;
4644 
4645  Assert(wstate);
4646  Assert(n >= 0 && n < wstate->num_workers);
4647  Assert(wstate->worker_inited[n]);
4648 
4649  /*
4650  * Save formatting state in case we do another ExplainOpenWorker(), then
4651  * pop the formatting stack.
4652  */
4653  ExplainSaveGroup(es, 2, &wstate->worker_state_save[n]);
4654 
4655  /*
4656  * In TEXT format, if we didn't actually produce any output line(s) then
4657  * truncate off the partial line emitted by ExplainOpenWorker. (This is
4658  * to avoid bogus output if, say, show_buffer_usage chooses not to print
4659  * anything for the worker.) Also fix up the indent level.
4660  */
4661  if (es->format == EXPLAIN_FORMAT_TEXT)
4662  {
4663  while (es->str->len > 0 && es->str->data[es->str->len - 1] != '\n')
4664  es->str->data[--(es->str->len)] = '\0';
4665 
4666  es->indent--;
4667  }
4668 
4669  /* Restore prior output buffer pointer */
4670  es->str = wstate->prev_str;
4671 }
#define Assert(condition)
Definition: c.h:858
static void ExplainSaveGroup(ExplainState *es, int depth, int *state_save)
Definition: explain.c:5097
ExplainWorkersState * workers_state
Definition: explain.h:71
bool * worker_inited
Definition: explain.h:38
int * worker_state_save
Definition: explain.h:40
StringInfo prev_str
Definition: explain.h:41

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

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

◆ ExplainCreateWorkersState()

static ExplainWorkersState * ExplainCreateWorkersState ( int  num_workers)
static

Definition at line 4562 of file explain.c.

4563 {
4564  ExplainWorkersState *wstate;
4565 
4566  wstate = (ExplainWorkersState *) palloc(sizeof(ExplainWorkersState));
4567  wstate->num_workers = num_workers;
4568  wstate->worker_inited = (bool *) palloc0(num_workers * sizeof(bool));
4569  wstate->worker_str = (StringInfoData *)
4570  palloc0(num_workers * sizeof(StringInfoData));
4571  wstate->worker_state_save = (int *) palloc(num_workers * sizeof(int));
4572  return wstate;
4573 }
void * palloc(Size size)
Definition: mcxt.c:1317
StringInfoData * worker_str
Definition: explain.h:39

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

Referenced by ExplainNode().

◆ ExplainCustomChildren()

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

Definition at line 4540 of file explain.c.

4541 {
4542  ListCell *cell;
4543  const char *label =
4544  (list_length(css->custom_ps) != 1 ? "children" : "child");
4545 
4546  foreach(cell, css->custom_ps)
4547  ExplainNode((PlanState *) lfirst(cell), ancestors, label, NULL, es);
4548 }
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1368
static char * label
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
List * custom_ps
Definition: execnodes.h:2093

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

Referenced by ExplainNode().

◆ ExplainDummyGroup()

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

Definition at line 5158 of file explain.c.

5159 {
5160  switch (es->format)
5161  {
5162  case EXPLAIN_FORMAT_TEXT:
5163  /* nothing to do */
5164  break;
5165 
5166  case EXPLAIN_FORMAT_XML:
5167  ExplainXMLTag(objtype, X_CLOSE_IMMEDIATE, es);
5168  break;
5169 
5170  case EXPLAIN_FORMAT_JSON:
5172  appendStringInfoSpaces(es->str, 2 * es->indent);
5173  if (labelname)
5174  {
5175  escape_json(es->str, labelname);
5176  appendStringInfoString(es->str, ": ");
5177  }
5178  escape_json(es->str, objtype);
5179  break;
5180 
5181  case EXPLAIN_FORMAT_YAML:
5183  if (labelname)
5184  {
5185  escape_yaml(es->str, labelname);
5186  appendStringInfoString(es->str, ": ");
5187  }
5188  else
5189  {
5190  appendStringInfoString(es->str, "- ");
5191  }
5192  escape_yaml(es->str, objtype);
5193  break;
5194  }
5195 }
#define X_CLOSE_IMMEDIATE
Definition: explain.c:63
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:5355
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:5335
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:5380

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().

◆ ExplainEndOutput()

void ExplainEndOutput ( ExplainState es)

Definition at line 5235 of file explain.c.

5236 {
5237  switch (es->format)
5238  {
5239  case EXPLAIN_FORMAT_TEXT:
5240  /* nothing to do */
5241  break;
5242 
5243  case EXPLAIN_FORMAT_XML:
5244  es->indent--;
5245  appendStringInfoString(es->str, "</explain>");
5246  break;
5247 
5248  case EXPLAIN_FORMAT_JSON:
5249  es->indent--;
5250  appendStringInfoString(es->str, "\n]");
5252  break;
5253 
5254  case EXPLAIN_FORMAT_YAML:
5256  break;
5257  }
5258 }

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().

◆ ExplainFlushWorkersState()

static void ExplainFlushWorkersState ( ExplainState es)
static

Definition at line 4677 of file explain.c.

4678 {
4679  ExplainWorkersState *wstate = es->workers_state;
4680 
4681  ExplainOpenGroup("Workers", "Workers", false, es);
4682  for (int i = 0; i < wstate->num_workers; i++)
4683  {
4684  if (wstate->worker_inited[i])
4685  {
4686  /* This must match previous ExplainOpenSetAsideGroup call */
4687  ExplainOpenGroup("Worker", NULL, true, es);
4688  appendStringInfoString(es->str, wstate->worker_str[i].data);
4689  ExplainCloseGroup("Worker", NULL, true, es);
4690 
4691  pfree(wstate->worker_str[i].data);
4692  }
4693  }
4694  ExplainCloseGroup("Workers", "Workers", false, es);
4695 
4696  pfree(wstate->worker_inited);
4697  pfree(wstate->worker_str);
4698  pfree(wstate->worker_state_save);
4699  pfree(wstate);
4700 }
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4948
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:5011
int i
Definition: isn.c:73
void pfree(void *pointer)
Definition: mcxt.c:1521

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().

◆ ExplainIndentText()

◆ ExplainIndexScanDetails()

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

Definition at line 4057 of file explain.c.

4059 {
4060  const char *indexname = explain_get_index_name(indexid);
4061 
4062  if (es->format == EXPLAIN_FORMAT_TEXT)
4063  {
4064  if (ScanDirectionIsBackward(indexorderdir))
4065  appendStringInfoString(es->str, " Backward");
4066  appendStringInfo(es->str, " using %s", quote_identifier(indexname));
4067  }
4068  else
4069  {
4070  const char *scandir;
4071 
4072  switch (indexorderdir)
4073  {
4074  case BackwardScanDirection:
4075  scandir = "Backward";
4076  break;
4077  case ForwardScanDirection:
4078  scandir = "Forward";
4079  break;
4080  default:
4081  scandir = "???";
4082  break;
4083  }
4084  ExplainPropertyText("Scan Direction", scandir, es);
4085  ExplainPropertyText("Index Name", indexname, es);
4086  }
4087 }
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:4883
static const char * explain_get_index_name(Oid indexId)
Definition: explain.c:3760
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:12596
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:50
@ BackwardScanDirection
Definition: sdir.h:26
@ ForwardScanDirection
Definition: sdir.h:28
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97

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

Referenced by ExplainNode().

◆ ExplainJSONLineEnding()

static void ExplainJSONLineEnding ( ExplainState es)
static

◆ ExplainMemberNodes()

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

Definition at line 4465 of file explain.c.

4467 {
4468  int j;
4469 
4470  for (j = 0; j < nplans; j++)
4471  ExplainNode(planstates[j], ancestors,
4472  "Member", NULL, es);
4473 }
int j
Definition: isn.c:74

References ExplainNode(), and j.

Referenced by ExplainNode().

◆ ExplainMissingMembers()

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

Definition at line 4483 of file explain.c.

4484 {
4485  if (nplans < nchildren || es->format != EXPLAIN_FORMAT_TEXT)
4486  ExplainPropertyInteger("Subplans Removed", NULL,
4487  nchildren - nplans, es);
4488 }
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:4892
static char format

References EXPLAIN_FORMAT_TEXT, ExplainPropertyInteger(), and format.

Referenced by ExplainNode().

◆ ExplainModifyTarget()

static void ExplainModifyTarget ( ModifyTable plan,
ExplainState es 
)
static

Definition at line 4106 of file explain.c.

4107 {
4108  ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
4109 }
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:4115
#define plan(x)
Definition: pg_regress.c:162

References ExplainTargetRel(), and plan.

Referenced by ExplainNode().

◆ ExplainNode()

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

Definition at line 1368 of file explain.c.

1371 {
1372  Plan *plan = planstate->plan;
1373  const char *pname; /* node type name for text output */
1374  const char *sname; /* node type name for non-text output */
1375  const char *strategy = NULL;
1376  const char *partialmode = NULL;
1377  const char *operation = NULL;
1378  const char *custom_name = NULL;
1379  ExplainWorkersState *save_workers_state = es->workers_state;
1380  int save_indent = es->indent;
1381  bool haschildren;
1382 
1383  /*
1384  * Prepare per-worker output buffers, if needed. We'll append the data in
1385  * these to the main output string further down.
1386  */
1387  if (planstate->worker_instrument && es->analyze && !es->hide_workers)
1389  else
1390  es->workers_state = NULL;
1391 
1392  /* Identify plan node type, and print generic details */
1393  switch (nodeTag(plan))
1394  {
1395  case T_Result:
1396  pname = sname = "Result";
1397  break;
1398  case T_ProjectSet:
1399  pname = sname = "ProjectSet";
1400  break;
1401  case T_ModifyTable:
1402  sname = "ModifyTable";
1403  switch (((ModifyTable *) plan)->operation)
1404  {
1405  case CMD_INSERT:
1406  pname = operation = "Insert";
1407  break;
1408  case CMD_UPDATE:
1409  pname = operation = "Update";
1410  break;
1411  case CMD_DELETE:
1412  pname = operation = "Delete";
1413  break;
1414  case CMD_MERGE:
1415  pname = operation = "Merge";
1416  break;
1417  default:
1418  pname = "???";
1419  break;
1420  }
1421  break;
1422  case T_Append:
1423  pname = sname = "Append";
1424  break;
1425  case T_MergeAppend:
1426  pname = sname = "Merge Append";
1427  break;
1428  case T_RecursiveUnion:
1429  pname = sname = "Recursive Union";
1430  break;
1431  case T_BitmapAnd:
1432  pname = sname = "BitmapAnd";
1433  break;
1434  case T_BitmapOr:
1435  pname = sname = "BitmapOr";
1436  break;
1437  case T_NestLoop:
1438  pname = sname = "Nested Loop";
1439  break;
1440  case T_MergeJoin:
1441  pname = "Merge"; /* "Join" gets added by jointype switch */
1442  sname = "Merge Join";
1443  break;
1444  case T_HashJoin:
1445  pname = "Hash"; /* "Join" gets added by jointype switch */
1446  sname = "Hash Join";
1447  break;
1448  case T_SeqScan:
1449  pname = sname = "Seq Scan";
1450  break;
1451  case T_SampleScan:
1452  pname = sname = "Sample Scan";
1453  break;
1454  case T_Gather:
1455  pname = sname = "Gather";
1456  break;
1457  case T_GatherMerge:
1458  pname = sname = "Gather Merge";
1459  break;
1460  case T_IndexScan:
1461  pname = sname = "Index Scan";
1462  break;
1463  case T_IndexOnlyScan:
1464  pname = sname = "Index Only Scan";
1465  break;
1466  case T_BitmapIndexScan:
1467  pname = sname = "Bitmap Index Scan";
1468  break;
1469  case T_BitmapHeapScan:
1470  pname = sname = "Bitmap Heap Scan";
1471  break;
1472  case T_TidScan:
1473  pname = sname = "Tid Scan";
1474  break;
1475  case T_TidRangeScan:
1476  pname = sname = "Tid Range Scan";
1477  break;
1478  case T_SubqueryScan:
1479  pname = sname = "Subquery Scan";
1480  break;
1481  case T_FunctionScan:
1482  pname = sname = "Function Scan";
1483  break;
1484  case T_TableFuncScan:
1485  pname = sname = "Table Function Scan";
1486  break;
1487  case T_ValuesScan:
1488  pname = sname = "Values Scan";
1489  break;
1490  case T_CteScan:
1491  pname = sname = "CTE Scan";
1492  break;
1493  case T_NamedTuplestoreScan:
1494  pname = sname = "Named Tuplestore Scan";
1495  break;
1496  case T_WorkTableScan:
1497  pname = sname = "WorkTable Scan";
1498  break;
1499  case T_ForeignScan:
1500  sname = "Foreign Scan";
1501  switch (((ForeignScan *) plan)->operation)
1502  {
1503  case CMD_SELECT:
1504  pname = "Foreign Scan";
1505  operation = "Select";
1506  break;
1507  case CMD_INSERT:
1508  pname = "Foreign Insert";
1509  operation = "Insert";
1510  break;
1511  case CMD_UPDATE:
1512  pname = "Foreign Update";
1513  operation = "Update";
1514  break;
1515  case CMD_DELETE:
1516  pname = "Foreign Delete";
1517  operation = "Delete";
1518  break;
1519  default:
1520  pname = "???";
1521  break;
1522  }
1523  break;
1524  case T_CustomScan:
1525  sname = "Custom Scan";
1526  custom_name = ((CustomScan *) plan)->methods->CustomName;
1527  if (custom_name)
1528  pname = psprintf("Custom Scan (%s)", custom_name);
1529  else
1530  pname = sname;
1531  break;
1532  case T_Material:
1533  pname = sname = "Materialize";
1534  break;
1535  case T_Memoize:
1536  pname = sname = "Memoize";
1537  break;
1538  case T_Sort:
1539  pname = sname = "Sort";
1540  break;
1541  case T_IncrementalSort:
1542  pname = sname = "Incremental Sort";
1543  break;
1544  case T_Group:
1545  pname = sname = "Group";
1546  break;
1547  case T_Agg:
1548  {
1549  Agg *agg = (Agg *) plan;
1550 
1551  sname = "Aggregate";
1552  switch (agg->aggstrategy)
1553  {
1554  case AGG_PLAIN:
1555  pname = "Aggregate";
1556  strategy = "Plain";
1557  break;
1558  case AGG_SORTED:
1559  pname = "GroupAggregate";
1560  strategy = "Sorted";
1561  break;
1562  case AGG_HASHED:
1563  pname = "HashAggregate";
1564  strategy = "Hashed";
1565  break;
1566  case AGG_MIXED:
1567  pname = "MixedAggregate";
1568  strategy = "Mixed";
1569  break;
1570  default:
1571  pname = "Aggregate ???";
1572  strategy = "???";
1573  break;
1574  }
1575 
1576  if (DO_AGGSPLIT_SKIPFINAL(agg->aggsplit))
1577  {
1578  partialmode = "Partial";
1579  pname = psprintf("%s %s", partialmode, pname);
1580  }
1581  else if (DO_AGGSPLIT_COMBINE(agg->aggsplit))
1582  {
1583  partialmode = "Finalize";
1584  pname = psprintf("%s %s", partialmode, pname);
1585  }
1586  else
1587  partialmode = "Simple";
1588  }
1589  break;
1590  case T_WindowAgg:
1591  pname = sname = "WindowAgg";
1592  break;
1593  case T_Unique:
1594  pname = sname = "Unique";
1595  break;
1596  case T_SetOp:
1597  sname = "SetOp";
1598  switch (((SetOp *) plan)->strategy)
1599  {
1600  case SETOP_SORTED:
1601  pname = "SetOp";
1602  strategy = "Sorted";
1603  break;
1604  case SETOP_HASHED:
1605  pname = "HashSetOp";
1606  strategy = "Hashed";
1607  break;
1608  default:
1609  pname = "SetOp ???";
1610  strategy = "???";
1611  break;
1612  }
1613  break;
1614  case T_LockRows:
1615  pname = sname = "LockRows";
1616  break;
1617  case T_Limit:
1618  pname = sname = "Limit";
1619  break;
1620  case T_Hash:
1621  pname = sname = "Hash";
1622  break;
1623  default:
1624  pname = sname = "???";
1625  break;
1626  }
1627 
1628  ExplainOpenGroup("Plan",
1629  relationship ? NULL : "Plan",
1630  true, es);
1631 
1632  if (es->format == EXPLAIN_FORMAT_TEXT)
1633  {
1634  if (plan_name)
1635  {
1636  ExplainIndentText(es);
1637  appendStringInfo(es->str, "%s\n", plan_name);
1638  es->indent++;
1639  }
1640  if (es->indent)
1641  {
1642  ExplainIndentText(es);
1643  appendStringInfoString(es->str, "-> ");
1644  es->indent += 2;
1645  }
1646  if (plan->parallel_aware)
1647  appendStringInfoString(es->str, "Parallel ");
1648  if (plan->async_capable)
1649  appendStringInfoString(es->str, "Async ");
1650  appendStringInfoString(es->str, pname);
1651  es->indent++;
1652  }
1653  else
1654  {
1655  ExplainPropertyText("Node Type", sname, es);
1656  if (strategy)
1657  ExplainPropertyText("Strategy", strategy, es);
1658  if (partialmode)
1659  ExplainPropertyText("Partial Mode", partialmode, es);
1660  if (operation)
1661  ExplainPropertyText("Operation", operation, es);
1662  if (relationship)
1663  ExplainPropertyText("Parent Relationship", relationship, es);
1664  if (plan_name)
1665  ExplainPropertyText("Subplan Name", plan_name, es);
1666  if (custom_name)
1667  ExplainPropertyText("Custom Plan Provider", custom_name, es);
1668  ExplainPropertyBool("Parallel Aware", plan->parallel_aware, es);
1669  ExplainPropertyBool("Async Capable", plan->async_capable, es);
1670  }
1671 
1672  switch (nodeTag(plan))
1673  {
1674  case T_SeqScan:
1675  case T_SampleScan:
1676  case T_BitmapHeapScan:
1677  case T_TidScan:
1678  case T_TidRangeScan:
1679  case T_SubqueryScan:
1680  case T_FunctionScan:
1681  case T_TableFuncScan:
1682  case T_ValuesScan:
1683  case T_CteScan:
1684  case T_WorkTableScan:
1685  ExplainScanTarget((Scan *) plan, es);
1686  break;
1687  case T_ForeignScan:
1688  case T_CustomScan:
1689  if (((Scan *) plan)->scanrelid > 0)
1690  ExplainScanTarget((Scan *) plan, es);
1691  break;
1692  case T_IndexScan:
1693  {
1694  IndexScan *indexscan = (IndexScan *) plan;
1695 
1696  ExplainIndexScanDetails(indexscan->indexid,
1697  indexscan->indexorderdir,
1698  es);
1699  ExplainScanTarget((Scan *) indexscan, es);
1700  }
1701  break;
1702  case T_IndexOnlyScan:
1703  {
1704  IndexOnlyScan *indexonlyscan = (IndexOnlyScan *) plan;
1705 
1706  ExplainIndexScanDetails(indexonlyscan->indexid,
1707  indexonlyscan->indexorderdir,
1708  es);
1709  ExplainScanTarget((Scan *) indexonlyscan, es);
1710  }
1711  break;
1712  case T_BitmapIndexScan:
1713  {
1714  BitmapIndexScan *bitmapindexscan = (BitmapIndexScan *) plan;
1715  const char *indexname =
1716  explain_get_index_name(bitmapindexscan->indexid);
1717 
1718  if (es->format == EXPLAIN_FORMAT_TEXT)
1719  appendStringInfo(es->str, " on %s",
1720  quote_identifier(indexname));
1721  else
1722  ExplainPropertyText("Index Name", indexname, es);
1723  }
1724  break;
1725  case T_ModifyTable:
1727  break;
1728  case T_NestLoop:
1729  case T_MergeJoin:
1730  case T_HashJoin:
1731  {
1732  const char *jointype;
1733 
1734  switch (((Join *) plan)->jointype)
1735  {
1736  case JOIN_INNER:
1737  jointype = "Inner";
1738  break;
1739  case JOIN_LEFT:
1740  jointype = "Left";
1741  break;
1742  case JOIN_FULL:
1743  jointype = "Full";
1744  break;
1745  case JOIN_RIGHT:
1746  jointype = "Right";
1747  break;
1748  case JOIN_SEMI:
1749  jointype = "Semi";
1750  break;
1751  case JOIN_ANTI:
1752  jointype = "Anti";
1753  break;
1754  case JOIN_RIGHT_SEMI:
1755  jointype = "Right Semi";
1756  break;
1757  case JOIN_RIGHT_ANTI:
1758  jointype = "Right Anti";
1759  break;
1760  default:
1761  jointype = "???";
1762  break;
1763  }
1764  if (es->format == EXPLAIN_FORMAT_TEXT)
1765  {
1766  /*
1767  * For historical reasons, the join type is interpolated
1768  * into the node type name...
1769  */
1770  if (((Join *) plan)->jointype != JOIN_INNER)
1771  appendStringInfo(es->str, " %s Join", jointype);
1772  else if (!IsA(plan, NestLoop))
1773  appendStringInfoString(es->str, " Join");
1774  }
1775  else
1776  ExplainPropertyText("Join Type", jointype, es);
1777  }
1778  break;
1779  case T_SetOp:
1780  {
1781  const char *setopcmd;
1782 
1783  switch (((SetOp *) plan)->cmd)
1784  {
1785  case SETOPCMD_INTERSECT:
1786  setopcmd = "Intersect";
1787  break;
1789  setopcmd = "Intersect All";
1790  break;
1791  case SETOPCMD_EXCEPT:
1792  setopcmd = "Except";
1793  break;
1794  case SETOPCMD_EXCEPT_ALL:
1795  setopcmd = "Except All";
1796  break;
1797  default:
1798  setopcmd = "???";
1799  break;
1800  }
1801  if (es->format == EXPLAIN_FORMAT_TEXT)
1802  appendStringInfo(es->str, " %s", setopcmd);
1803  else
1804  ExplainPropertyText("Command", setopcmd, es);
1805  }
1806  break;
1807  default:
1808  break;
1809  }
1810 
1811  if (es->costs)
1812  {
1813  if (es->format == EXPLAIN_FORMAT_TEXT)
1814  {
1815  appendStringInfo(es->str, " (cost=%.2f..%.2f rows=%.0f width=%d)",
1816  plan->startup_cost, plan->total_cost,
1817  plan->plan_rows, plan->plan_width);
1818  }
1819  else
1820  {
1821  ExplainPropertyFloat("Startup Cost", NULL, plan->startup_cost,
1822  2, es);
1823  ExplainPropertyFloat("Total Cost", NULL, plan->total_cost,
1824  2, es);
1825  ExplainPropertyFloat("Plan Rows", NULL, plan->plan_rows,
1826  0, es);
1827  ExplainPropertyInteger("Plan Width", NULL, plan->plan_width,
1828  es);
1829  }
1830  }
1831 
1832  /*
1833  * We have to forcibly clean up the instrumentation state because we
1834  * haven't done ExecutorEnd yet. This is pretty grotty ...
1835  *
1836  * Note: contrib/auto_explain could cause instrumentation to be set up
1837  * even though we didn't ask for it here. Be careful not to print any
1838  * instrumentation results the user didn't ask for. But we do the
1839  * InstrEndLoop call anyway, if possible, to reduce the number of cases
1840  * auto_explain has to contend with.
1841  */
1842  if (planstate->instrument)
1843  InstrEndLoop(planstate->instrument);
1844 
1845  if (es->analyze &&
1846  planstate->instrument && planstate->instrument->nloops > 0)
1847  {
1848  double nloops = planstate->instrument->nloops;
1849  double startup_ms = 1000.0 * planstate->instrument->startup / nloops;
1850  double total_ms = 1000.0 * planstate->instrument->total / nloops;
1851  double rows = planstate->instrument->ntuples / nloops;
1852 
1853  if (es->format == EXPLAIN_FORMAT_TEXT)
1854  {
1855  if (es->timing)
1856  appendStringInfo(es->str,
1857  " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",
1858  startup_ms, total_ms, rows, nloops);
1859  else
1860  appendStringInfo(es->str,
1861  " (actual rows=%.0f loops=%.0f)",
1862  rows, nloops);
1863  }
1864  else
1865  {
1866  if (es->timing)
1867  {
1868  ExplainPropertyFloat("Actual Startup Time", "ms", startup_ms,
1869  3, es);
1870  ExplainPropertyFloat("Actual Total Time", "ms", total_ms,
1871  3, es);
1872  }
1873  ExplainPropertyFloat("Actual Rows", NULL, rows, 0, es);
1874  ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es);
1875  }
1876  }
1877  else if (es->analyze)
1878  {
1879  if (es->format == EXPLAIN_FORMAT_TEXT)
1880  appendStringInfoString(es->str, " (never executed)");
1881  else
1882  {
1883  if (es->timing)
1884  {
1885  ExplainPropertyFloat("Actual Startup Time", "ms", 0.0, 3, es);
1886  ExplainPropertyFloat("Actual Total Time", "ms", 0.0, 3, es);
1887  }
1888  ExplainPropertyFloat("Actual Rows", NULL, 0.0, 0, es);
1889  ExplainPropertyFloat("Actual Loops", NULL, 0.0, 0, es);
1890  }
1891  }
1892 
1893  /* in text format, first line ends here */
1894  if (es->format == EXPLAIN_FORMAT_TEXT)
1895  appendStringInfoChar(es->str, '\n');
1896 
1897  /* prepare per-worker general execution details */
1898  if (es->workers_state && es->verbose)
1899  {
1900  WorkerInstrumentation *w = planstate->worker_instrument;
1901 
1902  for (int n = 0; n < w->num_workers; n++)
1903  {
1904  Instrumentation *instrument = &w->instrument[n];
1905  double nloops = instrument->nloops;
1906  double startup_ms;
1907  double total_ms;
1908  double rows;
1909 
1910  if (nloops <= 0)
1911  continue;
1912  startup_ms = 1000.0 * instrument->startup / nloops;
1913  total_ms = 1000.0 * instrument->total / nloops;
1914  rows = instrument->ntuples / nloops;
1915 
1916  ExplainOpenWorker(n, es);
1917 
1918  if (es->format == EXPLAIN_FORMAT_TEXT)
1919  {
1920  ExplainIndentText(es);
1921  if (es->timing)
1922  appendStringInfo(es->str,
1923  "actual time=%.3f..%.3f rows=%.0f loops=%.0f\n",
1924  startup_ms, total_ms, rows, nloops);
1925  else
1926  appendStringInfo(es->str,
1927  "actual rows=%.0f loops=%.0f\n",
1928  rows, nloops);
1929  }
1930  else
1931  {
1932  if (es->timing)
1933  {
1934  ExplainPropertyFloat("Actual Startup Time", "ms",
1935  startup_ms, 3, es);
1936  ExplainPropertyFloat("Actual Total Time", "ms",
1937  total_ms, 3, es);
1938  }
1939  ExplainPropertyFloat("Actual Rows", NULL, rows, 0, es);
1940  ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es);
1941  }
1942 
1943  ExplainCloseWorker(n, es);
1944  }
1945  }
1946 
1947  /* target list */
1948  if (es->verbose)
1949  show_plan_tlist(planstate, ancestors, es);
1950 
1951  /* unique join */
1952  switch (nodeTag(plan))
1953  {
1954  case T_NestLoop:
1955  case T_MergeJoin:
1956  case T_HashJoin:
1957  /* try not to be too chatty about this in text mode */
1958  if (es->format != EXPLAIN_FORMAT_TEXT ||
1959  (es->verbose && ((Join *) plan)->inner_unique))
1960  ExplainPropertyBool("Inner Unique",
1961  ((Join *) plan)->inner_unique,
1962  es);
1963  break;
1964  default:
1965  break;
1966  }
1967 
1968  /* quals, sort keys, etc */
1969  switch (nodeTag(plan))
1970  {
1971  case T_IndexScan:
1972  show_scan_qual(((IndexScan *) plan)->indexqualorig,
1973  "Index Cond", planstate, ancestors, es);
1974  if (((IndexScan *) plan)->indexqualorig)
1975  show_instrumentation_count("Rows Removed by Index Recheck", 2,
1976  planstate, es);
1977  show_scan_qual(((IndexScan *) plan)->indexorderbyorig,
1978  "Order By", planstate, ancestors, es);
1979  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1980  if (plan->qual)
1981  show_instrumentation_count("Rows Removed by Filter", 1,
1982  planstate, es);
1983  break;
1984  case T_IndexOnlyScan:
1985  show_scan_qual(((IndexOnlyScan *) plan)->indexqual,
1986  "Index Cond", planstate, ancestors, es);
1987  if (((IndexOnlyScan *) plan)->recheckqual)
1988  show_instrumentation_count("Rows Removed by Index Recheck", 2,
1989  planstate, es);
1990  show_scan_qual(((IndexOnlyScan *) plan)->indexorderby,
1991  "Order By", planstate, ancestors, es);
1992  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1993  if (plan->qual)
1994  show_instrumentation_count("Rows Removed by Filter", 1,
1995  planstate, es);
1996  if (es->analyze)
1997  ExplainPropertyFloat("Heap Fetches", NULL,
1998  planstate->instrument->ntuples2, 0, es);
1999  break;
2000  case T_BitmapIndexScan:
2001  show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig,
2002  "Index Cond", planstate, ancestors, es);
2003  break;
2004  case T_BitmapHeapScan:
2005  show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig,
2006  "Recheck Cond", planstate, ancestors, es);
2007  if (((BitmapHeapScan *) plan)->bitmapqualorig)
2008  show_instrumentation_count("Rows Removed by Index Recheck", 2,
2009  planstate, es);
2010  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2011  if (plan->qual)
2012  show_instrumentation_count("Rows Removed by Filter", 1,
2013  planstate, es);
2014  show_tidbitmap_info((BitmapHeapScanState *) planstate, es);
2015  break;
2016  case T_SampleScan:
2017  show_tablesample(((SampleScan *) plan)->tablesample,
2018  planstate, ancestors, es);
2019  /* fall through to print additional fields the same as SeqScan */
2020  /* FALLTHROUGH */
2021  case T_SeqScan:
2022  case T_ValuesScan:
2023  case T_CteScan:
2024  case T_NamedTuplestoreScan:
2025  case T_WorkTableScan:
2026  case T_SubqueryScan:
2027  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2028  if (plan->qual)
2029  show_instrumentation_count("Rows Removed by Filter", 1,
2030  planstate, es);
2031  break;
2032  case T_Gather:
2033  {
2034  Gather *gather = (Gather *) plan;
2035 
2036  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2037  if (plan->qual)
2038  show_instrumentation_count("Rows Removed by Filter", 1,
2039  planstate, es);
2040  ExplainPropertyInteger("Workers Planned", NULL,
2041  gather->num_workers, es);
2042 
2043  if (es->analyze)
2044  {
2045  int nworkers;
2046 
2047  nworkers = ((GatherState *) planstate)->nworkers_launched;
2048  ExplainPropertyInteger("Workers Launched", NULL,
2049  nworkers, es);
2050  }
2051 
2052  if (gather->single_copy || es->format != EXPLAIN_FORMAT_TEXT)
2053  ExplainPropertyBool("Single Copy", gather->single_copy, es);
2054  }
2055  break;
2056  case T_GatherMerge:
2057  {
2058  GatherMerge *gm = (GatherMerge *) plan;
2059 
2060  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2061  if (plan->qual)
2062  show_instrumentation_count("Rows Removed by Filter", 1,
2063  planstate, es);
2064  ExplainPropertyInteger("Workers Planned", NULL,
2065  gm->num_workers, es);
2066 
2067  if (es->analyze)
2068  {
2069  int nworkers;
2070 
2071  nworkers = ((GatherMergeState *) planstate)->nworkers_launched;
2072  ExplainPropertyInteger("Workers Launched", NULL,
2073  nworkers, es);
2074  }
2075  }
2076  break;
2077  case T_FunctionScan:
2078  if (es->verbose)
2079  {
2080  List *fexprs = NIL;
2081  ListCell *lc;
2082 
2083  foreach(lc, ((FunctionScan *) plan)->functions)
2084  {
2085  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
2086 
2087  fexprs = lappend(fexprs, rtfunc->funcexpr);
2088  }
2089  /* We rely on show_expression to insert commas as needed */
2090  show_expression((Node *) fexprs,
2091  "Function Call", planstate, ancestors,
2092  es->verbose, es);
2093  }
2094  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2095  if (plan->qual)
2096  show_instrumentation_count("Rows Removed by Filter", 1,
2097  planstate, es);
2098  break;
2099  case T_TableFuncScan:
2100  if (es->verbose)
2101  {
2102  TableFunc *tablefunc = ((TableFuncScan *) plan)->tablefunc;
2103 
2104  show_expression((Node *) tablefunc,
2105  "Table Function Call", planstate, ancestors,
2106  es->verbose, es);
2107  }
2108  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2109  if (plan->qual)
2110  show_instrumentation_count("Rows Removed by Filter", 1,
2111  planstate, es);
2112  break;
2113  case T_TidScan:
2114  {
2115  /*
2116  * The tidquals list has OR semantics, so be sure to show it
2117  * as an OR condition.
2118  */
2119  List *tidquals = ((TidScan *) plan)->tidquals;
2120 
2121  if (list_length(tidquals) > 1)
2122  tidquals = list_make1(make_orclause(tidquals));
2123  show_scan_qual(tidquals, "TID Cond", planstate, ancestors, es);
2124  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2125  if (plan->qual)
2126  show_instrumentation_count("Rows Removed by Filter", 1,
2127  planstate, es);
2128  }
2129  break;
2130  case T_TidRangeScan:
2131  {
2132  /*
2133  * The tidrangequals list has AND semantics, so be sure to
2134  * show it as an AND condition.
2135  */
2136  List *tidquals = ((TidRangeScan *) plan)->tidrangequals;
2137 
2138  if (list_length(tidquals) > 1)
2139  tidquals = list_make1(make_andclause(tidquals));
2140  show_scan_qual(tidquals, "TID Cond", planstate, ancestors, es);
2141  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2142  if (plan->qual)
2143  show_instrumentation_count("Rows Removed by Filter", 1,
2144  planstate, es);
2145  }
2146  break;
2147  case T_ForeignScan:
2148  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2149  if (plan->qual)
2150  show_instrumentation_count("Rows Removed by Filter", 1,
2151  planstate, es);
2152  show_foreignscan_info((ForeignScanState *) planstate, es);
2153  break;
2154  case T_CustomScan:
2155  {
2156  CustomScanState *css = (CustomScanState *) planstate;
2157 
2158  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2159  if (plan->qual)
2160  show_instrumentation_count("Rows Removed by Filter", 1,
2161  planstate, es);
2162  if (css->methods->ExplainCustomScan)
2163  css->methods->ExplainCustomScan(css, ancestors, es);
2164  }
2165  break;
2166  case T_NestLoop:
2167  show_upper_qual(((NestLoop *) plan)->join.joinqual,
2168  "Join Filter", planstate, ancestors, es);
2169  if (((NestLoop *) plan)->join.joinqual)
2170  show_instrumentation_count("Rows Removed by Join Filter", 1,
2171  planstate, es);
2172  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
2173  if (plan->qual)
2174  show_instrumentation_count("Rows Removed by Filter", 2,
2175  planstate, es);
2176  break;
2177  case T_MergeJoin:
2178  show_upper_qual(((MergeJoin *) plan)->mergeclauses,
2179  "Merge Cond", planstate, ancestors, es);
2180  show_upper_qual(((MergeJoin *) plan)->join.joinqual,
2181  "Join Filter", planstate, ancestors, es);
2182  if (((MergeJoin *) plan)->join.joinqual)
2183  show_instrumentation_count("Rows Removed by Join Filter", 1,
2184  planstate, es);
2185  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
2186  if (plan->qual)
2187  show_instrumentation_count("Rows Removed by Filter", 2,
2188  planstate, es);
2189  break;
2190  case T_HashJoin:
2191  show_upper_qual(((HashJoin *) plan)->hashclauses,
2192  "Hash Cond", planstate, ancestors, es);
2193  show_upper_qual(((HashJoin *) plan)->join.joinqual,
2194  "Join Filter", planstate, ancestors, es);
2195  if (((HashJoin *) plan)->join.joinqual)
2196  show_instrumentation_count("Rows Removed by Join Filter", 1,
2197  planstate, es);
2198  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
2199  if (plan->qual)
2200  show_instrumentation_count("Rows Removed by Filter", 2,
2201  planstate, es);
2202  break;
2203  case T_Agg:
2204  show_agg_keys(castNode(AggState, planstate), ancestors, es);
2205  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
2206  show_hashagg_info((AggState *) planstate, es);
2207  if (plan->qual)
2208  show_instrumentation_count("Rows Removed by Filter", 1,
2209  planstate, es);
2210  break;
2211  case T_WindowAgg:
2212  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
2213  if (plan->qual)
2214  show_instrumentation_count("Rows Removed by Filter", 1,
2215  planstate, es);
2216  show_upper_qual(((WindowAgg *) plan)->runConditionOrig,
2217  "Run Condition", planstate, ancestors, es);
2218  break;
2219  case T_Group:
2220  show_group_keys(castNode(GroupState, planstate), ancestors, es);
2221  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
2222  if (plan->qual)
2223  show_instrumentation_count("Rows Removed by Filter", 1,
2224  planstate, es);
2225  break;
2226  case T_Sort:
2227  show_sort_keys(castNode(SortState, planstate), ancestors, es);
2228  show_sort_info(castNode(SortState, planstate), es);
2229  break;
2230  case T_IncrementalSort:
2232  ancestors, es);
2234  es);
2235  break;
2236  case T_MergeAppend:
2238  ancestors, es);
2239  break;
2240  case T_Result:
2241  show_upper_qual((List *) ((Result *) plan)->resconstantqual,
2242  "One-Time Filter", planstate, ancestors, es);
2243  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
2244  if (plan->qual)
2245  show_instrumentation_count("Rows Removed by Filter", 1,
2246  planstate, es);
2247  break;
2248  case T_ModifyTable:
2249  show_modifytable_info(castNode(ModifyTableState, planstate), ancestors,
2250  es);
2251  break;
2252  case T_Hash:
2253  show_hash_info(castNode(HashState, planstate), es);
2254  break;
2255  case T_Material:
2256  show_material_info(castNode(MaterialState, planstate), es);
2257  break;
2258  case T_Memoize:
2259  show_memoize_info(castNode(MemoizeState, planstate), ancestors,
2260  es);
2261  break;
2262  default:
2263  break;
2264  }
2265 
2266  /*
2267  * Prepare per-worker JIT instrumentation. As with the overall JIT
2268  * summary, this is printed only if printing costs is enabled.
2269  */
2270  if (es->workers_state && es->costs && es->verbose)
2271  {
2273 
2274  if (w)
2275  {
2276  for (int n = 0; n < w->num_workers; n++)
2277  {
2278  ExplainOpenWorker(n, es);
2279  ExplainPrintJIT(es, planstate->state->es_jit_flags,
2280  &w->jit_instr[n]);
2281  ExplainCloseWorker(n, es);
2282  }
2283  }
2284  }
2285 
2286  /* Show buffer/WAL usage */
2287  if (es->buffers && planstate->instrument)
2288  show_buffer_usage(es, &planstate->instrument->bufusage);
2289  if (es->wal && planstate->instrument)
2290  show_wal_usage(es, &planstate->instrument->walusage);
2291 
2292  /* Prepare per-worker buffer/WAL usage */
2293  if (es->workers_state && (es->buffers || es->wal) && es->verbose)
2294  {
2295  WorkerInstrumentation *w = planstate->worker_instrument;
2296 
2297  for (int n = 0; n < w->num_workers; n++)
2298  {
2299  Instrumentation *instrument = &w->instrument[n];
2300  double nloops = instrument->nloops;
2301 
2302  if (nloops <= 0)
2303  continue;
2304 
2305  ExplainOpenWorker(n, es);
2306  if (es->buffers)
2307  show_buffer_usage(es, &instrument->bufusage);
2308  if (es->wal)
2309  show_wal_usage(es, &instrument->walusage);
2310  ExplainCloseWorker(n, es);
2311  }
2312  }
2313 
2314  /* Show per-worker details for this plan node, then pop that stack */
2315  if (es->workers_state)
2317  es->workers_state = save_workers_state;
2318 
2319  /*
2320  * If partition pruning was done during executor initialization, the
2321  * number of child plans we'll display below will be less than the number
2322  * of subplans that was specified in the plan. To make this a bit less
2323  * mysterious, emit an indication that this happened. Note that this
2324  * field is emitted now because we want it to be a property of the parent
2325  * node; it *cannot* be emitted within the Plans sub-node we'll open next.
2326  */
2327  switch (nodeTag(plan))
2328  {
2329  case T_Append:
2330  ExplainMissingMembers(((AppendState *) planstate)->as_nplans,
2331  list_length(((Append *) plan)->appendplans),
2332  es);
2333  break;
2334  case T_MergeAppend:
2335  ExplainMissingMembers(((MergeAppendState *) planstate)->ms_nplans,
2336  list_length(((MergeAppend *) plan)->mergeplans),
2337  es);
2338  break;
2339  default:
2340  break;
2341  }
2342 
2343  /* Get ready to display the child plans */
2344  haschildren = planstate->initPlan ||
2345  outerPlanState(planstate) ||
2346  innerPlanState(planstate) ||
2347  IsA(plan, Append) ||
2348  IsA(plan, MergeAppend) ||
2349  IsA(plan, BitmapAnd) ||
2350  IsA(plan, BitmapOr) ||
2351  IsA(plan, SubqueryScan) ||
2352  (IsA(planstate, CustomScanState) &&
2353  ((CustomScanState *) planstate)->custom_ps != NIL) ||
2354  planstate->subPlan;
2355  if (haschildren)
2356  {
2357  ExplainOpenGroup("Plans", "Plans", false, es);
2358  /* Pass current Plan as head of ancestors list for children */
2359  ancestors = lcons(plan, ancestors);
2360  }
2361 
2362  /* initPlan-s */
2363  if (planstate->initPlan)
2364  ExplainSubPlans(planstate->initPlan, ancestors, "InitPlan", es);
2365 
2366  /* lefttree */
2367  if (outerPlanState(planstate))
2368  ExplainNode(outerPlanState(planstate), ancestors,
2369  "Outer", NULL, es);
2370 
2371  /* righttree */
2372  if (innerPlanState(planstate))
2373  ExplainNode(innerPlanState(planstate), ancestors,
2374  "Inner", NULL, es);
2375 
2376  /* special child plans */
2377  switch (nodeTag(plan))
2378  {
2379  case T_Append:
2380  ExplainMemberNodes(((AppendState *) planstate)->appendplans,
2381  ((AppendState *) planstate)->as_nplans,
2382  ancestors, es);
2383  break;
2384  case T_MergeAppend:
2385  ExplainMemberNodes(((MergeAppendState *) planstate)->mergeplans,
2386  ((MergeAppendState *) planstate)->ms_nplans,
2387  ancestors, es);
2388  break;
2389  case T_BitmapAnd:
2390  ExplainMemberNodes(((BitmapAndState *) planstate)->bitmapplans,
2391  ((BitmapAndState *) planstate)->nplans,
2392  ancestors, es);
2393  break;
2394  case T_BitmapOr:
2395  ExplainMemberNodes(((BitmapOrState *) planstate)->bitmapplans,
2396  ((BitmapOrState *) planstate)->nplans,
2397  ancestors, es);
2398  break;
2399  case T_SubqueryScan:
2400  ExplainNode(((SubqueryScanState *) planstate)->subplan, ancestors,
2401  "Subquery", NULL, es);
2402  break;
2403  case T_CustomScan:
2404  ExplainCustomChildren((CustomScanState *) planstate,
2405  ancestors, es);
2406  break;
2407  default:
2408  break;
2409  }
2410 
2411  /* subPlan-s */
2412  if (planstate->subPlan)
2413  ExplainSubPlans(planstate->subPlan, ancestors, "SubPlan", es);
2414 
2415  /* end of child plans */
2416  if (haschildren)
2417  {
2418  ancestors = list_delete_first(ancestors);
2419  ExplainCloseGroup("Plans", "Plans", false, es);
2420  }
2421 
2422  /* in text format, undo whatever indentation we added */
2423  if (es->format == EXPLAIN_FORMAT_TEXT)
2424  es->indent = save_indent;
2425 
2426  ExplainCloseGroup("Plan",
2427  relationship ? NULL : "Plan",
2428  true, es);
2429 }
#define outerPlanState(node)
Definition: execnodes.h:1212
#define innerPlanState(node)
Definition: execnodes.h:1211
static void show_modifytable_info(ModifyTableState *mtstate, List *ancestors, ExplainState *es)
Definition: explain.c:4253
static void show_plan_tlist(PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:2435
static void show_memoize_info(MemoizeState *mstate, List *ancestors, ExplainState *es)
Definition: explain.c:3369
static void show_group_keys(GroupState *gstate, List *ancestors, ExplainState *es)
Definition: explain.c:2745
static void ExplainModifyTarget(ModifyTable *plan, ExplainState *es)
Definition: explain.c:4106
static void show_agg_keys(AggState *astate, List *ancestors, ExplainState *es)
Definition: explain.c:2613
static void show_hashagg_info(AggState *aggstate, ExplainState *es)
Definition: explain.c:3513
static void show_scan_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:2537
static void ExplainIndexScanDetails(Oid indexid, ScanDirection indexorderdir, ExplainState *es)
Definition: explain.c:4057
static void show_instrumentation_count(const char *qlabel, int which, PlanState *planstate, ExplainState *es)
Definition: explain.c:3703
static void ExplainMemberNodes(PlanState **planstates, int nplans, List *ancestors, ExplainState *es)
Definition: explain.c:4465
static void ExplainPrintJIT(ExplainState *es, int jit_flags, JitInstrumentation *ji)
Definition: explain.c:1012
static void show_incremental_sort_info(IncrementalSortState *incrsortstate, ExplainState *es)
Definition: explain.c:3156
static void show_tablesample(TableSampleClause *tsc, PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:2885
static void show_upper_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:2551
static void show_sort_info(SortState *sortstate, ExplainState *es)
Definition: explain.c:2951
static void ExplainMissingMembers(int nplans, int nchildren, ExplainState *es)
Definition: explain.c:4483
static void ExplainFlushWorkersState(ExplainState *es)
Definition: explain.c:4677
static void show_hash_info(HashState *hashstate, ExplainState *es)
Definition: explain.c:3242
void ExplainPropertyFloat(const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
Definition: explain.c:4919
static void show_expression(Node *node, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
Definition: explain.c:2493
static void ExplainIndentText(ExplainState *es)
Definition: explain.c:5320
static void show_tidbitmap_info(BitmapHeapScanState *planstate, ExplainState *es)
Definition: explain.c:3634
static void ExplainSubPlans(List *plans, List *ancestors, const char *relationship, ExplainState *es)
Definition: explain.c:4497
static void show_foreignscan_info(ForeignScanState *fsstate, ExplainState *es)
Definition: explain.c:3732
static void ExplainScanTarget(Scan *plan, ExplainState *es)
Definition: explain.c:4093
static void show_merge_append_keys(MergeAppendState *mstate, List *ancestors, ExplainState *es)
Definition: explain.c:2597
static void ExplainCloseWorker(int n, ExplainState *es)
Definition: explain.c:4641
static void ExplainOpenWorker(int n, ExplainState *es)
Definition: explain.c:4579
static void show_wal_usage(ExplainState *es, const WalUsage *usage)
Definition: explain.c:3993
void ExplainPropertyBool(const char *qlabel, bool value, ExplainState *es)
Definition: explain.c:4933
static void show_material_info(MaterialState *mstate, ExplainState *es)
Definition: explain.c:3334
static void show_sort_keys(SortState *sortstate, List *ancestors, ExplainState *es)
Definition: explain.c:2565
static ExplainWorkersState * ExplainCreateWorkersState(int num_workers)
Definition: explain.c:4562
static void show_buffer_usage(ExplainState *es, const BufferUsage *usage)
Definition: explain.c:3824
static void show_incremental_sort_keys(IncrementalSortState *incrsortstate, List *ancestors, ExplainState *es)
Definition: explain.c:2580
static void ExplainCustomChildren(CustomScanState *css, List *ancestors, ExplainState *es)
Definition: explain.c:4540
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:140
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
List * lappend(List *list, void *datum)
Definition: list.c:339
List * lcons(void *datum, List *list)
Definition: list.c:495
Expr * make_andclause(List *andclauses)
Definition: makefuncs.c:654
Expr * make_orclause(List *orclauses)
Definition: makefuncs.c:670
@ SETOPCMD_EXCEPT
Definition: nodes.h:400
@ SETOPCMD_EXCEPT_ALL
Definition: nodes.h:401
@ SETOPCMD_INTERSECT_ALL
Definition: nodes.h:399
@ SETOPCMD_INTERSECT
Definition: nodes.h:398
@ SETOP_HASHED
Definition: nodes.h:407
@ SETOP_SORTED
Definition: nodes.h:406
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:386
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define nodeTag(nodeptr)
Definition: nodes.h:133
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:385
@ CMD_MERGE
Definition: nodes.h:269
@ CMD_INSERT
Definition: nodes.h:267
@ CMD_DELETE
Definition: nodes.h:268
@ CMD_UPDATE
Definition: nodes.h:266
@ CMD_SELECT
Definition: nodes.h:265
@ AGG_SORTED
Definition: nodes.h:355
@ AGG_HASHED
Definition: nodes.h:356
@ AGG_MIXED
Definition: nodes.h:357
@ AGG_PLAIN
Definition: nodes.h:354
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
@ JOIN_SEMI
Definition: nodes.h:307
@ JOIN_FULL
Definition: nodes.h:295
@ JOIN_INNER
Definition: nodes.h:293
@ JOIN_RIGHT
Definition: nodes.h:296
@ JOIN_RIGHT_SEMI
Definition: nodes.h:309
@ JOIN_LEFT
Definition: nodes.h:294
@ JOIN_RIGHT_ANTI
Definition: nodes.h:310
@ JOIN_ANTI
Definition: nodes.h:308
#define NIL
Definition: pg_list.h:68
#define list_make1(x1)
Definition: pg_list.h:212
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
static const struct fns functions
Definition: regcomp.c:356
Definition: plannodes.h:997
AggSplit aggsplit
Definition: plannodes.h:1004
AggStrategy aggstrategy
Definition: plannodes.h:1001
void(* ExplainCustomScan)(CustomScanState *node, List *ancestors, ExplainState *es)
Definition: extensible.h:155
const struct CustomExecMethods * methods
Definition: execnodes.h:2095
int es_jit_flags
Definition: execnodes.h:715
bool verbose
Definition: explain.h:48
bool hide_workers
Definition: explain.h:69
bool timing
Definition: explain.h:53
bool analyze
Definition: explain.h:49
bool wal
Definition: explain.h:52
bool costs
Definition: explain.h:50
bool buffers
Definition: explain.h:51
int num_workers
Definition: plannodes.h:1160
int num_workers
Definition: plannodes.h:1143
bool single_copy
Definition: plannodes.h:1145
ScanDirection indexorderdir
Definition: plannodes.h:500
ScanDirection indexorderdir
Definition: plannodes.h:458
Oid indexid
Definition: plannodes.h:452
double startup
Definition: instrument.h:84
WalUsage walusage
Definition: instrument.h:92
double ntuples
Definition: instrument.h:86
BufferUsage bufusage
Definition: instrument.h:91
double ntuples2
Definition: instrument.h:87
Definition: pg_list.h:54
Definition: nodes.h:129
struct SharedJitInstrumentation * worker_jit_instrument
Definition: execnodes.h:1130
Instrumentation * instrument
Definition: execnodes.h:1126
Plan * plan
Definition: execnodes.h:1116
EState * state
Definition: execnodes.h:1118
WorkerInstrumentation * worker_instrument
Definition: execnodes.h:1127
JitInstrumentation jit_instr[FLEXIBLE_ARRAY_MEMBER]
Definition: jit.h:54
Instrumentation instrument[FLEXIBLE_ARRAY_MEMBER]
Definition: instrument.h:98

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_MERGE, CMD_SELECT, CMD_UPDATE, ExplainState::costs, DO_AGGSPLIT_COMBINE, DO_AGGSPLIT_SKIPFINAL, EState::es_jit_flags, EXPLAIN_FORMAT_TEXT, explain_get_index_name(), ExplainCloseGroup(), ExplainCloseWorker(), ExplainCreateWorkersState(), ExplainCustomChildren(), CustomExecMethods::ExplainCustomScan, ExplainFlushWorkersState(), ExplainIndentText(), ExplainIndexScanDetails(), ExplainMemberNodes(), ExplainMissingMembers(), ExplainModifyTarget(), ExplainOpenGroup(), ExplainOpenWorker(), ExplainPrintJIT(), ExplainPropertyBool(), ExplainPropertyFloat(), ExplainPropertyInteger(), ExplainPropertyText(), ExplainScanTarget(), ExplainSubPlans(), ExplainState::format, RangeTblFunction::funcexpr, functions, ExplainState::hide_workers, if(), ExplainState::indent, IndexScan::indexid, IndexOnlyScan::indexid, BitmapIndexScan::indexid, IndexScan::indexorderdir, IndexOnlyScan::indexorderdir, PlanState::initPlan, innerPlanState, InstrEndLoop(), WorkerInstrumentation::instrument, PlanState::instrument, IsA, SharedJitInstrumentation::jit_instr, JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, JOIN_RIGHT_ANTI, JOIN_RIGHT_SEMI, JOIN_SEMI, lappend(), lcons(), lfirst, list_delete_first(), list_length(), list_make1, make_andclause(), make_orclause(), CustomScanState::methods, NIL, Instrumentation::nloops, nodeTag, Instrumentation::ntuples, Instrumentation::ntuples2, WorkerInstrumentation::num_workers, SharedJitInstrumentation::num_workers, Gather::num_workers, GatherMerge::num_workers, outerPlanState, PlanState::plan, plan, psprintf(), quote_identifier(), SETOP_HASHED, SETOP_SORTED, SETOPCMD_EXCEPT, SETOPCMD_EXCEPT_ALL, SETOPCMD_INTERSECT, SETOPCMD_INTERSECT_ALL, show_agg_keys(), show_buffer_usage(), show_expression(), show_foreignscan_info(), show_group_keys(), show_hash_info(), show_hashagg_info(), show_incremental_sort_info(), show_incremental_sort_keys(), show_instrumentation_count(), show_material_info(), show_memoize_info(), show_merge_append_keys(), show_modifytable_info(), show_plan_tlist(), show_scan_qual(), show_sort_info(), show_sort_keys(), show_tablesample(), show_tidbitmap_info(), show_upper_qual(), show_wal_usage(), Gather::single_copy, Instrumentation::startup, PlanState::state, ExplainState::str, PlanState::subPlan, ExplainState::timing, Instrumentation::total, ExplainState::verbose, ExplainState::wal, Instrumentation::walusage, PlanState::worker_instrument, PlanState::worker_jit_instrument, and ExplainState::workers_state.

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

◆ ExplainOnePlan()

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

Definition at line 618 of file explain.c.

623 {
625  QueryDesc *queryDesc;
626  instr_time starttime;
627  double totaltime = 0;
628  int eflags;
629  int instrument_option = 0;
630  SerializeMetrics serializeMetrics = {0};
631 
632  Assert(plannedstmt->commandType != CMD_UTILITY);
633 
634  if (es->analyze && es->timing)
635  instrument_option |= INSTRUMENT_TIMER;
636  else if (es->analyze)
637  instrument_option |= INSTRUMENT_ROWS;
638 
639  if (es->buffers)
640  instrument_option |= INSTRUMENT_BUFFERS;
641  if (es->wal)
642  instrument_option |= INSTRUMENT_WAL;
643 
644  /*
645  * We always collect timing for the entire statement, even when node-level
646  * timing is off, so we don't look at es->timing here. (We could skip
647  * this if !es->summary, but it's hardly worth the complication.)
648  */
649  INSTR_TIME_SET_CURRENT(starttime);
650 
651  /*
652  * Use a snapshot with an updated command ID to ensure this query sees
653  * results of any previously executed queries.
654  */
657 
658  /*
659  * We discard the output if we have no use for it. If we're explaining
660  * CREATE TABLE AS, we'd better use the appropriate tuple receiver, while
661  * the SERIALIZE option requires its own tuple receiver. (If you specify
662  * SERIALIZE while explaining CREATE TABLE AS, you'll see zeroes for the
663  * results, which is appropriate since no data would have gone to the
664  * client.)
665  */
666  if (into)
668  else if (es->serialize != EXPLAIN_SERIALIZE_NONE)
670  else
672 
673  /* Create a QueryDesc for the query */
674  queryDesc = CreateQueryDesc(plannedstmt, queryString,
676  dest, params, queryEnv, instrument_option);
677 
678  /* Select execution options */
679  if (es->analyze)
680  eflags = 0; /* default run-to-completion flags */
681  else
682  eflags = EXEC_FLAG_EXPLAIN_ONLY;
683  if (es->generic)
684  eflags |= EXEC_FLAG_EXPLAIN_GENERIC;
685  if (into)
686  eflags |= GetIntoRelEFlags(into);
687 
688  /* call ExecutorStart to prepare the plan for execution */
689  ExecutorStart(queryDesc, eflags);
690 
691  /* Execute the plan for statistics if asked for */
692  if (es->analyze)
693  {
694  ScanDirection dir;
695 
696  /* EXPLAIN ANALYZE CREATE TABLE AS WITH NO DATA is weird */
697  if (into && into->skipData)
699  else
700  dir = ForwardScanDirection;
701 
702  /* run the plan */
703  ExecutorRun(queryDesc, dir, 0, true);
704 
705  /* run cleanup too */
706  ExecutorFinish(queryDesc);
707 
708  /* We can't run ExecutorEnd 'till we're done printing the stats... */
709  totaltime += elapsed_time(&starttime);
710  }
711 
712  /* grab serialization metrics before we destroy the DestReceiver */
714  serializeMetrics = GetSerializationMetrics(dest);
715 
716  /* call the DestReceiver's destroy method even during explain */
717  dest->rDestroy(dest);
718 
719  ExplainOpenGroup("Query", NULL, true, es);
720 
721  /* Create textual dump of plan tree */
722  ExplainPrintPlan(es, queryDesc);
723 
724  /* Show buffer and/or memory usage in planning */
725  if (peek_buffer_usage(es, bufusage) || mem_counters)
726  {
727  ExplainOpenGroup("Planning", "Planning", true, es);
728 
729  if (es->format == EXPLAIN_FORMAT_TEXT)
730  {
731  ExplainIndentText(es);
732  appendStringInfoString(es->str, "Planning:\n");
733  es->indent++;
734  }
735 
736  if (bufusage)
737  show_buffer_usage(es, bufusage);
738 
739  if (mem_counters)
740  show_memory_counters(es, mem_counters);
741 
742  if (es->format == EXPLAIN_FORMAT_TEXT)
743  es->indent--;
744 
745  ExplainCloseGroup("Planning", "Planning", true, es);
746  }
747 
748  if (es->summary && planduration)
749  {
750  double plantime = INSTR_TIME_GET_DOUBLE(*planduration);
751 
752  ExplainPropertyFloat("Planning Time", "ms", 1000.0 * plantime, 3, es);
753  }
754 
755  /* Print info about runtime of triggers */
756  if (es->analyze)
757  ExplainPrintTriggers(es, queryDesc);
758 
759  /*
760  * Print info about JITing. Tied to es->costs because we don't want to
761  * display this in regression tests, as it'd cause output differences
762  * depending on build options. Might want to separate that out from COSTS
763  * at a later stage.
764  */
765  if (es->costs)
766  ExplainPrintJITSummary(es, queryDesc);
767 
768  /* Print info about serialization of output */
770  ExplainPrintSerialize(es, &serializeMetrics);
771 
772  /*
773  * Close down the query and free resources. Include time for this in the
774  * total execution time (although it should be pretty minimal).
775  */
776  INSTR_TIME_SET_CURRENT(starttime);
777 
778  ExecutorEnd(queryDesc);
779 
780  FreeQueryDesc(queryDesc);
781 
783 
784  /* We need a CCI just in case query expanded to multiple plans */
785  if (es->analyze)
787 
788  totaltime += elapsed_time(&starttime);
789 
790  /*
791  * We only report execution time if we actually ran the query (that is,
792  * the user specified ANALYZE), and if summary reporting is enabled (the
793  * user can set SUMMARY OFF to not have the timing information included in
794  * the output). By default, ANALYZE sets SUMMARY to true.
795  */
796  if (es->summary && es->analyze)
797  ExplainPropertyFloat("Execution Time", "ms", 1000.0 * totaltime, 3,
798  es);
799 
800  ExplainCloseGroup("Query", NULL, true, es);
801 }
DestReceiver * CreateIntoRelDestReceiver(IntoClause *intoClause)
Definition: createas.c:433
int GetIntoRelEFlags(IntoClause *intoClause)
Definition: createas.c:368
DestReceiver * None_Receiver
Definition: dest.c:96
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:467
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:407
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:124
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:297
#define EXEC_FLAG_EXPLAIN_GENERIC
Definition: executor.h:66
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:65
DestReceiver * CreateExplainSerializeDestReceiver(ExplainState *es)
Definition: explain.c:5637
static bool peek_buffer_usage(ExplainState *es, const BufferUsage *usage)
Definition: explain.c:3784
void ExplainPrintJITSummary(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:986
static double elapsed_time(instr_time *starttime)
Definition: explain.c:1274
static void show_memory_counters(ExplainState *es, const MemoryContextCounters *mem_counters)
Definition: explain.c:4031
void ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:878
static void ExplainPrintSerialize(ExplainState *es, SerializeMetrics *metrics)
Definition: explain.c:1110
void ExplainPrintTriggers(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:943
static SerializeMetrics GetSerializationMetrics(DestReceiver *dest)
Definition: explain.c:5662
@ EXPLAIN_SERIALIZE_NONE
Definition: explain.h:22
@ INSTRUMENT_TIMER
Definition: instrument.h:61
@ INSTRUMENT_BUFFERS
Definition: instrument.h:62
@ INSTRUMENT_WAL
Definition: instrument.h:64
@ INSTRUMENT_ROWS
Definition: instrument.h:63
@ CMD_UTILITY
Definition: nodes.h:270
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
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:25
@ NoMovementScanDirection
Definition: sdir.h:27
void UpdateActiveSnapshotCommandId(void)
Definition: snapmgr.c:712
void PopActiveSnapshot(void)
Definition: snapmgr.c:743
void PushCopiedSnapshot(Snapshot snapshot)
Definition: snapmgr.c:700
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:770
#define InvalidSnapshot
Definition: snapshot.h:123
bool generic
Definition: explain.h:57
bool summary
Definition: explain.h:54
ExplainSerializeOption serialize
Definition: explain.h:58
bool skipData
Definition: primnodes.h:170
CmdType commandType
Definition: plannodes.h:52
void CommandCounterIncrement(void)
Definition: xact.c:1098

References ExplainState::analyze, appendStringInfoString(), Assert, ExplainState::buffers, CMD_UTILITY, CommandCounterIncrement(), PlannedStmt::commandType, ExplainState::costs, CreateExplainSerializeDestReceiver(), CreateIntoRelDestReceiver(), CreateQueryDesc(), generate_unaccent_rules::dest, elapsed_time(), EXEC_FLAG_EXPLAIN_GENERIC, EXEC_FLAG_EXPLAIN_ONLY, ExecutorEnd(), ExecutorFinish(), ExecutorRun(), ExecutorStart(), EXPLAIN_FORMAT_TEXT, EXPLAIN_SERIALIZE_NONE, ExplainCloseGroup(), ExplainIndentText(), ExplainOpenGroup(), ExplainPrintJITSummary(), ExplainPrintPlan(), ExplainPrintSerialize(), ExplainPrintTriggers(), ExplainPropertyFloat(), ExplainState::format, ForwardScanDirection, FreeQueryDesc(), ExplainState::generic, GetActiveSnapshot(), GetIntoRelEFlags(), GetSerializationMetrics(), ExplainState::indent, INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, INSTRUMENT_BUFFERS, INSTRUMENT_ROWS, INSTRUMENT_TIMER, INSTRUMENT_WAL, InvalidSnapshot, NoMovementScanDirection, None_Receiver, peek_buffer_usage(), PopActiveSnapshot(), PushCopiedSnapshot(), ExplainState::serialize, show_buffer_usage(), show_memory_counters(), IntoClause::skipData, ExplainState::str, ExplainState::summary, ExplainState::timing, UpdateActiveSnapshotCommandId(), and ExplainState::wal.

Referenced by ExplainExecuteQuery(), and standard_ExplainOneQuery().

◆ ExplainOneQuery()

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

Definition at line 429 of file explain.c.

433 {
434  /* planner will not cope with utility statements */
435  if (query->commandType == CMD_UTILITY)
436  {
437  ExplainOneUtility(query->utilityStmt, into, es, queryString, params,
438  queryEnv);
439  return;
440  }
441 
442  /* if an advisor plugin is present, let it manage things */
444  (*ExplainOneQuery_hook) (query, cursorOptions, into, es,
445  queryString, params, queryEnv);
446  else
447  standard_ExplainOneQuery(query, cursorOptions, into, es,
448  queryString, params, queryEnv);
449 }
ExplainOneQuery_hook_type ExplainOneQuery_hook
Definition: explain.c:46
void ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: explain.c:528
void standard_ExplainOneQuery(Query *query, int cursorOptions, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: explain.c:456
CmdType commandType
Definition: parsenodes.h:121
Node * utilityStmt
Definition: parsenodes.h:136

References CMD_UTILITY, Query::commandType, ExplainOneQuery_hook, ExplainOneUtility(), standard_ExplainOneQuery(), and Query::utilityStmt.

Referenced by ExplainOneUtility(), and ExplainQuery().

◆ ExplainOneUtility()

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

Definition at line 528 of file explain.c.

531 {
532  if (utilityStmt == NULL)
533  return;
534 
535  if (IsA(utilityStmt, CreateTableAsStmt))
536  {
537  /*
538  * We have to rewrite the contained SELECT and then pass it back to
539  * ExplainOneQuery. Copy to be safe in the EXPLAIN EXECUTE case.
540  */
541  CreateTableAsStmt *ctas = (CreateTableAsStmt *) utilityStmt;
542  List *rewritten;
543 
544  /*
545  * Check if the relation exists or not. This is done at this stage to
546  * avoid query planning or execution.
547  */
548  if (CreateTableAsRelExists(ctas))
549  {
550  if (ctas->objtype == OBJECT_TABLE)
551  ExplainDummyGroup("CREATE TABLE AS", NULL, es);
552  else if (ctas->objtype == OBJECT_MATVIEW)
553  ExplainDummyGroup("CREATE MATERIALIZED VIEW", NULL, es);
554  else
555  elog(ERROR, "unexpected object type: %d",
556  (int) ctas->objtype);
557  return;
558  }
559 
560  rewritten = QueryRewrite(castNode(Query, copyObject(ctas->query)));
561  Assert(list_length(rewritten) == 1);
562  ExplainOneQuery(linitial_node(Query, rewritten),
563  CURSOR_OPT_PARALLEL_OK, ctas->into, es,
564  queryString, params, queryEnv);
565  }
566  else if (IsA(utilityStmt, DeclareCursorStmt))
567  {
568  /*
569  * Likewise for DECLARE CURSOR.
570  *
571  * Notice that if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll
572  * actually run the query. This is different from pre-8.3 behavior
573  * but seems more useful than not running the query. No cursor will
574  * be created, however.
575  */
576  DeclareCursorStmt *dcs = (DeclareCursorStmt *) utilityStmt;
577  List *rewritten;
578 
579  rewritten = QueryRewrite(castNode(Query, copyObject(dcs->query)));
580  Assert(list_length(rewritten) == 1);
581  ExplainOneQuery(linitial_node(Query, rewritten),
582  dcs->options, NULL, es,
583  queryString, params, queryEnv);
584  }
585  else if (IsA(utilityStmt, ExecuteStmt))
586  ExplainExecuteQuery((ExecuteStmt *) utilityStmt, into, es,
587  queryString, params, queryEnv);
588  else if (IsA(utilityStmt, NotifyStmt))
589  {
590  if (es->format == EXPLAIN_FORMAT_TEXT)
591  appendStringInfoString(es->str, "NOTIFY\n");
592  else
593  ExplainDummyGroup("Notify", NULL, es);
594  }
595  else
596  {
597  if (es->format == EXPLAIN_FORMAT_TEXT)
599  "Utility statements have no plan structure\n");
600  else
601  ExplainDummyGroup("Utility Statement", NULL, es);
602  }
603 }
void ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: prepare.c:568
bool CreateTableAsRelExists(CreateTableAsStmt *ctas)
Definition: createas.c:386
static void ExplainDummyGroup(const char *objtype, const char *labelname, ExplainState *es)
Definition: explain.c:5158
static void ExplainOneQuery(Query *query, int cursorOptions, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: explain.c:429
#define copyObject(obj)
Definition: nodes.h:224
@ OBJECT_MATVIEW
Definition: parsenodes.h:2284
@ OBJECT_TABLE
Definition: parsenodes.h:2302
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:3296
#define linitial_node(type, l)
Definition: pg_list.h:181
List * QueryRewrite(Query *parsetree)
IntoClause * into
Definition: parsenodes.h:3897
ObjectType objtype
Definition: parsenodes.h:3898

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

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

◆ ExplainOpenGroup()

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

Definition at line 4948 of file explain.c.

4950 {
4951  switch (es->format)
4952  {
4953  case EXPLAIN_FORMAT_TEXT:
4954  /* nothing to do */
4955  break;
4956 
4957  case EXPLAIN_FORMAT_XML:
4958  ExplainXMLTag(objtype, X_OPENING, es);
4959  es->indent++;
4960  break;
4961 
4962  case EXPLAIN_FORMAT_JSON:
4964  appendStringInfoSpaces(es->str, 2 * es->indent);
4965  if (labelname)
4966  {
4967  escape_json(es->str, labelname);
4968  appendStringInfoString(es->str, ": ");
4969  }
4970  appendStringInfoChar(es->str, labeled ? '{' : '[');
4971 
4972  /*
4973  * In JSON format, the grouping_stack is an integer list. 0 means
4974  * we've emitted nothing at this grouping level, 1 means we've
4975  * emitted something (and so the next item needs a comma). See
4976  * ExplainJSONLineEnding().
4977  */
4978  es->grouping_stack = lcons_int(0, es->grouping_stack);
4979  es->indent++;
4980  break;
4981 
4982  case EXPLAIN_FORMAT_YAML:
4983 
4984  /*
4985  * In YAML format, the grouping stack is an integer list. 0 means
4986  * we've emitted nothing at this grouping level AND this grouping
4987  * level is unlabeled and must be marked with "- ". See
4988  * ExplainYAMLLineStarting().
4989  */
4991  if (labelname)
4992  {
4993  appendStringInfo(es->str, "%s: ", labelname);
4994  es->grouping_stack = lcons_int(1, es->grouping_stack);
4995  }
4996  else
4997  {
4998  appendStringInfoString(es->str, "- ");
4999  es->grouping_stack = lcons_int(0, es->grouping_stack);
5000  }
5001  es->indent++;
5002  break;
5003  }
5004 }
#define X_OPENING
Definition: explain.c:61

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(), ExplainPrintSerialize(), ExplainPrintSettings(), ExplainPrintTriggers(), report_triggers(), show_grouping_set_keys(), show_grouping_sets(), show_incremental_sort_group_info(), and show_modifytable_info().

◆ ExplainOpenSetAsideGroup()

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

Definition at line 5058 of file explain.c.

5060 {
5061  switch (es->format)
5062  {
5063  case EXPLAIN_FORMAT_TEXT:
5064  /* nothing to do */
5065  break;
5066 
5067  case EXPLAIN_FORMAT_XML:
5068  es->indent += depth;
5069  break;
5070 
5071  case EXPLAIN_FORMAT_JSON:
5072  es->grouping_stack = lcons_int(0, es->grouping_stack);
5073  es->indent += depth;
5074  break;
5075 
5076  case EXPLAIN_FORMAT_YAML:
5077  if (labelname)
5078  es->grouping_stack = lcons_int(1, es->grouping_stack);
5079  else
5080  es->grouping_stack = lcons_int(0, es->grouping_stack);
5081  es->indent += depth;
5082  break;
5083  }
5084 }

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().

◆ ExplainOpenWorker()

static void ExplainOpenWorker ( int  n,
ExplainState es 
)
static

Definition at line 4579 of file explain.c.

4580 {
4581  ExplainWorkersState *wstate = es->workers_state;
4582 
4583  Assert(wstate);
4584  Assert(n >= 0 && n < wstate->num_workers);
4585 
4586  /* Save prior output buffer pointer */
4587  wstate->prev_str = es->str;
4588 
4589  if (!wstate->worker_inited[n])
4590  {
4591  /* First time through, so create the buffer for this worker */
4592  initStringInfo(&wstate->worker_str[n]);
4593  es->str = &wstate->worker_str[n];
4594 
4595  /*
4596  * Push suitable initial formatting state for this worker's field
4597  * group. We allow one extra logical nesting level, since this group
4598  * will eventually be wrapped in an outer "Workers" group.
4599  */
4600  ExplainOpenSetAsideGroup("Worker", NULL, true, 2, es);
4601 
4602  /*
4603  * In non-TEXT formats we always emit a "Worker Number" field, even if
4604  * there's no other data for this worker.
4605  */
4606  if (es->format != EXPLAIN_FORMAT_TEXT)
4607  ExplainPropertyInteger("Worker Number", NULL, n, es);
4608 
4609  wstate->worker_inited[n] = true;
4610  }
4611  else
4612  {
4613  /* Resuming output for a worker we've already emitted some data for */
4614  es->str = &wstate->worker_str[n];
4615 
4616  /* Restore formatting state saved by last ExplainCloseWorker() */
4617  ExplainRestoreGroup(es, 2, &wstate->worker_state_save[n]);
4618  }
4619 
4620  /*
4621  * In TEXT format, prefix the first output line for this worker with
4622  * "Worker N:". Then, any additional lines should be indented one more
4623  * stop than the "Worker N" line is.
4624  */
4625  if (es->format == EXPLAIN_FORMAT_TEXT)
4626  {
4627  if (es->str->len == 0)
4628  {
4629  ExplainIndentText(es);
4630  appendStringInfo(es->str, "Worker %d: ", n);
4631  }
4632 
4633  es->indent++;
4634  }
4635 }
static void ExplainRestoreGroup(ExplainState *es, int depth, int *state_save)
Definition: explain.c:5127
static void ExplainOpenSetAsideGroup(const char *objtype, const char *labelname, bool labeled, int depth, ExplainState *es)
Definition: explain.c:5058
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59

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

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

◆ ExplainPreScanNode()

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

Definition at line 1293 of file explain.c.

1294 {
1295  Plan *plan = planstate->plan;
1296 
1297  switch (nodeTag(plan))
1298  {
1299  case T_SeqScan:
1300  case T_SampleScan:
1301  case T_IndexScan:
1302  case T_IndexOnlyScan:
1303  case T_BitmapHeapScan:
1304  case T_TidScan:
1305  case T_TidRangeScan:
1306  case T_SubqueryScan:
1307  case T_FunctionScan:
1308  case T_TableFuncScan:
1309  case T_ValuesScan:
1310  case T_CteScan:
1311  case T_NamedTuplestoreScan:
1312  case T_WorkTableScan:
1313  *rels_used = bms_add_member(*rels_used,
1314  ((Scan *) plan)->scanrelid);
1315  break;
1316  case T_ForeignScan:
1317  *rels_used = bms_add_members(*rels_used,
1318  ((ForeignScan *) plan)->fs_base_relids);
1319  break;
1320  case T_CustomScan:
1321  *rels_used = bms_add_members(*rels_used,
1322  ((CustomScan *) plan)->custom_relids);
1323  break;
1324  case T_ModifyTable:
1325  *rels_used = bms_add_member(*rels_used,
1326  ((ModifyTable *) plan)->nominalRelation);
1327  if (((ModifyTable *) plan)->exclRelRTI)
1328  *rels_used = bms_add_member(*rels_used,
1329  ((ModifyTable *) plan)->exclRelRTI);
1330  break;
1331  case T_Append:
1332  *rels_used = bms_add_members(*rels_used,
1333  ((Append *) plan)->apprelids);
1334  break;
1335  case T_MergeAppend:
1336  *rels_used = bms_add_members(*rels_used,
1337  ((MergeAppend *) plan)->apprelids);
1338  break;
1339  default:
1340  break;
1341  }
1342 
1343  return planstate_tree_walker(planstate, ExplainPreScanNode, rels_used);
1344 }
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:917
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
Definition: explain.c:1293
#define planstate_tree_walker(ps, w, c)
Definition: nodeFuncs.h:177

References bms_add_member(), bms_add_members(), nodeTag, PlanState::plan, plan, and planstate_tree_walker.

Referenced by ExplainPrintPlan().

◆ ExplainPrintJIT()

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

Definition at line 1012 of file explain.c.

1013 {
1014  instr_time total_time;
1015 
1016  /* don't print information if no JITing happened */
1017  if (!ji || ji->created_functions == 0)
1018  return;
1019 
1020  /* calculate total time */
1021  INSTR_TIME_SET_ZERO(total_time);
1022  /* don't add deform_counter, it's included in generation_counter */
1023  INSTR_TIME_ADD(total_time, ji->generation_counter);
1024  INSTR_TIME_ADD(total_time, ji->inlining_counter);
1025  INSTR_TIME_ADD(total_time, ji->optimization_counter);
1026  INSTR_TIME_ADD(total_time, ji->emission_counter);
1027 
1028  ExplainOpenGroup("JIT", "JIT", true, es);
1029 
1030  /* for higher density, open code the text output format */
1031  if (es->format == EXPLAIN_FORMAT_TEXT)
1032  {
1033  ExplainIndentText(es);
1034  appendStringInfoString(es->str, "JIT:\n");
1035  es->indent++;
1036 
1037  ExplainPropertyInteger("Functions", NULL, ji->created_functions, es);
1038 
1039  ExplainIndentText(es);
1040  appendStringInfo(es->str, "Options: %s %s, %s %s, %s %s, %s %s\n",
1041  "Inlining", jit_flags & PGJIT_INLINE ? "true" : "false",
1042  "Optimization", jit_flags & PGJIT_OPT3 ? "true" : "false",
1043  "Expressions", jit_flags & PGJIT_EXPR ? "true" : "false",
1044  "Deforming", jit_flags & PGJIT_DEFORM ? "true" : "false");
1045 
1046  if (es->analyze && es->timing)
1047  {
1048  ExplainIndentText(es);
1049  appendStringInfo(es->str,
1050  "Timing: %s %.3f ms (%s %.3f ms), %s %.3f ms, %s %.3f ms, %s %.3f ms, %s %.3f ms\n",
1051  "Generation", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->generation_counter),
1052  "Deform", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->deform_counter),
1053  "Inlining", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->inlining_counter),
1054  "Optimization", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->optimization_counter),
1055  "Emission", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->emission_counter),
1056  "Total", 1000.0 * INSTR_TIME_GET_DOUBLE(total_time));
1057  }
1058 
1059  es->indent--;
1060  }
1061  else
1062  {
1063  ExplainPropertyInteger("Functions", NULL, ji->created_functions, es);
1064 
1065  ExplainOpenGroup("Options", "Options", true, es);
1066  ExplainPropertyBool("Inlining", jit_flags & PGJIT_INLINE, es);
1067  ExplainPropertyBool("Optimization", jit_flags & PGJIT_OPT3, es);
1068  ExplainPropertyBool("Expressions", jit_flags & PGJIT_EXPR, es);
1069  ExplainPropertyBool("Deforming", jit_flags & PGJIT_DEFORM, es);
1070  ExplainCloseGroup("Options", "Options", true, es);
1071 
1072  if (es->analyze && es->timing)
1073  {
1074  ExplainOpenGroup("Timing", "Timing", true, es);
1075 
1076  ExplainOpenGroup("Generation", "Generation", true, es);
1077  ExplainPropertyFloat("Deform", "ms",
1078  1000.0 * INSTR_TIME_GET_DOUBLE(ji->deform_counter),
1079  3, es);
1080  ExplainPropertyFloat("Total", "ms",
1082  3, es);
1083  ExplainCloseGroup("Generation", "Generation", true, es);
1084 
1085  ExplainPropertyFloat("Inlining", "ms",
1087  3, es);
1088  ExplainPropertyFloat("Optimization", "ms",
1090  3, es);
1091  ExplainPropertyFloat("Emission", "ms",
1093  3, es);
1094  ExplainPropertyFloat("Total", "ms",
1095  1000.0 * INSTR_TIME_GET_DOUBLE(total_time),
1096  3, es);
1097 
1098  ExplainCloseGroup("Timing", "Timing", true, es);
1099  }
1100  }
1101 
1102  ExplainCloseGroup("JIT", "JIT", true, es);
1103 }
#define INSTR_TIME_ADD(x, y)
Definition: instr_time.h:178
#define INSTR_TIME_SET_ZERO(t)
Definition: instr_time.h:172
#define PGJIT_OPT3
Definition: jit.h:21
#define PGJIT_EXPR
Definition: jit.h:23
#define PGJIT_DEFORM
Definition: jit.h:24
#define PGJIT_INLINE
Definition: jit.h:22
instr_time generation_counter
Definition: jit.h:33
size_t created_functions
Definition: jit.h:30
instr_time optimization_counter
Definition: jit.h:42
instr_time deform_counter
Definition: jit.h:36
instr_time emission_counter
Definition: jit.h:45
instr_time inlining_counter
Definition: jit.h:39

References ExplainState::analyze, appendStringInfo(), appendStringInfoString(), JitInstrumentation::created_functions, JitInstrumentation::deform_counter, 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().

◆ ExplainPrintJITSummary()

void ExplainPrintJITSummary ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 986 of file explain.c.

987 {
988  JitInstrumentation ji = {0};
989 
990  if (!(queryDesc->estate->es_jit_flags & PGJIT_PERFORM))
991  return;
992 
993  /*
994  * Work with a copy instead of modifying the leader state, since this
995  * function may be called twice
996  */
997  if (queryDesc->estate->es_jit)
998  InstrJitAgg(&ji, &queryDesc->estate->es_jit->instr);
999 
1000  /* If this process has done JIT in parallel workers, merge stats */
1001  if (queryDesc->estate->es_jit_worker_instr)
1002  InstrJitAgg(&ji, queryDesc->estate->es_jit_worker_instr);
1003 
1004  ExplainPrintJIT(es, queryDesc->estate->es_jit_flags, &ji);
1005 }
void InstrJitAgg(JitInstrumentation *dst, JitInstrumentation *add)
Definition: jit.c:182
#define PGJIT_PERFORM
Definition: jit.h:20
struct JitContext * es_jit
Definition: execnodes.h:716
struct JitInstrumentation * es_jit_worker_instr
Definition: execnodes.h:717
JitInstrumentation instr
Definition: jit.h:62
EState * estate
Definition: execdesc.h:48

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().

◆ ExplainPrintPlan()

void ExplainPrintPlan ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 878 of file explain.c.

879 {
880  Bitmapset *rels_used = NULL;
881  PlanState *ps;
882 
883  /* Set up ExplainState fields associated with this plan tree */
884  Assert(queryDesc->plannedstmt != NULL);
885  es->pstmt = queryDesc->plannedstmt;
886  es->rtable = queryDesc->plannedstmt->rtable;
887  ExplainPreScanNode(queryDesc->planstate, &rels_used);
890  es->rtable_names);
891  es->printed_subplans = NULL;
892 
893  /*
894  * Sometimes we mark a Gather node as "invisible", which means that it's
895  * not to be displayed in EXPLAIN output. The purpose of this is to allow
896  * running regression tests with debug_parallel_query=regress to get the
897  * same results as running the same tests with debug_parallel_query=off.
898  * Such marking is currently only supported on a Gather at the top of the
899  * plan. We skip that node, and we must also hide per-worker detail data
900  * further down in the plan tree.
901  */
902  ps = queryDesc->planstate;
903  if (IsA(ps, GatherState) && ((Gather *) ps->plan)->invisible)
904  {
905  ps = outerPlanState(ps);
906  es->hide_workers = true;
907  }
908  ExplainNode(ps, NIL, NULL, NULL, es);
909 
910  /*
911  * If requested, include information about GUC parameters with values that
912  * don't match the built-in defaults.
913  */
915 
916  /*
917  * COMPUTE_QUERY_ID_REGRESS means COMPUTE_QUERY_ID_AUTO, but we don't show
918  * the queryid in any of the EXPLAIN plans to keep stable the results
919  * generated by regression test suites.
920  */
921  if (es->verbose && queryDesc->plannedstmt->queryId != UINT64CONST(0) &&
923  {
924  /*
925  * Output the queryid as an int64 rather than a uint64 so we match
926  * what would be seen in the BIGINT pg_stat_statements.queryid column.
927  */
928  ExplainPropertyInteger("Query Identifier", NULL, (int64)
929  queryDesc->plannedstmt->queryId, es);
930  }
931 }
static void ExplainPrintSettings(ExplainState *es)
Definition: explain.c:808
struct parser_state ps
@ COMPUTE_QUERY_ID_REGRESS
Definition: queryjumble.h:59
int compute_query_id
List * select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
Definition: ruleutils.c:3795
List * deparse_context_for_plan_tree(PlannedStmt *pstmt, List *rtable_names)
Definition: ruleutils.c:3703
Bitmapset * printed_subplans
Definition: explain.h:68
List * rtable_names
Definition: explain.h:66
List * rtable
Definition: explain.h:65
PlannedStmt * pstmt
Definition: explain.h:64
List * deparse_cxt
Definition: explain.h:67
List * rtable
Definition: plannodes.h:72
uint64 queryId
Definition: plannodes.h:54
PlannedStmt * plannedstmt
Definition: execdesc.h:37
PlanState * planstate
Definition: execdesc.h:49

References Assert, compute_query_id, COMPUTE_QUERY_ID_REGRESS, deparse_context_for_plan_tree(), ExplainState::deparse_cxt, ExplainNode(), ExplainPreScanNode(), ExplainPrintSettings(), ExplainPropertyInteger(), ExplainState::hide_workers, IsA, NIL, outerPlanState, QueryDesc::plannedstmt, QueryDesc::planstate, ExplainState::printed_subplans, ps, ExplainState::pstmt, PlannedStmt::queryId, ExplainState::rtable, PlannedStmt::rtable, ExplainState::rtable_names, select_rtable_names_for_explain(), and ExplainState::verbose.

Referenced by explain_ExecutorEnd(), and ExplainOnePlan().

◆ ExplainPrintSerialize()

static void ExplainPrintSerialize ( ExplainState es,
SerializeMetrics metrics 
)
static

Definition at line 1110 of file explain.c.

1111 {
1112  const char *format;
1113 
1114  /* We shouldn't get called for EXPLAIN_SERIALIZE_NONE */
1115  if (es->serialize == EXPLAIN_SERIALIZE_TEXT)
1116  format = "text";
1117  else
1118  {
1120  format = "binary";
1121  }
1122 
1123  ExplainOpenGroup("Serialization", "Serialization", true, es);
1124 
1125  if (es->format == EXPLAIN_FORMAT_TEXT)
1126  {
1127  ExplainIndentText(es);
1128  if (es->timing)
1129  appendStringInfo(es->str, "Serialization: time=%.3f ms output=" UINT64_FORMAT "kB format=%s\n",
1130  1000.0 * INSTR_TIME_GET_DOUBLE(metrics->timeSpent),
1131  BYTES_TO_KILOBYTES(metrics->bytesSent),
1132  format);
1133  else
1134  appendStringInfo(es->str, "Serialization: output=" UINT64_FORMAT "kB format=%s\n",
1135  BYTES_TO_KILOBYTES(metrics->bytesSent),
1136  format);
1137 
1138  if (es->buffers && peek_buffer_usage(es, &metrics->bufferUsage))
1139  {
1140  es->indent++;
1141  show_buffer_usage(es, &metrics->bufferUsage);
1142  es->indent--;
1143  }
1144  }
1145  else
1146  {
1147  if (es->timing)
1148  ExplainPropertyFloat("Time", "ms",
1149  1000.0 * INSTR_TIME_GET_DOUBLE(metrics->timeSpent),
1150  3, es);
1151  ExplainPropertyUInteger("Output Volume", "kB",
1152  BYTES_TO_KILOBYTES(metrics->bytesSent), es);
1153  ExplainPropertyText("Format", format, es);
1154  if (es->buffers)
1155  show_buffer_usage(es, &metrics->bufferUsage);
1156  }
1157 
1158  ExplainCloseGroup("Serialization", "Serialization", true, es);
1159 }
#define UINT64_FORMAT
Definition: c.h:549
#define BYTES_TO_KILOBYTES(b)
Definition: explain.c:70
void ExplainPropertyUInteger(const char *qlabel, const char *unit, uint64 value, ExplainState *es)
Definition: explain.c:4905
@ EXPLAIN_SERIALIZE_TEXT
Definition: explain.h:23
@ EXPLAIN_SERIALIZE_BINARY
Definition: explain.h:24
uint64 bytesSent
Definition: explain.c:55
instr_time timeSpent
Definition: explain.c:56
BufferUsage bufferUsage
Definition: explain.c:57

References appendStringInfo(), Assert, ExplainState::buffers, SerializeMetrics::bufferUsage, BYTES_TO_KILOBYTES, SerializeMetrics::bytesSent, EXPLAIN_FORMAT_TEXT, EXPLAIN_SERIALIZE_BINARY, EXPLAIN_SERIALIZE_TEXT, ExplainCloseGroup(), ExplainIndentText(), ExplainOpenGroup(), ExplainPropertyFloat(), ExplainPropertyText(), ExplainPropertyUInteger(), format, ExplainState::format, ExplainState::indent, INSTR_TIME_GET_DOUBLE, peek_buffer_usage(), ExplainState::serialize, show_buffer_usage(), ExplainState::str, SerializeMetrics::timeSpent, ExplainState::timing, and UINT64_FORMAT.

Referenced by ExplainOnePlan().

◆ ExplainPrintSettings()

static void ExplainPrintSettings ( ExplainState es)
static

Definition at line 808 of file explain.c.

809 {
810  int num;
811  struct config_generic **gucs;
812 
813  /* bail out if information about settings not requested */
814  if (!es->settings)
815  return;
816 
817  /* request an array of relevant settings */
818  gucs = get_explain_guc_options(&num);
819 
820  if (es->format != EXPLAIN_FORMAT_TEXT)
821  {
822  ExplainOpenGroup("Settings", "Settings", true, es);
823 
824  for (int i = 0; i < num; i++)
825  {
826  char *setting;
827  struct config_generic *conf = gucs[i];
828 
829  setting = GetConfigOptionByName(conf->name, NULL, true);
830 
831  ExplainPropertyText(conf->name, setting, es);
832  }
833 
834  ExplainCloseGroup("Settings", "Settings", true, es);
835  }
836  else
837  {
839 
840  /* In TEXT mode, print nothing if there are no options */
841  if (num <= 0)
842  return;
843 
845 
846  for (int i = 0; i < num; i++)
847  {
848  char *setting;
849  struct config_generic *conf = gucs[i];
850 
851  if (i > 0)
852  appendStringInfoString(&str, ", ");
853 
854  setting = GetConfigOptionByName(conf->name, NULL, true);
855 
856  if (setting)
857  appendStringInfo(&str, "%s = '%s'", conf->name, setting);
858  else
859  appendStringInfo(&str, "%s = NULL", conf->name);
860  }
861 
862  ExplainPropertyText("Settings", str.data, es);
863  }
864 }
struct config_generic ** get_explain_guc_options(int *num)
Definition: guc.c:5281
char * GetConfigOptionByName(const char *name, const char **varname, bool missing_ok)
Definition: guc.c:5382
bool settings
Definition: explain.h:56
const char * name
Definition: guc_tables.h:156

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

Referenced by ExplainPrintPlan().

◆ ExplainPrintTriggers()

void ExplainPrintTriggers ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 943 of file explain.c.

944 {
945  ResultRelInfo *rInfo;
946  bool show_relname;
947  List *resultrels;
948  List *routerels;
949  List *targrels;
950  ListCell *l;
951 
952  resultrels = queryDesc->estate->es_opened_result_relations;
953  routerels = queryDesc->estate->es_tuple_routing_result_relations;
954  targrels = queryDesc->estate->es_trig_target_relations;
955 
956  ExplainOpenGroup("Triggers", "Triggers", false, es);
957 
958  show_relname = (list_length(resultrels) > 1 ||
959  routerels != NIL || targrels != NIL);
960  foreach(l, resultrels)
961  {
962  rInfo = (ResultRelInfo *) lfirst(l);
963  report_triggers(rInfo, show_relname, es);
964  }
965 
966  foreach(l, routerels)
967  {
968  rInfo = (ResultRelInfo *) lfirst(l);
969  report_triggers(rInfo, show_relname, es);
970  }
971 
972  foreach(l, targrels)
973  {
974  rInfo = (ResultRelInfo *) lfirst(l);
975  report_triggers(rInfo, show_relname, es);
976  }
977 
978  ExplainCloseGroup("Triggers", "Triggers", false, es);
979 }
static void report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
Definition: explain.c:1203
List * es_tuple_routing_result_relations
Definition: execnodes.h:655
List * es_trig_target_relations
Definition: execnodes.h:658
List * es_opened_result_relations
Definition: execnodes.h:645

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

Referenced by explain_ExecutorEnd(), and ExplainOnePlan().

◆ ExplainProperty()

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

Definition at line 4830 of file explain.c.

4832 {
4833  switch (es->format)
4834  {
4835  case EXPLAIN_FORMAT_TEXT:
4836  ExplainIndentText(es);
4837  if (unit)
4838  appendStringInfo(es->str, "%s: %s %s\n", qlabel, value, unit);
4839  else
4840  appendStringInfo(es->str, "%s: %s\n", qlabel, value);
4841  break;
4842 
4843  case EXPLAIN_FORMAT_XML:
4844  {
4845  char *str;
4846 
4847  appendStringInfoSpaces(es->str, es->indent * 2);
4848  ExplainXMLTag(qlabel, X_OPENING | X_NOWHITESPACE, es);
4849  str = escape_xml(value);
4851  pfree(str);
4852  ExplainXMLTag(qlabel, X_CLOSING | X_NOWHITESPACE, es);
4853  appendStringInfoChar(es->str, '\n');
4854  }
4855  break;
4856 
4857  case EXPLAIN_FORMAT_JSON:
4859  appendStringInfoSpaces(es->str, es->indent * 2);
4860  escape_json(es->str, qlabel);
4861  appendStringInfoString(es->str, ": ");
4862  if (numeric)
4864  else
4865  escape_json(es->str, value);
4866  break;
4867 
4868  case EXPLAIN_FORMAT_YAML:
4870  appendStringInfo(es->str, "%s: ", qlabel);
4871  if (numeric)
4873  else
4874  escape_yaml(es->str, value);
4875  break;
4876  }
4877 }
#define X_NOWHITESPACE
Definition: explain.c:64
static struct @155 value
char * escape_xml(const char *str)
Definition: xml.c:2674

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, str, value, X_CLOSING, X_NOWHITESPACE, and X_OPENING.

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

◆ ExplainPropertyBool()

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

Definition at line 4933 of file explain.c.

4934 {
4935  ExplainProperty(qlabel, NULL, value ? "true" : "false", true, es);
4936 }
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:4830

References ExplainProperty(), and value.

Referenced by ExplainNode(), and ExplainPrintJIT().

◆ ExplainPropertyFloat()

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

Definition at line 4919 of file explain.c.

4921 {
4922  char *buf;
4923 
4924  buf = psprintf("%.*f", ndigits, value);
4925  ExplainProperty(qlabel, unit, buf, true, es);
4926  pfree(buf);
4927 }

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

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

◆ ExplainPropertyInteger()

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

◆ ExplainPropertyList()

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

Definition at line 4707 of file explain.c.

4708 {
4709  ListCell *lc;
4710  bool first = true;
4711 
4712  switch (es->format)
4713  {
4714  case EXPLAIN_FORMAT_TEXT:
4715  ExplainIndentText(es);
4716  appendStringInfo(es->str, "%s: ", qlabel);
4717  foreach(lc, data)
4718  {
4719  if (!first)
4720  appendStringInfoString(es->str, ", ");
4721  appendStringInfoString(es->str, (const char *) lfirst(lc));
4722  first = false;
4723  }
4724  appendStringInfoChar(es->str, '\n');
4725  break;
4726 
4727  case EXPLAIN_FORMAT_XML:
4728  ExplainXMLTag(qlabel, X_OPENING, es);
4729  foreach(lc, data)
4730  {
4731  char *str;
4732 
4733  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
4734  appendStringInfoString(es->str, "<Item>");
4735  str = escape_xml((const char *) lfirst(lc));
4737  pfree(str);
4738  appendStringInfoString(es->str, "</Item>\n");
4739  }
4740  ExplainXMLTag(qlabel, X_CLOSING, es);
4741  break;
4742 
4743  case EXPLAIN_FORMAT_JSON:
4745  appendStringInfoSpaces(es->str, es->indent * 2);
4746  escape_json(es->str, qlabel);
4747  appendStringInfoString(es->str, ": [");
4748  foreach(lc, data)
4749  {
4750  if (!first)
4751  appendStringInfoString(es->str, ", ");
4752  escape_json(es->str, (const char *) lfirst(lc));
4753  first = false;
4754  }
4755  appendStringInfoChar(es->str, ']');
4756  break;
4757 
4758  case EXPLAIN_FORMAT_YAML:
4760  appendStringInfo(es->str, "%s: ", qlabel);
4761  foreach(lc, data)
4762  {
4763  appendStringInfoChar(es->str, '\n');
4764  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
4765  appendStringInfoString(es->str, "- ");
4766  escape_yaml(es->str, (const char *) lfirst(lc));
4767  }
4768  break;
4769  }
4770 }
const void * data

References appendStringInfo(), appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), data, 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, str, X_CLOSING, and X_OPENING.

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

◆ ExplainPropertyListNested()

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

Definition at line 4777 of file explain.c.

4778 {
4779  ListCell *lc;
4780  bool first = true;
4781 
4782  switch (es->format)
4783  {
4784  case EXPLAIN_FORMAT_TEXT:
4785  case EXPLAIN_FORMAT_XML:
4786  ExplainPropertyList(qlabel, data, es);
4787  return;
4788 
4789  case EXPLAIN_FORMAT_JSON:
4791  appendStringInfoSpaces(es->str, es->indent * 2);
4792  appendStringInfoChar(es->str, '[');
4793  foreach(lc, data)
4794  {
4795  if (!first)
4796  appendStringInfoString(es->str, ", ");
4797  escape_json(es->str, (const char *) lfirst(lc));
4798  first = false;
4799  }
4800  appendStringInfoChar(es->str, ']');
4801  break;
4802 
4803  case EXPLAIN_FORMAT_YAML:
4805  appendStringInfoString(es->str, "- [");
4806  foreach(lc, data)
4807  {
4808  if (!first)
4809  appendStringInfoString(es->str, ", ");
4810  escape_yaml(es->str, (const char *) lfirst(lc));
4811  first = false;
4812  }
4813  appendStringInfoChar(es->str, ']');
4814  break;
4815  }
4816 }
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:4707

References appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), data, 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().

◆ ExplainPropertyText()

◆ ExplainPropertyUInteger()

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

Definition at line 4905 of file explain.c.

4907 {
4908  char buf[32];
4909 
4910  snprintf(buf, sizeof(buf), UINT64_FORMAT, value);
4911  ExplainProperty(qlabel, unit, buf, true, es);
4912 }

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

Referenced by ExplainPrintSerialize(), show_hash_info(), show_tidbitmap_info(), and show_wal_usage().

◆ ExplainQuery()

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

Definition at line 184 of file explain.c.

186 {
188  TupOutputState *tstate;
189  JumbleState *jstate = NULL;
190  Query *query;
191  List *rewritten;
192  ListCell *lc;
193  bool timing_set = false;
194  bool summary_set = false;
195 
196  /* Parse options list. */
197  foreach(lc, stmt->options)
198  {
199  DefElem *opt = (DefElem *) lfirst(lc);
200 
201  if (strcmp(opt->defname, "analyze") == 0)
202  es->analyze = defGetBoolean(opt);
203  else if (strcmp(opt->defname, "verbose") == 0)
204  es->verbose = defGetBoolean(opt);
205  else if (strcmp(opt->defname, "costs") == 0)
206  es->costs = defGetBoolean(opt);
207  else if (strcmp(opt->defname, "buffers") == 0)
208  es->buffers = defGetBoolean(opt);
209  else if (strcmp(opt->defname, "wal") == 0)
210  es->wal = defGetBoolean(opt);
211  else if (strcmp(opt->defname, "settings") == 0)
212  es->settings = defGetBoolean(opt);
213  else if (strcmp(opt->defname, "generic_plan") == 0)
214  es->generic = defGetBoolean(opt);
215  else if (strcmp(opt->defname, "timing") == 0)
216  {
217  timing_set = true;
218  es->timing = defGetBoolean(opt);
219  }
220  else if (strcmp(opt->defname, "summary") == 0)
221  {
222  summary_set = true;
223  es->summary = defGetBoolean(opt);
224  }
225  else if (strcmp(opt->defname, "memory") == 0)
226  es->memory = defGetBoolean(opt);
227  else if (strcmp(opt->defname, "serialize") == 0)
228  {
229  if (opt->arg)
230  {
231  char *p = defGetString(opt);
232 
233  if (strcmp(p, "off") == 0 || strcmp(p, "none") == 0)
235  else if (strcmp(p, "text") == 0)
237  else if (strcmp(p, "binary") == 0)
239  else
240  ereport(ERROR,
241  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
242  errmsg("unrecognized value for EXPLAIN option \"%s\": \"%s\"",
243  opt->defname, p),
244  parser_errposition(pstate, opt->location)));
245  }
246  else
247  {
248  /* SERIALIZE without an argument is taken as 'text' */
250  }
251  }
252  else if (strcmp(opt->defname, "format") == 0)
253  {
254  char *p = defGetString(opt);
255 
256  if (strcmp(p, "text") == 0)
258  else if (strcmp(p, "xml") == 0)
260  else if (strcmp(p, "json") == 0)
262  else if (strcmp(p, "yaml") == 0)
264  else
265  ereport(ERROR,
266  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
267  errmsg("unrecognized value for EXPLAIN option \"%s\": \"%s\"",
268  opt->defname, p),
269  parser_errposition(pstate, opt->location)));
270  }
271  else
272  ereport(ERROR,
273  (errcode(ERRCODE_SYNTAX_ERROR),
274  errmsg("unrecognized EXPLAIN option \"%s\"",
275  opt->defname),
276  parser_errposition(pstate, opt->location)));
277  }
278 
279  /* check that WAL is used with EXPLAIN ANALYZE */
280  if (es->wal && !es->analyze)
281  ereport(ERROR,
282  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
283  errmsg("EXPLAIN option WAL requires ANALYZE")));
284 
285  /* if the timing was not set explicitly, set default value */
286  es->timing = (timing_set) ? es->timing : es->analyze;
287 
288  /* check that timing is used with EXPLAIN ANALYZE */
289  if (es->timing && !es->analyze)
290  ereport(ERROR,
291  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
292  errmsg("EXPLAIN option TIMING requires ANALYZE")));
293 
294  /* check that serialize is used with EXPLAIN ANALYZE */
295  if (es->serialize != EXPLAIN_SERIALIZE_NONE && !es->analyze)
296  ereport(ERROR,
297  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
298  errmsg("EXPLAIN option SERIALIZE requires ANALYZE")));
299 
300  /* check that GENERIC_PLAN is not used with EXPLAIN ANALYZE */
301  if (es->generic && es->analyze)
302  ereport(ERROR,
303  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
304  errmsg("EXPLAIN options ANALYZE and GENERIC_PLAN cannot be used together")));
305 
306  /* if the summary was not set explicitly, set default value */
307  es->summary = (summary_set) ? es->summary : es->analyze;
308 
309  query = castNode(Query, stmt->query);
310  if (IsQueryIdEnabled())
311  jstate = JumbleQuery(query);
312 
314  (*post_parse_analyze_hook) (pstate, query, jstate);
315 
316  /*
317  * Parse analysis was done already, but we still have to run the rule
318  * rewriter. We do not do AcquireRewriteLocks: we assume the query either
319  * came straight from the parser, or suitable locks were acquired by
320  * plancache.c.
321  */
322  rewritten = QueryRewrite(castNode(Query, stmt->query));
323 
324  /* emit opening boilerplate */
325  ExplainBeginOutput(es);
326 
327  if (rewritten == NIL)
328  {
329  /*
330  * In the case of an INSTEAD NOTHING, tell at least that. But in
331  * non-text format, the output is delimited, so this isn't necessary.
332  */
333  if (es->format == EXPLAIN_FORMAT_TEXT)
334  appendStringInfoString(es->str, "Query rewrites to nothing\n");
335  }
336  else
337  {
338  ListCell *l;
339 
340  /* Explain every plan */
341  foreach(l, rewritten)
342  {
344  CURSOR_OPT_PARALLEL_OK, NULL, es,
345  pstate->p_sourcetext, params, pstate->p_queryEnv);
346 
347  /* Separate plans with an appropriate separator */
348  if (lnext(rewritten, l) != NULL)
350  }
351  }
352 
353  /* emit closing boilerplate */
354  ExplainEndOutput(es);
355  Assert(es->indent == 0);
356 
357  /* output tuples */
359  &TTSOpsVirtual);
360  if (es->format == EXPLAIN_FORMAT_TEXT)
361  do_text_output_multiline(tstate, es->str->data);
362  else
363  do_text_output_oneline(tstate, es->str->data);
364  end_tup_output(tstate);
365 
366  pfree(es->str->data);
367 }
bool defGetBoolean(DefElem *def)
Definition: define.c:107
char * defGetString(DefElem *def)
Definition: define.c:48
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ereport(elevel,...)
Definition: elog.h:149
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:84
void end_tup_output(TupOutputState *tstate)
Definition: execTuples.c:2420
void do_text_output_multiline(TupOutputState *tstate, const char *txt)
Definition: execTuples.c:2390
TupOutputState * begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:2342
#define do_text_output_oneline(tstate, str_to_emit)
Definition: executor.h:522
void ExplainSeparatePlans(ExplainState *es)
Definition: explain.c:5264
void ExplainEndOutput(ExplainState *es)
Definition: explain.c:5235
TupleDesc ExplainResultDesc(ExplainStmt *stmt)
Definition: explain.c:390
void ExplainBeginOutput(ExplainState *es)
Definition: explain.c:5204
ExplainState * NewExplainState(void)
Definition: explain.c:373
#define stmt
Definition: indent_codes.h:59
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:106
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:58
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
static bool IsQueryIdEnabled(void)
Definition: queryjumble.h:77
JumbleState * JumbleQuery(Query *query)
char * defname
Definition: parsenodes.h:815
ParseLoc location
Definition: parsenodes.h:819
Node * arg
Definition: parsenodes.h:816
bool memory
Definition: explain.h:55

References ExplainState::analyze, appendStringInfoString(), DefElem::arg, Assert, begin_tup_output_tupdesc(), ExplainState::buffers, castNode, ExplainState::costs, CURSOR_OPT_PARALLEL_OK, StringInfoData::data, defGetBoolean(), defGetString(), DefElem::defname, generate_unaccent_rules::dest, 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, EXPLAIN_SERIALIZE_BINARY, EXPLAIN_SERIALIZE_NONE, EXPLAIN_SERIALIZE_TEXT, ExplainBeginOutput(), ExplainEndOutput(), ExplainOneQuery(), ExplainResultDesc(), ExplainSeparatePlans(), ExplainState::format, ExplainState::generic, if(), ExplainState::indent, IsQueryIdEnabled(), JumbleQuery(), lfirst, lfirst_node, lnext(), DefElem::location, ExplainState::memory, NewExplainState(), NIL, ParseState::p_queryEnv, ParseState::p_sourcetext, parser_errposition(), pfree(), post_parse_analyze_hook, QueryRewrite(), ExplainState::serialize, ExplainState::settings, stmt, ExplainState::str, ExplainState::summary, ExplainState::timing, TTSOpsVirtual, ExplainState::verbose, and ExplainState::wal.

Referenced by standard_ProcessUtility().

◆ ExplainQueryParameters()

void ExplainQueryParameters ( ExplainState es,
ParamListInfo  params,
int  maxlen 
)

Definition at line 1185 of file explain.c.

1186 {
1187  char *str;
1188 
1189  /* This check is consistent with errdetail_params() */
1190  if (params == NULL || params->numParams <= 0 || maxlen == 0)
1191  return;
1192 
1193  str = BuildParamLogString(params, NULL, maxlen);
1194  if (str && str[0] != '\0')
1195  ExplainPropertyText("Query Parameters", str, es);
1196 }
char * BuildParamLogString(ParamListInfo params, char **knownTextValues, int maxlen)
Definition: params.c:335

References BuildParamLogString(), ExplainPropertyText(), ParamListInfoData::numParams, and str.

Referenced by explain_ExecutorEnd().

◆ ExplainQueryText()

void ExplainQueryText ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 1170 of file explain.c.

1171 {
1172  if (queryDesc->sourceText)
1173  ExplainPropertyText("Query Text", queryDesc->sourceText, es);
1174 }
const char * sourceText
Definition: execdesc.h:38

References ExplainPropertyText(), and QueryDesc::sourceText.

Referenced by explain_ExecutorEnd().

◆ ExplainRestoreGroup()

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

Definition at line 5127 of file explain.c.

5128 {
5129  switch (es->format)
5130  {
5131  case EXPLAIN_FORMAT_TEXT:
5132  /* nothing to do */
5133  break;
5134 
5135  case EXPLAIN_FORMAT_XML:
5136  es->indent += depth;
5137  break;
5138 
5139  case EXPLAIN_FORMAT_JSON:
5140  es->grouping_stack = lcons_int(*state_save, es->grouping_stack);
5141  es->indent += depth;
5142  break;
5143 
5144  case EXPLAIN_FORMAT_YAML:
5145  es->grouping_stack = lcons_int(*state_save, es->grouping_stack);
5146  es->indent += depth;
5147  break;
5148  }
5149 }

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().

◆ ExplainResultDesc()

TupleDesc ExplainResultDesc ( ExplainStmt stmt)

Definition at line 390 of file explain.c.

391 {
392  TupleDesc tupdesc;
393  ListCell *lc;
394  Oid result_type = TEXTOID;
395 
396  /* Check for XML format option */
397  foreach(lc, stmt->options)
398  {
399  DefElem *opt = (DefElem *) lfirst(lc);
400 
401  if (strcmp(opt->defname, "format") == 0)
402  {
403  char *p = defGetString(opt);
404 
405  if (strcmp(p, "xml") == 0)
406  result_type = XMLOID;
407  else if (strcmp(p, "json") == 0)
408  result_type = JSONOID;
409  else
410  result_type = TEXTOID;
411  /* don't "break", as ExplainQuery will use the last value */
412  }
413  }
414 
415  /* Need a tuple descriptor representing a single TEXT or XML column */
416  tupdesc = CreateTemplateTupleDesc(1);
417  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
418  result_type, -1, 0);
419  return tupdesc;
420 }
int16 AttrNumber
Definition: attnum.h:21
unsigned int Oid
Definition: postgres_ext.h:31
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:67
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:651

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

Referenced by ExplainQuery(), and UtilityTupleDescriptor().

◆ ExplainSaveGroup()

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

Definition at line 5097 of file explain.c.

5098 {
5099  switch (es->format)
5100  {
5101  case EXPLAIN_FORMAT_TEXT:
5102  /* nothing to do */
5103  break;
5104 
5105  case EXPLAIN_FORMAT_XML:
5106  es->indent -= depth;
5107  break;
5108 
5109  case EXPLAIN_FORMAT_JSON:
5110  es->indent -= depth;
5111  *state_save = linitial_int(es->grouping_stack);
5113  break;
5114 
5115  case EXPLAIN_FORMAT_YAML:
5116  es->indent -= depth;
5117  *state_save = linitial_int(es->grouping_stack);
5119  break;
5120  }
5121 }

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().

◆ ExplainScanTarget()

static void ExplainScanTarget ( Scan plan,
ExplainState es 
)
static

Definition at line 4093 of file explain.c.

4094 {
4095  ExplainTargetRel((Plan *) plan, plan->scanrelid, es);
4096 }

References ExplainTargetRel(), and plan.

Referenced by ExplainNode().

◆ ExplainSeparatePlans()

void ExplainSeparatePlans ( ExplainState es)

Definition at line 5264 of file explain.c.

5265 {
5266  switch (es->format)
5267  {
5268  case EXPLAIN_FORMAT_TEXT:
5269  /* add a blank line */
5270  appendStringInfoChar(es->str, '\n');
5271  break;
5272 
5273  case EXPLAIN_FORMAT_XML:
5274  case EXPLAIN_FORMAT_JSON:
5275  case EXPLAIN_FORMAT_YAML:
5276  /* nothing to do */
5277  break;
5278  }
5279 }

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

Referenced by ExplainExecuteQuery(), and ExplainQuery().

◆ ExplainSubPlans()

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

Definition at line 4497 of file explain.c.

4499 {
4500  ListCell *lst;
4501 
4502  foreach(lst, plans)
4503  {
4504  SubPlanState *sps = (SubPlanState *) lfirst(lst);
4505  SubPlan *sp = sps->subplan;
4506 
4507  /*
4508  * There can be multiple SubPlan nodes referencing the same physical
4509  * subplan (same plan_id, which is its index in PlannedStmt.subplans).
4510  * We should print a subplan only once, so track which ones we already
4511  * printed. This state must be global across the plan tree, since the
4512  * duplicate nodes could be in different plan nodes, eg both a bitmap
4513  * indexscan's indexqual and its parent heapscan's recheck qual. (We
4514  * do not worry too much about which plan node we show the subplan as
4515  * attached to in such cases.)
4516  */
4517  if (bms_is_member(sp->plan_id, es->printed_subplans))
4518  continue;
4520  sp->plan_id);
4521 
4522  /*
4523  * Treat the SubPlan node as an ancestor of the plan node(s) within
4524  * it, so that ruleutils.c can find the referents of subplan
4525  * parameters.
4526  */
4527  ancestors = lcons(sp, ancestors);
4528 
4529  ExplainNode(sps->planstate, ancestors,
4530  relationship, sp->plan_name, es);
4531 
4532  ancestors = list_delete_first(ancestors);
4533  }
4534 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
struct PlanState * planstate
Definition: execnodes.h:961
SubPlan * subplan
Definition: execnodes.h:960
int plan_id
Definition: primnodes.h:1070
char * plan_name
Definition: primnodes.h:1072

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().

◆ ExplainTargetRel()

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

Definition at line 4115 of file explain.c.

4116 {
4117  char *objectname = NULL;
4118  char *namespace = NULL;
4119  const char *objecttag = NULL;
4120  RangeTblEntry *rte;
4121  char *refname;
4122 
4123  rte = rt_fetch(rti, es->rtable);
4124  refname = (char *) list_nth(es->rtable_names, rti - 1);
4125  if (refname == NULL)
4126  refname = rte->eref->aliasname;
4127 
4128  switch (nodeTag(plan))
4129  {
4130  case T_SeqScan:
4131  case T_SampleScan:
4132  case T_IndexScan:
4133  case T_IndexOnlyScan:
4134  case T_BitmapHeapScan:
4135  case T_TidScan:
4136  case T_TidRangeScan:
4137  case T_ForeignScan:
4138  case T_CustomScan:
4139  case T_ModifyTable:
4140  /* Assert it's on a real relation */
4141  Assert(rte->rtekind == RTE_RELATION);
4142  objectname = get_rel_name(rte->relid);
4143  if (es->verbose)
4144  namespace = get_namespace_name_or_temp(get_rel_namespace(rte->relid));
4145  objecttag = "Relation Name";
4146  break;
4147  case T_FunctionScan:
4148  {
4149  FunctionScan *fscan = (FunctionScan *) plan;
4150 
4151  /* Assert it's on a RangeFunction */
4152  Assert(rte->rtekind == RTE_FUNCTION);
4153 
4154  /*
4155  * If the expression is still a function call of a single
4156  * function, we can get the real name of the function.
4157  * Otherwise, punt. (Even if it was a single function call
4158  * originally, the optimizer could have simplified it away.)
4159  */
4160  if (list_length(fscan->functions) == 1)
4161  {
4162  RangeTblFunction *rtfunc = (RangeTblFunction *) linitial(fscan->functions);
4163 
4164  if (IsA(rtfunc->funcexpr, FuncExpr))
4165  {
4166  FuncExpr *funcexpr = (FuncExpr *) rtfunc->funcexpr;
4167  Oid funcid = funcexpr->funcid;
4168 
4169  objectname = get_func_name(funcid);
4170  if (es->verbose)
4171  namespace = get_namespace_name_or_temp(get_func_namespace(funcid));
4172  }
4173  }
4174  objecttag = "Function Name";
4175  }
4176  break;
4177  case T_TableFuncScan:
4178  {
4179  TableFunc *tablefunc = ((TableFuncScan *) plan)->tablefunc;
4180 
4181  Assert(rte->rtekind == RTE_TABLEFUNC);
4182  switch (tablefunc->functype)
4183  {
4184  case TFT_XMLTABLE:
4185  objectname = "xmltable";
4186  break;
4187  case TFT_JSON_TABLE:
4188  objectname = "json_table";
4189  break;
4190  default:
4191  elog(ERROR, "invalid TableFunc type %d",
4192  (int) tablefunc->functype);
4193  }
4194  objecttag = "Table Function Name";
4195  }
4196  break;
4197  case T_ValuesScan:
4198  Assert(rte->rtekind == RTE_VALUES);
4199  break;
4200  case T_CteScan:
4201  /* Assert it's on a non-self-reference CTE */
4202  Assert(rte->rtekind == RTE_CTE);
4203  Assert(!rte->self_reference);
4204  objectname = rte->ctename;
4205  objecttag = "CTE Name";
4206  break;
4207  case T_NamedTuplestoreScan:
4209  objectname = rte->enrname;
4210  objecttag = "Tuplestore Name";
4211  break;
4212  case T_WorkTableScan:
4213  /* Assert it's on a self-reference CTE */
4214  Assert(rte->rtekind == RTE_CTE);
4215  Assert(rte->self_reference);
4216  objectname = rte->ctename;
4217  objecttag = "CTE Name";
4218  break;
4219  default:
4220  break;
4221  }
4222 
4223  if (es->format == EXPLAIN_FORMAT_TEXT)
4224  {
4225  appendStringInfoString(es->str, " on");
4226  if (namespace != NULL)
4227  appendStringInfo(es->str, " %s.%s", quote_identifier(namespace),
4228  quote_identifier(objectname));
4229  else if (objectname != NULL)
4230  appendStringInfo(es->str, " %s", quote_identifier(objectname));
4231  if (objectname == NULL || strcmp(refname, objectname) != 0)
4232  appendStringInfo(es->str, " %s", quote_identifier(refname));
4233  }
4234  else
4235  {
4236  if (objecttag != NULL && objectname != NULL)
4237  ExplainPropertyText(objecttag, objectname, es);
4238  if (namespace != NULL)
4239  ExplainPropertyText("Schema", namespace, es);
4240  ExplainPropertyText("Alias", refname, es);
4241  }
4242 }
char * get_namespace_name_or_temp(Oid nspid)
Definition: lsyscache.c:3390
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1952
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1608
Oid get_func_namespace(Oid funcid)
Definition: lsyscache.c:1632
@ RTE_CTE
Definition: parsenodes.h:1034
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1035
@ RTE_VALUES
Definition: parsenodes.h:1033
@ RTE_FUNCTION
Definition: parsenodes.h:1031
@ RTE_TABLEFUNC
Definition: parsenodes.h:1032
@ RTE_RELATION
Definition: parsenodes.h:1028
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define linitial(l)
Definition: pg_list.h:178
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
@ TFT_XMLTABLE
Definition: primnodes.h:99
@ TFT_JSON_TABLE
Definition: primnodes.h:100
Oid funcid
Definition: primnodes.h:750
List * functions
Definition: plannodes.h:612
char * ctename
Definition: parsenodes.h:1206
char * enrname
Definition: parsenodes.h:1241
RTEKind rtekind
Definition: parsenodes.h:1057
TableFuncType functype
Definition: primnodes.h:113

References appendStringInfo(), appendStringInfoString(), Assert, elog, ERROR, EXPLAIN_FORMAT_TEXT, ExplainPropertyText(), ExplainState::format, RangeTblFunction::funcexpr, FuncExpr::funcid, FunctionScan::functions, TableFunc::functype, get_func_name(), get_func_namespace(), get_namespace_name_or_temp(), get_rel_name(), get_rel_namespace(), IsA, linitial, list_length(), list_nth(), nodeTag, plan, 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, TFT_JSON_TABLE, TFT_XMLTABLE, and ExplainState::verbose.

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

◆ ExplainXMLTag()

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

Definition at line 5293 of file explain.c.

5294 {
5295  const char *s;
5296  const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
5297 
5298  if ((flags & X_NOWHITESPACE) == 0)
5299  appendStringInfoSpaces(es->str, 2 * es->indent);
5300  appendStringInfoCharMacro(es->str, '<');
5301  if ((flags & X_CLOSING) != 0)
5302  appendStringInfoCharMacro(es->str, '/');
5303  for (s = tagname; *s; s++)
5304  appendStringInfoChar(es->str, strchr(valid, *s) ? *s : '-');
5305  if ((flags & X_CLOSE_IMMEDIATE) != 0)
5306  appendStringInfoString(es->str, " /");
5307  appendStringInfoCharMacro(es->str, '>');
5308  if ((flags & X_NOWHITESPACE) == 0)
5309  appendStringInfoCharMacro(es->str, '\n');
5310 }
#define appendStringInfoCharMacro(str, ch)
Definition: stringinfo.h:204

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().

◆ ExplainYAMLLineStarting()

static void ExplainYAMLLineStarting ( ExplainState es)
static

◆ GetSerializationMetrics()

static SerializeMetrics GetSerializationMetrics ( DestReceiver dest)
static

Definition at line 5662 of file explain.c.

5663 {
5664  SerializeMetrics empty;
5665 
5666  if (dest->mydest == DestExplainSerialize)
5667  return ((SerializeDestReceiver *) dest)->metrics;
5668 
5669  memset(&empty, 0, sizeof(SerializeMetrics));
5671 
5672  return empty;
5673 }

References generate_unaccent_rules::dest, DestExplainSerialize, INSTR_TIME_SET_ZERO, and SerializeMetrics::timeSpent.

Referenced by ExplainOnePlan().

◆ NewExplainState()

ExplainState* NewExplainState ( void  )

Definition at line 373 of file explain.c.

374 {
375  ExplainState *es = (ExplainState *) palloc0(sizeof(ExplainState));
376 
377  /* Set default options (most fields can be left as zeroes). */
378  es->costs = true;
379  /* Prepare output buffer. */
380  es->str = makeStringInfo();
381 
382  return es;
383 }
StringInfo makeStringInfo(void)
Definition: stringinfo.c:41

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

Referenced by explain_ExecutorEnd(), and ExplainQuery().

◆ peek_buffer_usage()

static bool peek_buffer_usage ( ExplainState es,
const BufferUsage usage 
)
static

Definition at line 3784 of file explain.c.

3785 {
3786  bool has_shared;
3787  bool has_local;
3788  bool has_temp;
3789  bool has_shared_timing;
3790  bool has_local_timing;
3791  bool has_temp_timing;
3792 
3793  if (usage == NULL)
3794  return false;
3795 
3796  if (es->format != EXPLAIN_FORMAT_TEXT)
3797  return true;
3798 
3799  has_shared = (usage->shared_blks_hit > 0 ||
3800  usage->shared_blks_read > 0 ||
3801  usage->shared_blks_dirtied > 0 ||
3802  usage->shared_blks_written > 0);
3803  has_local = (usage->local_blks_hit > 0 ||
3804  usage->local_blks_read > 0 ||
3805  usage->local_blks_dirtied > 0 ||
3806  usage->local_blks_written > 0);
3807  has_temp = (usage->temp_blks_read > 0 ||
3808  usage->temp_blks_written > 0);
3809  has_shared_timing = (!INSTR_TIME_IS_ZERO(usage->shared_blk_read_time) ||
3810  !INSTR_TIME_IS_ZERO(usage->shared_blk_write_time));
3811  has_local_timing = (!INSTR_TIME_IS_ZERO(usage->local_blk_read_time) ||
3812  !INSTR_TIME_IS_ZERO(usage->local_blk_write_time));
3813  has_temp_timing = (!INSTR_TIME_IS_ZERO(usage->temp_blk_read_time) ||
3814  !INSTR_TIME_IS_ZERO(usage->temp_blk_write_time));
3815 
3816  return has_shared || has_local || has_temp || has_shared_timing ||
3817  has_local_timing || has_temp_timing;
3818 }
#define INSTR_TIME_IS_ZERO(t)
Definition: instr_time.h:169
static void usage(const char *progname)
Definition: vacuumlo.c:414

References EXPLAIN_FORMAT_TEXT, ExplainState::format, INSTR_TIME_IS_ZERO, and usage().

Referenced by ExplainOnePlan(), and ExplainPrintSerialize().

◆ report_triggers()

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

Definition at line 1203 of file explain.c.

1204 {
1205  int nt;
1206 
1207  if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
1208  return;
1209  for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
1210  {
1211  Trigger *trig = rInfo->ri_TrigDesc->triggers + nt;
1212  Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
1213  char *relname;
1214  char *conname = NULL;
1215 
1216  /* Must clean up instrumentation state */
1217  InstrEndLoop(instr);
1218 
1219  /*
1220  * We ignore triggers that were never invoked; they likely aren't
1221  * relevant to the current query type.
1222  */
1223  if (instr->ntuples == 0)
1224  continue;
1225 
1226  ExplainOpenGroup("Trigger", NULL, true, es);
1227 
1229  if (OidIsValid(trig->tgconstraint))
1230  conname = get_constraint_name(trig->tgconstraint);
1231 
1232  /*
1233  * In text format, we avoid printing both the trigger name and the
1234  * constraint name unless VERBOSE is specified. In non-text formats
1235  * we just print everything.
1236  */
1237  if (es->format == EXPLAIN_FORMAT_TEXT)
1238  {
1239  if (es->verbose || conname == NULL)
1240  appendStringInfo(es->str, "Trigger %s", trig->tgname);
1241  else
1242  appendStringInfoString(es->str, "Trigger");
1243  if (conname)
1244  appendStringInfo(es->str, " for constraint %s", conname);
1245  if (show_relname)
1246  appendStringInfo(es->str, " on %s", relname);
1247  if (es->timing)
1248  appendStringInfo(es->str, ": time=%.3f calls=%.0f\n",
1249  1000.0 * instr->total, instr->ntuples);
1250  else
1251  appendStringInfo(es->str, ": calls=%.0f\n", instr->ntuples);
1252  }
1253  else
1254  {
1255  ExplainPropertyText("Trigger Name", trig->tgname, es);
1256  if (conname)
1257  ExplainPropertyText("Constraint Name", conname, es);
1258  ExplainPropertyText("Relation", relname, es);
1259  if (es->timing)
1260  ExplainPropertyFloat("Time", "ms", 1000.0 * instr->total, 3,
1261  es);
1262  ExplainPropertyFloat("Calls", NULL, instr->ntuples, 0, es);
1263  }
1264 
1265  if (conname)
1266  pfree(conname);
1267 
1268  ExplainCloseGroup("Trigger", NULL, true, es);
1269  }
1270 }
#define OidIsValid(objectId)
Definition: c.h:775
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:1081
NameData relname
Definition: pg_class.h:38
#define RelationGetRelationName(relation)
Definition: rel.h:539
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:495
Relation ri_RelationDesc
Definition: execnodes.h:456
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:486
int numtriggers
Definition: reltrigger.h:50
Trigger * triggers
Definition: reltrigger.h:49
Oid tgconstraint
Definition: reltrigger.h:35
char * tgname
Definition: reltrigger.h:27

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().

◆ serialize_prepare_info()

static void serialize_prepare_info ( SerializeDestReceiver receiver,
TupleDesc  typeinfo,
int  nattrs 
)
static

Definition at line 5415 of file explain.c.

5417 {
5418  /* get rid of any old data */
5419  if (receiver->finfos)
5420  pfree(receiver->finfos);
5421  receiver->finfos = NULL;
5422 
5423  receiver->attrinfo = typeinfo;
5424  receiver->nattrs = nattrs;
5425  if (nattrs <= 0)
5426  return;
5427 
5428  receiver->finfos = (FmgrInfo *) palloc0(nattrs * sizeof(FmgrInfo));
5429 
5430  for (int i = 0; i < nattrs; i++)
5431  {
5432  FmgrInfo *finfo = receiver->finfos + i;
5433  Form_pg_attribute attr = TupleDescAttr(typeinfo, i);
5434  Oid typoutput;
5435  Oid typsend;
5436  bool typisvarlena;
5437 
5438  if (receiver->format == 0)
5439  {
5440  /* wire protocol format text */
5441  getTypeOutputInfo(attr->atttypid,
5442  &typoutput,
5443  &typisvarlena);
5444  fmgr_info(typoutput, finfo);
5445  }
5446  else if (receiver->format == 1)
5447  {
5448  /* wire protocol format binary */
5449  getTypeBinaryOutputInfo(attr->atttypid,
5450  &typsend,
5451  &typisvarlena);
5452  fmgr_info(typsend, finfo);
5453  }
5454  else
5455  ereport(ERROR,
5456  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5457  errmsg("unsupported format code: %d", receiver->format)));
5458  }
5459 }
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
void getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
Definition: lsyscache.c:2973
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2907
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
Definition: fmgr.h:57
TupleDesc attrinfo
Definition: explain.c:5400
FmgrInfo * finfos
Definition: explain.c:5402
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References SerializeDestReceiver::attrinfo, ereport, errcode(), errmsg(), ERROR, SerializeDestReceiver::finfos, fmgr_info(), SerializeDestReceiver::format, getTypeBinaryOutputInfo(), getTypeOutputInfo(), i, SerializeDestReceiver::nattrs, palloc0(), pfree(), and TupleDescAttr.

Referenced by serializeAnalyzeReceive().

◆ serializeAnalyzeDestroy()

static void serializeAnalyzeDestroy ( DestReceiver self)
static

Definition at line 5628 of file explain.c.

5629 {
5630  pfree(self);
5631 }

References pfree().

Referenced by CreateExplainSerializeDestReceiver().

◆ serializeAnalyzeReceive()

static bool serializeAnalyzeReceive ( TupleTableSlot slot,
DestReceiver self 
)
static

Definition at line 5468 of file explain.c.

5469 {
5470  TupleDesc typeinfo = slot->tts_tupleDescriptor;
5471  SerializeDestReceiver *myState = (SerializeDestReceiver *) self;
5472  MemoryContext oldcontext;
5473  StringInfo buf = &myState->buf;
5474  int natts = typeinfo->natts;
5475  instr_time start,
5476  end;
5477  BufferUsage instr_start;
5478 
5479  /* only measure time, buffers if requested */
5480  if (myState->es->timing)
5482  if (myState->es->buffers)
5483  instr_start = pgBufferUsage;
5484 
5485  /* Set or update my derived attribute info, if needed */
5486  if (myState->attrinfo != typeinfo || myState->nattrs != natts)
5487  serialize_prepare_info(myState, typeinfo, natts);
5488 
5489  /* Make sure the tuple is fully deconstructed */
5490  slot_getallattrs(slot);
5491 
5492  /* Switch into per-row context so we can recover memory below */
5493  oldcontext = MemoryContextSwitchTo(myState->tmpcontext);
5494 
5495  /*
5496  * Prepare a DataRow message (note buffer is in per-query context)
5497  *
5498  * Note that we fill a StringInfo buffer the same as printtup() does, so
5499  * as to capture the costs of manipulating the strings accurately.
5500  */
5502 
5503  pq_sendint16(buf, natts);
5504 
5505  /*
5506  * send the attributes of this tuple
5507  */
5508  for (int i = 0; i < natts; i++)
5509  {
5510  FmgrInfo *finfo = myState->finfos + i;
5511  Datum attr = slot->tts_values[i];
5512 
5513  if (slot->tts_isnull[i])
5514  {
5515  pq_sendint32(buf, -1);
5516  continue;
5517  }
5518 
5519  if (myState->format == 0)
5520  {
5521  /* Text output */
5522  char *outputstr;
5523 
5524  outputstr = OutputFunctionCall(finfo, attr);
5525  pq_sendcountedtext(buf, outputstr, strlen(outputstr));
5526  }
5527  else
5528  {
5529  /* Binary output */
5530  bytea *outputbytes;
5531 
5532  outputbytes = SendFunctionCall(finfo, attr);
5533  pq_sendint32(buf, VARSIZE(outputbytes) - VARHDRSZ);
5534  pq_sendbytes(buf, VARDATA(outputbytes),
5535  VARSIZE(outputbytes) - VARHDRSZ);
5536  }
5537  }
5538 
5539  /*
5540  * We mustn't call pq_endmessage_reuse(), since that would actually send
5541  * the data to the client. Just count the data, instead. We can leave
5542  * the buffer alone; it'll be reset on the next iteration (as would also
5543  * happen in printtup()).
5544  */
5545  myState->metrics.bytesSent += buf->len;
5546 
5547  /* Return to caller's context, and flush row's temporary memory */
5548  MemoryContextSwitchTo(oldcontext);
5549  MemoryContextReset(myState->tmpcontext);
5550 
5551  /* Update timing data */
5552  if (myState->es->timing)
5553  {
5555  INSTR_TIME_ACCUM_DIFF(myState->metrics.timeSpent, end, start);
5556  }
5557 
5558  /* Update buffer metrics */
5559  if (myState->es->buffers)
5561  &pgBufferUsage,
5562  &instr_start);
5563 
5564  return true;
5565 }
#define VARHDRSZ
Definition: c.h:692
static void serialize_prepare_info(SerializeDestReceiver *receiver, TupleDesc typeinfo, int nattrs)
Definition: explain.c:5415
bytea * SendFunctionCall(FmgrInfo *flinfo, Datum val)
Definition: fmgr.c:1744
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
Definition: fmgr.c:1683
return str start
#define INSTR_TIME_ACCUM_DIFF(x, y, z)
Definition: instr_time.h:184
BufferUsage pgBufferUsage
Definition: instrument.c:20
void BufferUsageAccumDiff(BufferUsage *dst, const BufferUsage *add, const BufferUsage *sub)
Definition: instrument.c:248
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
uintptr_t Datum
Definition: postgres.h:64
void pq_sendbytes(StringInfo buf, const void *data, int datalen)
Definition: pqformat.c:126
void pq_beginmessage_reuse(StringInfo buf, char msgtype)
Definition: pqformat.c:109
void pq_sendcountedtext(StringInfo buf, const char *str, int slen)
Definition: pqformat.c:142
static void pq_sendint32(StringInfo buf, uint32 i)
Definition: pqformat.h:144
static void pq_sendint16(StringInfo buf, uint16 i)
Definition: pqformat.h:136
#define PqMsg_DataRow
Definition: protocol.h:43
MemoryContextSwitchTo(old_ctx)
ExplainState * es
Definition: explain.c:5398
SerializeMetrics metrics
Definition: explain.c:5405
StringInfoData buf
Definition: explain.c:5404
MemoryContext tmpcontext
Definition: explain.c:5403
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:123
bool * tts_isnull
Definition: tuptable.h:127
Datum * tts_values
Definition: tuptable.h:125
Definition: c.h:687
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:368
#define VARDATA(PTR)
Definition: varatt.h:278
#define VARSIZE(PTR)
Definition: varatt.h:279

References SerializeDestReceiver::attrinfo, SerializeDestReceiver::buf, buf, ExplainState::buffers, SerializeMetrics::bufferUsage, BufferUsageAccumDiff(), SerializeMetrics::bytesSent, SerializeDestReceiver::es, SerializeDestReceiver::finfos, SerializeDestReceiver::format, i, INSTR_TIME_ACCUM_DIFF, INSTR_TIME_SET_CURRENT, MemoryContextReset(), MemoryContextSwitchTo(), SerializeDestReceiver::metrics, SerializeDestReceiver::nattrs, TupleDescData::natts, OutputFunctionCall(), pgBufferUsage, pq_beginmessage_reuse(), pq_sendbytes(), pq_sendcountedtext(), pq_sendint16(), pq_sendint32(), PqMsg_DataRow, SendFunctionCall(), serialize_prepare_info(), slot_getallattrs(), start, SerializeMetrics::timeSpent, ExplainState::timing, SerializeDestReceiver::tmpcontext, TupleTableSlot::tts_isnull, TupleTableSlot::tts_tupleDescriptor, TupleTableSlot::tts_values, VARDATA, VARHDRSZ, and VARSIZE.

Referenced by CreateExplainSerializeDestReceiver().

◆ serializeAnalyzeShutdown()

static void serializeAnalyzeShutdown ( DestReceiver self)
static

Definition at line 5607 of file explain.c.

5608 {
5609  SerializeDestReceiver *receiver = (SerializeDestReceiver *) self;
5610 
5611  if (receiver->finfos)
5612  pfree(receiver->finfos);
5613  receiver->finfos = NULL;
5614 
5615  if (receiver->buf.data)
5616  pfree(receiver->buf.data);
5617  receiver->buf.data = NULL;
5618 
5619  if (receiver->tmpcontext)
5620  MemoryContextDelete(receiver->tmpcontext);
5621  receiver->tmpcontext = NULL;
5622 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454

References SerializeDestReceiver::buf, StringInfoData::data, SerializeDestReceiver::finfos, MemoryContextDelete(), pfree(), and SerializeDestReceiver::tmpcontext.

Referenced by CreateExplainSerializeDestReceiver().

◆ serializeAnalyzeStartup()

static void serializeAnalyzeStartup ( DestReceiver self,
int  operation,
TupleDesc  typeinfo 
)
static

Definition at line 5571 of file explain.c.

5572 {
5573  SerializeDestReceiver *receiver = (SerializeDestReceiver *) self;
5574 
5575  Assert(receiver->es != NULL);
5576 
5577  switch (receiver->es->serialize)
5578  {
5580  Assert(false);
5581  break;
5583  receiver->format = 0; /* wire protocol format text */
5584  break;
5586  receiver->format = 1; /* wire protocol format binary */
5587  break;
5588  }
5589 
5590  /* Create per-row temporary memory context */
5592  "SerializeTupleReceive",
5594 
5595  /* The output buffer is re-used across rows, as in printtup.c */
5596  initStringInfo(&receiver->buf);
5597 
5598  /* Initialize results counters */
5599  memset(&receiver->metrics, 0, sizeof(SerializeMetrics));
5601 }
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, SerializeDestReceiver::buf, CurrentMemoryContext, SerializeDestReceiver::es, EXPLAIN_SERIALIZE_BINARY, EXPLAIN_SERIALIZE_NONE, EXPLAIN_SERIALIZE_TEXT, SerializeDestReceiver::format, initStringInfo(), INSTR_TIME_SET_ZERO, SerializeDestReceiver::metrics, ExplainState::serialize, SerializeMetrics::timeSpent, and SerializeDestReceiver::tmpcontext.

Referenced by CreateExplainSerializeDestReceiver().

◆ show_agg_keys()

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

Definition at line 2613 of file explain.c.

2615 {
2616  Agg *plan = (Agg *) astate->ss.ps.plan;
2617 
2618  if (plan->numCols > 0 || plan->groupingSets)
2619  {
2620  /* The key columns refer to the tlist of the child plan */
2621  ancestors = lcons(plan, ancestors);
2622 
2623  if (plan->groupingSets)
2624  show_grouping_sets(outerPlanState(astate), plan, ancestors, es);
2625  else
2626  show_sort_group_keys(outerPlanState(astate), "Group Key",
2627  plan->numCols, 0, plan->grpColIdx,
2628  NULL, NULL, NULL,
2629  ancestors, es);
2630 
2631  ancestors = list_delete_first(ancestors);
2632  }
2633 }
static void show_sort_group_keys(PlanState *planstate, const char *qlabel, int nkeys, int nPresortedKeys, AttrNumber *keycols, Oid *sortOperators, Oid *collations, bool *nullsFirst, List *ancestors, ExplainState *es)
Definition: explain.c:2765
static void show_grouping_sets(PlanState *planstate, Agg *agg, List *ancestors, ExplainState *es)
Definition: explain.c:2636
ScanState ss
Definition: execnodes.h:2489
PlanState ps
Definition: execnodes.h:1563

References if(), lcons(), list_delete_first(), outerPlanState, PlanState::plan, plan, ScanState::ps, show_grouping_sets(), show_sort_group_keys(), and AggState::ss.

Referenced by ExplainNode().

◆ show_buffer_usage()

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

Definition at line 3824 of file explain.c.

3825 {
3826  if (es->format == EXPLAIN_FORMAT_TEXT)
3827  {
3828  bool has_shared = (usage->shared_blks_hit > 0 ||
3829  usage->shared_blks_read > 0 ||
3830  usage->shared_blks_dirtied > 0 ||
3831  usage->shared_blks_written > 0);
3832  bool has_local = (usage->local_blks_hit > 0 ||
3833  usage->local_blks_read > 0 ||
3834  usage->local_blks_dirtied > 0 ||
3835  usage->local_blks_written > 0);
3836  bool has_temp = (usage->temp_blks_read > 0 ||
3837  usage->temp_blks_written > 0);
3838  bool has_shared_timing = (!INSTR_TIME_IS_ZERO(usage->shared_blk_read_time) ||
3839  !INSTR_TIME_IS_ZERO(usage->shared_blk_write_time));
3840  bool has_local_timing = (!INSTR_TIME_IS_ZERO(usage->local_blk_read_time) ||
3841  !INSTR_TIME_IS_ZERO(usage->local_blk_write_time));
3842  bool has_temp_timing = (!INSTR_TIME_IS_ZERO(usage->temp_blk_read_time) ||
3843  !INSTR_TIME_IS_ZERO(usage->temp_blk_write_time));
3844 
3845  /* Show only positive counter values. */
3846  if (has_shared || has_local || has_temp)
3847  {
3848  ExplainIndentText(es);
3849  appendStringInfoString(es->str, "Buffers:");
3850 
3851  if (has_shared)
3852  {
3853  appendStringInfoString(es->str, " shared");
3854  if (usage->shared_blks_hit > 0)
3855  appendStringInfo(es->str, " hit=%lld",
3856  (long long) usage->shared_blks_hit);
3857  if (usage->shared_blks_read > 0)
3858  appendStringInfo(es->str, " read=%lld",
3859  (long long) usage->shared_blks_read);
3860  if (usage->shared_blks_dirtied > 0)
3861  appendStringInfo(es->str, " dirtied=%lld",
3862  (long long) usage->shared_blks_dirtied);
3863  if (usage->shared_blks_written > 0)
3864  appendStringInfo(es->str, " written=%lld",
3865  (long long) usage->shared_blks_written);
3866  if (has_local || has_temp)
3867  appendStringInfoChar(es->str, ',');
3868  }
3869  if (has_local)
3870  {
3871  appendStringInfoString(es->str, " local");
3872  if (usage->local_blks_hit > 0)
3873  appendStringInfo(es->str, " hit=%lld",
3874  (long long) usage->local_blks_hit);
3875  if (usage->local_blks_read > 0)
3876  appendStringInfo(es->str, " read=%lld",
3877  (long long) usage->local_blks_read);
3878  if (usage->local_blks_dirtied > 0)
3879  appendStringInfo(es->str, " dirtied=%lld",
3880  (long long) usage->local_blks_dirtied);
3881  if (usage->local_blks_written > 0)
3882  appendStringInfo(es->str, " written=%lld",
3883  (long long) usage->local_blks_written);
3884  if (has_temp)
3885  appendStringInfoChar(es->str, ',');
3886  }
3887  if (has_temp)
3888  {
3889  appendStringInfoString(es->str, " temp");
3890  if (usage->temp_blks_read > 0)
3891  appendStringInfo(es->str, " read=%lld",
3892  (long long) usage->temp_blks_read);
3893  if (usage->temp_blks_written > 0)
3894  appendStringInfo(es->str, " written=%lld",
3895  (long long) usage->temp_blks_written);
3896  }
3897  appendStringInfoChar(es->str, '\n');
3898  }
3899 
3900  /* As above, show only positive counter values. */
3901  if (has_shared_timing || has_local_timing || has_temp_timing)
3902  {
3903  ExplainIndentText(es);
3904  appendStringInfoString(es->str, "I/O Timings:");
3905 
3906  if (has_shared_timing)
3907  {
3908  appendStringInfoString(es->str, " shared");
3909  if (!INSTR_TIME_IS_ZERO(usage->shared_blk_read_time))
3910  appendStringInfo(es->str, " read=%0.3f",
3911  INSTR_TIME_GET_MILLISEC(usage->shared_blk_read_time));
3912  if (!INSTR_TIME_IS_ZERO(usage->shared_blk_write_time))
3913  appendStringInfo(es->str, " write=%0.3f",
3914  INSTR_TIME_GET_MILLISEC(usage->shared_blk_write_time));
3915  if (has_local_timing || has_temp_timing)
3916  appendStringInfoChar(es->str, ',');
3917  }
3918  if (has_local_timing)
3919  {
3920  appendStringInfoString(es->str, " local");
3921  if (!INSTR_TIME_IS_ZERO(usage->local_blk_read_time))
3922  appendStringInfo(es->str, " read=%0.3f",
3923  INSTR_TIME_GET_MILLISEC(usage->local_blk_read_time));
3924  if (!INSTR_TIME_IS_ZERO(usage->local_blk_write_time))
3925  appendStringInfo(es->str, " write=%0.3f",
3926  INSTR_TIME_GET_MILLISEC(usage->local_blk_write_time));
3927  if (has_temp_timing)
3928  appendStringInfoChar(es->str, ',');
3929  }
3930  if (has_temp_timing)
3931  {
3932  appendStringInfoString(es->str, " temp");
3933  if (!INSTR_TIME_IS_ZERO(usage->temp_blk_read_time))
3934  appendStringInfo(es->str, " read=%0.3f",
3935  INSTR_TIME_GET_MILLISEC(usage->temp_blk_read_time));
3936  if (!INSTR_TIME_IS_ZERO(usage->temp_blk_write_time))
3937  appendStringInfo(es->str, " write=%0.3f",
3938  INSTR_TIME_GET_MILLISEC(usage->temp_blk_write_time));
3939  }
3940  appendStringInfoChar(es->str, '\n');
3941  }
3942  }
3943  else
3944  {
3945  ExplainPropertyInteger("Shared Hit Blocks", NULL,
3946  usage->shared_blks_hit, es);
3947  ExplainPropertyInteger("Shared Read Blocks", NULL,
3948  usage->shared_blks_read, es);
3949  ExplainPropertyInteger("Shared Dirtied Blocks", NULL,
3950  usage->shared_blks_dirtied, es);
3951  ExplainPropertyInteger("Shared Written Blocks", NULL,
3952  usage->shared_blks_written, es);
3953  ExplainPropertyInteger("Local Hit Blocks", NULL,
3954  usage->local_blks_hit, es);
3955  ExplainPropertyInteger("Local Read Blocks", NULL,
3956  usage->local_blks_read, es);
3957  ExplainPropertyInteger("Local Dirtied Blocks", NULL,
3958  usage->local_blks_dirtied, es);
3959  ExplainPropertyInteger("Local Written Blocks", NULL,
3960  usage->local_blks_written, es);
3961  ExplainPropertyInteger("Temp Read Blocks", NULL,
3962  usage->temp_blks_read, es);
3963  ExplainPropertyInteger("Temp Written Blocks", NULL,
3964  usage->temp_blks_written, es);
3965  if (track_io_timing)
3966  {
3967  ExplainPropertyFloat("Shared I/O Read Time", "ms",
3968  INSTR_TIME_GET_MILLISEC(usage->shared_blk_read_time),
3969  3, es);
3970  ExplainPropertyFloat("Shared I/O Write Time", "ms",
3971  INSTR_TIME_GET_MILLISEC(usage->shared_blk_write_time),
3972  3, es);
3973  ExplainPropertyFloat("Local I/O Read Time", "ms",
3974  INSTR_TIME_GET_MILLISEC(usage->local_blk_read_time),
3975  3, es);
3976  ExplainPropertyFloat("Local I/O Write Time", "ms",
3977  INSTR_TIME_GET_MILLISEC(usage->local_blk_write_time),
3978  3, es);
3979  ExplainPropertyFloat("Temp I/O Read Time", "ms",
3980  INSTR_TIME_GET_MILLISEC(usage->temp_blk_read_time),
3981  3, es);
3982  ExplainPropertyFloat("Temp I/O Write Time", "ms",
3983  INSTR_TIME_GET_MILLISEC(usage->temp_blk_write_time),
3984  3, es);
3985  }
3986  }
3987 }
bool track_io_timing
Definition: bufmgr.c:170
#define INSTR_TIME_GET_MILLISEC(t)
Definition: instr_time.h:191

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), EXPLAIN_FORMAT_TEXT, ExplainIndentText(), ExplainPropertyFloat(), ExplainPropertyInteger(), ExplainState::format, INSTR_TIME_GET_MILLISEC, INSTR_TIME_IS_ZERO, ExplainState::str, track_io_timing, and usage().

Referenced by ExplainNode(), ExplainOnePlan(), and ExplainPrintSerialize().

◆ show_expression()

static void show_expression ( Node node,
const char *  qlabel,
PlanState planstate,
List ancestors,
bool  useprefix,
ExplainState es 
)
static

Definition at line 2493 of file explain.c.

2496 {
2497  List *context;
2498  char *exprstr;
2499 
2500  /* Set up deparsing context */
2502  planstate->plan,
2503  ancestors);
2504 
2505  /* Deparse the expression */
2506  exprstr = deparse_expression(node, context, useprefix, false);
2507 
2508  /* And add to es->str */
2509  ExplainPropertyText(qlabel, exprstr, es);
2510 }
tree context
Definition: radixtree.h:1835
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:3598
List * set_deparse_context_plan(List *dpcontext, Plan *plan, List *ancestors)
Definition: ruleutils.c:3772

References context, ExplainState::deparse_cxt, deparse_expression(), ExplainPropertyText(), PlanState::plan, and set_deparse_context_plan().

Referenced by ExplainNode(), and show_qual().

◆ show_foreignscan_info()

static void show_foreignscan_info ( ForeignScanState fsstate,
ExplainState es 
)
static

Definition at line 3732 of file explain.c.

3733 {
3734  FdwRoutine *fdwroutine = fsstate->fdwroutine;
3735 
3736  /* Let the FDW emit whatever fields it wants */
3737  if (((ForeignScan *) fsstate->ss.ps.plan)->operation != CMD_SELECT)
3738  {
3739  if (fdwroutine->ExplainDirectModify != NULL)
3740  fdwroutine->ExplainDirectModify(fsstate, es);
3741  }
3742  else
3743  {
3744  if (fdwroutine->ExplainForeignScan != NULL)
3745  fdwroutine->ExplainForeignScan(fsstate, es);
3746  }
3747 }
ExplainForeignScan_function ExplainForeignScan
Definition: fdwapi.h:252
ExplainDirectModify_function ExplainDirectModify
Definition: fdwapi.h:254
struct FdwRoutine * fdwroutine
Definition: execnodes.h:2069
ScanState ss
Definition: execnodes.h:2064

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

Referenced by ExplainNode().

◆ show_group_keys()

static void show_group_keys ( GroupState gstate,
List ancestors,
ExplainState es 
)
static

Definition at line 2745 of file explain.c.

2747 {
2748  Group *plan = (Group *) gstate->ss.ps.plan;
2749 
2750  /* The key columns refer to the tlist of the child plan */
2751  ancestors = lcons(plan, ancestors);
2752  show_sort_group_keys(outerPlanState(gstate), "Group Key",
2753  plan->numCols, 0, plan->grpColIdx,
2754  NULL, NULL, NULL,
2755  ancestors, es);
2756  ancestors = list_delete_first(ancestors);
2757 }
ScanState ss
Definition: execnodes.h:2442

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

Referenced by ExplainNode().

◆ show_grouping_set_keys()

static void show_grouping_set_keys ( PlanState planstate,
Agg aggnode,
Sort sortnode,
List context,
bool  useprefix,
List ancestors,
ExplainState es 
)
static

Definition at line 2667 of file explain.c.

2671 {
2672  Plan *plan = planstate->plan;
2673  char *exprstr;
2674  ListCell *lc;
2675  List *gsets = aggnode->groupingSets;
2676  AttrNumber *keycols = aggnode->grpColIdx;
2677  const char *keyname;
2678  const char *keysetname;
2679 
2680  if (aggnode->aggstrategy == AGG_HASHED || aggnode->aggstrategy == AGG_MIXED)
2681  {
2682  keyname = "Hash Key";
2683  keysetname = "Hash Keys";
2684  }
2685  else
2686  {
2687  keyname = "Group Key";
2688  keysetname = "Group Keys";
2689  }
2690 
2691  ExplainOpenGroup("Grouping Set", NULL, true, es);
2692 
2693  if (sortnode)
2694  {
2695  show_sort_group_keys(planstate, "Sort Key",
2696  sortnode->numCols, 0, sortnode->sortColIdx,
2697  sortnode->sortOperators, sortnode->collations,
2698  sortnode->nullsFirst,
2699  ancestors, es);
2700  if (es->format == EXPLAIN_FORMAT_TEXT)
2701  es->indent++;
2702  }
2703 
2704  ExplainOpenGroup(keysetname, keysetname, false, es);
2705 
2706  foreach(lc, gsets)
2707  {
2708  List *result = NIL;
2709  ListCell *lc2;
2710 
2711  foreach(lc2, (List *) lfirst(lc))
2712  {
2713  Index i = lfirst_int(lc2);
2714  AttrNumber keyresno = keycols[i];
2715  TargetEntry *target = get_tle_by_resno(plan->targetlist,
2716  keyresno);
2717 
2718  if (!target)
2719  elog(ERROR, "no tlist entry for key %d", keyresno);
2720  /* Deparse the expression, showing any top-level cast */
2721  exprstr = deparse_expression((Node *) target->expr, context,
2722  useprefix, true);
2723 
2724  result = lappend(result, exprstr);
2725  }
2726 
2727  if (!result && es->format == EXPLAIN_FORMAT_TEXT)
2728  ExplainPropertyText(keyname, "()", es);
2729  else
2730  ExplainPropertyListNested(keyname, result, es);
2731  }
2732 
2733  ExplainCloseGroup(keysetname, keysetname, false, es);
2734 
2735  if (sortnode && es->format == EXPLAIN_FORMAT_TEXT)
2736  es->indent--;
2737 
2738  ExplainCloseGroup("Grouping Set", NULL, true, es);
2739 }
unsigned int Index
Definition: c.h:614
void ExplainPropertyListNested(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:4777
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
#define lfirst_int(lc)
Definition: pg_list.h:173
List * groupingSets
Definition: plannodes.h:1028
int numCols
Definition: plannodes.h:936
Expr * expr
Definition: primnodes.h:2186

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

Referenced by show_grouping_sets().

◆ show_grouping_sets()

static void show_grouping_sets ( PlanState planstate,
Agg agg,
List ancestors,
ExplainState es 
)
static

Definition at line 2636 of file explain.c.

2638 {
2639  List *context;
2640  bool useprefix;
2641  ListCell *lc;
2642 
2643  /* Set up deparsing context */
2645  planstate->plan,
2646  ancestors);
2647  useprefix = (list_length(es->rtable) > 1 || es->verbose);
2648 
2649  ExplainOpenGroup("Grouping Sets", "Grouping Sets", false, es);
2650 
2651  show_grouping_set_keys(planstate, agg, NULL,
2652  context, useprefix, ancestors, es);
2653 
2654  foreach(lc, agg->chain)
2655  {
2656  Agg *aggnode = lfirst(lc);
2657  Sort *sortnode = (Sort *) aggnode->plan.lefttree;
2658 
2659  show_grouping_set_keys(planstate, aggnode, sortnode,
2660  context, useprefix, ancestors, es);
2661  }
2662 
2663  ExplainCloseGroup("Grouping Sets", "Grouping Sets", false, es);
2664 }
static void show_grouping_set_keys(PlanState *planstate, Agg *aggnode, Sort *sortnode, List *context, bool useprefix, List *ancestors, ExplainState *es)
Definition: explain.c:2667
List * chain
Definition: plannodes.h:1031
Plan plan
Definition: plannodes.h:998
struct Plan * lefttree
Definition: plannodes.h:154

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

Referenced by show_agg_keys().

◆ show_hash_info()

static void show_hash_info ( HashState hashstate,
ExplainState es 
)
static

Definition at line 3242 of file explain.c.

3243 {
3244  HashInstrumentation hinstrument = {0};
3245 
3246  /*
3247  * Collect stats from the local process, even when it's a parallel query.
3248  * In a parallel query, the leader process may or may not have run the
3249  * hash join, and even if it did it may not have built a hash table due to
3250  * timing (if it started late it might have seen no tuples in the outer
3251  * relation and skipped building the hash table). Therefore we have to be
3252  * prepared to get instrumentation data from all participants.
3253  */
3254  if (hashstate->hinstrument)
3255  memcpy(&hinstrument, hashstate->hinstrument,
3256  sizeof(HashInstrumentation));
3257 
3258  /*
3259  * Merge results from workers. In the parallel-oblivious case, the
3260  * results from all participants should be identical, except where
3261  * participants didn't run the join at all so have no data. In the
3262  * parallel-aware case, we need to consider all the results. Each worker
3263  * may have seen a different subset of batches and we want to report the
3264  * highest memory usage across all batches. We take the maxima of other
3265  * values too, for the same reasons as in ExecHashAccumInstrumentation.
3266  */
3267  if (hashstate->shared_info)
3268  {
3269  SharedHashInfo *shared_info = hashstate->shared_info;
3270  int i;
3271 
3272  for (i = 0; i < shared_info->num_workers; ++i)
3273  {
3274  HashInstrumentation *worker_hi = &shared_info->hinstrument[i];
3275 
3276  hinstrument.nbuckets = Max(hinstrument.nbuckets,
3277  worker_hi->nbuckets);
3278  hinstrument.nbuckets_original = Max(hinstrument.nbuckets_original,
3279  worker_hi->nbuckets_original);
3280  hinstrument.nbatch = Max(hinstrument.nbatch,
3281  worker_hi->nbatch);
3282  hinstrument.nbatch_original = Max(hinstrument.nbatch_original,
3283  worker_hi->nbatch_original);
3284  hinstrument.space_peak = Max(hinstrument.space_peak,
3285  worker_hi->space_peak);
3286  }
3287  }
3288 
3289  if (hinstrument.nbatch > 0)
3290  {
3291  uint64 spacePeakKb = BYTES_TO_KILOBYTES(hinstrument.space_peak);
3292 
3293  if (es->format != EXPLAIN_FORMAT_TEXT)
3294  {
3295  ExplainPropertyInteger("Hash Buckets", NULL,
3296  hinstrument.nbuckets, es);
3297  ExplainPropertyInteger("Original Hash Buckets", NULL,
3298  hinstrument.nbuckets_original, es);
3299  ExplainPropertyInteger("Hash Batches", NULL,
3300  hinstrument.nbatch, es);
3301  ExplainPropertyInteger("Original Hash Batches", NULL,
3302  hinstrument.nbatch_original, es);
3303  ExplainPropertyUInteger("Peak Memory Usage", "kB",
3304  spacePeakKb, es);
3305  }
3306  else if (hinstrument.nbatch_original != hinstrument.nbatch ||
3307  hinstrument.nbuckets_original != hinstrument.nbuckets)
3308  {
3309  ExplainIndentText(es);
3310  appendStringInfo(es->str,
3311  "Buckets: %d (originally %d) Batches: %d (originally %d) Memory Usage: " UINT64_FORMAT "kB\n",
3312  hinstrument.nbuckets,
3313  hinstrument.nbuckets_original,
3314  hinstrument.nbatch,
3315  hinstrument.nbatch_original,
3316  spacePeakKb);
3317  }
3318  else
3319  {
3320  ExplainIndentText(es);
3321  appendStringInfo(es->str,
3322  "Buckets: %d Batches: %d Memory Usage: " UINT64_FORMAT "kB\n",
3323  hinstrument.nbuckets, hinstrument.nbatch,
3324  spacePeakKb);
3325  }
3326  }
3327 }
#define Max(x, y)
Definition: c.h:998
SharedHashInfo * shared_info
Definition: execnodes.h:2780
HashInstrumentation * hinstrument
Definition: execnodes.h:2787
HashInstrumentation hinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2761

References appendStringInfo(), BYTES_TO_KILOBYTES, EXPLAIN_FORMAT_TEXT, ExplainIndentText(), ExplainPropertyInteger(), ExplainPropertyUInteger(), ExplainState::format, SharedHashInfo::hinstrument, HashState::hinstrument, i, Max, HashInstrumentation::nbatch, HashInstrumentation::nbatch_original, HashInstrumentation::nbuckets, HashInstrumentation::nbuckets_original, SharedHashInfo::num_workers, HashState::shared_info, HashInstrumentation::space_peak, ExplainState::str, and UINT64_FORMAT.

Referenced by ExplainNode().

◆ show_hashagg_info()

static void show_hashagg_info ( AggState aggstate,
ExplainState es 
)
static

Definition at line 3513 of file explain.c.

3514 {
3515  Agg *agg = (Agg *) aggstate->ss.ps.plan;
3516  int64 memPeakKb = BYTES_TO_KILOBYTES(aggstate->hash_mem_peak);
3517 
3518  if (agg->aggstrategy != AGG_HASHED &&
3519  agg->aggstrategy != AGG_MIXED)
3520  return;
3521 
3522  if (es->format != EXPLAIN_FORMAT_TEXT)
3523  {
3524  if (es->costs)
3525  ExplainPropertyInteger("Planned Partitions", NULL,
3526  aggstate->hash_planned_partitions, es);
3527 
3528  /*
3529  * During parallel query the leader may have not helped out. We
3530  * detect this by checking how much memory it used. If we find it
3531  * didn't do any work then we don't show its properties.
3532  */
3533  if (es->analyze && aggstate->hash_mem_peak > 0)
3534  {
3535  ExplainPropertyInteger("HashAgg Batches", NULL,
3536  aggstate->hash_batches_used, es);
3537  ExplainPropertyInteger("Peak Memory Usage", "kB", memPeakKb, es);
3538  ExplainPropertyInteger("Disk Usage", "kB",
3539  aggstate->hash_disk_used, es);
3540  }
3541  }
3542  else
3543  {
3544  bool gotone = false;
3545 
3546  if (es->costs && aggstate->hash_planned_partitions > 0)
3547  {
3548  ExplainIndentText(es);
3549  appendStringInfo(es->str, "Planned Partitions: %d",
3550  aggstate->hash_planned_partitions);
3551  gotone = true;
3552  }
3553 
3554  /*
3555  * During parallel query the leader may have not helped out. We
3556  * detect this by checking how much memory it used. If we find it
3557  * didn't do any work then we don't show its properties.
3558  */
3559  if (es->analyze && aggstate->hash_mem_peak > 0)
3560  {
3561  if (!gotone)
3562  ExplainIndentText(es);
3563  else
3564  appendStringInfoSpaces(es->str, 2);
3565 
3566  appendStringInfo(es->str, "Batches: %d Memory Usage: " INT64_FORMAT "kB",
3567  aggstate->hash_batches_used, memPeakKb);
3568  gotone = true;
3569 
3570  /* Only display disk usage if we spilled to disk */
3571  if (aggstate->hash_batches_used > 1)
3572  {
3573  appendStringInfo(es->str, " Disk Usage: " UINT64_FORMAT "kB",
3574  aggstate->hash_disk_used);
3575  }
3576  }
3577 
3578  if (gotone)
3579  appendStringInfoChar(es->str, '\n');
3580  }
3581 
3582  /* Display stats for each parallel worker */
3583  if (es->analyze && aggstate->shared_info != NULL)
3584  {
3585  for (int n = 0; n < aggstate->shared_info->num_workers; n++)
3586  {
3587  AggregateInstrumentation *sinstrument;
3588  uint64 hash_disk_used;
3589  int hash_batches_used;
3590 
3591  sinstrument = &aggstate->shared_info->sinstrument[n];
3592  /* Skip workers that didn't do anything */
3593  if (sinstrument->hash_mem_peak == 0)
3594  continue;
3595  hash_disk_used = sinstrument->hash_disk_used;
3596  hash_batches_used = sinstrument->hash_batches_used;
3597  memPeakKb = BYTES_TO_KILOBYTES(sinstrument->hash_mem_peak);
3598 
3599  if (es->workers_state)
3600  ExplainOpenWorker(n, es);
3601 
3602  if (es->format == EXPLAIN_FORMAT_TEXT)
3603  {
3604  ExplainIndentText(es);
3605 
3606  appendStringInfo(es->str, "Batches: %d Memory Usage: " INT64_FORMAT "kB",
3607  hash_batches_used, memPeakKb);
3608 
3609  /* Only display disk usage if we spilled to disk */
3610  if (hash_batches_used > 1)
3611  appendStringInfo(es->str, " Disk Usage: " UINT64_FORMAT "kB",
3612  hash_disk_used);
3613  appendStringInfoChar(es->str, '\n');
3614  }
3615  else
3616  {
3617  ExplainPropertyInteger("HashAgg Batches", NULL,
3618  hash_batches_used, es);
3619  ExplainPropertyInteger("Peak Memory Usage", "kB", memPeakKb,
3620  es);
3621  ExplainPropertyInteger("Disk Usage", "kB", hash_disk_used, es);
3622  }
3623 
3624  if (es->workers_state)
3625  ExplainCloseWorker(n, es);
3626  }
3627  }
3628 }
uint64 hash_disk_used
Definition: execnodes.h:2549
int hash_planned_partitions
Definition: execnodes.h:2543
SharedAggInfo * shared_info
Definition: execnodes.h:2560
Size hash_mem_peak
Definition: execnodes.h:2546
int hash_batches_used
Definition: execnodes.h:2550
AggregateInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2465

References AGG_HASHED, AGG_MIXED, Agg::aggstrategy, ExplainState::analyze, appendStringInfo(), appendStringInfoChar(), appendStringInfoSpaces(), BYTES_TO_KILOBYTES, ExplainState::costs, EXPLAIN_FORMAT_TEXT, ExplainCloseWorker(), ExplainIndentText(), ExplainOpenWorker(), ExplainPropertyInteger(), ExplainState::format, AggregateInstrumentation::hash_batches_used, AggState::hash_batches_used, AggregateInstrumentation::hash_disk_used, AggState::hash_disk_used, AggregateInstrumentation::hash_mem_peak, AggState::hash_mem_peak, AggState::hash_planned_partitions, INT64_FORMAT, SharedAggInfo::num_workers, PlanState::plan, ScanState::ps, AggState::shared_info, SharedAggInfo::sinstrument, AggState::ss, ExplainState::str, UINT64_FORMAT, and ExplainState::workers_state.

Referenced by ExplainNode().

◆ show_incremental_sort_group_info()

static void show_incremental_sort_group_info ( IncrementalSortGroupInfo groupInfo,
const char *  groupLabel,
bool  indent,
ExplainState es 
)
static

Definition at line 3042 of file explain.c.

3044 {
3045  ListCell *methodCell;
3046  List *methodNames = NIL;
3047 
3048  /* Generate a list of sort methods used across all groups. */
3049  for (int bit = 0; bit < NUM_TUPLESORTMETHODS; bit++)
3050  {
3051  TuplesortMethod sortMethod = (1 << bit);
3052 
3053  if (groupInfo->sortMethods & sortMethod)
3054  {
3055  const char *methodName = tuplesort_method_name(sortMethod);
3056 
3057  methodNames = lappend(methodNames, unconstify(char *, methodName));
3058  }
3059  }
3060 
3061  if (es->format == EXPLAIN_FORMAT_TEXT)
3062  {
3063  if (indent)
3064  appendStringInfoSpaces(es->str, es->indent * 2);
3065  appendStringInfo(es->str, "%s Groups: " INT64_FORMAT " Sort Method", groupLabel,
3066  groupInfo->groupCount);
3067  /* plural/singular based on methodNames size */
3068  if (list_length(methodNames) > 1)
3069  appendStringInfoString(es->str, "s: ");
3070  else
3071  appendStringInfoString(es->str, ": ");
3072  foreach(methodCell, methodNames)
3073  {
3074  appendStringInfoString(es->str, (char *) methodCell->ptr_value);
3075  if (foreach_current_index(methodCell) < list_length(methodNames) - 1)
3076  appendStringInfoString(es->str, ", ");
3077  }
3078 
3079  if (groupInfo->maxMemorySpaceUsed > 0)
3080  {
3081  int64 avgSpace = groupInfo->totalMemorySpaceUsed / groupInfo->groupCount;
3082  const char *spaceTypeName;
3083 
3085  appendStringInfo(es->str, " Average %s: " INT64_FORMAT "kB Peak %s: " INT64_FORMAT "kB",
3086  spaceTypeName, avgSpace,
3087  spaceTypeName, groupInfo->maxMemorySpaceUsed);
3088  }
3089 
3090  if (groupInfo->maxDiskSpaceUsed > 0)
3091  {
3092  int64 avgSpace = groupInfo->totalDiskSpaceUsed / groupInfo->groupCount;
3093 
3094  const char *spaceTypeName;
3095 
3097  appendStringInfo(es->str, " Average %s: " INT64_FORMAT "kB Peak %s: " INT64_FORMAT "kB",
3098  spaceTypeName, avgSpace,
3099  spaceTypeName, groupInfo->maxDiskSpaceUsed);
3100  }
3101  }
3102  else
3103  {
3104  StringInfoData groupName;
3105 
3106  initStringInfo(&groupName);
3107  appendStringInfo(&groupName, "%s Groups", groupLabel);
3108  ExplainOpenGroup("Incremental Sort Groups", groupName.data, true, es);
3109  ExplainPropertyInteger("Group Count", NULL, groupInfo->groupCount, es);
3110 
3111  ExplainPropertyList("Sort Methods Used", methodNames, es);
3112 
3113  if (groupInfo->maxMemorySpaceUsed > 0)
3114  {
3115  int64 avgSpace = groupInfo->totalMemorySpaceUsed / groupInfo->groupCount;
3116  const char *spaceTypeName;
3117  StringInfoData memoryName;
3118 
3120  initStringInfo(&memoryName);
3121  appendStringInfo(&memoryName, "Sort Space %s", spaceTypeName);
3122  ExplainOpenGroup("Sort Space", memoryName.data, true, es);
3123 
3124  ExplainPropertyInteger("Average Sort Space Used", "kB", avgSpace, es);
3125  ExplainPropertyInteger("Peak Sort Space Used", "kB",
3126  groupInfo->maxMemorySpaceUsed, es);
3127 
3128  ExplainCloseGroup("Sort Space", memoryName.data, true, es);
3129  }
3130  if (groupInfo->maxDiskSpaceUsed > 0)
3131  {
3132  int64 avgSpace = groupInfo->totalDiskSpaceUsed / groupInfo->groupCount;
3133  const char *spaceTypeName;
3134  StringInfoData diskName;
3135 
3137  initStringInfo(&diskName);
3138  appendStringInfo(&diskName, "Sort Space %s", spaceTypeName);
3139  ExplainOpenGroup("Sort Space", diskName.data, true, es);
3140 
3141  ExplainPropertyInteger("Average Sort Space Used", "kB", avgSpace, es);
3142  ExplainPropertyInteger("Peak Sort Space Used", "kB",
3143  groupInfo->maxDiskSpaceUsed, es);
3144 
3145  ExplainCloseGroup("Sort Space", diskName.data, true, es);
3146  }
3147 
3148  ExplainCloseGroup("Incremental Sort Groups", groupName.data, true, es);
3149  }
3150 }
#define unconstify(underlying_type, expr)
Definition: c.h:1245
#define foreach_current_index(var_or_cell)
Definition: pg_list.h:403
const char * tuplesort_space_type_name(TuplesortSpaceType t)
Definition: tuplesort.c:2605
const char * tuplesort_method_name(TuplesortMethod m)
Definition: tuplesort.c:2582
#define NUM_TUPLESORTMETHODS
Definition: tuplesort.h:84
@ SORT_SPACE_TYPE_DISK
Definition: tuplesort.h:88
@ SORT_SPACE_TYPE_MEMORY
Definition: tuplesort.h:89
TuplesortMethod
Definition: tuplesort.h:76
void * ptr_value
Definition: pg_list.h:47
Datum bit(PG_FUNCTION_ARGS)
Definition: varbit.c:391

References appendStringInfo(), appendStringInfoSpaces(), appendStringInfoString(), bit(), StringInfoData::data, EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), ExplainOpenGroup(), ExplainPropertyInteger(), ExplainPropertyList(), foreach_current_index, ExplainState::format, IncrementalSortGroupInfo::groupCount, ExplainState::indent, initStringInfo(), INT64_FORMAT, lappend(), list_length(), IncrementalSortGroupInfo::maxDiskSpaceUsed, IncrementalSortGroupInfo::maxMemorySpaceUsed, NIL, NUM_TUPLESORTMETHODS, ListCell::ptr_value, SORT_SPACE_TYPE_DISK, SORT_SPACE_TYPE_MEMORY, IncrementalSortGroupInfo::sortMethods, ExplainState::str, IncrementalSortGroupInfo::totalDiskSpaceUsed, IncrementalSortGroupInfo::totalMemorySpaceUsed, tuplesort_method_name(), tuplesort_space_type_name(), and unconstify.

Referenced by show_incremental_sort_info().

◆ show_incremental_sort_info()

static void show_incremental_sort_info ( IncrementalSortState incrsortstate,
ExplainState es 
)
static

Definition at line 3156 of file explain.c.

3158 {
3159  IncrementalSortGroupInfo *fullsortGroupInfo;
3160  IncrementalSortGroupInfo *prefixsortGroupInfo;
3161 
3162  fullsortGroupInfo = &incrsortstate->incsort_info.fullsortGroupInfo;
3163 
3164  if (!es->analyze)
3165  return;
3166 
3167  /*
3168  * Since we never have any prefix groups unless we've first sorted a full
3169  * groups and transitioned modes (copying the tuples into a prefix group),
3170  * we don't need to do anything if there were 0 full groups.
3171  *
3172  * We still have to continue after this block if there are no full groups,
3173  * though, since it's possible that we have workers that did real work
3174  * even if the leader didn't participate.
3175  */
3176  if (fullsortGroupInfo->groupCount > 0)
3177  {
3178  show_incremental_sort_group_info(fullsortGroupInfo, "Full-sort", true, es);
3179  prefixsortGroupInfo = &incrsortstate->incsort_info.prefixsortGroupInfo;
3180  if (prefixsortGroupInfo->groupCount > 0)
3181  {
3182  if (es->format == EXPLAIN_FORMAT_TEXT)
3183  appendStringInfoChar(es->str, '\n');
3184  show_incremental_sort_group_info(prefixsortGroupInfo, "Pre-sorted", true, es);
3185  }
3186  if (es->format == EXPLAIN_FORMAT_TEXT)
3187  appendStringInfoChar(es->str, '\n');
3188  }
3189 
3190  if (incrsortstate->shared_info != NULL)
3191  {
3192  int n;
3193  bool indent_first_line;
3194 
3195  for (n = 0; n < incrsortstate->shared_info->num_workers; n++)
3196  {
3197  IncrementalSortInfo *incsort_info =
3198  &incrsortstate->shared_info->sinfo[n];
3199 
3200  /*
3201  * If a worker hasn't processed any sort groups at all, then
3202  * exclude it from output since it either didn't launch or didn't
3203  * contribute anything meaningful.
3204  */
3205  fullsortGroupInfo = &incsort_info->fullsortGroupInfo;
3206 
3207  /*
3208  * Since we never have any prefix groups unless we've first sorted
3209  * a full groups and transitioned modes (copying the tuples into a
3210  * prefix group), we don't need to do anything if there were 0
3211  * full groups.
3212  */
3213  if (fullsortGroupInfo->groupCount == 0)
3214  continue;
3215 
3216  if (es->workers_state)
3217  ExplainOpenWorker(n, es);
3218 
3219  indent_first_line = es->workers_state == NULL || es->verbose;
3220  show_incremental_sort_group_info(fullsortGroupInfo, "Full-sort",
3221  indent_first_line, es);
3222  prefixsortGroupInfo = &incsort_info->prefixsortGroupInfo;
3223  if (prefixsortGroupInfo->groupCount > 0)
3224  {
3225  if (es->format == EXPLAIN_FORMAT_TEXT)
3226  appendStringInfoChar(es->str, '\n');
3227  show_incremental_sort_group_info(prefixsortGroupInfo, "Pre-sorted", true, es);
3228  }
3229  if (es->format == EXPLAIN_FORMAT_TEXT)
3230  appendStringInfoChar(es->str, '\n');
3231 
3232  if (es->workers_state)
3233  ExplainCloseWorker(n, es);
3234  }
3235  }
3236 }
static void show_incremental_sort_group_info(IncrementalSortGroupInfo *groupInfo, const char *groupLabel, bool indent, ExplainState *es)
Definition: explain.c:3042
IncrementalSortGroupInfo prefixsortGroupInfo
Definition: execnodes.h:2388
IncrementalSortGroupInfo fullsortGroupInfo
Definition: execnodes.h:2387
SharedIncrementalSortInfo * shared_info
Definition: execnodes.h:2433
IncrementalSortInfo incsort_info
Definition: execnodes.h:2427
IncrementalSortInfo sinfo[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2398

References ExplainState::analyze, appendStringInfoChar(), EXPLAIN_FORMAT_TEXT, ExplainCloseWorker(), ExplainOpenWorker(), ExplainState::format, IncrementalSortInfo::fullsortGroupInfo, IncrementalSortGroupInfo::groupCount, IncrementalSortState::incsort_info, SharedIncrementalSortInfo::num_workers, IncrementalSortInfo::prefixsortGroupInfo, IncrementalSortState::shared_info, show_incremental_sort_group_info(), SharedIncrementalSortInfo::sinfo, ExplainState::str, ExplainState::verbose, and ExplainState::workers_state.

Referenced by ExplainNode().

◆ show_incremental_sort_keys()

static void show_incremental_sort_keys ( IncrementalSortState incrsortstate,
List ancestors,
ExplainState es 
)
static

Definition at line 2580 of file explain.c.

2582 {
2583  IncrementalSort *plan = (IncrementalSort *) incrsortstate->ss.ps.plan;
2584 
2585  show_sort_group_keys((PlanState *) incrsortstate, "Sort Key",
2586  plan->sort.numCols, plan->nPresortedCols,
2587  plan->sort.sortColIdx,
2588  plan->sort.sortOperators, plan->sort.collations,
2589  plan->sort.nullsFirst,
2590  ancestors, es);
2591 }

References PlanState::plan, plan, ScanState::ps, show_sort_group_keys(), and IncrementalSortState::ss.

Referenced by ExplainNode().

◆ show_instrumentation_count()

static void show_instrumentation_count ( const char *  qlabel,
int  which,
PlanState planstate,
ExplainState es 
)
static

Definition at line 3703 of file explain.c.

3705 {
3706  double nfiltered;
3707  double nloops;
3708 
3709  if (!es->analyze || !planstate->instrument)
3710  return;
3711 
3712  if (which == 2)
3713  nfiltered = planstate->instrument->nfiltered2;
3714  else
3715  nfiltered = planstate->instrument->nfiltered1;
3716  nloops = planstate->instrument->nloops;
3717 
3718  /* In text mode, suppress zero counts; they're not interesting enough */
3719  if (nfiltered > 0 || es->format != EXPLAIN_FORMAT_TEXT)
3720  {
3721  if (nloops > 0)
3722  ExplainPropertyFloat(qlabel, NULL, nfiltered / nloops, 0, es);
3723  else
3724  ExplainPropertyFloat(qlabel, NULL, 0.0, 0, es);
3725  }
3726 }
double nfiltered2
Definition: instrument.h:90
double nfiltered1
Definition: instrument.h:89

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

Referenced by ExplainNode(), and show_modifytable_info().

◆ show_material_info()

static void show_material_info ( MaterialState mstate,
ExplainState es 
)
static

Definition at line 3334 of file explain.c.

3335 {
3336  Tuplestorestate *tupstore = mstate->tuplestorestate;
3337  const char *storageType;
3338  int64 spaceUsedKB;
3339 
3340  /*
3341  * Nothing to show if ANALYZE option wasn't used or if execution didn't
3342  * get as far as creating the tuplestore.
3343  */
3344  if (!es->analyze || tupstore == NULL)
3345  return;
3346 
3347  storageType = tuplestore_storage_type_name(tupstore);
3348  spaceUsedKB = BYTES_TO_KILOBYTES(tuplestore_space_used(tupstore));
3349 
3350  if (es->format != EXPLAIN_FORMAT_TEXT)
3351  {
3352  ExplainPropertyText("Storage", storageType, es);
3353  ExplainPropertyInteger("Maximum Storage", "kB", spaceUsedKB, es);
3354  }
3355  else
3356  {
3357  ExplainIndentText(es);
3358  appendStringInfo(es->str,
3359  "Storage: %s Maximum Storage: " INT64_FORMAT "kB\n",
3360  storageType,
3361  spaceUsedKB);
3362  }
3363 }
Tuplestorestate * tuplestorestate
Definition: execnodes.h:2255
int64 tuplestore_space_used(Tuplestorestate *state)
Definition: tuplestore.c:1524
const char * tuplestore_storage_type_name(Tuplestorestate *state)
Definition: tuplestore.c:1510

References ExplainState::analyze, appendStringInfo(), BYTES_TO_KILOBYTES, EXPLAIN_FORMAT_TEXT, ExplainIndentText(), ExplainPropertyInteger(), ExplainPropertyText(), ExplainState::format, INT64_FORMAT, ExplainState::str, tuplestore_space_used(), tuplestore_storage_type_name(), and MaterialState::tuplestorestate.

Referenced by ExplainNode().

◆ show_memoize_info()

static void show_memoize_info ( MemoizeState mstate,
List ancestors,
ExplainState es 
)
static

Definition at line 3369 of file explain.c.

3370 {
3371  Plan *plan = ((PlanState *) mstate)->plan;
3372  ListCell *lc;
3373  List *context;
3374  StringInfoData keystr;
3375  char *separator = "";
3376  bool useprefix;
3377  int64 memPeakKb;
3378 
3379  initStringInfo(&keystr);
3380 
3381  /*
3382  * It's hard to imagine having a memoize node with fewer than 2 RTEs, but
3383  * let's just keep the same useprefix logic as elsewhere in this file.
3384  */
3385  useprefix = list_length(es->rtable) > 1 || es->verbose;
3386 
3387  /* Set up deparsing context */
3389  plan,
3390  ancestors);
3391 
3392  foreach(lc, ((Memoize *) plan)->param_exprs)
3393  {
3394  Node *expr = (Node *) lfirst(lc);
3395 
3397 
3399  useprefix, false));
3400  separator = ", ";
3401  }
3402 
3403  if (es->format != EXPLAIN_FORMAT_TEXT)
3404  {
3405  ExplainPropertyText("Cache Key", keystr.data, es);
3406  ExplainPropertyText("Cache Mode", mstate->binary_mode ? "binary" : "logical", es);
3407  }
3408  else
3409  {
3410  ExplainIndentText(es);
3411  appendStringInfo(es->str, "Cache Key: %s\n", keystr.data);
3412  ExplainIndentText(es);
3413  appendStringInfo(es->str, "Cache Mode: %s\n", mstate->binary_mode ? "binary" : "logical");
3414  }
3415 
3416  pfree(keystr.data);
3417 
3418  if (!es->analyze)
3419  return;
3420 
3421  if (mstate->stats.cache_misses > 0)
3422  {
3423  /*
3424  * mem_peak is only set when we freed memory, so we must use mem_used
3425  * when mem_peak is 0.
3426  */
3427  if (mstate->stats.mem_peak > 0)
3428  memPeakKb = BYTES_TO_KILOBYTES(mstate->stats.mem_peak);
3429  else
3430  memPeakKb = BYTES_TO_KILOBYTES(mstate->mem_used);
3431 
3432  if (es->format != EXPLAIN_FORMAT_TEXT)
3433  {
3434  ExplainPropertyInteger("Cache Hits", NULL, mstate->stats.cache_hits, es);
3435  ExplainPropertyInteger("Cache Misses", NULL, mstate->stats.cache_misses, es);
3436  ExplainPropertyInteger("Cache Evictions", NULL, mstate->stats.cache_evictions, es);
3437  ExplainPropertyInteger("Cache Overflows", NULL, mstate->stats.cache_overflows, es);
3438  ExplainPropertyInteger("Peak Memory Usage", "kB", memPeakKb, es);
3439  }
3440  else
3441  {
3442  ExplainIndentText(es);
3443  appendStringInfo(es->str,
3444  "Hits: " UINT64_FORMAT " Misses: " UINT64_FORMAT " Evictions: " UINT64_FORMAT " Overflows: " UINT64_FORMAT " Memory Usage: " INT64_FORMAT "kB\n",
3445  mstate->stats.cache_hits,
3446  mstate->stats.cache_misses,
3447  mstate->stats.cache_evictions,
3448  mstate->stats.cache_overflows,
3449  memPeakKb);
3450  }
3451  }
3452 
3453  if (mstate->shared_info == NULL)
3454  return;
3455 
3456  /* Show details from parallel workers */
3457  for (int n = 0; n < mstate->shared_info->num_workers; n++)
3458  {
3460 
3461  si = &mstate->shared_info->sinstrument[n];
3462 
3463  /*
3464  * Skip workers that didn't do any work. We needn't bother checking
3465  * for cache hits as a miss will always occur before a cache hit.
3466  */
3467  if (si->cache_misses == 0)
3468  continue;
3469 
3470  if (es->workers_state)
3471  ExplainOpenWorker(n, es);
3472 
3473  /*
3474  * Since the worker's MemoizeState.mem_used field is unavailable to
3475  * us, ExecEndMemoize will have set the
3476  * MemoizeInstrumentation.mem_peak field for us. No need to do the
3477  * zero checks like we did for the serial case above.
3478  */
3479  memPeakKb = BYTES_TO_KILOBYTES(si->mem_peak);
3480 
3481  if (es->format == EXPLAIN_FORMAT_TEXT)
3482  {
3483  ExplainIndentText(es);
3484  appendStringInfo(es->str,
3485  "Hits: " UINT64_FORMAT " Misses: " UINT64_FORMAT " Evictions: " UINT64_FORMAT " Overflows: " UINT64_FORMAT " Memory Usage: " INT64_FORMAT "kB\n",
3486  si->cache_hits, si->cache_misses,
3488  memPeakKb);
3489  }
3490  else
3491  {
3492  ExplainPropertyInteger("Cache Hits", NULL,
3493  si->cache_hits, es);
3494  ExplainPropertyInteger("Cache Misses", NULL,
3495  si->cache_misses, es);
3496  ExplainPropertyInteger("Cache Evictions", NULL,
3497  si->cache_evictions, es);
3498  ExplainPropertyInteger("Cache Overflows", NULL,
3499  si->cache_overflows, es);
3500  ExplainPropertyInteger("Peak Memory Usage", "kB", memPeakKb,
3501  es);
3502  }
3503 
3504  if (es->workers_state)
3505  ExplainCloseWorker(n, es);
3506  }
3507 }
uint64 mem_used
Definition: execnodes.h:2308
SharedMemoizeInfo * shared_info
Definition: execnodes.h:2323
MemoizeInstrumentation stats
Definition: execnodes.h:2322
bool binary_mode
Definition: execnodes.h:2320
MemoizeInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2284

References ExplainState::analyze, appendStringInfo(), appendStringInfoString(), MemoizeState::binary_mode, BYTES_TO_KILOBYTES, MemoizeInstrumentation::cache_evictions, MemoizeInstrumentation::cache_hits, MemoizeInstrumentation::cache_misses, MemoizeInstrumentation::cache_overflows, context, StringInfoData::data, ExplainState::deparse_cxt, deparse_expression(), EXPLAIN_FORMAT_TEXT, ExplainCloseWorker(), ExplainIndentText(), ExplainOpenWorker(), ExplainPropertyInteger(), ExplainPropertyText(), ExplainState::format, initStringInfo(), INT64_FORMAT, lfirst, list_length(), MemoizeInstrumentation::mem_peak, MemoizeState::mem_used, SharedMemoizeInfo::num_workers, pfree(), plan, ExplainState::rtable, set_deparse_context_plan(), MemoizeState::shared_info, SharedMemoizeInfo::sinstrument, MemoizeState::stats, ExplainState::str, UINT64_FORMAT, ExplainState::verbose, and ExplainState::workers_state.

Referenced by ExplainNode().

◆ show_memory_counters()

static void show_memory_counters ( ExplainState es,
const MemoryContextCounters mem_counters 
)
static

Definition at line 4031 of file explain.c.

4032 {
4033  int64 memUsedkB = BYTES_TO_KILOBYTES(mem_counters->totalspace -
4034  mem_counters->freespace);
4035  int64 memAllocatedkB = BYTES_TO_KILOBYTES(mem_counters->totalspace);
4036 
4037  if (es->format == EXPLAIN_FORMAT_TEXT)
4038  {
4039  ExplainIndentText(es);
4040  appendStringInfo(es->str,
4041  "Memory: used=" INT64_FORMAT "kB allocated=" INT64_FORMAT "kB",
4042  memUsedkB, memAllocatedkB);
4043  appendStringInfoChar(es->str, '\n');
4044  }
4045  else
4046  {
4047  ExplainPropertyInteger("Memory Used", "kB", memUsedkB, es);
4048  ExplainPropertyInteger("Memory Allocated", "kB", memAllocatedkB, es);
4049  }
4050 }

References appendStringInfo(), appendStringInfoChar(), BYTES_TO_KILOBYTES, EXPLAIN_FORMAT_TEXT, ExplainIndentText(), ExplainPropertyInteger(), ExplainState::format, MemoryContextCounters::freespace, INT64_FORMAT, ExplainState::str, and MemoryContextCounters::totalspace.

Referenced by ExplainOnePlan().

◆ show_merge_append_keys()

static void show_merge_append_keys ( MergeAppendState mstate,
List ancestors,
ExplainState es 
)
static

Definition at line 2597 of file explain.c.

2599 {
2600  MergeAppend *plan = (MergeAppend *) mstate->ps.plan;
2601 
2602  show_sort_group_keys((PlanState *) mstate, "Sort Key",
2603  plan->numCols, 0, plan->sortColIdx,
2604  plan->sortOperators, plan->collations,
2605  plan->nullsFirst,
2606  ancestors, es);
2607 }
PlanState ps
Definition: execnodes.h:1482

References PlanState::plan, plan, MergeAppendState::ps, and show_sort_group_keys().

Referenced by ExplainNode().

◆ show_modifytable_info()

static void show_modifytable_info ( ModifyTableState mtstate,
List ancestors,
ExplainState es 
)
static

Definition at line 4253 of file explain.c.

4255 {
4256  ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
4257  const char *operation;
4258  const char *foperation;
4259  bool labeltargets;
4260  int j;
4261  List *idxNames = NIL;
4262  ListCell *lst;
4263 
4264  switch (node->operation)
4265  {
4266  case CMD_INSERT:
4267  operation = "Insert";
4268  foperation = "Foreign Insert";
4269  break;
4270  case CMD_UPDATE:
4271  operation = "Update";
4272  foperation = "Foreign Update";
4273  break;
4274  case CMD_DELETE:
4275  operation = "Delete";
4276  foperation = "Foreign Delete";
4277  break;
4278  case CMD_MERGE:
4279  operation = "Merge";
4280  /* XXX unsupported for now, but avoid compiler noise */
4281  foperation = "Foreign Merge";
4282  break;
4283  default:
4284  operation = "???";
4285  foperation = "Foreign ???";
4286  break;
4287  }
4288 
4289  /* Should we explicitly label target relations? */
4290  labeltargets = (mtstate->mt_nrels > 1 ||
4291  (mtstate->mt_nrels == 1 &&
4292  mtstate->resultRelInfo[0].ri_RangeTableIndex != node->nominalRelation));
4293 
4294  if (labeltargets)
4295  ExplainOpenGroup("Target Tables", "Target Tables", false, es);
4296 
4297  for (j = 0; j < mtstate->mt_nrels; j++)
4298  {
4299  ResultRelInfo *resultRelInfo = mtstate->resultRelInfo + j;
4300  FdwRoutine *fdwroutine = resultRelInfo->ri_FdwRoutine;
4301 
4302  if (labeltargets)
4303  {
4304  /* Open a group for this target */
4305  ExplainOpenGroup("Target Table", NULL, true, es);
4306 
4307  /*
4308  * In text mode, decorate each target with operation type, so that
4309  * ExplainTargetRel's output of " on foo" will read nicely.
4310  */
4311  if (es->format == EXPLAIN_FORMAT_TEXT)
4312  {
4313  ExplainIndentText(es);
4315  fdwroutine ? foperation : operation);
4316  }
4317 
4318  /* Identify target */
4319  ExplainTargetRel((Plan *) node,
4320  resultRelInfo->ri_RangeTableIndex,
4321  es);
4322 
4323  if (es->format == EXPLAIN_FORMAT_TEXT)
4324  {
4325  appendStringInfoChar(es->str, '\n');
4326  es->indent++;
4327  }
4328  }
4329 
4330  /* Give FDW a chance if needed */
4331  if (!resultRelInfo->ri_usesFdwDirectModify &&
4332  fdwroutine != NULL &&
4333  fdwroutine->ExplainForeignModify != NULL)
4334  {
4335  List *fdw_private = (List *) list_nth(node->fdwPrivLists, j);
4336 
4337  fdwroutine->ExplainForeignModify(mtstate,
4338  resultRelInfo,
4339  fdw_private,
4340  j,
4341  es);
4342  }
4343 
4344  if (labeltargets)
4345  {
4346  /* Undo the indentation we added in text format */
4347  if (es->format == EXPLAIN_FORMAT_TEXT)
4348  es->indent--;
4349 
4350  /* Close the group */
4351  ExplainCloseGroup("Target Table", NULL, true, es);
4352  }
4353  }
4354 
4355  /* Gather names of ON CONFLICT arbiter indexes */
4356  foreach(lst, node->arbiterIndexes)
4357  {
4358  char *indexname = get_rel_name(lfirst_oid(lst));
4359 
4360  idxNames = lappend(idxNames, indexname);
4361  }
4362 
4363  if (node->onConflictAction != ONCONFLICT_NONE)
4364  {
4365  ExplainPropertyText("Conflict Resolution",
4367  "NOTHING" : "UPDATE",
4368  es);
4369 
4370  /*
4371  * Don't display arbiter indexes at all when DO NOTHING variant
4372  * implicitly ignores all conflicts
4373  */
4374  if (idxNames)
4375  ExplainPropertyList("Conflict Arbiter Indexes", idxNames, es);
4376 
4377  /* ON CONFLICT DO UPDATE WHERE qual is specially displayed */
4378  if (node->onConflictWhere)
4379  {
4380  show_upper_qual((List *) node->onConflictWhere, "Conflict Filter",
4381  &mtstate->ps, ancestors, es);
4382  show_instrumentation_count("Rows Removed by Conflict Filter", 1, &mtstate->ps, es);
4383  }
4384 
4385  /* EXPLAIN ANALYZE display of actual outcome for each tuple proposed */
4386  if (es->analyze && mtstate->ps.instrument)
4387  {
4388  double total;
4389  double insert_path;
4390  double other_path;
4391 
4392  InstrEndLoop(outerPlanState(mtstate)->instrument);
4393 
4394  /* count the number of source rows */
4395  total = outerPlanState(mtstate)->instrument->ntuples;
4396  other_path = mtstate->ps.instrument->ntuples2;
4397  insert_path = total - other_path;
4398 
4399  ExplainPropertyFloat("Tuples Inserted", NULL,
4400  insert_path, 0, es);
4401  ExplainPropertyFloat("Conflicting Tuples", NULL,
4402  other_path, 0, es);
4403  }
4404  }
4405  else if (node->operation == CMD_MERGE)
4406  {
4407  /* EXPLAIN ANALYZE display of tuples processed */
4408  if (es->analyze && mtstate->ps.instrument)
4409  {
4410  double total;
4411  double insert_path;
4412  double update_path;
4413  double delete_path;
4414  double skipped_path;
4415 
4416  InstrEndLoop(outerPlanState(mtstate)->instrument);
4417 
4418  /* count the number of source rows */
4419  total = outerPlanState(mtstate)->instrument->ntuples;
4420  insert_path = mtstate->mt_merge_inserted;
4421  update_path = mtstate->mt_merge_updated;
4422  delete_path = mtstate->mt_merge_deleted;
4423  skipped_path = total - insert_path - update_path - delete_path;
4424  Assert(skipped_path >= 0);
4425 
4426  if (es->format == EXPLAIN_FORMAT_TEXT)
4427  {
4428  if (total > 0)
4429  {
4430  ExplainIndentText(es);
4431  appendStringInfoString(es->str, "Tuples:");
4432  if (insert_path > 0)
4433  appendStringInfo(es->str, " inserted=%.0f", insert_path);
4434  if (update_path > 0)
4435  appendStringInfo(es->str, " updated=%.0f", update_path);
4436  if (delete_path > 0)
4437  appendStringInfo(es->str, " deleted=%.0f", delete_path);
4438  if (skipped_path > 0)
4439  appendStringInfo(es->str, " skipped=%.0f", skipped_path);
4440  appendStringInfoChar(es->str, '\n');
4441  }
4442  }
4443  else
4444  {
4445  ExplainPropertyFloat("Tuples Inserted", NULL, insert_path, 0, es);
4446  ExplainPropertyFloat("Tuples Updated", NULL, update_path, 0, es);
4447  ExplainPropertyFloat("Tuples Deleted", NULL, delete_path, 0, es);
4448  ExplainPropertyFloat("Tuples Skipped", NULL, skipped_path, 0, es);
4449  }
4450  }
4451  }
4452 
4453  if (labeltargets)
4454  ExplainCloseGroup("Target Tables", "Target Tables", false, es);
4455 }
@ ONCONFLICT_NONE
Definition: nodes.h:418
@ ONCONFLICT_NOTHING
Definition: nodes.h:419
#define lfirst_oid(lc)
Definition: pg_list.h:174
ExplainForeignModify_function ExplainForeignModify
Definition: fdwapi.h:253
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1359
double mt_merge_deleted
Definition: execnodes.h:1414
double mt_merge_inserted
Definition: execnodes.h:1412
double mt_merge_updated
Definition: execnodes.h:1413
PlanState ps
Definition: execnodes.h:1354
Index nominalRelation
Definition: plannodes.h:234
List * arbiterIndexes
Definition: plannodes.h:246
CmdType operation
Definition: plannodes.h:232
List * fdwPrivLists
Definition: plannodes.h:241
Node * onConflictWhere
Definition: plannodes.h:249
OnConflictAction onConflictAction
Definition: plannodes.h:245
Index ri_RangeTableIndex
Definition: execnodes.h:453
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:503
bool ri_usesFdwDirectModify
Definition: execnodes.h:509

References ExplainState::analyze, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), ModifyTable::arbiterIndexes, Assert, CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_UPDATE, EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), FdwRoutine::ExplainForeignModify, ExplainIndentText(), ExplainOpenGroup(), ExplainPropertyFloat(), ExplainPropertyList(), ExplainPropertyText(), ExplainTargetRel(), ModifyTable::fdwPrivLists, ExplainState::format, get_rel_name(), ExplainState::indent, InstrEndLoop(), PlanState::instrument, j, lappend(), lfirst_oid, list_nth(), ModifyTableState::mt_merge_deleted, ModifyTableState::mt_merge_inserted, ModifyTableState::mt_merge_updated, ModifyTableState::mt_nrels, NIL, ModifyTable::nominalRelation, Instrumentation::ntuples2, ONCONFLICT_NONE, ONCONFLICT_NOTHING, ModifyTable::onConflictAction, ModifyTable::onConflictWhere, ModifyTable::operation, outerPlanState, PlanState::plan, ModifyTableState::ps, ModifyTableState::resultRelInfo, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_RangeTableIndex, ResultRelInfo::ri_usesFdwDirectModify, show_instrumentation_count(), show_upper_qual(), and ExplainState::str.

Referenced by ExplainNode().

◆ show_plan_tlist()

static void show_plan_tlist ( PlanState planstate,
List ancestors,
ExplainState es 
)
static

Definition at line 2435 of file explain.c.

2436 {
2437  Plan *plan = planstate->plan;
2438  List *context;
2439  List *result = NIL;
2440  bool useprefix;
2441  ListCell *lc;
2442 
2443  /* No work if empty tlist (this occurs eg in bitmap indexscans) */
2444  if (plan->targetlist == NIL)
2445  return;
2446  /* The tlist of an Append isn't real helpful, so suppress it */
2447  if (IsA(plan, Append))
2448  return;
2449  /* Likewise for MergeAppend and RecursiveUnion */
2450  if (IsA(plan, MergeAppend))
2451  return;
2452  if (IsA(plan, RecursiveUnion))
2453  return;
2454 
2455  /*
2456  * Likewise for ForeignScan that executes a direct INSERT/UPDATE/DELETE
2457  *
2458  * Note: the tlist for a ForeignScan that executes a direct INSERT/UPDATE
2459  * might contain subplan output expressions that are confusing in this
2460  * context. The tlist for a ForeignScan that executes a direct UPDATE/
2461  * DELETE always contains "junk" target columns to identify the exact row
2462  * to update or delete, which would be confusing in this context. So, we
2463  * suppress it in all the cases.
2464  */
2465  if (IsA(plan, ForeignScan) &&
2466  ((ForeignScan *) plan)->operation != CMD_SELECT)
2467  return;
2468 
2469  /* Set up deparsing context */
2471  plan,
2472  ancestors);
2473  useprefix = list_length(es->rtable) > 1;
2474 
2475  /* Deparse each result column (we now include resjunk ones) */
2476  foreach(lc, plan->targetlist)
2477  {
2478  TargetEntry *tle = (TargetEntry *) lfirst(lc);
2479 
2480  result = lappend(result,
2481  deparse_expression((Node *) tle->expr, context,
2482  useprefix, false));
2483  }
2484 
2485  /* Print results */
2486  ExplainPropertyList("Output", result, es);
2487 }

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

Referenced by ExplainNode().

◆ show_qual()

static void show_qual ( List qual,
const char *  qlabel,
PlanState planstate,
List ancestors,
bool  useprefix,
ExplainState es 
)
static

Definition at line 2516 of file explain.c.

2519 {
2520  Node *node;
2521 
2522  /* No work if empty qual */
2523  if (qual == NIL)
2524  return;
2525 
2526  /* Convert AND list to explicit AND */
2527  node = (Node *) make_ands_explicit(qual);
2528 
2529  /* And show it */
2530  show_expression(node, qlabel, planstate, ancestors, useprefix, es);
2531 }
Expr * make_ands_explicit(List *andclauses)
Definition: makefuncs.c:726

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

Referenced by show_scan_qual(), and show_upper_qual().

◆ show_scan_qual()

static void show_scan_qual ( List qual,
const char *  qlabel,
PlanState planstate,
List ancestors,
ExplainState es 
)
static

Definition at line 2537 of file explain.c.

2540 {
2541  bool useprefix;
2542 
2543  useprefix = (IsA(planstate->plan, SubqueryScan) || es->verbose);
2544  show_qual(qual, qlabel, planstate, ancestors, useprefix, es);
2545 }
static void show_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
Definition: explain.c:2516

References IsA, PlanState::plan, show_qual(), and ExplainState::verbose.

Referenced by ExplainNode().

◆ show_sort_group_keys()

static void show_sort_group_keys ( PlanState planstate,
const char *  qlabel,
int  nkeys,
int  nPresortedKeys,
AttrNumber keycols,
Oid sortOperators,
Oid collations,
bool nullsFirst,
List ancestors,
ExplainState es 
)
static

Definition at line 2765 of file explain.c.

2769 {
2770  Plan *plan = planstate->plan;
2771  List *context;
2772  List *result = NIL;
2773  List *resultPresorted = NIL;
2774  StringInfoData sortkeybuf;
2775  bool useprefix;
2776  int keyno;
2777 
2778  if (nkeys <= 0)
2779  return;
2780 
2781  initStringInfo(&sortkeybuf);
2782 
2783  /* Set up deparsing context */
2785  plan,
2786  ancestors);
2787  useprefix = (list_length(es->rtable) > 1 || es->verbose);
2788 
2789  for (keyno = 0; keyno < nkeys; keyno++)
2790  {
2791  /* find key expression in tlist */
2792  AttrNumber keyresno = keycols[keyno];
2793  TargetEntry *target = get_tle_by_resno(plan->targetlist,
2794  keyresno);
2795  char *exprstr;
2796 
2797  if (!target)
2798  elog(ERROR, "no tlist entry for key %d", keyresno);
2799  /* Deparse the expression, showing any top-level cast */
2800  exprstr = deparse_expression((Node *) target->expr, context,
2801  useprefix, true);
2802  resetStringInfo(&sortkeybuf);
2803  appendStringInfoString(&sortkeybuf, exprstr);
2804  /* Append sort order information, if relevant */
2805  if (sortOperators != NULL)
2806  show_sortorder_options(&sortkeybuf,
2807  (Node *) target->expr,
2808  sortOperators[keyno],
2809  collations[keyno],
2810  nullsFirst[keyno]);
2811  /* Emit one property-list item per sort key */
2812  result = lappend(result, pstrdup(sortkeybuf.data));
2813  if (keyno < nPresortedKeys)
2814  resultPresorted = lappend(resultPresorted, exprstr);
2815  }
2816 
2817  ExplainPropertyList(qlabel, result, es);
2818  if (nPresortedKeys > 0)
2819  ExplainPropertyList("Presorted Key", resultPresorted, es);
2820 }
static void show_sortorder_options(StringInfo buf, Node *sortexpr, Oid sortOperator, Oid collation, bool nullsFirst)
Definition: explain.c:2827
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:78

References appendStringInfoString(), context, StringInfoData::data, ExplainState::deparse_cxt, deparse_expression(), elog, ERROR, ExplainPropertyList(), TargetEntry::expr, get_tle_by_resno(), initStringInfo(), lappend(), list_length(), NIL, PlanState::plan, plan, pstrdup(), resetStringInfo(), ExplainState::rtable, set_deparse_context_plan(), show_sortorder_options(), and ExplainState::verbose.

Referenced by show_agg_keys(), show_group_keys(), show_grouping_set_keys(), show_incremental_sort_keys(), show_merge_append_keys(), and show_sort_keys().

◆ show_sort_info()

static void show_sort_info ( SortState sortstate,
ExplainState es 
)
static

Definition at line 2951 of file explain.c.

2952 {
2953  if (!es->analyze)
2954  return;
2955 
2956  if (sortstate->sort_Done && sortstate->tuplesortstate != NULL)
2957  {
2960  const char *sortMethod;
2961  const char *spaceType;
2962  int64 spaceUsed;
2963 
2964  tuplesort_get_stats(state, &stats);
2965  sortMethod = tuplesort_method_name(stats.sortMethod);
2966  spaceType = tuplesort_space_type_name(stats.spaceType);
2967  spaceUsed = stats.spaceUsed;
2968 
2969  if (es->format == EXPLAIN_FORMAT_TEXT)
2970  {
2971  ExplainIndentText(es);
2972  appendStringInfo(es->str, "Sort Method: %s %s: " INT64_FORMAT "kB\n",
2973  sortMethod, spaceType, spaceUsed);
2974  }
2975  else
2976  {
2977  ExplainPropertyText("Sort Method", sortMethod, es);
2978  ExplainPropertyInteger("Sort Space Used", "kB", spaceUsed, es);
2979  ExplainPropertyText("Sort Space Type", spaceType, es);
2980  }
2981  }
2982 
2983  /*
2984  * You might think we should just skip this stanza entirely when
2985  * es->hide_workers is true, but then we'd get no sort-method output at
2986  * all. We have to make it look like worker 0's data is top-level data.
2987  * This is easily done by just skipping the OpenWorker/CloseWorker calls.
2988  * Currently, we don't worry about the possibility that there are multiple
2989  * workers in such a case; if there are, duplicate output fields will be
2990  * emitted.
2991  */
2992  if (sortstate->shared_info != NULL)
2993  {
2994  int n;
2995 
2996  for (n = 0; n < sortstate->shared_info->num_workers; n++)
2997  {
2998  TuplesortInstrumentation *sinstrument;
2999  const char *sortMethod;
3000  const char *spaceType;
3001  int64 spaceUsed;
3002 
3003  sinstrument = &sortstate->shared_info->sinstrument[n];
3004  if (sinstrument->sortMethod == SORT_TYPE_STILL_IN_PROGRESS)
3005  continue; /* ignore any unfilled slots */
3006  sortMethod = tuplesort_method_name(sinstrument->sortMethod);
3007  spaceType = tuplesort_space_type_name(sinstrument->spaceType);
3008  spaceUsed = sinstrument->spaceUsed;
3009 
3010  if (es->workers_state)
3011  ExplainOpenWorker(n, es);
3012 
3013  if (es->format == EXPLAIN_FORMAT_TEXT)
3014  {
3015  ExplainIndentText(es);
3016  appendStringInfo(es->str,
3017  "Sort Method: %s %s: " INT64_FORMAT "kB\n",
3018  sortMethod, spaceType, spaceUsed);
3019  }
3020  else
3021  {
3022  ExplainPropertyText("Sort Method", sortMethod, es);
3023  ExplainPropertyInteger("Sort Space Used", "kB", spaceUsed, es);
3024  ExplainPropertyText("Sort Space Type", spaceType, es);
3025  }
3026 
3027  if (es->workers_state)
3028  ExplainCloseWorker(n, es);
3029  }
3030  }
3031 }
TuplesortInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2349
bool sort_Done
Definition: execnodes.h:2362
void * tuplesortstate
Definition: execnodes.h:2365
SharedSortInfo * shared_info
Definition: execnodes.h:2368
TuplesortMethod sortMethod
Definition: tuplesort.h:112
TuplesortSpaceType spaceType
Definition: tuplesort.h:113
Definition: regguts.h:323
void tuplesort_get_stats(Tuplesortstate *state, TuplesortInstrumentation *stats)
Definition: tuplesort.c:2538
@ SORT_TYPE_STILL_IN_PROGRESS
Definition: tuplesort.h:77

References ExplainState::analyze, appendStringInfo(), EXPLAIN_FORMAT_TEXT, ExplainCloseWorker(), ExplainIndentText(), ExplainOpenWorker(), ExplainPropertyInteger(), ExplainPropertyText(), ExplainState::format, INT64_FORMAT, SharedSortInfo::num_workers, SortState::shared_info, SharedSortInfo::sinstrument, SortState::sort_Done, SORT_TYPE_STILL_IN_PROGRESS, TuplesortInstrumentation::sortMethod, TuplesortInstrumentation::spaceType, TuplesortInstrumentation::spaceUsed, ExplainState::str, tuplesort_get_stats(), tuplesort_method_name(), tuplesort_space_type_name(), SortState::tuplesortstate, and ExplainState::workers_state.

Referenced by ExplainNode().

◆ show_sort_keys()

static void show_sort_keys ( SortState sortstate,
List ancestors,
ExplainState es 
)
static

Definition at line 2565 of file explain.c.

2566 {
2567  Sort *plan = (Sort *) sortstate->ss.ps.plan;
2568 
2569  show_sort_group_keys((PlanState *) sortstate, "Sort Key",
2570  plan->numCols, 0, plan->sortColIdx,
2571  plan->sortOperators, plan->collations,
2572  plan->nullsFirst,
2573  ancestors, es);
2574 }
ScanState ss
Definition: execnodes.h:2358

References PlanState::plan, plan, ScanState::ps, show_sort_group_keys(), and SortState::ss.

Referenced by ExplainNode().

◆ show_sortorder_options()

static void show_sortorder_options ( StringInfo  buf,
Node sortexpr,
Oid  sortOperator,
Oid  collation,
bool  nullsFirst 
)
static

Definition at line 2827 of file explain.c.

2829 {
2830  Oid sortcoltype = exprType(sortexpr);
2831  bool reverse = false;
2832  TypeCacheEntry *typentry;
2833 
2834  typentry = lookup_type_cache(sortcoltype,
2836 
2837  /*
2838  * Print COLLATE if it's not default for the column's type. There are
2839  * some cases where this is redundant, eg if expression is a column whose
2840  * declared collation is that collation, but it's hard to distinguish that
2841  * here (and arguably, printing COLLATE explicitly is a good idea anyway
2842  * in such cases).
2843  */
2844  if (OidIsValid(collation) && collation != get_typcollation(sortcoltype))
2845  {
2846  char *collname = get_collation_name(collation);
2847 
2848  if (collname == NULL)
2849  elog(ERROR, "cache lookup failed for collation %u", collation);
2850  appendStringInfo(buf, " COLLATE %s", quote_identifier(collname));
2851  }
2852 
2853  /* Print direction if not ASC, or USING if non-default sort operator */
2854  if (sortOperator == typentry->gt_opr)
2855  {
2856  appendStringInfoString(buf, " DESC");
2857  reverse = true;
2858  }
2859  else if (sortOperator != typentry->lt_opr)
2860  {
2861  char *opname = get_opname(sortOperator);
2862 
2863  if (opname == NULL)
2864  elog(ERROR, "cache lookup failed for operator %u", sortOperator);
2865  appendStringInfo(buf, " USING %s", opname);
2866  /* Determine whether operator would be considered ASC or DESC */
2867  (void) get_equality_op_for_ordering_op(sortOperator, &reverse);
2868  }
2869 
2870  /* Add NULLS FIRST/LAST only if it wouldn't be default */
2871  if (nullsFirst && !reverse)
2872  {
2873  appendStringInfoString(buf, " NULLS FIRST");
2874  }
2875  else if (!nullsFirst && reverse)
2876  {
2877  appendStringInfoString(buf, " NULLS LAST");
2878  }
2879 }
char * get_opname(Oid opno)
Definition: lsyscache.c:1310
Oid get_equality_op_for_ordering_op(Oid opno, bool *reverse)
Definition: lsyscache.c:267
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3056
char * get_collation_name(Oid colloid)
Definition: lsyscache.c:1035
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:346
#define TYPECACHE_GT_OPR
Definition: typcache.h:139
#define TYPECACHE_LT_OPR
Definition: typcache.h:138

References appendStringInfo(), appendStringInfoString(), buf, elog, ERROR, exprType(), get_collation_name(), get_equality_op_for_ordering_op(), get_opname(), get_typcollation(), TypeCacheEntry::gt_opr, lookup_type_cache(), TypeCacheEntry::lt_opr, OidIsValid, quote_identifier(), TYPECACHE_GT_OPR, and TYPECACHE_LT_OPR.

Referenced by show_sort_group_keys().

◆ show_tablesample()

static void show_tablesample ( TableSampleClause tsc,
PlanState planstate,
List ancestors,
ExplainState es 
)
static

Definition at line 2885 of file explain.c.

2887 {
2888  List *context;
2889  bool useprefix;
2890  char *method_name;
2891  List *params = NIL;
2892  char *repeatable;
2893  ListCell *lc;
2894 
2895  /* Set up deparsing context */
2897  planstate->plan,
2898  ancestors);
2899  useprefix = list_length(es->rtable) > 1;
2900 
2901  /* Get the tablesample method name */
2902  method_name = get_func_name(tsc->tsmhandler);
2903 
2904  /* Deparse parameter expressions */
2905  foreach(lc, tsc->args)
2906  {
2907  Node *arg = (Node *) lfirst(lc);
2908 
2909  params = lappend(params,
2911  useprefix, false));
2912  }
2913  if (tsc->repeatable)
2914  repeatable = deparse_expression((Node *) tsc->repeatable, context,
2915  useprefix, false);
2916  else
2917  repeatable = NULL;
2918 
2919  /* Print results */
2920  if (es->format == EXPLAIN_FORMAT_TEXT)
2921  {
2922  bool first = true;
2923 
2924  ExplainIndentText(es);
2925  appendStringInfo(es->str, "Sampling: %s (", method_name);
2926  foreach(lc, params)
2927  {
2928  if (!first)
2929  appendStringInfoString(es->str, ", ");
2930  appendStringInfoString(es->str, (const char *) lfirst(lc));
2931  first = false;
2932  }
2933  appendStringInfoChar(es->str, ')');
2934  if (repeatable)
2935  appendStringInfo(es->str, " REPEATABLE (%s)", repeatable);
2936  appendStringInfoChar(es->str, '\n');
2937  }
2938  else
2939  {
2940  ExplainPropertyText("Sampling Method", method_name, es);
2941  ExplainPropertyList("Sampling Parameters", params, es);
2942  if (repeatable)
2943  ExplainPropertyText("Repeatable Seed", repeatable, es);
2944  }
2945 }
void * arg

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), arg, TableSampleClause::args, context, ExplainState::deparse_cxt, deparse_expression(), EXPLAIN_FORMAT_TEXT, ExplainIndentText(), ExplainPropertyList(), ExplainPropertyText(), ExplainState::format, get_func_name(), lappend(), lfirst, list_length(), NIL, PlanState::plan, TableSampleClause::repeatable, ExplainState::rtable, set_deparse_context_plan(), ExplainState::str, and TableSampleClause::tsmhandler.

Referenced by ExplainNode().

◆ show_tidbitmap_info()

static void show_tidbitmap_info ( BitmapHeapScanState planstate,
ExplainState es 
)
static

Definition at line 3634 of file explain.c.

3635 {
3636  if (!es->analyze)
3637  return;
3638 
3639  if (es->format != EXPLAIN_FORMAT_TEXT)
3640  {
3641  ExplainPropertyUInteger("Exact Heap Blocks", NULL,
3642  planstate->stats.exact_pages, es);
3643  ExplainPropertyUInteger("Lossy Heap Blocks", NULL,
3644  planstate->stats.lossy_pages, es);
3645  }
3646  else
3647  {
3648  if (planstate->stats.exact_pages > 0 || planstate->stats.lossy_pages > 0)
3649  {
3650  ExplainIndentText(es);
3651  appendStringInfoString(es->str, "Heap Blocks:");
3652  if (planstate->stats.exact_pages > 0)
3653  appendStringInfo(es->str, " exact=" UINT64_FORMAT, planstate->stats.exact_pages);
3654  if (planstate->stats.lossy_pages > 0)
3655  appendStringInfo(es->str, " lossy=" UINT64_FORMAT, planstate->stats.lossy_pages);
3656  appendStringInfoChar(es->str, '\n');
3657  }
3658  }
3659 
3660  /* Display stats for each parallel worker */
3661  if (planstate->pstate != NULL)
3662  {
3663  for (int n = 0; n < planstate->sinstrument->num_workers; n++)
3664  {
3666 
3667  if (si->exact_pages == 0 && si->lossy_pages == 0)
3668  continue;
3669 
3670  if (es->workers_state)
3671  ExplainOpenWorker(n, es);
3672 
3673  if (es->format == EXPLAIN_FORMAT_TEXT)
3674  {
3675  ExplainIndentText(es);
3676  appendStringInfoString(es->str, "Heap Blocks:");
3677  if (si->exact_pages > 0)
3678  appendStringInfo(es->str, " exact=" UINT64_FORMAT, si->exact_pages);
3679  if (si->lossy_pages > 0)
3680  appendStringInfo(es->str, " lossy=" UINT64_FORMAT, si->lossy_pages);
3681  appendStringInfoChar(es->str, '\n');
3682  }
3683  else
3684  {
3685  ExplainPropertyUInteger("Exact Heap Blocks", NULL,
3686  si->exact_pages, es);
3687  ExplainPropertyUInteger("Lossy Heap Blocks", NULL,
3688  si->lossy_pages, es);
3689  }
3690 
3691  if (es->workers_state)
3692  ExplainCloseWorker(n, es);
3693  }
3694  }
3695 }
ParallelBitmapHeapState * pstate
Definition: execnodes.h:1855
BitmapHeapScanInstrumentation stats
Definition: execnodes.h:1847
SharedBitmapHeapInstrumentation * sinstrument
Definition: execnodes.h:1856
BitmapHeapScanInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:1816

References ExplainState::analyze, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), BitmapHeapScanInstrumentation::exact_pages, EXPLAIN_FORMAT_TEXT, ExplainCloseWorker(), ExplainIndentText(), ExplainOpenWorker(), ExplainPropertyUInteger(), ExplainState::format, BitmapHeapScanInstrumentation::lossy_pages, SharedBitmapHeapInstrumentation::num_workers, BitmapHeapScanState::pstate, SharedBitmapHeapInstrumentation::sinstrument, BitmapHeapScanState::sinstrument, BitmapHeapScanState::stats, ExplainState::str, UINT64_FORMAT, and ExplainState::workers_state.

Referenced by ExplainNode().

◆ show_upper_qual()

static void show_upper_qual ( List qual,
const char *  qlabel,
PlanState planstate,
List ancestors,
ExplainState es 
)
static

Definition at line 2551 of file explain.c.

2554 {
2555  bool useprefix;
2556 
2557  useprefix = (list_length(es->rtable) > 1 || es->verbose);
2558  show_qual(qual, qlabel, planstate, ancestors, useprefix, es);
2559 }

References list_length(), ExplainState::rtable, show_qual(), and ExplainState::verbose.

Referenced by ExplainNode(), and show_modifytable_info().

◆ show_wal_usage()

static void show_wal_usage ( ExplainState es,
const WalUsage usage 
)
static

Definition at line 3993 of file explain.c.

3994 {
3995  if (es->format == EXPLAIN_FORMAT_TEXT)
3996  {
3997  /* Show only positive counter values. */
3998  if ((usage->wal_records > 0) || (usage->wal_fpi > 0) ||
3999  (usage->wal_bytes > 0))
4000  {
4001  ExplainIndentText(es);
4002  appendStringInfoString(es->str, "WAL:");
4003 
4004  if (usage->wal_records > 0)
4005  appendStringInfo(es->str, " records=%lld",
4006  (long long) usage->wal_records);
4007  if (usage->wal_fpi > 0)
4008  appendStringInfo(es->str, " fpi=%lld",
4009  (long long) usage->wal_fpi);
4010  if (usage->wal_bytes > 0)
4011  appendStringInfo(es->str, " bytes=" UINT64_FORMAT,
4012  usage->wal_bytes);
4013  appendStringInfoChar(es->str, '\n');
4014  }
4015  }
4016  else
4017  {
4018  ExplainPropertyInteger("WAL Records", NULL,
4019  usage->wal_records, es);
4020  ExplainPropertyInteger("WAL FPI", NULL,
4021  usage->wal_fpi, es);
4022  ExplainPropertyUInteger("WAL Bytes", NULL,
4023  usage->wal_bytes, es);
4024  }
4025 }

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), EXPLAIN_FORMAT_TEXT, ExplainIndentText(), ExplainPropertyInteger(), ExplainPropertyUInteger(), ExplainState::format, ExplainState::str, UINT64_FORMAT, and usage().

Referenced by ExplainNode().

◆ standard_ExplainOneQuery()

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

Definition at line 456 of file explain.c.

460 {
461  PlannedStmt *plan;
462  instr_time planstart,
463  planduration;
464  BufferUsage bufusage_start,
465  bufusage;
466  MemoryContextCounters mem_counters;
467  MemoryContext planner_ctx = NULL;
468  MemoryContext saved_ctx = NULL;
469 
470  if (es->memory)
471  {
472  /*
473  * Create a new memory context to measure planner's memory consumption
474  * accurately. Note that if the planner were to be modified to use a
475  * different memory context type, here we would be changing that to
476  * AllocSet, which might be undesirable. However, we don't have a way
477  * to create a context of the same type as another, so we pray and
478  * hope that this is OK.
479  */
481  "explain analyze planner context",
483  saved_ctx = MemoryContextSwitchTo(planner_ctx);
484  }
485 
486  if (es->buffers)
487  bufusage_start = pgBufferUsage;
488  INSTR_TIME_SET_CURRENT(planstart);
489 
490  /* plan the query */
491  plan = pg_plan_query(query, queryString, cursorOptions, params);
492 
493  INSTR_TIME_SET_CURRENT(planduration);
494  INSTR_TIME_SUBTRACT(planduration, planstart);
495 
496  if (es->memory)
497  {
498  MemoryContextSwitchTo(saved_ctx);
499  MemoryContextMemConsumed(planner_ctx, &mem_counters);
500  }
501 
502  /* calc differences of buffer counters. */
503  if (es->buffers)
504  {
505  memset(&bufusage, 0, sizeof(BufferUsage));
506  BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
507  }
508 
509  /* run it (if needed) and produce output */
510  ExplainOnePlan(plan, into, es, queryString, params, queryEnv,
511  &planduration, (es->buffers ? &bufusage : NULL),
512  es->memory ? &mem_counters : NULL);
513 }
void ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv, const instr_time *planduration, const BufferUsage *bufusage, const MemoryContextCounters *mem_counters)
Definition: explain.c:618
void MemoryContextMemConsumed(MemoryContext context, MemoryContextCounters *consumed)
Definition: mcxt.c:786
PlannedStmt * pg_plan_query(Query *querytree, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:886

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, ExplainState::buffers, BufferUsageAccumDiff(), CurrentMemoryContext, ExplainOnePlan(), INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, ExplainState::memory, MemoryContextMemConsumed(), MemoryContextSwitchTo(), pg_plan_query(), pgBufferUsage, and plan.

Referenced by ExplainOneQuery().

Variable Documentation

◆ explain_get_index_name_hook

explain_get_index_name_hook_type explain_get_index_name_hook = NULL

Definition at line 49 of file explain.c.

Referenced by explain_get_index_name().

◆ ExplainOneQuery_hook

ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL

Definition at line 46 of file explain.c.

Referenced by ExplainOneQuery().