PostgreSQL Source Code  git master
explain.c File Reference
#include "postgres.h"
#include "access/xact.h"
#include "catalog/pg_collation.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/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteHandler.h"
#include "storage/bufmgr.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.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)
 
void ExplainPrintPlan (ExplainState *es, QueryDesc *queryDesc)
 
void ExplainPrintTriggers (ExplainState *es, QueryDesc *queryDesc)
 
void ExplainPrintJIT (ExplainState *es, QueryDesc *queryDesc)
 
void ExplainQueryText (ExplainState *es, QueryDesc *queryDesc)
 
void ExplainPropertyList (const char *qlabel, List *data, ExplainState *es)
 
void ExplainPropertyListNested (const char *qlabel, List *data, ExplainState *es)
 
void ExplainPropertyText (const char *qlabel, const char *value, ExplainState *es)
 
void ExplainPropertyInteger (const char *qlabel, const char *unit, int64 value, ExplainState *es)
 
void ExplainPropertyFloat (const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
 
void ExplainPropertyBool (const char *qlabel, bool value, ExplainState *es)
 
void ExplainOpenGroup (const char *objtype, const char *labelname, bool labeled, ExplainState *es)
 
void ExplainCloseGroup (const char *objtype, const char *labelname, bool labeled, ExplainState *es)
 
void ExplainBeginOutput (ExplainState *es)
 
void ExplainEndOutput (ExplainState *es)
 
void ExplainSeparatePlans (ExplainState *es)
 

Variables

ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL
 
explain_get_index_name_hook_type explain_get_index_name_hook = NULL
 

Macro Definition Documentation

◆ X_CLOSE_IMMEDIATE

#define X_CLOSE_IMMEDIATE   2

Definition at line 54 of file explain.c.

Referenced by ExplainDummyGroup(), and ExplainXMLTag().

◆ X_CLOSING

#define X_CLOSING   1

Definition at line 53 of file explain.c.

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

◆ X_NOWHITESPACE

#define X_NOWHITESPACE   4

Definition at line 55 of file explain.c.

Referenced by ExplainProperty(), and ExplainXMLTag().

◆ X_OPENING

#define X_OPENING   0

Definition at line 52 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 830 of file explain.c.

References INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, and INSTR_TIME_SUBTRACT.

Referenced by ExplainOnePlan(), and IsCheckpointOnSchedule().

831 {
832  instr_time endtime;
833 
834  INSTR_TIME_SET_CURRENT(endtime);
835  INSTR_TIME_SUBTRACT(endtime, *starttime);
836  return INSTR_TIME_GET_DOUBLE(endtime);
837 }
struct timeval instr_time
Definition: instr_time.h:147
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:196
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:167
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153

◆ escape_yaml()

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

Definition at line 3760 of file explain.c.

References escape_json().

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

3761 {
3762  escape_json(buf, str);
3763 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2461

◆ explain_get_index_name()

static const char * explain_get_index_name ( Oid  indexId)
static

Definition at line 2655 of file explain.c.

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

Referenced by ExplainIndexScanDetails(), and ExplainNode().

2656 {
2657  const char *result;
2658 
2660  result = (*explain_get_index_name_hook) (indexId);
2661  else
2662  result = NULL;
2663  if (result == NULL)
2664  {
2665  /* default behavior: look in the catalogs and quote it */
2666  result = get_rel_name(indexId);
2667  if (result == NULL)
2668  elog(ERROR, "cache lookup failed for index %u", indexId);
2669  result = quote_identifier(result);
2670  }
2671  return result;
2672 }
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10488
#define ERROR
Definition: elog.h:43
explain_get_index_name_hook_type explain_get_index_name_hook
Definition: explain.c:48
#define elog
Definition: elog.h:219
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730

◆ ExplainBeginOutput()

void ExplainBeginOutput ( ExplainState es)

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

3600 {
3601  switch (es->format)
3602  {
3603  case EXPLAIN_FORMAT_TEXT:
3604  /* nothing to do */
3605  break;
3606 
3607  case EXPLAIN_FORMAT_XML:
3609  "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
3610  es->indent++;
3611  break;
3612 
3613  case EXPLAIN_FORMAT_JSON:
3614  /* top-level structure is an array of plans */
3615  appendStringInfoChar(es->str, '[');
3616  es->grouping_stack = lcons_int(0, es->grouping_stack);
3617  es->indent++;
3618  break;
3619 
3620  case EXPLAIN_FORMAT_YAML:
3621  es->grouping_stack = lcons_int(0, es->grouping_stack);
3622  break;
3623  }
3624 }
List * lcons_int(int datum, List *list)
Definition: list.c:277
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30

◆ ExplainCloseGroup()

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

Definition at line 3517 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(), ExplainPrintTriggers(), report_triggers(), show_grouping_set_keys(), show_grouping_sets(), show_modifytable_info(), and show_sort_info().

3519 {
3520  switch (es->format)
3521  {
3522  case EXPLAIN_FORMAT_TEXT:
3523  /* nothing to do */
3524  break;
3525 
3526  case EXPLAIN_FORMAT_XML:
3527  es->indent--;
3528  ExplainXMLTag(objtype, X_CLOSING, es);
3529  break;
3530 
3531  case EXPLAIN_FORMAT_JSON:
3532  es->indent--;
3533  appendStringInfoChar(es->str, '\n');
3534  appendStringInfoSpaces(es->str, 2 * es->indent);
3535  appendStringInfoChar(es->str, labeled ? '}' : ']');
3537  break;
3538 
3539  case EXPLAIN_FORMAT_YAML:
3540  es->indent--;
3542  break;
3543  }
3544 }
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3688
#define X_CLOSING
Definition: explain.c:53
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
List * list_delete_first(List *list)
Definition: list.c:666

◆ ExplainCustomChildren()

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

Definition at line 3211 of file explain.c.

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

Referenced by ExplainNode().

3212 {
3213  ListCell *cell;
3214  const char *label =
3215  (list_length(css->custom_ps) != 1 ? "children" : "child");
3216 
3217  foreach(cell, css->custom_ps)
3218  ExplainNode((PlanState *) lfirst(cell), ancestors, label, NULL, es);
3219 }
List * custom_ps
Definition: execnodes.h:1668
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:914
static char * label
Definition: pg_basebackup.c:84
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89

◆ ExplainDummyGroup()

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

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

3554 {
3555  switch (es->format)
3556  {
3557  case EXPLAIN_FORMAT_TEXT:
3558  /* nothing to do */
3559  break;
3560 
3561  case EXPLAIN_FORMAT_XML:
3562  ExplainXMLTag(objtype, X_CLOSE_IMMEDIATE, es);
3563  break;
3564 
3565  case EXPLAIN_FORMAT_JSON:
3567  appendStringInfoSpaces(es->str, 2 * es->indent);
3568  if (labelname)
3569  {
3570  escape_json(es->str, labelname);
3571  appendStringInfoString(es->str, ": ");
3572  }
3573  escape_json(es->str, objtype);
3574  break;
3575 
3576  case EXPLAIN_FORMAT_YAML:
3578  if (labelname)
3579  {
3580  escape_yaml(es->str, labelname);
3581  appendStringInfoString(es->str, ": ");
3582  }
3583  else
3584  {
3585  appendStringInfoString(es->str, "- ");
3586  }
3587  escape_yaml(es->str, objtype);
3588  break;
3589  }
3590 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2461
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3688
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3735
int indent
Definition: explain.h:40
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3760
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3715
ExplainFormat format
Definition: explain.h:38
#define X_CLOSE_IMMEDIATE
Definition: explain.c:54
StringInfo str
Definition: explain.h:30

◆ ExplainEndOutput()

void ExplainEndOutput ( ExplainState es)

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

3631 {
3632  switch (es->format)
3633  {
3634  case EXPLAIN_FORMAT_TEXT:
3635  /* nothing to do */
3636  break;
3637 
3638  case EXPLAIN_FORMAT_XML:
3639  es->indent--;
3640  appendStringInfoString(es->str, "</explain>");
3641  break;
3642 
3643  case EXPLAIN_FORMAT_JSON:
3644  es->indent--;
3645  appendStringInfoString(es->str, "\n]");
3647  break;
3648 
3649  case EXPLAIN_FORMAT_YAML:
3651  break;
3652  }
3653 }
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
List * list_delete_first(List *list)
Definition: list.c:666

◆ ExplainIndexScanDetails()

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

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

2804 {
2805  const char *indexname = explain_get_index_name(indexid);
2806 
2807  if (es->format == EXPLAIN_FORMAT_TEXT)
2808  {
2809  if (ScanDirectionIsBackward(indexorderdir))
2810  appendStringInfoString(es->str, " Backward");
2811  appendStringInfo(es->str, " using %s", indexname);
2812  }
2813  else
2814  {
2815  const char *scandir;
2816 
2817  switch (indexorderdir)
2818  {
2819  case BackwardScanDirection:
2820  scandir = "Backward";
2821  break;
2823  scandir = "NoMovement";
2824  break;
2825  case ForwardScanDirection:
2826  scandir = "Forward";
2827  break;
2828  default:
2829  scandir = "???";
2830  break;
2831  }
2832  ExplainPropertyText("Scan Direction", scandir, es);
2833  ExplainPropertyText("Index Name", indexname, es);
2834  }
2835 }
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3402
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
ExplainFormat format
Definition: explain.h:38
static const char * explain_get_index_name(Oid indexId)
Definition: explain.c:2655
StringInfo str
Definition: explain.h:30

◆ ExplainJSONLineEnding()

static void ExplainJSONLineEnding ( ExplainState es)
static

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

3716 {
3718  if (linitial_int(es->grouping_stack) != 0)
3719  appendStringInfoChar(es->str, ',');
3720  else
3721  linitial_int(es->grouping_stack) = 1;
3722  appendStringInfoChar(es->str, '\n');
3723 }
#define linitial_int(l)
Definition: pg_list.h:112
List * grouping_stack
Definition: explain.h:41
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
#define Assert(condition)
Definition: c.h:699
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30

◆ ExplainMemberNodes()

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

Definition at line 3150 of file explain.c.

References ExplainNode(), and ExplainPropertyInteger().

Referenced by ExplainNode().

3152 {
3153  int j;
3154 
3155  /*
3156  * The number of subnodes being lower than the number of subplans that was
3157  * specified in the plan means that some subnodes have been ignored per
3158  * instruction for the partition pruning code during the executor
3159  * initialization. To make this a bit less mysterious, we'll indicate
3160  * here that this has happened.
3161  */
3162  if (nsubnodes < nplans)
3163  ExplainPropertyInteger("Subplans Removed", NULL, nplans - nsubnodes, es);
3164 
3165  for (j = 0; j < nsubnodes; j++)
3166  ExplainNode(planstates[j], ancestors,
3167  "Member", NULL, es);
3168 }
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:3411
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:914

◆ ExplainModifyTarget()

static void ExplainModifyTarget ( ModifyTable plan,
ExplainState es 
)
static

Definition at line 2854 of file explain.c.

References ExplainTargetRel().

Referenced by ExplainNode().

2855 {
2856  ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
2857 }
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:2863

◆ ExplainNode()

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

Definition at line 914 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, EXPLAIN_FORMAT_TEXT, explain_get_index_name(), ExplainCloseGroup(), ExplainCustomChildren(), CustomExecMethods::ExplainCustomScan, ExplainIndexScanDetails(), ExplainMemberNodes(), ExplainModifyTarget(), ExplainOpenGroup(), 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, 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, 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, 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, and PlanState::worker_instrument.

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

917 {
918  Plan *plan = planstate->plan;
919  const char *pname; /* node type name for text output */
920  const char *sname; /* node type name for non-text output */
921  const char *strategy = NULL;
922  const char *partialmode = NULL;
923  const char *operation = NULL;
924  const char *custom_name = NULL;
925  int save_indent = es->indent;
926  bool haschildren;
927 
928  switch (nodeTag(plan))
929  {
930  case T_Result:
931  pname = sname = "Result";
932  break;
933  case T_ProjectSet:
934  pname = sname = "ProjectSet";
935  break;
936  case T_ModifyTable:
937  sname = "ModifyTable";
938  switch (((ModifyTable *) plan)->operation)
939  {
940  case CMD_INSERT:
941  pname = operation = "Insert";
942  break;
943  case CMD_UPDATE:
944  pname = operation = "Update";
945  break;
946  case CMD_DELETE:
947  pname = operation = "Delete";
948  break;
949  default:
950  pname = "???";
951  break;
952  }
953  break;
954  case T_Append:
955  pname = sname = "Append";
956  break;
957  case T_MergeAppend:
958  pname = sname = "Merge Append";
959  break;
960  case T_RecursiveUnion:
961  pname = sname = "Recursive Union";
962  break;
963  case T_BitmapAnd:
964  pname = sname = "BitmapAnd";
965  break;
966  case T_BitmapOr:
967  pname = sname = "BitmapOr";
968  break;
969  case T_NestLoop:
970  pname = sname = "Nested Loop";
971  break;
972  case T_MergeJoin:
973  pname = "Merge"; /* "Join" gets added by jointype switch */
974  sname = "Merge Join";
975  break;
976  case T_HashJoin:
977  pname = "Hash"; /* "Join" gets added by jointype switch */
978  sname = "Hash Join";
979  break;
980  case T_SeqScan:
981  pname = sname = "Seq Scan";
982  break;
983  case T_SampleScan:
984  pname = sname = "Sample Scan";
985  break;
986  case T_Gather:
987  pname = sname = "Gather";
988  break;
989  case T_GatherMerge:
990  pname = sname = "Gather Merge";
991  break;
992  case T_IndexScan:
993  pname = sname = "Index Scan";
994  break;
995  case T_IndexOnlyScan:
996  pname = sname = "Index Only Scan";
997  break;
998  case T_BitmapIndexScan:
999  pname = sname = "Bitmap Index Scan";
1000  break;
1001  case T_BitmapHeapScan:
1002  pname = sname = "Bitmap Heap Scan";
1003  break;
1004  case T_TidScan:
1005  pname = sname = "Tid Scan";
1006  break;
1007  case T_SubqueryScan:
1008  pname = sname = "Subquery Scan";
1009  break;
1010  case T_FunctionScan:
1011  pname = sname = "Function Scan";
1012  break;
1013  case T_TableFuncScan:
1014  pname = sname = "Table Function Scan";
1015  break;
1016  case T_ValuesScan:
1017  pname = sname = "Values Scan";
1018  break;
1019  case T_CteScan:
1020  pname = sname = "CTE Scan";
1021  break;
1022  case T_NamedTuplestoreScan:
1023  pname = sname = "Named Tuplestore Scan";
1024  break;
1025  case T_WorkTableScan:
1026  pname = sname = "WorkTable Scan";
1027  break;
1028  case T_ForeignScan:
1029  sname = "Foreign Scan";
1030  switch (((ForeignScan *) plan)->operation)
1031  {
1032  case CMD_SELECT:
1033  pname = "Foreign Scan";
1034  operation = "Select";
1035  break;
1036  case CMD_INSERT:
1037  pname = "Foreign Insert";
1038  operation = "Insert";
1039  break;
1040  case CMD_UPDATE:
1041  pname = "Foreign Update";
1042  operation = "Update";
1043  break;
1044  case CMD_DELETE:
1045  pname = "Foreign Delete";
1046  operation = "Delete";
1047  break;
1048  default:
1049  pname = "???";
1050  break;
1051  }
1052  break;
1053  case T_CustomScan:
1054  sname = "Custom Scan";
1055  custom_name = ((CustomScan *) plan)->methods->CustomName;
1056  if (custom_name)
1057  pname = psprintf("Custom Scan (%s)", custom_name);
1058  else
1059  pname = sname;
1060  break;
1061  case T_Material:
1062  pname = sname = "Materialize";
1063  break;
1064  case T_Sort:
1065  pname = sname = "Sort";
1066  break;
1067  case T_Group:
1068  pname = sname = "Group";
1069  break;
1070  case T_Agg:
1071  {
1072  Agg *agg = (Agg *) plan;
1073 
1074  sname = "Aggregate";
1075  switch (agg->aggstrategy)
1076  {
1077  case AGG_PLAIN:
1078  pname = "Aggregate";
1079  strategy = "Plain";
1080  break;
1081  case AGG_SORTED:
1082  pname = "GroupAggregate";
1083  strategy = "Sorted";
1084  break;
1085  case AGG_HASHED:
1086  pname = "HashAggregate";
1087  strategy = "Hashed";
1088  break;
1089  case AGG_MIXED:
1090  pname = "MixedAggregate";
1091  strategy = "Mixed";
1092  break;
1093  default:
1094  pname = "Aggregate ???";
1095  strategy = "???";
1096  break;
1097  }
1098 
1099  if (DO_AGGSPLIT_SKIPFINAL(agg->aggsplit))
1100  {
1101  partialmode = "Partial";
1102  pname = psprintf("%s %s", partialmode, pname);
1103  }
1104  else if (DO_AGGSPLIT_COMBINE(agg->aggsplit))
1105  {
1106  partialmode = "Finalize";
1107  pname = psprintf("%s %s", partialmode, pname);
1108  }
1109  else
1110  partialmode = "Simple";
1111  }
1112  break;
1113  case T_WindowAgg:
1114  pname = sname = "WindowAgg";
1115  break;
1116  case T_Unique:
1117  pname = sname = "Unique";
1118  break;
1119  case T_SetOp:
1120  sname = "SetOp";
1121  switch (((SetOp *) plan)->strategy)
1122  {
1123  case SETOP_SORTED:
1124  pname = "SetOp";
1125  strategy = "Sorted";
1126  break;
1127  case SETOP_HASHED:
1128  pname = "HashSetOp";
1129  strategy = "Hashed";
1130  break;
1131  default:
1132  pname = "SetOp ???";
1133  strategy = "???";
1134  break;
1135  }
1136  break;
1137  case T_LockRows:
1138  pname = sname = "LockRows";
1139  break;
1140  case T_Limit:
1141  pname = sname = "Limit";
1142  break;
1143  case T_Hash:
1144  pname = sname = "Hash";
1145  break;
1146  default:
1147  pname = sname = "???";
1148  break;
1149  }
1150 
1151  ExplainOpenGroup("Plan",
1152  relationship ? NULL : "Plan",
1153  true, es);
1154 
1155  if (es->format == EXPLAIN_FORMAT_TEXT)
1156  {
1157  if (plan_name)
1158  {
1159  appendStringInfoSpaces(es->str, es->indent * 2);
1160  appendStringInfo(es->str, "%s\n", plan_name);
1161  es->indent++;
1162  }
1163  if (es->indent)
1164  {
1165  appendStringInfoSpaces(es->str, es->indent * 2);
1166  appendStringInfoString(es->str, "-> ");
1167  es->indent += 2;
1168  }
1169  if (plan->parallel_aware)
1170  appendStringInfoString(es->str, "Parallel ");
1171  appendStringInfoString(es->str, pname);
1172  es->indent++;
1173  }
1174  else
1175  {
1176  ExplainPropertyText("Node Type", sname, es);
1177  if (strategy)
1178  ExplainPropertyText("Strategy", strategy, es);
1179  if (partialmode)
1180  ExplainPropertyText("Partial Mode", partialmode, es);
1181  if (operation)
1182  ExplainPropertyText("Operation", operation, es);
1183  if (relationship)
1184  ExplainPropertyText("Parent Relationship", relationship, es);
1185  if (plan_name)
1186  ExplainPropertyText("Subplan Name", plan_name, es);
1187  if (custom_name)
1188  ExplainPropertyText("Custom Plan Provider", custom_name, es);
1189  ExplainPropertyBool("Parallel Aware", plan->parallel_aware, es);
1190  }
1191 
1192  switch (nodeTag(plan))
1193  {
1194  case T_SeqScan:
1195  case T_SampleScan:
1196  case T_BitmapHeapScan:
1197  case T_TidScan:
1198  case T_SubqueryScan:
1199  case T_FunctionScan:
1200  case T_TableFuncScan:
1201  case T_ValuesScan:
1202  case T_CteScan:
1203  case T_WorkTableScan:
1204  ExplainScanTarget((Scan *) plan, es);
1205  break;
1206  case T_ForeignScan:
1207  case T_CustomScan:
1208  if (((Scan *) plan)->scanrelid > 0)
1209  ExplainScanTarget((Scan *) plan, es);
1210  break;
1211  case T_IndexScan:
1212  {
1213  IndexScan *indexscan = (IndexScan *) plan;
1214 
1215  ExplainIndexScanDetails(indexscan->indexid,
1216  indexscan->indexorderdir,
1217  es);
1218  ExplainScanTarget((Scan *) indexscan, es);
1219  }
1220  break;
1221  case T_IndexOnlyScan:
1222  {
1223  IndexOnlyScan *indexonlyscan = (IndexOnlyScan *) plan;
1224 
1225  ExplainIndexScanDetails(indexonlyscan->indexid,
1226  indexonlyscan->indexorderdir,
1227  es);
1228  ExplainScanTarget((Scan *) indexonlyscan, es);
1229  }
1230  break;
1231  case T_BitmapIndexScan:
1232  {
1233  BitmapIndexScan *bitmapindexscan = (BitmapIndexScan *) plan;
1234  const char *indexname =
1235  explain_get_index_name(bitmapindexscan->indexid);
1236 
1237  if (es->format == EXPLAIN_FORMAT_TEXT)
1238  appendStringInfo(es->str, " on %s", indexname);
1239  else
1240  ExplainPropertyText("Index Name", indexname, es);
1241  }
1242  break;
1243  case T_ModifyTable:
1244  ExplainModifyTarget((ModifyTable *) plan, es);
1245  break;
1246  case T_NestLoop:
1247  case T_MergeJoin:
1248  case T_HashJoin:
1249  {
1250  const char *jointype;
1251 
1252  switch (((Join *) plan)->jointype)
1253  {
1254  case JOIN_INNER:
1255  jointype = "Inner";
1256  break;
1257  case JOIN_LEFT:
1258  jointype = "Left";
1259  break;
1260  case JOIN_FULL:
1261  jointype = "Full";
1262  break;
1263  case JOIN_RIGHT:
1264  jointype = "Right";
1265  break;
1266  case JOIN_SEMI:
1267  jointype = "Semi";
1268  break;
1269  case JOIN_ANTI:
1270  jointype = "Anti";
1271  break;
1272  default:
1273  jointype = "???";
1274  break;
1275  }
1276  if (es->format == EXPLAIN_FORMAT_TEXT)
1277  {
1278  /*
1279  * For historical reasons, the join type is interpolated
1280  * into the node type name...
1281  */
1282  if (((Join *) plan)->jointype != JOIN_INNER)
1283  appendStringInfo(es->str, " %s Join", jointype);
1284  else if (!IsA(plan, NestLoop))
1285  appendStringInfoString(es->str, " Join");
1286  }
1287  else
1288  ExplainPropertyText("Join Type", jointype, es);
1289  }
1290  break;
1291  case T_SetOp:
1292  {
1293  const char *setopcmd;
1294 
1295  switch (((SetOp *) plan)->cmd)
1296  {
1297  case SETOPCMD_INTERSECT:
1298  setopcmd = "Intersect";
1299  break;
1301  setopcmd = "Intersect All";
1302  break;
1303  case SETOPCMD_EXCEPT:
1304  setopcmd = "Except";
1305  break;
1306  case SETOPCMD_EXCEPT_ALL:
1307  setopcmd = "Except All";
1308  break;
1309  default:
1310  setopcmd = "???";
1311  break;
1312  }
1313  if (es->format == EXPLAIN_FORMAT_TEXT)
1314  appendStringInfo(es->str, " %s", setopcmd);
1315  else
1316  ExplainPropertyText("Command", setopcmd, es);
1317  }
1318  break;
1319  default:
1320  break;
1321  }
1322 
1323  if (es->costs)
1324  {
1325  if (es->format == EXPLAIN_FORMAT_TEXT)
1326  {
1327  appendStringInfo(es->str, " (cost=%.2f..%.2f rows=%.0f width=%d)",
1328  plan->startup_cost, plan->total_cost,
1329  plan->plan_rows, plan->plan_width);
1330  }
1331  else
1332  {
1333  ExplainPropertyFloat("Startup Cost", NULL, plan->startup_cost,
1334  2, es);
1335  ExplainPropertyFloat("Total Cost", NULL, plan->total_cost,
1336  2, es);
1337  ExplainPropertyFloat("Plan Rows", NULL, plan->plan_rows,
1338  0, es);
1339  ExplainPropertyInteger("Plan Width", NULL, plan->plan_width,
1340  es);
1341  }
1342  }
1343 
1344  /*
1345  * We have to forcibly clean up the instrumentation state because we
1346  * haven't done ExecutorEnd yet. This is pretty grotty ...
1347  *
1348  * Note: contrib/auto_explain could cause instrumentation to be set up
1349  * even though we didn't ask for it here. Be careful not to print any
1350  * instrumentation results the user didn't ask for. But we do the
1351  * InstrEndLoop call anyway, if possible, to reduce the number of cases
1352  * auto_explain has to contend with.
1353  */
1354  if (planstate->instrument)
1355  InstrEndLoop(planstate->instrument);
1356 
1357  if (es->analyze &&
1358  planstate->instrument && planstate->instrument->nloops > 0)
1359  {
1360  double nloops = planstate->instrument->nloops;
1361  double startup_ms = 1000.0 * planstate->instrument->startup / nloops;
1362  double total_ms = 1000.0 * planstate->instrument->total / nloops;
1363  double rows = planstate->instrument->ntuples / nloops;
1364 
1365  if (es->format == EXPLAIN_FORMAT_TEXT)
1366  {
1367  if (es->timing)
1368  appendStringInfo(es->str,
1369  " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",
1370  startup_ms, total_ms, rows, nloops);
1371  else
1372  appendStringInfo(es->str,
1373  " (actual rows=%.0f loops=%.0f)",
1374  rows, nloops);
1375  }
1376  else
1377  {
1378  if (es->timing)
1379  {
1380  ExplainPropertyFloat("Actual Startup Time", "s", startup_ms,
1381  3, es);
1382  ExplainPropertyFloat("Actual Total Time", "s", total_ms,
1383  3, es);
1384  }
1385  ExplainPropertyFloat("Actual Rows", NULL, rows, 0, es);
1386  ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es);
1387  }
1388  }
1389  else if (es->analyze)
1390  {
1391  if (es->format == EXPLAIN_FORMAT_TEXT)
1392  appendStringInfoString(es->str, " (never executed)");
1393  else
1394  {
1395  if (es->timing)
1396  {
1397  ExplainPropertyFloat("Actual Startup Time", "ms", 0.0, 3, es);
1398  ExplainPropertyFloat("Actual Total Time", "ms", 0.0, 3, es);
1399  }
1400  ExplainPropertyFloat("Actual Rows", NULL, 0.0, 0, es);
1401  ExplainPropertyFloat("Actual Loops", NULL, 0.0, 0, es);
1402  }
1403  }
1404 
1405  /* in text format, first line ends here */
1406  if (es->format == EXPLAIN_FORMAT_TEXT)
1407  appendStringInfoChar(es->str, '\n');
1408 
1409  /* target list */
1410  if (es->verbose)
1411  show_plan_tlist(planstate, ancestors, es);
1412 
1413  /* unique join */
1414  switch (nodeTag(plan))
1415  {
1416  case T_NestLoop:
1417  case T_MergeJoin:
1418  case T_HashJoin:
1419  /* try not to be too chatty about this in text mode */
1420  if (es->format != EXPLAIN_FORMAT_TEXT ||
1421  (es->verbose && ((Join *) plan)->inner_unique))
1422  ExplainPropertyBool("Inner Unique",
1423  ((Join *) plan)->inner_unique,
1424  es);
1425  break;
1426  default:
1427  break;
1428  }
1429 
1430  /* quals, sort keys, etc */
1431  switch (nodeTag(plan))
1432  {
1433  case T_IndexScan:
1434  show_scan_qual(((IndexScan *) plan)->indexqualorig,
1435  "Index Cond", planstate, ancestors, es);
1436  if (((IndexScan *) plan)->indexqualorig)
1437  show_instrumentation_count("Rows Removed by Index Recheck", 2,
1438  planstate, es);
1439  show_scan_qual(((IndexScan *) plan)->indexorderbyorig,
1440  "Order By", planstate, ancestors, es);
1441  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1442  if (plan->qual)
1443  show_instrumentation_count("Rows Removed by Filter", 1,
1444  planstate, es);
1445  break;
1446  case T_IndexOnlyScan:
1447  show_scan_qual(((IndexOnlyScan *) plan)->indexqual,
1448  "Index Cond", planstate, ancestors, es);
1449  if (((IndexOnlyScan *) plan)->indexqual)
1450  show_instrumentation_count("Rows Removed by Index Recheck", 2,
1451  planstate, es);
1452  show_scan_qual(((IndexOnlyScan *) plan)->indexorderby,
1453  "Order By", planstate, ancestors, es);
1454  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1455  if (plan->qual)
1456  show_instrumentation_count("Rows Removed by Filter", 1,
1457  planstate, es);
1458  if (es->analyze)
1459  ExplainPropertyFloat("Heap Fetches", NULL,
1460  planstate->instrument->ntuples2, 0, es);
1461  break;
1462  case T_BitmapIndexScan:
1463  show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig,
1464  "Index Cond", planstate, ancestors, es);
1465  break;
1466  case T_BitmapHeapScan:
1467  show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig,
1468  "Recheck Cond", planstate, ancestors, es);
1469  if (((BitmapHeapScan *) plan)->bitmapqualorig)
1470  show_instrumentation_count("Rows Removed by Index Recheck", 2,
1471  planstate, es);
1472  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1473  if (plan->qual)
1474  show_instrumentation_count("Rows Removed by Filter", 1,
1475  planstate, es);
1476  if (es->analyze)
1477  show_tidbitmap_info((BitmapHeapScanState *) planstate, es);
1478  break;
1479  case T_SampleScan:
1480  show_tablesample(((SampleScan *) plan)->tablesample,
1481  planstate, ancestors, es);
1482  /* FALL THRU to print additional fields the same as SeqScan */
1483  case T_SeqScan:
1484  case T_ValuesScan:
1485  case T_CteScan:
1486  case T_NamedTuplestoreScan:
1487  case T_WorkTableScan:
1488  case T_SubqueryScan:
1489  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1490  if (plan->qual)
1491  show_instrumentation_count("Rows Removed by Filter", 1,
1492  planstate, es);
1493  break;
1494  case T_Gather:
1495  {
1496  Gather *gather = (Gather *) plan;
1497 
1498  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1499  if (plan->qual)
1500  show_instrumentation_count("Rows Removed by Filter", 1,
1501  planstate, es);
1502  ExplainPropertyInteger("Workers Planned", NULL,
1503  gather->num_workers, es);
1504 
1505  /* Show params evaluated at gather node */
1506  if (gather->initParam)
1507  show_eval_params(gather->initParam, es);
1508 
1509  if (es->analyze)
1510  {
1511  int nworkers;
1512 
1513  nworkers = ((GatherState *) planstate)->nworkers_launched;
1514  ExplainPropertyInteger("Workers Launched", NULL,
1515  nworkers, es);
1516  }
1517  if (gather->single_copy || es->format != EXPLAIN_FORMAT_TEXT)
1518  ExplainPropertyBool("Single Copy", gather->single_copy, es);
1519  }
1520  break;
1521  case T_GatherMerge:
1522  {
1523  GatherMerge *gm = (GatherMerge *) plan;
1524 
1525  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1526  if (plan->qual)
1527  show_instrumentation_count("Rows Removed by Filter", 1,
1528  planstate, es);
1529  ExplainPropertyInteger("Workers Planned", NULL,
1530  gm->num_workers, es);
1531 
1532  /* Show params evaluated at gather-merge node */
1533  if (gm->initParam)
1534  show_eval_params(gm->initParam, es);
1535 
1536  if (es->analyze)
1537  {
1538  int nworkers;
1539 
1540  nworkers = ((GatherMergeState *) planstate)->nworkers_launched;
1541  ExplainPropertyInteger("Workers Launched", NULL,
1542  nworkers, es);
1543  }
1544  }
1545  break;
1546  case T_FunctionScan:
1547  if (es->verbose)
1548  {
1549  List *fexprs = NIL;
1550  ListCell *lc;
1551 
1552  foreach(lc, ((FunctionScan *) plan)->functions)
1553  {
1554  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
1555 
1556  fexprs = lappend(fexprs, rtfunc->funcexpr);
1557  }
1558  /* We rely on show_expression to insert commas as needed */
1559  show_expression((Node *) fexprs,
1560  "Function Call", planstate, ancestors,
1561  es->verbose, es);
1562  }
1563  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1564  if (plan->qual)
1565  show_instrumentation_count("Rows Removed by Filter", 1,
1566  planstate, es);
1567  break;
1568  case T_TableFuncScan:
1569  if (es->verbose)
1570  {
1571  TableFunc *tablefunc = ((TableFuncScan *) plan)->tablefunc;
1572 
1573  show_expression((Node *) tablefunc,
1574  "Table Function Call", planstate, ancestors,
1575  es->verbose, es);
1576  }
1577  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1578  if (plan->qual)
1579  show_instrumentation_count("Rows Removed by Filter", 1,
1580  planstate, es);
1581  break;
1582  case T_TidScan:
1583  {
1584  /*
1585  * The tidquals list has OR semantics, so be sure to show it
1586  * as an OR condition.
1587  */
1588  List *tidquals = ((TidScan *) plan)->tidquals;
1589 
1590  if (list_length(tidquals) > 1)
1591  tidquals = list_make1(make_orclause(tidquals));
1592  show_scan_qual(tidquals, "TID Cond", planstate, ancestors, es);
1593  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1594  if (plan->qual)
1595  show_instrumentation_count("Rows Removed by Filter", 1,
1596  planstate, es);
1597  }
1598  break;
1599  case T_ForeignScan:
1600  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1601  if (plan->qual)
1602  show_instrumentation_count("Rows Removed by Filter", 1,
1603  planstate, es);
1604  show_foreignscan_info((ForeignScanState *) planstate, es);
1605  break;
1606  case T_CustomScan:
1607  {
1608  CustomScanState *css = (CustomScanState *) planstate;
1609 
1610  show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
1611  if (plan->qual)
1612  show_instrumentation_count("Rows Removed by Filter", 1,
1613  planstate, es);
1614  if (css->methods->ExplainCustomScan)
1615  css->methods->ExplainCustomScan(css, ancestors, es);
1616  }
1617  break;
1618  case T_NestLoop:
1619  show_upper_qual(((NestLoop *) plan)->join.joinqual,
1620  "Join Filter", planstate, ancestors, es);
1621  if (((NestLoop *) plan)->join.joinqual)
1622  show_instrumentation_count("Rows Removed by Join Filter", 1,
1623  planstate, es);
1624  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
1625  if (plan->qual)
1626  show_instrumentation_count("Rows Removed by Filter", 2,
1627  planstate, es);
1628  break;
1629  case T_MergeJoin:
1630  show_upper_qual(((MergeJoin *) plan)->mergeclauses,
1631  "Merge Cond", planstate, ancestors, es);
1632  show_upper_qual(((MergeJoin *) plan)->join.joinqual,
1633  "Join Filter", planstate, ancestors, es);
1634  if (((MergeJoin *) plan)->join.joinqual)
1635  show_instrumentation_count("Rows Removed by Join Filter", 1,
1636  planstate, es);
1637  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
1638  if (plan->qual)
1639  show_instrumentation_count("Rows Removed by Filter", 2,
1640  planstate, es);
1641  break;
1642  case T_HashJoin:
1643  show_upper_qual(((HashJoin *) plan)->hashclauses,
1644  "Hash Cond", planstate, ancestors, es);
1645  show_upper_qual(((HashJoin *) plan)->join.joinqual,
1646  "Join Filter", planstate, ancestors, es);
1647  if (((HashJoin *) plan)->join.joinqual)
1648  show_instrumentation_count("Rows Removed by Join Filter", 1,
1649  planstate, es);
1650  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
1651  if (plan->qual)
1652  show_instrumentation_count("Rows Removed by Filter", 2,
1653  planstate, es);
1654  break;
1655  case T_Agg:
1656  show_agg_keys(castNode(AggState, planstate), ancestors, es);
1657  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
1658  if (plan->qual)
1659  show_instrumentation_count("Rows Removed by Filter", 1,
1660  planstate, es);
1661  break;
1662  case T_Group:
1663  show_group_keys(castNode(GroupState, planstate), ancestors, es);
1664  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
1665  if (plan->qual)
1666  show_instrumentation_count("Rows Removed by Filter", 1,
1667  planstate, es);
1668  break;
1669  case T_Sort:
1670  show_sort_keys(castNode(SortState, planstate), ancestors, es);
1671  show_sort_info(castNode(SortState, planstate), es);
1672  break;
1673  case T_MergeAppend:
1675  ancestors, es);
1676  break;
1677  case T_Result:
1678  show_upper_qual((List *) ((Result *) plan)->resconstantqual,
1679  "One-Time Filter", planstate, ancestors, es);
1680  show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
1681  if (plan->qual)
1682  show_instrumentation_count("Rows Removed by Filter", 1,
1683  planstate, es);
1684  break;
1685  case T_ModifyTable:
1686  show_modifytable_info(castNode(ModifyTableState, planstate), ancestors,
1687  es);
1688  break;
1689  case T_Hash:
1690  show_hash_info(castNode(HashState, planstate), es);
1691  break;
1692  default:
1693  break;
1694  }
1695 
1696  /* Show buffer usage */
1697  if (es->buffers && planstate->instrument)
1698  show_buffer_usage(es, &planstate->instrument->bufusage);
1699 
1700  /* Show worker detail */
1701  if (es->analyze && es->verbose && planstate->worker_instrument)
1702  {
1703  WorkerInstrumentation *w = planstate->worker_instrument;
1704  bool opened_group = false;
1705  int n;
1706 
1707  for (n = 0; n < w->num_workers; ++n)
1708  {
1709  Instrumentation *instrument = &w->instrument[n];
1710  double nloops = instrument->nloops;
1711  double startup_ms;
1712  double total_ms;
1713  double rows;
1714 
1715  if (nloops <= 0)
1716  continue;
1717  startup_ms = 1000.0 * instrument->startup / nloops;
1718  total_ms = 1000.0 * instrument->total / nloops;
1719  rows = instrument->ntuples / nloops;
1720 
1721  if (es->format == EXPLAIN_FORMAT_TEXT)
1722  {
1723  appendStringInfoSpaces(es->str, es->indent * 2);
1724  appendStringInfo(es->str, "Worker %d: ", n);
1725  if (es->timing)
1726  appendStringInfo(es->str,
1727  "actual time=%.3f..%.3f rows=%.0f loops=%.0f\n",
1728  startup_ms, total_ms, rows, nloops);
1729  else
1730  appendStringInfo(es->str,
1731  "actual rows=%.0f loops=%.0f\n",
1732  rows, nloops);
1733  es->indent++;
1734  if (es->buffers)
1735  show_buffer_usage(es, &instrument->bufusage);
1736  es->indent--;
1737  }
1738  else
1739  {
1740  if (!opened_group)
1741  {
1742  ExplainOpenGroup("Workers", "Workers", false, es);
1743  opened_group = true;
1744  }
1745  ExplainOpenGroup("Worker", NULL, true, es);
1746  ExplainPropertyInteger("Worker Number", NULL, n, es);
1747 
1748  if (es->timing)
1749  {
1750  ExplainPropertyFloat("Actual Startup Time", "ms",
1751  startup_ms, 3, es);
1752  ExplainPropertyFloat("Actual Total Time", "ms",
1753  total_ms, 3, es);
1754  }
1755  ExplainPropertyFloat("Actual Rows", NULL, rows, 0, es);
1756  ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es);
1757 
1758  if (es->buffers)
1759  show_buffer_usage(es, &instrument->bufusage);
1760 
1761  ExplainCloseGroup("Worker", NULL, true, es);
1762  }
1763  }
1764 
1765  if (opened_group)
1766  ExplainCloseGroup("Workers", "Workers", false, es);
1767  }
1768 
1769  /* Get ready to display the child plans */
1770  haschildren = planstate->initPlan ||
1771  outerPlanState(planstate) ||
1772  innerPlanState(planstate) ||
1773  IsA(plan, ModifyTable) ||
1774  IsA(plan, Append) ||
1775  IsA(plan, MergeAppend) ||
1776  IsA(plan, BitmapAnd) ||
1777  IsA(plan, BitmapOr) ||
1778  IsA(plan, SubqueryScan) ||
1779  (IsA(planstate, CustomScanState) &&
1780  ((CustomScanState *) planstate)->custom_ps != NIL) ||
1781  planstate->subPlan;
1782  if (haschildren)
1783  {
1784  ExplainOpenGroup("Plans", "Plans", false, es);
1785  /* Pass current PlanState as head of ancestors list for children */
1786  ancestors = lcons(planstate, ancestors);
1787  }
1788 
1789  /* initPlan-s */
1790  if (planstate->initPlan)
1791  ExplainSubPlans(planstate->initPlan, ancestors, "InitPlan", es);
1792 
1793  /* lefttree */
1794  if (outerPlanState(planstate))
1795  ExplainNode(outerPlanState(planstate), ancestors,
1796  "Outer", NULL, es);
1797 
1798  /* righttree */
1799  if (innerPlanState(planstate))
1800  ExplainNode(innerPlanState(planstate), ancestors,
1801  "Inner", NULL, es);
1802 
1803  /* special child plans */
1804  switch (nodeTag(plan))
1805  {
1806  case T_ModifyTable:
1807  ExplainMemberNodes(((ModifyTableState *) planstate)->mt_plans,
1808  ((ModifyTableState *) planstate)->mt_nplans,
1809  list_length(((ModifyTable *) plan)->plans),
1810  ancestors, es);
1811  break;
1812  case T_Append:
1813  ExplainMemberNodes(((AppendState *) planstate)->appendplans,
1814  ((AppendState *) planstate)->as_nplans,
1815  list_length(((Append *) plan)->appendplans),
1816  ancestors, es);
1817  break;
1818  case T_MergeAppend:
1819  ExplainMemberNodes(((MergeAppendState *) planstate)->mergeplans,
1820  ((MergeAppendState *) planstate)->ms_nplans,
1821  list_length(((MergeAppend *) plan)->mergeplans),
1822  ancestors, es);
1823  break;
1824  case T_BitmapAnd:
1825  ExplainMemberNodes(((BitmapAndState *) planstate)->bitmapplans,
1826  ((BitmapAndState *) planstate)->nplans,
1827  list_length(((BitmapAnd *) plan)->bitmapplans),
1828  ancestors, es);
1829  break;
1830  case T_BitmapOr:
1831  ExplainMemberNodes(((BitmapOrState *) planstate)->bitmapplans,
1832  ((BitmapOrState *) planstate)->nplans,
1833  list_length(((BitmapOr *) plan)->bitmapplans),
1834  ancestors, es);
1835  break;
1836  case T_SubqueryScan:
1837  ExplainNode(((SubqueryScanState *) planstate)->subplan, ancestors,
1838  "Subquery", NULL, es);
1839  break;
1840  case T_CustomScan:
1841  ExplainCustomChildren((CustomScanState *) planstate,
1842  ancestors, es);
1843  break;
1844  default:
1845  break;
1846  }
1847 
1848  /* subPlan-s */
1849  if (planstate->subPlan)
1850  ExplainSubPlans(planstate->subPlan, ancestors, "SubPlan", es);
1851 
1852  /* end of child plans */
1853  if (haschildren)
1854  {
1855  ancestors = list_delete_first(ancestors);
1856  ExplainCloseGroup("Plans", "Plans", false, es);
1857  }
1858 
1859  /* in text format, undo whatever indentation we added */
1860  if (es->format == EXPLAIN_FORMAT_TEXT)
1861  es->indent = save_indent;
1862 
1863  ExplainCloseGroup("Plan",
1864  relationship ? NULL : "Plan",
1865  true, es);
1866 }
static void ExplainMemberNodes(PlanState **planstates, int nsubnodes, int nplans, List *ancestors, ExplainState *es)
Definition: explain.c:3150
#define NIL
Definition: pg_list.h:69
Definition: nodes.h:78
void ExplainPropertyBool(const char *qlabel, bool value, ExplainState *es)
Definition: explain.c:3439
ScanDirection indexorderdir
Definition: plannodes.h:409
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
Bitmapset * initParam
Definition: plannodes.h:883
WorkerInstrumentation * worker_instrument
Definition: execnodes.h:922
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:3411
Definition: nodes.h:80
Instrumentation * instrument
Definition: execnodes.h:921
static void show_modifytable_info(ModifyTableState *mtstate, List *ancestors, ExplainState *es)
Definition: explain.c:2986
#define castNode(_type_, nodeptr)
Definition: nodes.h:586
List * initPlan
Definition: execnodes.h:933
void ExplainPropertyFloat(const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
Definition: explain.c:3425
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
double startup
Definition: instrument.h:57
List * subPlan
Definition: execnodes.h:935
Definition: nodes.h:517
Definition: nodes.h:49
Definition: nodes.h:76
bool costs
Definition: explain.h:34
static void show_scan_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:1974
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:776
bool analyze
Definition: explain.h:33
static void show_sort_info(SortState *sortstate, ExplainState *es)
Definition: explain.c:2364
Oid indexid
Definition: plannodes.h:403
static void show_upper_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:1988
static void show_instrumentation_count(const char *qlabel, int which, PlanState *planstate, ExplainState *es)
Definition: explain.c:2579
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:114
const struct CustomExecMethods * methods
Definition: execnodes.h:1670
#define list_make1(x1)
Definition: pg_list.h:139
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3402
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:914
AggStrategy aggstrategy
Definition: plannodes.h:797
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
Definition: nodes.h:46
bool single_copy
Definition: plannodes.h:862
Definition: nodes.h:77
#define outerPlanState(node)
Definition: execnodes.h:965
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static void show_tablesample(TableSampleClause *tsc, PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:2298
ScanDirection indexorderdir
Definition: plannodes.h:436
double ntuples
Definition: instrument.h:59
int indent
Definition: explain.h:40
static void show_tidbitmap_info(BitmapHeapScanState *planstate, ExplainState *es)
Definition: explain.c:2549
static void ExplainModifyTarget(ModifyTable *plan, ExplainState *es)
Definition: explain.c:2854
static void ExplainIndexScanDetails(Oid indexid, ScanDirection indexorderdir, ExplainState *es)
Definition: explain.c:2802
static void show_group_keys(GroupState *gstate, List *ancestors, ExplainState *es)
Definition: explain.c:2165
static void show_buffer_usage(ExplainState *es, const BufferUsage *usage)
Definition: explain.c:2678
static void show_plan_tlist(PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:1872
List * lappend(List *list, void *datum)
Definition: list.c:128
bool timing
Definition: explain.h:36
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
Instrumentation instrument[FLEXIBLE_ARRAY_MEMBER]
Definition: instrument.h:70
bool verbose
Definition: explain.h:32
BufferUsage bufusage
Definition: instrument.h:64
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainCustomChildren(CustomScanState *css, List *ancestors, ExplainState *es)
Definition: explain.c:3211
Definition: nodes.h:83
Plan * plan
Definition: execnodes.h:911
int num_workers
Definition: plannodes.h:860
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:2017
List * lcons(void *datum, List *list)
Definition: list.c:259
#define lfirst(lc)
Definition: pg_list.h:106
AggSplit aggsplit
Definition: plannodes.h:798
static void ExplainSubPlans(List *plans, List *ancestors, const char *relationship, ExplainState *es)
Definition: explain.c:3177
static void show_hash_info(HashState *hashstate, ExplainState *es)
Definition: explain.c:2446
static void show_eval_params(Bitmapset *bms_params, ExplainState *es)
Definition: explain.c:2629
static void show_sort_keys(SortState *sortstate, List *ancestors, ExplainState *es)
Definition: explain.c:2002
static int list_length(const List *l)
Definition: pg_list.h:89
ExplainFormat format
Definition: explain.h:38
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:777
static const struct fns functions
Definition: regcomp.c:299
static const char * explain_get_index_name(Oid indexId)
Definition: explain.c:2655
double ntuples2
Definition: instrument.h:60
#define nodeTag(nodeptr)
Definition: nodes.h:522
static void show_expression(Node *node, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
Definition: explain.c:1930
Bitmapset * initParam
Definition: plannodes.h:864
Definition: nodes.h:84
int num_workers
Definition: plannodes.h:875
Definition: nodes.h:81
bool buffers
Definition: explain.h:35
static void show_foreignscan_info(ForeignScanState *fsstate, ExplainState *es)
Definition: explain.c:2608
static void ExplainScanTarget(Scan *plan, ExplainState *es)
Definition: explain.c:2841
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3517
Definition: plannodes.h:794
#define innerPlanState(node)
Definition: execnodes.h:964
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3454
Definition: pg_list.h:45
StringInfo str
Definition: explain.h:30
Expr * make_orclause(List *orclauses)
Definition: clauses.c:294
static void show_agg_keys(AggState *astate, List *ancestors, ExplainState *es)
Definition: explain.c:2033
List * list_delete_first(List *list)
Definition: list.c:666
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 463 of file explain.c.

References ExplainState::analyze, Assert, ExplainState::buffers, CMD_UTILITY, CommandCounterIncrement(), PlannedStmt::commandType, ExplainState::costs, JitContext::created_functions, CreateIntoRelDestReceiver(), CreateQueryDesc(), generate_unaccent_rules::dest, elapsed_time(), EState::es_jit, QueryDesc::estate, EXEC_FLAG_EXPLAIN_ONLY, ExecutorEnd(), ExecutorFinish(), ExecutorRun(), ExecutorStart(), ExplainCloseGroup(), ExplainOpenGroup(), ExplainPrintJIT(), 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().

466 {
468  QueryDesc *queryDesc;
469  instr_time starttime;
470  double totaltime = 0;
471  int eflags;
472  int instrument_option = 0;
473 
474  Assert(plannedstmt->commandType != CMD_UTILITY);
475 
476  if (es->analyze && es->timing)
477  instrument_option |= INSTRUMENT_TIMER;
478  else if (es->analyze)
479  instrument_option |= INSTRUMENT_ROWS;
480 
481  if (es->buffers)
482  instrument_option |= INSTRUMENT_BUFFERS;
483 
484  /*
485  * We always collect timing for the entire statement, even when node-level
486  * timing is off, so we don't look at es->timing here. (We could skip
487  * this if !es->summary, but it's hardly worth the complication.)
488  */
489  INSTR_TIME_SET_CURRENT(starttime);
490 
491  /*
492  * Use a snapshot with an updated command ID to ensure this query sees
493  * results of any previously executed queries.
494  */
497 
498  /*
499  * Normally we discard the query's output, but if explaining CREATE TABLE
500  * AS, we'd better use the appropriate tuple receiver.
501  */
502  if (into)
503  dest = CreateIntoRelDestReceiver(into);
504  else
505  dest = None_Receiver;
506 
507  /* Create a QueryDesc for the query */
508  queryDesc = CreateQueryDesc(plannedstmt, queryString,
510  dest, params, queryEnv, instrument_option);
511 
512  /* Select execution options */
513  if (es->analyze)
514  eflags = 0; /* default run-to-completion flags */
515  else
516  eflags = EXEC_FLAG_EXPLAIN_ONLY;
517  if (into)
518  eflags |= GetIntoRelEFlags(into);
519 
520  /* call ExecutorStart to prepare the plan for execution */
521  ExecutorStart(queryDesc, eflags);
522 
523  /* Execute the plan for statistics if asked for */
524  if (es->analyze)
525  {
526  ScanDirection dir;
527 
528  /* EXPLAIN ANALYZE CREATE TABLE AS WITH NO DATA is weird */
529  if (into && into->skipData)
531  else
532  dir = ForwardScanDirection;
533 
534  /* run the plan */
535  ExecutorRun(queryDesc, dir, 0L, true);
536 
537  /* run cleanup too */
538  ExecutorFinish(queryDesc);
539 
540  /* We can't run ExecutorEnd 'till we're done printing the stats... */
541  totaltime += elapsed_time(&starttime);
542  }
543 
544  ExplainOpenGroup("Query", NULL, true, es);
545 
546  /* Create textual dump of plan tree */
547  ExplainPrintPlan(es, queryDesc);
548 
549  if (es->summary && planduration)
550  {
551  double plantime = INSTR_TIME_GET_DOUBLE(*planduration);
552 
553  ExplainPropertyFloat("Planning Time", "ms", 1000.0 * plantime, 3, es);
554  }
555 
556  /* Print info about runtime of triggers */
557  if (es->analyze)
558  ExplainPrintTriggers(es, queryDesc);
559 
560  /*
561  * Print info about JITing. Tied to es->costs because we don't want to
562  * display this in regression tests, as it'd cause output differences
563  * depending on build options. Might want to separate that out from COSTS
564  * at a later stage.
565  */
566  if (queryDesc->estate->es_jit && es->costs &&
567  queryDesc->estate->es_jit->created_functions > 0)
568  ExplainPrintJIT(es, queryDesc);
569 
570  /*
571  * Close down the query and free resources. Include time for this in the
572  * total execution time (although it should be pretty minimal).
573  */
574  INSTR_TIME_SET_CURRENT(starttime);
575 
576  ExecutorEnd(queryDesc);
577 
578  FreeQueryDesc(queryDesc);
579 
581 
582  /* We need a CCI just in case query expanded to multiple plans */
583  if (es->analyze)
585 
586  totaltime += elapsed_time(&starttime);
587 
588  /*
589  * We only report execution time if we actually ran the query (that is,
590  * the user specified ANALYZE), and if summary reporting is enabled (the
591  * user can set SUMMARY OFF to not have the timing information included in
592  * the output). By default, ANALYZE sets SUMMARY to true.
593  */
594  if (es->summary && es->analyze)
595  ExplainPropertyFloat("Execution Time", "ms", 1000.0 * totaltime, 3,
596  es);
597 
598  ExplainCloseGroup("Query", NULL, true, es);
599 }
void ExplainPrintJIT(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:696
bool summary
Definition: explain.h:37
void UpdateActiveSnapshotCommandId(void)
Definition: snapmgr.c:781
EState * estate
Definition: execdesc.h:48
struct JitContext * es_jit
Definition: execnodes.h:573
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:3425
struct timeval instr_time
Definition: instr_time.h:147
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:141
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:839
void PopActiveSnapshot(void)
Definition: snapmgr.c:812
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:196
bool skipData
Definition: primnodes.h:116
bool costs
Definition: explain.h:34
DestReceiver * None_Receiver
Definition: dest.c:91
bool analyze
Definition: explain.h:33
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:461
int GetIntoRelEFlags(IntoClause *intoClause)
Definition: createas.c:392
void ExplainPrintTriggers(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:650
void ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:613
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:299
void PushCopiedSnapshot(Snapshot snapshot)
Definition: snapmgr.c:769
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:423
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:401
bool timing
Definition: explain.h:36
#define InvalidSnapshot
Definition: snapshot.h:25
void CommandCounterIncrement(void)
Definition: xact.c:914
CmdType commandType
Definition: plannodes.h:45
#define Assert(condition)
Definition: c.h:699
static double elapsed_time(instr_time *starttime)
Definition: explain.c:830
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153
size_t created_functions
Definition: jit.h:35
bool buffers
Definition: explain.h:35
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3517
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3454
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:58

◆ ExplainOneQuery()

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

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

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

◆ ExplainOneUtility()

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

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

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

◆ ExplainOpenGroup()

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

Definition at line 3454 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(), ExplainPrintTriggers(), report_triggers(), show_grouping_set_keys(), show_grouping_sets(), show_modifytable_info(), and show_sort_info().

3456 {
3457  switch (es->format)
3458  {
3459  case EXPLAIN_FORMAT_TEXT:
3460  /* nothing to do */
3461  break;
3462 
3463  case EXPLAIN_FORMAT_XML:
3464  ExplainXMLTag(objtype, X_OPENING, es);
3465  es->indent++;
3466  break;
3467 
3468  case EXPLAIN_FORMAT_JSON:
3470  appendStringInfoSpaces(es->str, 2 * es->indent);
3471  if (labelname)
3472  {
3473  escape_json(es->str, labelname);
3474  appendStringInfoString(es->str, ": ");
3475  }
3476  appendStringInfoChar(es->str, labeled ? '{' : '[');
3477 
3478  /*
3479  * In JSON format, the grouping_stack is an integer list. 0 means
3480  * we've emitted nothing at this grouping level, 1 means we've
3481  * emitted something (and so the next item needs a comma). See
3482  * ExplainJSONLineEnding().
3483  */
3484  es->grouping_stack = lcons_int(0, es->grouping_stack);
3485  es->indent++;
3486  break;
3487 
3488  case EXPLAIN_FORMAT_YAML:
3489 
3490  /*
3491  * In YAML format, the grouping stack is an integer list. 0 means
3492  * we've emitted nothing at this grouping level AND this grouping
3493  * level is unlabelled and must be marked with "- ". See
3494  * ExplainYAMLLineStarting().
3495  */
3497  if (labelname)
3498  {
3499  appendStringInfo(es->str, "%s: ", labelname);
3500  es->grouping_stack = lcons_int(1, es->grouping_stack);
3501  }
3502  else
3503  {
3504  appendStringInfoString(es->str, "- ");
3505  es->grouping_stack = lcons_int(0, es->grouping_stack);
3506  }
3507  es->indent++;
3508  break;
3509  }
3510 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2461
List * lcons_int(int datum, List *list)
Definition: list.c:277
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3688
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3735
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3715
#define X_OPENING
Definition: explain.c:52
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30

◆ ExplainPreScanNode()

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

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

850 {
851  Plan *plan = planstate->plan;
852 
853  switch (nodeTag(plan))
854  {
855  case T_SeqScan:
856  case T_SampleScan:
857  case T_IndexScan:
858  case T_IndexOnlyScan:
859  case T_BitmapHeapScan:
860  case T_TidScan:
861  case T_SubqueryScan:
862  case T_FunctionScan:
863  case T_TableFuncScan:
864  case T_ValuesScan:
865  case T_CteScan:
867  case T_WorkTableScan:
868  *rels_used = bms_add_member(*rels_used,
869  ((Scan *) plan)->scanrelid);
870  break;
871  case T_ForeignScan:
872  *rels_used = bms_add_members(*rels_used,
873  ((ForeignScan *) plan)->fs_relids);
874  break;
875  case T_CustomScan:
876  *rels_used = bms_add_members(*rels_used,
877  ((CustomScan *) plan)->custom_relids);
878  break;
879  case T_ModifyTable:
880  *rels_used = bms_add_member(*rels_used,
881  ((ModifyTable *) plan)->nominalRelation);
882  if (((ModifyTable *) plan)->exclRelRTI)
883  *rels_used = bms_add_member(*rels_used,
884  ((ModifyTable *) plan)->exclRelRTI);
885  break;
886  default:
887  break;
888  }
889 
890  return planstate_tree_walker(planstate, ExplainPreScanNode, rels_used);
891 }
Plan * plan
Definition: execnodes.h:911
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:764
#define nodeTag(nodeptr)
Definition: nodes.h:522
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
Definition: explain.c:849
bool planstate_tree_walker(PlanState *planstate, bool(*walker)(), void *context)
Definition: nodeFuncs.c:3722
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:821

◆ ExplainPrintJIT()

void ExplainPrintJIT ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 696 of file explain.c.

References ExplainState::analyze, appendStringInfo(), JitContext::created_functions, JitContext::emission_counter, EState::es_jit, QueryDesc::estate, EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), ExplainOpenGroup(), ExplainPropertyBool(), ExplainPropertyFloat(), ExplainPropertyInteger(), JitContext::flags, ExplainState::format, JitContext::generation_counter, ExplainState::indent, JitContext::inlining_counter, INSTR_TIME_GET_DOUBLE, JitContext::optimization_counter, PGJIT_INLINE, PGJIT_OPT3, ExplainState::str, and ExplainState::timing.

Referenced by ExplainOnePlan().

697 {
698  JitContext *jc = queryDesc->estate->es_jit;
699 
700  ExplainOpenGroup("JIT", "JIT", true, es);
701 
702  if (es->format == EXPLAIN_FORMAT_TEXT)
703  {
704  es->indent += 1;
705  appendStringInfo(es->str, "JIT:\n");
706  }
707 
708  ExplainPropertyInteger("Functions", NULL, jc->created_functions, es);
709  if (es->analyze && es->timing)
710  ExplainPropertyFloat("Generation Time", "ms",
712  3, es);
713 
714  ExplainPropertyBool("Inlining", jc->flags & PGJIT_INLINE, es);
715 
716  if (es->analyze && es->timing)
717  ExplainPropertyFloat("Inlining Time", "ms",
719  3, es);
720 
721  ExplainPropertyBool("Optimization", jc->flags & PGJIT_OPT3, es);
722  if (es->analyze && es->timing)
723  ExplainPropertyFloat("Optimization Time", "ms",
725  3, es);
726 
727  if (es->analyze && es->timing)
728  ExplainPropertyFloat("Emission Time", "ms",
730  3, es);
731 
732  ExplainCloseGroup("JIT", "JIT", true, es);
733  if (es->format == EXPLAIN_FORMAT_TEXT)
734  {
735  es->indent -= 1;
736  }
737 }
instr_time optimization_counter
Definition: jit.h:44
void ExplainPropertyBool(const char *qlabel, bool value, ExplainState *es)
Definition: explain.c:3439
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:3411
EState * estate
Definition: execdesc.h:48
struct JitContext * es_jit
Definition: execnodes.h:573
void ExplainPropertyFloat(const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
Definition: explain.c:3425
Definition: jit.h:27
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:196
bool analyze
Definition: explain.h:33
#define PGJIT_OPT3
Definition: jit.h:21
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
instr_time inlining_counter
Definition: jit.h:41
int indent
Definition: explain.h:40
instr_time emission_counter
Definition: jit.h:47
bool timing
Definition: explain.h:36
#define PGJIT_INLINE
Definition: jit.h:22
instr_time generation_counter
Definition: jit.h:38
ExplainFormat format
Definition: explain.h:38
size_t created_functions
Definition: jit.h:35
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3517
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3454
StringInfo str
Definition: explain.h:30
int flags
Definition: jit.h:30

◆ ExplainPrintPlan()

void ExplainPrintPlan ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 613 of file explain.c.

References Assert, deparse_context_for_plan_rtable(), ExplainState::deparse_cxt, ExplainNode(), ExplainPreScanNode(), 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().

614 {
615  Bitmapset *rels_used = NULL;
616  PlanState *ps;
617 
618  /* Set up ExplainState fields associated with this plan tree */
619  Assert(queryDesc->plannedstmt != NULL);
620  es->pstmt = queryDesc->plannedstmt;
621  es->rtable = queryDesc->plannedstmt->rtable;
622  ExplainPreScanNode(queryDesc->planstate, &rels_used);
625  es->rtable_names);
626  es->printed_subplans = NULL;
627 
628  /*
629  * Sometimes we mark a Gather node as "invisible", which means that it's
630  * not displayed in EXPLAIN output. The purpose of this is to allow
631  * running regression tests with force_parallel_mode=regress to get the
632  * same results as running the same tests with force_parallel_mode=off.
633  */
634  ps = queryDesc->planstate;
635  if (IsA(ps, GatherState) &&((Gather *) ps->plan)->invisible)
636  ps = outerPlanState(ps);
637  ExplainNode(ps, NIL, NULL, NULL, es);
638 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
Bitmapset * printed_subplans
Definition: explain.h:47
List * deparse_cxt
Definition: explain.h:46
PlannedStmt * pstmt
Definition: explain.h:43
List * rtable_names
Definition: explain.h:45
List * select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
Definition: ruleutils.c:3247
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:914
PlanState * planstate
Definition: execdesc.h:49
#define outerPlanState(node)
Definition: execnodes.h:965
Plan * plan
Definition: execnodes.h:911
#define Assert(condition)
Definition: c.h:699
List * rtable
Definition: plannodes.h:65
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
Definition: explain.c:849
PlannedStmt * plannedstmt
Definition: execdesc.h:37
List * deparse_context_for_plan_rtable(List *rtable, List *rtable_names)
Definition: ruleutils.c:3172
List * rtable
Definition: explain.h:44

◆ ExplainPrintTriggers()

void ExplainPrintTriggers ( ExplainState es,
QueryDesc queryDesc 
)

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

651 {
652  ResultRelInfo *rInfo;
653  bool show_relname;
654  int numrels = queryDesc->estate->es_num_result_relations;
655  int numrootrels = queryDesc->estate->es_num_root_result_relations;
656  List *routerels;
657  List *targrels;
658  int nr;
659  ListCell *l;
660 
661  routerels = queryDesc->estate->es_tuple_routing_result_relations;
662  targrels = queryDesc->estate->es_trig_target_relations;
663 
664  ExplainOpenGroup("Triggers", "Triggers", false, es);
665 
666  show_relname = (numrels > 1 || numrootrels > 0 ||
667  routerels != NIL || targrels != NIL);
668  rInfo = queryDesc->estate->es_result_relations;
669  for (nr = 0; nr < numrels; rInfo++, nr++)
670  report_triggers(rInfo, show_relname, es);
671 
672  rInfo = queryDesc->estate->es_root_result_relations;
673  for (nr = 0; nr < numrootrels; rInfo++, nr++)
674  report_triggers(rInfo, show_relname, es);
675 
676  foreach(l, routerels)
677  {
678  rInfo = (ResultRelInfo *) lfirst(l);
679  report_triggers(rInfo, show_relname, es);
680  }
681 
682  foreach(l, targrels)
683  {
684  rInfo = (ResultRelInfo *) lfirst(l);
685  report_triggers(rInfo, show_relname, es);
686  }
687 
688  ExplainCloseGroup("Triggers", "Triggers", false, es);
689 }
#define NIL
Definition: pg_list.h:69
EState * estate
Definition: execdesc.h:48
ResultRelInfo * es_result_relations
Definition: execnodes.h:490
static void report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
Definition: explain.c:759
int es_num_root_result_relations
Definition: execnodes.h:502
List * es_trig_target_relations
Definition: execnodes.h:511
int es_num_result_relations
Definition: execnodes.h:491
List * es_tuple_routing_result_relations
Definition: execnodes.h:508
#define lfirst(lc)
Definition: pg_list.h:106
ResultRelInfo * es_root_result_relations
Definition: execnodes.h:501
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3517
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3454
Definition: pg_list.h:45

◆ ExplainProperty()

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

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

3351 {
3352  switch (es->format)
3353  {
3354  case EXPLAIN_FORMAT_TEXT:
3355  appendStringInfoSpaces(es->str, es->indent * 2);
3356  if (unit)
3357  appendStringInfo(es->str, "%s: %s %s\n", qlabel, value, unit);
3358  else
3359  appendStringInfo(es->str, "%s: %s\n", qlabel, value);
3360  break;
3361 
3362  case EXPLAIN_FORMAT_XML:
3363  {
3364  char *str;
3365 
3366  appendStringInfoSpaces(es->str, es->indent * 2);
3367  ExplainXMLTag(qlabel, X_OPENING | X_NOWHITESPACE, es);
3368  str = escape_xml(value);
3369  appendStringInfoString(es->str, str);
3370  pfree(str);
3371  ExplainXMLTag(qlabel, X_CLOSING | X_NOWHITESPACE, es);
3372  appendStringInfoChar(es->str, '\n');
3373  }
3374  break;
3375 
3376  case EXPLAIN_FORMAT_JSON:
3378  appendStringInfoSpaces(es->str, es->indent * 2);
3379  escape_json(es->str, qlabel);
3380  appendStringInfoString(es->str, ": ");
3381  if (numeric)
3383  else
3384  escape_json(es->str, value);
3385  break;
3386 
3387  case EXPLAIN_FORMAT_YAML:
3389  appendStringInfo(es->str, "%s: ", qlabel);
3390  if (numeric)
3392  else
3393  escape_yaml(es->str, value);
3394  break;
3395  }
3396 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2461
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3688
#define X_CLOSING
Definition: explain.c:53
void pfree(void *pointer)
Definition: mcxt.c:1031
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3735
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3760
static struct @131 value
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3715
#define X_OPENING
Definition: explain.c:52
#define X_NOWHITESPACE
Definition: explain.c:55
ExplainFormat format
Definition: explain.h:38
char * escape_xml(const char *str)
Definition: xml.c:2232
StringInfo str
Definition: explain.h:30

◆ ExplainPropertyBool()

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

Definition at line 3439 of file explain.c.

References ExplainProperty().

Referenced by ExplainNode(), and ExplainPrintJIT().

3440 {
3441  ExplainProperty(qlabel, NULL, value ? "true" : "false", true, es);
3442 }
static struct @131 value
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3349

◆ ExplainPropertyFloat()

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

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

3427 {
3428  char *buf;
3429 
3430  buf = psprintf("%.*f", ndigits, value);
3431  ExplainProperty(qlabel, unit, buf, true, es);
3432  pfree(buf);
3433 }
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
void pfree(void *pointer)
Definition: mcxt.c:1031
static char * buf
Definition: pg_test_fsync.c:67
static struct @131 value
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3349

◆ ExplainPropertyInteger()

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

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

3413 {
3414  char buf[32];
3415 
3416  snprintf(buf, sizeof(buf), INT64_FORMAT, value);
3417  ExplainProperty(qlabel, unit, buf, true, es);
3418 }
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static char * buf
Definition: pg_test_fsync.c:67
static struct @131 value
#define INT64_FORMAT
Definition: c.h:367
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3349

◆ ExplainPropertyList()

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

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

3227 {
3228  ListCell *lc;
3229  bool first = true;
3230 
3231  switch (es->format)
3232  {
3233  case EXPLAIN_FORMAT_TEXT:
3234  appendStringInfoSpaces(es->str, es->indent * 2);
3235  appendStringInfo(es->str, "%s: ", qlabel);
3236  foreach(lc, data)
3237  {
3238  if (!first)
3239  appendStringInfoString(es->str, ", ");
3240  appendStringInfoString(es->str, (const char *) lfirst(lc));
3241  first = false;
3242  }
3243  appendStringInfoChar(es->str, '\n');
3244  break;
3245 
3246  case EXPLAIN_FORMAT_XML:
3247  ExplainXMLTag(qlabel, X_OPENING, es);
3248  foreach(lc, data)
3249  {
3250  char *str;
3251 
3252  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
3253  appendStringInfoString(es->str, "<Item>");
3254  str = escape_xml((const char *) lfirst(lc));
3255  appendStringInfoString(es->str, str);
3256  pfree(str);
3257  appendStringInfoString(es->str, "</Item>\n");
3258  }
3259  ExplainXMLTag(qlabel, X_CLOSING, es);
3260  break;
3261 
3262  case EXPLAIN_FORMAT_JSON:
3264  appendStringInfoSpaces(es->str, es->indent * 2);
3265  escape_json(es->str, qlabel);
3266  appendStringInfoString(es->str, ": [");
3267  foreach(lc, data)
3268  {
3269  if (!first)
3270  appendStringInfoString(es->str, ", ");
3271  escape_json(es->str, (const char *) lfirst(lc));
3272  first = false;
3273  }
3274  appendStringInfoChar(es->str, ']');
3275  break;
3276 
3277  case EXPLAIN_FORMAT_YAML:
3279  appendStringInfo(es->str, "%s: ", qlabel);
3280  foreach(lc, data)
3281  {
3282  appendStringInfoChar(es->str, '\n');
3283  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
3284  appendStringInfoString(es->str, "- ");
3285  escape_yaml(es->str, (const char *) lfirst(lc));
3286  }
3287  break;
3288  }
3289 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2461
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3688
#define X_CLOSING
Definition: explain.c:53
void pfree(void *pointer)
Definition: mcxt.c:1031
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3735
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3760
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3715
#define X_OPENING
Definition: explain.c:52
#define lfirst(lc)
Definition: pg_list.h:106
ExplainFormat format
Definition: explain.h:38
char * escape_xml(const char *str)
Definition: xml.c:2232
StringInfo str
Definition: explain.h:30

◆ ExplainPropertyListNested()

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

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

3297 {
3298  ListCell *lc;
3299  bool first = true;
3300 
3301  switch (es->format)
3302  {
3303  case EXPLAIN_FORMAT_TEXT:
3304  case EXPLAIN_FORMAT_XML:
3305  ExplainPropertyList(qlabel, data, es);
3306  return;
3307 
3308  case EXPLAIN_FORMAT_JSON:
3310  appendStringInfoSpaces(es->str, es->indent * 2);
3311  appendStringInfoChar(es->str, '[');
3312  foreach(lc, data)
3313  {
3314  if (!first)
3315  appendStringInfoString(es->str, ", ");
3316  escape_json(es->str, (const char *) lfirst(lc));
3317  first = false;
3318  }
3319  appendStringInfoChar(es->str, ']');
3320  break;
3321 
3322  case EXPLAIN_FORMAT_YAML:
3324  appendStringInfoString(es->str, "- [");
3325  foreach(lc, data)
3326  {
3327  if (!first)
3328  appendStringInfoString(es->str, ", ");
3329  escape_yaml(es->str, (const char *) lfirst(lc));
3330  first = false;
3331  }
3332  appendStringInfoChar(es->str, ']');
3333  break;
3334  }
3335 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2461
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3735
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3760
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3715
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:3226
#define lfirst(lc)
Definition: pg_list.h:106
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30

◆ ExplainPropertyText()

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

Definition at line 3402 of file explain.c.

References ExplainProperty().

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

3403 {
3404  ExplainProperty(qlabel, NULL, value, false, es);
3405 }
static struct @131 value
static void ExplainProperty(const char *qlabel, const char *unit, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3349

◆ ExplainQuery()

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

Definition at line 143 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::str, ExplainState::summary, ExplainState::timing, and ExplainState::verbose.

Referenced by standard_ProcessUtility().

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

◆ ExplainQueryText()

void ExplainQueryText ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 748 of file explain.c.

References ExplainPropertyText(), and QueryDesc::sourceText.

Referenced by explain_ExecutorEnd().

749 {
750  if (queryDesc->sourceText)
751  ExplainPropertyText("Query Text", queryDesc->sourceText, es);
752 }
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3402
const char * sourceText
Definition: execdesc.h:38

◆ ExplainResultDesc()

TupleDesc ExplainResultDesc ( ExplainStmt stmt)

Definition at line 300 of file explain.c.

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

Referenced by ExplainQuery(), and UtilityTupleDescriptor().

301 {
302  TupleDesc tupdesc;
303  ListCell *lc;
304  Oid result_type = TEXTOID;
305 
306  /* Check for XML format option */
307  foreach(lc, stmt->options)
308  {
309  DefElem *opt = (DefElem *) lfirst(lc);
310 
311  if (strcmp(opt->defname, "format") == 0)
312  {
313  char *p = defGetString(opt);
314 
315  if (strcmp(p, "xml") == 0)
316  result_type = XMLOID;
317  else if (strcmp(p, "json") == 0)
318  result_type = JSONOID;
319  else
320  result_type = TEXTOID;
321  /* don't "break", as ExplainQuery will use the last value */
322  }
323  }
324 
325  /* Need a tuple descriptor representing a single TEXT or XML column */
326  tupdesc = CreateTemplateTupleDesc(1, false);
327  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
328  result_type, -1, 0);
329  return tupdesc;
330 }
List * options
Definition: parsenodes.h:3177
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:600
#define lfirst(lc)
Definition: pg_list.h:106
TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid)
Definition: tupdesc.c:45
char * defname
Definition: parsenodes.h:730
int16 AttrNumber
Definition: attnum.h:21

◆ ExplainScanTarget()

static void ExplainScanTarget ( Scan plan,
ExplainState es 
)
static

Definition at line 2841 of file explain.c.

References ExplainTargetRel().

Referenced by ExplainNode().

2842 {
2843  ExplainTargetRel((Plan *) plan, plan->scanrelid, es);
2844 }
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:2863

◆ ExplainSeparatePlans()

void ExplainSeparatePlans ( ExplainState es)

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

3660 {
3661  switch (es->format)
3662  {
3663  case EXPLAIN_FORMAT_TEXT:
3664  /* add a blank line */
3665  appendStringInfoChar(es->str, '\n');
3666  break;
3667 
3668  case EXPLAIN_FORMAT_XML:
3669  case EXPLAIN_FORMAT_JSON:
3670  case EXPLAIN_FORMAT_YAML:
3671  /* nothing to do */
3672  break;
3673  }
3674 }
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30

◆ ExplainSubPlans()

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

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

3179 {
3180  ListCell *lst;
3181 
3182  foreach(lst, plans)
3183  {
3184  SubPlanState *sps = (SubPlanState *) lfirst(lst);
3185  SubPlan *sp = sps->subplan;
3186 
3187  /*
3188  * There can be multiple SubPlan nodes referencing the same physical
3189  * subplan (same plan_id, which is its index in PlannedStmt.subplans).
3190  * We should print a subplan only once, so track which ones we already
3191  * printed. This state must be global across the plan tree, since the
3192  * duplicate nodes could be in different plan nodes, eg both a bitmap
3193  * indexscan's indexqual and its parent heapscan's recheck qual. (We
3194  * do not worry too much about which plan node we show the subplan as
3195  * attached to in such cases.)
3196  */
3197  if (bms_is_member(sp->plan_id, es->printed_subplans))
3198  continue;
3200  sp->plan_id);
3201 
3202  ExplainNode(sps->planstate, ancestors,
3203  relationship, sp->plan_name, es);
3204  }
3205 }
int plan_id
Definition: primnodes.h:690
Bitmapset * printed_subplans
Definition: explain.h:47
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:914
struct PlanState * planstate
Definition: execnodes.h:821
SubPlan * subplan
Definition: execnodes.h:820
char * plan_name
Definition: primnodes.h:692
#define lfirst(lc)
Definition: pg_list.h:106
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:764
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:486

◆ ExplainTargetRel()

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

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

2864 {
2865  char *objectname = NULL;
2866  char *namespace = NULL;
2867  const char *objecttag = NULL;
2868  RangeTblEntry *rte;
2869  char *refname;
2870 
2871  rte = rt_fetch(rti, es->rtable);
2872  refname = (char *) list_nth(es->rtable_names, rti - 1);
2873  if (refname == NULL)
2874  refname = rte->eref->aliasname;
2875 
2876  switch (nodeTag(plan))
2877  {
2878  case T_SeqScan:
2879  case T_SampleScan:
2880  case T_IndexScan:
2881  case T_IndexOnlyScan:
2882  case T_BitmapHeapScan:
2883  case T_TidScan:
2884  case T_ForeignScan:
2885  case T_CustomScan:
2886  case T_ModifyTable:
2887  /* Assert it's on a real relation */
2888  Assert(rte->rtekind == RTE_RELATION);
2889  objectname = get_rel_name(rte->relid);
2890  if (es->verbose)
2891  namespace = get_namespace_name(get_rel_namespace(rte->relid));
2892  objecttag = "Relation Name";
2893  break;
2894  case T_FunctionScan:
2895  {
2896  FunctionScan *fscan = (FunctionScan *) plan;
2897 
2898  /* Assert it's on a RangeFunction */
2899  Assert(rte->rtekind == RTE_FUNCTION);
2900 
2901  /*
2902  * If the expression is still a function call of a single
2903  * function, we can get the real name of the function.
2904  * Otherwise, punt. (Even if it was a single function call
2905  * originally, the optimizer could have simplified it away.)
2906  */
2907  if (list_length(fscan->functions) == 1)
2908  {
2909  RangeTblFunction *rtfunc = (RangeTblFunction *) linitial(fscan->functions);
2910 
2911  if (IsA(rtfunc->funcexpr, FuncExpr))
2912  {
2913  FuncExpr *funcexpr = (FuncExpr *) rtfunc->funcexpr;
2914  Oid funcid = funcexpr->funcid;
2915 
2916  objectname = get_func_name(funcid);
2917  if (es->verbose)
2918  namespace =
2920  }
2921  }
2922  objecttag = "Function Name";
2923  }
2924  break;
2925  case T_TableFuncScan:
2926  Assert(rte->rtekind == RTE_TABLEFUNC);
2927  objectname = "xmltable";
2928  objecttag = "Table Function Name";
2929  break;
2930  case T_ValuesScan:
2931  Assert(rte->rtekind == RTE_VALUES);
2932  break;
2933  case T_CteScan:
2934  /* Assert it's on a non-self-reference CTE */
2935  Assert(rte->rtekind == RTE_CTE);
2936  Assert(!rte->self_reference);
2937  objectname = rte->ctename;
2938  objecttag = "CTE Name";
2939  break;
2940  case T_NamedTuplestoreScan:
2942  objectname = rte->enrname;
2943  objecttag = "Tuplestore Name";
2944  break;
2945  case T_WorkTableScan:
2946  /* Assert it's on a self-reference CTE */
2947  Assert(rte->rtekind == RTE_CTE);
2948  Assert(rte->self_reference);
2949  objectname = rte->ctename;
2950  objecttag = "CTE Name";
2951  break;
2952  default:
2953  break;
2954  }
2955 
2956  if (es->format == EXPLAIN_FORMAT_TEXT)
2957  {
2958  appendStringInfoString(es->str, " on");
2959  if (namespace != NULL)
2960  appendStringInfo(es->str, " %s.%s", quote_identifier(namespace),
2961  quote_identifier(objectname));
2962  else if (objectname != NULL)
2963  appendStringInfo(es->str, " %s", quote_identifier(objectname));
2964  if (objectname == NULL || strcmp(refname, objectname) != 0)
2965  appendStringInfo(es->str, " %s", quote_identifier(refname));
2966  }
2967  else
2968  {
2969  if (objecttag != NULL && objectname != NULL)
2970  ExplainPropertyText(objecttag, objectname, es);
2971  if (namespace != NULL)
2972  ExplainPropertyText("Schema", namespace, es);
2973  ExplainPropertyText("Alias", refname, es);
2974  }
2975 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10488
Oid get_func_namespace(Oid funcid)
Definition: lsyscache.c:1421
List * functions
Definition: plannodes.h:522
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1754
unsigned int Oid
Definition: postgres_ext.h:31
List * rtable_names
Definition: explain.h:45
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3402
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
#define linitial(l)
Definition: pg_list.h:111
Oid funcid
Definition: primnodes.h:450
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1397
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3051
void * list_nth(const List *list, int n)
Definition: list.c:410
char * enrname
Definition: parsenodes.h:1059
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
bool self_reference
Definition: parsenodes.h:1034
bool verbose
Definition: explain.h:32
#define Assert(condition)
Definition: c.h:699
char * aliasname
Definition: primnodes.h:43
static int list_length(const List *l)
Definition: pg_list.h:89
ExplainFormat format
Definition: explain.h:38
#define nodeTag(nodeptr)
Definition: nodes.h:522
RTEKind rtekind
Definition: parsenodes.h:962
char * ctename
Definition: parsenodes.h:1032
Alias * eref
Definition: parsenodes.h:1066
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
StringInfo str
Definition: explain.h:30
List * rtable
Definition: explain.h:44

◆ ExplainXMLTag()

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

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

3689 {
3690  const char *s;
3691  const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
3692 
3693  if ((flags & X_NOWHITESPACE) == 0)
3694  appendStringInfoSpaces(es->str, 2 * es->indent);
3695  appendStringInfoCharMacro(es->str, '<');
3696  if ((flags & X_CLOSING) != 0)
3697  appendStringInfoCharMacro(es->str, '/');
3698  for (s = tagname; *s; s++)
3699  appendStringInfoChar(es->str, strchr(valid, *s) ? *s : '-');
3700  if ((flags & X_CLOSE_IMMEDIATE) != 0)
3701  appendStringInfoString(es->str, " /");
3702  appendStringInfoCharMacro(es->str, '>');
3703  if ((flags & X_NOWHITESPACE) == 0)
3704  appendStringInfoCharMacro(es->str, '\n');
3705 }
#define X_CLOSING
Definition: explain.c:53
#define appendStringInfoCharMacro(str, ch)
Definition: stringinfo.h:127
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
#define X_NOWHITESPACE
Definition: explain.c:55
#define X_CLOSE_IMMEDIATE
Definition: explain.c:54
StringInfo str
Definition: explain.h:30

◆ ExplainYAMLLineStarting()

static void ExplainYAMLLineStarting ( ExplainState es)
static

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

3736 {
3738  if (linitial_int(es->grouping_stack) == 0)
3739  {
3740  linitial_int(es->grouping_stack) = 1;
3741  }
3742  else
3743  {
3744  appendStringInfoChar(es->str, '\n');
3745  appendStringInfoSpaces(es->str, es->indent * 2);
3746  }
3747 }
#define linitial_int(l)
Definition: pg_list.h:112
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
#define Assert(condition)
Definition: c.h:699
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30

◆ NewExplainState()

ExplainState* NewExplainState ( void  )

Definition at line 283 of file explain.c.

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

Referenced by explain_ExecutorEnd(), and ExplainQuery().

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

◆ report_triggers()

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

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

760 {
761  int nt;
762 
763  if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
764  return;
765  for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
766  {
767  Trigger *trig = rInfo->ri_TrigDesc->triggers + nt;
768  Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
769  char *relname;
770  char *conname = NULL;
771 
772  /* Must clean up instrumentation state */
773  InstrEndLoop(instr);
774 
775  /*
776  * We ignore triggers that were never invoked; they likely aren't
777  * relevant to the current query type.
778  */
779  if (instr->ntuples == 0)
780  continue;
781 
782  ExplainOpenGroup("Trigger", NULL, true, es);
783 
784  relname = RelationGetRelationName(rInfo->ri_RelationDesc);
785  if (OidIsValid(trig->tgconstraint))
786  conname = get_constraint_name(trig->tgconstraint);
787 
788  /*
789  * In text format, we avoid printing both the trigger name and the
790  * constraint name unless VERBOSE is specified. In non-text formats
791  * we just print everything.
792  */
793  if (es->format == EXPLAIN_FORMAT_TEXT)
794  {
795  if (es->verbose || conname == NULL)
796  appendStringInfo(es->str, "Trigger %s", trig->tgname);
797  else
798  appendStringInfoString(es->str, "Trigger");
799  if (conname)
800  appendStringInfo(es->str, " for constraint %s", conname);
801  if (show_relname)
802  appendStringInfo(es->str, " on %s", relname);
803  if (es->timing)
804  appendStringInfo(es->str, ": time=%.3f calls=%.0f\n",
805  1000.0 * instr->total, instr->ntuples);
806  else
807  appendStringInfo(es->str, ": calls=%.0f\n", instr->ntuples);
808  }
809  else
810  {
811  ExplainPropertyText("Trigger Name", trig->tgname, es);
812  if (conname)
813  ExplainPropertyText("Constraint Name", conname, es);
814  ExplainPropertyText("Relation", relname, es);
815  if (es->timing)
816  ExplainPropertyFloat("Time", "ms", 1000.0 * instr->total, 3,
817  es);
818  ExplainPropertyFloat("Calls", NULL, instr->ntuples, 0, es);
819  }
820 
821  if (conname)
822  pfree(conname);
823 
824  ExplainCloseGroup("Trigger", NULL, true, es);
825  }
826 }
Relation ri_RelationDesc
Definition: execnodes.h:397
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:982
void ExplainPropertyFloat(const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
Definition: explain.c:3425
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:418
#define OidIsValid(objectId)
Definition: c.h:605
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:114
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3402
void pfree(void *pointer)
Definition: mcxt.c:1031
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
Oid tgconstraint
Definition: reltrigger.h:34
char * tgname
Definition: reltrigger.h:27
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
Trigger * triggers
Definition: reltrigger.h:48
#define RelationGetRelationName(relation)
Definition: rel.h:441
double ntuples
Definition: instrument.h:59
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:409
bool timing
Definition: explain.h:36
int numtriggers
Definition: reltrigger.h:49
bool verbose
Definition: explain.h:32
ExplainFormat format
Definition: explain.h:38
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3517
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3454
StringInfo str
Definition: explain.h:30

◆ show_agg_keys()

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

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

2035 {
2036  Agg *plan = (Agg *) astate->ss.ps.plan;
2037 
2038  if (plan->numCols > 0 || plan->groupingSets)
2039  {
2040  /* The key columns refer to the tlist of the child plan */
2041  ancestors = lcons(astate, ancestors);
2042 
2043  if (plan->groupingSets)
2044  show_grouping_sets(outerPlanState(astate), plan, ancestors, es);
2045  else
2046  show_sort_group_keys(outerPlanState(astate), "Group Key",
2047  plan->numCols, plan->grpColIdx,
2048  NULL, NULL, NULL,
2049  ancestors, es);
2050 
2051  ancestors = list_delete_first(ancestors);
2052  }
2053 }
int numCols
Definition: plannodes.h:799
AttrNumber * grpColIdx
Definition: plannodes.h:800
ScanState ss
Definition: execnodes.h:1892
PlanState ps
Definition: execnodes.h:1191
#define outerPlanState(node)
Definition: execnodes.h:965
static void show_grouping_sets(PlanState *planstate, Agg *agg, List *ancestors, ExplainState *es)
Definition: explain.c:2056
List * groupingSets
Definition: plannodes.h:805
Plan * plan
Definition: execnodes.h:911
List * lcons(void *datum, List *list)
Definition: list.c:259
Definition: plannodes.h:794
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:2185
List * list_delete_first(List *list)
Definition: list.c:666

◆ show_buffer_usage()

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

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

2679 {
2680  if (es->format == EXPLAIN_FORMAT_TEXT)
2681  {
2682  bool has_shared = (usage->shared_blks_hit > 0 ||
2683  usage->shared_blks_read > 0 ||
2684  usage->shared_blks_dirtied > 0 ||
2685  usage->shared_blks_written > 0);
2686  bool has_local = (usage->local_blks_hit > 0 ||
2687  usage->local_blks_read > 0 ||
2688  usage->local_blks_dirtied > 0 ||
2689  usage->local_blks_written > 0);
2690  bool has_temp = (usage->temp_blks_read > 0 ||
2691  usage->temp_blks_written > 0);
2692  bool has_timing = (!INSTR_TIME_IS_ZERO(usage->blk_read_time) ||
2694 
2695  /* Show only positive counter values. */
2696  if (has_shared || has_local || has_temp)
2697  {
2698  appendStringInfoSpaces(es->str, es->indent * 2);
2699  appendStringInfoString(es->str, "Buffers:");
2700 
2701  if (has_shared)
2702  {
2703  appendStringInfoString(es->str, " shared");
2704  if (usage->shared_blks_hit > 0)
2705  appendStringInfo(es->str, " hit=%ld",
2706  usage->shared_blks_hit);
2707  if (usage->shared_blks_read > 0)
2708  appendStringInfo(es->str, " read=%ld",
2709  usage->shared_blks_read);
2710  if (usage->shared_blks_dirtied > 0)
2711  appendStringInfo(es->str, " dirtied=%ld",
2712  usage->shared_blks_dirtied);
2713  if (usage->shared_blks_written > 0)
2714  appendStringInfo(es->str, " written=%ld",
2715  usage->shared_blks_written);
2716  if (has_local || has_temp)
2717  appendStringInfoChar(es->str, ',');
2718  }
2719  if (has_local)
2720  {
2721  appendStringInfoString(es->str, " local");
2722  if (usage->local_blks_hit > 0)
2723  appendStringInfo(es->str, " hit=%ld",
2724  usage->local_blks_hit);
2725  if (usage->local_blks_read > 0)
2726  appendStringInfo(es->str, " read=%ld",
2727  usage->local_blks_read);
2728  if (usage->local_blks_dirtied > 0)
2729  appendStringInfo(es->str, " dirtied=%ld",
2730  usage->local_blks_dirtied);
2731  if (usage->local_blks_written > 0)
2732  appendStringInfo(es->str, " written=%ld",
2733  usage->local_blks_written);
2734  if (has_temp)
2735  appendStringInfoChar(es->str, ',');
2736  }
2737  if (has_temp)
2738  {
2739  appendStringInfoString(es->str, " temp");
2740  if (usage->temp_blks_read > 0)
2741  appendStringInfo(es->str, " read=%ld",
2742  usage->temp_blks_read);
2743  if (usage->temp_blks_written > 0)
2744  appendStringInfo(es->str, " written=%ld",
2745  usage->temp_blks_written);
2746  }
2747  appendStringInfoChar(es->str, '\n');
2748  }
2749 
2750  /* As above, show only positive counter values. */
2751  if (has_timing)
2752  {
2753  appendStringInfoSpaces(es->str, es->indent * 2);
2754  appendStringInfoString(es->str, "I/O Timings:");
2755  if (!INSTR_TIME_IS_ZERO(usage->blk_read_time))
2756  appendStringInfo(es->str, " read=%0.3f",
2758  if (!INSTR_TIME_IS_ZERO(usage->blk_write_time))
2759  appendStringInfo(es->str, " write=%0.3f",
2761  appendStringInfoChar(es->str, '\n');
2762  }
2763  }
2764  else
2765  {
2766  ExplainPropertyInteger("Shared Hit Blocks", NULL,
2767  usage->shared_blks_hit, es);
2768  ExplainPropertyInteger("Shared Read Blocks", NULL,
2769  usage->shared_blks_read, es);
2770  ExplainPropertyInteger("Shared Dirtied Blocks", NULL,
2771  usage->shared_blks_dirtied, es);
2772  ExplainPropertyInteger("Shared Written Blocks", NULL,
2773  usage->shared_blks_written, es);
2774  ExplainPropertyInteger("Local Hit Blocks", NULL,
2775  usage->local_blks_hit, es);
2776  ExplainPropertyInteger("Local Read Blocks", NULL,
2777  usage->local_blks_read, es);
2778  ExplainPropertyInteger("Local Dirtied Blocks", NULL,
2779  usage->local_blks_dirtied, es);
2780  ExplainPropertyInteger("Local Written Blocks", NULL,
2781  usage->local_blks_written, es);
2782  ExplainPropertyInteger("Temp Read Blocks", NULL,
2783  usage->temp_blks_read, es);
2784  ExplainPropertyInteger("Temp Written Blocks", NULL,
2785  usage->temp_blks_written, es);
2786  if (track_io_timing)
2787  {
2788  ExplainPropertyFloat("I/O Read Time", "ms",
2790  3, es);
2791  ExplainPropertyFloat("I/O Write Time", "ms",
2793  3, es);
2794  }
2795  }
2796 }
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:3411
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:3425
#define INSTR_TIME_GET_MILLISEC(t)
Definition: instr_time.h:199
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:149
long shared_blks_written
Definition: instrument.h:24
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
long shared_blks_dirtied
Definition: instrument.h:23
int indent
Definition: explain.h:40
long temp_blks_read
Definition: instrument.h:29
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
instr_time blk_write_time
Definition: instrument.h:32
ExplainFormat format
Definition: explain.h:38
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:111

◆ show_eval_params()

static void show_eval_params ( Bitmapset bms_params,
ExplainState es 
)
static

Definition at line 2629 of file explain.c.

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

Referenced by ExplainNode().

2630 {
2631  int paramid = -1;
2632  List *params = NIL;
2633 
2634  Assert(bms_params);
2635 
2636  while ((paramid = bms_next_member(bms_params, paramid)) >= 0)
2637  {
2638  char param[32];
2639 
2640  snprintf(param, sizeof(param), "$%d", paramid);
2641  params = lappend(params, pstrdup(param));
2642  }
2643 
2644  if (params)
2645  ExplainPropertyList("Params Evaluated", params, es);
2646 }
#define NIL
Definition: pg_list.h:69
char * pstrdup(const char *in)
Definition: mcxt.c:1161
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1075
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
List * lappend(List *list, void *datum)
Definition: list.c:128
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:3226
#define Assert(condition)
Definition: c.h:699
Definition: pg_list.h:45

◆ show_expression()

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

Definition at line 1930 of file explain.c.

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

Referenced by ExplainNode(), and show_qual().

1933 {
1934  List *context;
1935  char *exprstr;
1936 
1937  /* Set up deparsing context */
1939  (Node *) planstate,
1940  ancestors);
1941 
1942  /* Deparse the expression */
1943  exprstr = deparse_expression(node, context, useprefix, false);
1944 
1945  /* And add to es->str */
1946  ExplainPropertyText(qlabel, exprstr, es);
1947 }
Definition: nodes.h:517
List * deparse_cxt
Definition: explain.h:46
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3402
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:3223
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:3071
Definition: pg_list.h:45

◆ show_foreignscan_info()

static void show_foreignscan_info ( ForeignScanState fsstate,
ExplainState es 
)
static

Definition at line 2608 of file explain.c.

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

Referenced by ExplainNode().

2609 {
2610  FdwRoutine *fdwroutine = fsstate->fdwroutine;
2611 
2612  /* Let the FDW emit whatever fields it wants */
2613  if (((ForeignScan *) fsstate->ss.ps.plan)->operation != CMD_SELECT)
2614  {
2615  if (fdwroutine->ExplainDirectModify != NULL)
2616  fdwroutine->ExplainDirectModify(fsstate, es);
2617  }
2618  else
2619  {
2620  if (fdwroutine->ExplainForeignScan != NULL)
2621  fdwroutine->ExplainForeignScan(fsstate, es);
2622  }
2623 }
ScanState ss
Definition: execnodes.h:1640
ExplainForeignScan_function ExplainForeignScan
Definition: fdwapi.h:228
PlanState ps
Definition: execnodes.h:1191
ExplainDirectModify_function ExplainDirectModify
Definition: fdwapi.h:230
struct FdwRoutine * fdwroutine
Definition: execnodes.h:1644
Plan * plan
Definition: execnodes.h:911

◆ show_group_keys()

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

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

2167 {
2168  Group *plan = (Group *) gstate->ss.ps.plan;
2169 
2170  /* The key columns refer to the tlist of the child plan */
2171  ancestors = lcons(gstate, ancestors);
2172  show_sort_group_keys(outerPlanState(gstate), "Group Key",
2173  plan->numCols, plan->grpColIdx,
2174  NULL, NULL, NULL,
2175  ancestors, es);
2176  ancestors = list_delete_first(ancestors);
2177 }
ScanState ss
Definition: execnodes.h:1866
PlanState ps
Definition: execnodes.h:1191
#define outerPlanState(node)
Definition: execnodes.h:965
int numCols
Definition: plannodes.h:775
Plan * plan
Definition: execnodes.h:911
List * lcons(void *datum, List *list)
Definition: list.c:259
AttrNumber * grpColIdx
Definition: plannodes.h:776
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:2185
List * list_delete_first(List *list)
Definition: list.c:666

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

2091 {
2092  Plan *plan = planstate->plan;
2093  char *exprstr;
2094  ListCell *lc;
2095  List *gsets = aggnode->groupingSets;
2096  AttrNumber *keycols = aggnode->grpColIdx;
2097  const char *keyname;
2098  const char *keysetname;
2099 
2100  if (aggnode->aggstrategy == AGG_HASHED || aggnode->aggstrategy == AGG_MIXED)
2101  {
2102  keyname = "Hash Key";
2103  keysetname = "Hash Keys";
2104  }
2105  else
2106  {
2107  keyname = "Group Key";
2108  keysetname = "Group Keys";
2109  }
2110 
2111  ExplainOpenGroup("Grouping Set", NULL, true, es);
2112 
2113  if (sortnode)
2114  {
2115  show_sort_group_keys(planstate, "Sort Key",
2116  sortnode->numCols, sortnode->sortColIdx,
2117  sortnode->sortOperators, sortnode->collations,
2118  sortnode->nullsFirst,
2119  ancestors, es);
2120  if (es->format == EXPLAIN_FORMAT_TEXT)
2121  es->indent++;
2122  }
2123 
2124  ExplainOpenGroup(keysetname, keysetname, false, es);
2125 
2126  foreach(lc, gsets)
2127  {
2128  List *result = NIL;
2129  ListCell *lc2;
2130 
2131  foreach(lc2, (List *) lfirst(lc))
2132  {
2133  Index i = lfirst_int(lc2);
2134  AttrNumber keyresno = keycols[i];
2135  TargetEntry *target = get_tle_by_resno(plan->targetlist,
2136  keyresno);
2137 
2138  if (!target)
2139  elog(ERROR, "no tlist entry for key %d", keyresno);
2140  /* Deparse the expression, showing any top-level cast */
2141  exprstr = deparse_expression((Node *) target->expr, context,
2142  useprefix, true);
2143 
2144  result = lappend(result, exprstr);
2145  }
2146 
2147  if (!result && es->format == EXPLAIN_FORMAT_TEXT)
2148  ExplainPropertyText(keyname, "()", es);
2149  else
2150  ExplainPropertyListNested(keyname, result, es);
2151  }
2152 
2153  ExplainCloseGroup(keysetname, keysetname, false, es);
2154 
2155  if (sortnode && es->format == EXPLAIN_FORMAT_TEXT)
2156  es->indent--;
2157 
2158  ExplainCloseGroup("Grouping Set", NULL, true, es);
2159 }
#define NIL
Definition: pg_list.h:69
AttrNumber * grpColIdx
Definition: plannodes.h:800
Definition: nodes.h:517
bool * nullsFirst
Definition: plannodes.h:763
Oid * sortOperators
Definition: plannodes.h:761
void ExplainPropertyListNested(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:3296
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3402
AggStrategy aggstrategy
Definition: plannodes.h:797
#define ERROR
Definition: elog.h:43
#define lfirst_int(lc)
Definition: pg_list.h:107
int indent
Definition: explain.h:40
List * lappend(List *list, void *datum)
Definition: list.c:128
int numCols
Definition: plannodes.h:759
List * groupingSets
Definition: plannodes.h:805
unsigned int Index
Definition: c.h:442
Plan * plan
Definition: execnodes.h:911
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1376
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:3071
ExplainFormat format
Definition: explain.h:38
List * targetlist
Definition: plannodes.h:146
AttrNumber * sortColIdx
Definition: plannodes.h:760
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:3517
#define elog
Definition: elog.h:219
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:2185
Oid * collations
Definition: plannodes.h:762
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3454
Definition: pg_list.h:45
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 2056 of file explain.c.

References Agg::chain, 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().

2058 {
2059  List *context;
2060  bool useprefix;
2061  ListCell *lc;
2062 
2063  /* Set up deparsing context */
2065  (Node *) planstate,
2066  ancestors);
2067  useprefix = (list_length(es->rtable) > 1 || es->verbose);
2068 
2069  ExplainOpenGroup("Grouping Sets", "Grouping Sets", false, es);
2070 
2071  show_grouping_set_keys(planstate, agg, NULL,
2072  context, useprefix, ancestors, es);
2073 
2074  foreach(lc, agg->chain)
2075  {
2076  Agg *aggnode = lfirst(lc);
2077  Sort *sortnode = (Sort *) aggnode->plan.lefttree;
2078 
2079  show_grouping_set_keys(planstate, aggnode, sortnode,
2080  context, useprefix, ancestors, es);
2081  }
2082 
2083  ExplainCloseGroup("Grouping Sets", "Grouping Sets", false, es);
2084 }
Definition: nodes.h:517
List * deparse_cxt
Definition: explain.h:46
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:3223
Plan plan
Definition: plannodes.h:796
bool verbose
Definition: explain.h:32
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
struct Plan * lefttree
Definition: plannodes.h:148
static void show_grouping_set_keys(PlanState *planstate, Agg *aggnode, Sort *sortnode, List *context, bool useprefix, List *ancestors, ExplainState *es)
Definition: explain.c:2087
List * chain
Definition: plannodes.h:806
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3517
Definition: plannodes.h:794
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3454
Definition: pg_list.h:45
List * rtable
Definition: explain.h:44

◆ show_hash_info()

static void show_hash_info ( HashState hashstate,
ExplainState es 
)
static

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

2447 {
2448  HashInstrumentation hinstrument = {0};
2449 
2450  /*
2451  * In a parallel query, the leader process may or may not have run the
2452  * hash join, and even if it did it may not have built a hash table due to
2453  * timing (if it started late it might have seen no tuples in the outer
2454  * relation and skipped building the hash table). Therefore we have to be
2455  * prepared to get instrumentation data from all participants.
2456  */
2457  if (hashstate->hashtable)
2458  ExecHashGetInstrumentation(&hinstrument, hashstate->hashtable);
2459 
2460  /*
2461  * Merge results from workers. In the parallel-oblivious case, the
2462  * results from all participants should be identical, except where
2463  * participants didn't run the join at all so have no data. In the
2464  * parallel-aware case, we need to consider all the results. Each worker
2465  * may have seen a different subset of batches and we want to find the
2466  * highest memory usage for any one batch across all batches.
2467  */
2468  if (hashstate->shared_info)
2469  {
2470  SharedHashInfo *shared_info = hashstate->shared_info;
2471  int i;
2472 
2473  for (i = 0; i < shared_info->num_workers; ++i)
2474  {
2475  HashInstrumentation *worker_hi = &shared_info->hinstrument[i];
2476 
2477  if (worker_hi->nbatch > 0)
2478  {
2479  /*
2480  * Every participant should agree on the buckets, so to be
2481  * sure we have a value we'll just overwrite each time.
2482  */
2483  hinstrument.nbuckets = worker_hi->nbuckets;
2484  hinstrument.nbuckets_original = worker_hi->nbuckets_original;
2485 
2486  /*
2487  * Normally every participant should agree on the number of
2488  * batches too, but it's possible for a backend that started
2489  * late and missed the whole join not to have the final nbatch
2490  * number. So we'll take the largest number.
2491  */
2492  hinstrument.nbatch = Max(hinstrument.nbatch, worker_hi->nbatch);
2493  hinstrument.nbatch_original = worker_hi->nbatch_original;
2494 
2495  /*
2496  * In a parallel-aware hash join, for now we report the
2497  * maximum peak memory reported by any worker.
2498  */
2499  hinstrument.space_peak =
2500  Max(hinstrument.space_peak, worker_hi->space_peak);
2501  }
2502  }
2503  }
2504 
2505  if (hinstrument.nbatch > 0)
2506  {
2507  long spacePeakKb = (hinstrument.space_peak + 1023) / 1024;
2508 
2509  if (es->format != EXPLAIN_FORMAT_TEXT)
2510  {
2511  ExplainPropertyInteger("Hash Buckets", NULL,
2512  hinstrument.nbuckets, es);
2513  ExplainPropertyInteger("Original Hash Buckets", NULL,
2514  hinstrument.nbuckets_original, es);
2515  ExplainPropertyInteger("Hash Batches", NULL,
2516  hinstrument.nbatch, es);
2517  ExplainPropertyInteger("Original Hash Batches", NULL,
2518  hinstrument.nbatch_original, es);
2519  ExplainPropertyInteger("Peak Memory Usage", "kB",
2520  spacePeakKb, es);
2521  }
2522  else if (hinstrument.nbatch_original != hinstrument.nbatch ||
2523  hinstrument.nbuckets_original != hinstrument.nbuckets)
2524  {
2525  appendStringInfoSpaces(es->str, es->indent * 2);
2526  appendStringInfo(es->str,
2527  "Buckets: %d (originally %d) Batches: %d (originally %d) Memory Usage: %ldkB\n",
2528  hinstrument.nbuckets,
2529  hinstrument.nbuckets_original,
2530  hinstrument.nbatch,
2531  hinstrument.nbatch_original,
2532  spacePeakKb);
2533  }
2534  else
2535  {
2536  appendStringInfoSpaces(es->str, es->indent * 2);
2537  appendStringInfo(es->str,
2538  "Buckets: %d Batches: %d Memory Usage: %ldkB\n",
2539  hinstrument.nbuckets, hinstrument.nbatch,
2540  spacePeakKb);
2541  }
2542  }
2543 }
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:3411
void ExecHashGetInstrumentation(HashInstrumentation *instrument, HashJoinTable hashtable)
Definition: nodeHash.c:2636
HashJoinTable hashtable
Definition: execnodes.h:2128
SharedHashInfo * shared_info
Definition: execnodes.h:2132
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
int indent
Definition: explain.h:40
HashInstrumentation hinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2118
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
#define Max(x, y)
Definition: c.h:851
ExplainFormat format
Definition: explain.h:38
int i
StringInfo str
Definition: explain.h:30

◆ show_instrumentation_count()

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

Definition at line 2579 of file explain.c.

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

Referenced by ExplainNode(), and show_modifytable_info().

2581 {
2582  double nfiltered;
2583  double nloops;
2584 
2585  if (!es->analyze || !planstate->instrument)
2586  return;
2587 
2588  if (which == 2)
2589  nfiltered = planstate->instrument->nfiltered2;
2590  else
2591  nfiltered = planstate->instrument->nfiltered1;
2592  nloops = planstate->instrument->nloops;
2593 
2594  /* In text mode, suppress zero counts; they're not interesting enough */
2595  if (nfiltered > 0 || es->format != EXPLAIN_FORMAT_TEXT)
2596  {
2597  if (nloops > 0)
2598  ExplainPropertyFloat(qlabel, NULL, nfiltered / nloops, 0, es);
2599  else
2600  ExplainPropertyFloat(qlabel, NULL, 0.0, 0, es);
2601  }
2602 }
double nfiltered1
Definition: instrument.h:62
Instrumentation * instrument
Definition: execnodes.h:921
void ExplainPropertyFloat(const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
Definition: explain.c:3425
bool analyze
Definition: explain.h:33
double nfiltered2
Definition: instrument.h:63
ExplainFormat format
Definition: explain.h:38

◆ show_merge_append_keys()

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

Definition at line 2017 of file explain.c.

References MergeAppend::collations, MergeAppend::nullsFirst, MergeAppend::numCols, PlanState::plan, MergeAppendState::ps, show_sort_group_keys(), MergeAppend::sortColIdx, and MergeAppend::sortOperators.

Referenced by ExplainNode().

2019 {
2020  MergeAppend *plan = (MergeAppend *) mstate->ps.plan;
2021 
2022  show_sort_group_keys((PlanState *) mstate, "Sort Key",
2023  plan->numCols, plan->sortColIdx,
2024  plan->sortOperators, plan->collations,
2025  plan->nullsFirst,
2026  ancestors, es);
2027 }
Oid * collations
Definition: plannodes.h:282
Plan * plan
Definition: execnodes.h:911
PlanState ps
Definition: execnodes.h:1112
AttrNumber * sortColIdx
Definition: plannodes.h:280
bool * nullsFirst
Definition: plannodes.h:283
Oid * sortOperators
Definition: plannodes.h:281
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:2185

◆ show_modifytable_info()

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

Definition at line 2986 of file explain.c.

References ExplainState::analyze, appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), ModifyTable::arbiterIndexes, CMD_DELETE, CMD_INSERT, CMD_UPDATE, EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), FdwRoutine::ExplainForeignModify, ExplainOpenGroup(), ExplainPropertyFloat(), ExplainPropertyList(), ExplainPropertyText(), ExplainTargetRel(), ModifyTable::fdwPrivLists, ExplainState::format, get_rel_name(), ExplainState::indent, InstrEndLoop(), PlanState::instrument, lappend(), lfirst_oid, list_nth(), ModifyTableState::mt_nplans, ModifyTableState::mt_plans, NIL, ModifyTable::nominalRelation, Instrumentation::ntuples, Instrumentation::ntuples2, ONCONFLICT_NONE, ONCONFLICT_NOTHING, ModifyTable::onConflictAction, ModifyTable::onConflictWhere, ModifyTable::operation, PlanState::plan, ModifyTableState::ps, ModifyTableState::resultRelInfo, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_RangeTableIndex, ResultRelInfo::ri_usesFdwDirectModify, show_instrumentation_count(), show_upper_qual(), and ExplainState::str.

Referenced by ExplainNode().

2988 {
2989  ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
2990  const char *operation;
2991  const char *foperation;
2992  bool labeltargets;
2993  int j;
2994  List *idxNames = NIL;
2995  ListCell *lst;
2996 
2997  switch (node->operation)
2998  {
2999  case CMD_INSERT:
3000  operation = "Insert";
3001  foperation = "Foreign Insert";
3002  break;
3003  case CMD_UPDATE:
3004  operation = "Update";
3005  foperation = "Foreign Update";
3006  break;
3007  case CMD_DELETE:
3008  operation = "Delete";
3009  foperation = "Foreign Delete";
3010  break;
3011  default:
3012  operation = "???";
3013  foperation = "Foreign ???";
3014  break;
3015  }
3016 
3017  /* Should we explicitly label target relations? */
3018  labeltargets = (mtstate->mt_nplans > 1 ||
3019  (mtstate->mt_nplans == 1 &&
3020  mtstate->resultRelInfo->ri_RangeTableIndex != node->nominalRelation));
3021 
3022  if (labeltargets)
3023  ExplainOpenGroup("Target Tables", "Target Tables", false, es);
3024 
3025  for (j = 0; j < mtstate->mt_nplans; j++)
3026  {
3027  ResultRelInfo *resultRelInfo = mtstate->resultRelInfo + j;
3028  FdwRoutine *fdwroutine = resultRelInfo->ri_FdwRoutine;
3029 
3030  if (labeltargets)
3031  {
3032  /* Open a group for this target */
3033  ExplainOpenGroup("Target Table", NULL, true, es);
3034 
3035  /*
3036  * In text mode, decorate each target with operation type, so that
3037  * ExplainTargetRel's output of " on foo" will read nicely.
3038  */
3039  if (es->format == EXPLAIN_FORMAT_TEXT)
3040  {
3041  appendStringInfoSpaces(es->str, es->indent * 2);
3043  fdwroutine ? foperation : operation);
3044  }
3045 
3046  /* Identify target */
3047  ExplainTargetRel((Plan *) node,
3048  resultRelInfo->ri_RangeTableIndex,
3049  es);
3050 
3051  if (es->format == EXPLAIN_FORMAT_TEXT)
3052  {
3053  appendStringInfoChar(es->str, '\n');
3054  es->indent++;
3055  }
3056  }
3057 
3058  /* Give FDW a chance if needed */
3059  if (!resultRelInfo->ri_usesFdwDirectModify &&
3060  fdwroutine != NULL &&
3061  fdwroutine->ExplainForeignModify != NULL)
3062  {
3063  List *fdw_private = (List *) list_nth(node->fdwPrivLists, j);
3064 
3065  fdwroutine->ExplainForeignModify(mtstate,
3066  resultRelInfo,
3067  fdw_private,
3068  j,
3069  es);
3070  }
3071 
3072  if (labeltargets)
3073  {
3074  /* Undo the indentation we added in text format */
3075  if (es->format == EXPLAIN_FORMAT_TEXT)
3076  es->indent--;
3077 
3078  /* Close the group */
3079  ExplainCloseGroup("Target Table", NULL, true, es);
3080  }
3081  }
3082 
3083  /* Gather names of ON CONFLICT arbiter indexes */
3084  foreach(lst, node->arbiterIndexes)
3085  {
3086  char *indexname = get_rel_name(lfirst_oid(lst));
3087 
3088  idxNames = lappend(idxNames, indexname);
3089  }
3090 
3091  if (node->onConflictAction !=