PostgreSQL Source Code  git master
explain.c File Reference
#include "postgres.h"
#include "access/xact.h"
#include "catalog/pg_type.h"
#include "commands/createas.h"
#include "commands/defrem.h"
#include "commands/prepare.h"
#include "executor/nodeHash.h"
#include "foreign/fdwapi.h"
#include "jit/jit.h"
#include "nodes/extensible.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteHandler.h"
#include "storage/bufmgr.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/guc_tables.h"
#include "utils/json.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/ruleutils.h"
#include "utils/snapmgr.h"
#include "utils/tuplesort.h"
#include "utils/typcache.h"
#include "utils/xml.h"
Include dependency graph for explain.c:

Go to the source code of this file.

Macros

#define X_OPENING   0
 
#define X_CLOSING   1
 
#define X_CLOSE_IMMEDIATE   2
 
#define X_NOWHITESPACE   4
 

Functions

static void ExplainOneQuery (Query *query, int cursorOptions, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
 
static void report_triggers (ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
 
static double elapsed_time (instr_time *starttime)
 
static bool ExplainPreScanNode (PlanState *planstate, Bitmapset **rels_used)
 
static void ExplainNode (PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
 
static void show_plan_tlist (PlanState *planstate, List *ancestors, ExplainState *es)
 
static void show_expression (Node *node, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
 
static void show_qual (List *qual, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
 
static void show_scan_qual (List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
 
static void show_upper_qual (List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
 
static void show_sort_keys (SortState *sortstate, List *ancestors, ExplainState *es)
 
static void show_merge_append_keys (MergeAppendState *mstate, List *ancestors, ExplainState *es)
 
static void show_agg_keys (AggState *astate, List *ancestors, ExplainState *es)
 
static void show_grouping_sets (PlanState *planstate, Agg *agg, List *ancestors, ExplainState *es)
 
static void show_grouping_set_keys (PlanState *planstate, Agg *aggnode, Sort *sortnode, List *context, bool useprefix, List *ancestors, ExplainState *es)
 
static void show_group_keys (GroupState *gstate, List *ancestors, ExplainState *es)
 
static void show_sort_group_keys (PlanState *planstate, const char *qlabel, int nkeys, AttrNumber *keycols, Oid *sortOperators, Oid *collations, bool *nullsFirst, List *ancestors, ExplainState *es)
 
static void show_sortorder_options (StringInfo buf, Node *sortexpr, Oid sortOperator, Oid collation, bool nullsFirst)
 
static void show_tablesample (TableSampleClause *tsc, PlanState *planstate, List *ancestors, ExplainState *es)
 
static void show_sort_info (SortState *sortstate, ExplainState *es)
 
static void show_hash_info (HashState *hashstate, ExplainState *es)
 
static void show_tidbitmap_info (BitmapHeapScanState *planstate, ExplainState *es)
 
static void show_instrumentation_count (const char *qlabel, int which, PlanState *planstate, ExplainState *es)
 
static void show_foreignscan_info (ForeignScanState *fsstate, ExplainState *es)
 
static void show_eval_params (Bitmapset *bms_params, ExplainState *es)
 
static const char * explain_get_index_name (Oid indexId)
 
static void show_buffer_usage (ExplainState *es, const BufferUsage *usage)
 
static void ExplainIndexScanDetails (Oid indexid, ScanDirection indexorderdir, ExplainState *es)
 
static void ExplainScanTarget (Scan *plan, ExplainState *es)
 
static void ExplainModifyTarget (ModifyTable *plan, ExplainState *es)
 
static void ExplainTargetRel (Plan *plan, Index rti, ExplainState *es)
 
static void show_modifytable_info (ModifyTableState *mtstate, List *ancestors, ExplainState *es)
 
static void ExplainMemberNodes (PlanState **planstates, int nsubnodes, int nplans, List *ancestors, ExplainState *es)
 
static void ExplainSubPlans (List *plans, List *ancestors, const char *relationship, ExplainState *es)
 
static void ExplainCustomChildren (CustomScanState *css, List *ancestors, ExplainState *es)
 
static void ExplainProperty (const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
 
static void ExplainDummyGroup (const char *objtype, const char *labelname, ExplainState *es)
 
static void ExplainXMLTag (const char *tagname, int flags, ExplainState *es)
 
static void ExplainJSONLineEnding (ExplainState *es)
 
static void ExplainYAMLLineStarting (ExplainState *es)
 
static void escape_yaml (StringInfo buf, const char *str)
 
void ExplainQuery (ParseState *pstate, ExplainStmt *stmt, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest)
 
ExplainStateNewExplainState (void)
 
TupleDesc ExplainResultDesc (ExplainStmt *stmt)
 
void ExplainOneUtility (Node *utilityStmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
 
void ExplainOnePlan (PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv, const instr_time *planduration)
 
static void ExplainPrintSettings (ExplainState *es)
 
void ExplainPrintPlan (ExplainState *es, QueryDesc *queryDesc)
 
void ExplainPrintTriggers (ExplainState *es, QueryDesc *queryDesc)
 
void ExplainPrintJITSummary (ExplainState *es, QueryDesc *queryDesc)
 
void ExplainPrintJIT (ExplainState *es, int jit_flags, JitInstrumentation *ji, int worker_num)
 
void ExplainQueryText (ExplainState *es, QueryDesc *queryDesc)
 
void ExplainPropertyList (const char *qlabel, List *data, ExplainState *es)
 
void ExplainPropertyListNested (const char *qlabel, List *data, ExplainState *es)
 
void ExplainPropertyText (const char *qlabel, const char *value, ExplainState *es)
 
void ExplainPropertyInteger (const char *qlabel, const char *unit, int64 value, ExplainState *es)
 
void ExplainPropertyFloat (const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
 
void ExplainPropertyBool (const char *qlabel, bool value, ExplainState *es)
 
void ExplainOpenGroup (const char *objtype, const char *labelname, bool labeled, ExplainState *es)
 
void ExplainCloseGroup (const char *objtype, const char *labelname, bool labeled, ExplainState *es)
 
void ExplainBeginOutput (ExplainState *es)
 
void ExplainEndOutput (ExplainState *es)
 
void ExplainSeparatePlans (ExplainState *es)
 

Variables

ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL
 
explain_get_index_name_hook_type explain_get_index_name_hook = NULL
 

Macro Definition Documentation

◆ X_CLOSE_IMMEDIATE

#define X_CLOSE_IMMEDIATE   2

Definition at line 53 of file explain.c.

Referenced by ExplainDummyGroup(), and ExplainXMLTag().

◆ X_CLOSING

#define X_CLOSING   1

Definition at line 52 of file explain.c.

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

◆ X_NOWHITESPACE

#define X_NOWHITESPACE   4

Definition at line 54 of file explain.c.

Referenced by ExplainProperty(), and ExplainXMLTag().

◆ X_OPENING

#define X_OPENING   0

Definition at line 51 of file explain.c.

Referenced by ExplainOpenGroup(), ExplainProperty(), and ExplainPropertyList().

Function Documentation

◆ elapsed_time()

static double elapsed_time ( instr_time starttime)
static

Definition at line 981 of file explain.c.

References INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, and INSTR_TIME_SUBTRACT.

Referenced by ExplainOnePlan(), and IsCheckpointOnSchedule().

982 {
983  instr_time endtime;
984 
985  INSTR_TIME_SET_CURRENT(endtime);
986  INSTR_TIME_SUBTRACT(endtime, *starttime);
987  return INSTR_TIME_GET_DOUBLE(endtime);
988 }
struct timeval instr_time
Definition: instr_time.h:150
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:199
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:170
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156

◆ escape_yaml()

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

Definition at line 3933 of file explain.c.

References escape_json().

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

3934 {
3935  escape_json(buf, str);
3936 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2483

◆ explain_get_index_name()

static const char * explain_get_index_name ( Oid  indexId)
static

Definition at line 2828 of file explain.c.

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

Referenced by ExplainIndexScanDetails(), and ExplainNode().

2829 {
2830  const char *result;
2831 
2833  result = (*explain_get_index_name_hook) (indexId);
2834  else
2835  result = NULL;
2836  if (result == NULL)
2837  {
2838  /* default behavior: look in the catalogs and quote it */
2839  result = get_rel_name(indexId);
2840  if (result == NULL)
2841  elog(ERROR, "cache lookup failed for index %u", indexId);
2842  result = quote_identifier(result);
2843  }
2844  return result;
2845 }
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10640
#define ERROR
Definition: elog.h:43
explain_get_index_name_hook_type explain_get_index_name_hook
Definition: explain.c:47
#define elog(elevel,...)
Definition: elog.h:228
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730

◆ ExplainBeginOutput()

void ExplainBeginOutput ( ExplainState es)

Definition at line 3772 of file explain.c.

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

Referenced by explain_ExecutorEnd(), and ExplainQuery().

3773 {
3774  switch (es->format)
3775  {
3776  case EXPLAIN_FORMAT_TEXT:
3777  /* nothing to do */
3778  break;
3779 
3780  case EXPLAIN_FORMAT_XML:
3782  "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
3783  es->indent++;
3784  break;
3785 
3786  case EXPLAIN_FORMAT_JSON:
3787  /* top-level structure is an array of plans */
3788  appendStringInfoChar(es->str, '[');
3789  es->grouping_stack = lcons_int(0, es->grouping_stack);
3790  es->indent++;
3791  break;
3792 
3793  case EXPLAIN_FORMAT_YAML:
3794  es->grouping_stack = lcons_int(0, es->grouping_stack);
3795  break;
3796  }
3797 }
List * lcons_int(int datum, List *list)
Definition: list.c:472
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
List * grouping_stack
Definition: explain.h:42
int indent
Definition: explain.h:41
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
ExplainFormat format
Definition: explain.h:39
StringInfo str
Definition: explain.h:30

◆ ExplainCloseGroup()

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

Definition at line 3690 of file explain.c.

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

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

3692 {
3693  switch (es->format)
3694  {
3695  case EXPLAIN_FORMAT_TEXT:
3696  /* nothing to do */
3697  break;
3698 
3699  case EXPLAIN_FORMAT_XML:
3700  es->indent--;
3701  ExplainXMLTag(objtype, X_CLOSING, es);
3702  break;
3703 
3704  case EXPLAIN_FORMAT_JSON:
3705  es->indent--;
3706  appendStringInfoChar(es->str, '\n');
3707  appendStringInfoSpaces(es->str, 2 * es->indent);
3708  appendStringInfoChar(es->str, labeled ? '}' : ']');
3710  break;
3711 
3712  case EXPLAIN_FORMAT_YAML:
3713  es->indent--;
3715  break;
3716  }
3717 }
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3861
#define X_CLOSING
Definition: explain.c:52
List * grouping_stack
Definition: explain.h:42
int indent
Definition: explain.h:41
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
ExplainFormat format
Definition: explain.h:39
StringInfo str
Definition: explain.h:30
List * list_delete_first(List *list)
Definition: list.c:861

◆ ExplainCustomChildren()

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

Definition at line 3384 of file explain.c.

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

Referenced by ExplainNode().

3385 {
3386  ListCell *cell;
3387  const char *label =
3388  (list_length(css->custom_ps) != 1 ? "children" : "child");
3389 
3390  foreach(cell, css->custom_ps)
3391  ExplainNode((PlanState *) lfirst(cell), ancestors, label, NULL, es);
3392 }
List * custom_ps
Definition: execnodes.h:1812
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1065
static char * label
#define lfirst(lc)
Definition: pg_list.h:190
static int list_length(const List *l)
Definition: pg_list.h:169

◆ ExplainDummyGroup()

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

Definition at line 3726 of file explain.c.

References appendStringInfoSpaces(), appendStringInfoString(), escape_json(), escape_yaml(), EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainJSONLineEnding(), ExplainXMLTag(), ExplainYAMLLineStarting(), ExplainState::format, ExplainState::indent, ExplainState::str, and X_CLOSE_IMMEDIATE.

Referenced by ExplainOneUtility().

3727 {
3728  switch (es->format)
3729  {
3730  case EXPLAIN_FORMAT_TEXT:
3731  /* nothing to do */
3732  break;
3733 
3734  case EXPLAIN_FORMAT_XML:
3735  ExplainXMLTag(objtype, X_CLOSE_IMMEDIATE, es);
3736  break;
3737 
3738  case EXPLAIN_FORMAT_JSON:
3740  appendStringInfoSpaces(es->str, 2 * es->indent);
3741  if (labelname)
3742  {
3743  escape_json(es->str, labelname);
3744  appendStringInfoString(es->str, ": ");
3745  }
3746  escape_json(es->str, objtype);
3747  break;
3748 
3749  case EXPLAIN_FORMAT_YAML:
3751  if (labelname)
3752  {
3753  escape_yaml(es->str, labelname);
3754  appendStringInfoString(es->str, ": ");
3755  }
3756  else
3757  {
3758  appendStringInfoString(es->str, "- ");
3759  }
3760  escape_yaml(es->str, objtype);
3761  break;
3762  }
3763 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2483
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3861
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3908
int indent
Definition: explain.h:41
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3933
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3888
ExplainFormat format
Definition: explain.h:39
#define X_CLOSE_IMMEDIATE
Definition: explain.c:53
StringInfo str
Definition: explain.h:30

◆ ExplainEndOutput()

void ExplainEndOutput ( ExplainState es)

Definition at line 3803 of file explain.c.

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

Referenced by explain_ExecutorEnd(), and ExplainQuery().

3804 {
3805  switch (es->format)
3806  {
3807  case EXPLAIN_FORMAT_TEXT:
3808  /* nothing to do */
3809  break;
3810 
3811  case EXPLAIN_FORMAT_XML:
3812  es->indent--;
3813  appendStringInfoString(es->str, "</explain>");
3814  break;
3815 
3816  case EXPLAIN_FORMAT_JSON:
3817  es->indent--;
3818  appendStringInfoString(es->str, "\n]");
3820  break;
3821 
3822  case EXPLAIN_FORMAT_YAML:
3824  break;
3825  }
3826 }
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
List * grouping_stack
Definition: explain.h:42
int indent
Definition: explain.h:41
ExplainFormat format
Definition: explain.h:39
StringInfo str
Definition: explain.h:30
List * list_delete_first(List *list)
Definition: list.c:861

◆ ExplainIndexScanDetails()

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

Definition at line 2975 of file explain.c.

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

Referenced by ExplainNode().

2977 {
2978  const char *indexname = explain_get_index_name(indexid);
2979 
2980  if (es->format == EXPLAIN_FORMAT_TEXT)
2981  {
2982  if (ScanDirectionIsBackward(indexorderdir))
2983  appendStringInfoString(es->str, " Backward");
2984  appendStringInfo(es->str, " using %s", indexname);
2985  }
2986  else
2987  {
2988  const char *scandir;
2989 
2990  switch (indexorderdir)
2991  {
2992  case BackwardScanDirection:
2993  scandir = "Backward";
2994  break;
2996  scandir = "NoMovement";
2997  break;
2998  case ForwardScanDirection:
2999  scandir = "Forward";
3000  break;
3001  default:
3002  scandir = "???";
3003  break;
3004  }
3005  ExplainPropertyText("Scan Direction", scandir, es);
3006  ExplainPropertyText("Index Name", indexname, es);
3007  }
3008 }
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3575
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
ExplainFormat format
Definition: explain.h:39
static const char * explain_get_index_name(Oid indexId)
Definition: explain.c:2828
StringInfo str
Definition: explain.h:30

◆ ExplainJSONLineEnding()

static void ExplainJSONLineEnding ( ExplainState es)
static

Definition at line 3888 of file explain.c.

References appendStringInfoChar(), Assert, EXPLAIN_FORMAT_JSON, ExplainState::format, ExplainState::grouping_stack, linitial_int, and ExplainState::str.

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

3889 {
3891  if (linitial_int(es->grouping_stack) != 0)
3892  appendStringInfoChar(es->str, ',');
3893  else
3894  linitial_int(es->grouping_stack) = 1;
3895  appendStringInfoChar(es->str, '\n');
3896 }
#define linitial_int(l)
Definition: pg_list.h:196
List * grouping_stack
Definition: explain.h:42
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
#define Assert(condition)
Definition: c.h:739
ExplainFormat format
Definition: explain.h:39
StringInfo str
Definition: explain.h:30

◆ ExplainMemberNodes()

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

Definition at line 3323 of file explain.c.

References ExplainNode(), and ExplainPropertyInteger().

Referenced by ExplainNode().

3325 {
3326  int j;
3327 
3328  /*
3329  * The number of subnodes being lower than the number of subplans that was
3330  * specified in the plan means that some subnodes have been ignored per
3331  * instruction for the partition pruning code during the executor
3332  * initialization. To make this a bit less mysterious, we'll indicate
3333  * here that this has happened.
3334  */
3335  if (nsubnodes < nplans)
3336  ExplainPropertyInteger("Subplans Removed", NULL, nplans - nsubnodes, es);
3337 
3338  for (j = 0; j < nsubnodes; j++)
3339  ExplainNode(planstates[j], ancestors,
3340  "Member", NULL, es);
3341 }
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:3584
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1065

◆ ExplainModifyTarget()

static void ExplainModifyTarget ( ModifyTable plan,
ExplainState es 
)
static

Definition at line 3027 of file explain.c.

References ExplainTargetRel().

Referenced by ExplainNode().

3028 {
3029  ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
3030 }
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:3036

◆ ExplainNode()

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

Definition at line 1065 of file explain.c.

References AGG_HASHED, AGG_MIXED, AGG_PLAIN, AGG_SORTED, Agg::aggsplit, Agg::aggstrategy, ExplainState::analyze, appendStringInfo(), appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), ExplainState::buffers, Instrumentation::bufusage, castNode, CMD_DELETE, CMD_INSERT, CMD_SELECT, CMD_UPDATE, ExplainState::costs, DO_AGGSPLIT_COMBINE, DO_AGGSPLIT_SKIPFINAL, EState::es_jit_flags, EXPLAIN_FORMAT_TEXT, explain_get_index_name(), ExplainCloseGroup(), ExplainCustomChildren(), CustomExecMethods::ExplainCustomScan, ExplainIndexScanDetails(), ExplainMemberNodes(), ExplainModifyTarget(), ExplainOpenGroup(), ExplainPrintJIT(), ExplainPropertyBool(), ExplainPropertyFloat(), ExplainPropertyInteger(), ExplainPropertyText(), ExplainScanTarget(), ExplainSubPlans(), ExplainState::format, RangeTblFunction::funcexpr, functions, ExplainState::indent, IndexScan::indexid, IndexOnlyScan::indexid, BitmapIndexScan::indexid, IndexScan::indexorderdir, IndexOnlyScan::indexorderdir, Gather::initParam, GatherMerge::initParam, PlanState::initPlan, innerPlanState, InstrEndLoop(), WorkerInstrumentation::instrument, PlanState::instrument, IsA, SharedJitInstrumentation::jit_instr, JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, JOIN_SEMI, lappend(), lcons(), lfirst, list_delete_first(), list_length(), list_make1, make_orclause(), CustomScanState::methods, NIL, Instrumentation::nloops, nodeTag, Instrumentation::ntuples, Instrumentation::ntuples2, SharedJitInstrumentation::num_workers, WorkerInstrumentation::num_workers, Gather::num_workers, GatherMerge::num_workers, outerPlanState, Plan::parallel_aware, PlanState::plan, Plan::plan_rows, Plan::plan_width, psprintf(), SETOP_HASHED, SETOP_SORTED, SETOPCMD_EXCEPT, SETOPCMD_EXCEPT_ALL, SETOPCMD_INTERSECT, SETOPCMD_INTERSECT_ALL, show_agg_keys(), show_buffer_usage(), show_eval_params(), show_expression(), show_foreignscan_info(), show_group_keys(), show_hash_info(), show_instrumentation_count(), show_merge_append_keys(), show_modifytable_info(), show_plan_tlist(), show_scan_qual(), show_sort_info(), show_sort_keys(), show_tablesample(), show_tidbitmap_info(), show_upper_qual(), Gather::single_copy, Instrumentation::startup, Plan::startup_cost, PlanState::state, ExplainState::str, PlanState::subPlan, T_Agg, T_Append, T_BitmapAnd, T_BitmapHeapScan, T_BitmapIndexScan, T_BitmapOr, T_CteScan, T_CustomScan, T_ForeignScan, T_FunctionScan, T_Gather, T_GatherMerge, T_Group, T_Hash, T_HashJoin, T_IndexOnlyScan, T_IndexScan, T_Limit, T_LockRows, T_Material, T_MergeAppend, T_MergeJoin, T_ModifyTable, T_NamedTuplestoreScan, T_NestLoop, T_ProjectSet, T_RecursiveUnion, T_Result, T_SampleScan, T_SeqScan, T_SetOp, T_Sort, T_SubqueryScan, T_TableFuncScan, T_TidScan, T_Unique, T_ValuesScan, T_WindowAgg, T_WorkTableScan, ExplainState::timing, Instrumentation::total, Plan::total_cost, ExplainState::verbose, PlanState::worker_instrument, and PlanState::worker_jit_instrument.

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

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

◆ ExplainOnePlan()

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

Definition at line 465 of file explain.c.

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

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

468 {
470  QueryDesc *queryDesc;
471  instr_time starttime;
472  double totaltime = 0;
473  int eflags;
474  int instrument_option = 0;
475 
476  Assert(plannedstmt->commandType != CMD_UTILITY);
477 
478  if (es->analyze && es->timing)
479  instrument_option |= INSTRUMENT_TIMER;
480  else if (es->analyze)
481  instrument_option |= INSTRUMENT_ROWS;
482 
483  if (es->buffers)
484  instrument_option |= INSTRUMENT_BUFFERS;
485 
486  /*
487  * We always collect timing for the entire statement, even when node-level
488  * timing is off, so we don't look at es->timing here. (We could skip
489  * this if !es->summary, but it's hardly worth the complication.)
490  */
491  INSTR_TIME_SET_CURRENT(starttime);
492 
493  /*
494  * Use a snapshot with an updated command ID to ensure this query sees
495  * results of any previously executed queries.
496  */
499 
500  /*
501  * Normally we discard the query's output, but if explaining CREATE TABLE
502  * AS, we'd better use the appropriate tuple receiver.
503  */
504  if (into)
505  dest = CreateIntoRelDestReceiver(into);
506  else
507  dest = None_Receiver;
508 
509  /* Create a QueryDesc for the query */
510  queryDesc = CreateQueryDesc(plannedstmt, queryString,
512  dest, params, queryEnv, instrument_option);
513 
514  /* Select execution options */
515  if (es->analyze)
516  eflags = 0; /* default run-to-completion flags */
517  else
518  eflags = EXEC_FLAG_EXPLAIN_ONLY;
519  if (into)
520  eflags |= GetIntoRelEFlags(into);
521 
522  /* call ExecutorStart to prepare the plan for execution */
523  ExecutorStart(queryDesc, eflags);
524 
525  /* Execute the plan for statistics if asked for */
526  if (es->analyze)
527  {
528  ScanDirection dir;
529 
530  /* EXPLAIN ANALYZE CREATE TABLE AS WITH NO DATA is weird */
531  if (into && into->skipData)
533  else
534  dir = ForwardScanDirection;
535 
536  /* run the plan */
537  ExecutorRun(queryDesc, dir, 0L, true);
538 
539  /* run cleanup too */
540  ExecutorFinish(queryDesc);
541 
542  /* We can't run ExecutorEnd 'till we're done printing the stats... */
543  totaltime += elapsed_time(&starttime);
544  }
545 
546  ExplainOpenGroup("Query", NULL, true, es);
547 
548  /* Create textual dump of plan tree */
549  ExplainPrintPlan(es, queryDesc);
550 
551  if (es->summary && planduration)
552  {
553  double plantime = INSTR_TIME_GET_DOUBLE(*planduration);
554 
555  ExplainPropertyFloat("Planning Time", "ms", 1000.0 * plantime, 3, es);
556  }
557 
558  /* Print info about runtime of triggers */
559  if (es->analyze)
560  ExplainPrintTriggers(es, queryDesc);
561 
562  /*
563  * Print info about JITing. Tied to es->costs because we don't want to
564  * display this in regression tests, as it'd cause output differences
565  * depending on build options. Might want to separate that out from COSTS
566  * at a later stage.
567  */
568  if (es->costs)
569  ExplainPrintJITSummary(es, queryDesc);
570 
571  /*
572  * Close down the query and free resources. Include time for this in the
573  * total execution time (although it should be pretty minimal).
574  */
575  INSTR_TIME_SET_CURRENT(starttime);
576 
577  ExecutorEnd(queryDesc);
578 
579  FreeQueryDesc(queryDesc);
580 
582 
583  /* We need a CCI just in case query expanded to multiple plans */
584  if (es->analyze)
586 
587  totaltime += elapsed_time(&starttime);
588 
589  /*
590  * We only report execution time if we actually ran the query (that is,
591  * the user specified ANALYZE), and if summary reporting is enabled (the
592  * user can set SUMMARY OFF to not have the timing information included in
593  * the output). By default, ANALYZE sets SUMMARY to true.
594  */
595  if (es->summary && es->analyze)
596  ExplainPropertyFloat("Execution Time", "ms", 1000.0 * totaltime, 3,
597  es);
598 
599  ExplainCloseGroup("Query", NULL, true, es);
600 }
bool summary
Definition: explain.h:37
void UpdateActiveSnapshotCommandId(void)
Definition: snapmgr.c:783
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
void ExplainPropertyFloat(const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
Definition: explain.c:3598
struct timeval instr_time
Definition: instr_time.h:150
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:143
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:841
void PopActiveSnapshot(void)
Definition: snapmgr.c:814
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:199
bool skipData
Definition: primnodes.h:119
bool costs
Definition: explain.h:34
DestReceiver * None_Receiver
Definition: dest.c:96
bool analyze
Definition: explain.h:33
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:462
int GetIntoRelEFlags(IntoClause *intoClause)
Definition: createas.c:394
void ExplainPrintTriggers(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:724
void ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:681
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:301
void PushCopiedSnapshot(Snapshot snapshot)
Definition: snapmgr.c:771
QueryDesc * CreateQueryDesc(PlannedStmt *plannedstmt, const char *sourceText, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, QueryEnvironment *queryEnv, int instrument_options)
Definition: pquery.c:67
ScanDirection
Definition: sdir.h:22
DestReceiver * CreateIntoRelDestReceiver(IntoClause *intoClause)
Definition: createas.c:412
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:402
bool timing
Definition: explain.h:36
#define InvalidSnapshot
Definition: snapshot.h:123
void CommandCounterIncrement(void)
Definition: xact.c:1005
CmdType commandType
Definition: plannodes.h:46
#define Assert(condition)
Definition: c.h:739
static double elapsed_time(instr_time *starttime)
Definition: explain.c:981
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
bool buffers
Definition: explain.h:35
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3690
void ExplainPrintJITSummary(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:770
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3627
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:56

◆ ExplainOneQuery()

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

Definition at line 341 of file explain.c.

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

Referenced by ExplainOneUtility(), and ExplainQuery().

345 {
346  /* planner will not cope with utility statements */
347  if (query->commandType == CMD_UTILITY)
348  {
349  ExplainOneUtility(query->utilityStmt, into, es, queryString, params,
350  queryEnv);
351  return;
352  }
353 
354  /* if an advisor plugin is present, let it manage things */
356  (*ExplainOneQuery_hook) (query, cursorOptions, into, es,
357  queryString, params, queryEnv);
358  else
359  {
360  PlannedStmt *plan;
361  instr_time planstart,
362  planduration;
363 
364  INSTR_TIME_SET_CURRENT(planstart);
365 
366  /* plan the query */
367  plan = pg_plan_query(query, cursorOptions, params);
368 
369  INSTR_TIME_SET_CURRENT(planduration);
370  INSTR_TIME_SUBTRACT(planduration, planstart);
371 
372  /* run it (if needed) and produce output */
373  ExplainOnePlan(plan, into, es, queryString, params, queryEnv,
374  &planduration);
375  }
376 }
void ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv, const instr_time *planduration)
Definition: explain.c:465
struct timeval instr_time
Definition: instr_time.h:150
Node * utilityStmt
Definition: parsenodes.h:120
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:170
ExplainOneQuery_hook_type ExplainOneQuery_hook
Definition: explain.c:44
CmdType commandType
Definition: parsenodes.h:112
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
void ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: explain.c:390
PlannedStmt * pg_plan_query(Query *querytree, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:855

◆ ExplainOneUtility()

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

Definition at line 390 of file explain.c.

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

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

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

◆ ExplainOpenGroup()

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

Definition at line 3627 of file explain.c.

References appendStringInfo(), appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), escape_json(), EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainJSONLineEnding(), ExplainXMLTag(), ExplainYAMLLineStarting(), ExplainState::format, ExplainState::grouping_stack, ExplainState::indent, lcons_int(), ExplainState::str, and X_OPENING.

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

3629 {
3630  switch (es->format)
3631  {
3632  case EXPLAIN_FORMAT_TEXT:
3633  /* nothing to do */
3634  break;
3635 
3636  case EXPLAIN_FORMAT_XML:
3637  ExplainXMLTag(objtype, X_OPENING, es);
3638  es->indent++;
3639  break;
3640 
3641  case EXPLAIN_FORMAT_JSON:
3643  appendStringInfoSpaces(es->str, 2 * es->indent);
3644  if (labelname)
3645  {
3646  escape_json(es->str, labelname);
3647  appendStringInfoString(es->str, ": ");
3648  }
3649  appendStringInfoChar(es->str, labeled ? '{' : '[');
3650 
3651  /*
3652  * In JSON format, the grouping_stack is an integer list. 0 means
3653  * we've emitted nothing at this grouping level, 1 means we've
3654  * emitted something (and so the next item needs a comma). See
3655  * ExplainJSONLineEnding().
3656  */
3657  es->grouping_stack = lcons_int(0, es->grouping_stack);
3658  es->indent++;
3659  break;
3660 
3661  case EXPLAIN_FORMAT_YAML:
3662 
3663  /*
3664  * In YAML format, the grouping stack is an integer list. 0 means
3665  * we've emitted nothing at this grouping level AND this grouping
3666  * level is unlabelled and must be marked with "- ". See
3667  * ExplainYAMLLineStarting().
3668  */
3670  if (labelname)
3671  {
3672  appendStringInfo(es->str, "%s: ", labelname);
3673  es->grouping_stack = lcons_int(1, es->grouping_stack);
3674  }
3675  else
3676  {
3677  appendStringInfoString(es->str, "- ");
3678  es->grouping_stack = lcons_int(0, es->grouping_stack);
3679  }
3680  es->indent++;
3681  break;
3682  }
3683 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2483
List * lcons_int(int datum, List *list)
Definition: list.c:472
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3861
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3908
List * grouping_stack
Definition: explain.h:42
int indent
Definition: explain.h:41
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3888
#define X_OPENING
Definition: explain.c:51
ExplainFormat format
Definition: explain.h:39
StringInfo str
Definition: explain.h:30

◆ ExplainPreScanNode()

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

Definition at line 1000 of file explain.c.

References bms_add_member(), bms_add_members(), nodeTag, PlanState::plan, planstate_tree_walker(), T_BitmapHeapScan, T_CteScan, T_CustomScan, T_ForeignScan, T_FunctionScan, T_IndexOnlyScan, T_IndexScan, T_ModifyTable, T_NamedTuplestoreScan, T_SampleScan, T_SeqScan, T_SubqueryScan, T_TableFuncScan, T_TidScan, T_ValuesScan, and T_WorkTableScan.

Referenced by ExplainPrintPlan().

1001 {
1002  Plan *plan = planstate->plan;
1003 
1004  switch (nodeTag(plan))
1005  {
1006  case T_SeqScan:
1007  case T_SampleScan:
1008  case T_IndexScan:
1009  case T_IndexOnlyScan:
1010  case T_BitmapHeapScan:
1011  case T_TidScan:
1012  case T_SubqueryScan:
1013  case T_FunctionScan:
1014  case T_TableFuncScan:
1015  case T_ValuesScan:
1016  case T_CteScan:
1017  case T_NamedTuplestoreScan:
1018  case T_WorkTableScan:
1019  *rels_used = bms_add_member(*rels_used,
1020  ((Scan *) plan)->scanrelid);
1021  break;
1022  case T_ForeignScan:
1023  *rels_used = bms_add_members(*rels_used,
1024  ((ForeignScan *) plan)->fs_relids);
1025  break;
1026  case T_CustomScan:
1027  *rels_used = bms_add_members(*rels_used,
1028  ((CustomScan *) plan)->custom_relids);
1029  break;
1030  case T_ModifyTable:
1031  *rels_used = bms_add_member(*rels_used,
1032  ((ModifyTable *) plan)->nominalRelation);
1033  if (((ModifyTable *) plan)->exclRelRTI)
1034  *rels_used = bms_add_member(*rels_used,
1035  ((ModifyTable *) plan)->exclRelRTI);
1036  break;
1037  default:
1038  break;
1039  }
1040 
1041  return planstate_tree_walker(planstate, ExplainPreScanNode, rels_used);
1042 }
Plan * plan
Definition: execnodes.h:939
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define nodeTag(nodeptr)
Definition: nodes.h:530
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
Definition: explain.c:1000
bool planstate_tree_walker(PlanState *planstate, bool(*walker)(), void *context)
Definition: nodeFuncs.c:3867
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793

◆ ExplainPrintJIT()

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

Definition at line 799 of file explain.c.

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

801 {
802  instr_time total_time;
803  bool for_workers = (worker_num >= 0);
804 
805  /* don't print information if no JITing happened */
806  if (!ji || ji->created_functions == 0)
807  return;
808 
809  /* calculate total time */
810  INSTR_TIME_SET_ZERO(total_time);
811  INSTR_TIME_ADD(total_time, ji->generation_counter);
812  INSTR_TIME_ADD(total_time, ji->inlining_counter);
813  INSTR_TIME_ADD(total_time, ji->optimization_counter);
814  INSTR_TIME_ADD(total_time, ji->emission_counter);
815 
816  ExplainOpenGroup("JIT", "JIT", true, es);
817 
818  /* for higher density, open code the text output format */
819  if (es->format == EXPLAIN_FORMAT_TEXT)
820  {
821  appendStringInfoSpaces(es->str, es->indent * 2);
822  if (for_workers)
823  appendStringInfo(es->str, "JIT for worker %u:\n", worker_num);
824  else
825  appendStringInfoString(es->str, "JIT:\n");
826  es->indent += 1;
827 
828  ExplainPropertyInteger("Functions", NULL, ji->created_functions, es);
829 
830  appendStringInfoSpaces(es->str, es->indent * 2);
831  appendStringInfo(es->str, "Options: %s %s, %s %s, %s %s, %s %s\n",
832  "Inlining", jit_flags & PGJIT_INLINE ? "true" : "false",
833  "Optimization", jit_flags & PGJIT_OPT3 ? "true" : "false",
834  "Expressions", jit_flags & PGJIT_EXPR ? "true" : "false",
835  "Deforming", jit_flags & PGJIT_DEFORM ? "true" : "false");
836 
837  if (es->analyze && es->timing)
838  {
839  appendStringInfoSpaces(es->str, es->indent * 2);
840  appendStringInfo(es->str,
841  "Timing: %s %.3f ms, %s %.3f ms, %s %.3f ms, %s %.3f ms, %s %.3f ms\n",
842  "Generation", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->generation_counter),
843  "Inlining", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->inlining_counter),
844  "Optimization", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->optimization_counter),
845  "Emission", 1000.0 * INSTR_TIME_GET_DOUBLE(ji->emission_counter),
846  "Total", 1000.0 * INSTR_TIME_GET_DOUBLE(total_time));
847  }
848 
849  es->indent -= 1;
850  }
851  else
852  {
853  ExplainPropertyInteger("Worker Number", NULL, worker_num, es);
854  ExplainPropertyInteger("Functions", NULL, ji->created_functions, es);
855 
856  ExplainOpenGroup("Options", "Options", true, es);
857  ExplainPropertyBool("Inlining", jit_flags & PGJIT_INLINE, es);
858  ExplainPropertyBool("Optimization", jit_flags & PGJIT_OPT3, es);
859  ExplainPropertyBool("Expressions", jit_flags & PGJIT_EXPR, es);
860  ExplainPropertyBool("Deforming", jit_flags & PGJIT_DEFORM, es);
861  ExplainCloseGroup("Options", "Options", true, es);
862 
863  if (es->analyze && es->timing)
864  {
865  ExplainOpenGroup("Timing", "Timing", true, es);
866 
867  ExplainPropertyFloat("Generation", "ms",
869  3, es);
870  ExplainPropertyFloat("Inlining", "ms",
872  3, es);
873  ExplainPropertyFloat("Optimization", "ms",
875  3, es);
876  ExplainPropertyFloat("Emission", "ms",
878  3, es);
879  ExplainPropertyFloat("Total", "ms",
880  1000.0 * INSTR_TIME_GET_DOUBLE(total_time),
881  3, es);
882 
883  ExplainCloseGroup("Timing", "Timing", true, es);
884  }
885  }
886 
887  ExplainCloseGroup("JIT", "JIT", true, es);
888 }
void ExplainPropertyBool(const char *qlabel, bool value, ExplainState *es)
Definition: explain.c:3612
#define PGJIT_EXPR
Definition: jit.h:23
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:3584
instr_time generation_counter
Definition: jit.h:33
void ExplainPropertyFloat(const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
Definition: explain.c:3598
struct timeval instr_time
Definition: instr_time.h:150
#define INSTR_TIME_SET_ZERO(t)
Definition: instr_time.h:154
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:199
bool analyze
Definition: explain.h:33
#define PGJIT_OPT3
Definition: jit.h:21
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
size_t created_functions
Definition: jit.h:30
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
#define INSTR_TIME_ADD(x, y)
Definition: instr_time.h:158
instr_time optimization_counter
Definition: jit.h:39
int indent
Definition: explain.h:41
bool timing
Definition: explain.h:36
instr_time inlining_counter
Definition: jit.h:36
#define PGJIT_INLINE
Definition: jit.h:22
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
instr_time emission_counter
Definition: jit.h:42
ExplainFormat format
Definition: explain.h:39
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3690
#define PGJIT_DEFORM
Definition: jit.h:24
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3627
StringInfo str
Definition: explain.h:30

◆ ExplainPrintJITSummary()

void ExplainPrintJITSummary ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 770 of file explain.c.

References EState::es_jit, EState::es_jit_flags, EState::es_jit_worker_instr, QueryDesc::estate, ExplainPrintJIT(), JitContext::instr, InstrJitAgg(), and PGJIT_PERFORM.

Referenced by explain_ExecutorEnd(), and ExplainOnePlan().

771 {
772  JitInstrumentation ji = {0};
773 
774  if (!(queryDesc->estate->es_jit_flags & PGJIT_PERFORM))
775  return;
776 
777  /*
778  * Work with a copy instead of modifying the leader state, since this
779  * function may be called twice
780  */
781  if (queryDesc->estate->es_jit)
782  InstrJitAgg(&ji, &queryDesc->estate->es_jit->instr);
783 
784  /* If this process has done JIT in parallel workers, merge stats */
785  if (queryDesc->estate->es_jit_worker_instr)
786  InstrJitAgg(&ji, queryDesc->estate->es_jit_worker_instr);
787 
788  ExplainPrintJIT(es, queryDesc->estate->es_jit_flags, &ji, -1);
789 }
EState * estate
Definition: execdesc.h:48
struct JitContext * es_jit
Definition: execnodes.h:595
struct JitInstrumentation * es_jit_worker_instr
Definition: execnodes.h:596
JitInstrumentation instr
Definition: jit.h:61
int es_jit_flags
Definition: execnodes.h:594
void ExplainPrintJIT(ExplainState *es, int jit_flags, JitInstrumentation *ji, int worker_num)
Definition: explain.c:799
void InstrJitAgg(JitInstrumentation *dst, JitInstrumentation *add)
Definition: jit.c:184
#define PGJIT_PERFORM
Definition: jit.h:20

◆ ExplainPrintPlan()

void ExplainPrintPlan ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 681 of file explain.c.

References Assert, deparse_context_for_plan_rtable(), ExplainState::deparse_cxt, ExplainNode(), ExplainPreScanNode(), ExplainPrintSettings(), IsA, NIL, outerPlanState, PlanState::plan, QueryDesc::plannedstmt, QueryDesc::planstate, ExplainState::printed_subplans, ExplainState::pstmt, ExplainState::rtable, PlannedStmt::rtable, ExplainState::rtable_names, and select_rtable_names_for_explain().

Referenced by explain_ExecutorEnd(), and ExplainOnePlan().

682 {
683  Bitmapset *rels_used = NULL;
684  PlanState *ps;
685 
686  /* Set up ExplainState fields associated with this plan tree */
687  Assert(queryDesc->plannedstmt != NULL);
688  es->pstmt = queryDesc->plannedstmt;
689  es->rtable = queryDesc->plannedstmt->rtable;
690  ExplainPreScanNode(queryDesc->planstate, &rels_used);
693  es->rtable_names);
694  es->printed_subplans = NULL;
695 
696  /*
697  * Sometimes we mark a Gather node as "invisible", which means that it's
698  * not displayed in EXPLAIN output. The purpose of this is to allow
699  * running regression tests with force_parallel_mode=regress to get the
700  * same results as running the same tests with force_parallel_mode=off.
701  */
702  ps = queryDesc->planstate;
703  if (IsA(ps, GatherState) &&((Gather *) ps->plan)->invisible)
704  ps = outerPlanState(ps);
705  ExplainNode(ps, NIL, NULL, NULL, es);
706 
707  /*
708  * If requested, include information about GUC parameters with values that
709  * don't match the built-in defaults.
710  */
712 }
#define NIL
Definition: pg_list.h:65
static void ExplainPrintSettings(ExplainState *es)
Definition: explain.c:607
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Bitmapset * printed_subplans
Definition: explain.h:48
List * deparse_cxt
Definition: explain.h:47
PlannedStmt * pstmt
Definition: explain.h:44
List * rtable_names
Definition: explain.h:46
List * select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
Definition: ruleutils.c:3374
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1065
PlanState * planstate
Definition: execdesc.h:49
#define outerPlanState(node)
Definition: execnodes.h:1033
Plan * plan
Definition: execnodes.h:939
#define Assert(condition)
Definition: c.h:739
List * rtable
Definition: plannodes.h:66
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
Definition: explain.c:1000
PlannedStmt * plannedstmt
Definition: execdesc.h:37
List * deparse_context_for_plan_rtable(List *rtable, List *rtable_names)
Definition: ruleutils.c:3299
List * rtable
Definition: explain.h:45

◆ ExplainPrintSettings()

static void ExplainPrintSettings ( ExplainState es)
static

Definition at line 607 of file explain.c.

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

Referenced by ExplainPrintPlan().

608 {
609  int num;
610  struct config_generic **gucs;
611 
612  /* bail out if information about settings not requested */
613  if (!es->settings)
614  return;
615 
616  /* request an array of relevant settings */
617  gucs = get_explain_guc_options(&num);
618 
619  /* also bail out of there are no options */
620  if (!num)
621  return;
622 
623  if (es->format != EXPLAIN_FORMAT_TEXT)
624  {
625  int i;
626 
627  ExplainOpenGroup("Settings", "Settings", true, es);
628 
629  for (i = 0; i < num; i++)
630  {
631  char *setting;
632  struct config_generic *conf = gucs[i];
633 
634  setting = GetConfigOptionByName(conf->name, NULL, true);
635 
636  ExplainPropertyText(conf->name, setting, es);
637  }
638 
639  ExplainCloseGroup("Settings", "Settings", true, es);
640  }
641  else
642  {
643  int i;
645 
646  initStringInfo(&str);
647 
648  for (i = 0; i < num; i++)
649  {
650  char *setting;
651  struct config_generic *conf = gucs[i];
652 
653  if (i > 0)
654  appendStringInfoString(&str, ", ");
655 
656  setting = GetConfigOptionByName(conf->name, NULL, true);
657 
658  if (setting)
659  appendStringInfo(&str, "%s = '%s'", conf->name, setting);
660  else
661  appendStringInfo(&str, "%s = NULL", conf->name);
662  }
663 
664  if (num > 0)
665  ExplainPropertyText("Settings", str.data, es);
666  }
667 }
const char * name
Definition: guc_tables.h:149
struct config_generic ** get_explain_guc_options(int *num)
Definition: guc.c:8932
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3575
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
char * GetConfigOptionByName(const char *name, const char **varname, bool missing_ok)
Definition: guc.c:9030
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
ExplainFormat format
Definition: explain.h:39
int i
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3690
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3627
bool settings
Definition: explain.h:38

◆ ExplainPrintTriggers()

void ExplainPrintTriggers ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 724 of file explain.c.

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

Referenced by explain_ExecutorEnd(), and ExplainOnePlan().

725 {
726  ResultRelInfo *rInfo;
727  bool show_relname;
728  int numrels = queryDesc->estate->es_num_result_relations;
729  int numrootrels = queryDesc->estate->es_num_root_result_relations;
730  List *routerels;
731  List *targrels;
732  int nr;
733  ListCell *l;
734 
735  routerels = queryDesc->estate->es_tuple_routing_result_relations;
736  targrels = queryDesc->estate->es_trig_target_relations;
737 
738  ExplainOpenGroup("Triggers", "Triggers", false, es);
739 
740  show_relname = (numrels > 1 || numrootrels > 0 ||
741  routerels != NIL || targrels != NIL);
742  rInfo = queryDesc->estate->es_result_relations;
743  for (nr = 0; nr < numrels; rInfo++, nr++)
744  report_triggers(rInfo, show_relname, es);
745 
746  rInfo = queryDesc->estate->es_root_result_relations;
747  for (nr = 0; nr < numrootrels; rInfo++, nr++)
748  report_triggers(rInfo, show_relname, es);
749 
750  foreach(l, routerels)
751  {
752  rInfo = (ResultRelInfo *) lfirst(l);
753  report_triggers(rInfo, show_relname, es);
754  }
755 
756  foreach(l, targrels)
757  {
758  rInfo = (ResultRelInfo *) lfirst(l);
759  report_triggers(rInfo, show_relname, es);
760  }
761 
762  ExplainCloseGroup("Triggers", "Triggers", false, es);
763 }
#define NIL
Definition: pg_list.h:65
EState * estate
Definition: execdesc.h:48
ResultRelInfo * es_result_relations
Definition: execnodes.h:519
static void report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
Definition: explain.c:910
int es_num_root_result_relations
Definition: execnodes.h:530
List * es_trig_target_relations
Definition: execnodes.h:540
int es_num_result_relations
Definition: execnodes.h:520
List * es_tuple_routing_result_relations
Definition: execnodes.h:537
#define lfirst(lc)
Definition: pg_list.h:190
ResultRelInfo * es_root_result_relations
Definition: execnodes.h:529
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3690
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3627
Definition: pg_list.h:50

◆ ExplainProperty()

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

Definition at line 3522 of file explain.c.

References appendStringInfo(), appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), escape_json(), escape_xml(), escape_yaml(), EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainJSONLineEnding(), ExplainXMLTag(), ExplainYAMLLineStarting(), ExplainState::format, ExplainState::indent, pfree(), ExplainState::str, generate_unaccent_rules::str, X_CLOSING, X_NOWHITESPACE, and X_OPENING.

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

3524 {
3525  switch (es->format)
3526  {
3527  case EXPLAIN_FORMAT_TEXT:
3528  appendStringInfoSpaces(es->str, es->indent * 2);
3529  if (unit)
3530  appendStringInfo(es->str, "%s: %s %s\n", qlabel, value, unit);
3531  else
3532  appendStringInfo(es->str, "%s: %s\n", qlabel, value);
3533  break;
3534 
3535  case EXPLAIN_FORMAT_XML:
3536  {
3537  char *str;
3538 
3539  appendStringInfoSpaces(es->str, es->indent * 2);
3540  ExplainXMLTag(qlabel, X_OPENING | X_NOWHITESPACE, es);
3541  str = escape_xml(value);
3542  appendStringInfoString(es->str, str);
3543  pfree(str);
3544  ExplainXMLTag(qlabel, X_CLOSING | X_NOWHITESPACE, es);
3545  appendStringInfoChar(es->str, '\n');
3546  }
3547  break;
3548 
3549  case EXPLAIN_FORMAT_JSON:
3551  appendStringInfoSpaces(es->str, es->indent * 2);
3552  escape_json(es->str, qlabel);
3553  appendStringInfoString(es->str, ": ");
3554  if (numeric)
3556  else
3557  escape_json(es->str, value);
3558  break;
3559 
3560  case EXPLAIN_FORMAT_YAML:
3562  appendStringInfo(es->str, "%s: ", qlabel);
3563  if (numeric)
3565  else
3566  escape_yaml(es->str, value);
3567  break;
3568  }
3569 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2483
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3861
static struct @145 value
#define X_CLOSING
Definition: explain.c:52
void pfree(void *pointer)
Definition: mcxt.c:1056
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3908
int indent
Definition: explain.h:41
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3933
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3888
#define X_OPENING
Definition: explain.c:51
#define X_NOWHITESPACE
Definition: explain.c:54
ExplainFormat format
Definition: explain.h:39
char * escape_xml(const char *str)
Definition: xml.c:2371
StringInfo str
Definition: explain.h:30

◆ ExplainPropertyBool()

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

Definition at line 3612 of file explain.c.

References ExplainProperty().

Referenced by ExplainNode(), and ExplainPrintJIT().

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

◆ ExplainPropertyFloat()

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

Definition at line 3598 of file explain.c.

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

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

3600 {
3601  char *buf;
3602 
3603  buf = psprintf("%.*f", ndigits, value);
3604  ExplainProperty(qlabel, unit, buf, true, es);
3605  pfree(buf);
3606 }
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
static struct @145 value
void pfree(void *pointer)
Definition: mcxt.c:1056
static char * buf
Definition: pg_test_fsync.c:67
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3522

◆ ExplainPropertyInteger()

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

Definition at line 3584 of file explain.c.

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

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

3586 {
3587  char buf[32];
3588 
3589  snprintf(buf, sizeof(buf), INT64_FORMAT, value);
3590  ExplainProperty(qlabel, unit, buf, true, es);
3591 }
static struct @145 value
static char * buf
Definition: pg_test_fsync.c:67
#define INT64_FORMAT
Definition: c.h:401
#define snprintf
Definition: port.h:192
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3522

◆ ExplainPropertyList()

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

Definition at line 3399 of file explain.c.

References appendStringInfo(), appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), escape_json(), escape_xml(), escape_yaml(), EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainJSONLineEnding(), ExplainXMLTag(), ExplainYAMLLineStarting(), ExplainState::format, ExplainState::indent, lfirst, pfree(), ExplainState::str, generate_unaccent_rules::str, X_CLOSING, and X_OPENING.

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

3400 {
3401  ListCell *lc;
3402  bool first = true;
3403 
3404  switch (es->format)
3405  {
3406  case EXPLAIN_FORMAT_TEXT:
3407  appendStringInfoSpaces(es->str, es->indent * 2);
3408  appendStringInfo(es->str, "%s: ", qlabel);
3409  foreach(lc, data)
3410  {
3411  if (!first)
3412  appendStringInfoString(es->str, ", ");
3413  appendStringInfoString(es->str, (const char *) lfirst(lc));
3414  first = false;
3415  }
3416  appendStringInfoChar(es->str, '\n');
3417  break;
3418 
3419  case EXPLAIN_FORMAT_XML:
3420  ExplainXMLTag(qlabel, X_OPENING, es);
3421  foreach(lc, data)
3422  {
3423  char *str;
3424 
3425  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
3426  appendStringInfoString(es->str, "<Item>");
3427  str = escape_xml((const char *) lfirst(lc));
3428  appendStringInfoString(es->str, str);
3429  pfree(str);
3430  appendStringInfoString(es->str, "</Item>\n");
3431  }
3432  ExplainXMLTag(qlabel, X_CLOSING, es);
3433  break;
3434 
3435  case EXPLAIN_FORMAT_JSON:
3437  appendStringInfoSpaces(es->str, es->indent * 2);
3438  escape_json(es->str, qlabel);
3439  appendStringInfoString(es->str, ": [");
3440  foreach(lc, data)
3441  {
3442  if (!first)
3443  appendStringInfoString(es->str, ", ");
3444  escape_json(es->str, (const char *) lfirst(lc));
3445  first = false;
3446  }
3447  appendStringInfoChar(es->str, ']');
3448  break;
3449 
3450  case EXPLAIN_FORMAT_YAML:
3452  appendStringInfo(es->str, "%s: ", qlabel);
3453  foreach(lc, data)
3454  {
3455  appendStringInfoChar(es->str, '\n');
3456  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
3457  appendStringInfoString(es->str, "- ");
3458  escape_yaml(es->str, (const char *) lfirst(lc));
3459  }
3460  break;
3461  }
3462 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2483
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3861
#define X_CLOSING
Definition: explain.c:52
void pfree(void *pointer)
Definition: mcxt.c:1056
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3908
int indent
Definition: explain.h:41
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3933
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3888
#define X_OPENING
Definition: explain.c:51
#define lfirst(lc)
Definition: pg_list.h:190
ExplainFormat format
Definition: explain.h:39
char * escape_xml(const char *str)
Definition: xml.c:2371
StringInfo str
Definition: explain.h:30

◆ ExplainPropertyListNested()

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

Definition at line 3469 of file explain.c.

References appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), escape_json(), escape_yaml(), EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainJSONLineEnding(), ExplainPropertyList(), ExplainYAMLLineStarting(), ExplainState::format, ExplainState::indent, lfirst, and ExplainState::str.

Referenced by show_grouping_set_keys().

3470 {
3471  ListCell *lc;
3472  bool first = true;
3473 
3474  switch (es->format)
3475  {
3476  case EXPLAIN_FORMAT_TEXT:
3477  case EXPLAIN_FORMAT_XML:
3478  ExplainPropertyList(qlabel, data, es);
3479  return;
3480 
3481  case EXPLAIN_FORMAT_JSON:
3483  appendStringInfoSpaces(es->str, es->indent * 2);
3484  appendStringInfoChar(es->str, '[');
3485  foreach(lc, data)
3486  {
3487  if (!first)
3488  appendStringInfoString(es->str, ", ");
3489  escape_json(es->str, (const char *) lfirst(lc));
3490  first = false;
3491  }
3492  appendStringInfoChar(es->str, ']');
3493  break;
3494 
3495  case EXPLAIN_FORMAT_YAML:
3497  appendStringInfoString(es->str, "- [");
3498  foreach(lc, data)
3499  {
3500  if (!first)
3501  appendStringInfoString(es->str, ", ");
3502  escape_yaml(es->str, (const char *) lfirst(lc));
3503  first = false;
3504  }
3505  appendStringInfoChar(es->str, ']');
3506  break;
3507  }
3508 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2483
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3908
int indent
Definition: explain.h:41
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3933
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3888
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:3399
#define lfirst(lc)
Definition: pg_list.h:190
ExplainFormat format
Definition: explain.h:39
StringInfo str
Definition: explain.h:30

◆ ExplainPropertyText()

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

Definition at line 3575 of file explain.c.

References ExplainProperty().

Referenced by ExplainIndexScanDetails(), ExplainNode(), ExplainPrintSettings(), ExplainQueryText(), ExplainTargetRel(), fileExplainForeignScan(), postgresExplainDirectModify(), postgresExplainForeignModify(), postgresExplainForeignScan(), report_triggers(), show_expression(), show_grouping_set_keys(), show_modifytable_info(), show_sort_info(), and show_tablesample().

3576 {
3577  ExplainProperty(qlabel, NULL, value, false, es);
3578 }
static struct @145 value
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3522

◆ ExplainQuery()

void ExplainQuery ( ParseState pstate,
ExplainStmt stmt,
const char *  queryString,
ParamListInfo  params,
QueryEnvironment queryEnv,
DestReceiver dest 
)

Definition at line 142 of file explain.c.

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

Referenced by standard_ProcessUtility().

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

◆ ExplainQueryText()

void ExplainQueryText ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 899 of file explain.c.

References ExplainPropertyText(), and QueryDesc::sourceText.

Referenced by explain_ExecutorEnd().

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

◆ ExplainResultDesc()

TupleDesc ExplainResultDesc ( ExplainStmt stmt)

Definition at line 302 of file explain.c.

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

Referenced by ExplainQuery(), and UtilityTupleDescriptor().

303 {
304  TupleDesc tupdesc;
305  ListCell *lc;
306  Oid result_type = TEXTOID;
307 
308  /* Check for XML format option */
309  foreach(lc, stmt->options)
310  {
311  DefElem *opt = (DefElem *) lfirst(lc);
312 
313  if (strcmp(opt->defname, "format") == 0)
314  {
315  char *p = defGetString(opt);
316 
317  if (strcmp(p, "xml") == 0)
318  result_type = XMLOID;
319  else if (strcmp(p, "json") == 0)
320  result_type = JSONOID;
321  else
322  result_type = TEXTOID;
323  /* don't "break", as ExplainQuery will use the last value */
324  }
325  }
326 
327  /* Need a tuple descriptor representing a single TEXT or XML column */
328  tupdesc = CreateTemplateTupleDesc(1);
329  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
330  result_type, -1, 0);
331  return tupdesc;
332 }
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
List * options
Definition: parsenodes.h:3221
unsigned int Oid
Definition: postgres_ext.h:31
char * defGetString(DefElem *def)
Definition: define.c:49
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:603
#define lfirst(lc)
Definition: pg_list.h:190
char * defname
Definition: parsenodes.h:730
int16 AttrNumber
Definition: attnum.h:21

◆ ExplainScanTarget()

static void ExplainScanTarget ( Scan plan,
ExplainState es 
)
static

Definition at line 3014 of file explain.c.

References ExplainTargetRel().

Referenced by ExplainNode().

3015 {
3016  ExplainTargetRel((Plan *) plan, plan->scanrelid, es);
3017 }
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:3036

◆ ExplainSeparatePlans()

void ExplainSeparatePlans ( ExplainState es)

Definition at line 3832 of file explain.c.

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

Referenced by ExplainExecuteQuery(), and ExplainQuery().

3833 {
3834  switch (es->format)
3835  {
3836  case EXPLAIN_FORMAT_TEXT:
3837  /* add a blank line */
3838  appendStringInfoChar(es->str, '\n');
3839  break;
3840 
3841  case EXPLAIN_FORMAT_XML:
3842  case EXPLAIN_FORMAT_JSON:
3843  case EXPLAIN_FORMAT_YAML:
3844  /* nothing to do */
3845  break;
3846  }
3847 }
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
ExplainFormat format
Definition: explain.h:39
StringInfo str
Definition: explain.h:30

◆ ExplainSubPlans()

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

Definition at line 3350 of file explain.c.

References bms_add_member(), bms_is_member(), ExplainNode(), lfirst, SubPlan::plan_id, SubPlan::plan_name, SubPlanState::planstate, ExplainState::printed_subplans, and SubPlanState::subplan.

Referenced by ExplainNode().

3352 {
3353  ListCell *lst;
3354 
3355  foreach(lst, plans)
3356  {
3357  SubPlanState *sps = (SubPlanState *) lfirst(lst);
3358  SubPlan *sp = sps->subplan;
3359 
3360  /*
3361  * There can be multiple SubPlan nodes referencing the same physical
3362  * subplan (same plan_id, which is its index in PlannedStmt.subplans).
3363  * We should print a subplan only once, so track which ones we already
3364  * printed. This state must be global across the plan tree, since the
3365  * duplicate nodes could be in different plan nodes, eg both a bitmap
3366  * indexscan's indexqual and its parent heapscan's recheck qual. (We
3367  * do not worry too much about which plan node we show the subplan as
3368  * attached to in such cases.)
3369  */
3370  if (bms_is_member(sp->plan_id, es->printed_subplans))
3371  continue;
3373  sp->plan_id);
3374 
3375  ExplainNode(sps->planstate, ancestors,
3376  relationship, sp->plan_name, es);
3377  }
3378 }
int plan_id
Definition: primnodes.h:695
Bitmapset * printed_subplans
Definition: explain.h:48
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1065
struct PlanState * planstate
Definition: execnodes.h:847
SubPlan * subplan
Definition: execnodes.h:846
char * plan_name
Definition: primnodes.h:697
#define lfirst(lc)
Definition: pg_list.h:190
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427

◆ ExplainTargetRel()

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

Definition at line 3036 of file explain.c.

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

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

3037 {
3038  char *objectname = NULL;
3039  char *namespace = NULL;
3040  const char *objecttag = NULL;
3041  RangeTblEntry *rte;
3042  char *refname;
3043 
3044  rte = rt_fetch(rti, es->rtable);
3045  refname = (char *) list_nth(es->rtable_names, rti - 1);
3046  if (refname == NULL)
3047  refname = rte->eref->aliasname;
3048 
3049  switch (nodeTag(plan))
3050  {
3051  case T_SeqScan:
3052  case T_SampleScan:
3053  case T_IndexScan:
3054  case T_IndexOnlyScan:
3055  case T_BitmapHeapScan:
3056  case T_TidScan:
3057  case T_ForeignScan:
3058  case T_CustomScan:
3059  case T_ModifyTable:
3060  /* Assert it's on a real relation */
3061  Assert(rte->rtekind == RTE_RELATION);
3062  objectname = get_rel_name(rte->relid);
3063  if (es->verbose)
3064  namespace = get_namespace_name(get_rel_namespace(rte->relid));
3065  objecttag = "Relation Name";
3066  break;
3067  case T_FunctionScan:
3068  {
3069  FunctionScan *fscan = (FunctionScan *) plan;
3070 
3071  /* Assert it's on a RangeFunction */
3072  Assert(rte->rtekind == RTE_FUNCTION);
3073 
3074  /*
3075  * If the expression is still a function call of a single
3076  * function, we can get the real name of the function.
3077  * Otherwise, punt. (Even if it was a single function call
3078  * originally, the optimizer could have simplified it away.)
3079  */
3080  if (list_length(fscan->functions) == 1)
3081  {
3082  RangeTblFunction *rtfunc = (RangeTblFunction *) linitial(fscan->functions);
3083 
3084  if (IsA(rtfunc->funcexpr, FuncExpr))
3085  {
3086  FuncExpr *funcexpr = (FuncExpr *) rtfunc->funcexpr;
3087  Oid funcid = funcexpr->funcid;
3088 
3089  objectname = get_func_name(funcid);
3090  if (es->verbose)
3091  namespace =
3093  }
3094  }
3095  objecttag = "Function Name";
3096  }
3097  break;
3098  case T_TableFuncScan:
3099  Assert(rte->rtekind == RTE_TABLEFUNC);
3100  objectname = "xmltable";
3101  objecttag = "Table Function Name";
3102  break;
3103  case T_ValuesScan:
3104  Assert(rte->rtekind == RTE_VALUES);
3105  break;
3106  case T_CteScan:
3107  /* Assert it's on a non-self-reference CTE */
3108  Assert(rte->rtekind == RTE_CTE);
3109  Assert(!rte->self_reference);
3110  objectname = rte->ctename;
3111  objecttag = "CTE Name";
3112  break;
3113  case T_NamedTuplestoreScan:
3115  objectname = rte->enrname;
3116  objecttag = "Tuplestore Name";
3117  break;
3118  case T_WorkTableScan:
3119  /* Assert it's on a self-reference CTE */
3120  Assert(rte->rtekind == RTE_CTE);
3121  Assert(rte->self_reference);
3122  objectname = rte->ctename;
3123  objecttag = "CTE Name";
3124  break;
3125  default:
3126  break;
3127  }
3128 
3129  if (es->format == EXPLAIN_FORMAT_TEXT)
3130  {
3131  appendStringInfoString(es->str, " on");
3132  if (namespace != NULL)
3133  appendStringInfo(es->str, " %s.%s", quote_identifier(namespace),
3134  quote_identifier(objectname));
3135  else if (objectname != NULL)
3136  appendStringInfo(es->str, " %s", quote_identifier(objectname));
3137  if (objectname == NULL || strcmp(refname, objectname) != 0)
3138  appendStringInfo(es->str, " %s", quote_identifier(refname));
3139  }
3140  else
3141  {
3142  if (objecttag != NULL && objectname != NULL)
3143  ExplainPropertyText(objecttag, objectname, es);
3144  if (namespace != NULL)
3145  ExplainPropertyText("Schema", namespace, es);
3146  ExplainPropertyText("Alias", refname, es);
3147  }
3148 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10640
Oid get_func_namespace(Oid funcid)
Definition: lsyscache.c:1434
List * functions
Definition: plannodes.h:521
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1754
unsigned int Oid
Definition: postgres_ext.h:31
List * rtable_names
Definition: explain.h:46
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3575
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
#define linitial(l)
Definition: pg_list.h:195
Oid funcid
Definition: primnodes.h:455
static void * list_nth(const List *list, int n)
Definition: pg_list.h:277
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1410
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3094
char * enrname
Definition: parsenodes.h:1085
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
bool self_reference
Definition: parsenodes.h:1058
bool verbose
Definition: explain.h:32
#define Assert(condition)
Definition: c.h:739
char * aliasname
Definition: primnodes.h:42
static int list_length(const List *l)
Definition: pg_list.h:169
ExplainFormat format
Definition: explain.h:39
#define nodeTag(nodeptr)
Definition: nodes.h:530
RTEKind rtekind
Definition: parsenodes.h:974
char * ctename
Definition: parsenodes.h:1056
Alias * eref
Definition: parsenodes.h:1092
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
StringInfo str
Definition: explain.h:30
List * rtable
Definition: explain.h:45

◆ ExplainXMLTag()

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

Definition at line 3861 of file explain.c.

References appendStringInfoChar(), appendStringInfoCharMacro, appendStringInfoSpaces(), appendStringInfoString(), ExplainState::indent, ExplainState::str, X_CLOSE_IMMEDIATE, X_CLOSING, and X_NOWHITESPACE.

Referenced by ExplainCloseGroup(), ExplainDummyGroup(), ExplainOpenGroup(), ExplainProperty(), and ExplainPropertyList().

3862 {
3863  const char *s;
3864  const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
3865 
3866  if ((flags & X_NOWHITESPACE) == 0)
3867  appendStringInfoSpaces(es->str, 2 * es->indent);
3868  appendStringInfoCharMacro(es->str, '<');
3869  if ((flags & X_CLOSING) != 0)
3870  appendStringInfoCharMacro(es->str, '/');
3871  for (s = tagname; *s; s++)
3872  appendStringInfoChar(es->str, strchr(valid, *s) ? *s : '-');
3873  if ((flags & X_CLOSE_IMMEDIATE) != 0)
3874  appendStringInfoString(es->str, " /");
3875  appendStringInfoCharMacro(es->str, '>');
3876  if ((flags & X_NOWHITESPACE) == 0)
3877  appendStringInfoCharMacro(es->str, '\n');
3878 }
#define X_CLOSING
Definition: explain.c:52
#define appendStringInfoCharMacro(str, ch)
Definition: stringinfo.h:128
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
int indent
Definition: explain.h:41
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
#define X_NOWHITESPACE
Definition: explain.c:54
#define X_CLOSE_IMMEDIATE
Definition: explain.c:53
StringInfo str
Definition: explain.h:30

◆ ExplainYAMLLineStarting()

static void ExplainYAMLLineStarting ( ExplainState es)
static

Definition at line 3908 of file explain.c.

References appendStringInfoChar(), appendStringInfoSpaces(), Assert, EXPLAIN_FORMAT_YAML, ExplainState::format, ExplainState::grouping_stack, ExplainState::indent, linitial_int, and ExplainState::str.

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

3909 {
3911  if (linitial_int(es->grouping_stack) == 0)
3912  {
3913  linitial_int(es->grouping_stack) = 1;
3914  }
3915  else
3916  {
3917  appendStringInfoChar(es->str, '\n');
3918  appendStringInfoSpaces(es->str, es->indent * 2);
3919  }
3920 }
#define linitial_int(l)
Definition: pg_list.h:196
List * grouping_stack
Definition: explain.h:42
int indent
Definition: explain.h:41
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
#define Assert(condition)
Definition: c.h:739
ExplainFormat format
Definition: explain.h:39
StringInfo str
Definition: explain.h:30

◆ NewExplainState()

ExplainState* NewExplainState ( void  )

Definition at line 285 of file explain.c.

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

Referenced by explain_ExecutorEnd(), and ExplainQuery().

286 {
287  ExplainState *es = (ExplainState *) palloc0(sizeof(ExplainState));
288 
289  /* Set default options (most fields can be left as zeroes). */
290  es->costs = true;
291  /* Prepare output buffer. */
292  es->str = makeStringInfo();
293 
294  return es;
295 }
StringInfo makeStringInfo(void)
Definition: stringinfo.c:41
bool costs
Definition: explain.h:34
void * palloc0(Size size)
Definition: mcxt.c:980
StringInfo str
Definition: explain.h:30

◆ report_triggers()

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

Definition at line 910 of file explain.c.

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

Referenced by ExplainPrintTriggers().

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

◆ show_agg_keys()

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

Definition at line 2204 of file explain.c.

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

Referenced by ExplainNode().

2206 {
2207  Agg *plan = (Agg *) astate->ss.ps.plan;
2208 
2209  if (plan->numCols > 0 || plan->groupingSets)
2210  {
2211  /* The key columns refer to the tlist of the child plan */
2212  ancestors = lcons(astate, ancestors);
2213 
2214  if (plan->groupingSets)
2215  show_grouping_sets(outerPlanState(astate), plan, ancestors, es);
2216  else
2217  show_sort_group_keys(outerPlanState(astate), "Group Key",
2218  plan->numCols, plan->grpColIdx,
2219  NULL, NULL, NULL,
2220  ancestors, es);
2221 
2222  ancestors = list_delete_first(ancestors);
2223  }
2224 }
int numCols
Definition: plannodes.h:807
AttrNumber * grpColIdx
Definition: plannodes.h:808
ScanState ss
Definition: execnodes.h:2035
PlanState ps
Definition: execnodes.h:1330
#define outerPlanState(node)
Definition: execnodes.h:1033
static void show_grouping_sets(PlanState *planstate, Agg *agg, List *ancestors, ExplainState *es)
Definition: explain.c:2227
List * groupingSets
Definition: plannodes.h:814
Plan * plan
Definition: execnodes.h:939
List * lcons(void *datum, List *list)
Definition: list.c:454
Definition: plannodes.h:802
static void show_sort_group_keys(PlanState *planstate, const char *qlabel, int nkeys, AttrNumber *keycols, Oid *sortOperators, Oid *collations, bool *nullsFirst, List *ancestors, ExplainState *es)
Definition: explain.c:2356
List * list_delete_first(List *list)
Definition: list.c:861

◆ show_buffer_usage()

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

Definition at line 2851 of file explain.c.

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

Referenced by ExplainNode().

2852 {
2853  if (es->format == EXPLAIN_FORMAT_TEXT)
2854  {
2855  bool has_shared = (usage->shared_blks_hit > 0 ||
2856  usage->shared_blks_read > 0 ||
2857  usage->shared_blks_dirtied > 0 ||
2858  usage->shared_blks_written > 0);
2859  bool has_local = (usage->local_blks_hit > 0 ||
2860  usage->local_blks_read > 0 ||
2861  usage->local_blks_dirtied > 0 ||
2862  usage->local_blks_written > 0);
2863  bool has_temp = (usage->temp_blks_read > 0 ||
2864  usage->temp_blks_written > 0);
2865  bool has_timing = (!INSTR_TIME_IS_ZERO(usage->blk_read_time) ||
2867 
2868  /* Show only positive counter values. */
2869  if (has_shared || has_local || has_temp)
2870  {
2871  appendStringInfoSpaces(es->str, es->indent * 2);
2872  appendStringInfoString(es->str, "Buffers:");
2873 
2874  if (has_shared)
2875  {
2876  appendStringInfoString(es->str, " shared");
2877  if (usage->shared_blks_hit > 0)
2878  appendStringInfo(es->str, " hit=%ld",
2879  usage->shared_blks_hit);
2880  if (usage->shared_blks_read > 0)
2881  appendStringInfo(es->str, " read=%ld",
2882  usage->shared_blks_read);
2883  if (usage->shared_blks_dirtied > 0)
2884  appendStringInfo(es->str, " dirtied=%ld",
2885  usage->shared_blks_dirtied);
2886  if (usage->shared_blks_written > 0)
2887  appendStringInfo(es->str, " written=%ld",
2888  usage->shared_blks_written);
2889  if (has_local || has_temp)
2890  appendStringInfoChar(es->str, ',');
2891  }
2892  if (has_local)
2893  {
2894  appendStringInfoString(es->str, " local");
2895  if (usage->local_blks_hit > 0)
2896  appendStringInfo(es->str, " hit=%ld",
2897  usage->local_blks_hit);
2898  if (usage->local_blks_read > 0)
2899  appendStringInfo(es->str, " read=%ld",
2900  usage->local_blks_read);
2901  if (usage->local_blks_dirtied > 0)
2902  appendStringInfo(es->str, " dirtied=%ld",
2903  usage->local_blks_dirtied);
2904  if (usage->local_blks_written > 0)
2905  appendStringInfo(es->str, " written=%ld",
2906  usage->local_blks_written);
2907  if (has_temp)
2908  appendStringInfoChar(es->str, ',');
2909  }
2910  if (has_temp)
2911  {
2912  appendStringInfoString(es->str, " temp");
2913  if (usage->temp_blks_read > 0)
2914  appendStringInfo(es->str, " read=%ld",
2915  usage->temp_blks_read);
2916  if (usage->temp_blks_written > 0)
2917  appendStringInfo(es->str, " written=%ld",
2918  usage->temp_blks_written);
2919  }
2920  appendStringInfoChar(es->str, '\n');
2921  }
2922 
2923  /* As above, show only positive counter values. */
2924  if (has_timing)
2925  {
2926  appendStringInfoSpaces(es->str, es->indent * 2);
2927  appendStringInfoString(es->str, "I/O Timings:");
2928  if (!INSTR_TIME_IS_ZERO(usage->blk_read_time))
2929  appendStringInfo(es->str, " read=%0.3f",
2931  if (!INSTR_TIME_IS_ZERO(usage->blk_write_time))
2932  appendStringInfo(es->str, " write=%0.3f",
2934  appendStringInfoChar(es->str, '\n');
2935  }
2936  }
2937  else
2938  {
2939  ExplainPropertyInteger("Shared Hit Blocks", NULL,
2940  usage->shared_blks_hit, es);
2941  ExplainPropertyInteger("Shared Read Blocks", NULL,
2942  usage->shared_blks_read, es);
2943  ExplainPropertyInteger("Shared Dirtied Blocks", NULL,
2944  usage->shared_blks_dirtied, es);
2945  ExplainPropertyInteger("Shared Written Blocks", NULL,
2946  usage->shared_blks_written, es);
2947  ExplainPropertyInteger("Local Hit Blocks", NULL,
2948  usage->local_blks_hit, es);
2949  ExplainPropertyInteger("Local Read Blocks", NULL,
2950  usage->local_blks_read, es);
2951  ExplainPropertyInteger("Local Dirtied Blocks", NULL,
2952  usage->local_blks_dirtied, es);
2953  ExplainPropertyInteger("Local Written Blocks", NULL,
2954  usage->local_blks_written, es);
2955  ExplainPropertyInteger("Temp Read Blocks", NULL,
2956  usage->temp_blks_read, es);
2957  ExplainPropertyInteger("Temp Written Blocks", NULL,
2958  usage->temp_blks_written, es);
2959  if (track_io_timing)
2960  {
2961  ExplainPropertyFloat("I/O Read Time", "ms",
2963  3, es);
2964  ExplainPropertyFloat("I/O Write Time", "ms",
2966  3, es);
2967  }
2968  }
2969 }
long local_blks_hit
Definition: instrument.h:25
long local_blks_dirtied
Definition: instrument.h:27
long local_blks_read
Definition: instrument.h:26
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:3584
instr_time blk_read_time
Definition: instrument.h:31
void ExplainPropertyFloat(const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
Definition: explain.c:3598
#define INSTR_TIME_GET_MILLISEC(t)
Definition: instr_time.h:202
long shared_blks_read
Definition: instrument.h:22
long temp_blks_written
Definition: instrument.h:30
#define INSTR_TIME_IS_ZERO(t)
Definition: instr_time.h:152
long shared_blks_written
Definition: instrument.h:24
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
long shared_blks_dirtied
Definition: instrument.h:23
int indent
Definition: explain.h:41
long temp_blks_read
Definition: instrument.h:29
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
instr_time blk_write_time
Definition: instrument.h:32
ExplainFormat format
Definition: explain.h:39
long shared_blks_hit
Definition: instrument.h:21
long local_blks_written
Definition: instrument.h:28
StringInfo str
Definition: explain.h:30
bool track_io_timing
Definition: bufmgr.c:112

◆ show_eval_params()

static void show_eval_params ( Bitmapset bms_params,
ExplainState es 
)
static

Definition at line 2802 of file explain.c.

References Assert, bms_next_member(), ExplainPropertyList(), lappend(), NIL, pstrdup(), and snprintf.

Referenced by ExplainNode().

2803 {
2804  int paramid = -1;
2805  List *params = NIL;
2806 
2807  Assert(bms_params);
2808 
2809  while ((paramid = bms_next_member(bms_params, paramid)) >= 0)
2810  {
2811  char param[32];
2812 
2813  snprintf(param, sizeof(param), "$%d", paramid);
2814  params = lappend(params, pstrdup(param));
2815  }
2816 
2817  if (params)
2818  ExplainPropertyList("Params Evaluated", params, es);
2819 }
#define NIL
Definition: pg_list.h:65
char * pstrdup(const char *in)
Definition: mcxt.c:1186
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
List * lappend(List *list, void *datum)
Definition: list.c:322
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:3399
#define Assert(condition)
Definition: c.h:739
Definition: pg_list.h:50
#define snprintf
Definition: port.h:192

◆ show_expression()

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

Definition at line 2101 of file explain.c.

References config_generic::context, ExplainState::deparse_cxt, deparse_expression(), ExplainPropertyText(), and set_deparse_context_planstate().

Referenced by ExplainNode(), and show_qual().

2104 {
2105  List *context;
2106  char *exprstr;
2107 
2108  /* Set up deparsing context */
2110  (Node *) planstate,
2111  ancestors);
2112 
2113  /* Deparse the expression */
2114  exprstr = deparse_expression(node, context, useprefix, false);
2115 
2116  /* And add to es->str */
2117  ExplainPropertyText(qlabel, exprstr, es);
2118 }
Definition: nodes.h:525
List * deparse_cxt
Definition: explain.h:47
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3575
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:3350
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:3197
Definition: pg_list.h:50

◆ show_foreignscan_info()

static void show_foreignscan_info ( ForeignScanState fsstate,
ExplainState es 
)
static

Definition at line 2781 of file explain.c.

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

Referenced by ExplainNode().

2782 {
2783  FdwRoutine *fdwroutine = fsstate->fdwroutine;
2784 
2785  /* Let the FDW emit whatever fields it wants */
2786  if (((ForeignScan *) fsstate->ss.ps.plan)->operation != CMD_SELECT)
2787  {
2788  if (fdwroutine->ExplainDirectModify != NULL)
2789  fdwroutine->ExplainDirectModify(fsstate, es);
2790  }
2791  else
2792  {
2793  if (fdwroutine->ExplainForeignScan != NULL)
2794  fdwroutine->ExplainForeignScan(fsstate, es);
2795  }
2796 }
ScanState ss
Definition: execnodes.h:1784
ExplainForeignScan_function ExplainForeignScan
Definition: fdwapi.h:229
PlanState ps
Definition: execnodes.h:1330
ExplainDirectModify_function ExplainDirectModify
Definition: fdwapi.h:231
struct FdwRoutine * fdwroutine
Definition: execnodes.h:1788
Plan * plan
Definition: execnodes.h:939

◆ show_group_keys()

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

Definition at line 2336 of file explain.c.

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

Referenced by ExplainNode().

2338 {
2339  Group *plan = (Group *) gstate->ss.ps.plan;
2340 
2341  /* The key columns refer to the tlist of the child plan */
2342  ancestors = lcons(gstate, ancestors);
2343  show_sort_group_keys(outerPlanState(gstate), "Group Key",
2344  plan->numCols, plan->grpColIdx,
2345  NULL, NULL, NULL,
2346  ancestors, es);
2347  ancestors = list_delete_first(ancestors);
2348 }
ScanState ss
Definition: execnodes.h:2009
PlanState ps
Definition: execnodes.h:1330
#define outerPlanState(node)
Definition: execnodes.h:1033
int numCols
Definition: plannodes.h:782
Plan * plan
Definition: execnodes.h:939
List * lcons(void *datum, List *list)
Definition: list.c:454
AttrNumber * grpColIdx
Definition: plannodes.h:783
static void show_sort_group_keys(PlanState *planstate, const char *qlabel, int nkeys, AttrNumber *keycols, Oid *sortOperators, Oid *collations, bool *nullsFirst, List *ancestors, ExplainState *es)
Definition: explain.c:2356
List * list_delete_first(List *list)
Definition: list.c:861

◆ show_grouping_set_keys()

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

Definition at line 2258 of file explain.c.

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

Referenced by show_grouping_sets().

2262 {
2263  Plan *plan = planstate->plan;
2264  char *exprstr;
2265  ListCell *lc;
2266  List *gsets = aggnode->groupingSets;
2267  AttrNumber *keycols = aggnode->grpColIdx;
2268  const char *keyname;
2269  const char *keysetname;
2270 
2271  if (aggnode->aggstrategy == AGG_HASHED || aggnode->aggstrategy == AGG_MIXED)
2272  {
2273  keyname = "Hash Key";
2274  keysetname = "Hash Keys";
2275  }
2276  else
2277  {
2278  keyname = "Group Key";
2279  keysetname = "Group Keys";
2280  }
2281 
2282  ExplainOpenGroup("Grouping Set", NULL, true, es);
2283 
2284  if (sortnode)
2285  {
2286  show_sort_group_keys(planstate, "Sort Key",
2287  sortnode->numCols, sortnode->sortColIdx,
2288  sortnode->sortOperators, sortnode->collations,
2289  sortnode->nullsFirst,
2290  ancestors, es);
2291  if (es->format == EXPLAIN_FORMAT_TEXT)
2292  es->indent++;
2293  }
2294 
2295  ExplainOpenGroup(keysetname, keysetname, false, es);
2296 
2297  foreach(lc, gsets)
2298  {
2299  List *result = NIL;
2300  ListCell *lc2;
2301 
2302  foreach(lc2, (List *) lfirst(lc))
2303  {
2304  Index i = lfirst_int(lc2);
2305  AttrNumber keyresno = keycols[i];
2306  TargetEntry *target = get_tle_by_resno(plan->targetlist,
2307  keyresno);
2308 
2309  if (!target)
2310  elog(ERROR, "no tlist entry for key %d", keyresno);
2311  /* Deparse the expression, showing any top-level cast */
2312  exprstr = deparse_expression((Node *) target->expr, context,
2313  useprefix, true);
2314 
2315  result = lappend(result, exprstr);
2316  }
2317 
2318  if (!result && es->format == EXPLAIN_FORMAT_TEXT)
2319  ExplainPropertyText(keyname, "()", es);
2320  else
2321  ExplainPropertyListNested(keyname, result, es);
2322  }
2323 
2324  ExplainCloseGroup(keysetname, keysetname, false, es);
2325 
2326  if (sortnode && es->format == EXPLAIN_FORMAT_TEXT)
2327  es->indent--;
2328 
2329  ExplainCloseGroup("Grouping Set", NULL, true, es);
2330 }
#define NIL
Definition: pg_list.h:65
AttrNumber * grpColIdx
Definition: plannodes.h:808
Definition: nodes.h:525
bool * nullsFirst
Definition: plannodes.h:770
Oid * sortOperators
Definition: plannodes.h:768
void ExplainPropertyListNested(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:3469
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3575
AggStrategy aggstrategy
Definition: plannodes.h:805
#define ERROR
Definition: elog.h:43
#define lfirst_int(lc)
Definition: pg_list.h:191
int indent
Definition: explain.h:41
List * lappend(List *list, void *datum)
Definition: list.c:322
int numCols
Definition: plannodes.h:766
List * groupingSets
Definition: plannodes.h:814
unsigned int Index
Definition: c.h:476
Plan * plan
Definition: execnodes.h:939
#define lfirst(lc)
Definition: pg_list.h:190
Expr * expr
Definition: primnodes.h:1393
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:3197
ExplainFormat format
Definition: explain.h:39
List * targetlist
Definition: plannodes.h:140
AttrNumber * sortColIdx
Definition: plannodes.h:767
#define elog(elevel,...)
Definition: elog.h:228
int i
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3690
static void show_sort_group_keys(PlanState *planstate, const char *qlabel, int nkeys, AttrNumber *keycols, Oid *sortOperators, Oid *collations, bool *nullsFirst, List *ancestors, ExplainState *es)
Definition: explain.c:2356
Oid * collations
Definition: plannodes.h:769
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3627
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21

◆ show_grouping_sets()

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

Definition at line 2227 of file explain.c.

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

Referenced by show_agg_keys().

2229 {
2230  List *context;
2231  bool useprefix;
2232  ListCell *lc;
2233 
2234  /* Set up deparsing context */
2236  (Node *) planstate,
2237  ancestors);
2238  useprefix = (list_length(es->rtable) > 1 || es->verbose);
2239 
2240  ExplainOpenGroup("Grouping Sets", "Grouping Sets", false, es);
2241 
2242  show_grouping_set_keys(planstate, agg, NULL,
2243  context, useprefix, ancestors, es);
2244 
2245  foreach(lc, agg->chain)
2246  {
2247  Agg *aggnode = lfirst(lc);
2248  Sort *sortnode = (Sort *) aggnode->plan.lefttree;
2249 
2250  show_grouping_set_keys(planstate, aggnode, sortnode,
2251  context, useprefix, ancestors, es);
2252  }
2253 
2254  ExplainCloseGroup("Grouping Sets", "Grouping Sets", false, es);
2255 }
Definition: nodes.h:525
List * deparse_cxt
Definition: explain.h:47
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:3350
Plan plan
Definition: plannodes.h:804
bool verbose
Definition: explain.h:32
#define lfirst(lc)
Definition: pg_list.h:190
static int list_length(const List *l)
Definition: pg_list.h:169
struct Plan * lefttree
Definition: plannodes.h:142
static void show_grouping_set_keys(PlanState *planstate, Agg *aggnode, Sort *sortnode, List *context, bool useprefix, List *ancestors, ExplainState *es)
Definition: explain.c:2258
List * chain
Definition: plannodes.h:815
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3690
Definition: plannodes.h:802
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3627
Definition: pg_list.h:50
List * rtable
Definition: explain.h:45

◆ show_hash_info()

static void show_hash_info ( HashState hashstate,
ExplainState es 
)
static

Definition at line 2619 of file explain.c.

References appendStringInfo(), appendStringInfoSpaces(), ExecHashGetInstrumentation(), EXPLAIN_FORMAT_TEXT, ExplainPropertyInteger(), ExplainState::format, HashState::hashtable, SharedHashInfo::hinstrument, i, ExplainState::indent, Max, HashInstrumentation::nbatch, HashInstrumentation::nbatch_original, HashInstrumentation::nbuckets, HashInstrumentation::nbuckets_original, SharedHashInfo::num_workers, HashState::shared_info, HashInstrumentation::space_peak, and ExplainState::str.

Referenced by ExplainNode().

2620 {
2621  HashInstrumentation hinstrument = {0};
2622 
2623  /*
2624  * In a parallel query, the leader process may or may not have run the
2625  * hash join, and even if it did it may not have built a hash table due to
2626  * timing (if it started late it might have seen no tuples in the outer
2627  * relation and skipped building the hash table). Therefore we have to be
2628  * prepared to get instrumentation data from all participants.
2629  */
2630  if (hashstate->hashtable)
2631  ExecHashGetInstrumentation(&hinstrument, hashstate->hashtable);
2632 
2633  /*
2634  * Merge results from workers. In the parallel-oblivious case, the
2635  * results from all participants should be identical, except where
2636  * participants didn't run the join at all so have no data. In the
2637  * parallel-aware case, we need to consider all the results. Each worker
2638  * may have seen a different subset of batches and we want to find the
2639  * highest memory usage for any one batch across all batches.
2640  */
2641  if (hashstate->shared_info)
2642  {
2643  SharedHashInfo *shared_info = hashstate->shared_info;
2644  int i;
2645 
2646  for (i = 0; i < shared_info->num_workers; ++i)
2647  {
2648  HashInstrumentation *worker_hi = &shared_info->hinstrument[i];
2649 
2650  if (worker_hi->nbatch > 0)
2651  {
2652  /*
2653  * Every participant should agree on the buckets, so to be
2654  * sure we have a value we'll just overwrite each time.
2655  */
2656  hinstrument.nbuckets = worker_hi->nbuckets;
2657  hinstrument.nbuckets_original = worker_hi->nbuckets_original;
2658 
2659  /*
2660  * Normally every participant should agree on the number of
2661  * batches too, but it's possible for a backend that started
2662  * late and missed the whole join not to have the final nbatch
2663  * number. So we'll take the largest number.
2664  */
2665  hinstrument.nbatch = Max(hinstrument.nbatch, worker_hi->nbatch);
2666  hinstrument.nbatch_original = worker_hi->nbatch_original;
2667 
2668  /*
2669  * In a parallel-aware hash join, for now we report the
2670  * maximum peak memory reported by any worker.
2671  */
2672  hinstrument.space_peak =
2673  Max(hinstrument.space_peak, worker_hi->space_peak);
2674  }
2675  }
2676  }
2677 
2678  if (hinstrument.nbatch > 0)
2679  {
2680  long spacePeakKb = (hinstrument.space_peak + 1023) / 1024;
2681 
2682  if (es->format != EXPLAIN_FORMAT_TEXT)
2683  {
2684  ExplainPropertyInteger("Hash Buckets", NULL,
2685  hinstrument.nbuckets, es);
2686  ExplainPropertyInteger("Original Hash Buckets", NULL,
2687  hinstrument.nbuckets_original, es);
2688  ExplainPropertyInteger("Hash Batches", NULL,
2689  hinstrument.nbatch, es);
2690  ExplainPropertyInteger("Original Hash Batches", NULL,
2691  hinstrument.nbatch_original, es);
2692  ExplainPropertyInteger("Peak Memory Usage", "kB",
2693  spacePeakKb, es);
2694  }
2695  else if (hinstrument.nbatch_original != hinstrument.nbatch ||
2696  hinstrument.nbuckets_original != hinstrument.nbuckets)
2697  {
2698  appendStringInfoSpaces(es->str, es->indent * 2);
2699  appendStringInfo(es->str,
2700  "Buckets: %d (originally %d)