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, QueryEnvironment *queryEnv)
 
static void report_triggers (ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
 
static double elapsed_time (instr_time *starttime)
 
static bool ExplainPreScanNode (PlanState *planstate, Bitmapset **rels_used)
 
static void ExplainNode (PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
 
static void show_plan_tlist (PlanState *planstate, List *ancestors, ExplainState *es)
 
static void show_expression (Node *node, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
 
static void show_qual (List *qual, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
 
static void show_scan_qual (List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
 
static void show_upper_qual (List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
 
static void show_sort_keys (SortState *sortstate, List *ancestors, ExplainState *es)
 
static void show_merge_append_keys (MergeAppendState *mstate, List *ancestors, ExplainState *es)
 
static void show_agg_keys (AggState *astate, List *ancestors, ExplainState *es)
 
static void show_grouping_sets (PlanState *planstate, Agg *agg, List *ancestors, ExplainState *es)
 
static void show_grouping_set_keys (PlanState *planstate, Agg *aggnode, Sort *sortnode, List *context, bool useprefix, List *ancestors, ExplainState *es)
 
static void show_group_keys (GroupState *gstate, List *ancestors, ExplainState *es)
 
static void show_sort_group_keys (PlanState *planstate, const char *qlabel, int nkeys, AttrNumber *keycols, Oid *sortOperators, Oid *collations, bool *nullsFirst, List *ancestors, ExplainState *es)
 
static void show_sortorder_options (StringInfo buf, Node *sortexpr, Oid sortOperator, Oid collation, bool nullsFirst)
 
static void show_tablesample (TableSampleClause *tsc, PlanState *planstate, List *ancestors, ExplainState *es)
 
static void show_sort_info (SortState *sortstate, ExplainState *es)
 
static void show_hash_info (HashState *hashstate, ExplainState *es)
 
static void show_tidbitmap_info (BitmapHeapScanState *planstate, ExplainState *es)
 
static void show_instrumentation_count (const char *qlabel, int which, PlanState *planstate, ExplainState *es)
 
static void show_foreignscan_info (ForeignScanState *fsstate, ExplainState *es)
 
static 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, QueryEnvironment *queryEnv, DestReceiver *dest)
 
ExplainStateNewExplainState (void)
 
TupleDesc ExplainResultDesc (ExplainStmt *stmt)
 
void ExplainOneUtility (Node *utilityStmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
 
void ExplainOnePlan (PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv, const instr_time *planduration)
 
void ExplainPrintPlan (ExplainState *es, QueryDesc *queryDesc)
 
void ExplainPrintTriggers (ExplainState *es, QueryDesc *queryDesc)
 
void ExplainQueryText (ExplainState *es, QueryDesc *queryDesc)
 
void ExplainPropertyList (const char *qlabel, List *data, ExplainState *es)
 
void ExplainPropertyListNested (const char *qlabel, List *data, ExplainState *es)
 
void ExplainPropertyText (const char *qlabel, const char *value, ExplainState *es)
 
void ExplainPropertyInteger (const char *qlabel, int value, ExplainState *es)
 
void ExplainPropertyLong (const char *qlabel, long value, ExplainState *es)
 
void ExplainPropertyFloat (const char *qlabel, double value, int ndigits, ExplainState *es)
 
void ExplainPropertyBool (const char *qlabel, bool value, ExplainState *es)
 
void 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 769 of file explain.c.

References INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, and INSTR_TIME_SUBTRACT.

Referenced by ExplainOnePlan(), and IsCheckpointOnSchedule().

770 {
771  instr_time endtime;
772 
773  INSTR_TIME_SET_CURRENT(endtime);
774  INSTR_TIME_SUBTRACT(endtime, *starttime);
775  return INSTR_TIME_GET_DOUBLE(endtime);
776 }
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 3523 of file explain.c.

References escape_json().

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

3524 {
3525  escape_json(buf, str);
3526 }
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 2439 of file explain.c.

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

Referenced by ExplainIndexScanDetails(), and ExplainNode().

2440 {
2441  const char *result;
2442 
2444  result = (*explain_get_index_name_hook) (indexId);
2445  else
2446  result = NULL;
2447  if (result == NULL)
2448  {
2449  /* default behavior: look in the catalogs and quote it */
2450  result = get_rel_name(indexId);
2451  if (result == NULL)
2452  elog(ERROR, "cache lookup failed for index %u", indexId);
2453  result = quote_identifier(result);
2454  }
2455  return result;
2456 }
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10404
return result
Definition: formatting.c:1633
#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:1726
void ExplainBeginOutput ( ExplainState es)

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

3363 {
3364  switch (es->format)
3365  {
3366  case EXPLAIN_FORMAT_TEXT:
3367  /* nothing to do */
3368  break;
3369 
3370  case EXPLAIN_FORMAT_XML:
3372  "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
3373  es->indent++;
3374  break;
3375 
3376  case EXPLAIN_FORMAT_JSON:
3377  /* top-level structure is an array of plans */
3378  appendStringInfoChar(es->str, '[');
3379  es->grouping_stack = lcons_int(0, es->grouping_stack);
3380  es->indent++;
3381  break;
3382 
3383  case EXPLAIN_FORMAT_YAML:
3384  es->grouping_stack = lcons_int(0, es->grouping_stack);
3385  break;
3386  }
3387 }
List * lcons_int(int datum, List *list)
Definition: list.c:277
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
static void ExplainCloseGroup ( const char *  objtype,
const char *  labelname,
bool  labeled,
ExplainState es 
)
static

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

3282 {
3283  switch (es->format)
3284  {
3285  case EXPLAIN_FORMAT_TEXT:
3286  /* nothing to do */
3287  break;
3288 
3289  case EXPLAIN_FORMAT_XML:
3290  es->indent--;
3291  ExplainXMLTag(objtype, X_CLOSING, es);
3292  break;
3293 
3294  case EXPLAIN_FORMAT_JSON:
3295  es->indent--;
3296  appendStringInfoChar(es->str, '\n');
3297  appendStringInfoSpaces(es->str, 2 * es->indent);
3298  appendStringInfoChar(es->str, labeled ? '}' : ']');
3300  break;
3301 
3302  case EXPLAIN_FORMAT_YAML:
3303  es->indent--;
3305  break;
3306  }
3307 }
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3451
#define X_CLOSING
Definition: explain.c:52
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
List * list_delete_first(List *list)
Definition: list.c:666
static void ExplainCustomChildren ( CustomScanState css,
List ancestors,
ExplainState es 
)
static

Definition at line 2969 of file explain.c.

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

Referenced by ExplainNode().

2970 {
2971  ListCell *cell;
2972  const char *label =
2973  (list_length(css->custom_ps) != 1 ? "children" : "child");
2974 
2975  foreach(cell, css->custom_ps)
2976  ExplainNode((PlanState *) lfirst(cell), ancestors, label, NULL, es);
2977 }
List * custom_ps
Definition: execnodes.h:1550
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:853
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 3316 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().

3317 {
3318  switch (es->format)
3319  {
3320  case EXPLAIN_FORMAT_TEXT:
3321  /* nothing to do */
3322  break;
3323 
3324  case EXPLAIN_FORMAT_XML:
3325  ExplainXMLTag(objtype, X_CLOSE_IMMEDIATE, es);
3326  break;
3327 
3328  case EXPLAIN_FORMAT_JSON:
3330  appendStringInfoSpaces(es->str, 2 * es->indent);
3331  if (labelname)
3332  {
3333  escape_json(es->str, labelname);
3334  appendStringInfoString(es->str, ": ");
3335  }
3336  escape_json(es->str, objtype);
3337  break;
3338 
3339  case EXPLAIN_FORMAT_YAML:
3341  if (labelname)
3342  {
3343  escape_yaml(es->str, labelname);
3344  appendStringInfoString(es->str, ": ");
3345  }
3346  else
3347  {
3348  appendStringInfoString(es->str, "- ");
3349  }
3350  escape_yaml(es->str, objtype);
3351  break;
3352  }
3353 }
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:3451
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3498
int indent
Definition: explain.h:40
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3523
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3478
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 3393 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().

3394 {
3395  switch (es->format)
3396  {
3397  case EXPLAIN_FORMAT_TEXT:
3398  /* nothing to do */
3399  break;
3400 
3401  case EXPLAIN_FORMAT_XML:
3402  es->indent--;
3403  appendStringInfoString(es->str, "</explain>");
3404  break;
3405 
3406  case EXPLAIN_FORMAT_JSON:
3407  es->indent--;
3408  appendStringInfoString(es->str, "\n]");
3410  break;
3411 
3412  case EXPLAIN_FORMAT_YAML:
3414  break;
3415  }
3416 }
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
List * list_delete_first(List *list)
Definition: list.c:666
static void ExplainIndexScanDetails ( Oid  indexid,
ScanDirection  indexorderdir,
ExplainState es 
)
static

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

2574 {
2575  const char *indexname = explain_get_index_name(indexid);
2576 
2577  if (es->format == EXPLAIN_FORMAT_TEXT)
2578  {
2579  if (ScanDirectionIsBackward(indexorderdir))
2580  appendStringInfoString(es->str, " Backward");
2581  appendStringInfo(es->str, " using %s", indexname);
2582  }
2583  else
2584  {
2585  const char *scandir;
2586 
2587  switch (indexorderdir)
2588  {
2589  case BackwardScanDirection:
2590  scandir = "Backward";
2591  break;
2593  scandir = "NoMovement";
2594  break;
2595  case ForwardScanDirection:
2596  scandir = "Forward";
2597  break;
2598  default:
2599  scandir = "???";
2600  break;
2601  }
2602  ExplainPropertyText("Scan Direction", scandir, es);
2603  ExplainPropertyText("Index Name", indexname, es);
2604  }
2605 }
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3155
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
ExplainFormat format
Definition: explain.h:38
static const char * explain_get_index_name(Oid indexId)
Definition: explain.c:2439
StringInfo str
Definition: explain.h:30
static void ExplainJSONLineEnding ( ExplainState es)
static

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

3479 {
3481  if (linitial_int(es->grouping_stack) != 0)
3482  appendStringInfoChar(es->str, ',');
3483  else
3484  linitial_int(es->grouping_stack) = 1;
3485  appendStringInfoChar(es->str, '\n');
3486 }
#define linitial_int(l)
Definition: pg_list.h:112
List * grouping_stack
Definition: explain.h:41
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
#define Assert(condition)
Definition: c.h: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 2917 of file explain.c.

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

Referenced by ExplainNode().

2919 {
2920  int nplans = list_length(plans);
2921  int j;
2922 
2923  for (j = 0; j < nplans; j++)
2924  ExplainNode(planstates[j], ancestors,
2925  "Member", NULL, es);
2926 }
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:853
#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 2624 of file explain.c.

References ExplainTargetRel(), and ModifyTable::nominalRelation.

Referenced by ExplainNode().

2625 {
2626  ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
2627 }
Index nominalRelation
Definition: plannodes.h:219
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:2633
static void ExplainNode ( PlanState planstate,
List ancestors,
const char *  relationship,
const char *  plan_name,
ExplainState es 
)
static

Definition at line 853 of file explain.c.

References AGG_HASHED, AGG_MIXED, AGG_PLAIN, AGG_SORTED, Agg::aggsplit, Agg::aggstrategy, ExplainState::analyze, appendStringInfo(), appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), ExplainState::buffers, Instrumentation::bufusage, castNode, CMD_DELETE, CMD_INSERT, CMD_SELECT, CMD_UPDATE, ExplainState::costs, DO_AGGSPLIT_COMBINE, DO_AGGSPLIT_SKIPFINAL, EXPLAIN_FORMAT_TEXT, explain_get_index_name(), ExplainCloseGroup(), ExplainCustomChildren(), CustomExecMethods::ExplainCustomScan, ExplainIndexScanDetails(), ExplainMemberNodes(), ExplainModifyTarget(), ExplainOpenGroup(), ExplainPropertyBool(), ExplainPropertyFloat(), ExplainPropertyInteger(), ExplainPropertyLong(), ExplainPropertyText(), ExplainScanTarget(), ExplainSubPlans(), ExplainState::format, RangeTblFunction::funcexpr, functions, ExplainState::indent, IndexScan::indexid, IndexOnlyScan::indexid, BitmapIndexScan::indexid, IndexScan::indexorderdir, IndexOnlyScan::indexorderdir, 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_NamedTuplestoreScan, T_NestLoop, T_ProjectSet, T_RecursiveUnion, T_Result, T_SampleScan, T_SeqScan, T_SetOp, T_Sort, T_SubqueryScan, T_TableFuncScan, T_TidScan, T_Unique, T_ValuesScan, T_WindowAgg, T_WorkTableScan, ExplainState::timing, Instrumentation::total, Plan::total_cost, ExplainState::verbose, and PlanState::worker_instrument.

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

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

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

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

Definition at line 341 of file explain.c.

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

Referenced by ExplainOneUtility(), and ExplainQuery().

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

Definition at line 390 of file explain.c.

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

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

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

3219 {
3220  switch (es->format)
3221  {
3222  case EXPLAIN_FORMAT_TEXT:
3223  /* nothing to do */
3224  break;
3225 
3226  case EXPLAIN_FORMAT_XML:
3227  ExplainXMLTag(objtype, X_OPENING, es);
3228  es->indent++;
3229  break;
3230 
3231  case EXPLAIN_FORMAT_JSON:
3233  appendStringInfoSpaces(es->str, 2 * es->indent);
3234  if (labelname)
3235  {
3236  escape_json(es->str, labelname);
3237  appendStringInfoString(es->str, ": ");
3238  }
3239  appendStringInfoChar(es->str, labeled ? '{' : '[');
3240 
3241  /*
3242  * In JSON format, the grouping_stack is an integer list. 0 means
3243  * we've emitted nothing at this grouping level, 1 means we've
3244  * emitted something (and so the next item needs a comma). See
3245  * ExplainJSONLineEnding().
3246  */
3247  es->grouping_stack = lcons_int(0, es->grouping_stack);
3248  es->indent++;
3249  break;
3250 
3251  case EXPLAIN_FORMAT_YAML:
3252 
3253  /*
3254  * In YAML format, the grouping stack is an integer list. 0 means
3255  * we've emitted nothing at this grouping level AND this grouping
3256  * level is unlabelled and must be marked with "- ". See
3257  * ExplainYAMLLineStarting().
3258  */
3260  if (labelname)
3261  {
3262  appendStringInfo(es->str, "%s: ", labelname);
3263  es->grouping_stack = lcons_int(1, es->grouping_stack);
3264  }
3265  else
3266  {
3267  appendStringInfoString(es->str, "- ");
3268  es->grouping_stack = lcons_int(0, es->grouping_stack);
3269  }
3270  es->indent++;
3271  break;
3272  }
3273 }
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:3451
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3498
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3478
#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 788 of file explain.c.

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

Referenced by ExplainPrintPlan().

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

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

618 {
619  Bitmapset *rels_used = NULL;
620  PlanState *ps;
621 
622  /* Set up ExplainState fields associated with this plan tree */
623  Assert(queryDesc->plannedstmt != NULL);
624  es->pstmt = queryDesc->plannedstmt;
625  es->rtable = queryDesc->plannedstmt->rtable;
626  ExplainPreScanNode(queryDesc->planstate, &rels_used);
629  es->rtable_names);
630  es->printed_subplans = NULL;
631 
632  /*
633  * Sometimes we mark a Gather node as "invisible", which means that it's
634  * not displayed in EXPLAIN output. The purpose of this is to allow
635  * running regression tests with force_parallel_mode=regress to get the
636  * same results as running the same tests with force_parallel_mode=off.
637  */
638  ps = queryDesc->planstate;
639  if (IsA(ps, GatherState) &&((Gather *) ps->plan)->invisible)
640  ps = outerPlanState(ps);
641  ExplainNode(ps, NIL, NULL, NULL, es);
642 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
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:3160
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:853
PlanState * planstate
Definition: execdesc.h:49
#define outerPlanState(node)
Definition: execnodes.h:874
Plan * plan
Definition: execnodes.h:832
#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:788
PlannedStmt * plannedstmt
Definition: execdesc.h:37
List * deparse_context_for_plan_rtable(List *rtable, List *rtable_names)
Definition: ruleutils.c:3085
List * rtable
Definition: explain.h:44
void ExplainPrintTriggers ( ExplainState es,
QueryDesc queryDesc 
)

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

655 {
656  ResultRelInfo *rInfo;
657  bool show_relname;
658  int numrels = queryDesc->estate->es_num_result_relations;
659  List *targrels = queryDesc->estate->es_trig_target_relations;
660  int nr;
661  ListCell *l;
662 
663  ExplainOpenGroup("Triggers", "Triggers", false, es);
664 
665  show_relname = (numrels > 1 || targrels != NIL);
666  rInfo = queryDesc->estate->es_result_relations;
667  for (nr = 0; nr < numrels; rInfo++, nr++)
668  report_triggers(rInfo, show_relname, es);
669 
670  foreach(l, targrels)
671  {
672  rInfo = (ResultRelInfo *) lfirst(l);
673  report_triggers(rInfo, show_relname, es);
674  }
675 
676  ExplainCloseGroup("Triggers", "Triggers", false, es);
677 }
#define NIL
Definition: pg_list.h:69
EState * estate
Definition: execdesc.h:48
static void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3217
ResultRelInfo * es_result_relations
Definition: execnodes.h:441
static void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3280
static void report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
Definition: explain.c:699
List * es_trig_target_relations
Definition: execnodes.h:456
int es_num_result_relations
Definition: execnodes.h:442
#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 3105 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().

3107 {
3108  switch (es->format)
3109  {
3110  case EXPLAIN_FORMAT_TEXT:
3111  appendStringInfoSpaces(es->str, es->indent * 2);
3112  appendStringInfo(es->str, "%s: %s\n", qlabel, value);
3113  break;
3114 
3115  case EXPLAIN_FORMAT_XML:
3116  {
3117  char *str;
3118 
3119  appendStringInfoSpaces(es->str, es->indent * 2);
3120  ExplainXMLTag(qlabel, X_OPENING | X_NOWHITESPACE, es);
3121  str = escape_xml(value);
3122  appendStringInfoString(es->str, str);
3123  pfree(str);
3124  ExplainXMLTag(qlabel, X_CLOSING | X_NOWHITESPACE, es);
3125  appendStringInfoChar(es->str, '\n');
3126  }
3127  break;
3128 
3129  case EXPLAIN_FORMAT_JSON:
3131  appendStringInfoSpaces(es->str, es->indent * 2);
3132  escape_json(es->str, qlabel);
3133  appendStringInfoString(es->str, ": ");
3134  if (numeric)
3136  else
3137  escape_json(es->str, value);
3138  break;
3139 
3140  case EXPLAIN_FORMAT_YAML:
3142  appendStringInfo(es->str, "%s: ", qlabel);
3143  if (numeric)
3145  else
3146  escape_yaml(es->str, value);
3147  break;
3148  }
3149 }
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:3451
#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:78
static struct @121 value
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3498
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3523
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3478
#define X_OPENING
Definition: explain.c:51
#define X_NOWHITESPACE
Definition: explain.c:54
ExplainFormat format
Definition: explain.h:38
char * escape_xml(const char *str)
Definition: xml.c:2232
StringInfo str
Definition: explain.h:30
void ExplainPropertyBool ( const char *  qlabel,
bool  value,
ExplainState es 
)

Definition at line 3202 of file explain.c.

References ExplainProperty().

Referenced by ExplainNode().

3203 {
3204  ExplainProperty(qlabel, value ? "true" : "false", true, es);
3205 }
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3105
static struct @121 value
void ExplainPropertyFloat ( const char *  qlabel,
double  value,
int  ndigits,
ExplainState es 
)

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

3191 {
3192  char buf[256];
3193 
3194  snprintf(buf, sizeof(buf), "%.*f", ndigits, value);
3195  ExplainProperty(qlabel, buf, true, es);
3196 }
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3105
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static struct @121 value
static char * buf
Definition: pg_test_fsync.c:66
void ExplainPropertyInteger ( const char *  qlabel,
int  value,
ExplainState es 
)

Definition at line 3164 of file explain.c.

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

Referenced by ExplainNode().

3165 {
3166  char buf[32];
3167 
3168  snprintf(buf, sizeof(buf), "%d", value);
3169  ExplainProperty(qlabel, buf, true, es);
3170 }
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3105
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static struct @121 value
static char * buf
Definition: pg_test_fsync.c:66
void ExplainPropertyList ( const char *  qlabel,
List data,
ExplainState es 
)

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

2985 {
2986  ListCell *lc;
2987  bool first = true;
2988 
2989  switch (es->format)
2990  {
2991  case EXPLAIN_FORMAT_TEXT:
2992  appendStringInfoSpaces(es->str, es->indent * 2);
2993  appendStringInfo(es->str, "%s: ", qlabel);
2994  foreach(lc, data)
2995  {
2996  if (!first)
2997  appendStringInfoString(es->str, ", ");
2998  appendStringInfoString(es->str, (const char *) lfirst(lc));
2999  first = false;
3000  }
3001  appendStringInfoChar(es->str, '\n');
3002  break;
3003 
3004  case EXPLAIN_FORMAT_XML:
3005  ExplainXMLTag(qlabel, X_OPENING, es);
3006  foreach(lc, data)
3007  {
3008  char *str;
3009 
3010  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
3011  appendStringInfoString(es->str, "<Item>");
3012  str = escape_xml((const char *) lfirst(lc));
3013  appendStringInfoString(es->str, str);
3014  pfree(str);
3015  appendStringInfoString(es->str, "</Item>\n");
3016  }
3017  ExplainXMLTag(qlabel, X_CLOSING, es);
3018  break;
3019 
3020  case EXPLAIN_FORMAT_JSON:
3022  appendStringInfoSpaces(es->str, es->indent * 2);
3023  escape_json(es->str, qlabel);
3024  appendStringInfoString(es->str, ": [");
3025  foreach(lc, data)
3026  {
3027  if (!first)
3028  appendStringInfoString(es->str, ", ");
3029  escape_json(es->str, (const char *) lfirst(lc));
3030  first = false;
3031  }
3032  appendStringInfoChar(es->str, ']');
3033  break;
3034 
3035  case EXPLAIN_FORMAT_YAML:
3037  appendStringInfo(es->str, "%s: ", qlabel);
3038  foreach(lc, data)
3039  {
3040  appendStringInfoChar(es->str, '\n');
3041  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
3042  appendStringInfoString(es->str, "- ");
3043  escape_yaml(es->str, (const char *) lfirst(lc));
3044  }
3045  break;
3046  }
3047 }
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:3451
#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:78
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3498
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3523
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3478
#define X_OPENING
Definition: explain.c:51
#define lfirst(lc)
Definition: pg_list.h:106
ExplainFormat format
Definition: explain.h:38
char * escape_xml(const char *str)
Definition: xml.c:2232
StringInfo str
Definition: explain.h:30
void ExplainPropertyListNested ( const char *  qlabel,
List data,
ExplainState es 
)

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

3055 {
3056  ListCell *lc;
3057  bool first = true;
3058 
3059  switch (es->format)
3060  {
3061  case EXPLAIN_FORMAT_TEXT:
3062  case EXPLAIN_FORMAT_XML:
3063  ExplainPropertyList(qlabel, data, es);
3064  return;
3065 
3066  case EXPLAIN_FORMAT_JSON:
3068  appendStringInfoSpaces(es->str, es->indent * 2);
3069  appendStringInfoChar(es->str, '[');
3070  foreach(lc, data)
3071  {
3072  if (!first)
3073  appendStringInfoString(es->str, ", ");
3074  escape_json(es->str, (const char *) lfirst(lc));
3075  first = false;
3076  }
3077  appendStringInfoChar(es->str, ']');
3078  break;
3079 
3080  case EXPLAIN_FORMAT_YAML:
3082  appendStringInfoString(es->str, "- [");
3083  foreach(lc, data)
3084  {
3085  if (!first)
3086  appendStringInfoString(es->str, ", ");
3087  escape_yaml(es->str, (const char *) lfirst(lc));
3088  first = false;
3089  }
3090  appendStringInfoChar(es->str, ']');
3091  break;
3092  }
3093 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2433
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3498
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3523
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3478
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:2984
#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 3176 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().

3177 {
3178  char buf[32];
3179 
3180  snprintf(buf, sizeof(buf), "%ld", value);
3181  ExplainProperty(qlabel, buf, true, es);
3182 }
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3105
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static struct @121 value
static char * buf
Definition: pg_test_fsync.c:66
void ExplainPropertyText ( const char *  qlabel,
const char *  value,
ExplainState es 
)

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

3156 {
3157  ExplainProperty(qlabel, value, false, es);
3158 }
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3105
static struct @121 value
void ExplainQuery ( ParseState pstate,
ExplainStmt stmt,
const char *  queryString,
ParamListInfo  params,
QueryEnvironment queryEnv,
DestReceiver dest 
)

Definition at line 145 of file explain.c.

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

Referenced by standard_ProcessUtility().

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

Definition at line 688 of file explain.c.

References ExplainPropertyText(), and QueryDesc::sourceText.

Referenced by explain_ExecutorEnd().

689 {
690  if (queryDesc->sourceText)
691  ExplainPropertyText("Query Text", queryDesc->sourceText, es);
692 }
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3155
const char * sourceText
Definition: execdesc.h:38
TupleDesc ExplainResultDesc ( ExplainStmt stmt)

Definition at line 302 of file explain.c.

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

Referenced by ExplainQuery(), and UtilityTupleDescriptor().

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

Definition at line 2611 of file explain.c.

References ExplainTargetRel(), and Scan::scanrelid.

Referenced by ExplainNode().

2612 {
2613  ExplainTargetRel((Plan *) plan, plan->scanrelid, es);
2614 }
Index scanrelid
Definition: plannodes.h:329
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:2633
void ExplainSeparatePlans ( ExplainState es)

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

3423 {
3424  switch (es->format)
3425  {
3426  case EXPLAIN_FORMAT_TEXT:
3427  /* add a blank line */
3428  appendStringInfoChar(es->str, '\n');
3429  break;
3430 
3431  case EXPLAIN_FORMAT_XML:
3432  case EXPLAIN_FORMAT_JSON:
3433  case EXPLAIN_FORMAT_YAML:
3434  /* nothing to do */
3435  break;
3436  }
3437 }
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
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 2935 of file explain.c.

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

Referenced by ExplainNode().

2937 {
2938  ListCell *lst;
2939 
2940  foreach(lst, plans)
2941  {
2942  SubPlanState *sps = (SubPlanState *) lfirst(lst);
2943  SubPlan *sp = sps->subplan;
2944 
2945  /*
2946  * There can be multiple SubPlan nodes referencing the same physical
2947  * subplan (same plan_id, which is its index in PlannedStmt.subplans).
2948  * We should print a subplan only once, so track which ones we already
2949  * printed. This state must be global across the plan tree, since the
2950  * duplicate nodes could be in different plan nodes, eg both a bitmap
2951  * indexscan's indexqual and its parent heapscan's recheck qual. (We
2952  * do not worry too much about which plan node we show the subplan as
2953  * attached to in such cases.)
2954  */
2955  if (bms_is_member(sp->plan_id, es->printed_subplans))
2956  continue;
2958  sp->plan_id);
2959 
2960  ExplainNode(sps->planstate, ancestors,
2961  relationship, sp->plan_name, es);
2962  }
2963 }
int plan_id
Definition: primnodes.h:689
Bitmapset * printed_subplans
Definition: explain.h:47
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:853
struct PlanState * planstate
Definition: execnodes.h:755
SubPlan * subplan
Definition: execnodes.h:754
char * plan_name
Definition: primnodes.h:691
#define lfirst(lc)
Definition: pg_list.h:106
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420
static void ExplainTargetRel ( Plan plan,
Index  rti,
ExplainState es 
)
static

Definition at line 2633 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_NAMEDTUPLESTORE, RTE_RELATION, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, ExplainState::str, T_BitmapHeapScan, T_CteScan, T_CustomScan, T_ForeignScan, T_FunctionScan, T_IndexOnlyScan, T_IndexScan, T_ModifyTable, T_NamedTuplestoreScan, T_SampleScan, T_SeqScan, T_TableFuncScan, T_TidScan, T_ValuesScan, T_WorkTableScan, and ExplainState::verbose.

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

2634 {
2635  char *objectname = NULL;
2636  char *namespace = NULL;
2637  const char *objecttag = NULL;
2638  RangeTblEntry *rte;
2639  char *refname;
2640 
2641  rte = rt_fetch(rti, es->rtable);
2642  refname = (char *) list_nth(es->rtable_names, rti - 1);
2643  if (refname == NULL)
2644  refname = rte->eref->aliasname;
2645 
2646  switch (nodeTag(plan))
2647  {
2648  case T_SeqScan:
2649  case T_SampleScan:
2650  case T_IndexScan:
2651  case T_IndexOnlyScan:
2652  case T_BitmapHeapScan:
2653  case T_TidScan:
2654  case T_ForeignScan:
2655  case T_CustomScan:
2656  case T_ModifyTable:
2657  /* Assert it's on a real relation */
2658  Assert(rte->rtekind == RTE_RELATION);
2659  objectname = get_rel_name(rte->relid);
2660  if (es->verbose)
2661  namespace = get_namespace_name(get_rel_namespace(rte->relid));
2662  objecttag = "Relation Name";
2663  break;
2664  case T_FunctionScan:
2665  {
2666  FunctionScan *fscan = (FunctionScan *) plan;
2667 
2668  /* Assert it's on a RangeFunction */
2669  Assert(rte->rtekind == RTE_FUNCTION);
2670 
2671  /*
2672  * If the expression is still a function call of a single
2673  * function, we can get the real name of the function.
2674  * Otherwise, punt. (Even if it was a single function call
2675  * originally, the optimizer could have simplified it away.)
2676  */
2677  if (list_length(fscan->functions) == 1)
2678  {
2679  RangeTblFunction *rtfunc = (RangeTblFunction *) linitial(fscan->functions);
2680 
2681  if (IsA(rtfunc->funcexpr, FuncExpr))
2682  {
2683  FuncExpr *funcexpr = (FuncExpr *) rtfunc->funcexpr;
2684  Oid funcid = funcexpr->funcid;
2685 
2686  objectname = get_func_name(funcid);
2687  if (es->verbose)
2688  namespace =
2690  }
2691  }
2692  objecttag = "Function Name";
2693  }
2694  break;
2695  case T_TableFuncScan:
2696  Assert(rte->rtekind == RTE_TABLEFUNC);
2697  objectname = "xmltable";
2698  objecttag = "Table Function Name";
2699  break;
2700  case T_ValuesScan:
2701  Assert(rte->rtekind == RTE_VALUES);
2702  break;
2703  case T_CteScan:
2704  /* Assert it's on a non-self-reference CTE */
2705  Assert(rte->rtekind == RTE_CTE);
2706  Assert(!rte->self_reference);
2707  objectname = rte->ctename;
2708  objecttag = "CTE Name";
2709  break;
2710  case T_NamedTuplestoreScan:
2712  objectname = rte->enrname;
2713  objecttag = "Tuplestore Name";
2714  break;
2715  case T_WorkTableScan:
2716  /* Assert it's on a self-reference CTE */
2717  Assert(rte->rtekind == RTE_CTE);
2718  Assert(rte->self_reference);
2719  objectname = rte->ctename;
2720  objecttag = "CTE Name";
2721  break;
2722  default:
2723  break;
2724  }
2725 
2726  if (es->format == EXPLAIN_FORMAT_TEXT)
2727  {
2728  appendStringInfoString(es->str, " on");
2729  if (namespace != NULL)
2730  appendStringInfo(es->str, " %s.%s", quote_identifier(namespace),
2731  quote_identifier(objectname));
2732  else if (objectname != NULL)
2733  appendStringInfo(es->str, " %s", quote_identifier(objectname));
2734  if (objectname == NULL || strcmp(refname, objectname) != 0)
2735  appendStringInfo(es->str, " %s", quote_identifier(refname));
2736  }
2737  else
2738  {
2739  if (objecttag != NULL && objectname != NULL)
2740  ExplainPropertyText(objecttag, objectname, es);
2741  if (namespace != NULL)
2742  ExplainPropertyText("Schema", namespace, es);
2743  ExplainPropertyText("Alias", refname, es);
2744  }
2745 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10404
Oid get_func_namespace(Oid funcid)
Definition: lsyscache.c:1436
List * functions
Definition: plannodes.h:508
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1750
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:3155
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
#define linitial(l)
Definition: pg_list.h:111
Oid funcid
Definition: primnodes.h:449
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1412
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3033
void * list_nth(const List *list, int n)
Definition: list.c:410
char * enrname
Definition: parsenodes.h:1036
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
bool self_reference
Definition: parsenodes.h:1016
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:514
RTEKind rtekind
Definition: parsenodes.h:944
char * ctename
Definition: parsenodes.h:1014
Alias * eref
Definition: parsenodes.h:1043
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
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 3451 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().

3452 {
3453  const char *s;
3454  const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
3455 
3456  if ((flags & X_NOWHITESPACE) == 0)
3457  appendStringInfoSpaces(es->str, 2 * es->indent);
3458  appendStringInfoCharMacro(es->str, '<');
3459  if ((flags & X_CLOSING) != 0)
3460  appendStringInfoCharMacro(es->str, '/');
3461  for (s = tagname; *s; s++)
3462  appendStringInfoChar(es->str, strchr(valid, *s) ? *s : '-');
3463  if ((flags & X_CLOSE_IMMEDIATE) != 0)
3464  appendStringInfoString(es->str, " /");
3465  appendStringInfoCharMacro(es->str, '>');
3466  if ((flags & X_NOWHITESPACE) == 0)
3467  appendStringInfoCharMacro(es->str, '\n');
3468 }
#define X_CLOSING
Definition: explain.c:52
#define appendStringInfoCharMacro(str, ch)
Definition: stringinfo.h:127
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
#define X_NOWHITESPACE
Definition: explain.c:54
#define X_CLOSE_IMMEDIATE
Definition: explain.c:53
StringInfo str
Definition: explain.h:30
static void ExplainYAMLLineStarting ( ExplainState es)
static

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

3499 {
3501  if (linitial_int(es->grouping_stack) == 0)
3502  {
3503  linitial_int(es->grouping_stack) = 1;
3504  }
3505  else
3506  {
3507  appendStringInfoChar(es->str, '\n');
3508  appendStringInfoSpaces(es->str, es->indent * 2);
3509  }
3510 }
#define linitial_int(l)
Definition: pg_list.h:112
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
#define Assert(condition)
Definition: c.h:675
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
ExplainState* NewExplainState ( void  )

Definition at line 285 of file explain.c.

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

Referenced by explain_ExecutorEnd(), and ExplainQuery().

286 {
287  ExplainState *es = (ExplainState *) palloc0(sizeof(ExplainState));
288 
289  /* Set default options (most fields can be left as zeroes). */
290  es->costs = true;
291  /* Prepare output buffer. */
292  es->str = makeStringInfo();
293 
294  return es;
295 }
StringInfo makeStringInfo(void)
Definition: stringinfo.c:28
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 699 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().

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

1951 {
1952  Agg *plan = (Agg *) astate->ss.ps.plan;
1953 
1954  if (plan->numCols > 0 || plan->groupingSets)
1955  {
1956  /* The key columns refer to the tlist of the child plan */
1957  ancestors = lcons(astate, ancestors);
1958 
1959  if (plan->groupingSets)
1960  show_grouping_sets(outerPlanState(astate), plan, ancestors, es);
1961  else
1962  show_sort_group_keys(outerPlanState(astate), "Group Key",
1963  plan->numCols, plan->grpColIdx,
1964  NULL, NULL, NULL,
1965  ancestors, es);
1966 
1967  ancestors = list_delete_first(ancestors);
1968  }
1969 }
int numCols
Definition: plannodes.h:785
AttrNumber * grpColIdx
Definition: plannodes.h:786
ScanState ss
Definition: execnodes.h:1762
PlanState ps
Definition: execnodes.h:1079
#define outerPlanState(node)
Definition: execnodes.h:874
static void show_grouping_sets(PlanState *planstate, Agg *agg, List *ancestors, ExplainState *es)
Definition: explain.c:1972
List * groupingSets
Definition: plannodes.h:791
Plan * plan
Definition: execnodes.h:832
List * lcons(void *datum, List *list)
Definition: list.c:259
#define NULL
Definition: c.h:229
Definition: plannodes.h:780
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:2101
List * list_delete_first(List *list)
Definition: list.c:666
static void show_buffer_usage ( ExplainState es,
const BufferUsage usage 
)
static

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

2463 {
2464  if (es->format == EXPLAIN_FORMAT_TEXT)
2465  {
2466  bool has_shared = (usage->shared_blks_hit > 0 ||
2467  usage->shared_blks_read > 0 ||
2468  usage->shared_blks_dirtied > 0 ||
2469  usage->shared_blks_written > 0);
2470  bool has_local = (usage->local_blks_hit > 0 ||
2471  usage->local_blks_read > 0 ||
2472  usage->local_blks_dirtied > 0 ||
2473  usage->local_blks_written > 0);
2474  bool has_temp = (usage->temp_blks_read > 0 ||
2475  usage->temp_blks_written > 0);
2476  bool has_timing = (!INSTR_TIME_IS_ZERO(usage->blk_read_time) ||
2478 
2479  /* Show only positive counter values. */
2480  if (has_shared || has_local || has_temp)
2481  {
2482  appendStringInfoSpaces(es->str, es->indent * 2);
2483  appendStringInfoString(es->str, "Buffers:");
2484 
2485  if (has_shared)
2486  {
2487  appendStringInfoString(es->str, " shared");
2488  if (usage->shared_blks_hit > 0)
2489  appendStringInfo(es->str, " hit=%ld",
2490  usage->shared_blks_hit);
2491  if (usage->shared_blks_read > 0)
2492  appendStringInfo(es->str, " read=%ld",
2493  usage->shared_blks_read);
2494  if (usage->shared_blks_dirtied > 0)
2495  appendStringInfo(es->str, " dirtied=%ld",
2496  usage->shared_blks_dirtied);
2497  if (usage->shared_blks_written > 0)
2498  appendStringInfo(es->str, " written=%ld",
2499  usage->shared_blks_written);
2500  if (has_local || has_temp)
2501  appendStringInfoChar(es->str, ',');
2502  }
2503  if (has_local)
2504  {
2505  appendStringInfoString(es->str, " local");
2506  if (usage->local_blks_hit > 0)
2507  appendStringInfo(es->str, " hit=%ld",
2508  usage->local_blks_hit);
2509  if (usage->local_blks_read > 0)
2510  appendStringInfo(es->str, " read=%ld",
2511  usage->local_blks_read);
2512  if (usage->local_blks_dirtied > 0)
2513  appendStringInfo(es->str, " dirtied=%ld",
2514  usage->local_blks_dirtied);
2515  if (usage->local_blks_written > 0)
2516  appendStringInfo(es->str, " written=%ld",
2517  usage->local_blks_written);
2518  if (has_temp)
2519  appendStringInfoChar(es->str, ',');
2520  }
2521  if (has_temp)
2522  {
2523  appendStringInfoString(es->str, " temp");
2524  if (usage->temp_blks_read > 0)
2525  appendStringInfo(es->str, " read=%ld",
2526  usage->temp_blks_read);
2527  if (usage->temp_blks_written > 0)
2528  appendStringInfo(es->str, " written=%ld",
2529  usage->temp_blks_written);
2530  }
2531  appendStringInfoChar(es->str, '\n');
2532  }
2533 
2534  /* As above, show only positive counter values. */
2535  if (has_timing)
2536  {
2537  appendStringInfoSpaces(es->str, es->indent * 2);
2538  appendStringInfoString(es->str, "I/O Timings:");
2539  if (!INSTR_TIME_IS_ZERO(usage->blk_read_time))
2540  appendStringInfo(es->str, " read=%0.3f",
2542  if (!INSTR_TIME_IS_ZERO(usage->blk_write_time))
2543  appendStringInfo(es->str, " write=%0.3f",
2545  appendStringInfoChar(es->str, '\n');
2546  }
2547  }
2548  else
2549  {
2550  ExplainPropertyLong("Shared Hit Blocks", usage->shared_blks_hit, es);
2551  ExplainPropertyLong("Shared Read Blocks", usage->shared_blks_read, es);
2552  ExplainPropertyLong("Shared Dirtied Blocks", usage->shared_blks_dirtied, es);
2553  ExplainPropertyLong("Shared Written Blocks", usage->shared_blks_written, es);
2554  ExplainPropertyLong("Local Hit Blocks", usage->local_blks_hit, es);
2555  ExplainPropertyLong("Local Read Blocks", usage->local_blks_read, es);
2556  ExplainPropertyLong("Local Dirtied Blocks", usage->local_blks_dirtied, es);
2557  ExplainPropertyLong("Local Written Blocks", usage->local_blks_written, es);
2558  ExplainPropertyLong("Temp Read Blocks", usage->temp_blks_read, es);
2559  ExplainPropertyLong("Temp Written Blocks", usage->temp_blks_written, es);
2560  if (track_io_timing)
2561  {
2562  ExplainPropertyFloat("I/O Read Time", INSTR_TIME_GET_MILLISEC(usage->blk_read_time), 3, es);
2563  ExplainPropertyFloat("I/O Write Time", INSTR_TIME_GET_MILLISEC(usage->blk_write_time), 3, es);
2564  }
2565  }
2566 }
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:3176
#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:3189
long temp_blks_written
Definition: instrument.h:30
#define INSTR_TIME_IS_ZERO(t)
Definition: instr_time.h:149
long shared_blks_written
Definition: instrument.h:24
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
long shared_blks_dirtied
Definition: instrument.h:23
int indent
Definition: explain.h:40
long temp_blks_read
Definition: instrument.h:29
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
instr_time blk_write_time
Definition: instrument.h:32
ExplainFormat format
Definition: explain.h:38
long shared_blks_hit
Definition: instrument.h:21
long local_blks_written
Definition: instrument.h:28
StringInfo str
Definition: explain.h:30
bool track_io_timing
Definition: bufmgr.c:111
static void show_expression ( Node node,
const char *  qlabel,
PlanState planstate,
List ancestors,
bool  useprefix,
ExplainState es 
)
static

Definition at line 1846 of file explain.c.

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

Referenced by ExplainNode(), and show_qual().

1849 {
1850  List *context;
1851  char *exprstr;
1852 
1853  /* Set up deparsing context */
1855  (Node *) planstate,
1856  ancestors);
1857 
1858  /* Deparse the expression */
1859  exprstr = deparse_expression(node, context, useprefix, false);
1860 
1861  /* And add to es->str */
1862  ExplainPropertyText(qlabel, exprstr, es);
1863 }
Definition: nodes.h:509
List * deparse_cxt
Definition: explain.h:46
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3155
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:3136
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:2984
Definition: pg_list.h:45
static void show_foreignscan_info ( ForeignScanState fsstate,
ExplainState es 
)
static

Definition at line 2415 of file explain.c.

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

Referenced by ExplainNode().

2416 {
2417  FdwRoutine *fdwroutine = fsstate->fdwroutine;
2418 
2419  /* Let the FDW emit whatever fields it wants */
2420  if (((ForeignScan *) fsstate->ss.ps.plan)->operation != CMD_SELECT)
2421  {
2422  if (fdwroutine->ExplainDirectModify != NULL)
2423  fdwroutine->ExplainDirectModify(fsstate, es);
2424  }
2425  else
2426  {
2427  if (fdwroutine->ExplainForeignScan != NULL)
2428  fdwroutine->ExplainForeignScan(fsstate, es);
2429  }
2430 }
ScanState ss
Definition: execnodes.h:1522
ExplainForeignScan_function ExplainForeignScan
Definition: fdwapi.h:213
PlanState ps
Definition: execnodes.h:1079
ExplainDirectModify_function ExplainDirectModify
Definition: fdwapi.h:215
struct FdwRoutine * fdwroutine
Definition: execnodes.h:1526
Plan * plan
Definition: execnodes.h:832
#define NULL
Definition: c.h:229
static void show_group_keys ( GroupState gstate,
List ancestors,
ExplainState es 
)
static

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

2083 {
2084  Group *plan = (Group *) gstate->ss.ps.plan;
2085 
2086  /* The key columns refer to the tlist of the child plan */
2087  ancestors = lcons(gstate, ancestors);
2088  show_sort_group_keys(outerPlanState(gstate), "Group Key",
2089  plan->numCols, plan->grpColIdx,
2090  NULL, NULL, NULL,
2091  ancestors, es);
2092  ancestors = list_delete_first(ancestors);
2093 }
ScanState ss
Definition: execnodes.h:1736
PlanState ps
Definition: execnodes.h:1079
#define outerPlanState(node)
Definition: execnodes.h:874
int numCols
Definition: plannodes.h:761
Plan * plan
Definition: execnodes.h:832
List * lcons(void *datum, List *list)
Definition: list.c:259
#define NULL
Definition: c.h:229
AttrNumber * grpColIdx
Definition: plannodes.h:762
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:2101
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 2003 of file explain.c.

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

Referenced by show_grouping_sets().

2007 {
2008  Plan *plan = planstate->plan;
2009  char *exprstr;
2010  ListCell *lc;
2011  List *gsets = aggnode->groupingSets;
2012  AttrNumber *keycols = aggnode->grpColIdx;
2013  const char *keyname;
2014  const char *keysetname;
2015 
2016  if (aggnode->aggstrategy == AGG_HASHED || aggnode->aggstrategy == AGG_MIXED)
2017  {
2018  keyname = "Hash Key";
2019  keysetname = "Hash Keys";
2020  }
2021  else
2022  {
2023  keyname = "Group Key";
2024  keysetname = "Group Keys";
2025  }
2026 
2027  ExplainOpenGroup("Grouping Set", NULL, true, es);
2028 
2029  if (sortnode)
2030  {
2031  show_sort_group_keys(planstate, "Sort Key",
2032  sortnode->numCols, sortnode->sortColIdx,
2033  sortnode->sortOperators, sortnode->collations,
2034  sortnode->nullsFirst,
2035  ancestors, es);
2036  if (es->format == EXPLAIN_FORMAT_TEXT)
2037  es->indent++;
2038  }
2039 
2040  ExplainOpenGroup(keysetname, keysetname, false, es);
2041 
2042  foreach(lc, gsets)
2043  {
2044  List *result = NIL;
2045  ListCell *lc2;
2046 
2047  foreach(lc2, (List *) lfirst(lc))
2048  {
2049  Index i = lfirst_int(lc2);
2050  AttrNumber keyresno = keycols[i];
2051  TargetEntry *target = get_tle_by_resno(plan->targetlist,
2052  keyresno);
2053 
2054  if (!target)
2055  elog(ERROR, "no tlist entry for key %d", keyresno);
2056  /* Deparse the expression, showing any top-level cast */
2057  exprstr = deparse_expression((Node *) target->expr, context,
2058  useprefix, true);
2059 
2060  result = lappend(result, exprstr);
2061  }
2062 
2063  if (!result && es->format == EXPLAIN_FORMAT_TEXT)
2064  ExplainPropertyText(keyname, "()", es);
2065  else
2066  ExplainPropertyListNested(keyname, result, es);
2067  }
2068 
2069  ExplainCloseGroup(keysetname, keysetname, false, es);
2070 
2071  if (sortnode && es->format == EXPLAIN_FORMAT_TEXT)
2072  es->indent--;
2073 
2074  ExplainCloseGroup("Grouping Set", NULL, true, es);
2075 }
#define NIL
Definition: pg_list.h:69
AttrNumber * grpColIdx
Definition: plannodes.h:786
Definition: nodes.h:509
bool * nullsFirst
Definition: plannodes.h:749
return result
Definition: formatting.c:1633
Oid * sortOperators
Definition: plannodes.h:747
static void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3217
void ExplainPropertyListNested(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:3054
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3155
AggStrategy aggstrategy
Definition: plannodes.h:783
#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:3280
int indent
Definition: explain.h:40
List * lappend(List *list, void *datum)
Definition: list.c:128
int numCols
Definition: plannodes.h:745
List * groupingSets
Definition: plannodes.h:791
unsigned int Index
Definition: c.h:365
Plan * plan
Definition: execnodes.h:832
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1368
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:2984
ExplainFormat format
Definition: explain.h:38
List * targetlist
Definition: plannodes.h:144
AttrNumber * sortColIdx
Definition: plannodes.h:746
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:2101
Oid * collations
Definition: plannodes.h:748
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 1972 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().

1974 {
1975  List *context;
1976  bool useprefix;
1977  ListCell *lc;
1978 
1979  /* Set up deparsing context */
1981  (Node *) planstate,
1982  ancestors);
1983  useprefix = (list_length(es->rtable) > 1 || es->verbose);
1984 
1985  ExplainOpenGroup("Grouping Sets", "Grouping Sets", false, es);
1986 
1987  show_grouping_set_keys(planstate, agg, NULL,
1988  context, useprefix, ancestors, es);
1989 
1990  foreach(lc, agg->chain)
1991  {
1992  Agg *aggnode = lfirst(lc);
1993  Sort *sortnode = (Sort *) aggnode->plan.lefttree;
1994 
1995  show_grouping_set_keys(planstate, aggnode, sortnode,
1996  context, useprefix, ancestors, es);
1997  }
1998 
1999  ExplainCloseGroup("Grouping Sets", "Grouping Sets", false, es);
2000 }
Definition: nodes.h:509
List * deparse_cxt
Definition: explain.h:46
static void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3217
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:3136
static void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3280
Plan plan
Definition: plannodes.h:782
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:146
static void show_grouping_set_keys(PlanState *planstate, Agg *aggnode, Sort *sortnode, List *context, bool useprefix, List *ancestors, ExplainState *es)
Definition: explain.c:2003
List * chain
Definition: plannodes.h:792
Definition: plannodes.h:780
Definition: pg_list.h:45
List * rtable
Definition: explain.h:44
static void show_hash_info ( HashState hashstate,
ExplainState es 
)
static

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

2312 {
2313  HashJoinTable hashtable;
2314 
2315  hashtable = hashstate->hashtable;
2316 
2317  if (hashtable)
2318  {
2319  long spacePeakKb = (hashtable->spacePeak + 1023) / 1024;
2320 
2321  if (es->format != EXPLAIN_FORMAT_TEXT)
2322  {
2323  ExplainPropertyLong("Hash Buckets", hashtable->nbuckets, es);
2324  ExplainPropertyLong("Original Hash Buckets",
2325  hashtable->nbuckets_original, es);
2326  ExplainPropertyLong("Hash Batches", hashtable->nbatch, es);
2327  ExplainPropertyLong("Original Hash Batches",
2328  hashtable->nbatch_original, es);
2329  ExplainPropertyLong("Peak Memory Usage", spacePeakKb, es);
2330  }
2331  else if (hashtable->nbatch_original != hashtable->nbatch ||
2332  hashtable->nbuckets_original != hashtable->nbuckets)
2333  {
2334  appendStringInfoSpaces(es->str, es->indent * 2);
2335  appendStringInfo(es->str,
2336  "Buckets: %d (originally %d) Batches: %d (originally %d) Memory Usage: %ldkB\n",
2337  hashtable->nbuckets,
2338  hashtable->nbuckets_original,
2339  hashtable->nbatch,
2340  hashtable->nbatch_original,
2341  spacePeakKb);
2342  }
2343  else
2344  {
2345  appendStringInfoSpaces(es->str, es->indent * 2);
2346  appendStringInfo(es->str,
2347  "Buckets: %d Batches: %d Memory Usage: %ldkB\n",
2348  hashtable->nbuckets, hashtable->nbatch,
2349  spacePeakKb);
2350  }
2351  }
2352 }
void ExplainPropertyLong(const char *qlabel, long value, ExplainState *es)
Definition: explain.c:3176
HashJoinTable hashtable
Definition: execnodes.h:1940
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
int indent
Definition: explain.h:40
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
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 2386 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().

2388 {
2389  double nfiltered;
2390  double nloops;
2391 
2392  if (!es->analyze || !planstate->instrument)
2393  return;
2394 
2395  if (which == 2)
2396  nfiltered = planstate->instrument->nfiltered2;
2397  else
2398  nfiltered = planstate->instrument->nfiltered1;
2399  nloops = planstate->instrument->nloops;
2400 
2401  /* In text mode, suppress zero counts; they're not interesting enough */
2402  if (nfiltered > 0 || es->format != EXPLAIN_FORMAT_TEXT)
2403  {
2404  if (nloops > 0)
2405  ExplainPropertyFloat(qlabel, nfiltered / nloops, 0, es);
2406  else
2407  ExplainPropertyFloat(qlabel, 0.0, 0, es);
2408  }
2409 }
double nfiltered1
Definition: instrument.h:61
Instrumentation * instrument
Definition: execnodes.h:838
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3189
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 1933 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().

1935 {
1936  MergeAppend *plan = (MergeAppend *) mstate->ps.plan;
1937 
1938  show_sort_group_keys((PlanState *) mstate, "Sort Key",
1939  plan->numCols, plan->sortColIdx,
1940  plan->sortOperators, plan->collations,
1941  plan->nullsFirst,
1942  ancestors, es);
1943 }
Oid * collations
Definition: plannodes.h:268
Plan * plan
Definition: execnodes.h:832
PlanState ps
Definition: execnodes.h:1000
AttrNumber * sortColIdx
Definition: plannodes.h:266
bool * nullsFirst
Definition: plannodes.h:269
Oid * sortOperators
Definition: plannodes.h:267
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:2101
static void show_modifytable_info ( ModifyTableState mtstate,
List ancestors,
ExplainState es 
)
static

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

2758 {
2759  ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
2760  const char *operation;
2761  const char *foperation;
2762  bool labeltargets;
2763  int j;
2764  List *idxNames = NIL;
2765  ListCell *lst;
2766 
2767  switch (node->operation)
2768  {
2769  case CMD_INSERT:
2770  operation = "Insert";
2771  foperation = "Foreign Insert";
2772  break;
2773  case CMD_UPDATE:
2774  operation = "Update";
2775  foperation = "Foreign Update";
2776  break;
2777  case CMD_DELETE:
2778  operation = "Delete";
2779  foperation = "Foreign Delete";
2780  break;
2781  default:
2782  operation = "???";
2783  foperation = "Foreign ???";
2784  break;
2785  }
2786 
2787  /* Should we explicitly label target relations? */
2788  labeltargets = (mtstate->mt_nplans > 1 ||
2789  (mtstate->mt_nplans == 1 &&
2790  mtstate->resultRelInfo->ri_RangeTableIndex != node->nominalRelation));
2791 
2792  if (labeltargets)
2793  ExplainOpenGroup("Target Tables", "Target Tables", false, es);
2794 
2795  for (j = 0; j < mtstate->mt_nplans; j++)
2796  {
2797  ResultRelInfo *resultRelInfo = mtstate->resultRelInfo + j;
2798  FdwRoutine *fdwroutine = resultRelInfo->ri_FdwRoutine;
2799 
2800  if (labeltargets)
2801  {
2802  /* Open a group for this target */
2803  ExplainOpenGroup("Target Table", NULL, true, es);
2804 
2805  /*
2806  * In text mode, decorate each target with operation type, so that
2807  * ExplainTargetRel's output of " on foo" will read nicely.
2808  */
2809  if (es->format == EXPLAIN_FORMAT_TEXT)
2810  {
2811  appendStringInfoSpaces(es->str, es->indent * 2);
2813  fdwroutine ? foperation : operation);
2814  }
2815 
2816  /* Identify target */
2817  ExplainTargetRel((Plan *) node,
2818  resultRelInfo->ri_RangeTableIndex,
2819  es);
2820 
2821  if (es->format == EXPLAIN_FORMAT_TEXT)
2822  {
2823  appendStringInfoChar(es->str, '\n');
2824  es->indent++;
2825  }
2826  }
2827 
2828  /* Give FDW a chance if needed */
2829  if (!resultRelInfo->ri_usesFdwDirectModify &&
2830  fdwroutine != NULL &&
2831  fdwroutine->ExplainForeignModify != NULL)
2832  {
2833  List *fdw_private = (List *) list_nth(node->fdwPrivLists, j);
2834 
2835  fdwroutine->ExplainForeignModify(mtstate,
2836  resultRelInfo,
2837  fdw_private,
2838  j,
2839  es);
2840  }
2841 
2842  if (labeltargets)
2843  {
2844  /* Undo the indentation we added in text format */
2845  if (es->format == EXPLAIN_FORMAT_TEXT)
2846  es->indent--;
2847 
2848  /* Close the group */
2849  ExplainCloseGroup("Target Table", NULL, true, es);
2850  }
2851  }
2852 
2853  /* Gather names of ON CONFLICT arbiter indexes */
2854  foreach(lst, node->arbiterIndexes)
2855  {
2856  char *indexname = get_rel_name(lfirst_oid(lst));
2857 
2858  idxNames = lappend(idxNames, indexname);
2859  }
2860 
2861  if (node->onConflictAction != ONCONFLICT_NONE)
2862  {
2863  ExplainProperty("Conflict Resolution",
2865  "NOTHING" : "UPDATE",
2866  false, es);
2867 
2868  /*
2869  * Don't display arbiter indexes at all when DO NOTHING variant
2870  * implicitly ignores all conflicts
2871  */
2872  if (idxNames)
2873  ExplainPropertyList("Conflict Arbiter Indexes", idxNames, es);
2874 
2875  /* ON CONFLICT DO UPDATE WHERE qual is specially displayed */
2876  if (node->onConflictWhere)
2877  {
2878  show_upper_qual((List *) node->onConflictWhere, "Conflict Filter",
2879  &mtstate->ps, ancestors, es);
2880  show_instrumentation_count("Rows Removed by Conflict Filter", 1, &mtstate->ps, es);
2881  }
2882 
2883  /* EXPLAIN ANALYZE display of actual outcome for each tuple proposed */
2884  if (es->analyze && mtstate->ps.instrument)
2885  {
2886  double total;
2887  double insert_path;
2888  double other_path;
2889 
2890  InstrEndLoop(mtstate->mt_plans[0]->instrument);
2891 
2892  /* count the number of source rows */
2893  total = mtstate->mt_plans[0]->instrument->ntuples;
2894  other_path = mtstate->ps.instrument->nfiltered2;
2895  insert_path = total - other_path;
2896 
2897  ExplainPropertyFloat("Tuples Inserted", insert_path, 0, es);
2898  ExplainPropertyFloat("Conflicting Tuples", other_path, 0, es);
2899  }
2900  }
2901 
2902  if (labeltargets)
2903  ExplainCloseGroup("Target Tables", "Target Tables", false, es);
2904 }
#define NIL
Definition: pg_list.h:69
List * arbiterIndexes
Definition: plannodes.h:233
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:3105
Index nominalRelation
Definition: plannodes.h:219
Instrumentation * instrument
Definition: execnodes.h:838
ResultRelInfo * resultRelInfo
Definition: execnodes.h:945
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3189
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:1904
Index ri_RangeTableIndex
Definition: execnodes.h:351
static void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3217
static void show_instrumentation_count(const char *qlabel, int which, PlanState *planstate, ExplainState *es)
Definition: explain.c:2386
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:114
PlanState ps
Definition: execnodes.h:938
double nfiltered2
Definition: instrument.h:62
bool ri_usesFdwDirectModify
Definition: execnodes.h:384
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
void * list_nth(const List *list, int n)
Definition: list.c:410
List * fdwPrivLists
Definition: plannodes.h:228
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:378
static void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3280
double ntuples
Definition: instrument.h:59
int indent
Definition: explain.h:40
List * lappend(List *list, void *datum)
Definition: list.c:128
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
PlanState ** mt_plans
Definition: execnodes.h:942
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:2633
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:187
Plan * plan
Definition: execnodes.h:832
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:2984
#define NULL
Definition: c.h:229
OnConflictAction onConflictAction
Definition: plannodes.h:232
ExplainFormat format
Definition: explain.h:38
CmdType operation
Definition: plannodes.h:217
ExplainForeignModify_function ExplainForeignModify
Definition: fdwapi.h:214
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
StringInfo str
Definition: explain.h:30
#define lfirst_oid(lc)
Definition: pg_list.h:108
Node * onConflictWhere
Definition: plannodes.h:235
static void show_plan_tlist ( PlanState planstate,
List ancestors,
ExplainState es 
)
static

Definition at line 1788 of file explain.c.

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

Referenced by ExplainNode().

1789 {
1790  Plan *plan = planstate->plan;
1791  List *context;
1792  List *result = NIL;
1793  bool useprefix;
1794  ListCell *lc;
1795 
1796  /* No work if empty tlist (this occurs eg in bitmap indexscans) */
1797  if (plan->targetlist == NIL)
1798  return;
1799  /* The tlist of an Append isn't real helpful, so suppress it */
1800  if (IsA(plan, Append))
1801  return;
1802  /* Likewise for MergeAppend and RecursiveUnion */
1803  if (IsA(plan, MergeAppend))
1804  return;
1805  if (IsA(plan, RecursiveUnion))
1806  return;
1807 
1808  /*
1809  * Likewise for ForeignScan that executes a direct INSERT/UPDATE/DELETE
1810  *
1811  * Note: the tlist for a ForeignScan that executes a direct INSERT/UPDATE
1812  * might contain subplan output expressions that are confusing in this
1813  * context. The tlist for a ForeignScan that executes a direct UPDATE/
1814  * DELETE always contains "junk" target columns to identify the exact row
1815  * to update or delete, which would be confusing in this context. So, we
1816  * suppress it in all the cases.
1817  */
1818  if (IsA(plan, ForeignScan) &&
1819  ((ForeignScan *) plan)->operation != CMD_SELECT)
1820  return;
1821 
1822  /* Set up deparsing context */
1824  (Node *) planstate,
1825  ancestors);
1826  useprefix = list_length(es->rtable) > 1;
1827 
1828  /* Deparse each result column (we now include resjunk ones) */
1829  foreach(lc, plan->targetlist)
1830  {
1831  TargetEntry *tle = (TargetEntry *) lfirst(lc);
1832 
1833  result = lappend(result,
1834  deparse_expression((Node *) tle->expr, context,
1835  useprefix, false));
1836  }
1837 
1838  /* Print results */
1839  ExplainPropertyList("Output", result, es);
1840 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
Definition: nodes.h:509
List * deparse_cxt
Definition: explain.h:46
return result
Definition: formatting.c:1633
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:3136
List * lappend(List *list, void *datum)
Definition: list.c:128
Plan * plan
Definition: execnodes.h:832
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:2984
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1368
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:2984
static int list_length(const List *l)
Definition: pg_list.h:89