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 "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 (List *plans, PlanState **planstates, 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 *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 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, int value, ExplainState *es)
 
void ExplainPropertyLong (const char *qlabel, long value, ExplainState *es)
 
void ExplainPropertyFloat (const char *qlabel, double value, int ndigits, ExplainState *es)
 
void ExplainPropertyBool (const char *qlabel, bool value, ExplainState *es)
 
void ExplainOpenGroup (const char *objtype, const char *labelname, bool labeled, ExplainState *es)
 
void ExplainCloseGroup (const char *objtype, const char *labelname, bool labeled, ExplainState *es)
 
void ExplainBeginOutput (ExplainState *es)
 
void ExplainEndOutput (ExplainState *es)
 
void ExplainSeparatePlans (ExplainState *es)
 

Variables

ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL
 
explain_get_index_name_hook_type explain_get_index_name_hook = NULL
 

Macro Definition Documentation

◆ X_CLOSE_IMMEDIATE

#define X_CLOSE_IMMEDIATE   2

Definition at line 53 of file explain.c.

Referenced by ExplainDummyGroup(), and ExplainXMLTag().

◆ X_CLOSING

#define X_CLOSING   1

Definition at line 52 of file explain.c.

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

◆ X_NOWHITESPACE

#define X_NOWHITESPACE   4

Definition at line 54 of file explain.c.

Referenced by ExplainProperty(), and ExplainXMLTag().

◆ X_OPENING

#define X_OPENING   0

Definition at line 51 of file explain.c.

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

Function Documentation

◆ elapsed_time()

static double elapsed_time ( instr_time starttime)
static

Definition at line 780 of file explain.c.

References INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, and INSTR_TIME_SUBTRACT.

Referenced by ExplainOnePlan(), and IsCheckpointOnSchedule().

781 {
782  instr_time endtime;
783 
784  INSTR_TIME_SET_CURRENT(endtime);
785  INSTR_TIME_SUBTRACT(endtime, *starttime);
786  return INSTR_TIME_GET_DOUBLE(endtime);
787 }
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 3671 of file explain.c.

References escape_json().

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

3672 {
3673  escape_json(buf, str);
3674 }
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 2587 of file explain.c.

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

Referenced by ExplainIndexScanDetails(), and ExplainNode().

2588 {
2589  const char *result;
2590 
2592  result = (*explain_get_index_name_hook) (indexId);
2593  else
2594  result = NULL;
2595  if (result == NULL)
2596  {
2597  /* default behavior: look in the catalogs and quote it */
2598  result = get_rel_name(indexId);
2599  if (result == NULL)
2600  elog(ERROR, "cache lookup failed for index %u", indexId);
2601  result = quote_identifier(result);
2602  }
2603  return result;
2604 }
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10435
#define ERROR
Definition: elog.h:43
explain_get_index_name_hook_type explain_get_index_name_hook
Definition: explain.c:47
#define elog
Definition: elog.h:219
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730

◆ ExplainBeginOutput()

void ExplainBeginOutput ( ExplainState es)

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

3511 {
3512  switch (es->format)
3513  {
3514  case EXPLAIN_FORMAT_TEXT:
3515  /* nothing to do */
3516  break;
3517 
3518  case EXPLAIN_FORMAT_XML:
3520  "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
3521  es->indent++;
3522  break;
3523 
3524  case EXPLAIN_FORMAT_JSON:
3525  /* top-level structure is an array of plans */
3526  appendStringInfoChar(es->str, '[');
3527  es->grouping_stack = lcons_int(0, es->grouping_stack);
3528  es->indent++;
3529  break;
3530 
3531  case EXPLAIN_FORMAT_YAML:
3532  es->grouping_stack = lcons_int(0, es->grouping_stack);
3533  break;
3534  }
3535 }
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 3428 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(), ExplainPrintTriggers(), report_triggers(), show_grouping_set_keys(), show_grouping_sets(), show_modifytable_info(), and show_sort_info().

3430 {
3431  switch (es->format)
3432  {
3433  case EXPLAIN_FORMAT_TEXT:
3434  /* nothing to do */
3435  break;
3436 
3437  case EXPLAIN_FORMAT_XML:
3438  es->indent--;
3439  ExplainXMLTag(objtype, X_CLOSING, es);
3440  break;
3441 
3442  case EXPLAIN_FORMAT_JSON:
3443  es->indent--;
3444  appendStringInfoChar(es->str, '\n');
3445  appendStringInfoSpaces(es->str, 2 * es->indent);
3446  appendStringInfoChar(es->str, labeled ? '}' : ']');
3448  break;
3449 
3450  case EXPLAIN_FORMAT_YAML:
3451  es->indent--;
3453  break;
3454  }
3455 }
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3599
#define X_CLOSING
Definition: explain.c:52
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 3117 of file explain.c.

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

Referenced by ExplainNode().

3118 {
3119  ListCell *cell;
3120  const char *label =
3121  (list_length(css->custom_ps) != 1 ? "children" : "child");
3122 
3123  foreach(cell, css->custom_ps)
3124  ExplainNode((PlanState *) lfirst(cell), ancestors, label, NULL, es);
3125 }
List * custom_ps
Definition: execnodes.h:1603
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:864
static char * label
Definition: pg_basebackup.c:82
#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 3464 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().

3465 {
3466  switch (es->format)
3467  {
3468  case EXPLAIN_FORMAT_TEXT:
3469  /* nothing to do */
3470  break;
3471 
3472  case EXPLAIN_FORMAT_XML:
3473  ExplainXMLTag(objtype, X_CLOSE_IMMEDIATE, es);
3474  break;
3475 
3476  case EXPLAIN_FORMAT_JSON:
3478  appendStringInfoSpaces(es->str, 2 * es->indent);
3479  if (labelname)
3480  {
3481  escape_json(es->str, labelname);
3482  appendStringInfoString(es->str, ": ");
3483  }
3484  escape_json(es->str, objtype);
3485  break;
3486 
3487  case EXPLAIN_FORMAT_YAML:
3489  if (labelname)
3490  {
3491  escape_yaml(es->str, labelname);
3492  appendStringInfoString(es->str, ": ");
3493  }
3494  else
3495  {
3496  appendStringInfoString(es->str, "- ");
3497  }
3498  escape_yaml(es->str, objtype);
3499  break;
3500  }
3501 }
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:3599
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3646
int indent
Definition: explain.h:40
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3671
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3626
ExplainFormat format
Definition: explain.h:38
#define X_CLOSE_IMMEDIATE
Definition: explain.c:53
StringInfo str
Definition: explain.h:30

◆ ExplainEndOutput()

void ExplainEndOutput ( ExplainState es)

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

3542 {
3543  switch (es->format)
3544  {
3545  case EXPLAIN_FORMAT_TEXT:
3546  /* nothing to do */
3547  break;
3548 
3549  case EXPLAIN_FORMAT_XML:
3550  es->indent--;
3551  appendStringInfoString(es->str, "</explain>");
3552  break;
3553 
3554  case EXPLAIN_FORMAT_JSON:
3555  es->indent--;
3556  appendStringInfoString(es->str, "\n]");
3558  break;
3559 
3560  case EXPLAIN_FORMAT_YAML:
3562  break;
3563  }
3564 }
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 2720 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().

2722 {
2723  const char *indexname = explain_get_index_name(indexid);
2724 
2725  if (es->format == EXPLAIN_FORMAT_TEXT)
2726  {
2727  if (ScanDirectionIsBackward(indexorderdir))
2728  appendStringInfoString(es->str, " Backward");
2729  appendStringInfo(es->str, " using %s", indexname);
2730  }
2731  else
2732  {
2733  const char *scandir;
2734 
2735  switch (indexorderdir)
2736  {
2737  case BackwardScanDirection:
2738  scandir = "Backward";
2739  break;
2741  scandir = "NoMovement";
2742  break;
2743  case ForwardScanDirection:
2744  scandir = "Forward";
2745  break;
2746  default:
2747  scandir = "???";
2748  break;
2749  }
2750  ExplainPropertyText("Scan Direction", scandir, es);
2751  ExplainPropertyText("Index Name", indexname, es);
2752  }
2753 }
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3303
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:2587
StringInfo str
Definition: explain.h:30

◆ ExplainJSONLineEnding()

static void ExplainJSONLineEnding ( ExplainState es)
static

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

3627 {
3629  if (linitial_int(es->grouping_stack) != 0)
3630  appendStringInfoChar(es->str, ',');
3631  else
3632  linitial_int(es->grouping_stack) = 1;
3633  appendStringInfoChar(es->str, '\n');
3634 }
#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:688
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30

◆ ExplainMemberNodes()

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

Definition at line 3065 of file explain.c.

References ExplainNode(), and list_length().

Referenced by ExplainNode().

3067 {
3068  int nplans = list_length(plans);
3069  int j;
3070 
3071  for (j = 0; j < nplans; j++)
3072  ExplainNode(planstates[j], ancestors,
3073  "Member", NULL, es);
3074 }
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:864
static int list_length(const List *l)
Definition: pg_list.h:89

◆ ExplainModifyTarget()

static void ExplainModifyTarget ( ModifyTable plan,
ExplainState es 
)
static

Definition at line 2772 of file explain.c.

References ExplainTargetRel().

Referenced by ExplainNode().

2773 {
2774  ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
2775 }
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:2781

◆ ExplainNode()

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

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

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

◆ ExplainOnePlan()

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

Definition at line 462 of file explain.c.

References ExplainState::analyze, appendStringInfo(), Assert, ExplainState::buffers, CMD_UTILITY, CommandCounterIncrement(), PlannedStmt::commandType, CreateIntoRelDestReceiver(), CreateQueryDesc(), generate_unaccent_rules::dest, elapsed_time(), EXEC_FLAG_EXPLAIN_ONLY, ExecutorEnd(), ExecutorFinish(), ExecutorRun(), ExecutorStart(), EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), ExplainOpenGroup(), ExplainPrintPlan(), ExplainPrintTriggers(), ExplainPropertyFloat(), ExplainState::format, 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::str, ExplainState::summary, ExplainState::timing, and UpdateActiveSnapshotCommandId().

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

465 {
467  QueryDesc *queryDesc;
468  instr_time starttime;
469  double totaltime = 0;
470  int eflags;
471  int instrument_option = 0;
472 
473  Assert(plannedstmt->commandType != CMD_UTILITY);
474 
475  if (es->analyze && es->timing)
476  instrument_option |= INSTRUMENT_TIMER;
477  else if (es->analyze)
478  instrument_option |= INSTRUMENT_ROWS;
479 
480  if (es->buffers)
481  instrument_option |= INSTRUMENT_BUFFERS;
482 
483  /*
484  * We always collect timing for the entire statement, even when node-level
485  * timing is off, so we don't look at es->timing here. (We could skip
486  * this if !es->summary, but it's hardly worth the complication.)
487  */
488  INSTR_TIME_SET_CURRENT(starttime);
489 
490  /*
491  * Use a snapshot with an updated command ID to ensure this query sees
492  * results of any previously executed queries.
493  */
496 
497  /*
498  * Normally we discard the query's output, but if explaining CREATE TABLE
499  * AS, we'd better use the appropriate tuple receiver.
500  */
501  if (into)
502  dest = CreateIntoRelDestReceiver(into);
503  else
504  dest = None_Receiver;
505 
506  /* Create a QueryDesc for the query */
507  queryDesc = CreateQueryDesc(plannedstmt, queryString,
509  dest, params, queryEnv, instrument_option);
510 
511  /* Select execution options */
512  if (es->analyze)
513  eflags = 0; /* default run-to-completion flags */
514  else
515  eflags = EXEC_FLAG_EXPLAIN_ONLY;
516  if (into)
517  eflags |= GetIntoRelEFlags(into);
518 
519  /* call ExecutorStart to prepare the plan for execution */
520  ExecutorStart(queryDesc, eflags);
521 
522  /* Execute the plan for statistics if asked for */
523  if (es->analyze)
524  {
525  ScanDirection dir;
526 
527  /* EXPLAIN ANALYZE CREATE TABLE AS WITH NO DATA is weird */
528  if (into && into->skipData)
530  else
531  dir = ForwardScanDirection;
532 
533  /* run the plan */
534  ExecutorRun(queryDesc, dir, 0L, true);
535 
536  /* run cleanup too */
537  ExecutorFinish(queryDesc);
538 
539  /* We can't run ExecutorEnd 'till we're done printing the stats... */
540  totaltime += elapsed_time(&starttime);
541  }
542 
543  ExplainOpenGroup("Query", NULL, true, es);
544 
545  /* Create textual dump of plan tree */
546  ExplainPrintPlan(es, queryDesc);
547 
548  if (es->summary && planduration)
549  {
550  double plantime = INSTR_TIME_GET_DOUBLE(*planduration);
551 
552  if (es->format == EXPLAIN_FORMAT_TEXT)
553  appendStringInfo(es->str, "Planning time: %.3f ms\n",
554  1000.0 * plantime);
555  else
556  ExplainPropertyFloat("Planning Time", 1000.0 * plantime, 3, es);
557  }
558 
559  /* Print info about runtime of triggers */
560  if (es->analyze)
561  ExplainPrintTriggers(es, queryDesc);
562 
563  /*
564  * Close down the query and free resources. Include time for this in the
565  * total execution time (although it should be pretty minimal).
566  */
567  INSTR_TIME_SET_CURRENT(starttime);
568 
569  ExecutorEnd(queryDesc);
570 
571  FreeQueryDesc(queryDesc);
572 
574 
575  /* We need a CCI just in case query expanded to multiple plans */
576  if (es->analyze)
578 
579  totaltime += elapsed_time(&starttime);
580 
581  /*
582  * We only report execution time if we actually ran the query (that is,
583  * the user specified ANALYZE), and if summary reporting is enabled (the
584  * user can set SUMMARY OFF to not have the timing information included in
585  * the output). By default, ANALYZE sets SUMMARY to true.
586  */
587  if (es->summary && es->analyze)
588  {
589  if (es->format == EXPLAIN_FORMAT_TEXT)
590  appendStringInfo(es->str, "Execution time: %.3f ms\n",
591  1000.0 * totaltime);
592  else
593  ExplainPropertyFloat("Execution Time", 1000.0 * totaltime,
594  3, es);
595  }
596 
597  ExplainCloseGroup("Query", NULL, true, es);
598 }
bool summary
Definition: explain.h:37
void UpdateActiveSnapshotCommandId(void)
Definition: snapmgr.c:781
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
struct timeval instr_time
Definition: instr_time.h:147
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3337
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:140
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:115
DestReceiver * None_Receiver
Definition: dest.c:91
bool analyze
Definition: explain.h:33
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:459
int GetIntoRelEFlags(IntoClause *intoClause)
Definition: createas.c:392
void ExplainPrintTriggers(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:649
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
void ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:612
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:297
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:399
bool timing
Definition: explain.h:36
#define InvalidSnapshot
Definition: snapshot.h:25
void CommandCounterIncrement(void)
Definition: xact.c:915
CmdType commandType
Definition: plannodes.h:45
#define Assert(condition)
Definition: c.h:688
ExplainFormat format
Definition: explain.h:38
static double elapsed_time(instr_time *starttime)
Definition: explain.c:780
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153
bool buffers
Definition: explain.h:35
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3428
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3365
StringInfo str
Definition: explain.h:30
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:59

◆ ExplainOneQuery()

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

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

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

◆ ExplainOneUtility()

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

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

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

3367 {
3368  switch (es->format)
3369  {
3370  case EXPLAIN_FORMAT_TEXT:
3371  /* nothing to do */
3372  break;
3373 
3374  case EXPLAIN_FORMAT_XML:
3375  ExplainXMLTag(objtype, X_OPENING, es);
3376  es->indent++;
3377  break;
3378 
3379  case EXPLAIN_FORMAT_JSON:
3381  appendStringInfoSpaces(es->str, 2 * es->indent);
3382  if (labelname)
3383  {
3384  escape_json(es->str, labelname);
3385  appendStringInfoString(es->str, ": ");
3386  }
3387  appendStringInfoChar(es->str, labeled ? '{' : '[');
3388 
3389  /*
3390  * In JSON format, the grouping_stack is an integer list. 0 means
3391  * we've emitted nothing at this grouping level, 1 means we've
3392  * emitted something (and so the next item needs a comma). See
3393  * ExplainJSONLineEnding().
3394  */
3395  es->grouping_stack = lcons_int(0, es->grouping_stack);
3396  es->indent++;
3397  break;
3398 
3399  case EXPLAIN_FORMAT_YAML:
3400 
3401  /*
3402  * In YAML format, the grouping stack is an integer list. 0 means
3403  * we've emitted nothing at this grouping level AND this grouping
3404  * level is unlabelled and must be marked with "- ". See
3405  * ExplainYAMLLineStarting().
3406  */
3408  if (labelname)
3409  {
3410  appendStringInfo(es->str, "%s: ", labelname);
3411  es->grouping_stack = lcons_int(1, es->grouping_stack);
3412  }
3413  else
3414  {
3415  appendStringInfoString(es->str, "- ");
3416  es->grouping_stack = lcons_int(0, es->grouping_stack);
3417  }
3418  es->indent++;
3419  break;
3420  }
3421 }
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:3599
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:3646
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:3626
#define X_OPENING
Definition: explain.c:51
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 799 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().

800 {
801  Plan *plan = planstate->plan;
802 
803  switch (nodeTag(plan))
804  {
805  case T_SeqScan:
806  case T_SampleScan:
807  case T_IndexScan:
808  case T_IndexOnlyScan:
809  case T_BitmapHeapScan:
810  case T_TidScan:
811  case T_SubqueryScan:
812  case T_FunctionScan:
813  case T_TableFuncScan:
814  case T_ValuesScan:
815  case T_CteScan:
817  case T_WorkTableScan:
818  *rels_used = bms_add_member(*rels_used,
819  ((Scan *) plan)->scanrelid);
820  break;
821  case T_ForeignScan:
822  *rels_used = bms_add_members(*rels_used,
823  ((ForeignScan *) plan)->fs_relids);
824  break;
825  case T_CustomScan:
826  *rels_used = bms_add_members(*rels_used,
827  ((CustomScan *) plan)->custom_relids);
828  break;
829  case T_ModifyTable:
830  *rels_used = bms_add_member(*rels_used,
831  ((ModifyTable *) plan)->nominalRelation);
832  if (((ModifyTable *) plan)->exclRelRTI)
833  *rels_used = bms_add_member(*rels_used,
834  ((ModifyTable *) plan)->exclRelRTI);
835  break;
836  default:
837  break;
838  }
839 
840  return planstate_tree_walker(planstate, ExplainPreScanNode, rels_used);
841 }
Plan * plan
Definition: execnodes.h:868
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:742
#define nodeTag(nodeptr)
Definition: nodes.h:518
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
Definition: explain.c:799
bool planstate_tree_walker(PlanState *planstate, bool(*walker)(), void *context)
Definition: nodeFuncs.c:3697
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:799

◆ ExplainPrintPlan()

void ExplainPrintPlan ( ExplainState es,
QueryDesc queryDesc 
)

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

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

◆ ExplainPrintTriggers()

void ExplainPrintTriggers ( ExplainState es,
QueryDesc queryDesc 
)

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

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

◆ ExplainProperty()

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

Definition at line 3253 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(), ExplainPropertyLong(), ExplainPropertyText(), and show_modifytable_info().

3255 {
3256  switch (es->format)
3257  {
3258  case EXPLAIN_FORMAT_TEXT:
3259  appendStringInfoSpaces(es->str, es->indent * 2);
3260  appendStringInfo(es->str, "%s: %s\n", qlabel, value);
3261  break;
3262 
3263  case EXPLAIN_FORMAT_XML:
3264  {
3265  char *str;
3266 
3267  appendStringInfoSpaces(es->str, es->indent * 2);
3268  ExplainXMLTag(qlabel, X_OPENING | X_NOWHITESPACE, es);
3269  str = escape_xml(value);
3270  appendStringInfoString(es->str, str);
3271  pfree(str);
3272  ExplainXMLTag(qlabel, X_CLOSING | X_NOWHITESPACE, es);
3273  appendStringInfoChar(es->str, '\n');
3274  }
3275  break;
3276 
3277  case EXPLAIN_FORMAT_JSON:
3279  appendStringInfoSpaces(es->str, es->indent * 2);
3280  escape_json(es->str, qlabel);
3281  appendStringInfoString(es->str, ": ");
3282  if (numeric)
3284  else
3285  escape_json(es->str, value);
3286  break;
3287 
3288  case EXPLAIN_FORMAT_YAML:
3290  appendStringInfo(es->str, "%s: ", qlabel);
3291  if (numeric)
3293  else
3294  escape_yaml(es->str, value);
3295  break;
3296  }
3297 }
static struct @130 value
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:3599
#define X_CLOSING
Definition: explain.c:52
void pfree(void *pointer)
Definition: mcxt.c:936
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:3646
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:3671
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3626
#define X_OPENING
Definition: explain.c:51
#define X_NOWHITESPACE
Definition: explain.c:54
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 3350 of file explain.c.

References ExplainProperty().

Referenced by ExplainNode().

3351 {
3352  ExplainProperty(qlabel, value ? "true" : "false", true, es);
3353 }
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3253
static struct @130 value

◆ ExplainPropertyFloat()

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

Definition at line 3337 of file explain.c.

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

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

3339 {
3340  char buf[256];
3341 
3342  snprintf(buf, sizeof(buf), "%.*f", ndigits, value);
3343  ExplainProperty(qlabel, buf, true, es);
3344 }
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3253
static struct @130 value
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static char * buf
Definition: pg_test_fsync.c:67

◆ ExplainPropertyInteger()

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

Definition at line 3312 of file explain.c.

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

Referenced by ExplainNode(), and show_sort_info().

3313 {
3314  char buf[32];
3315 
3316  snprintf(buf, sizeof(buf), "%d", value);
3317  ExplainProperty(qlabel, buf, true, es);
3318 }
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3253
static struct @130 value
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static char * buf
Definition: pg_test_fsync.c:67

◆ ExplainPropertyList()

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

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

3133 {
3134  ListCell *lc;
3135  bool first = true;
3136 
3137  switch (es->format)
3138  {
3139  case EXPLAIN_FORMAT_TEXT:
3140  appendStringInfoSpaces(es->str, es->indent * 2);
3141  appendStringInfo(es->str, "%s: ", qlabel);
3142  foreach(lc, data)
3143  {
3144  if (!first)
3145  appendStringInfoString(es->str, ", ");
3146  appendStringInfoString(es->str, (const char *) lfirst(lc));
3147  first = false;
3148  }
3149  appendStringInfoChar(es->str, '\n');
3150  break;
3151 
3152  case EXPLAIN_FORMAT_XML:
3153  ExplainXMLTag(qlabel, X_OPENING, es);
3154  foreach(lc, data)
3155  {
3156  char *str;
3157 
3158  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
3159  appendStringInfoString(es->str, "<Item>");
3160  str = escape_xml((const char *) lfirst(lc));
3161  appendStringInfoString(es->str, str);
3162  pfree(str);
3163  appendStringInfoString(es->str, "</Item>\n");
3164  }
3165  ExplainXMLTag(qlabel, X_CLOSING, es);
3166  break;
3167 
3168  case EXPLAIN_FORMAT_JSON:
3170  appendStringInfoSpaces(es->str, es->indent * 2);
3171  escape_json(es->str, qlabel);
3172  appendStringInfoString(es->str, ": [");
3173  foreach(lc, data)
3174  {
3175  if (!first)
3176  appendStringInfoString(es->str, ", ");
3177  escape_json(es->str, (const char *) lfirst(lc));
3178  first = false;
3179  }
3180  appendStringInfoChar(es->str, ']');
3181  break;
3182 
3183  case EXPLAIN_FORMAT_YAML:
3185  appendStringInfo(es->str, "%s: ", qlabel);
3186  foreach(lc, data)
3187  {
3188  appendStringInfoChar(es->str, '\n');
3189  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
3190  appendStringInfoString(es->str, "- ");
3191  escape_yaml(es->str, (const char *) lfirst(lc));
3192  }
3193  break;
3194  }
3195 }
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:3599
#define X_CLOSING
Definition: explain.c:52
void pfree(void *pointer)
Definition: mcxt.c:936
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:3646
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:3671
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3626
#define X_OPENING
Definition: explain.c:51
#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 3202 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().

3203 {
3204  ListCell *lc;
3205  bool first = true;
3206 
3207  switch (es->format)
3208  {
3209  case EXPLAIN_FORMAT_TEXT:
3210  case EXPLAIN_FORMAT_XML:
3211  ExplainPropertyList(qlabel, data, es);
3212  return;
3213 
3214  case EXPLAIN_FORMAT_JSON:
3216  appendStringInfoSpaces(es->str, es->indent * 2);
3217  appendStringInfoChar(es->str, '[');
3218  foreach(lc, data)
3219  {
3220  if (!first)
3221  appendStringInfoString(es->str, ", ");
3222  escape_json(es->str, (const char *) lfirst(lc));
3223  first = false;
3224  }
3225  appendStringInfoChar(es->str, ']');
3226  break;
3227 
3228  case EXPLAIN_FORMAT_YAML:
3230  appendStringInfoString(es->str, "- [");
3231  foreach(lc, data)
3232  {
3233  if (!first)
3234  appendStringInfoString(es->str, ", ");
3235  escape_yaml(es->str, (const char *) lfirst(lc));
3236  first = false;
3237  }
3238  appendStringInfoChar(es->str, ']');
3239  break;
3240  }
3241 }
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:3646
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:3671
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3626
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:3132
#define lfirst(lc)
Definition: pg_list.h:106
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30

◆ ExplainPropertyLong()

void ExplainPropertyLong ( const char *  qlabel,
long  value,
ExplainState es 
)

Definition at line 3324 of file explain.c.

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

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

3325 {
3326  char buf[32];
3327 
3328  snprintf(buf, sizeof(buf), "%ld", value);
3329  ExplainProperty(qlabel, buf, true, es);
3330 }
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3253
static struct @130 value
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static char * buf
Definition: pg_test_fsync.c:67

◆ ExplainPropertyText()

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

Definition at line 3303 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_sort_info(), and show_tablesample().

3304 {
3305  ExplainProperty(qlabel, value, false, es);
3306 }
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3253
static struct @130 value

◆ ExplainQuery()

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

Definition at line 142 of file explain.c.

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

Referenced by standard_ProcessUtility().

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

◆ ExplainQueryText()

void ExplainQueryText ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 699 of file explain.c.

References ExplainPropertyText(), and QueryDesc::sourceText.

Referenced by explain_ExecutorEnd().

700 {
701  if (queryDesc->sourceText)
702  ExplainPropertyText("Query Text", queryDesc->sourceText, es);
703 }
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3303
const char * sourceText
Definition: execdesc.h:38

◆ ExplainResultDesc()

TupleDesc ExplainResultDesc ( ExplainStmt stmt)

Definition at line 299 of file explain.c.

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

Referenced by ExplainQuery(), and UtilityTupleDescriptor().

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

◆ ExplainScanTarget()

static void ExplainScanTarget ( Scan plan,
ExplainState es 
)
static

Definition at line 2759 of file explain.c.

References ExplainTargetRel().

Referenced by ExplainNode().

2760 {
2761  ExplainTargetRel((Plan *) plan, plan->scanrelid, es);
2762 }
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:2781

◆ ExplainSeparatePlans()

void ExplainSeparatePlans ( ExplainState es)

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

3571 {
3572  switch (es->format)
3573  {
3574  case EXPLAIN_FORMAT_TEXT:
3575  /* add a blank line */
3576  appendStringInfoChar(es->str, '\n');
3577  break;
3578 
3579  case EXPLAIN_FORMAT_XML:
3580  case EXPLAIN_FORMAT_JSON:
3581  case EXPLAIN_FORMAT_YAML:
3582  /* nothing to do */
3583  break;
3584  }
3585 }
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 3083 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().

3085 {
3086  ListCell *lst;
3087 
3088  foreach(lst, plans)
3089  {
3090  SubPlanState *sps = (SubPlanState *) lfirst(lst);
3091  SubPlan *sp = sps->subplan;
3092 
3093  /*
3094  * There can be multiple SubPlan nodes referencing the same physical
3095  * subplan (same plan_id, which is its index in PlannedStmt.subplans).
3096  * We should print a subplan only once, so track which ones we already
3097  * printed. This state must be global across the plan tree, since the
3098  * duplicate nodes could be in different plan nodes, eg both a bitmap
3099  * indexscan's indexqual and its parent heapscan's recheck qual. (We
3100  * do not worry too much about which plan node we show the subplan as
3101  * attached to in such cases.)
3102  */
3103  if (bms_is_member(sp->plan_id, es->printed_subplans))
3104  continue;
3106  sp->plan_id);
3107 
3108  ExplainNode(sps->planstate, ancestors,
3109  relationship, sp->plan_name, es);
3110  }
3111 }
int plan_id
Definition: primnodes.h:689
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:864
struct PlanState * planstate
Definition: execnodes.h:778
SubPlan * subplan
Definition: execnodes.h:777
char * plan_name
Definition: primnodes.h:691
#define lfirst(lc)
Definition: pg_list.h:106
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:742
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:464

◆ ExplainTargetRel()

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

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

2782 {
2783  char *objectname = NULL;
2784  char *namespace = NULL;
2785  const char *objecttag = NULL;
2786  RangeTblEntry *rte;
2787  char *refname;
2788 
2789  rte = rt_fetch(rti, es->rtable);
2790  refname = (char *) list_nth(es->rtable_names, rti - 1);
2791  if (refname == NULL)
2792  refname = rte->eref->aliasname;
2793 
2794  switch (nodeTag(plan))
2795  {
2796  case T_SeqScan:
2797  case T_SampleScan:
2798  case T_IndexScan:
2799  case T_IndexOnlyScan:
2800  case T_BitmapHeapScan:
2801  case T_TidScan:
2802  case T_ForeignScan:
2803  case T_CustomScan:
2804  case T_ModifyTable:
2805  /* Assert it's on a real relation */
2806  Assert(rte->rtekind == RTE_RELATION);
2807  objectname = get_rel_name(rte->relid);
2808  if (es->verbose)
2809  namespace = get_namespace_name(get_rel_namespace(rte->relid));
2810  objecttag = "Relation Name";
2811  break;
2812  case T_FunctionScan:
2813  {
2814  FunctionScan *fscan = (FunctionScan *) plan;
2815 
2816  /* Assert it's on a RangeFunction */
2817  Assert(rte->rtekind == RTE_FUNCTION);
2818 
2819  /*
2820  * If the expression is still a function call of a single
2821  * function, we can get the real name of the function.
2822  * Otherwise, punt. (Even if it was a single function call
2823  * originally, the optimizer could have simplified it away.)
2824  */
2825  if (list_length(fscan->functions) == 1)
2826  {
2827  RangeTblFunction *rtfunc = (RangeTblFunction *) linitial(fscan->functions);
2828 
2829  if (IsA(rtfunc->funcexpr, FuncExpr))
2830  {
2831  FuncExpr *funcexpr = (FuncExpr *) rtfunc->funcexpr;
2832  Oid funcid = funcexpr->funcid;
2833 
2834  objectname = get_func_name(funcid);
2835  if (es->verbose)
2836  namespace =
2838  }
2839  }
2840  objecttag = "Function Name";
2841  }
2842  break;
2843  case T_TableFuncScan:
2844  Assert(rte->rtekind == RTE_TABLEFUNC);
2845  objectname = "xmltable";
2846  objecttag = "Table Function Name";
2847  break;
2848  case T_ValuesScan:
2849  Assert(rte->rtekind == RTE_VALUES);
2850  break;
2851  case T_CteScan:
2852  /* Assert it's on a non-self-reference CTE */
2853  Assert(rte->rtekind == RTE_CTE);
2854  Assert(!rte->self_reference);
2855  objectname = rte->ctename;
2856  objecttag = "CTE Name";
2857  break;
2858  case T_NamedTuplestoreScan:
2860  objectname = rte->enrname;
2861  objecttag = "Tuplestore Name";
2862  break;
2863  case T_WorkTableScan:
2864  /* Assert it's on a self-reference CTE */
2865  Assert(rte->rtekind == RTE_CTE);
2866  Assert(rte->self_reference);
2867  objectname = rte->ctename;
2868  objecttag = "CTE Name";
2869  break;
2870  default:
2871  break;
2872  }
2873 
2874  if (es->format == EXPLAIN_FORMAT_TEXT)
2875  {
2876  appendStringInfoString(es->str, " on");
2877  if (namespace != NULL)
2878  appendStringInfo(es->str, " %s.%s", quote_identifier(namespace),
2879  quote_identifier(objectname));
2880  else if (objectname != NULL)
2881  appendStringInfo(es->str, " %s", quote_identifier(objectname));
2882  if (objectname == NULL || strcmp(refname, objectname) != 0)
2883  appendStringInfo(es->str, " %s", quote_identifier(refname));
2884  }
2885  else
2886  {
2887  if (objecttag != NULL && objectname != NULL)
2888  ExplainPropertyText(objecttag, objectname, es);
2889  if (namespace != NULL)
2890  ExplainPropertyText("Schema", namespace, es);
2891  ExplainPropertyText("Alias", refname, es);
2892  }
2893 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:564
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10435
Oid get_func_namespace(Oid funcid)
Definition: lsyscache.c:1421
List * functions
Definition: plannodes.h:510
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:3303
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
#define linitial(l)
Definition: pg_list.h:111
Oid funcid
Definition: primnodes.h:449
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:1056
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
bool self_reference
Definition: parsenodes.h:1031
bool verbose
Definition: explain.h:32
#define Assert(condition)
Definition: c.h:688
char * aliasname
Definition: primnodes.h:42
static int list_length(const List *l)
Definition: pg_list.h:89
ExplainFormat format
Definition: explain.h:38
#define nodeTag(nodeptr)
Definition: nodes.h:518
RTEKind rtekind
Definition: parsenodes.h:959
char * ctename
Definition: parsenodes.h:1029
Alias * eref
Definition: parsenodes.h:1063
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 3599 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().

3600 {
3601  const char *s;
3602  const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
3603 
3604  if ((flags & X_NOWHITESPACE) == 0)
3605  appendStringInfoSpaces(es->str, 2 * es->indent);
3606  appendStringInfoCharMacro(es->str, '<');
3607  if ((flags & X_CLOSING) != 0)
3608  appendStringInfoCharMacro(es->str, '/');
3609  for (s = tagname; *s; s++)
3610  appendStringInfoChar(es->str, strchr(valid, *s) ? *s : '-');
3611  if ((flags & X_CLOSE_IMMEDIATE) != 0)
3612  appendStringInfoString(es->str, " /");
3613  appendStringInfoCharMacro(es->str, '>');
3614  if ((flags & X_NOWHITESPACE) == 0)
3615  appendStringInfoCharMacro(es->str, '\n');
3616 }
#define X_CLOSING
Definition: explain.c:52
#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:54
#define X_CLOSE_IMMEDIATE
Definition: explain.c:53
StringInfo str
Definition: explain.h:30

◆ ExplainYAMLLineStarting()

static void ExplainYAMLLineStarting ( ExplainState es)
static

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

3647 {
3649  if (linitial_int(es->grouping_stack) == 0)
3650  {
3651  linitial_int(es->grouping_stack) = 1;
3652  }
3653  else
3654  {
3655  appendStringInfoChar(es->str, '\n');
3656  appendStringInfoSpaces(es->str, es->indent * 2);
3657  }
3658 }
#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:688
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30

◆ NewExplainState()

ExplainState* NewExplainState ( void  )

Definition at line 282 of file explain.c.

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

Referenced by explain_ExecutorEnd(), and ExplainQuery().

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

◆ report_triggers()

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

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

711 {
712  int nt;
713 
714  if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
715  return;
716  for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
717  {
718  Trigger *trig = rInfo->ri_TrigDesc->triggers + nt;
719  Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
720  char *relname;
721  char *conname = NULL;
722 
723  /* Must clean up instrumentation state */
724  InstrEndLoop(instr);
725 
726  /*
727  * We ignore triggers that were never invoked; they likely aren't
728  * relevant to the current query type.
729  */
730  if (instr->ntuples == 0)
731  continue;
732 
733  ExplainOpenGroup("Trigger", NULL, true, es);
734 
735  relname = RelationGetRelationName(rInfo->ri_RelationDesc);
736  if (OidIsValid(trig->tgconstraint))
737  conname = get_constraint_name(trig->tgconstraint);
738 
739  /*
740  * In text format, we avoid printing both the trigger name and the
741  * constraint name unless VERBOSE is specified. In non-text formats
742  * we just print everything.
743  */
744  if (es->format == EXPLAIN_FORMAT_TEXT)
745  {
746  if (es->verbose || conname == NULL)
747  appendStringInfo(es->str, "Trigger %s", trig->tgname);
748  else
749  appendStringInfoString(es->str, "Trigger");
750  if (conname)
751  appendStringInfo(es->str, " for constraint %s", conname);
752  if (show_relname)
753  appendStringInfo(es->str, " on %s", relname);
754  if (es->timing)
755  appendStringInfo(es->str, ": time=%.3f calls=%.0f\n",
756  1000.0 * instr->total, instr->ntuples);
757  else
758  appendStringInfo(es->str, ": calls=%.0f\n", instr->ntuples);
759  }
760  else
761  {
762  ExplainPropertyText("Trigger Name", trig->tgname, es);
763  if (conname)
764  ExplainPropertyText("Constraint Name", conname, es);
765  ExplainPropertyText("Relation", relname, es);
766  if (es->timing)
767  ExplainPropertyFloat("Time", 1000.0 * instr->total, 3, es);
768  ExplainPropertyFloat("Calls", instr->ntuples, 0, es);
769  }
770 
771  if (conname)
772  pfree(conname);
773 
774  ExplainCloseGroup("Trigger", NULL, true, es);
775  }
776 }
Relation ri_RelationDesc
Definition: execnodes.h:368
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:982
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3337
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:389
#define OidIsValid(objectId)
Definition: c.h:594
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:114
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3303
void pfree(void *pointer)
Definition: mcxt.c:936
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:445
double ntuples
Definition: instrument.h:59
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:380
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:3428
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3365
StringInfo str
Definition: explain.h:30

◆ show_agg_keys()

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

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

1972 {
1973  Agg *plan = (Agg *) astate->ss.ps.plan;
1974 
1975  if (plan->numCols > 0 || plan->groupingSets)
1976  {
1977  /* The key columns refer to the tlist of the child plan */
1978  ancestors = lcons(astate, ancestors);
1979 
1980  if (plan->groupingSets)
1981  show_grouping_sets(outerPlanState(astate), plan, ancestors, es);
1982  else
1983  show_sort_group_keys(outerPlanState(astate), "Group Key",
1984  plan->numCols, plan->grpColIdx,
1985  NULL, NULL, NULL,
1986  ancestors, es);
1987 
1988  ancestors = list_delete_first(ancestors);
1989  }
1990 }
int numCols
Definition: plannodes.h:787
AttrNumber * grpColIdx
Definition: plannodes.h:788
ScanState ss
Definition: execnodes.h:1827
PlanState ps
Definition: execnodes.h:1124
#define outerPlanState(node)
Definition: execnodes.h:914
static void show_grouping_sets(PlanState *planstate, Agg *agg, List *ancestors, ExplainState *es)
Definition: explain.c:1993
List * groupingSets
Definition: plannodes.h:793
Plan * plan
Definition: execnodes.h:868
List * lcons(void *datum, List *list)
Definition: list.c:259
Definition: plannodes.h:782
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:2122
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 2610 of file explain.c.

References appendStringInfo(), appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), BufferUsage::blk_read_time, BufferUsage::blk_write_time, EXPLAIN_FORMAT_TEXT, ExplainPropertyFloat(), ExplainPropertyLong(), 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().

2611 {
2612  if (es->format == EXPLAIN_FORMAT_TEXT)
2613  {
2614  bool has_shared = (usage->shared_blks_hit > 0 ||
2615  usage->shared_blks_read > 0 ||
2616  usage->shared_blks_dirtied > 0 ||
2617  usage->shared_blks_written > 0);
2618  bool has_local = (usage->local_blks_hit > 0 ||
2619  usage->local_blks_read > 0 ||
2620  usage->local_blks_dirtied > 0 ||
2621  usage->local_blks_written > 0);
2622  bool has_temp = (usage->temp_blks_read > 0 ||
2623  usage->temp_blks_written > 0);
2624  bool has_timing = (!INSTR_TIME_IS_ZERO(usage->blk_read_time) ||
2626 
2627  /* Show only positive counter values. */
2628  if (has_shared || has_local || has_temp)
2629  {
2630  appendStringInfoSpaces(es->str, es->indent * 2);
2631  appendStringInfoString(es->str, "Buffers:");
2632 
2633  if (has_shared)
2634  {
2635  appendStringInfoString(es->str, " shared");
2636  if (usage->shared_blks_hit > 0)
2637  appendStringInfo(es->str, " hit=%ld",
2638  usage->shared_blks_hit);
2639  if (usage->shared_blks_read > 0)
2640  appendStringInfo(es->str, " read=%ld",
2641  usage->shared_blks_read);
2642  if (usage->shared_blks_dirtied > 0)
2643  appendStringInfo(es->str, " dirtied=%ld",
2644  usage->shared_blks_dirtied);
2645  if (usage->shared_blks_written > 0)
2646  appendStringInfo(es->str, " written=%ld",
2647  usage->shared_blks_written);
2648  if (has_local || has_temp)
2649  appendStringInfoChar(es->str, ',');
2650  }
2651  if (has_local)
2652  {
2653  appendStringInfoString(es->str, " local");
2654  if (usage->local_blks_hit > 0)
2655  appendStringInfo(es->str, " hit=%ld",
2656  usage->local_blks_hit);
2657  if (usage->local_blks_read > 0)
2658  appendStringInfo(es->str, " read=%ld",
2659  usage->local_blks_read);
2660  if (usage->local_blks_dirtied > 0)
2661  appendStringInfo(es->str, " dirtied=%ld",
2662  usage->local_blks_dirtied);
2663  if (usage->local_blks_written > 0)
2664  appendStringInfo(es->str, " written=%ld",
2665  usage->local_blks_written);
2666  if (has_temp)
2667  appendStringInfoChar(es->str, ',');
2668  }
2669  if (has_temp)
2670  {
2671  appendStringInfoString(es->str, " temp");
2672  if (usage->temp_blks_read > 0)
2673  appendStringInfo(es->str, " read=%ld",
2674  usage->temp_blks_read);
2675  if (usage->temp_blks_written > 0)
2676  appendStringInfo(es->str, " written=%ld",
2677  usage->temp_blks_written);
2678  }
2679  appendStringInfoChar(es->str, '\n');
2680  }
2681 
2682  /* As above, show only positive counter values. */
2683  if (has_timing)
2684  {
2685  appendStringInfoSpaces(es->str, es->indent * 2);
2686  appendStringInfoString(es->str, "I/O Timings:");
2687  if (!INSTR_TIME_IS_ZERO(usage->blk_read_time))
2688  appendStringInfo(es->str, " read=%0.3f",
2690  if (!INSTR_TIME_IS_ZERO(usage->blk_write_time))
2691  appendStringInfo(es->str, " write=%0.3f",
2693  appendStringInfoChar(es->str, '\n');
2694  }
2695  }
2696  else
2697  {
2698  ExplainPropertyLong("Shared Hit Blocks", usage->shared_blks_hit, es);
2699  ExplainPropertyLong("Shared Read Blocks", usage->shared_blks_read, es);
2700  ExplainPropertyLong("Shared Dirtied Blocks", usage->shared_blks_dirtied, es);
2701  ExplainPropertyLong("Shared Written Blocks", usage->shared_blks_written, es);
2702  ExplainPropertyLong("Local Hit Blocks", usage->local_blks_hit, es);
2703  ExplainPropertyLong("Local Read Blocks", usage->local_blks_read, es);
2704  ExplainPropertyLong("Local Dirtied Blocks", usage->local_blks_dirtied, es);
2705  ExplainPropertyLong("Local Written Blocks", usage->local_blks_written, es);
2706  ExplainPropertyLong("Temp Read Blocks", usage->temp_blks_read, es);
2707  ExplainPropertyLong("Temp Written Blocks", usage->temp_blks_written, es);
2708  if (track_io_timing)
2709  {
2710  ExplainPropertyFloat("I/O Read Time", INSTR_TIME_GET_MILLISEC(usage->blk_read_time), 3, es);
2711  ExplainPropertyFloat("I/O Write Time", INSTR_TIME_GET_MILLISEC(usage->blk_write_time), 3, es);
2712  }
2713  }
2714 }
long local_blks_hit
Definition: instrument.h:25
long local_blks_dirtied
Definition: instrument.h:27
long local_blks_read
Definition: instrument.h:26
instr_time blk_read_time
Definition: instrument.h:31
void ExplainPropertyLong(const char *qlabel, long value, ExplainState *es)
Definition: explain.c:3324
#define INSTR_TIME_GET_MILLISEC(t)
Definition: instr_time.h:199
long shared_blks_read
Definition: instrument.h:22
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3337
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 2561 of file explain.c.

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

Referenced by ExplainNode().

2562 {
2563  int paramid = -1;
2564  List *params = NIL;
2565 
2566  Assert(bms_params);
2567 
2568  while ((paramid = bms_next_member(bms_params, paramid)) >= 0)
2569  {
2570  char param[32];
2571 
2572  snprintf(param, sizeof(param), "$%d", paramid);
2573  params = lappend(params, pstrdup(param));
2574  }
2575 
2576  if (params)
2577  ExplainPropertyList("Params Evaluated", params, es);
2578 }
#define NIL
Definition: pg_list.h:69
char * pstrdup(const char *in)
Definition: mcxt.c:1063
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1053
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:3132
#define Assert(condition)
Definition: c.h:688
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 1867 of file explain.c.

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

Referenced by ExplainNode(), and show_qual().

1870 {
1871  List *context;
1872  char *exprstr;
1873 
1874  /* Set up deparsing context */
1876  (Node *) planstate,
1877  ancestors);
1878 
1879  /* Deparse the expression */
1880  exprstr = deparse_expression(node, context, useprefix, false);
1881 
1882  /* And add to es->str */
1883  ExplainPropertyText(qlabel, exprstr, es);
1884 }
Definition: nodes.h:513
List * deparse_cxt
Definition: explain.h:46
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3303
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:3173
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:3021
Definition: pg_list.h:45

◆ show_foreignscan_info()

static void show_foreignscan_info ( ForeignScanState fsstate,
ExplainState es 
)
static

Definition at line 2540 of file explain.c.

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

Referenced by ExplainNode().

2541 {
2542  FdwRoutine *fdwroutine = fsstate->fdwroutine;
2543 
2544  /* Let the FDW emit whatever fields it wants */
2545  if (((ForeignScan *) fsstate->ss.ps.plan)->operation != CMD_SELECT)
2546  {
2547  if (fdwroutine->ExplainDirectModify != NULL)
2548  fdwroutine->ExplainDirectModify(fsstate, es);
2549  }
2550  else
2551  {
2552  if (fdwroutine->ExplainForeignScan != NULL)
2553  fdwroutine->ExplainForeignScan(fsstate, es);
2554  }
2555 }
ScanState ss
Definition: execnodes.h:1575
ExplainForeignScan_function ExplainForeignScan
Definition: fdwapi.h:219
PlanState ps
Definition: execnodes.h:1124
ExplainDirectModify_function ExplainDirectModify
Definition: fdwapi.h:221
struct FdwRoutine * fdwroutine
Definition: execnodes.h:1579
Plan * plan
Definition: execnodes.h:868

◆ show_group_keys()

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

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

2104 {
2105  Group *plan = (Group *) gstate->ss.ps.plan;
2106 
2107  /* The key columns refer to the tlist of the child plan */
2108  ancestors = lcons(gstate, ancestors);
2109  show_sort_group_keys(outerPlanState(gstate), "Group Key",
2110  plan->numCols, plan->grpColIdx,
2111  NULL, NULL, NULL,
2112  ancestors, es);
2113  ancestors = list_delete_first(ancestors);
2114 }
ScanState ss
Definition: execnodes.h:1801
PlanState ps
Definition: execnodes.h:1124
#define outerPlanState(node)
Definition: execnodes.h:914
int numCols
Definition: plannodes.h:763
Plan * plan
Definition: execnodes.h:868
List * lcons(void *datum, List *list)
Definition: list.c:259
AttrNumber * grpColIdx
Definition: plannodes.h:764
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:2122
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 2024 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().

2028 {
2029  Plan *plan = planstate->plan;
2030  char *exprstr;
2031  ListCell *lc;
2032  List *gsets = aggnode->groupingSets;
2033  AttrNumber *keycols = aggnode->grpColIdx;
2034  const char *keyname;
2035  const char *keysetname;
2036 
2037  if (aggnode->aggstrategy == AGG_HASHED || aggnode->aggstrategy == AGG_MIXED)
2038  {
2039  keyname = "Hash Key";
2040  keysetname = "Hash Keys";
2041  }
2042  else
2043  {
2044  keyname = "Group Key";
2045  keysetname = "Group Keys";
2046  }
2047 
2048  ExplainOpenGroup("Grouping Set", NULL, true, es);
2049 
2050  if (sortnode)
2051  {
2052  show_sort_group_keys(planstate, "Sort Key",
2053  sortnode->numCols, sortnode->sortColIdx,
2054  sortnode->sortOperators, sortnode->collations,
2055  sortnode->nullsFirst,
2056  ancestors, es);
2057  if (es->format == EXPLAIN_FORMAT_TEXT)
2058  es->indent++;
2059  }
2060 
2061  ExplainOpenGroup(keysetname, keysetname, false, es);
2062 
2063  foreach(lc, gsets)
2064  {
2065  List *result = NIL;
2066  ListCell *lc2;
2067 
2068  foreach(lc2, (List *) lfirst(lc))
2069  {
2070  Index i = lfirst_int(lc2);
2071  AttrNumber keyresno = keycols[i];
2072  TargetEntry *target = get_tle_by_resno(plan->targetlist,
2073  keyresno);
2074 
2075  if (!target)
2076  elog(ERROR, "no tlist entry for key %d", keyresno);
2077  /* Deparse the expression, showing any top-level cast */
2078  exprstr = deparse_expression((Node *) target->expr, context,
2079  useprefix, true);
2080 
2081  result = lappend(result, exprstr);
2082  }
2083 
2084  if (!result && es->format == EXPLAIN_FORMAT_TEXT)
2085  ExplainPropertyText(keyname, "()", es);
2086  else
2087  ExplainPropertyListNested(keyname, result, es);
2088  }
2089 
2090  ExplainCloseGroup(keysetname, keysetname, false, es);
2091 
2092  if (sortnode && es->format == EXPLAIN_FORMAT_TEXT)
2093  es->indent--;
2094 
2095  ExplainCloseGroup("Grouping Set", NULL, true, es);
2096 }
#define NIL
Definition: pg_list.h:69
AttrNumber * grpColIdx
Definition: plannodes.h:788
Definition: nodes.h:513
bool * nullsFirst
Definition: plannodes.h:751
Oid * sortOperators
Definition: plannodes.h:749
void ExplainPropertyListNested(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:3202
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3303
AggStrategy aggstrategy
Definition: plannodes.h:785
#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:747
List * groupingSets
Definition: plannodes.h:793
unsigned int Index
Definition: c.h:431
Plan * plan
Definition: execnodes.h:868
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1375
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:3021
ExplainFormat format
Definition: explain.h:38
List * targetlist
Definition: plannodes.h:144
AttrNumber * sortColIdx
Definition: plannodes.h:748
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:3428
#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:2122
Oid * collations
Definition: plannodes.h:750
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3365
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 1993 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().

1995 {
1996  List *context;
1997  bool useprefix;
1998  ListCell *lc;
1999 
2000  /* Set up deparsing context */
2002  (Node *) planstate,
2003  ancestors);
2004  useprefix = (list_length(es->rtable) > 1 || es->verbose);
2005 
2006  ExplainOpenGroup("Grouping Sets", "Grouping Sets", false, es);
2007 
2008  show_grouping_set_keys(planstate, agg, NULL,
2009  context, useprefix, ancestors, es);
2010 
2011  foreach(lc, agg->chain)
2012  {
2013  Agg *aggnode = lfirst(lc);
2014  Sort *sortnode = (Sort *) aggnode->plan.lefttree;
2015 
2016  show_grouping_set_keys(planstate, aggnode, sortnode,
2017  context, useprefix, ancestors, es);
2018  }
2019 
2020  ExplainCloseGroup("Grouping Sets", "Grouping Sets", false, es);
2021 }
Definition: nodes.h:513
List * deparse_cxt
Definition: explain.h:46
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:3173
Plan plan
Definition: plannodes.h:784
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:146
static void show_grouping_set_keys(PlanState *planstate, Agg *aggnode, Sort *sortnode, List *context, bool useprefix, List *ancestors, ExplainState *es)
Definition: explain.c:2024
List * chain
Definition: plannodes.h:794
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3428
Definition: plannodes.h:782
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3365
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 2383 of file explain.c.

References appendStringInfo(), appendStringInfoSpaces(), ExecHashGetInstrumentation(), EXPLAIN_FORMAT_TEXT, ExplainPropertyLong(), 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().

2384 {
2385  HashInstrumentation hinstrument = {0};
2386 
2387  /*
2388  * In a parallel query, the leader process may or may not have run the
2389  * hash join, and even if it did it may not have built a hash table due to
2390  * timing (if it started late it might have seen no tuples in the outer
2391  * relation and skipped building the hash table). Therefore we have to be
2392  * prepared to get instrumentation data from all participants.
2393  */
2394  if (hashstate->hashtable)
2395  ExecHashGetInstrumentation(&hinstrument, hashstate->hashtable);
2396 
2397  /*
2398  * Merge results from workers. In the parallel-oblivious case, the
2399  * results from all participants should be identical, except where
2400  * participants didn't run the join at all so have no data. In the
2401  * parallel-aware case, we need to consider all the results. Each worker
2402  * may have seen a different subset of batches and we want to find the
2403  * highest memory usage for any one batch across all batches.
2404  */
2405  if (hashstate->shared_info)
2406  {
2407  SharedHashInfo *shared_info = hashstate->shared_info;
2408  int i;
2409 
2410  for (i = 0; i < shared_info->num_workers; ++i)
2411  {
2412  HashInstrumentation *worker_hi = &shared_info->hinstrument[i];
2413 
2414  if (worker_hi->nbatch > 0)
2415  {
2416  /*
2417  * Every participant should agree on the buckets, so to be
2418  * sure we have a value we'll just overwrite each time.
2419  */
2420  hinstrument.nbuckets = worker_hi->nbuckets;
2421  hinstrument.nbuckets_original = worker_hi->nbuckets_original;
2422 
2423  /*
2424  * Normally every participant should agree on the number of
2425  * batches too, but it's possible for a backend that started
2426  * late and missed the whole join not to have the final nbatch
2427  * number. So we'll take the largest number.
2428  */
2429  hinstrument.nbatch = Max(hinstrument.nbatch, worker_hi->nbatch);
2430  hinstrument.nbatch_original = worker_hi->nbatch_original;
2431 
2432  /*
2433  * In a parallel-aware hash join, for now we report the
2434  * maximum peak memory reported by any worker.
2435  */
2436  hinstrument.space_peak =
2437  Max(hinstrument.space_peak, worker_hi->space_peak);
2438  }
2439  }
2440  }
2441 
2442  if (hinstrument.nbatch > 0)
2443  {
2444  long spacePeakKb = (hinstrument.space_peak + 1023) / 1024;
2445 
2446  if (es->format != EXPLAIN_FORMAT_TEXT)
2447  {
2448  ExplainPropertyLong("Hash Buckets", hinstrument.nbuckets, es);
2449  ExplainPropertyLong("Original Hash Buckets",
2450  hinstrument.nbuckets_original, es);
2451  ExplainPropertyLong("Hash Batches", hinstrument.nbatch, es);
2452  ExplainPropertyLong("Original Hash Batches",
2453  hinstrument.nbatch_original, es);
2454  ExplainPropertyLong("Peak Memory Usage", spacePeakKb, es);
2455  }
2456  else if (hinstrument.nbatch_original != hinstrument.nbatch ||
2457  hinstrument.nbuckets_original != hinstrument.nbuckets)
2458  {
2459  appendStringInfoSpaces(es->str, es->indent * 2);
2460  appendStringInfo(es->str,
2461  "Buckets: %d (originally %d) Batches: %d (originally %d) Memory Usage: %ldkB\n",
2462  hinstrument.nbuckets,
2463  hinstrument.nbuckets_original,
2464  hinstrument.nbatch,
2465  hinstrument.nbatch_original,
2466  spacePeakKb);
2467  }
2468  else
2469  {
2470  appendStringInfoSpaces(es->str, es->indent * 2);
2471  appendStringInfo(es->str,
2472  "Buckets: %d Batches: %d Memory Usage: %ldkB\n",
2473  hinstrument.nbuckets, hinstrument.nbatch,
2474  spacePeakKb);
2475  }
2476  }
2477 }
void ExecHashGetInstrumentation(HashInstrumentation *instrument, HashJoinTable hashtable)
Definition: nodeHash.c:2635
void ExplainPropertyLong(const char *qlabel, long value, ExplainState *es)
Definition: explain.c:3324
HashJoinTable hashtable
Definition: execnodes.h:2059
SharedHashInfo * shared_info
Definition: execnodes.h:2063
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:2049
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
#define Max(x, y)
Definition: c.h:840
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 2511 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().

2513 {
2514  double nfiltered;
2515  double nloops;
2516 
2517  if (!es->analyze || !planstate->instrument)
2518  return;
2519 
2520  if (which == 2)
2521  nfiltered = planstate->instrument->nfiltered2;
2522  else
2523  nfiltered = planstate->instrument->nfiltered1;
2524  nloops = planstate->instrument->nloops;
2525 
2526  /* In text mode, suppress zero counts; they're not interesting enough */
2527  if (nfiltered > 0 || es->format != EXPLAIN_FORMAT_TEXT)
2528  {
2529  if (nloops > 0)
2530  ExplainPropertyFloat(qlabel, nfiltered / nloops, 0, es);
2531  else
2532  ExplainPropertyFloat(qlabel, 0.0, 0, es);
2533  }
2534 }
double nfiltered1
Definition: instrument.h:61
Instrumentation * instrument
Definition: execnodes.h:878
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3337
bool analyze
Definition: explain.h:33
double nfiltered2
Definition: instrument.h:62
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 1954 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().

1956 {
1957  MergeAppend *plan = (MergeAppend *) mstate->ps.plan;
1958 
1959  show_sort_group_keys((PlanState *) mstate, "Sort Key",
1960  plan->numCols, plan->sortColIdx,
1961  plan->sortOperators, plan->collations,
1962  plan->nullsFirst,
1963  ancestors, es);
1964 }
Oid * collations
Definition: plannodes.h:270
Plan * plan
Definition: execnodes.h:868
PlanState ps
Definition: execnodes.h:1045
AttrNumber * sortColIdx
Definition: plannodes.h:268
bool * nullsFirst
Definition: plannodes.h:271
Oid * sortOperators
Definition: plannodes.h:269
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:2122

◆ show_modifytable_info()

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

Definition at line 2904 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(), ExplainProperty(), ExplainPropertyFloat(), ExplainPropertyList(), ExplainTargetRel(), ModifyTable::fdwPrivLists, ExplainState::format, get_rel_name(), ExplainState::indent, InstrEndLoop(), PlanState::instrument, lappend(), lfirst_oid, list_nth(), ModifyTableState::mt_nplans, ModifyTableState::mt_plans, Instrumentation::nfiltered2, NIL, ModifyTable::nominalRelation, Instrumentation::ntuples, 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().

2906 {
2907  ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
2908  const char *operation;
2909  const char *foperation;
2910  bool labeltargets;
2911  int j;
2912  List *idxNames = NIL;
2913  ListCell *lst;
2914 
2915  switch (node->operation)
2916  {
2917  case CMD_INSERT:
2918  operation = "Insert";
2919  foperation = "Foreign Insert";
2920  break;
2921  case CMD_UPDATE:
2922  operation = "Update";
2923  foperation = "Foreign Update";
2924  break;
2925  case CMD_DELETE:
2926  operation = "Delete";
2927  foperation = "Foreign Delete";
2928  break;
2929  default:
2930  operation = "???";
2931  foperation = "Foreign ???";
2932  break;
2933  }
2934 
2935  /* Should we explicitly label target relations? */
2936  labeltargets = (mtstate->mt_nplans > 1 ||
2937  (mtstate->mt_nplans == 1 &&
2938  mtstate->resultRelInfo->ri_RangeTableIndex != node->nominalRelation));
2939 
2940  if (labeltargets)
2941  ExplainOpenGroup("Target Tables", "Target Tables", false, es);
2942 
2943  for (j = 0; j < mtstate->mt_nplans; j++)
2944  {
2945  ResultRelInfo *resultRelInfo = mtstate->resultRelInfo + j;
2946  FdwRoutine *fdwroutine = resultRelInfo->ri_FdwRoutine;
2947 
2948  if (labeltargets)
2949  {
2950  /* Open a group for this target */
2951  ExplainOpenGroup("Target Table", NULL, true, es);
2952 
2953  /*
2954  * In text mode, decorate each target with operation type, so that
2955  * ExplainTargetRel's output of " on foo" will read nicely.
2956  */
2957  if (es->format == EXPLAIN_FORMAT_TEXT)
2958  {
2959  appendStringInfoSpaces(es->str, es->indent * 2);
2961  fdwroutine ? foperation : operation);
2962  }
2963 
2964  /* Identify target */
2965  ExplainTargetRel((Plan *) node,
2966  resultRelInfo->ri_RangeTableIndex,
2967  es);
2968 
2969  if (es->format == EXPLAIN_FORMAT_TEXT)
2970  {
2971  appendStringInfoChar(es->str, '\n');
2972  es->indent++;
2973  }
2974  }
2975 
2976  /* Give FDW a chance if needed */
2977  if (!resultRelInfo->ri_usesFdwDirectModify &&
2978  fdwroutine != NULL &&
2979  fdwroutine->ExplainForeignModify != NULL)
2980  {
2981  List *fdw_private = (List *) list_nth(node->fdwPrivLists, j);
2982 
2983  fdwroutine->ExplainForeignModify(mtstate,
2984  resultRelInfo,
2985  fdw_private,
2986  j,
2987  es);
2988  }
2989 
2990  if (labeltargets)
2991  {
2992  /* Undo the indentation we added in text format */
2993  if (es->format == EXPLAIN_FORMAT_TEXT)
2994  es->indent--;
2995 
2996  /* Close the group */
2997  ExplainCloseGroup("Target Table", NULL, true, es);
2998  }
2999  }
3000 
3001  /* Gather names of ON CONFLICT arbiter indexes */
3002  foreach(lst, node->arbiterIndexes)
3003  {
3004  char *indexname = get_rel_name(lfirst_oid(lst));
3005 
3006  idxNames = lappend(idxNames, indexname);
3007  }
3008 
3009  if (node->onConflictAction != ONCONFLICT_NONE)
3010  {
3011  ExplainProperty("Conflict Resolution",
3013  "NOTHING" : "UPDATE",
3014  false, es);
3015 
3016  /*
3017  * Don't display arbiter indexes at all when DO NOTHING variant
3018  * implicitly ignores all conflicts
3019  */
3020  if (idxNames)
3021  ExplainPropertyList("Conflict Arbiter Indexes", idxNames, es);
3022 
3023  /* ON CONFLICT DO UPDATE WHERE qual is specially displayed */
3024  if (node->onConflictWhere)
3025  {
3026  show_upper_qual((List *) node->onConflictWhere, "Conflict Filter",
3027  &mtstate->ps, ancestors, es);
3028  show_instrumentation_count("Rows Removed by Conflict Filter", 1, &mtstate->ps, es);
3029  }
3030 
3031  /* EXPLAIN ANALYZE display of actual outcome for each tuple proposed */
3032  if (es->analyze && mtstate->ps.instrument)
3033  {
3034  double total;
3035  double insert_path;
3036  double other_path;
3037 
3038  InstrEndLoop(mtstate->mt_plans[0]->instrument);
3039 
3040  /* count the number of source rows */
3041  total = mtstate->mt_plans[0]->instrument->ntuples;
3042  other_path = mtstate->ps.instrument->nfiltered2;
3043  insert_path = total - other_path;
3044 
3045  ExplainPropertyFloat("Tuples Inserted", insert_path, 0, es);
3046  ExplainPropertyFloat("Conflicting Tuples", other_path, 0, es);
3047  }
3048  }
3049 
3050  if (labeltargets)
3051  ExplainCloseGroup("Target Tables", "Target Tables", false, es);
3052 }
#define NIL
Definition: pg_list.h:69
List * arbiterIndexes
Definition: plannodes.h:234
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3253
Index nominalRelation
Definition: plannodes.h:219
Instrumentation * instrument
Definition: execnodes.h:878
ResultRelInfo * resultRelInfo
Definition: execnodes.h:986
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3337
bool analyze
Definition: explain.h:33
static void show_upper_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
Definition: explain.c:1925
Index ri_RangeTableIndex
Definition: execnodes.h:365
static void show_instrumentation_count(const char *qlabel, int which, PlanState *planstate, ExplainState *es)
Definition: explain.c:2511
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:114
PlanState ps
Definition: execnodes.h:979
double nfiltered2
Definition: instrument.h:62
bool ri_usesFdwDirectModify
Definition: execnodes.h:398
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
void * list_nth(const List *list, int n)
Definition: list.c:410
List * fdwPrivLists
Definition: plannodes.h:229
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:392
double ntuples
Definition: instrument.h:59
int indent
Definition: explain.h:40
List * lappend(List *list, void *datum)
Definition: list.c:128
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
PlanState ** mt_plans
Definition: execnodes.h:983
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:2781
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
Plan * plan
Definition: execnodes.h:868
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:3132
OnConflictAction onConflictAction
Definition: plannodes.h:233
ExplainFormat format
Definition: explain.h:38
CmdType operation
Definition: plannodes.h:217
ExplainForeignModify_function ExplainForeignModify
Definition: fdwapi.h:220
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3428
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3365
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
StringInfo str
Definition: explain.h:30
#define lfirst_oid(lc)
Definition: pg_list.h:108
Node * onConflictWhere
Definition: plannodes.h:236

◆ show_plan_tlist()

<