PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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/hashjoin.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)
 
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 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 ExplainOpenGroup (const char *objtype, const char *labelname, bool labeled, ExplainState *es)
 
static void ExplainCloseGroup (const char *objtype, const char *labelname, bool labeled, 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, DestReceiver *dest)
 
ExplainStateNewExplainState (void)
 
TupleDesc ExplainResultDesc (ExplainStmt *stmt)
 
void ExplainOneUtility (Node *utilityStmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params)
 
void ExplainOnePlan (PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, 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 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

#define X_CLOSE_IMMEDIATE   2

Definition at line 53 of file explain.c.

Referenced by ExplainDummyGroup(), and ExplainXMLTag().

#define X_CLOSING   1

Definition at line 52 of file explain.c.

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

#define X_NOWHITESPACE   4

Definition at line 54 of file explain.c.

Referenced by ExplainProperty(), and ExplainXMLTag().

#define X_OPENING   0

Definition at line 51 of file explain.c.

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

Function Documentation

static double elapsed_time ( instr_time starttime)
static

Definition at line 763 of file explain.c.

References INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, and INSTR_TIME_SUBTRACT.

Referenced by ExplainOnePlan(), and IsCheckpointOnSchedule().

764 {
765  instr_time endtime;
766 
767  INSTR_TIME_SET_CURRENT(endtime);
768  INSTR_TIME_SUBTRACT(endtime, *starttime);
769  return INSTR_TIME_GET_DOUBLE(endtime);
770 }
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
static void escape_yaml ( StringInfo  buf,
const char *  str 
)
static

Definition at line 3473 of file explain.c.

References escape_json().

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

3474 {
3475  escape_json(buf, str);
3476 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2433
static const char * explain_get_index_name ( Oid  indexId)
static

Definition at line 2394 of file explain.c.

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

Referenced by ExplainIndexScanDetails(), and ExplainNode().

2395 {
2396  const char *result;
2397 
2399  result = (*explain_get_index_name_hook) (indexId);
2400  else
2401  result = NULL;
2402  if (result == NULL)
2403  {
2404  /* default behavior: look in the catalogs and quote it */
2405  result = get_rel_name(indexId);
2406  if (result == NULL)
2407  elog(ERROR, "cache lookup failed for index %u", indexId);
2408  result = quote_identifier(result);
2409  }
2410  return result;
2411 }
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10114
#define ERROR
Definition: elog.h:43
#define NULL
Definition: c.h:229
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:1694
void ExplainBeginOutput ( ExplainState es)

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

3313 {
3314  switch (es->format)
3315  {
3316  case EXPLAIN_FORMAT_TEXT:
3317  /* nothing to do */
3318  break;
3319 
3320  case EXPLAIN_FORMAT_XML:
3322  "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
3323  es->indent++;
3324  break;
3325 
3326  case EXPLAIN_FORMAT_JSON:
3327  /* top-level structure is an array of plans */
3328  appendStringInfoChar(es->str, '[');
3329  es->grouping_stack = lcons_int(0, es->grouping_stack);
3330  es->indent++;
3331  break;
3332 
3333  case EXPLAIN_FORMAT_YAML:
3334  es->grouping_stack = lcons_int(0, es->grouping_stack);
3335  break;
3336  }
3337 }
List * lcons_int(int datum, List *list)
Definition: list.c:277
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
static void ExplainCloseGroup ( const char *  objtype,
const char *  labelname,
bool  labeled,
ExplainState es 
)
static

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

3232 {
3233  switch (es->format)
3234  {
3235  case EXPLAIN_FORMAT_TEXT:
3236  /* nothing to do */
3237  break;
3238 
3239  case EXPLAIN_FORMAT_XML:
3240  es->indent--;
3241  ExplainXMLTag(objtype, X_CLOSING, es);
3242  break;
3243 
3244  case EXPLAIN_FORMAT_JSON:
3245  es->indent--;
3246  appendStringInfoChar(es->str, '\n');
3247  appendStringInfoSpaces(es->str, 2 * es->indent);
3248  appendStringInfoChar(es->str, labeled ? '}' : ']');
3250  break;
3251 
3252  case EXPLAIN_FORMAT_YAML:
3253  es->indent--;
3255  break;
3256  }
3257 }
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3401
#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:201
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
List * list_delete_first(List *list)
Definition: list.c:666
static void ExplainCustomChildren ( CustomScanState css,
List ancestors,
ExplainState es 
)
static

Definition at line 2919 of file explain.c.

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

Referenced by ExplainNode().

2920 {
2921  ListCell *cell;
2922  const char *label =
2923  (list_length(css->custom_ps) != 1 ? "children" : "child");
2924 
2925  foreach(cell, css->custom_ps)
2926  ExplainNode((PlanState *) lfirst(cell), ancestors, label, NULL, es);
2927 }
List * custom_ps
Definition: execnodes.h:1742
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:846
static char * label
Definition: pg_basebackup.c:81
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
static void ExplainDummyGroup ( const char *  objtype,
const char *  labelname,
ExplainState es 
)
static

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

3267 {
3268  switch (es->format)
3269  {
3270  case EXPLAIN_FORMAT_TEXT:
3271  /* nothing to do */
3272  break;
3273 
3274  case EXPLAIN_FORMAT_XML:
3275  ExplainXMLTag(objtype, X_CLOSE_IMMEDIATE, es);
3276  break;
3277 
3278  case EXPLAIN_FORMAT_JSON:
3280  appendStringInfoSpaces(es->str, 2 * es->indent);
3281  if (labelname)
3282  {
3283  escape_json(es->str, labelname);
3284  appendStringInfoString(es->str, ": ");
3285  }
3286  escape_json(es->str, objtype);
3287  break;
3288 
3289  case EXPLAIN_FORMAT_YAML:
3291  if (labelname)
3292  {
3293  escape_yaml(es->str, labelname);
3294  appendStringInfoString(es->str, ": ");
3295  }
3296  else
3297  {
3298  appendStringInfoString(es->str, "- ");
3299  }
3300  escape_yaml(es->str, objtype);
3301  break;
3302  }
3303 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2433
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3401
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3448
int indent
Definition: explain.h:40
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3473
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3428
ExplainFormat format
Definition: explain.h:38
#define X_CLOSE_IMMEDIATE
Definition: explain.c:53
StringInfo str
Definition: explain.h:30
void ExplainEndOutput ( ExplainState es)

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

3344 {
3345  switch (es->format)
3346  {
3347  case EXPLAIN_FORMAT_TEXT:
3348  /* nothing to do */
3349  break;
3350 
3351  case EXPLAIN_FORMAT_XML:
3352  es->indent--;
3353  appendStringInfoString(es->str, "</explain>");
3354  break;
3355 
3356  case EXPLAIN_FORMAT_JSON:
3357  es->indent--;
3358  appendStringInfoString(es->str, "\n]");
3360  break;
3361 
3362  case EXPLAIN_FORMAT_YAML:
3364  break;
3365  }
3366 }
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
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
static void ExplainIndexScanDetails ( Oid  indexid,
ScanDirection  indexorderdir,
ExplainState es 
)
static

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

2529 {
2530  const char *indexname = explain_get_index_name(indexid);
2531 
2532  if (es->format == EXPLAIN_FORMAT_TEXT)
2533  {
2534  if (ScanDirectionIsBackward(indexorderdir))
2535  appendStringInfoString(es->str, " Backward");
2536  appendStringInfo(es->str, " using %s", indexname);
2537  }
2538  else
2539  {
2540  const char *scandir;
2541 
2542  switch (indexorderdir)
2543  {
2544  case BackwardScanDirection:
2545  scandir = "Backward";
2546  break;
2548  scandir = "NoMovement";
2549  break;
2550  case ForwardScanDirection:
2551  scandir = "Forward";
2552  break;
2553  default:
2554  scandir = "???";
2555  break;
2556  }
2557  ExplainPropertyText("Scan Direction", scandir, es);
2558  ExplainPropertyText("Index Name", indexname, es);
2559  }
2560 }
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3105
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
ExplainFormat format
Definition: explain.h:38
static const char * explain_get_index_name(Oid indexId)
Definition: explain.c:2394
StringInfo str
Definition: explain.h:30
static void ExplainJSONLineEnding ( ExplainState es)
static

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

3429 {
3431  if (linitial_int(es->grouping_stack) != 0)
3432  appendStringInfoChar(es->str, ',');
3433  else
3434  linitial_int(es->grouping_stack) = 1;
3435  appendStringInfoChar(es->str, '\n');
3436 }
#define linitial_int(l)
Definition: pg_list.h:111
List * grouping_stack
Definition: explain.h:41
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
#define Assert(condition)
Definition: c.h:675
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
static void ExplainMemberNodes ( List plans,
PlanState **  planstates,
List ancestors,
ExplainState es 
)
static

Definition at line 2867 of file explain.c.

References ExplainNode(), list_length(), and NULL.

Referenced by ExplainNode().

2869 {
2870  int nplans = list_length(plans);
2871  int j;
2872 
2873  for (j = 0; j < nplans; j++)
2874  ExplainNode(planstates[j], ancestors,
2875  "Member", NULL, es);
2876 }
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:846
#define NULL
Definition: c.h:229
static int list_length(const List *l)
Definition: pg_list.h:89
static void ExplainModifyTarget ( ModifyTable plan,
ExplainState es 
)
static

Definition at line 2579 of file explain.c.

References ExplainTargetRel(), and ModifyTable::nominalRelation.

Referenced by ExplainNode().

2580 {
2581  ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
2582 }
Index nominalRelation
Definition: plannodes.h:207
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:2588
static void ExplainNode ( PlanState planstate,
List ancestors,
const char *  relationship,
const char *  plan_name,
ExplainState es 
)
static

Definition at line 846 of file explain.c.

References AGG_HASHED, 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, 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, NULL, WorkerInstrumentation::num_workers, Gather::num_workers, GatherMerge::num_workers, outerPlanState, Plan::parallel_aware, PlanState::plan, Plan::plan_rows, Plan::plan_width, psprintf(), Plan::qual, SETOP_HASHED, SETOP_SORTED, SETOPCMD_EXCEPT, SETOPCMD_EXCEPT_ALL, SETOPCMD_INTERSECT, SETOPCMD_INTERSECT_ALL, show_agg_keys(), show_buffer_usage(), show_expression(), show_foreignscan_info(), show_group_keys(), show_hash_info(), show_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_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().

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

Definition at line 461 of file explain.c.

References ExplainState::analyze, appendStringInfo(), Assert, ExplainState::buffers, CMD_UTILITY, CommandCounterIncrement(), PlannedStmt::commandType, CreateIntoRelDestReceiver(), CreateQueryDesc(), 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, NULL, PopActiveSnapshot(), PushCopiedSnapshot(), IntoClause::skipData, ExplainState::str, ExplainState::summary, ExplainState::timing, and UpdateActiveSnapshotCommandId().

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

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

Definition at line 339 of file explain.c.

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

Referenced by ExplainOneUtility(), and ExplainQuery().

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  return;
348  }
349 
350  /* if an advisor plugin is present, let it manage things */
352  (*ExplainOneQuery_hook) (query, cursorOptions, into, es,
353  queryString, params);
354  else
355  {
356  PlannedStmt *plan;
357  instr_time planstart,
358  planduration;
359 
360  INSTR_TIME_SET_CURRENT(planstart);
361 
362  /* plan the query */
363  plan = pg_plan_query(query, cursorOptions, params);
364 
365  INSTR_TIME_SET_CURRENT(planduration);
366  INSTR_TIME_SUBTRACT(planduration, planstart);
367 
368  /* run it (if needed) and produce output */
369  ExplainOnePlan(plan, into, es, queryString, params, &planduration);
370  }
371 }
void ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params)
Definition: explain.c:385
struct timeval instr_time
Definition: instr_time.h:147
Node * utilityStmt
Definition: parsenodes.h:111
#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:103
void ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, const instr_time *planduration)
Definition: explain.c:461
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153
PlannedStmt * pg_plan_query(Query *querytree, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:781
void ExplainOneUtility ( Node utilityStmt,
IntoClause into,
ExplainState es,
const char *  queryString,
ParamListInfo  params 
)

Definition at line 385 of file explain.c.

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

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

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

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

3169 {
3170  switch (es->format)
3171  {
3172  case EXPLAIN_FORMAT_TEXT:
3173  /* nothing to do */
3174  break;
3175 
3176  case EXPLAIN_FORMAT_XML:
3177  ExplainXMLTag(objtype, X_OPENING, es);
3178  es->indent++;
3179  break;
3180 
3181  case EXPLAIN_FORMAT_JSON:
3183  appendStringInfoSpaces(es->str, 2 * es->indent);
3184  if (labelname)
3185  {
3186  escape_json(es->str, labelname);
3187  appendStringInfoString(es->str, ": ");
3188  }
3189  appendStringInfoChar(es->str, labeled ? '{' : '[');
3190 
3191  /*
3192  * In JSON format, the grouping_stack is an integer list. 0 means
3193  * we've emitted nothing at this grouping level, 1 means we've
3194  * emitted something (and so the next item needs a comma). See
3195  * ExplainJSONLineEnding().
3196  */
3197  es->grouping_stack = lcons_int(0, es->grouping_stack);
3198  es->indent++;
3199  break;
3200 
3201  case EXPLAIN_FORMAT_YAML:
3202 
3203  /*
3204  * In YAML format, the grouping stack is an integer list. 0 means
3205  * we've emitted nothing at this grouping level AND this grouping
3206  * level is unlabelled and must be marked with "- ". See
3207  * ExplainYAMLLineStarting().
3208  */
3210  if (labelname)
3211  {
3212  appendStringInfo(es->str, "%s: ", labelname);
3213  es->grouping_stack = lcons_int(1, es->grouping_stack);
3214  }
3215  else
3216  {
3217  appendStringInfoString(es->str, "- ");
3218  es->grouping_stack = lcons_int(0, es->grouping_stack);
3219  }
3220  es->indent++;
3221  break;
3222  }
3223 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2433
List * lcons_int(int datum, List *list)
Definition: list.c:277
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3401
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3448
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3428
#define X_OPENING
Definition: explain.c:51
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
static bool ExplainPreScanNode ( PlanState planstate,
Bitmapset **  rels_used 
)
static

Definition at line 782 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_SampleScan, T_SeqScan, T_SubqueryScan, T_TableFuncScan, T_TidScan, T_ValuesScan, and T_WorkTableScan.

Referenced by ExplainPrintPlan().

783 {
784  Plan *plan = planstate->plan;
785 
786  switch (nodeTag(plan))
787  {
788  case T_SeqScan:
789  case T_SampleScan:
790  case T_IndexScan:
791  case T_IndexOnlyScan:
792  case T_BitmapHeapScan:
793  case T_TidScan:
794  case T_SubqueryScan:
795  case T_FunctionScan:
796  case T_TableFuncScan:
797  case T_ValuesScan:
798  case T_CteScan:
799  case T_WorkTableScan:
800  *rels_used = bms_add_member(*rels_used,
801  ((Scan *) plan)->scanrelid);
802  break;
803  case T_ForeignScan:
804  *rels_used = bms_add_members(*rels_used,
805  ((ForeignScan *) plan)->fs_relids);
806  break;
807  case T_CustomScan:
808  *rels_used = bms_add_members(*rels_used,
809  ((CustomScan *) plan)->custom_relids);
810  break;
811  case T_ModifyTable:
812  *rels_used = bms_add_member(*rels_used,
813  ((ModifyTable *) plan)->nominalRelation);
814  if (((ModifyTable *) plan)->exclRelRTI)
815  *rels_used = bms_add_member(*rels_used,
816  ((ModifyTable *) plan)->exclRelRTI);
817  break;
818  default:
819  break;
820  }
821 
822  return planstate_tree_walker(planstate, ExplainPreScanNode, rels_used);
823 }
Plan * plan
Definition: execnodes.h:1049
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:668
#define nodeTag(nodeptr)
Definition: nodes.h:523
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
Definition: explain.c:782
bool planstate_tree_walker(PlanState *planstate, bool(*walker)(), void *context)
Definition: nodeFuncs.c:3705
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:725
void ExplainPrintPlan ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 611 of file explain.c.

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

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

Definition at line 648 of file explain.c.

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

Referenced by explain_ExecutorEnd(), and ExplainOnePlan().

649 {
650  ResultRelInfo *rInfo;
651  bool show_relname;
652  int numrels = queryDesc->estate->es_num_result_relations;
653  List *targrels = queryDesc->estate->es_trig_target_relations;
654  int nr;
655  ListCell *l;
656 
657  ExplainOpenGroup("Triggers", "Triggers", false, es);
658 
659  show_relname = (numrels > 1 || targrels != NIL);
660  rInfo = queryDesc->estate->es_result_relations;
661  for (nr = 0; nr < numrels; rInfo++, nr++)
662  report_triggers(rInfo, show_relname, es);
663 
664  foreach(l, targrels)
665  {
666  rInfo = (ResultRelInfo *) lfirst(l);
667  report_triggers(rInfo, show_relname, es);
668  }
669 
670  ExplainCloseGroup("Triggers", "Triggers", false, es);
671 }
#define NIL
Definition: pg_list.h:69
EState * estate
Definition: execdesc.h:47
static void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3167
ResultRelInfo * es_result_relations
Definition: execnodes.h:384
static void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3230
static void report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
Definition: explain.c:693
List * es_trig_target_relations
Definition: execnodes.h:389
int es_num_result_relations
Definition: execnodes.h:385
#define lfirst(lc)
Definition: pg_list.h:106
Definition: pg_list.h:45
static void ExplainProperty ( const char *  qlabel,
const char *  value,
bool  numeric,
ExplainState es 
)
static

Definition at line 3055 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, X_CLOSING, X_NOWHITESPACE, and X_OPENING.

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

3057 {
3058  switch (es->format)
3059  {
3060  case EXPLAIN_FORMAT_TEXT:
3061  appendStringInfoSpaces(es->str, es->indent * 2);
3062  appendStringInfo(es->str, "%s: %s\n", qlabel, value);
3063  break;
3064 
3065  case EXPLAIN_FORMAT_XML:
3066  {
3067  char *str;
3068 
3069  appendStringInfoSpaces(es->str, es->indent * 2);
3070  ExplainXMLTag(qlabel, X_OPENING | X_NOWHITESPACE, es);
3071  str = escape_xml(value);
3072  appendStringInfoString(es->str, str);
3073  pfree(str);
3074  ExplainXMLTag(qlabel, X_CLOSING | X_NOWHITESPACE, es);
3075  appendStringInfoChar(es->str, '\n');
3076  }
3077  break;
3078 
3079  case EXPLAIN_FORMAT_JSON:
3081  appendStringInfoSpaces(es->str, es->indent * 2);
3082  escape_json(es->str, qlabel);
3083  appendStringInfoString(es->str, ": ");
3084  if (numeric)
3086  else
3087  escape_json(es->str, value);
3088  break;
3089 
3090  case EXPLAIN_FORMAT_YAML:
3092  appendStringInfo(es->str, "%s: ", qlabel);
3093  if (numeric)
3095  else
3096  escape_yaml(es->str, value);
3097  break;
3098  }
3099 }
static struct @76 value
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2433
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3401
#define X_CLOSING
Definition: explain.c:52
void pfree(void *pointer)
Definition: mcxt.c:950
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3448
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3473
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3428
#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:2229
StringInfo str
Definition: explain.h:30
void ExplainPropertyBool ( const char *  qlabel,
bool  value,
ExplainState es 
)

Definition at line 3152 of file explain.c.

References ExplainProperty().

Referenced by ExplainNode().

3153 {
3154  ExplainProperty(qlabel, value ? "true" : "false", true, es);
3155 }
static struct @76 value
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3055
void ExplainPropertyFloat ( const char *  qlabel,
double  value,
int  ndigits,
ExplainState es 
)

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

3141 {
3142  char buf[256];
3143 
3144  snprintf(buf, sizeof(buf), "%.*f", ndigits, value);
3145  ExplainProperty(qlabel, buf, true, es);
3146 }
static struct @76 value
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3055
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static char * buf
Definition: pg_test_fsync.c:65
void ExplainPropertyInteger ( const char *  qlabel,
int  value,
ExplainState es 
)

Definition at line 3114 of file explain.c.

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

Referenced by ExplainNode().

3115 {
3116  char buf[32];
3117 
3118  snprintf(buf, sizeof(buf), "%d", value);
3119  ExplainProperty(qlabel, buf, true, es);
3120 }
static struct @76 value
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3055
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static char * buf
Definition: pg_test_fsync.c:65
void ExplainPropertyList ( const char *  qlabel,
List data,
ExplainState es 
)

Definition at line 2934 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, X_CLOSING, and X_OPENING.

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

2935 {
2936  ListCell *lc;
2937  bool first = true;
2938 
2939  switch (es->format)
2940  {
2941  case EXPLAIN_FORMAT_TEXT:
2942  appendStringInfoSpaces(es->str, es->indent * 2);
2943  appendStringInfo(es->str, "%s: ", qlabel);
2944  foreach(lc, data)
2945  {
2946  if (!first)
2947  appendStringInfoString(es->str, ", ");
2948  appendStringInfoString(es->str, (const char *) lfirst(lc));
2949  first = false;
2950  }
2951  appendStringInfoChar(es->str, '\n');
2952  break;
2953 
2954  case EXPLAIN_FORMAT_XML:
2955  ExplainXMLTag(qlabel, X_OPENING, es);
2956  foreach(lc, data)
2957  {
2958  char *str;
2959 
2960  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
2961  appendStringInfoString(es->str, "<Item>");
2962  str = escape_xml((const char *) lfirst(lc));
2963  appendStringInfoString(es->str, str);
2964  pfree(str);
2965  appendStringInfoString(es->str, "</Item>\n");
2966  }
2967  ExplainXMLTag(qlabel, X_CLOSING, es);
2968  break;
2969 
2970  case EXPLAIN_FORMAT_JSON:
2972  appendStringInfoSpaces(es->str, es->indent * 2);
2973  escape_json(es->str, qlabel);
2974  appendStringInfoString(es->str, ": [");
2975  foreach(lc, data)
2976  {
2977  if (!first)
2978  appendStringInfoString(es->str, ", ");
2979  escape_json(es->str, (const char *) lfirst(lc));
2980  first = false;
2981  }
2982  appendStringInfoChar(es->str, ']');
2983  break;
2984 
2985  case EXPLAIN_FORMAT_YAML:
2987  appendStringInfo(es->str, "%s: ", qlabel);
2988  foreach(lc, data)
2989  {
2990  appendStringInfoChar(es->str, '\n');
2991  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
2992  appendStringInfoString(es->str, "- ");
2993  escape_yaml(es->str, (const char *) lfirst(lc));
2994  }
2995  break;
2996  }
2997 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2433
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3401
#define X_CLOSING
Definition: explain.c:52
void pfree(void *pointer)
Definition: mcxt.c:950
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3448
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3473
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3428
#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:2229
StringInfo str
Definition: explain.h:30
void ExplainPropertyListNested ( const char *  qlabel,
List data,
ExplainState es 
)

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

3005 {
3006  ListCell *lc;
3007  bool first = true;
3008 
3009  switch (es->format)
3010  {
3011  case EXPLAIN_FORMAT_TEXT:
3012  case EXPLAIN_FORMAT_XML:
3013  ExplainPropertyList(qlabel, data, es);
3014  return;
3015 
3016  case EXPLAIN_FORMAT_JSON:
3018  appendStringInfoSpaces(es->str, es->indent * 2);
3019  appendStringInfoChar(es->str, '[');
3020  foreach(lc, data)
3021  {
3022  if (!first)
3023  appendStringInfoString(es->str, ", ");
3024  escape_json(es->str, (const char *) lfirst(lc));
3025  first = false;
3026  }
3027  appendStringInfoChar(es->str, ']');
3028  break;
3029 
3030  case EXPLAIN_FORMAT_YAML:
3032  appendStringInfoString(es->str, "- [");
3033  foreach(lc, data)
3034  {
3035  if (!first)
3036  appendStringInfoString(es->str, ", ");
3037  escape_yaml(es->str, (const char *) lfirst(lc));
3038  first = false;
3039  }
3040  appendStringInfoChar(es->str, ']');
3041  break;
3042  }
3043 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2433
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3448
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3473
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3428
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:2934
#define lfirst(lc)
Definition: pg_list.h:106
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
void ExplainPropertyLong ( const char *  qlabel,
long  value,
ExplainState es 
)

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

3127 {
3128  char buf[32];
3129 
3130  snprintf(buf, sizeof(buf), "%ld", value);
3131  ExplainProperty(qlabel, buf, true, es);
3132 }
static struct @76 value
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3055
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static char * buf
Definition: pg_test_fsync.c:65
void ExplainPropertyText ( const char *  qlabel,
const char *  value,
ExplainState es 
)

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

3106 {
3107  ExplainProperty(qlabel, value, false, es);
3108 }
static struct @76 value
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3055
void ExplainQuery ( ParseState pstate,
ExplainStmt stmt,
const char *  queryString,
ParamListInfo  params,
DestReceiver dest 
)

Definition at line 144 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, lnext, DefElem::location, NewExplainState(), NIL, NULL, ExplainStmt::options, parser_errposition(), pfree(), ExplainStmt::query, QueryRewrite(), ExplainState::str, ExplainState::summary, ExplainState::timing, and ExplainState::verbose.

Referenced by standard_ProcessUtility().

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

Definition at line 682 of file explain.c.

References ExplainPropertyText(), and QueryDesc::sourceText.

Referenced by explain_ExecutorEnd().

683 {
684  if (queryDesc->sourceText)
685  ExplainPropertyText("Query Text", queryDesc->sourceText, es);
686 }
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3105
const char * sourceText
Definition: execdesc.h:38
TupleDesc ExplainResultDesc ( ExplainStmt stmt)

Definition at line 300 of file explain.c.

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

Referenced by ExplainQuery(), and UtilityTupleDescriptor().

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

Definition at line 2566 of file explain.c.

References ExplainTargetRel(), and Scan::scanrelid.

Referenced by ExplainNode().

2567 {
2568  ExplainTargetRel((Plan *) plan, plan->scanrelid, es);
2569 }
Index scanrelid
Definition: plannodes.h:316
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:2588
void ExplainSeparatePlans ( ExplainState es)

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

3373 {
3374  switch (es->format)
3375  {
3376  case EXPLAIN_FORMAT_TEXT:
3377  /* add a blank line */
3378  appendStringInfoChar(es->str, '\n');
3379  break;
3380 
3381  case EXPLAIN_FORMAT_XML:
3382  case EXPLAIN_FORMAT_JSON:
3383  case EXPLAIN_FORMAT_YAML:
3384  /* nothing to do */
3385  break;
3386  }
3387 }
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
static void ExplainSubPlans ( List plans,
List ancestors,
const char *  relationship,
ExplainState es 
)
static

Definition at line 2885 of file explain.c.

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

Referenced by ExplainNode().

2887 {
2888  ListCell *lst;
2889 
2890  foreach(lst, plans)
2891  {
2892  SubPlanState *sps = (SubPlanState *) lfirst(lst);
2893  SubPlan *sp = (SubPlan *) sps->xprstate.expr;
2894 
2895  /*
2896  * There can be multiple SubPlan nodes referencing the same physical
2897  * subplan (same plan_id, which is its index in PlannedStmt.subplans).
2898  * We should print a subplan only once, so track which ones we already
2899  * printed. This state must be global across the plan tree, since the
2900  * duplicate nodes could be in different plan nodes, eg both a bitmap
2901  * indexscan's indexqual and its parent heapscan's recheck qual. (We
2902  * do not worry too much about which plan node we show the subplan as
2903  * attached to in such cases.)
2904  */
2905  if (bms_is_member(sp->plan_id, es->printed_subplans))
2906  continue;
2908  sp->plan_id);
2909 
2910  ExplainNode(sps->planstate, ancestors,
2911  relationship, sp->plan_name, es);
2912  }
2913 }
int plan_id
Definition: primnodes.h:688
ExprState xprstate
Definition: execnodes.h:787
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:846
struct PlanState * planstate
Definition: execnodes.h:788
Expr * expr
Definition: execnodes.h:600
char * plan_name
Definition: primnodes.h:690
#define lfirst(lc)
Definition: pg_list.h:106
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:668
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:419
static void ExplainTargetRel ( Plan plan,
Index  rti,
ExplainState es 
)
static

Definition at line 2588 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, NULL, quote_identifier(), RangeTblEntry::relid, rt_fetch, ExplainState::rtable, ExplainState::rtable_names, RTE_CTE, RTE_FUNCTION, 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_SampleScan, T_SeqScan, T_TableFuncScan, T_TidScan, T_ValuesScan, T_WorkTableScan, and ExplainState::verbose.

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

2589 {
2590  char *objectname = NULL;
2591  char *namespace = NULL;
2592  const char *objecttag = NULL;
2593  RangeTblEntry *rte;
2594  char *refname;
2595 
2596  rte = rt_fetch(rti, es->rtable);
2597  refname = (char *) list_nth(es->rtable_names, rti - 1);
2598  if (refname == NULL)
2599  refname = rte->eref->aliasname;
2600 
2601  switch (nodeTag(plan))
2602  {
2603  case T_SeqScan:
2604  case T_SampleScan:
2605  case T_IndexScan:
2606  case T_IndexOnlyScan:
2607  case T_BitmapHeapScan:
2608  case T_TidScan:
2609  case T_ForeignScan:
2610  case T_CustomScan:
2611  case T_ModifyTable:
2612  /* Assert it's on a real relation */
2613  Assert(rte->rtekind == RTE_RELATION);
2614  objectname = get_rel_name(rte->relid);
2615  if (es->verbose)
2616  namespace = get_namespace_name(get_rel_namespace(rte->relid));
2617  objecttag = "Relation Name";
2618  break;
2619  case T_FunctionScan:
2620  {
2621  FunctionScan *fscan = (FunctionScan *) plan;
2622 
2623  /* Assert it's on a RangeFunction */
2624  Assert(rte->rtekind == RTE_FUNCTION);
2625 
2626  /*
2627  * If the expression is still a function call of a single
2628  * function, we can get the real name of the function.
2629  * Otherwise, punt. (Even if it was a single function call
2630  * originally, the optimizer could have simplified it away.)
2631  */
2632  if (list_length(fscan->functions) == 1)
2633  {
2634  RangeTblFunction *rtfunc = (RangeTblFunction *) linitial(fscan->functions);
2635 
2636  if (IsA(rtfunc->funcexpr, FuncExpr))
2637  {
2638  FuncExpr *funcexpr = (FuncExpr *) rtfunc->funcexpr;
2639  Oid funcid = funcexpr->funcid;
2640 
2641  objectname = get_func_name(funcid);
2642  if (es->verbose)
2643  namespace =
2645  }
2646  }
2647  objecttag = "Function Name";
2648  }
2649  break;
2650  case T_TableFuncScan:
2651  Assert(rte->rtekind == RTE_TABLEFUNC);
2652  objectname = "xmltable";
2653  objecttag = "Table Function Name";
2654  break;
2655  case T_ValuesScan:
2656  Assert(rte->rtekind == RTE_VALUES);
2657  break;
2658  case T_CteScan:
2659  /* Assert it's on a non-self-reference CTE */
2660  Assert(rte->rtekind == RTE_CTE);
2661  Assert(!rte->self_reference);
2662  objectname = rte->ctename;
2663  objecttag = "CTE Name";
2664  break;
2665  case T_WorkTableScan:
2666  /* Assert it's on a self-reference CTE */
2667  Assert(rte->rtekind == RTE_CTE);
2668  Assert(rte->self_reference);
2669  objectname = rte->ctename;
2670  objecttag = "CTE Name";
2671  break;
2672  default:
2673  break;
2674  }
2675 
2676  if (es->format == EXPLAIN_FORMAT_TEXT)
2677  {
2678  appendStringInfoString(es->str, " on");
2679  if (namespace != NULL)
2680  appendStringInfo(es->str, " %s.%s", quote_identifier(namespace),
2681  quote_identifier(objectname));
2682  else if (objectname != NULL)
2683  appendStringInfo(es->str, " %s", quote_identifier(objectname));
2684  if (objectname == NULL || strcmp(refname, objectname) != 0)
2685  appendStringInfo(es->str, " %s", quote_identifier(refname));
2686  }
2687  else
2688  {
2689  if (objecttag != NULL && objectname != NULL)
2690  ExplainPropertyText(objecttag, objectname, es);
2691  if (namespace != NULL)
2692  ExplainPropertyText("Schema", namespace, es);
2693  ExplainPropertyText("Alias", refname, es);
2694  }
2695 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:569
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10114
Oid get_func_namespace(Oid funcid)
Definition: lsyscache.c:1404
List * functions
Definition: plannodes.h:495
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1718
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:3105
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
#define linitial(l)
Definition: pg_list.h:110
Oid funcid
Definition: primnodes.h:448
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1380
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3006
void * list_nth(const List *list, int n)
Definition: list.c:410
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
bool self_reference
Definition: parsenodes.h:983
bool verbose
Definition: explain.h:32
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
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:523
RTEKind rtekind
Definition: parsenodes.h:916
char * ctename
Definition: parsenodes.h:981
Alias * eref
Definition: parsenodes.h:1000
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1694
StringInfo str
Definition: explain.h:30
List * rtable
Definition: explain.h:44
static void ExplainXMLTag ( const char *  tagname,
int  flags,
ExplainState es 
)
static

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

3402 {
3403  const char *s;
3404  const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
3405 
3406  if ((flags & X_NOWHITESPACE) == 0)
3407  appendStringInfoSpaces(es->str, 2 * es->indent);
3408  appendStringInfoCharMacro(es->str, '<');
3409  if ((flags & X_CLOSING) != 0)
3410  appendStringInfoCharMacro(es->str, '/');
3411  for (s = tagname; *s; s++)
3412  appendStringInfoChar(es->str, strchr(valid, *s) ? *s : '-');
3413  if ((flags & X_CLOSE_IMMEDIATE) != 0)
3414  appendStringInfoString(es->str, " /");
3415  appendStringInfoCharMacro(es->str, '>');
3416  if ((flags & X_NOWHITESPACE) == 0)
3417  appendStringInfoCharMacro(es->str, '\n');
3418 }
#define X_CLOSING
Definition: explain.c:52
#define appendStringInfoCharMacro(str, ch)
Definition: stringinfo.h:135
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
#define X_NOWHITESPACE
Definition: explain.c:54
#define X_CLOSE_IMMEDIATE
Definition: explain.c:53
StringInfo str
Definition: explain.h:30
static void ExplainYAMLLineStarting ( ExplainState es)
static

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

3449 {
3451  if (linitial_int(es->grouping_stack) == 0)
3452  {
3453  linitial_int(es->grouping_stack) = 1;
3454  }
3455  else
3456  {
3457  appendStringInfoChar(es->str, '\n');
3458  appendStringInfoSpaces(es->str, es->indent * 2);
3459  }
3460 }
#define linitial_int(l)
Definition: pg_list.h:111
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
#define Assert(condition)
Definition: c.h:675
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
ExplainState* NewExplainState ( void  )

Definition at line 283 of file explain.c.

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

Referenced by explain_ExecutorEnd(), and ExplainQuery().

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

Definition at line 693 of file explain.c.

References appendStringInfo(), appendStringInfoString(), EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), ExplainOpenGroup(), ExplainPropertyFloat(), ExplainPropertyText(), ExplainState::format, get_constraint_name(), InstrEndLoop(), Instrumentation::ntuples, NULL, 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().

694 {
695  int nt;
696 
697  if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
698  return;
699  for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
700  {
701  Trigger *trig = rInfo->ri_TrigDesc->triggers + nt;
702  Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
703  char *relname;
704  char *conname = NULL;
705 
706  /* Must clean up instrumentation state */
707  InstrEndLoop(instr);
708 
709  /*
710  * We ignore triggers that were never invoked; they likely aren't
711  * relevant to the current query type.
712  */
713  if (instr->ntuples == 0)
714  continue;
715 
716  ExplainOpenGroup("Trigger", NULL, true, es);
717 
718  relname = RelationGetRelationName(rInfo->ri_RelationDesc);
719  if (OidIsValid(trig->tgconstraint))
720  conname = get_constraint_name(trig->tgconstraint);
721 
722  /*
723  * In text format, we avoid printing both the trigger name and the
724  * constraint name unless VERBOSE is specified. In non-text formats
725  * we just print everything.
726  */
727  if (es->format == EXPLAIN_FORMAT_TEXT)
728  {
729  if (es->verbose || conname == NULL)
730  appendStringInfo(es->str, "Trigger %s", trig->tgname);
731  else
732  appendStringInfoString(es->str, "Trigger");
733  if (conname)
734  appendStringInfo(es->str, " for constraint %s", conname);
735  if (show_relname)
736  appendStringInfo(es->str, " on %s", relname);
737  if (es->timing)
738  appendStringInfo(es->str, ": time=%.3f calls=%.0f\n",
739  1000.0 * instr->total, instr->ntuples);
740  else
741  appendStringInfo(es->str, ": calls=%.0f\n", instr->ntuples);
742  }
743  else
744  {
745  ExplainPropertyText("Trigger Name", trig->tgname, es);
746  if (conname)
747  ExplainPropertyText("Constraint Name", conname, es);
748  ExplainPropertyText("Relation", relname, es);
749  if (es->timing)
750  ExplainPropertyFloat("Time", 1000.0 * instr->total, 3, es);
751  ExplainPropertyFloat("Calls", instr->ntuples, 0, es);
752  }
753 
754  if (conname)
755  pfree(conname);
756 
757  ExplainCloseGroup("Trigger", NULL, true, es);
758  }
759 }
Relation ri_RelationDesc
Definition: execnodes.h:337
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:965
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3139
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:344
#define OidIsValid(objectId)
Definition: c.h:538
static void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3167
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:114
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3105
void pfree(void *pointer)
Definition: mcxt.c:950
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
Oid tgconstraint
Definition: reltrigger.h:34
char * tgname
Definition: reltrigger.h:27
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
Trigger * triggers
Definition: reltrigger.h:48
#define RelationGetRelationName(relation)
Definition: rel.h:433
static void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3230
double ntuples
Definition: instrument.h:59
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:341
bool timing
Definition: explain.h:36
int numtriggers
Definition: reltrigger.h:49
bool verbose
Definition: explain.h:32
#define NULL
Definition: c.h:229
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
static void show_agg_keys ( AggState astate,
List ancestors,
ExplainState es 
)
static

Definition at line 1917 of file explain.c.

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

Referenced by ExplainNode().

1919 {
1920  Agg *plan = (Agg *) astate->ss.ps.plan;
1921 
1922  if (plan->numCols > 0 || plan->groupingSets)
1923  {
1924  /* The key columns refer to the tlist of the child plan */
1925  ancestors = lcons(astate, ancestors);
1926 
1927  if (plan->groupingSets)
1928  show_grouping_sets(outerPlanState(astate), plan, ancestors, es);
1929  else
1930  show_sort_group_keys(outerPlanState(astate), "Group Key",
1931  plan->numCols, plan->grpColIdx,
1932  NULL, NULL, NULL,
1933  ancestors, es);
1934 
1935  ancestors = list_delete_first(ancestors);
1936  }
1937 }
int numCols
Definition: plannodes.h:756
AttrNumber * grpColIdx
Definition: plannodes.h:757
ScanState ss
Definition: execnodes.h:1949
PlanState ps
Definition: execnodes.h:1290
#define outerPlanState(node)
Definition: execnodes.h:1092
static void show_grouping_sets(PlanState *planstate, Agg *agg, List *ancestors, ExplainState *es)
Definition: explain.c:1940
List * groupingSets
Definition: plannodes.h:762
Plan * plan
Definition: execnodes.h:1049
List * lcons(void *datum, List *list)
Definition: list.c:259
#define NULL
Definition: c.h:229
Definition: plannodes.h:751
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:2056
List * list_delete_first(List *list)
Definition: list.c:666
static void show_buffer_usage ( ExplainState es,
const BufferUsage usage 
)
static

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

2418 {
2419  if (es->format == EXPLAIN_FORMAT_TEXT)
2420  {
2421  bool has_shared = (usage->shared_blks_hit > 0 ||
2422  usage->shared_blks_read > 0 ||
2423  usage->shared_blks_dirtied > 0 ||
2424  usage->shared_blks_written > 0);
2425  bool has_local = (usage->local_blks_hit > 0 ||
2426  usage->local_blks_read > 0 ||
2427  usage->local_blks_dirtied > 0 ||
2428  usage->local_blks_written > 0);
2429  bool has_temp = (usage->temp_blks_read > 0 ||
2430  usage->temp_blks_written > 0);
2431  bool has_timing = (!INSTR_TIME_IS_ZERO(usage->blk_read_time) ||
2433 
2434  /* Show only positive counter values. */
2435  if (has_shared || has_local || has_temp)
2436  {
2437  appendStringInfoSpaces(es->str, es->indent * 2);
2438  appendStringInfoString(es->str, "Buffers:");
2439 
2440  if (has_shared)
2441  {
2442  appendStringInfoString(es->str, " shared");
2443  if (usage->shared_blks_hit > 0)
2444  appendStringInfo(es->str, " hit=%ld",
2445  usage->shared_blks_hit);
2446  if (usage->shared_blks_read > 0)
2447  appendStringInfo(es->str, " read=%ld",
2448  usage->shared_blks_read);
2449  if (usage->shared_blks_dirtied > 0)
2450  appendStringInfo(es->str, " dirtied=%ld",
2451  usage->shared_blks_dirtied);
2452  if (usage->shared_blks_written > 0)
2453  appendStringInfo(es->str, " written=%ld",
2454  usage->shared_blks_written);
2455  if (has_local || has_temp)
2456  appendStringInfoChar(es->str, ',');
2457  }
2458  if (has_local)
2459  {
2460  appendStringInfoString(es->str, " local");
2461  if (usage->local_blks_hit > 0)
2462  appendStringInfo(es->str, " hit=%ld",
2463  usage->local_blks_hit);
2464  if (usage->local_blks_read > 0)
2465  appendStringInfo(es->str, " read=%ld",
2466  usage->local_blks_read);
2467  if (usage->local_blks_dirtied > 0)
2468  appendStringInfo(es->str, " dirtied=%ld",
2469  usage->local_blks_dirtied);
2470  if (usage->local_blks_written > 0)
2471  appendStringInfo(es->str, " written=%ld",
2472  usage->local_blks_written);
2473  if (has_temp)
2474  appendStringInfoChar(es->str, ',');
2475  }
2476  if (has_temp)
2477  {
2478  appendStringInfoString(es->str, " temp");
2479  if (usage->temp_blks_read > 0)
2480  appendStringInfo(es->str, " read=%ld",
2481  usage->temp_blks_read);
2482  if (usage->temp_blks_written > 0)
2483  appendStringInfo(es->str, " written=%ld",
2484  usage->temp_blks_written);
2485  }
2486  appendStringInfoChar(es->str, '\n');
2487  }
2488 
2489  /* As above, show only positive counter values. */
2490  if (has_timing)
2491  {
2492  appendStringInfoSpaces(es->str, es->indent * 2);
2493  appendStringInfoString(es->str, "I/O Timings:");
2494  if (!INSTR_TIME_IS_ZERO(usage->blk_read_time))
2495  appendStringInfo(es->str, " read=%0.3f",
2497  if (!INSTR_TIME_IS_ZERO(usage->blk_write_time))
2498  appendStringInfo(es->str, " write=%0.3f",
2500  appendStringInfoChar(es->str, '\n');
2501  }
2502  }
2503  else
2504  {
2505  ExplainPropertyLong("Shared Hit Blocks", usage->shared_blks_hit, es);
2506  ExplainPropertyLong("Shared Read Blocks", usage->shared_blks_read, es);
2507  ExplainPropertyLong("Shared Dirtied Blocks", usage->shared_blks_dirtied, es);
2508  ExplainPropertyLong("Shared Written Blocks", usage->shared_blks_written, es);
2509  ExplainPropertyLong("Local Hit Blocks", usage->local_blks_hit, es);
2510  ExplainPropertyLong("Local Read Blocks", usage->local_blks_read, es);
2511  ExplainPropertyLong("Local Dirtied Blocks", usage->local_blks_dirtied, es);
2512  ExplainPropertyLong("Local Written Blocks", usage->local_blks_written, es);
2513  ExplainPropertyLong("Temp Read Blocks", usage->temp_blks_read, es);
2514  ExplainPropertyLong("Temp Written Blocks", usage->temp_blks_written, es);
2515  if (track_io_timing)
2516  {
2517  ExplainPropertyFloat("I/O Read Time", INSTR_TIME_GET_MILLISEC(usage->blk_read_time), 3, es);
2518  ExplainPropertyFloat("I/O Write Time", INSTR_TIME_GET_MILLISEC(usage->blk_write_time), 3, es);
2519  }
2520  }
2521 }
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:3126
#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:3139
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:110
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
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:201
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
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
static void show_expression ( Node node,
const char *  qlabel,
PlanState planstate,
List ancestors,
bool  useprefix,
ExplainState es 
)
static

Definition at line 1814 of file explain.c.

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

Referenced by ExplainNode(), and show_qual().

1817 {
1818  List *context;
1819  char *exprstr;
1820 
1821  /* Set up deparsing context */
1823  (Node *) planstate,
1824  ancestors);
1825 
1826  /* Deparse the expression */
1827  exprstr = deparse_expression(node, context, useprefix, false);
1828 
1829  /* And add to es->str */
1830  ExplainPropertyText(qlabel, exprstr, es);
1831 }
Definition: nodes.h:518
List * deparse_cxt
Definition: explain.h:46
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3105
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:2968
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:2816
Definition: pg_list.h:45
static void show_foreignscan_info ( ForeignScanState fsstate,
ExplainState es 
)
static

Definition at line 2370 of file explain.c.

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

Referenced by ExplainNode().

2371 {
2372  FdwRoutine *fdwroutine = fsstate->fdwroutine;
2373 
2374  /* Let the FDW emit whatever fields it wants */
2375  if (((ForeignScan *) fsstate->ss.ps.plan)->operation != CMD_SELECT)
2376  {
2377  if (fdwroutine->ExplainDirectModify != NULL)
2378  fdwroutine->ExplainDirectModify(fsstate, es);
2379  }
2380  else
2381  {
2382  if (fdwroutine->ExplainForeignScan != NULL)
2383  fdwroutine->ExplainForeignScan(fsstate, es);
2384  }
2385 }
ScanState ss
Definition: execnodes.h:1714
ExplainForeignScan_function ExplainForeignScan
Definition: fdwapi.h:213
PlanState ps
Definition: execnodes.h:1290
ExplainDirectModify_function ExplainDirectModify
Definition: fdwapi.h:215
struct FdwRoutine * fdwroutine
Definition: execnodes.h:1718
Plan * plan
Definition: execnodes.h:1049
#define NULL
Definition: c.h:229
static void show_group_keys ( GroupState gstate,
List ancestors,
ExplainState es 
)
static

Definition at line 2036 of file explain.c.

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

Referenced by ExplainNode().

2038 {
2039  Group *plan = (Group *) gstate->ss.ps.plan;
2040 
2041  /* The key columns refer to the tlist of the child plan */
2042  ancestors = lcons(gstate, ancestors);
2043  show_sort_group_keys(outerPlanState(gstate), "Group Key",
2044  plan->numCols, plan->grpColIdx,
2045  NULL, NULL, NULL,
2046  ancestors, es);
2047  ancestors = list_delete_first(ancestors);
2048 }
ScanState ss
Definition: execnodes.h:1924
PlanState ps
Definition: execnodes.h:1290
#define outerPlanState(node)
Definition: execnodes.h:1092
int numCols
Definition: plannodes.h:732
Plan * plan
Definition: execnodes.h:1049
List * lcons(void *datum, List *list)
Definition: list.c:259
#define NULL
Definition: c.h:229
AttrNumber * grpColIdx
Definition: plannodes.h:733
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:2056
List * list_delete_first(List *list)
Definition: list.c:666
static void show_grouping_set_keys ( PlanState planstate,
Agg aggnode,
Sort sortnode,
List context,
bool  useprefix,
List ancestors,
ExplainState es 
)
static

Definition at line 1971 of file explain.c.

References 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, NULL, Sort::nullsFirst, Sort::numCols, PlanState::plan, show_sort_group_keys(), Sort::sortColIdx, Sort::sortOperators, and Plan::targetlist.

Referenced by show_grouping_sets().

1975 {
1976  Plan *plan = planstate->plan;
1977  char *exprstr;
1978  ListCell *lc;
1979  List *gsets = aggnode->groupingSets;
1980  AttrNumber *keycols = aggnode->grpColIdx;
1981 
1982  ExplainOpenGroup("Grouping Set", NULL, true, es);
1983 
1984  if (sortnode)
1985  {
1986  show_sort_group_keys(planstate, "Sort Key",
1987  sortnode->numCols, sortnode->sortColIdx,
1988  sortnode->sortOperators, sortnode->collations,
1989  sortnode->nullsFirst,
1990  ancestors, es);
1991  if (es->format == EXPLAIN_FORMAT_TEXT)
1992  es->indent++;
1993  }
1994 
1995  ExplainOpenGroup("Group Keys", "Group Keys", false, es);
1996 
1997  foreach(lc, gsets)
1998  {
1999  List *result = NIL;
2000  ListCell *lc2;
2001 
2002  foreach(lc2, (List *) lfirst(lc))
2003  {
2004  Index i = lfirst_int(lc2);
2005  AttrNumber keyresno = keycols[i];
2006  TargetEntry *target = get_tle_by_resno(plan->targetlist,
2007  keyresno);
2008 
2009  if (!target)
2010  elog(ERROR, "no tlist entry for key %d", keyresno);
2011  /* Deparse the expression, showing any top-level cast */
2012  exprstr = deparse_expression((Node *) target->expr, context,
2013  useprefix, true);
2014 
2015  result = lappend(result, exprstr);
2016  }
2017 
2018  if (!result && es->format == EXPLAIN_FORMAT_TEXT)
2019  ExplainPropertyText("Group Key", "()", es);
2020  else
2021  ExplainPropertyListNested("Group Key", result, es);
2022  }
2023 
2024  ExplainCloseGroup("Group Keys", "Group Keys", false, es);
2025 
2026  if (sortnode && es->format == EXPLAIN_FORMAT_TEXT)
2027  es->indent--;
2028 
2029  ExplainCloseGroup("Grouping Set", NULL, true, es);
2030 }
#define NIL
Definition: pg_list.h:69
AttrNumber * grpColIdx
Definition: plannodes.h:757
Definition: nodes.h:518
bool * nullsFirst
Definition: plannodes.h:720
Oid * sortOperators
Definition: plannodes.h:718
static void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3167
void ExplainPropertyListNested(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:3004
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3105
#define ERROR
Definition: elog.h:43
#define lfirst_int(lc)
Definition: pg_list.h:107
static void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3230
int indent
Definition: explain.h:40
List * lappend(List *list, void *datum)
Definition: list.c:128
int numCols
Definition: plannodes.h:716
List * groupingSets
Definition: plannodes.h:762
unsigned int Index
Definition: c.h:365
Plan * plan
Definition: execnodes.h:1049
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1352
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:2816
ExplainFormat format
Definition: explain.h:38
List * targetlist
Definition: plannodes.h:132
AttrNumber * sortColIdx
Definition: plannodes.h:717
int i
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
#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:2056
Oid * collations
Definition: plannodes.h:719
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
static void show_grouping_sets ( PlanState planstate,
Agg agg,
List ancestors,
ExplainState es 
)
static

Definition at line 1940 of file explain.c.

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

Referenced by show_agg_keys().

1942 {
1943  List *context;
1944  bool useprefix;
1945  ListCell *lc;
1946 
1947  /* Set up deparsing context */
1949  (Node *) planstate,
1950  ancestors);
1951  useprefix = (list_length(es->rtable) > 1 || es->verbose);
1952 
1953  ExplainOpenGroup("Grouping Sets", "Grouping Sets", false, es);
1954 
1955  show_grouping_set_keys(planstate, agg, NULL,
1956  context, useprefix, ancestors, es);
1957 
1958  foreach(lc, agg->chain)
1959  {
1960  Agg *aggnode = lfirst(lc);
1961  Sort *sortnode = (Sort *) aggnode->plan.lefttree;
1962 
1963  show_grouping_set_keys(planstate, aggnode, sortnode,
1964  context, useprefix, ancestors, es);
1965  }
1966 
1967  ExplainCloseGroup("Grouping Sets", "Grouping Sets", false, es);
1968 }
Definition: nodes.h:518
List * deparse_cxt
Definition: explain.h:46
static void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3167
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:2968
static void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3230
Plan plan
Definition: plannodes.h:753
bool verbose
Definition: explain.h:32
#define NULL
Definition: c.h:229
#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:134
static void show_grouping_set_keys(PlanState *planstate, Agg *aggnode, Sort *sortnode, List *context, bool useprefix, List *ancestors, ExplainState *es)
Definition: explain.c:1971
List * chain
Definition: plannodes.h:763
Definition: plannodes.h:751
Definition: pg_list.h:45
List * rtable
Definition: explain.h:44
static void show_hash_info ( HashState hashstate,
ExplainState es 
)
static

Definition at line 2266 of file explain.c.

References appendStringInfo(), appendStringInfoSpaces(), EXPLAIN_FORMAT_TEXT, ExplainPropertyLong(), ExplainState::format, HashState::hashtable, ExplainState::indent, HashJoinTableData::nbatch, HashJoinTableData::nbatch_original, HashJoinTableData::nbuckets, HashJoinTableData::nbuckets_original, HashJoinTableData::spacePeak, and ExplainState::str.

Referenced by ExplainNode().

2267 {
2268  HashJoinTable hashtable;
2269 
2270  hashtable = hashstate->hashtable;
2271 
2272  if (hashtable)
2273  {
2274  long spacePeakKb = (hashtable->spacePeak + 1023) / 1024;
2275 
2276  if (es->format != EXPLAIN_FORMAT_TEXT)
2277  {
2278  ExplainPropertyLong("Hash Buckets", hashtable->nbuckets, es);
2279  ExplainPropertyLong("Original Hash Buckets",
2280  hashtable->nbuckets_original, es);
2281  ExplainPropertyLong("Hash Batches", hashtable->nbatch, es);
2282  ExplainPropertyLong("Original Hash Batches",
2283  hashtable->nbatch_original, es);
2284  ExplainPropertyLong("Peak Memory Usage", spacePeakKb, es);
2285  }
2286  else if (hashtable->nbatch_original != hashtable->nbatch ||
2287  hashtable->nbuckets_original != hashtable->nbuckets)
2288  {
2289  appendStringInfoSpaces(es->str, es->indent * 2);
2290  appendStringInfo(es->str,
2291  "Buckets: %d (originally %d) Batches: %d (originally %d) Memory Usage: %ldkB\n",
2292  hashtable->nbuckets,
2293  hashtable->nbuckets_original,
2294  hashtable->nbatch,
2295  hashtable->nbatch_original,
2296  spacePeakKb);
2297  }
2298  else
2299  {
2300  appendStringInfoSpaces(es->str, es->indent * 2);
2301  appendStringInfo(es->str,
2302  "Buckets: %d Batches: %d Memory Usage: %ldkB\n",
2303  hashtable->nbuckets, hashtable->nbatch,
2304  spacePeakKb);
2305  }
2306  }
2307 }
void ExplainPropertyLong(const char *qlabel, long value, ExplainState *es)
Definition: explain.c:3126
HashJoinTable hashtable
Definition: execnodes.h:2133
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
int indent
Definition: explain.h:40
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
static void show_instrumentation_count ( const char *  qlabel,
int  which,
PlanState planstate,
ExplainState es 
)
static

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

2343 {
2344  double nfiltered;
2345  double nloops;
2346 
2347  if (!es->analyze || !planstate->instrument)
2348  return;
2349 
2350  if (which == 2)
2351  nfiltered = planstate->instrument->nfiltered2;
2352  else
2353  nfiltered = planstate->instrument->nfiltered1;
2354  nloops = planstate->instrument->nloops;
2355 
2356  /* In text mode, suppress zero counts; they're not interesting enough */
2357  if (nfiltered > 0 || es->format != EXPLAIN_FORMAT_TEXT)
2358  {
2359  if (nloops > 0)
2360  ExplainPropertyFloat(qlabel, nfiltered / nloops, 0, es);
2361  else
2362  ExplainPropertyFloat(qlabel, 0.0, 0, es);
2363  }
2364 }
double nfiltered1
Definition: instrument.h:61
Instrumentation * instrument
Definition: execnodes.h:1055
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3139
bool analyze
Definition: explain.h:33
double nfiltered2
Definition: instrument.h:62
ExplainFormat format
Definition: explain.h:38
static void show_merge_append_keys ( MergeAppendState mstate,
List ancestors,
ExplainState es 
)
static

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

1903 {
1904  MergeAppend *plan = (MergeAppend *) mstate->ps.plan;
1905 
1906  show_sort_group_keys((PlanState *) mstate, "Sort Key",
1907  plan->numCols, plan->sortColIdx,
1908  plan->sortOperators, plan->collations,
1909  plan->nullsFirst,
1910  ancestors, es);
1911 }
Oid * collations
Definition: plannodes.h:255
Plan * plan
Definition: execnodes.h:1049
PlanState ps
Definition: execnodes.h:1211
AttrNumber * sortColIdx
Definition: plannodes.h:253
bool * nullsFirst
Definition: plannodes.h:256
Oid * sortOperators
Definition: plannodes.h:254
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:2056
static void show_modifytable_info ( ModifyTableState mtstate,
List ancestors,
ExplainState es 
)
static

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

2708 {
2709  ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
2710  const char *operation;
2711  const char *foperation;
2712  bool labeltargets;
2713  int j;
2714  List *idxNames = NIL;
2715  ListCell *lst;
2716 
2717  switch (node->operation)
2718  {
2719  case CMD_INSERT:
2720  operation = "Insert";
2721  foperation = "Foreign Insert";
2722  break;
2723  case CMD_UPDATE:
2724  operation = "Update";
2725  foperation = "Foreign Update";
2726  break;
2727  case CMD_DELETE:
2728  operation = "Delete";
2729  foperation = "Foreign Delete";
2730  break;
2731  default:
2732  operation = "???";
2733  foperation = "Foreign ???";
2734  break;
2735  }
2736 
2737  /* Should we explicitly label target relations? */
2738  labeltargets = (mtstate->mt_nplans > 1 ||
2739  (mtstate->mt_nplans == 1 &&
2740  mtstate->resultRelInfo->ri_RangeTableIndex != node->nominalRelation));
2741 
2742  if (labeltargets)
2743  ExplainOpenGroup("Target Tables", "Target Tables", false, es);
2744 
2745  for (j = 0; j < mtstate->mt_nplans; j++)
2746  {
2747  ResultRelInfo *resultRelInfo = mtstate->resultRelInfo + j;
2748  FdwRoutine *fdwroutine = resultRelInfo->ri_FdwRoutine;
2749 
2750  if (labeltargets)
2751  {
2752  /* Open a group for this target */
2753  ExplainOpenGroup("Target Table", NULL, true, es);
2754 
2755  /*
2756  * In text mode, decorate each target with operation type, so that
2757  * ExplainTargetRel's output of " on foo" will read nicely.
2758  */
2759  if (es->format == EXPLAIN_FORMAT_TEXT)
2760  {
2761  appendStringInfoSpaces(es->str, es->indent * 2);
2763  fdwroutine ? foperation : operation);
2764  }
2765 
2766  /* Identify target */
2767  ExplainTargetRel((Plan *) node,
2768  resultRelInfo->ri_RangeTableIndex,
2769  es);
2770 
2771  if (es->format == EXPLAIN_FORMAT_TEXT)
2772  {
2773  appendStringInfoChar(es->str, '\n');
2774  es->indent++;
2775  }
2776  }
2777 
2778  /* Give FDW a chance if needed */
2779  if (!resultRelInfo->ri_usesFdwDirectModify &&
2780  fdwroutine != NULL &&
2781  fdwroutine->ExplainForeignModify != NULL)
2782  {
2783  List *fdw_private = (List *) list_nth(node->fdwPrivLists, j);
2784 
2785  fdwroutine->ExplainForeignModify(mtstate,
2786  resultRelInfo,
2787  fdw_private,
2788  j,
2789  es);
2790  }
2791 
2792  if (labeltargets)
2793  {
2794  /* Undo the indentation we added in text format */
2795  if (es->format == EXPLAIN_FORMAT_TEXT)
2796  es->indent--;
2797 
2798  /* Close the group */
2799  ExplainCloseGroup("Target Table", NULL, true, es);
2800  }
2801  }
2802 
2803  /* Gather names of ON CONFLICT arbiter indexes */
2804  foreach(lst, node->arbiterIndexes)
2805  {
2806  char *indexname = get_rel_name(lfirst_oid(lst));
2807 
2808  idxNames = lappend(idxNames, indexname);
2809  }
2810 
2811  if (node->onConflictAction != ONCONFLICT_NONE)
2812  {
2813  ExplainProperty("Conflict Resolution",
2815  "NOTHING" : "UPDATE",
2816  false, es);
2817 
2818  /*
2819  * Don't display arbiter indexes at all when DO NOTHING variant
2820  * implicitly ignores all conflicts
2821  */
2822  if (idxNames)
2823  ExplainPropertyList("Conflict Arbiter Indexes", idxNames, es);
2824 
2825  /* ON CONFLICT DO UPDATE WHERE qual is specially displayed */
2826  if (node->onConflictWhere)
2827  {
2828  show_upper_qual((List *) node->onConflictWhere, "Conflict Filter",
2829  &mtstate->ps, ancestors, es);
2830  show_instrumentation_count("Rows Removed by Conflict Filter", 1, &mtstate->ps, es);
2831  }
2832 
2833  /* EXPLAIN ANALYZE display of actual outcome for each tuple proposed */
2834  if (es->analyze && mtstate->ps.instrument)
2835  {
2836  double total;
2837  double insert_path;
2838  double other_path;
2839 
2840  InstrEndLoop(mtstate->mt_plans[0]->instrument);
2841 
2842  /* count the number of source rows */
2843  total = mtstate->mt_plans[0]->instrument->ntuples;
2844  other_path = mtstate->ps.instrument->nfiltered2;
2845  insert_path = total - other_path;
2846 
2847  ExplainPropertyFloat("Tuples Inserted", insert_path, 0, es);
2848  ExplainPropertyFloat("Conflicting Tuples", other_path, 0, es);
2849  }
2850  }
2851 
2852  if (labeltargets)
2853  ExplainCloseGroup("Target Tables", "Target Tables", false, es);
2854 }
#define NIL
Definition: pg_list.h:69
List * arbiterIndexes
Definition: plannodes.h:220
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3055
Index nominalRelation
Definition: plannodes.h:207
Instrumentation * instrument
Definition: execnodes.h:1055
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1159
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3139
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:1872
Index ri_RangeTableIndex
Definition: execnodes.h:336
static void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3167
static void show_instrumentation_count(const char *qlabel, int which, PlanState *planstate, ExplainState *es)
Definition: explain.c:2341
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:114
PlanState ps
Definition: execnodes.h:1152
double nfiltered2
Definition: instrument.h:62
bool ri_usesFdwDirectModify
Definition: execnodes.h:347
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
void * list_nth(const List *list, int n)
Definition: list.c:410
List * fdwPrivLists
Definition: plannodes.h:215
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:345
static void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3230
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:201
PlanState ** mt_plans
Definition: execnodes.h:1156
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:2588
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
Plan * plan
Definition: execnodes.h:1049
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:2934
#define NULL
Definition: c.h:229
OnConflictAction onConflictAction
Definition: plannodes.h:219
ExplainFormat format
Definition: explain.h:38
CmdType operation
Definition: plannodes.h:205
ExplainForeignModify_function ExplainForeignModify
Definition: fdwapi.h:214
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1694
StringInfo str
Definition: explain.h:30
#define lfirst_oid(lc)
Definition: pg_list.h:108
Node * onConflictWhere
Definition: plannodes.h:222
static void show_plan_tlist ( PlanState planstate,
List ancestors,
ExplainState es 
)
static

Definition at line 1756 of file explain.c.

References CMD_SELECT, ExplainState::deparse_cxt, deparse_expression(), ExplainPropertyList(), TargetEntry::expr, IsA, lappend(), lfirst, list_length(), NIL, PlanState::plan, ExplainState::rtable, set_deparse_context_planstate(), and Plan::targetlist.

Referenced by ExplainNode().

1757 {
1758  Plan *plan = planstate->plan;
1759  List *context;
1760  List *result = NIL;
1761  bool useprefix;
1762  ListCell *lc;
1763 
1764  /* No work if empty tlist (this occurs eg in bitmap indexscans) */
1765  if (plan->targetlist == NIL)
1766  return;
1767  /* The tlist of an Append isn't real helpful, so suppress it */
1768  if (IsA(plan, Append))
1769  return;
1770  /* Likewise for MergeAppend and RecursiveUnion */
1771  if (IsA(plan, MergeAppend))
1772  return;
1773  if (IsA(plan, RecursiveUnion))
1774  return;
1775 
1776  /*
1777  * Likewise for ForeignScan that executes a direct INSERT/UPDATE/DELETE
1778  *
1779  * Note: the tlist for a ForeignScan that executes a direct INSERT/UPDATE
1780  * might contain subplan output expressions that are confusing in this
1781  * context. The tlist for a ForeignScan that executes a direct UPDATE/
1782  * DELETE always contains "junk" target columns to identify the exact row
1783  * to update or delete, which would be confusing in this context. So, we
1784  * suppress it in all the cases.
1785  */
1786  if (IsA(plan, ForeignScan) &&
1787  ((ForeignScan *) plan)->operation != CMD_SELECT)
1788  return;
1789 
1790  /* Set up deparsing context */
1792  (Node *) planstate,
1793  ancestors);
1794  useprefix = list_length(es->rtable) > 1;
1795 
1796  /* Deparse each result column (we now include resjunk ones) */
1797  foreach(lc, plan->targetlist)
1798  {
1799  TargetEntry *tle = (TargetEntry *) lfirst(lc);
1800 
1801  result = lappend(result,
1802  deparse_expression((Node *) tle->expr, context,
1803  useprefix, false));
1804  }
1805 
1806  /* Print results */
1807  ExplainPropertyList("Output", result, es);
1808 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:569
Definition: nodes.h:518
List * deparse_cxt
Definition: explain.h:46
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:2968
List * lappend(List *list, void *datum)
Definition: list.c:128
Plan * plan
Definition: execnodes.h:1049
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:2934
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1352
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:2816
static int list_length(const List *l)
Definition: pg_list.h:89
List * targetlist
Definition: plannodes.h:132
Definition: pg_list.h:45
List * rtable
Definition: explain.h:44
static void show_qual ( List qual,
const char *  qlabel,
PlanState planstate,
List ancestors,
bool  useprefix,
ExplainState es 
)
static

Definition at line 1837 of file explain.c.

References make_ands_explicit(), NIL, and show_expression().

Referenced by show_scan_qual(), and show_upper_qual().

1840 {
1841  Node *node;
1842 
1843  /* No work if empty qual */
1844  if (qual == NIL)
1845  return;
1846 
1847  /* Convert AND list to explicit AND */
1848  node = (Node *) make_ands_explicit(qual);
1849 
1850  /* And show it */
1851  show_expression(node, qlabel, planstate, ancestors, useprefix, es);
1852 }
#define NIL
Definition: pg_list.h:69
Definition: nodes.h:518
Expr * make_ands_explicit(List *andclauses)
Definition: clauses.c:366
static void show_expression(Node *node, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
Definition: explain.c:1814
static void show_scan_qual ( List qual,
const char *  qlabel,
PlanState planstate,
List ancestors,
ExplainState es 
)
static

Definition at line 1858 of file explain.c.

References IsA, PlanState::plan, show_qual(), and ExplainState::verbose.

Referenced by ExplainNode().

1861 {
1862  bool useprefix;
1863 
1864  useprefix = (IsA(planstate->plan, SubqueryScan) ||es->verbose);
1865  show_qual(qual, qlabel, planstate, ancestors, useprefix, es);
1866 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:569
static void show_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
Definition: explain.c:1837
bool verbose
Definition: explain.h:32
Plan * plan
Definition: execnodes.h:1049
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