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 "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
 

Typedefs

typedef struct SerializeMetrics SerializeMetrics
 
typedef struct SerializeDestReceiver SerializeDestReceiver
 

Functions

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

Variables

ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL
 
explain_get_index_name_hook_type explain_get_index_name_hook = NULL
 

Macro Definition Documentation

◆ X_CLOSE_IMMEDIATE

#define X_CLOSE_IMMEDIATE   2

Definition at line 62 of file explain.c.

◆ X_CLOSING

#define X_CLOSING   1

Definition at line 61 of file explain.c.

◆ X_NOWHITESPACE

#define X_NOWHITESPACE   4

Definition at line 63 of file explain.c.

◆ X_OPENING

#define X_OPENING   0

Definition at line 60 of file explain.c.

Typedef Documentation

◆ SerializeDestReceiver

◆ SerializeMetrics

Function Documentation

◆ CreateExplainSerializeDestReceiver()

DestReceiver* CreateExplainSerializeDestReceiver ( ExplainState es)

Definition at line 5549 of file explain.c.

5550 {
5551  SerializeDestReceiver *self;
5552 
5554 
5555  self->pub.receiveSlot = serializeAnalyzeReceive;
5556  self->pub.rStartup = serializeAnalyzeStartup;
5557  self->pub.rShutdown = serializeAnalyzeShutdown;
5558  self->pub.rDestroy = serializeAnalyzeDestroy;
5559  self->pub.mydest = DestExplainSerialize;
5560 
5561  self->es = es;
5562 
5563  return (DestReceiver *) self;
5564 }
@ DestExplainSerialize
Definition: dest.h:99
static void serializeAnalyzeStartup(DestReceiver *self, int operation, TupleDesc typeinfo)
Definition: explain.c:5483
static void serializeAnalyzeDestroy(DestReceiver *self)
Definition: explain.c:5540
static bool serializeAnalyzeReceive(TupleTableSlot *slot, DestReceiver *self)
Definition: explain.c:5380
static void serializeAnalyzeShutdown(DestReceiver *self)
Definition: explain.c:5519
void * palloc0(Size size)
Definition: mcxt.c:1346

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

1267 {
1268  instr_time endtime;
1269 
1270  INSTR_TIME_SET_CURRENT(endtime);
1271  INSTR_TIME_SUBTRACT(endtime, *starttime);
1272  return INSTR_TIME_GET_DOUBLE(endtime);
1273 }
#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 5292 of file explain.c.

5293 {
5294  escape_json(buf, str);
5295 }
const char * str
void escape_json(StringInfo buf, const char *str)
Definition: json.c:1549
static char * buf
Definition: pg_test_fsync.c:73

References buf, escape_json(), and str.

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

◆ explain_get_index_name()

static const char * explain_get_index_name ( Oid  indexId)
static

Definition at line 3672 of file explain.c.

3673 {
3674  const char *result;
3675 
3677  result = (*explain_get_index_name_hook) (indexId);
3678  else
3679  result = NULL;
3680  if (result == NULL)
3681  {
3682  /* default behavior: look it up in the catalogs */
3683  result = get_rel_name(indexId);
3684  if (result == NULL)
3685  elog(ERROR, "cache lookup failed for index %u", indexId);
3686  }
3687  return result;
3688 }
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
explain_get_index_name_hook_type explain_get_index_name_hook
Definition: explain.c:48
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 5116 of file explain.c.

5117 {
5118  switch (es->format)
5119  {
5120  case EXPLAIN_FORMAT_TEXT:
5121  /* nothing to do */
5122  break;
5123 
5124  case EXPLAIN_FORMAT_XML:
5126  "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
5127  es->indent++;
5128  break;
5129 
5130  case EXPLAIN_FORMAT_JSON:
5131  /* top-level structure is an array of plans */
5132  appendStringInfoChar(es->str, '[');
5133  es->grouping_stack = lcons_int(0, es->grouping_stack);
5134  es->indent++;
5135  break;
5136 
5137  case EXPLAIN_FORMAT_YAML:
5138  es->grouping_stack = lcons_int(0, es->grouping_stack);
5139  break;
5140  }
5141 }
@ EXPLAIN_FORMAT_XML
Definition: explain.h:30
@ EXPLAIN_FORMAT_YAML
Definition: explain.h:32
@ EXPLAIN_FORMAT_TEXT
Definition: explain.h:29
@ EXPLAIN_FORMAT_JSON
Definition: explain.h:31
List * lcons_int(int datum, List *list)
Definition: list.c:513
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:182
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
List * grouping_stack
Definition: explain.h:62
StringInfo str
Definition: explain.h:46
ExplainFormat format
Definition: explain.h:59
int indent
Definition: explain.h:61

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

Referenced by explain_ExecutorEnd(), and ExplainQuery().

◆ ExplainCloseGroup()

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

Definition at line 4923 of file explain.c.

4925 {
4926  switch (es->format)
4927  {
4928  case EXPLAIN_FORMAT_TEXT:
4929  /* nothing to do */
4930  break;
4931 
4932  case EXPLAIN_FORMAT_XML:
4933  es->indent--;
4934  ExplainXMLTag(objtype, X_CLOSING, es);
4935  break;
4936 
4937  case EXPLAIN_FORMAT_JSON:
4938  es->indent--;
4939  appendStringInfoChar(es->str, '\n');
4940  appendStringInfoSpaces(es->str, 2 * es->indent);
4941  appendStringInfoChar(es->str, labeled ? '}' : ']');
4943  break;
4944 
4945  case EXPLAIN_FORMAT_YAML:
4946  es->indent--;
4948  break;
4949  }
4950 }
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:5205
#define X_CLOSING
Definition: explain.c:61
List * list_delete_first(List *list)
Definition: list.c:943
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:212

References appendStringInfoChar(), appendStringInfoSpaces(), EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainXMLTag(), ExplainState::format, ExplainState::grouping_stack, ExplainState::indent, list_delete_first(), ExplainState::str, and X_CLOSING.

Referenced by ExplainFlushWorkersState(), ExplainNode(), ExplainOnePlan(), ExplainPrintJIT(), ExplainPrintSerialize(), ExplainPrintSettings(), ExplainPrintTriggers(), report_triggers(), show_grouping_set_keys(), show_grouping_sets(), show_incremental_sort_group_info(), and show_modifytable_info().

◆ ExplainCloseWorker()

static void ExplainCloseWorker ( int  n,
ExplainState es 
)
static

Definition at line 4553 of file explain.c.

4554 {
4555  ExplainWorkersState *wstate = es->workers_state;
4556 
4557  Assert(wstate);
4558  Assert(n >= 0 && n < wstate->num_workers);
4559  Assert(wstate->worker_inited[n]);
4560 
4561  /*
4562  * Save formatting state in case we do another ExplainOpenWorker(), then
4563  * pop the formatting stack.
4564  */
4565  ExplainSaveGroup(es, 2, &wstate->worker_state_save[n]);
4566 
4567  /*
4568  * In TEXT format, if we didn't actually produce any output line(s) then
4569  * truncate off the partial line emitted by ExplainOpenWorker. (This is
4570  * to avoid bogus output if, say, show_buffer_usage chooses not to print
4571  * anything for the worker.) Also fix up the indent level.
4572  */
4573  if (es->format == EXPLAIN_FORMAT_TEXT)
4574  {
4575  while (es->str->len > 0 && es->str->data[es->str->len - 1] != '\n')
4576  es->str->data[--(es->str->len)] = '\0';
4577 
4578  es->indent--;
4579  }
4580 
4581  /* Restore prior output buffer pointer */
4582  es->str = wstate->prev_str;
4583 }
#define Assert(condition)
Definition: c.h:858
static void ExplainSaveGroup(ExplainState *es, int depth, int *state_save)
Definition: explain.c:5009
ExplainWorkersState * workers_state
Definition: explain.h:71
bool * worker_inited
Definition: explain.h:38
int * worker_state_save
Definition: explain.h:40
StringInfo prev_str
Definition: explain.h:41

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

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

◆ ExplainCreateWorkersState()

static ExplainWorkersState * ExplainCreateWorkersState ( int  num_workers)
static

Definition at line 4474 of file explain.c.

4475 {
4476  ExplainWorkersState *wstate;
4477 
4478  wstate = (ExplainWorkersState *) palloc(sizeof(ExplainWorkersState));
4479  wstate->num_workers = num_workers;
4480  wstate->worker_inited = (bool *) palloc0(num_workers * sizeof(bool));
4481  wstate->worker_str = (StringInfoData *)
4482  palloc0(num_workers * sizeof(StringInfoData));
4483  wstate->worker_state_save = (int *) palloc(num_workers * sizeof(int));
4484  return wstate;
4485 }
void * palloc(Size size)
Definition: mcxt.c:1316
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 4452 of file explain.c.

4453 {
4454  ListCell *cell;
4455  const char *label =
4456  (list_length(css->custom_ps) != 1 ? "children" : "child");
4457 
4458  foreach(cell, css->custom_ps)
4459  ExplainNode((PlanState *) lfirst(cell), ancestors, label, NULL, es);
4460 }
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1360
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:2066

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

5071 {
5072  switch (es->format)
5073  {
5074  case EXPLAIN_FORMAT_TEXT:
5075  /* nothing to do */
5076  break;
5077 
5078  case EXPLAIN_FORMAT_XML:
5079  ExplainXMLTag(objtype, X_CLOSE_IMMEDIATE, es);
5080  break;
5081 
5082  case EXPLAIN_FORMAT_JSON:
5084  appendStringInfoSpaces(es->str, 2 * es->indent);
5085  if (labelname)
5086  {
5087  escape_json(es->str, labelname);
5088  appendStringInfoString(es->str, ": ");
5089  }
5090  escape_json(es->str, objtype);
5091  break;
5092 
5093  case EXPLAIN_FORMAT_YAML:
5095  if (labelname)
5096  {
5097  escape_yaml(es->str, labelname);
5098  appendStringInfoString(es->str, ": ");
5099  }
5100  else
5101  {
5102  appendStringInfoString(es->str, "- ");
5103  }
5104  escape_yaml(es->str, objtype);
5105  break;
5106  }
5107 }
#define X_CLOSE_IMMEDIATE
Definition: explain.c:62
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:5267
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:5247
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:5292

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

5148 {
5149  switch (es->format)
5150  {
5151  case EXPLAIN_FORMAT_TEXT:
5152  /* nothing to do */
5153  break;
5154 
5155  case EXPLAIN_FORMAT_XML:
5156  es->indent--;
5157  appendStringInfoString(es->str, "</explain>");
5158  break;
5159 
5160  case EXPLAIN_FORMAT_JSON:
5161  es->indent--;
5162  appendStringInfoString(es->str, "\n]");
5164  break;
5165 
5166  case EXPLAIN_FORMAT_YAML:
5168  break;
5169  }
5170 }

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

4590 {
4591  ExplainWorkersState *wstate = es->workers_state;
4592 
4593  ExplainOpenGroup("Workers", "Workers", false, es);
4594  for (int i = 0; i < wstate->num_workers; i++)
4595  {
4596  if (wstate->worker_inited[i])
4597  {
4598  /* This must match previous ExplainOpenSetAsideGroup call */
4599  ExplainOpenGroup("Worker", NULL, true, es);
4600  appendStringInfoString(es->str, wstate->worker_str[i].data);
4601  ExplainCloseGroup("Worker", NULL, true, es);
4602 
4603  pfree(wstate->worker_str[i].data);
4604  }
4605  }
4606  ExplainCloseGroup("Workers", "Workers", false, es);
4607 
4608  pfree(wstate->worker_inited);
4609  pfree(wstate->worker_str);
4610  pfree(wstate->worker_state_save);
4611  pfree(wstate);
4612 }
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4860
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:4923
int i
Definition: isn.c:73
void pfree(void *pointer)
Definition: mcxt.c:1520

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

3971 {
3972  const char *indexname = explain_get_index_name(indexid);
3973 
3974  if (es->format == EXPLAIN_FORMAT_TEXT)
3975  {
3976  if (ScanDirectionIsBackward(indexorderdir))
3977  appendStringInfoString(es->str, " Backward");
3978  appendStringInfo(es->str, " using %s", quote_identifier(indexname));
3979  }
3980  else
3981  {
3982  const char *scandir;
3983 
3984  switch (indexorderdir)
3985  {
3986  case BackwardScanDirection:
3987  scandir = "Backward";
3988  break;
3989  case ForwardScanDirection:
3990  scandir = "Forward";
3991  break;
3992  default:
3993  scandir = "???";
3994  break;
3995  }
3996  ExplainPropertyText("Scan Direction", scandir, es);
3997  ExplainPropertyText("Index Name", indexname, es);
3998  }
3999 }
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:4795
static const char * explain_get_index_name(Oid indexId)
Definition: explain.c:3672
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:12623
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:50
@ BackwardScanDirection
Definition: sdir.h:26
@ ForwardScanDirection
Definition: sdir.h:28
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97

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

Referenced by ExplainNode().

◆ ExplainJSONLineEnding()

static void ExplainJSONLineEnding ( ExplainState es)
static

◆ ExplainMemberNodes()

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

Definition at line 4377 of file explain.c.

4379 {
4380  int j;
4381 
4382  for (j = 0; j < nplans; j++)
4383  ExplainNode(planstates[j], ancestors,
4384  "Member", NULL, es);
4385 }
int j
Definition: isn.c:74

References ExplainNode(), and j.

Referenced by ExplainNode().

◆ ExplainMissingMembers()

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

Definition at line 4395 of file explain.c.

4396 {
4397  if (nplans < nchildren || es->format != EXPLAIN_FORMAT_TEXT)
4398  ExplainPropertyInteger("Subplans Removed", NULL,
4399  nchildren - nplans, es);
4400 }
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:4804
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 4018 of file explain.c.

4019 {
4020  ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
4021 }
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:4027
#define plan(x)
Definition: pg_regress.c:162

References ExplainTargetRel(), and plan.

Referenced by ExplainNode().

◆ ExplainNode()

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

Definition at line 1360 of file explain.c.

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

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

◆ ExplainOnePlan()

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

Definition at line 610 of file explain.c.

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

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

Referenced by ExplainExecuteQuery(), and standard_ExplainOneQuery().

◆ ExplainOneQuery()

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

Definition at line 421 of file explain.c.

425 {
426  /* planner will not cope with utility statements */
427  if (query->commandType == CMD_UTILITY)
428  {
429  ExplainOneUtility(query->utilityStmt, into, es, queryString, params,
430  queryEnv);
431  return;
432  }
433 
434  /* if an advisor plugin is present, let it manage things */
436  (*ExplainOneQuery_hook) (query, cursorOptions, into, es,
437  queryString, params, queryEnv);
438  else
439  standard_ExplainOneQuery(query, cursorOptions, into, es,
440  queryString, params, queryEnv);
441 }
ExplainOneQuery_hook_type ExplainOneQuery_hook
Definition: explain.c:45
void ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: explain.c:520
void standard_ExplainOneQuery(Query *query, int cursorOptions, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: explain.c:448
CmdType commandType
Definition: parsenodes.h:121
Node * utilityStmt
Definition: parsenodes.h:136

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

Referenced by ExplainOneUtility(), and ExplainQuery().

◆ ExplainOneUtility()

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

Definition at line 520 of file explain.c.

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

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

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

◆ ExplainOpenGroup()

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

Definition at line 4860 of file explain.c.

4862 {
4863  switch (es->format)
4864  {
4865  case EXPLAIN_FORMAT_TEXT:
4866  /* nothing to do */
4867  break;
4868 
4869  case EXPLAIN_FORMAT_XML:
4870  ExplainXMLTag(objtype, X_OPENING, es);
4871  es->indent++;
4872  break;
4873 
4874  case EXPLAIN_FORMAT_JSON:
4876  appendStringInfoSpaces(es->str, 2 * es->indent);
4877  if (labelname)
4878  {
4879  escape_json(es->str, labelname);
4880  appendStringInfoString(es->str, ": ");
4881  }
4882  appendStringInfoChar(es->str, labeled ? '{' : '[');
4883 
4884  /*
4885  * In JSON format, the grouping_stack is an integer list. 0 means
4886  * we've emitted nothing at this grouping level, 1 means we've
4887  * emitted something (and so the next item needs a comma). See
4888  * ExplainJSONLineEnding().
4889  */
4890  es->grouping_stack = lcons_int(0, es->grouping_stack);
4891  es->indent++;
4892  break;
4893 
4894  case EXPLAIN_FORMAT_YAML:
4895 
4896  /*
4897  * In YAML format, the grouping stack is an integer list. 0 means
4898  * we've emitted nothing at this grouping level AND this grouping
4899  * level is unlabeled and must be marked with "- ". See
4900  * ExplainYAMLLineStarting().
4901  */
4903  if (labelname)
4904  {
4905  appendStringInfo(es->str, "%s: ", labelname);
4906  es->grouping_stack = lcons_int(1, es->grouping_stack);
4907  }
4908  else
4909  {
4910  appendStringInfoString(es->str, "- ");
4911  es->grouping_stack = lcons_int(0, es->grouping_stack);
4912  }
4913  es->indent++;
4914  break;
4915  }
4916 }
#define X_OPENING
Definition: explain.c:60

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

4972 {
4973  switch (es->format)
4974  {
4975  case EXPLAIN_FORMAT_TEXT:
4976  /* nothing to do */
4977  break;
4978 
4979  case EXPLAIN_FORMAT_XML:
4980  es->indent += depth;
4981  break;
4982 
4983  case EXPLAIN_FORMAT_JSON:
4984  es->grouping_stack = lcons_int(0, es->grouping_stack);
4985  es->indent += depth;
4986  break;
4987 
4988  case EXPLAIN_FORMAT_YAML:
4989  if (labelname)
4990  es->grouping_stack = lcons_int(1, es->grouping_stack);
4991  else
4992  es->grouping_stack = lcons_int(0, es->grouping_stack);
4993  es->indent += depth;
4994  break;
4995  }
4996 }

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

4492 {
4493  ExplainWorkersState *wstate = es->workers_state;
4494 
4495  Assert(wstate);
4496  Assert(n >= 0 && n < wstate->num_workers);
4497 
4498  /* Save prior output buffer pointer */
4499  wstate->prev_str = es->str;
4500 
4501  if (!wstate->worker_inited[n])
4502  {
4503  /* First time through, so create the buffer for this worker */
4504  initStringInfo(&wstate->worker_str[n]);
4505  es->str = &wstate->worker_str[n];
4506 
4507  /*
4508  * Push suitable initial formatting state for this worker's field
4509  * group. We allow one extra logical nesting level, since this group
4510  * will eventually be wrapped in an outer "Workers" group.
4511  */
4512  ExplainOpenSetAsideGroup("Worker", NULL, true, 2, es);
4513 
4514  /*
4515  * In non-TEXT formats we always emit a "Worker Number" field, even if
4516  * there's no other data for this worker.
4517  */
4518  if (es->format != EXPLAIN_FORMAT_TEXT)
4519  ExplainPropertyInteger("Worker Number", NULL, n, es);
4520 
4521  wstate->worker_inited[n] = true;
4522  }
4523  else
4524  {
4525  /* Resuming output for a worker we've already emitted some data for */
4526  es->str = &wstate->worker_str[n];
4527 
4528  /* Restore formatting state saved by last ExplainCloseWorker() */
4529  ExplainRestoreGroup(es, 2, &wstate->worker_state_save[n]);
4530  }
4531 
4532  /*
4533  * In TEXT format, prefix the first output line for this worker with
4534  * "Worker N:". Then, any additional lines should be indented one more
4535  * stop than the "Worker N" line is.
4536  */
4537  if (es->format == EXPLAIN_FORMAT_TEXT)
4538  {
4539  if (es->str->len == 0)
4540  {
4541  ExplainIndentText(es);
4542  appendStringInfo(es->str, "Worker %d: ", n);
4543  }
4544 
4545  es->indent++;
4546  }
4547 }
static void ExplainRestoreGroup(ExplainState *es, int depth, int *state_save)
Definition: explain.c:5039
static void ExplainOpenSetAsideGroup(const char *objtype, const char *labelname, bool labeled, int depth, ExplainState *es)
Definition: explain.c:4970
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59

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

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

◆ ExplainPreScanNode()

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

Definition at line 1285 of file explain.c.

1286 {
1287  Plan *plan = planstate->plan;
1288 
1289  switch (nodeTag(plan))
1290  {
1291  case T_SeqScan:
1292  case T_SampleScan:
1293  case T_IndexScan:
1294  case T_IndexOnlyScan:
1295  case T_BitmapHeapScan:
1296  case T_TidScan:
1297  case T_TidRangeScan:
1298  case T_SubqueryScan:
1299  case T_FunctionScan:
1300  case T_TableFuncScan:
1301  case T_ValuesScan:
1302  case T_CteScan:
1303  case T_NamedTuplestoreScan:
1304  case T_WorkTableScan:
1305  *rels_used = bms_add_member(*rels_used,
1306  ((Scan *) plan)->scanrelid);
1307  break;
1308  case T_ForeignScan:
1309  *rels_used = bms_add_members(*rels_used,
1310  ((ForeignScan *) plan)->fs_base_relids);
1311  break;
1312  case T_CustomScan:
1313  *rels_used = bms_add_members(*rels_used,
1314  ((CustomScan *) plan)->custom_relids);
1315  break;
1316  case T_ModifyTable:
1317  *rels_used = bms_add_member(*rels_used,
1318  ((ModifyTable *) plan)->nominalRelation);
1319  if (((ModifyTable *) plan)->exclRelRTI)
1320  *rels_used = bms_add_member(*rels_used,
1321  ((ModifyTable *) plan)->exclRelRTI);
1322  break;
1323  case T_Append:
1324  *rels_used = bms_add_members(*rels_used,
1325  ((Append *) plan)->apprelids);
1326  break;
1327  case T_MergeAppend:
1328  *rels_used = bms_add_members(*rels_used,
1329  ((MergeAppend *) plan)->apprelids);
1330  break;
1331  default:
1332  break;
1333  }
1334 
1335  return planstate_tree_walker(planstate, ExplainPreScanNode, rels_used);
1336 }
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:1285
#define planstate_tree_walker(ps, w, c)
Definition: nodeFuncs.h:177

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

Referenced by ExplainPrintPlan().

◆ ExplainPrintJIT()

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

Definition at line 1004 of file explain.c.

1005 {
1006  instr_time total_time;
1007 
1008  /* don't print information if no JITing happened */
1009  if (!ji || ji->created_functions == 0)
1010  return;
1011 
1012  /* calculate total time */
1013  INSTR_TIME_SET_ZERO(total_time);
1014  /* don't add deform_counter, it's included in generation_counter */
1015  INSTR_TIME_ADD(total_time, ji->generation_counter);
1016  INSTR_TIME_ADD(total_time, ji->inlining_counter);
1017  INSTR_TIME_ADD(total_time, ji->optimization_counter);
1018  INSTR_TIME_ADD(total_time, ji->emission_counter);
1019 
1020  ExplainOpenGroup("JIT", "JIT", true, es);
1021 
1022  /* for higher density, open code the text output format */
1023  if (es->format == EXPLAIN_FORMAT_TEXT)
1024  {
1025  ExplainIndentText(es);
1026  appendStringInfoString(es->str, "JIT:\n");
1027  es->indent++;
1028 
1029  ExplainPropertyInteger("Functions", NULL, ji->created_functions, es);
1030 
1031  ExplainIndentText(es);
1032  appendStringInfo(es->str, "Options: %s %s, %s %s, %s %s, %s %s\n",
1033  "Inlining", jit_flags & PGJIT_INLINE ? "true" : "false",
1034  "Optimization", jit_flags & PGJIT_OPT3 ? "true" : "false",
1035  "Expressions", jit_flags & PGJIT_EXPR ? "true" : "false",
1036  "Deforming", jit_flags & PGJIT_DEFORM ? "true" : "false");
1037 
1038  if (es->analyze && es->timing)
1039  {
1040  ExplainIndentText(es);
1041  appendStringInfo(es->str,
1042  "Timing: %s %.3f ms (%s %.3f ms), %s %.3f ms, %s %.3f ms, %s %.3f ms, %s %.3f ms\n",
1043  "Generation", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->generation_counter),
1044  "Deform", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->deform_counter),
1045  "Inlining", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->inlining_counter),
1046  "Optimization", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->optimization_counter),
1047  "Emission", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->emission_counter),
1048  "Total", 1000.0 * INSTR_TIME_GET_DOUBLE(total_time));
1049  }
1050 
1051  es->indent--;
1052  }
1053  else
1054  {
1055  ExplainPropertyInteger("Functions", NULL, ji->created_functions, es);
1056 
1057  ExplainOpenGroup("Options", "Options", true, es);
1058  ExplainPropertyBool("Inlining", jit_flags & PGJIT_INLINE, es);
1059  ExplainPropertyBool("Optimization", jit_flags & PGJIT_OPT3, es);
1060  ExplainPropertyBool("Expressions", jit_flags & PGJIT_EXPR, es);
1061  ExplainPropertyBool("Deforming", jit_flags & PGJIT_DEFORM, es);
1062  ExplainCloseGroup("Options", "Options", true, es);
1063 
1064  if (es->analyze && es->timing)
1065  {
1066  ExplainOpenGroup("Timing", "Timing", true, es);
1067 
1068  ExplainOpenGroup("Generation", "Generation", true, es);
1069  ExplainPropertyFloat("Deform", "ms",
1070  1000.0 * INSTR_TIME_GET_DOUBLE(ji->deform_counter),
1071  3, es);
1072  ExplainPropertyFloat("Total", "ms",
1074  3, es);
1075  ExplainCloseGroup("Generation", "Generation", true, es);
1076 
1077  ExplainPropertyFloat("Inlining", "ms",
1079  3, es);
1080  ExplainPropertyFloat("Optimization", "ms",
1082  3, es);
1083  ExplainPropertyFloat("Emission", "ms",
1085  3, es);
1086  ExplainPropertyFloat("Total", "ms",
1087  1000.0 * INSTR_TIME_GET_DOUBLE(total_time),
1088  3, es);
1089 
1090  ExplainCloseGroup("Timing", "Timing", true, es);
1091  }
1092  }
1093 
1094  ExplainCloseGroup("JIT", "JIT", true, es);
1095 }
#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 978 of file explain.c.

979 {
980  JitInstrumentation ji = {0};
981 
982  if (!(queryDesc->estate->es_jit_flags & PGJIT_PERFORM))
983  return;
984 
985  /*
986  * Work with a copy instead of modifying the leader state, since this
987  * function may be called twice
988  */
989  if (queryDesc->estate->es_jit)
990  InstrJitAgg(&ji, &queryDesc->estate->es_jit->instr);
991 
992  /* If this process has done JIT in parallel workers, merge stats */
993  if (queryDesc->estate->es_jit_worker_instr)
994  InstrJitAgg(&ji, queryDesc->estate->es_jit_worker_instr);
995 
996  ExplainPrintJIT(es, queryDesc->estate->es_jit_flags, &ji);
997 }
void InstrJitAgg(JitInstrumentation *dst, JitInstrumentation *add)
Definition: jit.c:182
#define PGJIT_PERFORM
Definition: jit.h:20
struct JitContext * es_jit
Definition: execnodes.h:716
struct JitInstrumentation * es_jit_worker_instr
Definition: execnodes.h:717
JitInstrumentation instr
Definition: jit.h:64
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 870 of file explain.c.

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

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

Referenced by explain_ExecutorEnd(), and ExplainOnePlan().

◆ ExplainPrintSerialize()

static void ExplainPrintSerialize ( ExplainState es,
SerializeMetrics metrics 
)
static

Definition at line 1102 of file explain.c.

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

References appendStringInfo(), Assert, ExplainState::buffers, SerializeMetrics::bufferUsage, 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 800 of file explain.c.

801 {
802  int num;
803  struct config_generic **gucs;
804 
805  /* bail out if information about settings not requested */
806  if (!es->settings)
807  return;
808 
809  /* request an array of relevant settings */
810  gucs = get_explain_guc_options(&num);
811 
812  if (es->format != EXPLAIN_FORMAT_TEXT)
813  {
814  ExplainOpenGroup("Settings", "Settings", true, es);
815 
816  for (int i = 0; i < num; i++)
817  {
818  char *setting;
819  struct config_generic *conf = gucs[i];
820 
821  setting = GetConfigOptionByName(conf->name, NULL, true);
822 
823  ExplainPropertyText(conf->name, setting, es);
824  }
825 
826  ExplainCloseGroup("Settings", "Settings", true, es);
827  }
828  else
829  {
831 
832  /* In TEXT mode, print nothing if there are no options */
833  if (num <= 0)
834  return;
835 
837 
838  for (int i = 0; i < num; i++)
839  {
840  char *setting;
841  struct config_generic *conf = gucs[i];
842 
843  if (i > 0)
844  appendStringInfoString(&str, ", ");
845 
846  setting = GetConfigOptionByName(conf->name, NULL, true);
847 
848  if (setting)
849  appendStringInfo(&str, "%s = '%s'", conf->name, setting);
850  else
851  appendStringInfo(&str, "%s = NULL", conf->name);
852  }
853 
854  ExplainPropertyText("Settings", str.data, es);
855  }
856 }
struct config_generic ** get_explain_guc_options(int *num)
Definition: guc.c:5274
char * GetConfigOptionByName(const char *name, const char **varname, bool missing_ok)
Definition: guc.c:5375
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 935 of file explain.c.

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

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

Referenced by explain_ExecutorEnd(), and ExplainOnePlan().

◆ ExplainProperty()

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

Definition at line 4742 of file explain.c.

4744 {
4745  switch (es->format)
4746  {
4747  case EXPLAIN_FORMAT_TEXT:
4748  ExplainIndentText(es);
4749  if (unit)
4750  appendStringInfo(es->str, "%s: %s %s\n", qlabel, value, unit);
4751  else
4752  appendStringInfo(es->str, "%s: %s\n", qlabel, value);
4753  break;
4754 
4755  case EXPLAIN_FORMAT_XML:
4756  {
4757  char *str;
4758 
4759  appendStringInfoSpaces(es->str, es->indent * 2);
4760  ExplainXMLTag(qlabel, X_OPENING | X_NOWHITESPACE, es);
4761  str = escape_xml(value);
4763  pfree(str);
4764  ExplainXMLTag(qlabel, X_CLOSING | X_NOWHITESPACE, es);
4765  appendStringInfoChar(es->str, '\n');
4766  }
4767  break;
4768 
4769  case EXPLAIN_FORMAT_JSON:
4771  appendStringInfoSpaces(es->str, es->indent * 2);
4772  escape_json(es->str, qlabel);
4773  appendStringInfoString(es->str, ": ");
4774  if (numeric)
4776  else
4777  escape_json(es->str, value);
4778  break;
4779 
4780  case EXPLAIN_FORMAT_YAML:
4782  appendStringInfo(es->str, "%s: ", qlabel);
4783  if (numeric)
4785  else
4786  escape_yaml(es->str, value);
4787  break;
4788  }
4789 }
#define X_NOWHITESPACE
Definition: explain.c:63
static struct @155 value
char * escape_xml(const char *str)
Definition: xml.c:2632

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

4846 {
4847  ExplainProperty(qlabel, NULL, value ? "true" : "false", true, es);
4848 }
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:4742

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

4833 {
4834  char *buf;
4835 
4836  buf = psprintf("%.*f", ndigits, value);
4837  ExplainProperty(qlabel, unit, buf, true, es);
4838  pfree(buf);
4839 }

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

4620 {
4621  ListCell *lc;
4622  bool first = true;
4623 
4624  switch (es->format)
4625  {
4626  case EXPLAIN_FORMAT_TEXT:
4627  ExplainIndentText(es);
4628  appendStringInfo(es->str, "%s: ", qlabel);
4629  foreach(lc, data)
4630  {
4631  if (!first)
4632  appendStringInfoString(es->str, ", ");
4633  appendStringInfoString(es->str, (const char *) lfirst(lc));
4634  first = false;
4635  }
4636  appendStringInfoChar(es->str, '\n');
4637  break;
4638 
4639  case EXPLAIN_FORMAT_XML:
4640  ExplainXMLTag(qlabel, X_OPENING, es);
4641  foreach(lc, data)
4642  {
4643  char *str;
4644 
4645  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
4646  appendStringInfoString(es->str, "<Item>");
4647  str = escape_xml((const char *) lfirst(lc));
4649  pfree(str);
4650  appendStringInfoString(es->str, "</Item>\n");
4651  }
4652  ExplainXMLTag(qlabel, X_CLOSING, es);
4653  break;
4654 
4655  case EXPLAIN_FORMAT_JSON:
4657  appendStringInfoSpaces(es->str, es->indent * 2);
4658  escape_json(es->str, qlabel);
4659  appendStringInfoString(es->str, ": [");
4660  foreach(lc, data)
4661  {
4662  if (!first)
4663  appendStringInfoString(es->str, ", ");
4664  escape_json(es->str, (const char *) lfirst(lc));
4665  first = false;
4666  }
4667  appendStringInfoChar(es->str, ']');
4668  break;
4669 
4670  case EXPLAIN_FORMAT_YAML:
4672  appendStringInfo(es->str, "%s: ", qlabel);
4673  foreach(lc, data)
4674  {
4675  appendStringInfoChar(es->str, '\n');
4676  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
4677  appendStringInfoString(es->str, "- ");
4678  escape_yaml(es->str, (const char *) lfirst(lc));
4679  }
4680  break;
4681  }
4682 }
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 4689 of file explain.c.

4690 {
4691  ListCell *lc;
4692  bool first = true;
4693 
4694  switch (es->format)
4695  {
4696  case EXPLAIN_FORMAT_TEXT:
4697  case EXPLAIN_FORMAT_XML:
4698  ExplainPropertyList(qlabel, data, es);
4699  return;
4700 
4701  case EXPLAIN_FORMAT_JSON:
4703  appendStringInfoSpaces(es->str, es->indent * 2);
4704  appendStringInfoChar(es->str, '[');
4705  foreach(lc, data)
4706  {
4707  if (!first)
4708  appendStringInfoString(es->str, ", ");
4709  escape_json(es->str, (const char *) lfirst(lc));
4710  first = false;
4711  }
4712  appendStringInfoChar(es->str, ']');
4713  break;
4714 
4715  case EXPLAIN_FORMAT_YAML:
4717  appendStringInfoString(es->str, "- [");
4718  foreach(lc, data)
4719  {
4720  if (!first)
4721  appendStringInfoString(es->str, ", ");
4722  escape_yaml(es->str, (const char *) lfirst(lc));
4723  first = false;
4724  }
4725  appendStringInfoChar(es->str, ']');
4726  break;
4727  }
4728 }
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:4619

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

4819 {
4820  char buf[32];
4821 
4822  snprintf(buf, sizeof(buf), UINT64_FORMAT, value);
4823  ExplainProperty(qlabel, unit, buf, true, es);
4824 }

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

Referenced by ExplainPrintSerialize(), and show_wal_usage().

◆ ExplainQuery()

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

Definition at line 176 of file explain.c.

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

References ExplainState::analyze, appendStringInfoString(), DefElem::arg, Assert, begin_tup_output_tupdesc(), ExplainState::buffers, castNode, ExplainState::costs, CURSOR_OPT_PARALLEL_OK, StringInfoData::data, defGetBoolean(), defGetString(), DefElem::defname, generate_unaccent_rules::dest, do_text_output_multiline(), do_text_output_oneline, end_tup_output(), ereport, errcode(), errmsg(), ERROR, EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, EXPLAIN_SERIALIZE_BINARY, EXPLAIN_SERIALIZE_NONE, EXPLAIN_SERIALIZE_TEXT, ExplainBeginOutput(), ExplainEndOutput(), ExplainOneQuery(), ExplainResultDesc(), ExplainSeparatePlans(), ExplainState::format, ExplainState::generic, if(), ExplainState::indent, IsQueryIdEnabled(), JumbleQuery(), lfirst, lfirst_node, lnext(), DefElem::location, ExplainState::memory, NewExplainState(), NIL, ParseState::p_queryEnv, ParseState::p_sourcetext, parser_errposition(), pfree(), post_parse_analyze_hook, QueryRewrite(), ExplainState::serialize, ExplainState::settings, stmt, ExplainState::str, ExplainState::summary, ExplainState::timing, TTSOpsVirtual, ExplainState::verbose, and ExplainState::wal.

Referenced by standard_ProcessUtility().

◆ ExplainQueryParameters()

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

Definition at line 1177 of file explain.c.

1178 {
1179  char *str;
1180 
1181  /* This check is consistent with errdetail_params() */
1182  if (params == NULL || params->numParams <= 0 || maxlen == 0)
1183  return;
1184 
1185  str = BuildParamLogString(params, NULL, maxlen);
1186  if (str && str[0] != '\0')
1187  ExplainPropertyText("Query Parameters", str, es);
1188 }
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 1162 of file explain.c.

1163 {
1164  if (queryDesc->sourceText)
1165  ExplainPropertyText("Query Text", queryDesc->sourceText, es);
1166 }
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 5039 of file explain.c.

5040 {
5041  switch (es->format)
5042  {
5043  case EXPLAIN_FORMAT_TEXT:
5044  /* nothing to do */
5045  break;
5046 
5047  case EXPLAIN_FORMAT_XML:
5048  es->indent += depth;
5049  break;
5050 
5051  case EXPLAIN_FORMAT_JSON:
5052  es->grouping_stack = lcons_int(*state_save, es->grouping_stack);
5053  es->indent += depth;
5054  break;
5055 
5056  case EXPLAIN_FORMAT_YAML:
5057  es->grouping_stack = lcons_int(*state_save, es->grouping_stack);
5058  es->indent += depth;
5059  break;
5060  }
5061 }

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

383 {
384  TupleDesc tupdesc;
385  ListCell *lc;
386  Oid result_type = TEXTOID;
387 
388  /* Check for XML format option */
389  foreach(lc, stmt->options)
390  {
391  DefElem *opt = (DefElem *) lfirst(lc);
392 
393  if (strcmp(opt->defname, "format") == 0)
394  {
395  char *p = defGetString(opt);
396 
397  if (strcmp(p, "xml") == 0)
398  result_type = XMLOID;
399  else if (strcmp(p, "json") == 0)
400  result_type = JSONOID;
401  else
402  result_type = TEXTOID;
403  /* don't "break", as ExplainQuery will use the last value */
404  }
405  }
406 
407  /* Need a tuple descriptor representing a single TEXT or XML column */
408  tupdesc = CreateTemplateTupleDesc(1);
409  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
410  result_type, -1, 0);
411  return tupdesc;
412 }
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 5009 of file explain.c.

5010 {
5011  switch (es->format)
5012  {
5013  case EXPLAIN_FORMAT_TEXT:
5014  /* nothing to do */
5015  break;
5016 
5017  case EXPLAIN_FORMAT_XML:
5018  es->indent -= depth;
5019  break;
5020 
5021  case EXPLAIN_FORMAT_JSON:
5022  es->indent -= depth;
5023  *state_save = linitial_int(es->grouping_stack);
5025  break;
5026 
5027  case EXPLAIN_FORMAT_YAML:
5028  es->indent -= depth;
5029  *state_save = linitial_int(es->grouping_stack);
5031  break;
5032  }
5033 }

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

4006 {
4007  ExplainTargetRel((Plan *) plan, plan->scanrelid, es);
4008 }

References ExplainTargetRel(), and plan.

Referenced by ExplainNode().

◆ ExplainSeparatePlans()

void ExplainSeparatePlans ( ExplainState es)

Definition at line 5176 of file explain.c.

5177 {
5178  switch (es->format)
5179  {
5180  case EXPLAIN_FORMAT_TEXT:
5181  /* add a blank line */
5182  appendStringInfoChar(es->str, '\n');
5183  break;
5184 
5185  case EXPLAIN_FORMAT_XML:
5186  case EXPLAIN_FORMAT_JSON:
5187  case EXPLAIN_FORMAT_YAML:
5188  /* nothing to do */
5189  break;
5190  }
5191 }

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

4411 {
4412  ListCell *lst;
4413 
4414  foreach(lst, plans)
4415  {
4416  SubPlanState *sps = (SubPlanState *) lfirst(lst);
4417  SubPlan *sp = sps->subplan;
4418 
4419  /*
4420  * There can be multiple SubPlan nodes referencing the same physical
4421  * subplan (same plan_id, which is its index in PlannedStmt.subplans).
4422  * We should print a subplan only once, so track which ones we already
4423  * printed. This state must be global across the plan tree, since the
4424  * duplicate nodes could be in different plan nodes, eg both a bitmap
4425  * indexscan's indexqual and its parent heapscan's recheck qual. (We
4426  * do not worry too much about which plan node we show the subplan as
4427  * attached to in such cases.)
4428  */
4429  if (bms_is_member(sp->plan_id, es->printed_subplans))
4430  continue;
4432  sp->plan_id);
4433 
4434  /*
4435  * Treat the SubPlan node as an ancestor of the plan node(s) within
4436  * it, so that ruleutils.c can find the referents of subplan
4437  * parameters.
4438  */
4439  ancestors = lcons(sp, ancestors);
4440 
4441  ExplainNode(sps->planstate, ancestors,
4442  relationship, sp->plan_name, es);
4443 
4444  ancestors = list_delete_first(ancestors);
4445  }
4446 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
struct PlanState * planstate
Definition: execnodes.h:961
SubPlan * subplan
Definition: execnodes.h:960
int plan_id
Definition: primnodes.h:1040
char * plan_name
Definition: primnodes.h:1042

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

4028 {
4029  char *objectname = NULL;
4030  char *namespace = NULL;
4031  const char *objecttag = NULL;
4032  RangeTblEntry *rte;
4033  char *refname;
4034 
4035  rte = rt_fetch(rti, es->rtable);
4036  refname = (char *) list_nth(es->rtable_names, rti - 1);
4037  if (refname == NULL)
4038  refname = rte->eref->aliasname;
4039 
4040  switch (nodeTag(plan))
4041  {
4042  case T_SeqScan:
4043  case T_SampleScan:
4044  case T_IndexScan:
4045  case T_IndexOnlyScan:
4046  case T_BitmapHeapScan:
4047  case T_TidScan:
4048  case T_TidRangeScan:
4049  case T_ForeignScan:
4050  case T_CustomScan:
4051  case T_ModifyTable:
4052  /* Assert it's on a real relation */
4053  Assert(rte->rtekind == RTE_RELATION);
4054  objectname = get_rel_name(rte->relid);
4055  if (es->verbose)
4056  namespace = get_namespace_name_or_temp(get_rel_namespace(rte->relid));
4057  objecttag = "Relation Name";
4058  break;
4059  case T_FunctionScan:
4060  {
4061  FunctionScan *fscan = (FunctionScan *) plan;
4062 
4063  /* Assert it's on a RangeFunction */
4064  Assert(rte->rtekind == RTE_FUNCTION);
4065 
4066  /*
4067  * If the expression is still a function call of a single
4068  * function, we can get the real name of the function.
4069  * Otherwise, punt. (Even if it was a single function call
4070  * originally, the optimizer could have simplified it away.)
4071  */
4072  if (list_length(fscan->functions) == 1)
4073  {
4074  RangeTblFunction *rtfunc = (RangeTblFunction *) linitial(fscan->functions);
4075 
4076  if (IsA(rtfunc->funcexpr, FuncExpr))
4077  {
4078  FuncExpr *funcexpr = (FuncExpr *) rtfunc->funcexpr;
4079  Oid funcid = funcexpr->funcid;
4080 
4081  objectname = get_func_name(funcid);
4082  if (es->verbose)
4083  namespace = get_namespace_name_or_temp(get_func_namespace(funcid));
4084  }
4085  }
4086  objecttag = "Function Name";
4087  }
4088  break;
4089  case T_TableFuncScan:
4090  {
4091  TableFunc *tablefunc = ((TableFuncScan *) plan)->tablefunc;
4092 
4093  Assert(rte->rtekind == RTE_TABLEFUNC);
4094  switch (tablefunc->functype)
4095  {
4096  case TFT_XMLTABLE:
4097  objectname = "xmltable";
4098  break;
4099  case TFT_JSON_TABLE:
4100  objectname = "json_table";
4101  break;
4102  default:
4103  elog(ERROR, "invalid TableFunc type %d",
4104  (int) tablefunc->functype);
4105  }
4106  objecttag = "Table Function Name";
4107  }
4108  break;
4109  case T_ValuesScan:
4110  Assert(rte->rtekind == RTE_VALUES);
4111  break;
4112  case T_CteScan:
4113  /* Assert it's on a non-self-reference CTE */
4114  Assert(rte->rtekind == RTE_CTE);
4115  Assert(!rte->self_reference);
4116  objectname = rte->ctename;
4117  objecttag = "CTE Name";
4118  break;
4119  case T_NamedTuplestoreScan:
4121  objectname = rte->enrname;
4122  objecttag = "Tuplestore Name";
4123  break;
4124  case T_WorkTableScan:
4125  /* Assert it's on a self-reference CTE */
4126  Assert(rte->rtekind == RTE_CTE);
4127  Assert(rte->self_reference);
4128  objectname = rte->ctename;
4129  objecttag = "CTE Name";
4130  break;
4131  default:
4132  break;
4133  }
4134 
4135  if (es->format == EXPLAIN_FORMAT_TEXT)
4136  {
4137  appendStringInfoString(es->str, " on");
4138  if (namespace != NULL)
4139  appendStringInfo(es->str, " %s.%s", quote_identifier(namespace),
4140  quote_identifier(objectname));
4141  else if (objectname != NULL)
4142  appendStringInfo(es->str, " %s", quote_identifier(objectname));
4143  if (objectname == NULL || strcmp(refname, objectname) != 0)
4144  appendStringInfo(es->str, " %s", quote_identifier(refname));
4145  }
4146  else
4147  {
4148  if (objecttag != NULL && objectname != NULL)
4149  ExplainPropertyText(objecttag, objectname, es);
4150  if (namespace != NULL)
4151  ExplainPropertyText("Schema", namespace, es);
4152  ExplainPropertyText("Alias", refname, es);
4153  }
4154 }
char * get_namespace_name_or_temp(Oid nspid)
Definition: lsyscache.c:3390
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1952
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1608
Oid get_func_namespace(Oid funcid)
Definition: lsyscache.c:1632
@ RTE_CTE
Definition: parsenodes.h:1034
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1035
@ RTE_VALUES
Definition: parsenodes.h:1033
@ RTE_FUNCTION
Definition: parsenodes.h:1031
@ RTE_TABLEFUNC
Definition: parsenodes.h:1032
@ RTE_RELATION
Definition: parsenodes.h:1028
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define linitial(l)
Definition: pg_list.h:178
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
@ TFT_XMLTABLE
Definition: primnodes.h:99
@ TFT_JSON_TABLE
Definition: primnodes.h:100
Oid funcid
Definition: primnodes.h:720
List * functions
Definition: plannodes.h:612
char * ctename
Definition: parsenodes.h:1206
char * enrname
Definition: parsenodes.h:1241
RTEKind rtekind
Definition: parsenodes.h:1057
TableFuncType functype
Definition: primnodes.h:113

References appendStringInfo(), appendStringInfoString(), Assert, elog, ERROR, EXPLAIN_FORMAT_TEXT, ExplainPropertyText(), ExplainState::format, RangeTblFunction::funcexpr, FuncExpr::funcid, FunctionScan::functions, TableFunc::functype, get_func_name(), get_func_namespace(), get_namespace_name_or_temp(), get_rel_name(), get_rel_namespace(), IsA, linitial, list_length(), list_nth(), nodeTag, plan, quote_identifier(), RangeTblEntry::relid, rt_fetch, ExplainState::rtable, ExplainState::rtable_names, RTE_CTE, RTE_FUNCTION, RTE_NAMEDTUPLESTORE, RTE_RELATION, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, ExplainState::str, TFT_JSON_TABLE, TFT_XMLTABLE, and ExplainState::verbose.

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

◆ ExplainXMLTag()

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

Definition at line 5205 of file explain.c.

5206 {
5207  const char *s;
5208  const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
5209 
5210  if ((flags & X_NOWHITESPACE) == 0)
5211  appendStringInfoSpaces(es->str, 2 * es->indent);
5212  appendStringInfoCharMacro(es->str, '<');
5213  if ((flags & X_CLOSING) != 0)
5214  appendStringInfoCharMacro(es->str, '/');
5215  for (s = tagname; *s; s++)
5216  appendStringInfoChar(es->str, strchr(valid, *s) ? *s : '-');
5217  if ((flags & X_CLOSE_IMMEDIATE) != 0)
5218  appendStringInfoString(es->str, " /");
5219  appendStringInfoCharMacro(es->str, '>');
5220  if ((flags & X_NOWHITESPACE) == 0)
5221  appendStringInfoCharMacro(es->str, '\n');
5222 }
#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 5574 of file explain.c.

5575 {
5576  SerializeMetrics empty;
5577 
5578  if (dest->mydest == DestExplainSerialize)
5579  return ((SerializeDestReceiver *) dest)->metrics;
5580 
5581  memset(&empty, 0, sizeof(SerializeMetrics));
5583 
5584  return empty;
5585 }

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

Referenced by ExplainOnePlan().

◆ NewExplainState()

ExplainState* NewExplainState ( void  )

Definition at line 365 of file explain.c.

366 {
367  ExplainState *es = (ExplainState *) palloc0(sizeof(ExplainState));
368 
369  /* Set default options (most fields can be left as zeroes). */
370  es->costs = true;
371  /* Prepare output buffer. */
372  es->str = makeStringInfo();
373 
374  return es;
375 }
StringInfo makeStringInfo(void)
Definition: stringinfo.c:41

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

Referenced by explain_ExecutorEnd(), and ExplainQuery().

◆ peek_buffer_usage()

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

Definition at line 3696 of file explain.c.

3697 {
3698  bool has_shared;
3699  bool has_local;
3700  bool has_temp;
3701  bool has_shared_timing;
3702  bool has_local_timing;
3703  bool has_temp_timing;
3704 
3705  if (usage == NULL)
3706  return false;
3707 
3708  if (es->format != EXPLAIN_FORMAT_TEXT)
3709  return true;
3710 
3711  has_shared = (usage->shared_blks_hit > 0 ||
3712  usage->shared_blks_read > 0 ||
3713  usage->shared_blks_dirtied > 0 ||
3714  usage->shared_blks_written > 0);
3715  has_local = (usage->local_blks_hit > 0 ||
3716  usage->local_blks_read > 0 ||
3717  usage->local_blks_dirtied > 0 ||
3718  usage->local_blks_written > 0);
3719  has_temp = (usage->temp_blks_read > 0 ||
3720  usage->temp_blks_written > 0);
3721  has_shared_timing = (!INSTR_TIME_IS_ZERO(usage->shared_blk_read_time) ||
3722  !INSTR_TIME_IS_ZERO(usage->shared_blk_write_time));
3723  has_local_timing = (!INSTR_TIME_IS_ZERO(usage->local_blk_read_time) ||
3724  !INSTR_TIME_IS_ZERO(usage->local_blk_write_time));
3725  has_temp_timing = (!INSTR_TIME_IS_ZERO(usage->temp_blk_read_time) ||
3726  !INSTR_TIME_IS_ZERO(usage->temp_blk_write_time));
3727 
3728  return has_shared || has_local || has_temp || has_shared_timing ||
3729  has_local_timing || has_temp_timing;
3730 }
#define INSTR_TIME_IS_ZERO(t)
Definition: instr_time.h:169
static void usage(const char *progname)
Definition: vacuumlo.c:414

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

Referenced by ExplainOnePlan(), and ExplainPrintSerialize().

◆ report_triggers()

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

Definition at line 1195 of file explain.c.

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

References appendStringInfo(), appendStringInfoString(), EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), ExplainOpenGroup(), ExplainPropertyFloat(), ExplainPropertyText(), ExplainState::format, get_constraint_name(), InstrEndLoop(), Instrumentation::ntuples, TriggerDesc::numtriggers, OidIsValid, pfree(), RelationGetRelationName, relname, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigInstrument, ExplainState::str, Trigger::tgconstraint, Trigger::tgname, ExplainState::timing, Instrumentation::total, TriggerDesc::triggers, and ExplainState::verbose.

Referenced by ExplainPrintTriggers().

◆ serialize_prepare_info()

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

Definition at line 5327 of file explain.c.

5329 {
5330  /* get rid of any old data */
5331  if (receiver->finfos)
5332  pfree(receiver->finfos);
5333  receiver->finfos = NULL;
5334 
5335  receiver->attrinfo = typeinfo;
5336  receiver->nattrs = nattrs;
5337  if (nattrs <= 0)
5338  return;
5339 
5340  receiver->finfos = (FmgrInfo *) palloc0(nattrs * sizeof(FmgrInfo));
5341 
5342  for (int i = 0; i < nattrs; i++)
5343  {
5344  FmgrInfo *finfo = receiver->finfos + i;
5345  Form_pg_attribute attr = TupleDescAttr(typeinfo, i);
5346  Oid typoutput;
5347  Oid typsend;
5348  bool typisvarlena;
5349 
5350  if (receiver->format == 0)
5351  {
5352  /* wire protocol format text */
5353  getTypeOutputInfo(attr->atttypid,
5354  &typoutput,
5355  &typisvarlena);
5356  fmgr_info(typoutput, finfo);
5357  }
5358  else if (receiver->format == 1)
5359  {
5360  /* wire protocol format binary */
5361  getTypeBinaryOutputInfo(attr->atttypid,
5362  &typsend,
5363  &typisvarlena);
5364  fmgr_info(typsend, finfo);
5365  }
5366  else
5367  ereport(ERROR,
5368  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5369  errmsg("unsupported format code: %d", receiver->format)));
5370  }
5371 }
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:5312
FmgrInfo * finfos
Definition: explain.c:5314
#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 5540 of file explain.c.

5541 {
5542  pfree(self);
5543 }

References pfree().

Referenced by CreateExplainSerializeDestReceiver().

◆ serializeAnalyzeReceive()

static bool serializeAnalyzeReceive ( TupleTableSlot slot,
DestReceiver self 
)
static

Definition at line 5380 of file explain.c.

5381 {
5382  TupleDesc typeinfo = slot->tts_tupleDescriptor;
5383  SerializeDestReceiver *myState = (SerializeDestReceiver *) self;
5384  MemoryContext oldcontext;
5385  StringInfo buf = &myState->buf;
5386  int natts = typeinfo->natts;
5387  instr_time start,
5388  end;
5389  BufferUsage instr_start;
5390 
5391  /* only measure time, buffers if requested */
5392  if (myState->es->timing)
5394  if (myState->es->buffers)
5395  instr_start = pgBufferUsage;
5396 
5397  /* Set or update my derived attribute info, if needed */
5398  if (myState->attrinfo != typeinfo || myState->nattrs != natts)
5399  serialize_prepare_info(myState, typeinfo, natts);
5400 
5401  /* Make sure the tuple is fully deconstructed */
5402  slot_getallattrs(slot);
5403 
5404  /* Switch into per-row context so we can recover memory below */
5405  oldcontext = MemoryContextSwitchTo(myState->tmpcontext);
5406 
5407  /*
5408  * Prepare a DataRow message (note buffer is in per-query context)
5409  *
5410  * Note that we fill a StringInfo buffer the same as printtup() does, so
5411  * as to capture the costs of manipulating the strings accurately.
5412  */
5413  pq_beginmessage_reuse(buf, 'D');
5414 
5415  pq_sendint16(buf, natts);
5416 
5417  /*
5418  * send the attributes of this tuple
5419  */
5420  for (int i = 0; i < natts; i++)
5421  {
5422  FmgrInfo *finfo = myState->finfos + i;
5423  Datum attr = slot->tts_values[i];
5424 
5425  if (slot->tts_isnull[i])
5426  {
5427  pq_sendint32(buf, -1);
5428  continue;
5429  }
5430 
5431  if (myState->format == 0)
5432  {
5433  /* Text output */
5434  char *outputstr;
5435 
5436  outputstr = OutputFunctionCall(finfo, attr);
5437  pq_sendcountedtext(buf, outputstr, strlen(outputstr));
5438  }
5439  else
5440  {
5441  /* Binary output */
5442  bytea *outputbytes;
5443 
5444  outputbytes = SendFunctionCall(finfo, attr);
5445  pq_sendint32(buf, VARSIZE(outputbytes) - VARHDRSZ);
5446  pq_sendbytes(buf, VARDATA(outputbytes),
5447  VARSIZE(outputbytes) - VARHDRSZ);
5448  }
5449  }
5450 
5451  /*
5452  * We mustn't call pq_endmessage_reuse(), since that would actually send
5453  * the data to the client. Just count the data, instead. We can leave
5454  * the buffer alone; it'll be reset on the next iteration (as would also
5455  * happen in printtup()).
5456  */
5457  myState->metrics.bytesSent += buf->len;
5458 
5459  /* Return to caller's context, and flush row's temporary memory */
5460  MemoryContextSwitchTo(oldcontext);
5461  MemoryContextReset(myState->tmpcontext);
5462 
5463  /* Update timing data */
5464  if (myState->es->timing)
5465  {
5467  INSTR_TIME_ACCUM_DIFF(myState->metrics.timeSpent, end, start);
5468  }
5469 
5470  /* Update buffer metrics */
5471  if (myState->es->buffers)
5473  &pgBufferUsage,
5474  &instr_start);
5475 
5476  return true;
5477 }
#define VARHDRSZ
Definition: c.h:692
static void serialize_prepare_info(SerializeDestReceiver *receiver, TupleDesc typeinfo, int nattrs)
Definition: explain.c:5327
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
MemoryContextSwitchTo(old_ctx)
ExplainState * es
Definition: explain.c:5310
SerializeMetrics metrics
Definition: explain.c:5317
StringInfoData buf
Definition: explain.c:5316
MemoryContext tmpcontext
Definition: explain.c:5315
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:123
bool * tts_isnull
Definition: tuptable.h:127
Datum * tts_values
Definition: tuptable.h:125
Definition: c.h:687
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:368
#define VARDATA(PTR)
Definition: varatt.h:278
#define VARSIZE(PTR)
Definition: varatt.h:279

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

Referenced by CreateExplainSerializeDestReceiver().

◆ serializeAnalyzeShutdown()

static void serializeAnalyzeShutdown ( DestReceiver self)
static

Definition at line 5519 of file explain.c.

5520 {
5521  SerializeDestReceiver *receiver = (SerializeDestReceiver *) self;
5522 
5523  if (receiver->finfos)
5524  pfree(receiver->finfos);
5525  receiver->finfos = NULL;
5526 
5527  if (receiver->buf.data)
5528  pfree(receiver->buf.data);
5529  receiver->buf.data = NULL;
5530 
5531  if (receiver->tmpcontext)
5532  MemoryContextDelete(receiver->tmpcontext);
5533  receiver->tmpcontext = NULL;
5534 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454

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

Referenced by CreateExplainSerializeDestReceiver().

◆ serializeAnalyzeStartup()

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

Definition at line 5483 of file explain.c.

5484 {
5485  SerializeDestReceiver *receiver = (SerializeDestReceiver *) self;
5486 
5487  Assert(receiver->es != NULL);
5488 
5489  switch (receiver->es->serialize)
5490  {
5492  Assert(false);
5493  break;
5495  receiver->format = 0; /* wire protocol format text */
5496  break;
5498  receiver->format = 1; /* wire protocol format binary */
5499  break;
5500  }
5501 
5502  /* Create per-row temporary memory context */
5504  "SerializeTupleReceive",
5506 
5507  /* The output buffer is re-used across rows, as in printtup.c */
5508  initStringInfo(&receiver->buf);
5509 
5510  /* Initialize results counters */
5511  memset(&receiver->metrics, 0, sizeof(SerializeMetrics));
5513 }
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160

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

Referenced by CreateExplainSerializeDestReceiver().

◆ show_agg_keys()

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

Definition at line 2600 of file explain.c.

2602 {
2603  Agg *plan = (Agg *) astate->ss.ps.plan;
2604 
2605  if (plan->numCols > 0 || plan->groupingSets)
2606  {
2607  /* The key columns refer to the tlist of the child plan */
2608  ancestors = lcons(plan, ancestors);
2609 
2610  if (plan->groupingSets)
2611  show_grouping_sets(outerPlanState(astate), plan, ancestors, es);
2612  else
2613  show_sort_group_keys(outerPlanState(astate), "Group Key",
2614  plan->numCols, 0, plan->grpColIdx,
2615  NULL, NULL, NULL,
2616  ancestors, es);
2617 
2618  ancestors = list_delete_first(ancestors);
2619  }
2620 }
static void show_sort_group_keys(PlanState *planstate, const char *qlabel, int nkeys, int nPresortedKeys, AttrNumber *keycols, Oid *sortOperators, Oid *collations, bool *nullsFirst, List *ancestors, ExplainState *es)
Definition: explain.c:2752
static void show_grouping_sets(PlanState *planstate, Agg *agg, List *ancestors, ExplainState *es)
Definition: explain.c:2623
ScanState ss
Definition: execnodes.h:2462
PlanState ps
Definition: execnodes.h:1565

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

Referenced by ExplainNode().

◆ show_buffer_usage()

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

Definition at line 3736 of file explain.c.

3737 {
3738  if (es->format == EXPLAIN_FORMAT_TEXT)
3739  {
3740  bool has_shared = (usage->shared_blks_hit > 0 ||
3741  usage->shared_blks_read > 0 ||
3742  usage->shared_blks_dirtied > 0 ||
3743  usage->shared_blks_written > 0);
3744  bool has_local = (usage->local_blks_hit > 0 ||
3745  usage->local_blks_read > 0 ||
3746  usage->local_blks_dirtied > 0 ||
3747  usage->local_blks_written > 0);
3748  bool has_temp = (usage->temp_blks_read > 0 ||
3749  usage->temp_blks_written > 0);
3750  bool has_shared_timing = (!INSTR_TIME_IS_ZERO(usage->shared_blk_read_time) ||
3751  !INSTR_TIME_IS_ZERO(usage->shared_blk_write_time));
3752  bool has_local_timing = (!INSTR_TIME_IS_ZERO(usage->local_blk_read_time) ||
3753  !INSTR_TIME_IS_ZERO(usage->local_blk_write_time));
3754  bool has_temp_timing = (!INSTR_TIME_IS_ZERO(usage->temp_blk_read_time) ||
3755  !INSTR_TIME_IS_ZERO(usage->temp_blk_write_time));
3756 
3757  /* Show only positive counter values. */
3758  if (has_shared || has_local || has_temp)
3759  {
3760  ExplainIndentText(es);
3761  appendStringInfoString(es->str, "Buffers:");
3762 
3763  if (has_shared)
3764  {
3765  appendStringInfoString(es->str, " shared");
3766  if (usage->shared_blks_hit > 0)
3767  appendStringInfo(es->str, " hit=%lld",
3768  (long long) usage->shared_blks_hit);
3769  if (usage->shared_blks_read > 0)
3770  appendStringInfo(es->str, " read=%lld",
3771  (long long) usage->shared_blks_read);
3772  if (usage->shared_blks_dirtied > 0)
3773  appendStringInfo(es->str, " dirtied=%lld",
3774  (long long) usage->shared_blks_dirtied);
3775  if (usage->shared_blks_written > 0)
3776  appendStringInfo(es->str, " written=%lld",
3777  (long long) usage->shared_blks_written);
3778  if (has_local || has_temp)
3779  appendStringInfoChar(es->str, ',');
3780  }
3781  if (has_local)
3782  {
3783  appendStringInfoString(es->str, " local");
3784  if (usage->local_blks_hit > 0)
3785  appendStringInfo(es->str, " hit=%lld",
3786  (long long) usage->local_blks_hit);
3787  if (usage->local_blks_read > 0)
3788  appendStringInfo(es->str, " read=%lld",
3789  (long long) usage->local_blks_read);
3790  if (usage->local_blks_dirtied > 0)
3791  appendStringInfo(es->str, " dirtied=%lld",
3792  (long long) usage->local_blks_dirtied);
3793  if (usage->local_blks_written > 0)
3794  appendStringInfo(es->str, " written=%lld",
3795  (long lon