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, ParseState *pstate, ParamListInfo params)
 
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_storage_info (char *maxStorageType, int64 maxSpaceUsed, ExplainState *es)
 
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_windowagg_info (WindowAggState *winstate, ExplainState *es)
 
static void show_ctescan_info (CteScanState *ctescanstate, ExplainState *es)
 
static void show_table_func_scan_info (TableFuncScanState *tscanstate, ExplainState *es)
 
static void show_recursive_union_info (RecursiveUnionState *rstate, 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, ParseState *pstate, ParamListInfo params)
 
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 bool plan_is_disabled (Plan *plan)
 
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 5876 of file explain.c.

5877 {
5878  SerializeDestReceiver *self;
5879 
5881 
5882  self->pub.receiveSlot = serializeAnalyzeReceive;
5883  self->pub.rStartup = serializeAnalyzeStartup;
5884  self->pub.rShutdown = serializeAnalyzeShutdown;
5885  self->pub.rDestroy = serializeAnalyzeDestroy;
5886  self->pub.mydest = DestExplainSerialize;
5887 
5888  self->es = es;
5889 
5890  return (DestReceiver *) self;
5891 }
@ DestExplainSerialize
Definition: dest.h:99
static void serializeAnalyzeStartup(DestReceiver *self, int operation, TupleDesc typeinfo)
Definition: explain.c:5810
static void serializeAnalyzeDestroy(DestReceiver *self)
Definition: explain.c:5867
static bool serializeAnalyzeReceive(TupleTableSlot *slot, DestReceiver *self)
Definition: explain.c:5707
static void serializeAnalyzeShutdown(DestReceiver *self)
Definition: explain.c:5846
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 1305 of file explain.c.

1306 {
1307  instr_time endtime;
1308 
1309  INSTR_TIME_SET_CURRENT(endtime);
1310  INSTR_TIME_SUBTRACT(endtime, *starttime);
1311  return INSTR_TIME_GET_DOUBLE(endtime);
1312 }
#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 5619 of file explain.c.

5620 {
5621  escape_json(buf, str);
5622 }
const char * str
void escape_json(StringInfo buf, const char *str)
Definition: json.c:1602
static char * buf
Definition: pg_test_fsync.c:72

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 3999 of file explain.c.

4000 {
4001  const char *result;
4002 
4004  result = (*explain_get_index_name_hook) (indexId);
4005  else
4006  result = NULL;
4007  if (result == NULL)
4008  {
4009  /* default behavior: look it up in the catalogs */
4010  result = get_rel_name(indexId);
4011  if (result == NULL)
4012  elog(ERROR, "cache lookup failed for index %u", indexId);
4013  }
4014  return result;
4015 }
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
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 5443 of file explain.c.

5444 {
5445  switch (es->format)
5446  {
5447  case EXPLAIN_FORMAT_TEXT:
5448  /* nothing to do */
5449  break;
5450 
5451  case EXPLAIN_FORMAT_XML:
5453  "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
5454  es->indent++;
5455  break;
5456 
5457  case EXPLAIN_FORMAT_JSON:
5458  /* top-level structure is an array of plans */
5459  appendStringInfoChar(es->str, '[');
5460  es->grouping_stack = lcons_int(0, es->grouping_stack);
5461  es->indent++;
5462  break;
5463 
5464  case EXPLAIN_FORMAT_YAML:
5465  es->grouping_stack = lcons_int(0, es->grouping_stack);
5466  break;
5467  }
5468 }
@ 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:179
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:191
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 5250 of file explain.c.

5252 {
5253  switch (es->format)
5254  {
5255  case EXPLAIN_FORMAT_TEXT:
5256  /* nothing to do */
5257  break;
5258 
5259  case EXPLAIN_FORMAT_XML:
5260  es->indent--;
5261  ExplainXMLTag(objtype, X_CLOSING, es);
5262  break;
5263 
5264  case EXPLAIN_FORMAT_JSON:
5265  es->indent--;
5266  appendStringInfoChar(es->str, '\n');
5267  appendStringInfoSpaces(es->str, 2 * es->indent);
5268  appendStringInfoChar(es->str, labeled ? '}' : ']');
5270  break;
5271 
5272  case EXPLAIN_FORMAT_YAML:
5273  es->indent--;
5275  break;
5276  }
5277 }
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:5532
#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:209

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 4880 of file explain.c.

4881 {
4882  ExplainWorkersState *wstate = es->workers_state;
4883 
4884  Assert(wstate);
4885  Assert(n >= 0 && n < wstate->num_workers);
4886  Assert(wstate->worker_inited[n]);
4887 
4888  /*
4889  * Save formatting state in case we do another ExplainOpenWorker(), then
4890  * pop the formatting stack.
4891  */
4892  ExplainSaveGroup(es, 2, &wstate->worker_state_save[n]);
4893 
4894  /*
4895  * In TEXT format, if we didn't actually produce any output line(s) then
4896  * truncate off the partial line emitted by ExplainOpenWorker. (This is
4897  * to avoid bogus output if, say, show_buffer_usage chooses not to print
4898  * anything for the worker.) Also fix up the indent level.
4899  */
4900  if (es->format == EXPLAIN_FORMAT_TEXT)
4901  {
4902  while (es->str->len > 0 && es->str->data[es->str->len - 1] != '\n')
4903  es->str->data[--(es->str->len)] = '\0';
4904 
4905  es->indent--;
4906  }
4907 
4908  /* Restore prior output buffer pointer */
4909  es->str = wstate->prev_str;
4910 }
#define Assert(condition)
Definition: c.h:849
static void ExplainSaveGroup(ExplainState *es, int depth, int *state_save)
Definition: explain.c:5336
ExplainWorkersState * workers_state
Definition: explain.h:73
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 4801 of file explain.c.

4802 {
4803  ExplainWorkersState *wstate;
4804 
4805  wstate = (ExplainWorkersState *) palloc(sizeof(ExplainWorkersState));
4806  wstate->num_workers = num_workers;
4807  wstate->worker_inited = (bool *) palloc0(num_workers * sizeof(bool));
4808  wstate->worker_str = (StringInfoData *)
4809  palloc0(num_workers * sizeof(StringInfoData));
4810  wstate->worker_state_save = (int *) palloc(num_workers * sizeof(int));
4811  return wstate;
4812 }
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 4779 of file explain.c.

4780 {
4781  ListCell *cell;
4782  const char *label =
4783  (list_length(css->custom_ps) != 1 ? "children" : "child");
4784 
4785  foreach(cell, css->custom_ps)
4786  ExplainNode((PlanState *) lfirst(cell), ancestors, label, NULL, es);
4787 }
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1489
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:2104

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 5397 of file explain.c.

5398 {
5399  switch (es->format)
5400  {
5401  case EXPLAIN_FORMAT_TEXT:
5402  /* nothing to do */
5403  break;
5404 
5405  case EXPLAIN_FORMAT_XML:
5406  ExplainXMLTag(objtype, X_CLOSE_IMMEDIATE, es);
5407  break;
5408 
5409  case EXPLAIN_FORMAT_JSON:
5411  appendStringInfoSpaces(es->str, 2 * es->indent);
5412  if (labelname)
5413  {
5414  escape_json(es->str, labelname);
5415  appendStringInfoString(es->str, ": ");
5416  }
5417  escape_json(es->str, objtype);
5418  break;
5419 
5420  case EXPLAIN_FORMAT_YAML:
5422  if (labelname)
5423  {
5424  escape_yaml(es->str, labelname);
5425  appendStringInfoString(es->str, ": ");
5426  }
5427  else
5428  {
5429  appendStringInfoString(es->str, "- ");
5430  }
5431  escape_yaml(es->str, objtype);
5432  break;
5433  }
5434 }
#define X_CLOSE_IMMEDIATE
Definition: explain.c:63
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:5594
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:5574
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:5619

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 5474 of file explain.c.

5475 {
5476  switch (es->format)
5477  {
5478  case EXPLAIN_FORMAT_TEXT:
5479  /* nothing to do */
5480  break;
5481 
5482  case EXPLAIN_FORMAT_XML:
5483  es->indent--;
5484  appendStringInfoString(es->str, "</explain>");
5485  break;
5486 
5487  case EXPLAIN_FORMAT_JSON:
5488  es->indent--;
5489  appendStringInfoString(es->str, "\n]");
5491  break;
5492 
5493  case EXPLAIN_FORMAT_YAML:
5495  break;
5496  }
5497 }

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 4916 of file explain.c.

4917 {
4918  ExplainWorkersState *wstate = es->workers_state;
4919 
4920  ExplainOpenGroup("Workers", "Workers", false, es);
4921  for (int i = 0; i < wstate->num_workers; i++)
4922  {
4923  if (wstate->worker_inited[i])
4924  {
4925  /* This must match previous ExplainOpenSetAsideGroup call */
4926  ExplainOpenGroup("Worker", NULL, true, es);
4927  appendStringInfoString(es->str, wstate->worker_str[i].data);
4928  ExplainCloseGroup("Worker", NULL, true, es);
4929 
4930  pfree(wstate->worker_str[i].data);
4931  }
4932  }
4933  ExplainCloseGroup("Workers", "Workers", false, es);
4934 
4935  pfree(wstate->worker_inited);
4936  pfree(wstate->worker_str);
4937  pfree(wstate->worker_state_save);
4938  pfree(wstate);
4939 }
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:5187
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:5250
int i
Definition: isn.c:72
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 4296 of file explain.c.

4298 {
4299  const char *indexname = explain_get_index_name(indexid);
4300 
4301  if (es->format == EXPLAIN_FORMAT_TEXT)
4302  {
4303  if (ScanDirectionIsBackward(indexorderdir))
4304  appendStringInfoString(es->str, " Backward");
4305  appendStringInfo(es->str, " using %s", quote_identifier(indexname));
4306  }
4307  else
4308  {
4309  const char *scandir;
4310 
4311  switch (indexorderdir)
4312  {
4313  case BackwardScanDirection:
4314  scandir = "Backward";
4315  break;
4316  case ForwardScanDirection:
4317  scandir = "Forward";
4318  break;
4319  default:
4320  scandir = "???";
4321  break;
4322  }
4323  ExplainPropertyText("Scan Direction", scandir, es);
4324  ExplainPropertyText("Index Name", indexname, es);
4325  }
4326 }
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:5122
static const char * explain_get_index_name(Oid indexId)
Definition: explain.c:3999
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:12840
#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:94

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 4704 of file explain.c.

4706 {
4707  int j;
4708 
4709  for (j = 0; j < nplans; j++)
4710  ExplainNode(planstates[j], ancestors,
4711  "Member", NULL, es);
4712 }
int j
Definition: isn.c:73

References ExplainNode(), and j.

Referenced by ExplainNode().

◆ ExplainMissingMembers()

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

Definition at line 4722 of file explain.c.

4723 {
4724  if (nplans < nchildren || es->format != EXPLAIN_FORMAT_TEXT)
4725  ExplainPropertyInteger("Subplans Removed", NULL,
4726  nchildren - nplans, es);
4727 }
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:5131
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 4345 of file explain.c.

4346 {
4347  ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
4348 }
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:4354
#define plan(x)
Definition: pg_regress.c:161

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 1489 of file explain.c.

1492 {
1493  Plan *plan = planstate->plan;
1494  const char *pname; /* node type name for text output */
1495  const char *sname; /* node type name for non-text output */
1496  const char *strategy = NULL;
1497  const char *partialmode = NULL;
1498  const char *operation = NULL;
1499  const char *custom_name = NULL;
1500  ExplainWorkersState *save_workers_state = es->workers_state;
1501  int save_indent = es->indent;
1502  bool haschildren;
1503  bool isdisabled;
1504 
1505  /*
1506  * Prepare per-worker output buffers, if needed. We'll append the data in
1507  * these to the main output string further down.
1508  */
1509  if (planstate->worker_instrument && es->analyze && !es->hide_workers)
1511  else
1512  es->workers_state = NULL;
1513 
1514  /* Identify plan node type, and print generic details */
1515  switch (nodeTag(plan))
1516  {
1517  case T_Result:
1518  pname = sname = "Result";
1519  break;
1520  case T_ProjectSet:
1521  pname = sname = "ProjectSet";
1522  break;
1523  case T_ModifyTable:
1524  sname = "ModifyTable";
1525  switch (((ModifyTable *) plan)->operation)
1526  {
1527  case CMD_INSERT:
1528  pname = operation = "Insert";
1529  break;
1530  case CMD_UPDATE:
1531  pname = operation = "Update";
1532  break;
1533  case CMD_DELETE:
1534  pname = operation = "Delete";
1535  break;
1536  case CMD_MERGE:
1537  pname = operation = "Merge";
1538  break;
1539  default:
1540  pname = "???";
1541  break;
1542  }
1543  break;
1544  case T_Append:
1545  pname = sname = "Append";
1546  break;
1547  case T_MergeAppend:
1548  pname = sname = "Merge Append";
1549  break;
1550  case T_RecursiveUnion:
1551  pname = sname = "Recursive Union";
1552  break;
1553  case T_BitmapAnd:
1554  pname = sname = "BitmapAnd";
1555  break;
1556  case T_BitmapOr:
1557  pname = sname = "BitmapOr";
1558  break;
1559  case T_NestLoop:
1560  pname = sname = "Nested Loop";
1561  break;
1562  case T_MergeJoin:
1563  pname = "Merge"; /* "Join" gets added by jointype switch */
1564  sname = "Merge Join";
1565  break;
1566  case T_HashJoin:
1567  pname = "Hash"; /* "Join" gets added by jointype switch */
1568  sname = "Hash Join";
1569  break;
1570  case T_SeqScan:
1571  pname = sname = "Seq Scan";
1572  break;
1573  case T_SampleScan:
1574  pname = sname = "Sample Scan";
1575  break;
1576  case T_Gather:
1577  pname = sname = "Gather";
1578  break;
1579  case T_GatherMerge:
1580  pname = sname = "Gather Merge";
1581  break;
1582  case T_IndexScan:
1583  pname = sname = "Index Scan";
1584  break;
1585  case T_IndexOnlyScan:
1586  pname = sname = "Index Only Scan";
1587  break;
1588  case T_BitmapIndexScan:
1589  pname = sname = "Bitmap Index Scan";
1590  break;
1591  case T_BitmapHeapScan:
1592  pname = sname = "Bitmap Heap Scan";
1593  break;
1594  case T_TidScan:
1595  pname = sname = "Tid Scan";
1596  break;
1597  case T_TidRangeScan:
1598  pname = sname = "Tid Range Scan";
1599  break;
1600  case T_SubqueryScan:
1601  pname = sname = "Subquery Scan";
1602  break;
1603  case T_FunctionScan:
1604  pname = sname = "Function Scan";
1605  break;
1606  case T_TableFuncScan:
1607  pname = sname = "Table Function Scan";
1608  break;
1609  case T_ValuesScan:
1610  pname = sname = "Values Scan";
1611  break;
1612  case T_CteScan:
1613  pname = sname = "CTE Scan";
1614  break;
1615  case T_NamedTuplestoreScan:
1616  pname = sname = "Named Tuplestore Scan";
1617  break;
1618  case T_WorkTableScan:
1619  pname = sname = "WorkTable Scan";
1620  break;
1621  case T_ForeignScan:
1622  sname = "Foreign Scan";
1623  switch (((ForeignScan *) plan)->operation)
1624  {
1625  case CMD_SELECT:
1626  pname = "Foreign Scan";
1627  operation = "Select";
1628  break;
1629  case CMD_INSERT:
1630  pname = "Foreign Insert";
1631  operation = "Insert";
1632  break;
1633  case CMD_UPDATE:
1634  pname = "Foreign Update";
1635  operation = "Update";
1636  break;
1637  case CMD_DELETE:
1638  pname = "Foreign Delete";
1639  operation = "Delete";
1640  break;
1641  default:
1642  pname = "???";
1643  break;
1644  }
1645  break;
1646  case T_CustomScan:
1647  sname = "Custom Scan";
1648  custom_name = ((CustomScan *) plan)->methods->CustomName;
1649  if (custom_name)
1650  pname = psprintf("Custom Scan (%s)", custom_name);
1651  else
1652  pname = sname;
1653  break;
1654  case T_Material:
1655  pname = sname = "Materialize";
1656  break;
1657  case T_Memoize:
1658  pname = sname = "Memoize";
1659  break;
1660  case T_Sort:
1661  pname = sname = "Sort";
1662  break;
1663  case T_IncrementalSort:
1664  pname = sname = "Incremental Sort";
1665  break;
1666  case T_Group:
1667  pname = sname = "Group";
1668  break;
1669  case T_Agg:
1670  {
1671  Agg *agg = (Agg *) plan;
1672 
1673  sname = "Aggregate";
1674  switch (agg->aggstrategy)
1675  {
1676  case AGG_PLAIN:
1677  pname = "Aggregate";
1678  strategy = "Plain";
1679  break;
1680  case AGG_SORTED:
1681  pname = "GroupAggregate";
1682  strategy = "Sorted";
1683  break;
1684  case AGG_HASHED:
1685  pname = "HashAggregate";
1686  strategy = "Hashed";
1687  break;
1688  case AGG_MIXED:
1689  pname = "MixedAggregate";
1690  strategy = "Mixed";
1691  break;
1692  default:
1693  pname = "Aggregate ???";
1694  strategy = "???";
1695  break;
1696  }
1697 
1698  if (DO_AGGSPLIT_SKIPFINAL(agg->aggsplit))
1699  {
1700  partialmode = "Partial";
1701  pname = psprintf("%s %s", partialmode, pname);
1702  }
1703  else if (DO_AGGSPLIT_COMBINE(agg->aggsplit))
1704  {
1705  partialmode = "Finalize";
1706  pname = psprintf("%s %s", partialmode, pname);
1707  }
1708  else
1709  partialmode = "Simple";
1710  }
1711  break;
1712  case T_WindowAgg:
1713  pname = sname = "WindowAgg";
1714  break;
1715  case T_Unique:
1716  pname = sname = "Unique";
1717  break;
1718  case T_SetOp:
1719  sname = "SetOp";
1720  switch (((SetOp *) plan)->strategy)
1721  {
1722  case SETOP_SORTED:
1723  pname = "SetOp";
1724  strategy = "Sorted";
1725  break;
1726  case SETOP_HASHED:
1727  pname = "HashSetOp";
1728  strategy = "Hashed";
1729  break;
1730  default:
1731  pname = "SetOp ???";
1732  strategy = "???";
1733  break;
1734  }
1735  break;
1736  case T_LockRows:
1737  pname = sname = "LockRows";
1738  break;
1739  case T_Limit:
1740  pname = sname = "Limit";
1741  break;
1742  case T_Hash:
1743  pname = sname = "Hash";
1744  break;
1745  default:
1746  pname = sname = "???";
1747  break;
1748  }
1749 
1750  ExplainOpenGroup("Plan",
1751  relationship ? NULL : "Plan",
1752  true, es);
1753 
1754  if (es->format == EXPLAIN_FORMAT_TEXT)
1755  {
1756  if (plan_name)
1757  {
1758  ExplainIndentText(es);
1759  appendStringInfo(es->str, "%s\n", plan_name);
1760  es->indent++;
1761  }
1762  if (es->indent)
1763  {
1764  ExplainIndentText(es);
1765  appendStringInfoString(es->str, "-> ");
1766  es->indent += 2;
1767  }
1768  if (plan->parallel_aware)
1769  appendStringInfoString(es->str, "Parallel ");
1770  if (plan->async_capable)
1771  appendStringInfoString(es->str, "Async ");
1772  appendStringInfoString(es->str, pname);
1773  es->indent++;
1774  }
1775  else
1776  {
1777  ExplainPropertyText("Node Type", sname, es);
1778  if (strategy)
1779  ExplainPropertyText("Strategy", strategy, es);
1780  if (partialmode)
1781  ExplainPropertyText("Partial Mode", partialmode, es);
1782  if (operation)
1783  ExplainPropertyText("Operation", operation, es);
1784  if (relationship)
1785  ExplainPropertyText("Parent Relationship", relationship, es);
1786  if (plan_name)
1787  ExplainPropertyText("Subplan Name", plan_name, es);
1788  if (custom_name)
1789  ExplainPropertyText("Custom Plan Provider", custom_name, es);
1790  ExplainPropertyBool("Parallel Aware", plan->parallel_aware, es);
1791  ExplainPropertyBool("Async Capable", plan->async_capable, es);
1792  }
1793 
1794  switch (nodeTag(plan))
1795  {
1796  case T_SeqScan:
1797  case T_SampleScan:
1798  case T_BitmapHeapScan:
1799  case T_TidScan:
1800  case T_TidRangeScan:
1801  case T_SubqueryScan:
1802  case T_FunctionScan:
1803  case T_TableFuncScan:
1804  case T_ValuesScan:
1805  case T_CteScan:
1806  case T_WorkTableScan:
1807  ExplainScanTarget((Scan *) plan, es);
1808  break;
1809  case T_ForeignScan:
1810  case T_CustomScan:
1811  if (((Scan *) plan)->scanrelid > 0)
1812  ExplainScanTarget((Scan *) plan, es);
1813  break;
1814  case T_IndexScan:
1815  {
1816  IndexScan *indexscan = (IndexScan *) plan;
1817 
1818  ExplainIndexScanDetails(indexscan->indexid,
1819  indexscan->indexorderdir,
1820  es);
1821  ExplainScanTarget((Scan *) indexscan, es);
1822  }
1823  break;
1824  case T_IndexOnlyScan:
1825  {
1826  IndexOnlyScan *indexonlyscan = (IndexOnlyScan *) plan;
1827 
1828  ExplainIndexScanDetails(indexonlyscan->indexid,
1829  indexonlyscan->indexorderdir,
1830  es);
1831  ExplainScanTarget((Scan *) indexonlyscan, es);
1832  }
1833  break;
1834  case T_BitmapIndexScan:
1835  {
1836  BitmapIndexScan *bitmapindexscan = (BitmapIndexScan *) plan;
1837  const char *indexname =
1838  explain_get_index_name(bitmapindexscan->indexid);
1839 
1840  if (es->format == EXPLAIN_FORMAT_TEXT)
1841  appendStringInfo(es->str, " on %s",
1842  quote_identifier(indexname));
1843  else
1844  ExplainPropertyText("Index Name", indexname, es);
1845  }
1846  break;
1847  case T_ModifyTable:
1849  break;
1850  case T_NestLoop:
1851  case T_MergeJoin:
1852  case T_HashJoin:
1853  {
1854  const char *jointype;
1855 
1856  switch (((Join *) plan)->jointype)
1857  {
1858  case JOIN_INNER:
1859  jointype = "Inner";
1860  break;
1861  case JOIN_LEFT:
1862  jointype = "Left";
1863  break;
1864  case JOIN_FULL:
1865  jointype = "Full";
1866  break;
1867  case JOIN_RIGHT:
1868  jointype = "Right";
1869  break;
1870  case JOIN_SEMI:
1871  jointype = "Semi";
1872  break;
1873  case JOIN_ANTI:
1874  jointype = "Anti";
1875  break;
1876  case JOIN_RIGHT_SEMI:
1877  jointype = "Right Semi";
1878  break;
1879  case JOIN_RIGHT_ANTI:
1880  jointype = "Right Anti";
1881  break;
1882  default:
1883  jointype = "???";
1884  break;
1885  }
1886  if (es->format == EXPLAIN_FORMAT_TEXT)
1887  {
1888  /*
1889  * For historical reasons, the join type is interpolated
1890  * into the node type name...
1891  */
1892  if (((Join *) plan)->jointype != JOIN_INNER)
1893  appendStringInfo(es->str, " %s Join", jointype);
1894  else if (!IsA(plan, NestLoop))
1895  appendStringInfoString(es->str, " Join");
1896  }
1897  else
1898  ExplainPropertyText("Join Type", jointype, es);
1899  }
1900  break;
1901  case T_SetOp:
1902  {
1903  const char *setopcmd;
1904 
1905  switch (((SetOp *) plan)->cmd)
1906  {
1907  case SETOPCMD_INTERSECT:
1908  setopcmd = "Intersect";
1909  break;
1911  setopcmd = "Intersect All";
1912  break;
1913  case SETOPCMD_EXCEPT:
1914  setopcmd = "Except";
1915  break;
1916  case SETOPCMD_EXCEPT_ALL:
1917  setopcmd = "Except All";
1918  break;
1919  default:
1920  setopcmd = "???";
1921  break;
1922  }
1923  if (es->format == EXPLAIN_FORMAT_TEXT)
1924  appendStringInfo(es->str, " %s", setopcmd);
1925  else
1926  ExplainPropertyText("Command", setopcmd, es);
1927  }
1928  break;
1929  default:
1930  break;
1931  }
1932 
1933  if (es->costs)
1934  {
1935  if (es->format == EXPLAIN_FORMAT_TEXT)
1936  {
1937  appendStringInfo(es->str, " (cost=%.2f..%.2f rows=%.0f width=%d)",
1938  plan->startup_cost, plan->total_cost,
1939  plan->plan_rows, plan->plan_width);
1940  }
1941  else
1942  {
1943  ExplainPropertyFloat("Startup Cost", NULL, plan->startup_cost,
1944  2, es);
1945  ExplainPropertyFloat("Total Cost", NULL, plan->total_cost,
1946  2, es);
1947  ExplainPropertyFloat("Plan Rows", NULL, plan->plan_rows,
1948  0, es);
1949  ExplainPropertyInteger("Plan Width", NULL, plan->plan_width,
1950  es);
1951  }
1952  }
1953 
1954  /*
1955  * We have to forcibly clean up the instrumentation state because we
1956  * haven't done ExecutorEnd yet. This is pretty grotty ...
1957  *
1958  * Note: contrib/auto_explain could cause instrumentation to be set up
1959  * even though we didn't ask for it here. Be careful not to print any
1960  * instrumentation results the user didn't ask for. But we do the
1961  * InstrEndLoop call anyway, if possible, to reduce the number of cases
1962  * auto_explain has to contend with.
1963  */
1964  if (planstate->instrument)
1965  InstrEndLoop(planstate->instrument);
1966 
1967  if (es->analyze &&
1968  planstate->instrument && planstate->instrument->nloops > 0)
1969  {
1970  double nloops = planstate->instrument->nloops;
1971  double startup_ms = 1000.0 * planstate->instrument->startup / nloops;
1972  double total_ms = 1000.0 * planstate->instrument->total / nloops;
1973  double rows = planstate->instrument->ntuples / nloops;
1974 
1975  if (es->format == EXPLAIN_FORMAT_TEXT)
1976  {
1977  if (es->timing)
1978  appendStringInfo(es->str,
1979  " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",
1980  startup_ms, total_ms, rows, nloops);
1981  else
1982  appendStringInfo(es->str,
1983  " (actual rows=%.0f loops=%.0f)",
1984  rows, nloops);
1985  }
1986  else
1987  {
1988  if (es->timing)
1989  {
1990  ExplainPropertyFloat("Actual Startup Time", "ms", startup_ms,
1991  3, es);
1992  ExplainPropertyFloat("Actual Total Time", "ms", total_ms,
1993  3, es);
1994  }
1995  ExplainPropertyFloat("Actual Rows", NULL, rows, 0, es);
1996  ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es);
1997  }
1998  }
1999  else if (es->analyze)
2000  {
2001  if (es->format == EXPLAIN_FORMAT_TEXT)
2002  appendStringInfoString(es->str, " (never executed)");
2003  else
2004  {
2005  if (es->timing)
2006  {
2007  ExplainPropertyFloat("Actual Startup Time", "ms", 0.0, 3, es);
2008  ExplainPropertyFloat("Actual Total Time", "ms", 0.0, 3, es);
2009  }
2010  ExplainPropertyFloat("Actual Rows", NULL, 0.0, 0, es);
2011  ExplainPropertyFloat("Actual Loops", NULL, 0.0, 0, es);
2012  }
2013  }
2014 
2015  /* in text format, first line ends here */
2016  if (es->format == EXPLAIN_FORMAT_TEXT)
2017  appendStringInfoChar(es->str, '\n');
2018 
2019 
2020  isdisabled = plan_is_disabled(plan);
2021  if (es->format != EXPLAIN_FORMAT_TEXT || isdisabled)
2022  ExplainPropertyBool("Disabled", isdisabled, es);
2023 
2024  /* prepare per-worker general execution details */
2025  if (es->workers_state && es->verbose)
2026  {
2027  WorkerInstrumentation *w = planstate->worker_instrument;
2028 
2029  for (int n = 0; n < w->num_workers; n++)
2030  {
2031  Instrumentation *instrument = &w->instrument[n];
2032  double nloops = instrument->nloops;
2033  double startup_ms;
2034  double total_ms;
2035  double rows;
2036 
2037  if (nloops <= 0)
2038  continue;
2039  startup_ms = 1000.0 * instrument->startup / nloops;
2040  total_ms = 1000.0 * instrument->total / nloops;
2041  rows = instrument->ntuples / nloops;
2042 
2043  ExplainOpenWorker(n, es);
2044 
2045  if (es->format == EXPLAIN_FORMAT_TEXT)
2046  {
2047  ExplainIndentText(es);
2048  if (es->timing)
2049  appendStringInfo(es->str,
2050  "actual time=%.3f..%.3f rows=%.0f loops=%.0f\n",
2051  startup_ms, total_ms, rows, nloops);
2052  else
2053  appendStringInfo(es->str,
2054  "actual rows=%.0f loops=%.0f\n",
2055  rows, nloops);
2056  }
2057  else
2058  {
2059  if (es->timing)
2060  {
2061  ExplainPropertyFloat("Actual Startup Time", "ms",
2062  startup_ms, 3, es);
2063  ExplainPropertyFloat("Actual Total Time", "ms",
2064  total_ms, 3, es);
2065  }
2066  ExplainPropertyFloat("Actual Rows", NULL, rows, 0, es);
2067  ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es);
2068  }
2069 
2070  ExplainCloseWorker(n, es);
2071  }
2072  }
2073 
2074  /* target list */
2075  if (es->verbose)
2076  show_plan_tlist(planstate, ancestors, es);
2077 
2078  /* unique join */
2079  switch (nodeTag(plan))
2080  {
2081  case T_NestLoop:
2082  case T_MergeJoin:
2083  case T_HashJoin:
2084  /* try not to be too chatty about this in text mode */
2085  if (es->format != EXPLAIN_FORMAT_TEXT ||
2086  (es->verbose && ((Join *) plan)->inner_unique))
2087  ExplainPropertyBool("Inner Unique",
2088  ((Join *) plan)->inner_unique,
2089  es);
2090  break;
2091  default:
2092  break;
2093  }
2094 
2095  /* quals, sort keys, etc */
2096  switch (nodeTag(plan))
2097  {
2098  case T_IndexScan:
2099  show_scan_qual(((IndexScan *) plan)->indexqualorig,
2100  "Index Cond", planstate, ancestors, es);
2101  if (((IndexScan *) plan)->indexqualorig)
2102  show_instrumentation_count("Rows Removed by Index Recheck", 2,
2103  planstate, es);
2104  show_scan_qual(((IndexScan *) plan)->indexorderbyorig,
2105  "Order By", planstate, ancestors, es);
2106  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2107  if (plan->qual)
2108  show_instrumentation_count("Rows Removed by Filter", 1,
2109  planstate, es);
2110  break;
2111  case T_IndexOnlyScan:
2112  show_scan_qual(((IndexOnlyScan *) plan)->indexqual,
2113  "Index Cond", planstate, ancestors, es);
2114  if (((IndexOnlyScan *) plan)->recheckqual)
2115  show_instrumentation_count("Rows Removed by Index Recheck", 2,
2116  planstate, es);
2117  show_scan_qual(((IndexOnlyScan *) plan)->indexorderby,
2118  "Order By", planstate, ancestors, es);
2119  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2120  if (plan->qual)
2121  show_instrumentation_count("Rows Removed by Filter", 1,
2122  planstate, es);
2123  if (es->analyze)
2124  ExplainPropertyFloat("Heap Fetches", NULL,
2125  planstate->instrument->ntuples2, 0, es);
2126  break;
2127  case T_BitmapIndexScan:
2128  show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig,
2129  "Index Cond", planstate, ancestors, es);
2130  break;
2131  case T_BitmapHeapScan:
2132  show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig,
2133  "Recheck Cond", planstate, ancestors, es);
2134  if (((BitmapHeapScan *) plan)->bitmapqualorig)
2135  show_instrumentation_count("Rows Removed by Index Recheck", 2,
2136  planstate, es);
2137  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2138  if (plan->qual)
2139  show_instrumentation_count("Rows Removed by Filter", 1,
2140  planstate, es);
2141  show_tidbitmap_info((BitmapHeapScanState *) planstate, es);
2142  break;
2143  case T_SampleScan:
2144  show_tablesample(((SampleScan *) plan)->tablesample,
2145  planstate, ancestors, es);
2146  /* fall through to print additional fields the same as SeqScan */
2147  /* FALLTHROUGH */
2148  case T_SeqScan:
2149  case T_ValuesScan:
2150  case T_CteScan:
2151  case T_NamedTuplestoreScan:
2152  case T_WorkTableScan:
2153  case T_SubqueryScan:
2154  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2155  if (plan->qual)
2156  show_instrumentation_count("Rows Removed by Filter", 1,
2157  planstate, es);
2158  if (IsA(plan, CteScan))
2159  show_ctescan_info(castNode(CteScanState, planstate), es);
2160  break;
2161  case T_Gather:
2162  {
2163  Gather *gather = (Gather *) plan;
2164 
2165  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2166  if (plan->qual)
2167  show_instrumentation_count("Rows Removed by Filter", 1,
2168  planstate, es);
2169  ExplainPropertyInteger("Workers Planned", NULL,
2170  gather->num_workers, es);
2171 
2172  if (es->analyze)
2173  {
2174  int nworkers;
2175 
2176  nworkers = ((GatherState *) planstate)->nworkers_launched;
2177  ExplainPropertyInteger("Workers Launched", NULL,
2178  nworkers, es);
2179  }
2180 
2181  if (gather->single_copy || es->format != EXPLAIN_FORMAT_TEXT)
2182  ExplainPropertyBool("Single Copy", gather->single_copy, es);
2183  }
2184  break;
2185  case T_GatherMerge:
2186  {
2187  GatherMerge *gm = (GatherMerge *) plan;
2188 
2189  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2190  if (plan->qual)
2191  show_instrumentation_count("Rows Removed by Filter", 1,
2192  planstate, es);
2193  ExplainPropertyInteger("Workers Planned", NULL,
2194  gm->num_workers, es);
2195 
2196  if (es->analyze)
2197  {
2198  int nworkers;
2199 
2200  nworkers = ((GatherMergeState *) planstate)->nworkers_launched;
2201  ExplainPropertyInteger("Workers Launched", NULL,
2202  nworkers, es);
2203  }
2204  }
2205  break;
2206  case T_FunctionScan:
2207  if (es->verbose)
2208  {
2209  List *fexprs = NIL;
2210  ListCell *lc;
2211 
2212  foreach(lc, ((FunctionScan *) plan)->functions)
2213  {
2214  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
2215 
2216  fexprs = lappend(fexprs, rtfunc->funcexpr);
2217  }
2218  /* We rely on show_expression to insert commas as needed */
2219  show_expression((Node *) fexprs,
2220  "Function Call", planstate, ancestors,
2221  es->verbose, es);
2222  }
2223  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2224  if (plan->qual)
2225  show_instrumentation_count("Rows Removed by Filter", 1,
2226  planstate, es);
2227  break;
2228  case T_TableFuncScan:
2229  if (es->verbose)
2230  {
2231  TableFunc *tablefunc = ((TableFuncScan *) plan)->tablefunc;
2232 
2233  show_expression((Node *) tablefunc,
2234  "Table Function Call", planstate, ancestors,
2235  es->verbose, es);
2236  }
2237  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2238  if (plan->qual)
2239  show_instrumentation_count("Rows Removed by Filter", 1,
2240  planstate, es);
2242  planstate), es);
2243  break;
2244  case T_TidScan:
2245  {
2246  /*
2247  * The tidquals list has OR semantics, so be sure to show it
2248  * as an OR condition.
2249  */
2250  List *tidquals = ((TidScan *) plan)->tidquals;
2251 
2252  if (list_length(tidquals) > 1)
2253  tidquals = list_make1(make_orclause(tidquals));
2254  show_scan_qual(tidquals, "TID Cond", planstate, ancestors, es);
2255  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2256  if (plan->qual)
2257  show_instrumentation_count("Rows Removed by Filter", 1,
2258  planstate, es);
2259  }
2260  break;
2261  case T_TidRangeScan:
2262  {
2263  /*
2264  * The tidrangequals list has AND semantics, so be sure to
2265  * show it as an AND condition.
2266  */
2267  List *tidquals = ((TidRangeScan *) plan)->tidrangequals;
2268 
2269  if (list_length(tidquals) > 1)
2270  tidquals = list_make1(make_andclause(tidquals));
2271  show_scan_qual(tidquals, "TID Cond", planstate, ancestors, es);
2272  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2273  if (plan->qual)
2274  show_instrumentation_count("Rows Removed by Filter", 1,
2275  planstate, es);
2276  }
2277  break;
2278  case T_ForeignScan:
2279  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2280  if (plan->qual)
2281  show_instrumentation_count("Rows Removed by Filter", 1,
2282  planstate, es);
2283  show_foreignscan_info((ForeignScanState *) planstate, es);
2284  break;
2285  case T_CustomScan:
2286  {
2287  CustomScanState *css = (CustomScanState *) planstate;
2288 
2289  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
2290  if (plan->qual)
2291  show_instrumentation_count("Rows Removed by Filter", 1,
2292  planstate, es);
2293  if (css->methods->ExplainCustomScan)
2294  css->methods->ExplainCustomScan(css, ancestors, es);
2295  }
2296  break;
2297  case T_NestLoop:
2298  show_upper_qual(((NestLoop *) plan)->join.joinqual,
2299  "Join Filter", planstate, ancestors, es);
2300  if (((NestLoop *) plan)->join.joinqual)
2301  show_instrumentation_count("Rows Removed by Join Filter", 1,
2302  planstate, es);
2303  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
2304  if (plan->qual)
2305  show_instrumentation_count("Rows Removed by Filter", 2,
2306  planstate, es);
2307  break;
2308  case T_MergeJoin:
2309  show_upper_qual(((MergeJoin *) plan)->mergeclauses,
2310  "Merge Cond", planstate, ancestors, es);
2311  show_upper_qual(((MergeJoin *) plan)->join.joinqual,
2312  "Join Filter", planstate, ancestors, es);
2313  if (((MergeJoin *) plan)->join.joinqual)
2314  show_instrumentation_count("Rows Removed by Join Filter", 1,
2315  planstate, es);
2316  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
2317  if (plan->qual)
2318  show_instrumentation_count("Rows Removed by Filter", 2,
2319  planstate, es);
2320  break;
2321  case T_HashJoin:
2322  show_upper_qual(((HashJoin *) plan)->hashclauses,
2323  "Hash Cond", planstate, ancestors, es);
2324  show_upper_qual(((HashJoin *) plan)->join.joinqual,
2325  "Join Filter", planstate, ancestors, es);
2326  if (((HashJoin *) plan)->join.joinqual)
2327  show_instrumentation_count("Rows Removed by Join Filter", 1,
2328  planstate, es);
2329  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
2330  if (plan->qual)
2331  show_instrumentation_count("Rows Removed by Filter", 2,
2332  planstate, es);
2333  break;
2334  case T_Agg:
2335  show_agg_keys(castNode(AggState, planstate), ancestors, es);
2336  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
2337  show_hashagg_info((AggState *) planstate, es);
2338  if (plan->qual)
2339  show_instrumentation_count("Rows Removed by Filter", 1,
2340  planstate, es);
2341  break;
2342  case T_WindowAgg:
2343  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
2344  if (plan->qual)
2345  show_instrumentation_count("Rows Removed by Filter", 1,
2346  planstate, es);
2347  show_upper_qual(((WindowAgg *) plan)->runConditionOrig,
2348  "Run Condition", planstate, ancestors, es);
2349  show_windowagg_info(castNode(WindowAggState, planstate), es);
2350  break;
2351  case T_Group:
2352  show_group_keys(castNode(GroupState, planstate), ancestors, es);
2353  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
2354  if (plan->qual)
2355  show_instrumentation_count("Rows Removed by Filter", 1,
2356  planstate, es);
2357  break;
2358  case T_Sort:
2359  show_sort_keys(castNode(SortState, planstate), ancestors, es);
2360  show_sort_info(castNode(SortState, planstate), es);
2361  break;
2362  case T_IncrementalSort:
2364  ancestors, es);
2366  es);
2367  break;
2368  case T_MergeAppend:
2370  ancestors, es);
2371  break;
2372  case T_Result:
2373  show_upper_qual((List *) ((Result *) plan)->resconstantqual,
2374  "One-Time Filter", planstate, ancestors, es);
2375  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
2376  if (plan->qual)
2377  show_instrumentation_count("Rows Removed by Filter", 1,
2378  planstate, es);
2379  break;
2380  case T_ModifyTable:
2381  show_modifytable_info(castNode(ModifyTableState, planstate), ancestors,
2382  es);
2383  break;
2384  case T_Hash:
2385  show_hash_info(castNode(HashState, planstate), es);
2386  break;
2387  case T_Material:
2388  show_material_info(castNode(MaterialState, planstate), es);
2389  break;
2390  case T_Memoize:
2391  show_memoize_info(castNode(MemoizeState, planstate), ancestors,
2392  es);
2393  break;
2394  case T_RecursiveUnion:
2396  planstate), es);
2397  break;
2398  default:
2399  break;
2400  }
2401 
2402  /*
2403  * Prepare per-worker JIT instrumentation. As with the overall JIT
2404  * summary, this is printed only if printing costs is enabled.
2405  */
2406  if (es->workers_state && es->costs && es->verbose)
2407  {
2409 
2410  if (w)
2411  {
2412  for (int n = 0; n < w->num_workers; n++)
2413  {
2414  ExplainOpenWorker(n, es);
2415  ExplainPrintJIT(es, planstate->state->es_jit_flags,
2416  &w->jit_instr[n]);
2417  ExplainCloseWorker(n, es);
2418  }
2419  }
2420  }
2421 
2422  /* Show buffer/WAL usage */
2423  if (es->buffers && planstate->instrument)
2424  show_buffer_usage(es, &planstate->instrument->bufusage);
2425  if (es->wal && planstate->instrument)
2426  show_wal_usage(es, &planstate->instrument->walusage);
2427 
2428  /* Prepare per-worker buffer/WAL usage */
2429  if (es->workers_state && (es->buffers || es->wal) && es->verbose)
2430  {
2431  WorkerInstrumentation *w = planstate->worker_instrument;
2432 
2433  for (int n = 0; n < w->num_workers; n++)
2434  {
2435  Instrumentation *instrument = &w->instrument[n];
2436  double nloops = instrument->nloops;
2437 
2438  if (nloops <= 0)
2439  continue;
2440 
2441  ExplainOpenWorker(n, es);
2442  if (es->buffers)
2443  show_buffer_usage(es, &instrument->bufusage);
2444  if (es->wal)
2445  show_wal_usage(es, &instrument->walusage);
2446  ExplainCloseWorker(n, es);
2447  }
2448  }
2449 
2450  /* Show per-worker details for this plan node, then pop that stack */
2451  if (es->workers_state)
2453  es->workers_state = save_workers_state;
2454 
2455  /*
2456  * If partition pruning was done during executor initialization, the
2457  * number of child plans we'll display below will be less than the number
2458  * of subplans that was specified in the plan. To make this a bit less
2459  * mysterious, emit an indication that this happened. Note that this
2460  * field is emitted now because we want it to be a property of the parent
2461  * node; it *cannot* be emitted within the Plans sub-node we'll open next.
2462  */
2463  switch (nodeTag(plan))
2464  {
2465  case T_Append:
2466  ExplainMissingMembers(((AppendState *) planstate)->as_nplans,
2467  list_length(((Append *) plan)->appendplans),
2468  es);
2469  break;
2470  case T_MergeAppend:
2471  ExplainMissingMembers(((MergeAppendState *) planstate)->ms_nplans,
2472  list_length(((MergeAppend *) plan)->mergeplans),
2473  es);
2474  break;
2475  default:
2476  break;
2477  }
2478 
2479  /* Get ready to display the child plans */
2480  haschildren = planstate->initPlan ||
2481  outerPlanState(planstate) ||
2482  innerPlanState(planstate) ||
2483  IsA(plan, Append) ||
2484  IsA(plan, MergeAppend) ||
2485  IsA(plan, BitmapAnd) ||
2486  IsA(plan, BitmapOr) ||
2487  IsA(plan, SubqueryScan) ||
2488  (IsA(planstate, CustomScanState) &&
2489  ((CustomScanState *) planstate)->custom_ps != NIL) ||
2490  planstate->subPlan;
2491  if (haschildren)
2492  {
2493  ExplainOpenGroup("Plans", "Plans", false, es);
2494  /* Pass current Plan as head of ancestors list for children */
2495  ancestors = lcons(plan, ancestors);
2496  }
2497 
2498  /* initPlan-s */
2499  if (planstate->initPlan)
2500  ExplainSubPlans(planstate->initPlan, ancestors, "InitPlan", es);
2501 
2502  /* lefttree */
2503  if (outerPlanState(planstate))
2504  ExplainNode(outerPlanState(planstate), ancestors,
2505  "Outer", NULL, es);
2506 
2507  /* righttree */
2508  if (innerPlanState(planstate))
2509  ExplainNode(innerPlanState(planstate), ancestors,
2510  "Inner", NULL, es);
2511 
2512  /* special child plans */
2513  switch (nodeTag(plan))
2514  {
2515  case T_Append:
2516  ExplainMemberNodes(((AppendState *) planstate)->appendplans,
2517  ((AppendState *) planstate)->as_nplans,
2518  ancestors, es);
2519  break;
2520  case T_MergeAppend:
2521  ExplainMemberNodes(((MergeAppendState *) planstate)->mergeplans,
2522  ((MergeAppendState *) planstate)->ms_nplans,
2523  ancestors, es);
2524  break;
2525  case T_BitmapAnd:
2526  ExplainMemberNodes(((BitmapAndState *) planstate)->bitmapplans,
2527  ((BitmapAndState *) planstate)->nplans,
2528  ancestors, es);
2529  break;
2530  case T_BitmapOr:
2531  ExplainMemberNodes(((BitmapOrState *) planstate)->bitmapplans,
2532  ((BitmapOrState *) planstate)->nplans,
2533  ancestors, es);
2534  break;
2535  case T_SubqueryScan:
2536  ExplainNode(((SubqueryScanState *) planstate)->subplan, ancestors,
2537  "Subquery", NULL, es);
2538  break;
2539  case T_CustomScan:
2540  ExplainCustomChildren((CustomScanState *) planstate,
2541  ancestors, es);
2542  break;
2543  default:
2544  break;
2545  }
2546 
2547  /* subPlan-s */
2548  if (planstate->subPlan)
2549  ExplainSubPlans(planstate->subPlan, ancestors, "SubPlan", es);
2550 
2551  /* end of child plans */
2552  if (haschildren)
2553  {
2554  ancestors = list_delete_first(ancestors);
2555  ExplainCloseGroup("Plans", "Plans", false, es);
2556  }
2557 
2558  /* in text format, undo whatever indentation we added */
2559  if (es->format == EXPLAIN_FORMAT_TEXT)
2560  es->indent = save_indent;
2561 
2562  ExplainCloseGroup("Plan",
2563  relationship ? NULL : "Plan",
2564  true, es);
2565 }
#define outerPlanState(node)
Definition: execnodes.h:1223
#define innerPlanState(node)
Definition: execnodes.h:1222
static void show_modifytable_info(ModifyTableState *mtstate, List *ancestors, ExplainState *es)
Definition: explain.c:4492
static void show_plan_tlist(PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:2571
static void show_memoize_info(MemoizeState *mstate, List *ancestors, ExplainState *es)
Definition: explain.c:3608
static void show_group_keys(GroupState *gstate, List *ancestors, ExplainState *es)
Definition: explain.c:2881
static void ExplainModifyTarget(ModifyTable *plan, ExplainState *es)
Definition: explain.c:4345
static void show_agg_keys(AggState *astate, List *ancestors, ExplainState *es)
Definition: explain.c:2749
static void show_hashagg_info(AggState *aggstate, ExplainState *es)
Definition: explain.c:3752
static void show_scan_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:2673
static void ExplainIndexScanDetails(Oid indexid, ScanDirection indexorderdir, ExplainState *es)
Definition: explain.c:4296
static void show_instrumentation_count(const char *qlabel, int which, PlanState *planstate, ExplainState *es)
Definition: explain.c:3942
static void ExplainMemberNodes(PlanState **planstates, int nplans, List *ancestors, ExplainState *es)
Definition: explain.c:4704
static void show_ctescan_info(CteScanState *ctescanstate, ExplainState *es)
Definition: explain.c:3539
static void ExplainPrintJIT(ExplainState *es, int jit_flags, JitInstrumentation *ji)
Definition: explain.c:1043
static void show_recursive_union_info(RecursiveUnionState *rstate, ExplainState *es)
Definition: explain.c:3577
static void show_incremental_sort_info(IncrementalSortState *incrsortstate, ExplainState *es)
Definition: explain.c:3315
static void show_tablesample(TableSampleClause *tsc, PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:3044
static void show_upper_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:2687
static void show_sort_info(SortState *sortstate, ExplainState *es)
Definition: explain.c:3110
static void ExplainMissingMembers(int nplans, int nchildren, ExplainState *es)
Definition: explain.c:4722
static void ExplainFlushWorkersState(ExplainState *es)
Definition: explain.c:4916
static void show_hash_info(HashState *hashstate, ExplainState *es)
Definition: explain.c:3401
void ExplainPropertyFloat(const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
Definition: explain.c:5158
static void show_table_func_scan_info(TableFuncScanState *tscanstate, ExplainState *es)
Definition: explain.c:3558
static void show_expression(Node *node, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
Definition: explain.c:2629
static void ExplainIndentText(ExplainState *es)
Definition: explain.c:5559
static bool plan_is_disabled(Plan *plan)
Definition: explain.c:1384
static void show_tidbitmap_info(BitmapHeapScanState *planstate, ExplainState *es)
Definition: explain.c:3873
static void show_windowagg_info(WindowAggState *winstate, ExplainState *es)
Definition: explain.c:3516
static void ExplainSubPlans(List *plans, List *ancestors, const char *relationship, ExplainState *es)
Definition: explain.c:4736
static void show_foreignscan_info(ForeignScanState *fsstate, ExplainState *es)
Definition: explain.c:3971
static void ExplainScanTarget(Scan *plan, ExplainState *es)
Definition: explain.c:4332
static void show_merge_append_keys(MergeAppendState *mstate, List *ancestors, ExplainState *es)
Definition: explain.c:2733
static void ExplainCloseWorker(int n, ExplainState *es)
Definition: explain.c:4880
static void ExplainOpenWorker(int n, ExplainState *es)
Definition: explain.c:4818
static void show_wal_usage(ExplainState *es, const WalUsage *usage)
Definition: explain.c:4232
void ExplainPropertyBool(const char *qlabel, bool value, ExplainState *es)
Definition: explain.c:5172
static void show_material_info(MaterialState *mstate, ExplainState *es)
Definition: explain.c:3493
static void show_sort_keys(SortState *sortstate, List *ancestors, ExplainState *es)
Definition: explain.c:2701
static ExplainWorkersState * ExplainCreateWorkersState(int num_workers)
Definition: explain.c:4801
static void show_buffer_usage(ExplainState *es, const BufferUsage *usage)
Definition: explain.c:4063
static void show_incremental_sort_keys(IncrementalSortState *incrsortstate, List *ancestors, ExplainState *es)
Definition: explain.c:2716
static void ExplainCustomChildren(CustomScanState *css, List *ancestors, ExplainState *es)
Definition: explain.c:4779
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:140
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
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:43
static const struct fns functions
Definition: regcomp.c:356
Definition: plannodes.h:998
AggSplit aggsplit
Definition: plannodes.h:1005
AggStrategy aggstrategy
Definition: plannodes.h:1002
void(* ExplainCustomScan)(CustomScanState *node, List *ancestors, ExplainState *es)
Definition: extensible.h:155
const struct CustomExecMethods * methods
Definition: execnodes.h:2106
int es_jit_flags
Definition: execnodes.h:728
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:1161
int num_workers
Definition: plannodes.h:1144
bool single_copy
Definition: plannodes.h:1146
ScanDirection indexorderdir
Definition: plannodes.h:501
ScanDirection indexorderdir
Definition: plannodes.h:459
Oid indexid
Definition: plannodes.h:453
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:1141
Instrumentation * instrument
Definition: execnodes.h:1137
Plan * plan
Definition: execnodes.h:1127
EState * state
Definition: execnodes.h:1129
WorkerInstrumentation * worker_instrument
Definition: execnodes.h:1138
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, plan_is_disabled(), psprintf(), quote_identifier(), SETOP_HASHED, SETOP_SORTED, SETOPCMD_EXCEPT, SETOPCMD_EXCEPT_ALL, SETOPCMD_INTERSECT, SETOPCMD_INTERSECT_ALL, show_agg_keys(), show_buffer_usage(), show_ctescan_info(), 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_recursive_union_info(), show_scan_qual(), show_sort_info(), show_sort_keys(), show_table_func_scan_info(), show_tablesample(), show_tidbitmap_info(), show_upper_qual(), show_wal_usage(), show_windowagg_info(), 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 637 of file explain.c.

642 {
644  QueryDesc *queryDesc;
645  instr_time starttime;
646  double totaltime = 0;
647  int eflags;
648  int instrument_option = 0;
649  SerializeMetrics serializeMetrics = {0};
650 
651  Assert(plannedstmt->commandType != CMD_UTILITY);
652 
653  if (es->analyze && es->timing)
654  instrument_option |= INSTRUMENT_TIMER;
655  else if (es->analyze)
656  instrument_option |= INSTRUMENT_ROWS;
657 
658  if (es->buffers)
659  instrument_option |= INSTRUMENT_BUFFERS;
660  if (es->wal)
661  instrument_option |= INSTRUMENT_WAL;
662 
663  /*
664  * We always collect timing for the entire statement, even when node-level
665  * timing is off, so we don't look at es->timing here. (We could skip
666  * this if !es->summary, but it's hardly worth the complication.)
667  */
668  INSTR_TIME_SET_CURRENT(starttime);
669 
670  /*
671  * Use a snapshot with an updated command ID to ensure this query sees
672  * results of any previously executed queries.
673  */
676 
677  /*
678  * We discard the output if we have no use for it. If we're explaining
679  * CREATE TABLE AS, we'd better use the appropriate tuple receiver, while
680  * the SERIALIZE option requires its own tuple receiver. (If you specify
681  * SERIALIZE while explaining CREATE TABLE AS, you'll see zeroes for the
682  * results, which is appropriate since no data would have gone to the
683  * client.)
684  */
685  if (into)
687  else if (es->serialize != EXPLAIN_SERIALIZE_NONE)
689  else
691 
692  /* Create a QueryDesc for the query */
693  queryDesc = CreateQueryDesc(plannedstmt, queryString,
695  dest, params, queryEnv, instrument_option);
696 
697  /* Select execution options */
698  if (es->analyze)
699  eflags = 0; /* default run-to-completion flags */
700  else
701  eflags = EXEC_FLAG_EXPLAIN_ONLY;
702  if (es->generic)
703  eflags |= EXEC_FLAG_EXPLAIN_GENERIC;
704  if (into)
705  eflags |= GetIntoRelEFlags(into);
706 
707  /* call ExecutorStart to prepare the plan for execution */
708  ExecutorStart(queryDesc, eflags);
709 
710  /* Execute the plan for statistics if asked for */
711  if (es->analyze)
712  {
713  ScanDirection dir;
714 
715  /* EXPLAIN ANALYZE CREATE TABLE AS WITH NO DATA is weird */
716  if (into && into->skipData)
718  else
719  dir = ForwardScanDirection;
720 
721  /* run the plan */
722  ExecutorRun(queryDesc, dir, 0, true);
723 
724  /* run cleanup too */
725  ExecutorFinish(queryDesc);
726 
727  /* We can't run ExecutorEnd 'till we're done printing the stats... */
728  totaltime += elapsed_time(&starttime);
729  }
730 
731  /* grab serialization metrics before we destroy the DestReceiver */
733  serializeMetrics = GetSerializationMetrics(dest);
734 
735  /* call the DestReceiver's destroy method even during explain */
736  dest->rDestroy(dest);
737 
738  ExplainOpenGroup("Query", NULL, true, es);
739 
740  /* Create textual dump of plan tree */
741  ExplainPrintPlan(es, queryDesc);
742 
743  /* Show buffer and/or memory usage in planning */
744  if (peek_buffer_usage(es, bufusage) || mem_counters)
745  {
746  ExplainOpenGroup("Planning", "Planning", true, es);
747 
748  if (es->format == EXPLAIN_FORMAT_TEXT)
749  {
750  ExplainIndentText(es);
751  appendStringInfoString(es->str, "Planning:\n");
752  es->indent++;
753  }
754 
755  if (bufusage)
756  show_buffer_usage(es, bufusage);
757 
758  if (mem_counters)
759  show_memory_counters(es, mem_counters);
760 
761  if (es->format == EXPLAIN_FORMAT_TEXT)
762  es->indent--;
763 
764  ExplainCloseGroup("Planning", "Planning", true, es);
765  }
766 
767  if (es->summary && planduration)
768  {
769  double plantime = INSTR_TIME_GET_DOUBLE(*planduration);
770 
771  ExplainPropertyFloat("Planning Time", "ms", 1000.0 * plantime, 3, es);
772  }
773 
774  /* Print info about runtime of triggers */
775  if (es->analyze)
776  ExplainPrintTriggers(es, queryDesc);
777 
778  /*
779  * Print info about JITing. Tied to es->costs because we don't want to
780  * display this in regression tests, as it'd cause output differences
781  * depending on build options. Might want to separate that out from COSTS
782  * at a later stage.
783  */
784  if (es->costs)
785  ExplainPrintJITSummary(es, queryDesc);
786 
787  /* Print info about serialization of output */
789  ExplainPrintSerialize(es, &serializeMetrics);
790 
791  /*
792  * Close down the query and free resources. Include time for this in the
793  * total execution time (although it should be pretty minimal).
794  */
795  INSTR_TIME_SET_CURRENT(starttime);
796 
797  ExecutorEnd(queryDesc);
798 
799  FreeQueryDesc(queryDesc);
800 
802 
803  /* We need a CCI just in case query expanded to multiple plans */
804  if (es->analyze)
806 
807  totaltime += elapsed_time(&starttime);
808 
809  /*
810  * We only report execution time if we actually ran the query (that is,
811  * the user specified ANALYZE), and if summary reporting is enabled (the
812  * user can set SUMMARY OFF to not have the timing information included in
813  * the output). By default, ANALYZE sets SUMMARY to true.
814  */
815  if (es->summary && es->analyze)
816  ExplainPropertyFloat("Execution Time", "ms", 1000.0 * totaltime, 3,
817  es);
818 
819  ExplainCloseGroup("Query", NULL, true, es);
820 }
DestReceiver * CreateIntoRelDestReceiver(IntoClause *intoClause)
Definition: createas.c:438
int GetIntoRelEFlags(IntoClause *intoClause)
Definition: createas.c:373
DestReceiver * None_Receiver
Definition: dest.c:96
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:465
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:405
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:120
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:295
#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:5876
static bool peek_buffer_usage(ExplainState *es, const BufferUsage *usage)
Definition: explain.c:4023
void ExplainPrintJITSummary(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:1017
static double elapsed_time(instr_time *starttime)
Definition: explain.c:1305
static void show_memory_counters(ExplainState *es, const MemoryContextCounters *mem_counters)
Definition: explain.c:4270
void ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:897
static void ExplainPrintSerialize(ExplainState *es, SerializeMetrics *metrics)
Definition: explain.c:1141
void ExplainPrintTriggers(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:974
static SerializeMetrics GetSerializationMetrics(DestReceiver *dest)
Definition: explain.c:5901
@ 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:1099

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,
ParseState pstate,
ParamListInfo  params 
)
static

Definition at line 436 of file explain.c.

439 {
440  /* planner will not cope with utility statements */
441  if (query->commandType == CMD_UTILITY)
442  {
443  ExplainOneUtility(query->utilityStmt, into, es, pstate, params);
444  return;
445  }
446 
447  /* if an advisor plugin is present, let it manage things */
449  (*ExplainOneQuery_hook) (query, cursorOptions, into, es,
450  pstate->p_sourcetext, params, pstate->p_queryEnv);
451  else
452  standard_ExplainOneQuery(query, cursorOptions, into, es,
453  pstate->p_sourcetext, params, pstate->p_queryEnv);
454 }
ExplainOneQuery_hook_type ExplainOneQuery_hook
Definition: explain.c:46
void ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, ParseState *pstate, ParamListInfo params)
Definition: explain.c:533
void standard_ExplainOneQuery(Query *query, int cursorOptions, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: explain.c:461
QueryEnvironment * p_queryEnv
Definition: parse_node.h:239
const char * p_sourcetext
Definition: parse_node.h:209
CmdType commandType
Definition: parsenodes.h:121
Node * utilityStmt
Definition: parsenodes.h:136

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

Referenced by ExplainOneUtility(), and ExplainQuery().

◆ ExplainOneUtility()

void ExplainOneUtility ( Node utilityStmt,
IntoClause into,
ExplainState es,
ParseState pstate,
ParamListInfo  params 
)

Definition at line 533 of file explain.c.

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

References appendStringInfoString(), Assert, castNode, copyObject, CreateTableAsRelExists(), CURSOR_OPT_PARALLEL_OK, elog, ERROR, EXPLAIN_FORMAT_TEXT, ExplainDummyGroup(), ExplainExecuteQuery(), ExplainOneQuery(), ExplainState::format, CreateTableAsStmt::into, IsA, IsQueryIdEnabled(), JumbleQuery(), linitial_node, list_length(), OBJECT_MATVIEW, OBJECT_TABLE, CreateTableAsStmt::objtype, DeclareCursorStmt::options, post_parse_analyze_hook, 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 5187 of file explain.c.

5189 {
5190  switch (es->format)
5191  {
5192  case EXPLAIN_FORMAT_TEXT:
5193  /* nothing to do */
5194  break;
5195 
5196  case EXPLAIN_FORMAT_XML:
5197  ExplainXMLTag(objtype, X_OPENING, es);
5198  es->indent++;
5199  break;
5200 
5201  case EXPLAIN_FORMAT_JSON:
5203  appendStringInfoSpaces(es->str, 2 * es->indent);
5204  if (labelname)
5205  {
5206  escape_json(es->str, labelname);
5207  appendStringInfoString(es->str, ": ");
5208  }
5209  appendStringInfoChar(es->str, labeled ? '{' : '[');
5210 
5211  /*
5212  * In JSON format, the grouping_stack is an integer list. 0 means
5213  * we've emitted nothing at this grouping level, 1 means we've
5214  * emitted something (and so the next item needs a comma). See
5215  * ExplainJSONLineEnding().
5216  */
5217  es->grouping_stack = lcons_int(0, es->grouping_stack);
5218  es->indent++;
5219  break;
5220 
5221  case EXPLAIN_FORMAT_YAML:
5222 
5223  /*
5224  * In YAML format, the grouping stack is an integer list. 0 means
5225  * we've emitted nothing at this grouping level AND this grouping
5226  * level is unlabeled and must be marked with "- ". See
5227  * ExplainYAMLLineStarting().
5228  */
5230  if (labelname)
5231  {
5232  appendStringInfo(es->str, "%s: ", labelname);
5233  es->grouping_stack = lcons_int(1, es->grouping_stack);
5234  }
5235  else
5236  {
5237  appendStringInfoString(es->str, "- ");
5238  es->grouping_stack = lcons_int(0, es->grouping_stack);
5239  }
5240  es->indent++;
5241  break;
5242  }
5243 }
#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 5297 of file explain.c.

5299 {
5300  switch (es->format)
5301  {
5302  case EXPLAIN_FORMAT_TEXT:
5303  /* nothing to do */
5304  break;
5305 
5306  case EXPLAIN_FORMAT_XML:
5307  es->indent += depth;
5308  break;
5309 
5310  case EXPLAIN_FORMAT_JSON:
5311  es->grouping_stack = lcons_int(0, es->grouping_stack);
5312  es->indent += depth;
5313  break;
5314 
5315  case EXPLAIN_FORMAT_YAML:
5316  if (labelname)
5317  es->grouping_stack = lcons_int(1, es->grouping_stack);
5318  else
5319  es->grouping_stack = lcons_int(0, es->grouping_stack);
5320  es->indent += depth;
5321  break;
5322  }
5323 }

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 4818 of file explain.c.

4819 {
4820  ExplainWorkersState *wstate = es->workers_state;
4821 
4822  Assert(wstate);
4823  Assert(n >= 0 && n < wstate->num_workers);
4824 
4825  /* Save prior output buffer pointer */
4826  wstate->prev_str = es->str;
4827 
4828  if (!wstate->worker_inited[n])
4829  {
4830  /* First time through, so create the buffer for this worker */
4831  initStringInfo(&wstate->worker_str[n]);
4832  es->str = &wstate->worker_str[n];
4833 
4834  /*
4835  * Push suitable initial formatting state for this worker's field
4836  * group. We allow one extra logical nesting level, since this group
4837  * will eventually be wrapped in an outer "Workers" group.
4838  */
4839  ExplainOpenSetAsideGroup("Worker", NULL, true, 2, es);
4840 
4841  /*
4842  * In non-TEXT formats we always emit a "Worker Number" field, even if
4843  * there's no other data for this worker.
4844  */
4845  if (es->format != EXPLAIN_FORMAT_TEXT)
4846  ExplainPropertyInteger("Worker Number", NULL, n, es);
4847 
4848  wstate->worker_inited[n] = true;
4849  }
4850  else
4851  {
4852  /* Resuming output for a worker we've already emitted some data for */
4853  es->str = &wstate->worker_str[n];
4854 
4855  /* Restore formatting state saved by last ExplainCloseWorker() */
4856  ExplainRestoreGroup(es, 2, &wstate->worker_state_save[n]);
4857  }
4858 
4859  /*
4860  * In TEXT format, prefix the first output line for this worker with
4861  * "Worker N:". Then, any additional lines should be indented one more
4862  * stop than the "Worker N" line is.
4863  */
4864  if (es->format == EXPLAIN_FORMAT_TEXT)
4865  {
4866  if (es->str->len == 0)
4867  {
4868  ExplainIndentText(es);
4869  appendStringInfo(es->str, "Worker %d: ", n);
4870  }
4871 
4872  es->indent++;
4873  }
4874 }
static void ExplainRestoreGroup(ExplainState *es, int depth, int *state_save)
Definition: explain.c:5366
static void ExplainOpenSetAsideGroup(const char *objtype, const char *labelname, bool labeled, int depth, ExplainState *es)
Definition: explain.c:5297
void initStringInfo(StringInfo str)
Definition: stringinfo.c:56

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 1324 of file explain.c.

1325 {
1326  Plan *plan = planstate->plan;
1327 
1328  switch (nodeTag(plan))
1329  {
1330  case T_SeqScan:
1331  case T_SampleScan:
1332  case T_IndexScan:
1333  case T_IndexOnlyScan:
1334  case T_BitmapHeapScan:
1335  case T_TidScan:
1336  case T_TidRangeScan:
1337  case T_SubqueryScan:
1338  case T_FunctionScan:
1339  case T_TableFuncScan:
1340  case T_ValuesScan:
1341  case T_CteScan:
1342  case T_NamedTuplestoreScan:
1343  case T_WorkTableScan:
1344  *rels_used = bms_add_member(*rels_used,
1345  ((Scan *) plan)->scanrelid);
1346  break;
1347  case T_ForeignScan:
1348  *rels_used = bms_add_members(*rels_used,
1349  ((ForeignScan *) plan)->fs_base_relids);
1350  break;
1351  case T_CustomScan:
1352  *rels_used = bms_add_members(*rels_used,
1353  ((CustomScan *) plan)->custom_relids);
1354  break;
1355  case T_ModifyTable:
1356  *rels_used = bms_add_member(*rels_used,
1357  ((ModifyTable *) plan)->nominalRelation);
1358  if (((ModifyTable *) plan)->exclRelRTI)
1359  *rels_used = bms_add_member(*rels_used,
1360  ((ModifyTable *) plan)->exclRelRTI);
1361  break;
1362  case T_Append:
1363  *rels_used = bms_add_members(*rels_used,
1364  ((Append *) plan)->apprelids);
1365  break;
1366  case T_MergeAppend:
1367  *rels_used = bms_add_members(*rels_used,
1368  ((MergeAppend *) plan)->apprelids);
1369  break;
1370  default:
1371  break;
1372  }
1373 
1374  return planstate_tree_walker(planstate, ExplainPreScanNode, rels_used);
1375 }
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:1324
#define planstate_tree_walker(ps, w, c)
Definition: nodeFuncs.h:179

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 1043 of file explain.c.

1044 {
1045  instr_time total_time;
1046 
1047  /* don't print information if no JITing happened */
1048  if (!ji || ji->created_functions == 0)
1049  return;
1050 
1051  /* calculate total time */
1052  INSTR_TIME_SET_ZERO(total_time);
1053  /* don't add deform_counter, it's included in generation_counter */
1054  INSTR_TIME_ADD(total_time, ji->generation_counter);
1055  INSTR_TIME_ADD(total_time, ji->inlining_counter);
1056  INSTR_TIME_ADD(total_time, ji->optimization_counter);
1057  INSTR_TIME_ADD(total_time, ji->emission_counter);
1058 
1059  ExplainOpenGroup("JIT", "JIT", true, es);
1060 
1061  /* for higher density, open code the text output format */
1062  if (es->format == EXPLAIN_FORMAT_TEXT)
1063  {
1064  ExplainIndentText(es);
1065  appendStringInfoString(es->str, "JIT:\n");
1066  es->indent++;
1067 
1068  ExplainPropertyInteger("Functions", NULL, ji->created_functions, es);
1069 
1070  ExplainIndentText(es);
1071  appendStringInfo(es->str, "Options: %s %s, %s %s, %s %s, %s %s\n",
1072  "Inlining", jit_flags & PGJIT_INLINE ? "true" : "false",
1073  "Optimization", jit_flags & PGJIT_OPT3 ? "true" : "false",
1074  "Expressions", jit_flags & PGJIT_EXPR ? "true" : "false",
1075  "Deforming", jit_flags & PGJIT_DEFORM ? "true" : "false");
1076 
1077  if (es->analyze && es->timing)
1078  {
1079  ExplainIndentText(es);
1080  appendStringInfo(es->str,
1081  "Timing: %s %.3f ms (%s %.3f ms), %s %.3f ms, %s %.3f ms, %s %.3f ms, %s %.3f ms\n",
1082  "Generation", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->generation_counter),
1083  "Deform", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->deform_counter),
1084  "Inlining", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->inlining_counter),
1085  "Optimization", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->optimization_counter),
1086  "Emission", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->emission_counter),
1087  "Total", 1000.0 * INSTR_TIME_GET_DOUBLE(total_time));
1088  }
1089 
1090  es->indent--;
1091  }
1092  else
1093  {
1094  ExplainPropertyInteger("Functions", NULL, ji->created_functions, es);
1095 
1096  ExplainOpenGroup("Options", "Options", true, es);
1097  ExplainPropertyBool("Inlining", jit_flags & PGJIT_INLINE, es);
1098  ExplainPropertyBool("Optimization", jit_flags & PGJIT_OPT3, es);
1099  ExplainPropertyBool("Expressions", jit_flags & PGJIT_EXPR, es);
1100  ExplainPropertyBool("Deforming", jit_flags & PGJIT_DEFORM, es);
1101  ExplainCloseGroup("Options", "Options", true, es);
1102 
1103  if (es->analyze && es->timing)
1104  {
1105  ExplainOpenGroup("Timing", "Timing", true, es);
1106 
1107  ExplainOpenGroup("Generation", "Generation", true, es);
1108  ExplainPropertyFloat("Deform", "ms",
1109  1000.0 * INSTR_TIME_GET_DOUBLE(ji->deform_counter),
1110  3, es);
1111  ExplainPropertyFloat("Total", "ms",
1113  3, es);
1114  ExplainCloseGroup("Generation", "Generation", true, es);
1115 
1116  ExplainPropertyFloat("Inlining", "ms",
1118  3, es);
1119  ExplainPropertyFloat("Optimization", "ms",
1121  3, es);
1122  ExplainPropertyFloat("Emission", "ms",
1124  3, es);
1125  ExplainPropertyFloat("Total", "ms",
1126  1000.0 * INSTR_TIME_GET_DOUBLE(total_time),
1127  3, es);
1128 
1129  ExplainCloseGroup("Timing", "Timing", true, es);
1130  }
1131  }
1132 
1133  ExplainCloseGroup("JIT", "JIT", true, es);
1134 }
#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 1017 of file explain.c.

1018 {
1019  JitInstrumentation ji = {0};
1020 
1021  if (!(queryDesc->estate->es_jit_flags & PGJIT_PERFORM))
1022  return;
1023 
1024  /*
1025  * Work with a copy instead of modifying the leader state, since this
1026  * function may be called twice
1027  */
1028  if (queryDesc->estate->es_jit)
1029  InstrJitAgg(&ji, &queryDesc->estate->es_jit->instr);
1030 
1031  /* If this process has done JIT in parallel workers, merge stats */
1032  if (queryDesc->estate->es_jit_worker_instr)
1033  InstrJitAgg(&ji, queryDesc->estate->es_jit_worker_instr);
1034 
1035  ExplainPrintJIT(es, queryDesc->estate->es_jit_flags, &ji);
1036 }
void InstrJitAgg(JitInstrumentation *dst, JitInstrumentation *add)
Definition: jit.c:182
#define PGJIT_PERFORM
Definition: jit.h:20
struct JitContext * es_jit
Definition: execnodes.h:729
struct JitInstrumentation * es_jit_worker_instr
Definition: execnodes.h:730
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 897 of file explain.c.

898 {
899  Bitmapset *rels_used = NULL;
900  PlanState *ps;
901  ListCell *lc;
902 
903  /* Set up ExplainState fields associated with this plan tree */
904  Assert(queryDesc->plannedstmt != NULL);
905  es->pstmt = queryDesc->plannedstmt;
906  es->rtable = queryDesc->plannedstmt->rtable;
907  ExplainPreScanNode(queryDesc->planstate, &rels_used);
910  es->rtable_names);
911  es->printed_subplans = NULL;
912  es->rtable_size = list_length(es->rtable);
913  foreach(lc, es->rtable)
914  {
916 
917  if (rte->rtekind == RTE_GROUP)
918  {
919  es->rtable_size--;
920  break;
921  }
922  }
923 
924  /*
925  * Sometimes we mark a Gather node as "invisible", which means that it's
926  * not to be displayed in EXPLAIN output. The purpose of this is to allow
927  * running regression tests with debug_parallel_query=regress to get the
928  * same results as running the same tests with debug_parallel_query=off.
929  * Such marking is currently only supported on a Gather at the top of the
930  * plan. We skip that node, and we must also hide per-worker detail data
931  * further down in the plan tree.
932  */
933  ps = queryDesc->planstate;
934  if (IsA(ps, GatherState) && ((Gather *) ps->plan)->invisible)
935  {
936  ps = outerPlanState(ps);
937  es->hide_workers = true;
938  }
939  ExplainNode(ps, NIL, NULL, NULL, es);
940 
941  /*
942  * If requested, include information about GUC parameters with values that
943  * don't match the built-in defaults.
944  */
946 
947  /*
948  * COMPUTE_QUERY_ID_REGRESS means COMPUTE_QUERY_ID_AUTO, but we don't show
949  * the queryid in any of the EXPLAIN plans to keep stable the results
950  * generated by regression test suites.
951  */
952  if (es->verbose && queryDesc->plannedstmt->queryId != UINT64CONST(0) &&
954  {
955  /*
956  * Output the queryid as an int64 rather than a uint64 so we match
957  * what would be seen in the BIGINT pg_stat_statements.queryid column.
958  */
959  ExplainPropertyInteger("Query Identifier", NULL, (int64)
960  queryDesc->plannedstmt->queryId, es);
961  }
962 }
static void ExplainPrintSettings(ExplainState *es)
Definition: explain.c:827
struct parser_state ps
@ RTE_GROUP
Definition: parsenodes.h:1028
#define lfirst_node(type, lc)
Definition: pg_list.h:176
@ 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:3813
List * deparse_context_for_plan_tree(PlannedStmt *pstmt, List *rtable_names)
Definition: ruleutils.c:3721
int rtable_size
Definition: explain.h:70
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
RTEKind rtekind
Definition: parsenodes.h:1047

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, lfirst_node, list_length(), NIL, outerPlanState, QueryDesc::plannedstmt, QueryDesc::planstate, ExplainState::printed_subplans, ps, ExplainState::pstmt, PlannedStmt::queryId, ExplainState::rtable, PlannedStmt::rtable, ExplainState::rtable_names, ExplainState::rtable_size, RTE_GROUP, RangeTblEntry::rtekind, 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 1141 of file explain.c.

1142 {
1143  const char *format;
1144 
1145  /* We shouldn't get called for EXPLAIN_SERIALIZE_NONE */
1146  if (es->serialize == EXPLAIN_SERIALIZE_TEXT)
1147  format = "text";
1148  else
1149  {
1151  format = "binary";
1152  }
1153 
1154  ExplainOpenGroup("Serialization", "Serialization", true, es);
1155 
1156  if (es->format == EXPLAIN_FORMAT_TEXT)
1157  {
1158  ExplainIndentText(es);
1159  if (es->timing)
1160  appendStringInfo(es->str, "Serialization: time=%.3f ms output=" UINT64_FORMAT "kB format=%s\n",
1161  1000.0 * INSTR_TIME_GET_DOUBLE(metrics->timeSpent),
1162  BYTES_TO_KILOBYTES(metrics->bytesSent),
1163  format);
1164  else
1165  appendStringInfo(es->str, "Serialization: output=" UINT64_FORMAT "kB format=%s\n",
1166  BYTES_TO_KILOBYTES(metrics->bytesSent),
1167  format);
1168 
1169  if (es->buffers && peek_buffer_usage(es, &metrics->bufferUsage))
1170  {
1171  es->indent++;
1172  show_buffer_usage(es, &metrics->bufferUsage);
1173  es->indent--;
1174  }
1175  }
1176  else
1177  {
1178  if (es->timing)
1179  ExplainPropertyFloat("Time", "ms",
1180  1000.0 * INSTR_TIME_GET_DOUBLE(metrics->timeSpent),
1181  3, es);
1182  ExplainPropertyUInteger("Output Volume", "kB",
1183  BYTES_TO_KILOBYTES(metrics->bytesSent), es);
1184  ExplainPropertyText("Format", format, es);
1185  if (es->buffers)
1186  show_buffer_usage(es, &metrics->bufferUsage);
1187  }
1188 
1189  ExplainCloseGroup("Serialization", "Serialization", true, es);
1190 }
#define UINT64_FORMAT
Definition: c.h:540
#define BYTES_TO_KILOBYTES(b)
Definition: explain.c:70
void ExplainPropertyUInteger(const char *qlabel, const char *unit, uint64 value, ExplainState *es)
Definition: explain.c:5144
@ 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 827 of file explain.c.

828 {
829  int num;
830  struct config_generic **gucs;
831 
832  /* bail out if information about settings not requested */
833  if (!es->settings)
834  return;
835 
836  /* request an array of relevant settings */
837  gucs = get_explain_guc_options(&num);
838 
839  if (es->format != EXPLAIN_FORMAT_TEXT)
840  {
841  ExplainOpenGroup("Settings", "Settings", true, es);
842 
843  for (int i = 0; i < num; i++)
844  {
845  char *setting;
846  struct config_generic *conf = gucs[i];
847 
848  setting = GetConfigOptionByName(conf->name, NULL, true);
849 
850  ExplainPropertyText(conf->name, setting, es);
851  }
852 
853  ExplainCloseGroup("Settings", "Settings", true, es);
854  }
855  else
856  {
858 
859  /* In TEXT mode, print nothing if there are no options */
860  if (num <= 0)
861  return;
862 
864 
865  for (int i = 0; i < num; i++)
866  {
867  char *setting;
868  struct config_generic *conf = gucs[i];
869 
870  if (i > 0)
871  appendStringInfoString(&str, ", ");
872 
873  setting = GetConfigOptionByName(conf->name, NULL, true);
874 
875  if (setting)
876  appendStringInfo(&str, "%s = '%s'", conf->name, setting);
877  else
878  appendStringInfo(&str, "%s = NULL", conf->name);
879  }
880 
881  ExplainPropertyText("Settings", str.data, es);
882  }
883 }
struct config_generic ** get_explain_guc_options(int *num)
Definition: guc.c:5290
char * GetConfigOptionByName(const char *name, const char **varname, bool missing_ok)
Definition: guc.c:5391
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 974 of file explain.c.

975 {
976  ResultRelInfo *rInfo;
977  bool show_relname;
978  List *resultrels;
979  List *routerels;
980  List *targrels;
981  ListCell *l;
982 
983  resultrels = queryDesc->estate->es_opened_result_relations;
984  routerels = queryDesc->estate->es_tuple_routing_result_relations;
985  targrels = queryDesc->estate->es_trig_target_relations;
986 
987  ExplainOpenGroup("Triggers", "Triggers", false, es);
988 
989  show_relname = (list_length(resultrels) > 1 ||
990  routerels != NIL || targrels != NIL);
991  foreach(l, resultrels)
992  {
993  rInfo = (ResultRelInfo *) lfirst(l);
994  report_triggers(rInfo, show_relname, es);
995  }
996 
997  foreach(l, routerels)
998  {
999  rInfo = (ResultRelInfo *) lfirst(l);
1000  report_triggers(rInfo, show_relname, es);
1001  }
1002 
1003  foreach(l, targrels)
1004  {
1005  rInfo = (ResultRelInfo *) lfirst(l);
1006  report_triggers(rInfo, show_relname, es);
1007  }
1008 
1009  ExplainCloseGroup("Triggers", "Triggers", false, es);
1010 }
static void report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
Definition: explain.c:1234
List * es_tuple_routing_result_relations
Definition: execnodes.h:663
List * es_trig_target_relations
Definition: execnodes.h:666
List * es_opened_result_relations
Definition: execnodes.h:653

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 5069 of file explain.c.

5071 {
5072  switch (es->format)
5073  {
5074  case EXPLAIN_FORMAT_TEXT:
5075  ExplainIndentText(es);
5076  if (unit)
5077  appendStringInfo(es->str, "%s: %s %s\n", qlabel, value, unit);
5078  else
5079  appendStringInfo(es->str, "%s: %s\n", qlabel, value);
5080  break;
5081 
5082  case EXPLAIN_FORMAT_XML:
5083  {
5084  char *str;
5085 
5086  appendStringInfoSpaces(es->str, es->indent * 2);
5087  ExplainXMLTag(qlabel, X_OPENING | X_NOWHITESPACE, es);
5088  str = escape_xml(value);
5090  pfree(str);
5091  ExplainXMLTag(qlabel, X_CLOSING | X_NOWHITESPACE, es);
5092  appendStringInfoChar(es->str, '\n');
5093  }
5094  break;
5095 
5096  case EXPLAIN_FORMAT_JSON:
5098  appendStringInfoSpaces(es->str, es->indent * 2);
5099  escape_json(es->str, qlabel);
5100  appendStringInfoString(es->str, ": ");
5101  if (numeric)
5103  else
5104  escape_json(es->str, value);
5105  break;
5106 
5107  case EXPLAIN_FORMAT_YAML:
5109  appendStringInfo(es->str, "%s: ", qlabel);
5110  if (numeric)
5112  else
5113  escape_yaml(es->str, value);
5114  break;
5115  }
5116 }
#define X_NOWHITESPACE
Definition: explain.c:64
static struct @160 value
char * escape_xml(const char *str)
Definition: xml.c:2695

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 5172 of file explain.c.

5173 {
5174  ExplainProperty(qlabel, NULL, value ? "true" : "false", true, es);
5175 }
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:5069

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 5158 of file explain.c.

5160 {
5161  char *buf;
5162 
5163  buf = psprintf("%.*f", ndigits, value);
5164  ExplainProperty(qlabel, unit, buf, true, es);
5165  pfree(buf);
5166 }

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 4946 of file explain.c.

4947 {
4948  ListCell *lc;
4949  bool first = true;
4950 
4951  switch (es->format)
4952  {
4953  case EXPLAIN_FORMAT_TEXT:
4954  ExplainIndentText(es);
4955  appendStringInfo(es->str, "%s: ", qlabel);
4956  foreach(lc, data)
4957  {
4958  if (!first)
4959  appendStringInfoString(es->str, ", ");
4960  appendStringInfoString(es->str, (const char *) lfirst(lc));
4961  first = false;
4962  }
4963  appendStringInfoChar(es->str, '\n');
4964  break;
4965 
4966  case EXPLAIN_FORMAT_XML:
4967  ExplainXMLTag(qlabel, X_OPENING, es);
4968  foreach(lc, data)
4969  {
4970  char *str;
4971 
4972  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
4973  appendStringInfoString(es->str, "<Item>");
4974  str = escape_xml((const char *) lfirst(lc));
4976  pfree(str);
4977  appendStringInfoString(es->str, "</Item>\n");
4978  }
4979  ExplainXMLTag(qlabel, X_CLOSING, es);
4980  break;
4981 
4982  case EXPLAIN_FORMAT_JSON:
4984  appendStringInfoSpaces(es->str, es->indent * 2);
4985  escape_json(es->str, qlabel);
4986  appendStringInfoString(es->str, ": [");
4987  foreach(lc, data)
4988  {
4989  if (!first)
4990  appendStringInfoString(es->str, ", ");
4991  escape_json(es->str, (const char *) lfirst(lc));
4992  first = false;
4993  }
4994  appendStringInfoChar(es->str, ']');
4995  break;
4996 
4997  case EXPLAIN_FORMAT_YAML:
4999  appendStringInfo(es->str, "%s: ", qlabel);
5000  foreach(lc, data)
5001  {
5002  appendStringInfoChar(es->str, '\n');
5003  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
5004  appendStringInfoString(es->str, "- ");
5005  escape_yaml(es->str, (const char *) lfirst(lc));
5006  }
5007  break;
5008  }
5009 }
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 5016 of file explain.c.

5017 {
5018  ListCell *lc;
5019  bool first = true;
5020 
5021  switch (es->format)
5022  {
5023  case EXPLAIN_FORMAT_TEXT:
5024  case EXPLAIN_FORMAT_XML:
5025  ExplainPropertyList(qlabel, data, es);
5026  return;
5027 
5028  case EXPLAIN_FORMAT_JSON:
5030  appendStringInfoSpaces(es->str, es->indent * 2);
5031  appendStringInfoChar(es->str, '[');
5032  foreach(lc, data)
5033  {
5034  if (!first)
5035  appendStringInfoString(es->str, ", ");
5036  escape_json(es->str, (const char *) lfirst(lc));
5037  first = false;
5038  }
5039  appendStringInfoChar(es->str, ']');
5040  break;
5041 
5042  case EXPLAIN_FORMAT_YAML:
5044  appendStringInfoString(es->str, "- [");
5045  foreach(lc, data)
5046  {
5047  if (!first)
5048  appendStringInfoString(es->str, ", ");
5049  escape_yaml(es->str, (const char *) lfirst(lc));
5050  first = false;
5051  }
5052  appendStringInfoChar(es->str, ']');
5053  break;
5054  }
5055 }
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:4946

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 5144 of file explain.c.

5146 {
5147  char buf[32];
5148 
5149  snprintf(buf, sizeof(buf), UINT64_FORMAT, value);
5150  ExplainProperty(qlabel, unit, buf, true, es);
5151 }

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 191 of file explain.c.

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

1217 {
1218  char *str;
1219 
1220  /* This check is consistent with errdetail_params() */
1221  if (params == NULL || params->numParams <= 0 || maxlen == 0)
1222  return;
1223 
1224  str = BuildParamLogString(params, NULL, maxlen);
1225  if (str && str[0] != '\0')
1226  ExplainPropertyText("Query Parameters", str, es);
1227 }
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 1201 of file explain.c.

1202 {
1203  if (queryDesc->sourceText)
1204  ExplainPropertyText("Query Text", queryDesc->sourceText, es);
1205 }
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 5366 of file explain.c.

5367 {
5368  switch (es->format)
5369  {
5370  case EXPLAIN_FORMAT_TEXT:
5371  /* nothing to do */
5372  break;
5373 
5374  case EXPLAIN_FORMAT_XML:
5375  es->indent += depth;
5376  break;
5377 
5378  case EXPLAIN_FORMAT_JSON:
5379  es->grouping_stack = lcons_int(*state_save, es->grouping_stack);
5380  es->indent += depth;
5381  break;
5382 
5383  case EXPLAIN_FORMAT_YAML:
5384  es->grouping_stack = lcons_int(*state_save, es->grouping_stack);
5385  es->indent += depth;
5386  break;
5387  }
5388 }

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 397 of file explain.c.

398 {
399  TupleDesc tupdesc;
400  ListCell *lc;
401  Oid result_type = TEXTOID;
402 
403  /* Check for XML format option */
404  foreach(lc, stmt->options)
405  {
406  DefElem *opt = (DefElem *) lfirst(lc);
407 
408  if (strcmp(opt->defname, "format") == 0)
409  {
410  char *p = defGetString(opt);
411 
412  if (strcmp(p, "xml") == 0)
413  result_type = XMLOID;
414  else if (strcmp(p, "json") == 0)
415  result_type = JSONOID;
416  else
417  result_type = TEXTOID;
418  /* don't "break", as ExplainQuery will use the last value */
419  }
420  }
421 
422  /* Need a tuple descriptor representing a single TEXT or XML column */
423  tupdesc = CreateTemplateTupleDesc(1);
424  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
425  result_type, -1, 0);
426  return tupdesc;
427 }
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 5336 of file explain.c.

5337 {
5338  switch (es->format)
5339  {
5340  case EXPLAIN_FORMAT_TEXT:
5341  /* nothing to do */
5342  break;
5343 
5344  case EXPLAIN_FORMAT_XML:
5345  es->indent -= depth;
5346  break;
5347 
5348  case EXPLAIN_FORMAT_JSON:
5349  es->indent -= depth;
5350  *state_save = linitial_int(es->grouping_stack);
5352  break;
5353 
5354  case EXPLAIN_FORMAT_YAML:
5355  es->indent -= depth;
5356  *state_save = linitial_int(es->grouping_stack);
5358  break;
5359  }
5360 }

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 4332 of file explain.c.

4333 {
4334  ExplainTargetRel((Plan *) plan, plan->scanrelid, es);
4335 }

References ExplainTargetRel(), and plan.

Referenced by ExplainNode().

◆ ExplainSeparatePlans()

void ExplainSeparatePlans ( ExplainState es)

Definition at line 5503 of file explain.c.

5504 {
5505  switch (es->format)
5506  {
5507  case EXPLAIN_FORMAT_TEXT:
5508  /* add a blank line */
5509  appendStringInfoChar(es->str, '\n');
5510  break;
5511 
5512  case EXPLAIN_FORMAT_XML:
5513  case EXPLAIN_FORMAT_JSON:
5514  case EXPLAIN_FORMAT_YAML:
5515  /* nothing to do */
5516  break;
5517  }
5518 }

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 4736 of file explain.c.

4738 {
4739  ListCell *lst;
4740 
4741  foreach(lst, plans)
4742  {
4743  SubPlanState *sps = (SubPlanState *) lfirst(lst);
4744  SubPlan *sp = sps->subplan;
4745 
4746  /*
4747  * There can be multiple SubPlan nodes referencing the same physical
4748  * subplan (same plan_id, which is its index in PlannedStmt.subplans).
4749  * We should print a subplan only once, so track which ones we already
4750  * printed. This state must be global across the plan tree, since the
4751  * duplicate nodes could be in different plan nodes, eg both a bitmap
4752  * indexscan's indexqual and its parent heapscan's recheck qual. (We
4753  * do not worry too much about which plan node we show the subplan as
4754  * attached to in such cases.)
4755  */
4756  if (bms_is_member(sp->plan_id, es->printed_subplans))
4757  continue;
4759  sp->plan_id);
4760 
4761  /*
4762  * Treat the SubPlan node as an ancestor of the plan node(s) within
4763  * it, so that ruleutils.c can find the referents of subplan
4764  * parameters.
4765  */
4766  ancestors = lcons(sp, ancestors);
4767 
4768  ExplainNode(sps->planstate, ancestors,
4769  relationship, sp->plan_name, es);
4770 
4771  ancestors = list_delete_first(ancestors);
4772  }
4773 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
struct PlanState * planstate
Definition: execnodes.h:974
SubPlan * subplan
Definition: execnodes.h:973
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 4354 of file explain.c.

4355 {
4356  char *objectname = NULL;
4357  char *namespace = NULL;
4358  const char *objecttag = NULL;
4359  RangeTblEntry *rte;
4360  char *refname;
4361 
4362  rte = rt_fetch(rti, es->rtable);
4363  refname = (char *) list_nth(es->rtable_names, rti - 1);
4364  if (refname == NULL)
4365  refname = rte->eref->aliasname;
4366 
4367  switch (nodeTag(plan))
4368  {
4369  case T_SeqScan:
4370  case T_SampleScan:
4371  case T_IndexScan:
4372  case T_IndexOnlyScan:
4373  case T_BitmapHeapScan:
4374  case T_TidScan:
4375  case T_TidRangeScan:
4376  case T_ForeignScan:
4377  case T_CustomScan:
4378  case T_ModifyTable:
4379  /* Assert it's on a real relation */
4380  Assert(rte->rtekind == RTE_RELATION);
4381  objectname = get_rel_name(rte->relid);
4382  if (es->verbose)
4383  namespace = get_namespace_name_or_temp(get_rel_namespace(rte->relid));
4384  objecttag = "Relation Name";
4385  break;
4386  case T_FunctionScan:
4387  {
4388  FunctionScan *fscan = (FunctionScan *) plan;
4389 
4390  /* Assert it's on a RangeFunction */
4391  Assert(rte->rtekind == RTE_FUNCTION);
4392 
4393  /*
4394  * If the expression is still a function call of a single
4395  * function, we can get the real name of the function.
4396  * Otherwise, punt. (Even if it was a single function call
4397  * originally, the optimizer could have simplified it away.)
4398  */
4399  if (list_length(fscan->functions) == 1)
4400  {
4401  RangeTblFunction *rtfunc = (RangeTblFunction *) linitial(fscan->functions);
4402 
4403  if (IsA(rtfunc->funcexpr, FuncExpr))
4404  {
4405  FuncExpr *funcexpr = (FuncExpr *) rtfunc->funcexpr;
4406  Oid funcid = funcexpr->funcid;
4407 
4408  objectname = get_func_name(funcid);
4409  if (es->verbose)
4410  namespace = get_namespace_name_or_temp(get_func_namespace(funcid));
4411  }
4412  }
4413  objecttag = "Function Name";
4414  }
4415  break;
4416  case T_TableFuncScan:
4417  {
4418  TableFunc *tablefunc = ((TableFuncScan *) plan)->tablefunc;
4419 
4420  Assert(rte->rtekind == RTE_TABLEFUNC);
4421  switch (tablefunc->functype)
4422  {
4423  case TFT_XMLTABLE:
4424  objectname = "xmltable";
4425  break;
4426  case TFT_JSON_TABLE:
4427  objectname = "json_table";
4428  break;
4429  default:
4430  elog(ERROR, "invalid TableFunc type %d",
4431  (int) tablefunc->functype);
4432  }
4433  objecttag = "Table Function Name";
4434  }
4435  break;
4436  case T_ValuesScan:
4437  Assert(rte->rtekind == RTE_VALUES);
4438  break;
4439  case T_CteScan:
4440  /* Assert it's on a non-self-reference CTE */
4441  Assert(rte->rtekind == RTE_CTE);
4442  Assert(!rte->self_reference);
4443  objectname = rte->ctename;
4444  objecttag = "CTE Name";
4445  break;
4446  case T_NamedTuplestoreScan:
4448  objectname = rte->enrname;
4449  objecttag = "Tuplestore Name";
4450  break;
4451  case T_WorkTableScan:
4452  /* Assert it's on a self-reference CTE */
4453  Assert(rte->rtekind == RTE_CTE);
4454  Assert(rte->self_reference);
4455  objectname = rte->ctename;
4456  objecttag = "CTE Name";
4457  break;
4458  default:
4459  break;
4460  }
4461 
4462  if (es->format == EXPLAIN_FORMAT_TEXT)
4463  {
4464  appendStringInfoString(es->str, " on");
4465  if (namespace != NULL)
4466  appendStringInfo(es->str, " %s.%s", quote_identifier(namespace),
4467  quote_identifier(objectname));
4468  else if (objectname != NULL)
4469  appendStringInfo(es->str, " %s", quote_identifier(objectname));
4470  if (objectname == NULL || strcmp(refname, objectname) != 0)
4471  appendStringInfo(es->str, " %s", quote_identifier(refname));
4472  }
4473  else
4474  {
4475  if (objecttag != NULL && objectname != NULL)
4476  ExplainPropertyText(objecttag, objectname, es);
4477  if (namespace != NULL)
4478  ExplainPropertyText("Schema", namespace, es);
4479  ExplainPropertyText("Alias", refname, es);
4480  }
4481 }
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:1023
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1024
@ RTE_VALUES
Definition: parsenodes.h:1022
@ RTE_FUNCTION
Definition: parsenodes.h:1020
@ RTE_TABLEFUNC
Definition: parsenodes.h:1021
@ RTE_RELATION
Definition: parsenodes.h:1017
#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:613
char * ctename
Definition: parsenodes.h:1196
char * enrname
Definition: parsenodes.h:1231
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 5532 of file explain.c.

5533 {
5534  const char *s;
5535  const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
5536 
5537  if ((flags & X_NOWHITESPACE) == 0)
5538  appendStringInfoSpaces(es->str, 2 * es->indent);
5539  appendStringInfoCharMacro(es->str, '<');
5540  if ((flags & X_CLOSING) != 0)
5541  appendStringInfoCharMacro(es->str, '/');
5542  for (s = tagname; *s; s++)
5543  appendStringInfoChar(es->str, strchr(valid, *s) ? *s : '-');
5544  if ((flags & X_CLOSE_IMMEDIATE) != 0)
5545  appendStringInfoString(es->str, " /");
5546  appendStringInfoCharMacro(es->str, '>');
5547  if ((flags & X_NOWHITESPACE) == 0)
5548  appendStringInfoCharMacro(es->str, '\n');
5549 }
#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 5901 of file explain.c.

5902 {
5903  SerializeMetrics empty;
5904 
5905  if (dest->mydest == DestExplainSerialize)
5906  return ((SerializeDestReceiver *) dest)->metrics;
5907 
5908  memset(&empty, 0, sizeof(SerializeMetrics));
5910 
5911  return empty;
5912 }

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

Referenced by ExplainOnePlan().

◆ NewExplainState()

ExplainState* NewExplainState ( void  )

Definition at line 380 of file explain.c.

381 {
382  ExplainState *es = (ExplainState *) palloc0(sizeof(ExplainState));
383 
384  /* Set default options (most fields can be left as zeroes). */
385  es->costs = true;
386  /* Prepare output buffer. */
387  es->str = makeStringInfo();
388 
389  return es;
390 }
StringInfo makeStringInfo(void)
Definition: stringinfo.c:38

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 4023 of file explain.c.

4024 {
4025  bool has_shared;
4026  bool has_local;
4027  bool has_temp;
4028  bool has_shared_timing;
4029  bool has_local_timing;
4030  bool has_temp_timing;
4031 
4032  if (usage == NULL)
4033  return false;
4034 
4035  if (es->format != EXPLAIN_FORMAT_TEXT)
4036  return true;
4037 
4038  has_shared = (usage->shared_blks_hit > 0 ||
4039  usage->shared_blks_read > 0 ||
4040  usage->shared_blks_dirtied > 0 ||
4041  usage->shared_blks_written > 0);
4042  has_local = (usage->local_blks_hit > 0 ||
4043  usage->local_blks_read > 0 ||
4044  usage->local_blks_dirtied > 0 ||
4045  usage->local_blks_written > 0);
4046  has_temp = (usage->temp_blks_read > 0 ||
4047  usage->temp_blks_written > 0);
4048  has_shared_timing = (!INSTR_TIME_IS_ZERO(usage->shared_blk_read_time) ||
4049  !INSTR_TIME_IS_ZERO(usage->shared_blk_write_time));
4050  has_local_timing = (!INSTR_TIME_IS_ZERO(usage->local_blk_read_time) ||
4051  !INSTR_TIME_IS_ZERO(usage->local_blk_write_time));
4052  has_temp_timing = (!INSTR_TIME_IS_ZERO(usage->temp_blk_read_time) ||
4053  !INSTR_TIME_IS_ZERO(usage->temp_blk_write_time));
4054 
4055  return has_shared || has_local || has_temp || has_shared_timing ||
4056  has_local_timing || has_temp_timing;
4057 }
#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().

◆ plan_is_disabled()

static bool plan_is_disabled ( Plan plan)
static

Definition at line 1384 of file explain.c.

1385 {
1386  int child_disabled_nodes;
1387 
1388  /* The node is certainly not disabled if this is zero */
1389  if (plan->disabled_nodes == 0)
1390  return false;
1391 
1392  child_disabled_nodes = 0;
1393 
1394  /*
1395  * Handle special nodes first. Children of BitmapOrs and BitmapAnds can't
1396  * be disabled, so no need to handle those specifically.
1397  */
1398  if (IsA(plan, Append))
1399  {
1400  ListCell *lc;
1401  Append *aplan = (Append *) plan;
1402 
1403  /*
1404  * Sum the Append childrens' disabled_nodes. This purposefully
1405  * includes any run-time pruned children. Ignoring those could give
1406  * us the incorrect number of disabled nodes.
1407  */
1408  foreach(lc, aplan->appendplans)
1409  {
1410  Plan *subplan = lfirst(lc);
1411 
1412  child_disabled_nodes += subplan->disabled_nodes;
1413  }
1414  }
1415  else if (IsA(plan, MergeAppend))
1416  {
1417  ListCell *lc;
1418  MergeAppend *maplan = (MergeAppend *) plan;
1419 
1420  /*
1421  * Sum the MergeAppend childrens' disabled_nodes. This purposefully
1422  * includes any run-time pruned children. Ignoring those could give
1423  * us the incorrect number of disabled nodes.
1424  */
1425  foreach(lc, maplan->mergeplans)
1426  {
1427  Plan *subplan = lfirst(lc);
1428 
1429  child_disabled_nodes += subplan->disabled_nodes;
1430  }
1431  }
1432  else if (IsA(plan, SubqueryScan))
1433  child_disabled_nodes += ((SubqueryScan *) plan)->subplan->disabled_nodes;
1434  else if (IsA(plan, CustomScan))
1435  {
1436  ListCell *lc;
1437  CustomScan *cplan = (CustomScan *) plan;
1438 
1439  foreach(lc, cplan->custom_plans)
1440  {
1441  Plan *subplan = lfirst(lc);
1442 
1443  child_disabled_nodes += subplan->disabled_nodes;
1444  }
1445  }
1446  else
1447  {
1448  /*
1449  * Else, sum up disabled_nodes from the plan's inner and outer side.
1450  */
1451  if (outerPlan(plan))
1452  child_disabled_nodes += outerPlan(plan)->disabled_nodes;
1453  if (innerPlan(plan))
1454  child_disabled_nodes += innerPlan(plan)->disabled_nodes;
1455  }
1456 
1457  /*
1458  * It's disabled if the plan's disable_nodes is higher than the sum of its
1459  * child's plan disabled_nodes.
1460  */
1461  if (plan->disabled_nodes > child_disabled_nodes)
1462  return true;
1463 
1464  return false;
1465 }
#define innerPlan(node)
Definition: plannodes.h:182
#define outerPlan(node)
Definition: plannodes.h:183
List * appendplans
Definition: plannodes.h:270
List * custom_plans
Definition: plannodes.h:745
List * mergeplans
Definition: plannodes.h:295
int disabled_nodes
Definition: plannodes.h:128

References Append::appendplans, CustomScan::custom_plans, Plan::disabled_nodes, innerPlan, IsA, lfirst, MergeAppend::mergeplans, outerPlan, and plan.

Referenced by ExplainNode().

◆ report_triggers()

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

Definition at line 1234 of file explain.c.

1235 {
1236  int nt;
1237 
1238  if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
1239  return;
1240  for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
1241  {
1242  Trigger *trig = rInfo->ri_TrigDesc->triggers + nt;
1243  Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
1244  char *relname;
1245  char *conname = NULL;
1246 
1247  /* Must clean up instrumentation state */
1248  InstrEndLoop(instr);
1249 
1250  /*
1251  * We ignore triggers that were never invoked; they likely aren't
1252  * relevant to the current query type.
1253  */
1254  if (instr->ntuples == 0)
1255  continue;
1256 
1257  ExplainOpenGroup("Trigger", NULL, true, es);
1258 
1260  if (OidIsValid(trig->tgconstraint))
1261  conname = get_constraint_name(trig->tgconstraint);
1262 
1263  /*
1264  * In text format, we avoid printing both the trigger name and the
1265  * constraint name unless VERBOSE is specified. In non-text formats
1266  * we just print everything.
1267  */
1268  if (es->format == EXPLAIN_FORMAT_TEXT)
1269  {
1270  if (es->verbose || conname == NULL)
1271  appendStringInfo(es->str, "Trigger %s", trig->tgname);
1272  else
1273  appendStringInfoString(es->str, "Trigger");
1274  if (conname)
1275  appendStringInfo(es->str, " for constraint %s", conname);
1276  if (show_relname)
1277  appendStringInfo(es->str, " on %s", relname);
1278  if (es->timing)
1279  appendStringInfo(es->str, ": time=%.3f calls=%.0f\n",
1280  1000.0 * instr->total, instr->ntuples);
1281  else
1282  appendStringInfo(es->str, ": calls=%.0f\n", instr->ntuples);
1283  }
1284  else
1285  {
1286  ExplainPropertyText("Trigger Name", trig->tgname, es);
1287  if (conname)
1288  ExplainPropertyText("Constraint Name", conname, es);
1289  ExplainPropertyText("Relation", relname, es);
1290  if (es->timing)
1291  ExplainPropertyFloat("Time", "ms", 1000.0 * instr->total, 3,
1292  es);
1293  ExplainPropertyFloat("Calls", NULL, instr->ntuples, 0, es);
1294  }
1295 
1296  if (conname)
1297  pfree(conname);
1298 
1299  ExplainCloseGroup("Trigger", NULL, true, es);
1300  }
1301 }
#define OidIsValid(objectId)
Definition: c.h:766
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:501
Relation ri_RelationDesc
Definition: execnodes.h:459
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:492
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 5654 of file explain.c.

5656 {
5657  /* get rid of any old data */
5658  if (receiver->finfos)
5659  pfree(receiver->finfos);
5660  receiver->finfos = NULL;
5661 
5662  receiver->attrinfo = typeinfo;
5663  receiver->nattrs = nattrs;
5664  if (nattrs <= 0)
5665  return;
5666 
5667  receiver->finfos = (FmgrInfo *) palloc0(nattrs * sizeof(FmgrInfo));
5668 
5669  for (int i = 0; i < nattrs; i++)
5670  {
5671  FmgrInfo *finfo = receiver->finfos + i;
5672  Form_pg_attribute attr = TupleDescAttr(typeinfo, i);
5673  Oid typoutput;
5674  Oid typsend;
5675  bool typisvarlena;
5676 
5677  if (receiver->format == 0)
5678  {
5679  /* wire protocol format text */
5680  getTypeOutputInfo(attr->atttypid,
5681  &typoutput,
5682  &typisvarlena);
5683  fmgr_info(typoutput, finfo);
5684  }
5685  else if (receiver->format == 1)
5686  {
5687  /* wire protocol format binary */
5688  getTypeBinaryOutputInfo(attr->atttypid,
5689  &typsend,
5690  &typisvarlena);
5691  fmgr_info(typsend, finfo);
5692  }
5693  else
5694  ereport(ERROR,
5695  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5696  errmsg("unsupported format code: %d", receiver->format)));
5697  }
5698 }
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:5639
FmgrInfo * finfos
Definition: explain.c:5641
#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 5867 of file explain.c.

5868 {
5869  pfree(self);
5870 }

References pfree().

Referenced by CreateExplainSerializeDestReceiver().

◆ serializeAnalyzeReceive()

static bool serializeAnalyzeReceive ( TupleTableSlot slot,
DestReceiver self 
)
static

Definition at line 5707 of file explain.c.

5708 {
5709  TupleDesc typeinfo = slot->tts_tupleDescriptor;
5710  SerializeDestReceiver *myState = (SerializeDestReceiver *) self;
5711  MemoryContext oldcontext;
5712  StringInfo buf = &myState->buf;
5713  int natts = typeinfo->natts;
5714  instr_time start,
5715  end;
5716  BufferUsage instr_start;
5717 
5718  /* only measure time, buffers if requested */
5719  if (myState->es->timing)
5721  if (myState->es->buffers)
5722  instr_start = pgBufferUsage;
5723 
5724  /* Set or update my derived attribute info, if needed */
5725  if (myState->attrinfo != typeinfo || myState->nattrs != natts)
5726  serialize_prepare_info(myState, typeinfo, natts);
5727 
5728  /* Make sure the tuple is fully deconstructed */
5729  slot_getallattrs(slot);
5730 
5731  /* Switch into per-row context so we can recover memory below */
5732  oldcontext = MemoryContextSwitchTo(myState->tmpcontext);
5733 
5734  /*
5735  * Prepare a DataRow message (note buffer is in per-query context)
5736  *
5737  * Note that we fill a StringInfo buffer the same as printtup() does, so
5738  * as to capture the costs of manipulating the strings accurately.
5739  */
5741 
5742  pq_sendint16(buf, natts);
5743 
5744  /*
5745  * send the attributes of this tuple
5746  */
5747  for (int i = 0; i < natts; i++)
5748  {
5749  FmgrInfo *finfo = myState->finfos + i;
5750  Datum attr = slot->tts_values[i];
5751 
5752  if (slot->tts_isnull[i])
5753  {
5754  pq_sendint32(buf, -1);
5755  continue;
5756  }
5757 
5758  if (myState->format == 0)
5759  {
5760  /* Text output */
5761  char *outputstr;
5762 
5763  outputstr = OutputFunctionCall(finfo, attr);
5764  pq_sendcountedtext(buf, outputstr, strlen(outputstr));
5765  }
5766  else
5767  {
5768  /* Binary output */
5769  bytea *outputbytes;
5770 
5771  outputbytes = SendFunctionCall(finfo, attr);
5772  pq_sendint32(buf, VARSIZE(outputbytes) - VARHDRSZ);
5773  pq_sendbytes(buf, VARDATA(outputbytes),
5774  VARSIZE(outputbytes) - VARHDRSZ);
5775  }
5776  }
5777 
5778  /*
5779  * We mustn't call pq_endmessage_reuse(), since that would actually send
5780  * the data to the client. Just count the data, instead. We can leave
5781  * the buffer alone; it'll be reset on the next iteration (as would also
5782  * happen in printtup()).
5783  */
5784  myState->metrics.bytesSent += buf->len;
5785 
5786  /* Return to caller's context, and flush row's temporary memory */
5787  MemoryContextSwitchTo(oldcontext);
5788  MemoryContextReset(myState->tmpcontext);
5789 
5790  /* Update timing data */
5791  if (myState->es->timing)
5792  {
5794  INSTR_TIME_ACCUM_DIFF(myState->metrics.timeSpent, end, start);
5795  }
5796 
5797  /* Update buffer metrics */
5798  if (myState->es->buffers)
5800  &pgBufferUsage,
5801  &instr_start);
5802 
5803  return true;
5804 }
#define VARHDRSZ
Definition: c.h:683
static void serialize_prepare_info(SerializeDestReceiver *receiver, TupleDesc typeinfo, int nattrs)
Definition: explain.c:5654
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:5637
SerializeMetrics metrics
Definition: explain.c:5644
StringInfoData buf
Definition: explain.c:5643
MemoryContext tmpcontext
Definition: explain.c:5642
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:123
bool * tts_isnull
Definition: tuptable.h:127
Datum * tts_values
Definition: tuptable.h:125
Definition: c.h:678
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,