PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
explain.c File Reference
#include "postgres.h"
#include "access/xact.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "commands/createas.h"
#include "commands/defrem.h"
#include "commands/prepare.h"
#include "executor/hashjoin.h"
#include "foreign/fdwapi.h"
#include "nodes/extensible.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteHandler.h"
#include "storage/bufmgr.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/json.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/ruleutils.h"
#include "utils/snapmgr.h"
#include "utils/tuplesort.h"
#include "utils/typcache.h"
#include "utils/xml.h"
Include dependency graph for explain.c:

Go to the source code of this file.

Macros

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

Functions

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

Variables

ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL
 
explain_get_index_name_hook_type explain_get_index_name_hook = NULL
 

Macro Definition Documentation

#define X_CLOSE_IMMEDIATE   2

Definition at line 53 of file explain.c.

Referenced by ExplainDummyGroup(), and ExplainXMLTag().

#define X_CLOSING   1

Definition at line 52 of file explain.c.

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

#define X_NOWHITESPACE   4

Definition at line 54 of file explain.c.

Referenced by ExplainProperty(), and ExplainXMLTag().

#define X_OPENING   0

Definition at line 51 of file explain.c.

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

Function Documentation

static double elapsed_time ( instr_time starttime)
static

Definition at line 751 of file explain.c.

References INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, and INSTR_TIME_SUBTRACT.

Referenced by ExplainOnePlan(), and IsCheckpointOnSchedule().

752 {
753  instr_time endtime;
754 
755  INSTR_TIME_SET_CURRENT(endtime);
756  INSTR_TIME_SUBTRACT(endtime, *starttime);
757  return INSTR_TIME_GET_DOUBLE(endtime);
758 }
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 3414 of file explain.c.

References escape_json().

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

3415 {
3416  escape_json(buf, str);
3417 }
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 2340 of file explain.c.

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

Referenced by ExplainIndexScanDetails(), and ExplainNode().

2341 {
2342  const char *result;
2343 
2345  result = (*explain_get_index_name_hook) (indexId);
2346  else
2347  result = NULL;
2348  if (result == NULL)
2349  {
2350  /* default behavior: look in the catalogs and quote it */
2351  result = get_rel_name(indexId);
2352  if (result == NULL)
2353  elog(ERROR, "cache lookup failed for index %u", indexId);
2354  result = quote_identifier(result);
2355  }
2356  return result;
2357 }
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:9968
#define ERROR
Definition: elog.h:43
#define NULL
Definition: c.h:226
explain_get_index_name_hook_type explain_get_index_name_hook
Definition: explain.c:47
#define elog
Definition: elog.h:219
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1694
void ExplainBeginOutput ( ExplainState es)

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

3254 {
3255  switch (es->format)
3256  {
3257  case EXPLAIN_FORMAT_TEXT:
3258  /* nothing to do */
3259  break;
3260 
3261  case EXPLAIN_FORMAT_XML:
3263  "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
3264  es->indent++;
3265  break;
3266 
3267  case EXPLAIN_FORMAT_JSON:
3268  /* top-level structure is an array of plans */
3269  appendStringInfoChar(es->str, '[');
3270  es->grouping_stack = lcons_int(0, es->grouping_stack);
3271  es->indent++;
3272  break;
3273 
3274  case EXPLAIN_FORMAT_YAML:
3275  es->grouping_stack = lcons_int(0, es->grouping_stack);
3276  break;
3277  }
3278 }
List * lcons_int(int datum, List *list)
Definition: list.c:277
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
static void ExplainCloseGroup ( const char *  objtype,
const char *  labelname,
bool  labeled,
ExplainState es 
)
static

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

3173 {
3174  switch (es->format)
3175  {
3176  case EXPLAIN_FORMAT_TEXT:
3177  /* nothing to do */
3178  break;
3179 
3180  case EXPLAIN_FORMAT_XML:
3181  es->indent--;
3182  ExplainXMLTag(objtype, X_CLOSING, es);
3183  break;
3184 
3185  case EXPLAIN_FORMAT_JSON:
3186  es->indent--;
3187  appendStringInfoChar(es->str, '\n');
3188  appendStringInfoSpaces(es->str, 2 * es->indent);
3189  appendStringInfoChar(es->str, labeled ? '}' : ']');
3191  break;
3192 
3193  case EXPLAIN_FORMAT_YAML:
3194  es->indent--;
3196  break;
3197  }
3198 }
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3342
#define X_CLOSING
Definition: explain.c:52
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
List * list_delete_first(List *list)
Definition: list.c:666
static void ExplainCustomChildren ( CustomScanState css,
List ancestors,
ExplainState es 
)
static

Definition at line 2860 of file explain.c.

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

Referenced by ExplainNode().

2861 {
2862  ListCell *cell;
2863  const char *label =
2864  (list_length(css->custom_ps) != 1 ? "children" : "child");
2865 
2866  foreach(cell, css->custom_ps)
2867  ExplainNode((PlanState *) lfirst(cell), ancestors, label, NULL, es);
2868 }
List * custom_ps
Definition: execnodes.h:1660
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:833
static char * label
Definition: pg_basebackup.c:84
#define NULL
Definition: c.h:226
#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 3207 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().

3208 {
3209  switch (es->format)
3210  {
3211  case EXPLAIN_FORMAT_TEXT:
3212  /* nothing to do */
3213  break;
3214 
3215  case EXPLAIN_FORMAT_XML:
3216  ExplainXMLTag(objtype, X_CLOSE_IMMEDIATE, es);
3217  break;
3218 
3219  case EXPLAIN_FORMAT_JSON:
3221  appendStringInfoSpaces(es->str, 2 * es->indent);
3222  if (labelname)
3223  {
3224  escape_json(es->str, labelname);
3225  appendStringInfoString(es->str, ": ");
3226  }
3227  escape_json(es->str, objtype);
3228  break;
3229 
3230  case EXPLAIN_FORMAT_YAML:
3232  if (labelname)
3233  {
3234  escape_yaml(es->str, labelname);
3235  appendStringInfoString(es->str, ": ");
3236  }
3237  else
3238  {
3239  appendStringInfoString(es->str, "- ");
3240  }
3241  escape_yaml(es->str, objtype);
3242  break;
3243  }
3244 }
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:3342
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3389
int indent
Definition: explain.h:40
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3414
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3369
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 3284 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().

3285 {
3286  switch (es->format)
3287  {
3288  case EXPLAIN_FORMAT_TEXT:
3289  /* nothing to do */
3290  break;
3291 
3292  case EXPLAIN_FORMAT_XML:
3293  es->indent--;
3294  appendStringInfoString(es->str, "</explain>");
3295  break;
3296 
3297  case EXPLAIN_FORMAT_JSON:
3298  es->indent--;
3299  appendStringInfoString(es->str, "\n]");
3301  break;
3302 
3303  case EXPLAIN_FORMAT_YAML:
3305  break;
3306  }
3307 }
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
List * list_delete_first(List *list)
Definition: list.c:666
static void ExplainIndexScanDetails ( Oid  indexid,
ScanDirection  indexorderdir,
ExplainState es 
)
static

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

2475 {
2476  const char *indexname = explain_get_index_name(indexid);
2477 
2478  if (es->format == EXPLAIN_FORMAT_TEXT)
2479  {
2480  if (ScanDirectionIsBackward(indexorderdir))
2481  appendStringInfoString(es->str, " Backward");
2482  appendStringInfo(es->str, " using %s", indexname);
2483  }
2484  else
2485  {
2486  const char *scandir;
2487 
2488  switch (indexorderdir)
2489  {
2490  case BackwardScanDirection:
2491  scandir = "Backward";
2492  break;
2494  scandir = "NoMovement";
2495  break;
2496  case ForwardScanDirection:
2497  scandir = "Forward";
2498  break;
2499  default:
2500  scandir = "???";
2501  break;
2502  }
2503  ExplainPropertyText("Scan Direction", scandir, es);
2504  ExplainPropertyText("Index Name", indexname, es);
2505  }
2506 }
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3046
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
ExplainFormat format
Definition: explain.h:38
static const char * explain_get_index_name(Oid indexId)
Definition: explain.c:2340
StringInfo str
Definition: explain.h:30
static void ExplainJSONLineEnding ( ExplainState es)
static

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

3370 {
3372  if (linitial_int(es->grouping_stack) != 0)
3373  appendStringInfoChar(es->str, ',');
3374  else
3375  linitial_int(es->grouping_stack) = 1;
3376  appendStringInfoChar(es->str, '\n');
3377 }
#define linitial_int(l)
Definition: pg_list.h:111
List * grouping_stack
Definition: explain.h:41
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
#define Assert(condition)
Definition: c.h:671
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 2808 of file explain.c.

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

Referenced by ExplainNode().

2810 {
2811  int nplans = list_length(plans);
2812  int j;
2813 
2814  for (j = 0; j < nplans; j++)
2815  ExplainNode(planstates[j], ancestors,
2816  "Member", NULL, es);
2817 }
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:833
#define NULL
Definition: c.h:226
static int list_length(const List *l)
Definition: pg_list.h:89
static void ExplainModifyTarget ( ModifyTable plan,
ExplainState es 
)
static

Definition at line 2525 of file explain.c.

References ExplainTargetRel(), and ModifyTable::nominalRelation.

Referenced by ExplainNode().

2526 {
2527  ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
2528 }
Index nominalRelation
Definition: plannodes.h:204
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:2534
static void ExplainNode ( PlanState planstate,
List ancestors,
const char *  relationship,
const char *  plan_name,
ExplainState es 
)
static

Definition at line 833 of file explain.c.

References AGG_HASHED, AGG_PLAIN, AGG_SORTED, Agg::aggsplit, Agg::aggstrategy, ExplainState::analyze, appendStringInfo(), appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), ExplainState::buffers, Instrumentation::bufusage, castNode, CMD_DELETE, CMD_INSERT, CMD_SELECT, CMD_UPDATE, ExplainState::costs, DO_AGGSPLIT_COMBINE, DO_AGGSPLIT_SKIPFINAL, EXPLAIN_FORMAT_TEXT, explain_get_index_name(), ExplainCloseGroup(), ExplainCustomChildren(), CustomExecMethods::ExplainCustomScan, ExplainIndexScanDetails(), ExplainMemberNodes(), ExplainModifyTarget(), ExplainOpenGroup(), ExplainPropertyBool(), ExplainPropertyFloat(), ExplainPropertyInteger(), ExplainPropertyLong(), ExplainPropertyText(), ExplainScanTarget(), ExplainSubPlans(), ExplainState::format, RangeTblFunction::funcexpr, functions, ExplainState::indent, IndexScan::indexid, IndexOnlyScan::indexid, BitmapIndexScan::indexid, IndexScan::indexorderdir, IndexOnlyScan::indexorderdir, PlanState::initPlan, innerPlanState, InstrEndLoop(), WorkerInstrumentation::instrument, PlanState::instrument, IsA, JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, JOIN_SEMI, lappend(), lcons(), lfirst, list_delete_first(), list_length(), list_make1, make_orclause(), CustomScanState::methods, NIL, Instrumentation::nloops, nodeTag, Instrumentation::ntuples, NULL, WorkerInstrumentation::num_workers, Gather::num_workers, 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_Group, T_Hash, T_HashJoin, T_IndexOnlyScan, T_IndexScan, T_Limit, T_LockRows, T_Material, T_MergeAppend, T_MergeJoin, T_ModifyTable, T_NestLoop, T_ProjectSet, T_RecursiveUnion, T_Result, T_SampleScan, T_SeqScan, T_SetOp, T_Sort, T_SubqueryScan, T_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().

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

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

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

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

336 {
337  /* planner will not cope with utility statements */
338  if (query->commandType == CMD_UTILITY)
339  {
340  ExplainOneUtility(query->utilityStmt, into, es, queryString, params);
341  return;
342  }
343 
344  /* if an advisor plugin is present, let it manage things */
346  (*ExplainOneQuery_hook) (query, cursorOptions, into, es,
347  queryString, params);
348  else
349  {
350  PlannedStmt *plan;
351  instr_time planstart,
352  planduration;
353 
354  INSTR_TIME_SET_CURRENT(planstart);
355 
356  /* plan the query */
357  plan = pg_plan_query(query, cursorOptions, params);
358 
359  INSTR_TIME_SET_CURRENT(planduration);
360  INSTR_TIME_SUBTRACT(planduration, planstart);
361 
362  /* run it (if needed) and produce output */
363  ExplainOnePlan(plan, into, es, queryString, params, &planduration);
364  }
365 }
void ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params)
Definition: explain.c:379
struct timeval instr_time
Definition: instr_time.h:147
Node * utilityStmt
Definition: parsenodes.h:111
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:167
ExplainOneQuery_hook_type ExplainOneQuery_hook
Definition: explain.c:44
CmdType commandType
Definition: parsenodes.h:103
void ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, const instr_time *planduration)
Definition: explain.c:455
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153
PlannedStmt * pg_plan_query(Query *querytree, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:781
void ExplainOneUtility ( Node utilityStmt,
IntoClause into,
ExplainState es,
const char *  queryString,
ParamListInfo  params 
)

Definition at line 379 of file explain.c.

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

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

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

3110 {
3111  switch (es->format)
3112  {
3113  case EXPLAIN_FORMAT_TEXT:
3114  /* nothing to do */
3115  break;
3116 
3117  case EXPLAIN_FORMAT_XML:
3118  ExplainXMLTag(objtype, X_OPENING, es);
3119  es->indent++;
3120  break;
3121 
3122  case EXPLAIN_FORMAT_JSON:
3124  appendStringInfoSpaces(es->str, 2 * es->indent);
3125  if (labelname)
3126  {
3127  escape_json(es->str, labelname);
3128  appendStringInfoString(es->str, ": ");
3129  }
3130  appendStringInfoChar(es->str, labeled ? '{' : '[');
3131 
3132  /*
3133  * In JSON format, the grouping_stack is an integer list. 0 means
3134  * we've emitted nothing at this grouping level, 1 means we've
3135  * emitted something (and so the next item needs a comma). See
3136  * ExplainJSONLineEnding().
3137  */
3138  es->grouping_stack = lcons_int(0, es->grouping_stack);
3139  es->indent++;
3140  break;
3141 
3142  case EXPLAIN_FORMAT_YAML:
3143 
3144  /*
3145  * In YAML format, the grouping stack is an integer list. 0 means
3146  * we've emitted nothing at this grouping level AND this grouping
3147  * level is unlabelled and must be marked with "- ". See
3148  * ExplainYAMLLineStarting().
3149  */
3151  if (labelname)
3152  {
3153  appendStringInfo(es->str, "%s: ", labelname);
3154  es->grouping_stack = lcons_int(1, es->grouping_stack);
3155  }
3156  else
3157  {
3158  appendStringInfoString(es->str, "- ");
3159  es->grouping_stack = lcons_int(0, es->grouping_stack);
3160  }
3161  es->indent++;
3162  break;
3163  }
3164 }
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:3342
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3389
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3369
#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 770 of file explain.c.

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

Referenced by ExplainPrintPlan().

771 {
772  Plan *plan = planstate->plan;
773 
774  switch (nodeTag(plan))
775  {
776  case T_SeqScan:
777  case T_SampleScan:
778  case T_IndexScan:
779  case T_IndexOnlyScan:
780  case T_BitmapHeapScan:
781  case T_TidScan:
782  case T_SubqueryScan:
783  case T_FunctionScan:
784  case T_ValuesScan:
785  case T_CteScan:
786  case T_WorkTableScan:
787  *rels_used = bms_add_member(*rels_used,
788  ((Scan *) plan)->scanrelid);
789  break;
790  case T_ForeignScan:
791  *rels_used = bms_add_members(*rels_used,
792  ((ForeignScan *) plan)->fs_relids);
793  break;
794  case T_CustomScan:
795  *rels_used = bms_add_members(*rels_used,
796  ((CustomScan *) plan)->custom_relids);
797  break;
798  case T_ModifyTable:
799  *rels_used = bms_add_member(*rels_used,
800  ((ModifyTable *) plan)->nominalRelation);
801  if (((ModifyTable *) plan)->exclRelRTI)
802  *rels_used = bms_add_member(*rels_used,
803  ((ModifyTable *) plan)->exclRelRTI);
804  break;
805  default:
806  break;
807  }
808 
809  return planstate_tree_walker(planstate, ExplainPreScanNode, rels_used);
810 }
Plan * plan
Definition: execnodes.h:1047
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:668
#define nodeTag(nodeptr)
Definition: nodes.h:513
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
Definition: explain.c:770
bool planstate_tree_walker(PlanState *planstate, bool(*walker)(), void *context)
Definition: nodeFuncs.c:3639
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:725
void ExplainPrintPlan ( ExplainState es,
QueryDesc queryDesc 
)

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

600 {
601  Bitmapset *rels_used = NULL;
602  PlanState *ps;
603 
604  /* Set up ExplainState fields associated with this plan tree */
605  Assert(queryDesc->plannedstmt != NULL);
606  es->pstmt = queryDesc->plannedstmt;
607  es->rtable = queryDesc->plannedstmt->rtable;
608  ExplainPreScanNode(queryDesc->planstate, &rels_used);
611  es->rtable_names);
612  es->printed_subplans = NULL;
613 
614  /*
615  * Sometimes we mark a Gather node as "invisible", which means that it's
616  * not displayed in EXPLAIN output. The purpose of this is to allow
617  * running regression tests with force_parallel_mode=regress to get the
618  * same results as running the same tests with force_parallel_mode=off.
619  */
620  ps = queryDesc->planstate;
621  if (IsA(ps, GatherState) &&((Gather *) ps->plan)->invisible)
622  ps = outerPlanState(ps);
623  ExplainNode(ps, NIL, NULL, NULL, es);
624 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
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:2971
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:833
PlanState * planstate
Definition: execdesc.h:48
#define outerPlanState(node)
Definition: execnodes.h:1090
Plan * plan
Definition: execnodes.h:1047
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
List * rtable
Definition: plannodes.h:63
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
Definition: explain.c:770
PlannedStmt * plannedstmt
Definition: execdesc.h:37
List * deparse_context_for_plan_rtable(List *rtable, List *rtable_names)
Definition: ruleutils.c:2896
List * rtable
Definition: explain.h:44
void ExplainPrintTriggers ( ExplainState es,
QueryDesc queryDesc 
)

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

637 {
638  ResultRelInfo *rInfo;
639  bool show_relname;
640  int numrels = queryDesc->estate->es_num_result_relations;
641  List *targrels = queryDesc->estate->es_trig_target_relations;
642  int nr;
643  ListCell *l;
644 
645  ExplainOpenGroup("Triggers", "Triggers", false, es);
646 
647  show_relname = (numrels > 1 || targrels != NIL);
648  rInfo = queryDesc->estate->es_result_relations;
649  for (nr = 0; nr < numrels; rInfo++, nr++)
650  report_triggers(rInfo, show_relname, es);
651 
652  foreach(l, targrels)
653  {
654  rInfo = (ResultRelInfo *) lfirst(l);
655  report_triggers(rInfo, show_relname, es);
656  }
657 
658  ExplainCloseGroup("Triggers", "Triggers", false, es);
659 }
#define NIL
Definition: pg_list.h:69
EState * estate
Definition: execdesc.h:47
static void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3108
ResultRelInfo * es_result_relations
Definition: execnodes.h:382
static void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3171
static void report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
Definition: explain.c:681
List * es_trig_target_relations
Definition: execnodes.h:387
int es_num_result_relations
Definition: execnodes.h:383
#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 2996 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().

2998 {
2999  switch (es->format)
3000  {
3001  case EXPLAIN_FORMAT_TEXT:
3002  appendStringInfoSpaces(es->str, es->indent * 2);
3003  appendStringInfo(es->str, "%s: %s\n", qlabel, value);
3004  break;
3005 
3006  case EXPLAIN_FORMAT_XML:
3007  {
3008  char *str;
3009 
3010  appendStringInfoSpaces(es->str, es->indent * 2);
3011  ExplainXMLTag(qlabel, X_OPENING | X_NOWHITESPACE, es);
3012  str = escape_xml(value);
3013  appendStringInfoString(es->str, str);
3014  pfree(str);
3015  ExplainXMLTag(qlabel, X_CLOSING | X_NOWHITESPACE, es);
3016  appendStringInfoChar(es->str, '\n');
3017  }
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  if (numeric)
3027  else
3028  escape_json(es->str, value);
3029  break;
3030 
3031  case EXPLAIN_FORMAT_YAML:
3033  appendStringInfo(es->str, "%s: ", qlabel);
3034  if (numeric)
3036  else
3037  escape_yaml(es->str, value);
3038  break;
3039  }
3040 }
static struct @76 value
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2433
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
Definition: explain.c:3342
#define X_CLOSING
Definition: explain.c:52
void pfree(void *pointer)
Definition: mcxt.c:992
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3389
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3414
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3369
#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:2170
StringInfo str
Definition: explain.h:30
void ExplainPropertyBool ( const char *  qlabel,
bool  value,
ExplainState es 
)

Definition at line 3093 of file explain.c.

References ExplainProperty().

Referenced by ExplainNode().

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

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

3082 {
3083  char buf[256];
3084 
3085  snprintf(buf, sizeof(buf), "%.*f", ndigits, value);
3086  ExplainProperty(qlabel, buf, true, es);
3087 }
static struct @76 value
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:2996
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static char * buf
Definition: pg_test_fsync.c:65
void ExplainPropertyInteger ( const char *  qlabel,
int  value,
ExplainState es 
)

Definition at line 3055 of file explain.c.

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

Referenced by ExplainNode().

3056 {
3057  char buf[32];
3058 
3059  snprintf(buf, sizeof(buf), "%d", value);
3060  ExplainProperty(qlabel, buf, true, es);
3061 }
static struct @76 value
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:2996
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static char * buf
Definition: pg_test_fsync.c:65
void ExplainPropertyList ( const char *  qlabel,
List data,
ExplainState es 
)

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

2876 {
2877  ListCell *lc;
2878  bool first = true;
2879 
2880  switch (es->format)
2881  {
2882  case EXPLAIN_FORMAT_TEXT:
2883  appendStringInfoSpaces(es->str, es->indent * 2);
2884  appendStringInfo(es->str, "%s: ", qlabel);
2885  foreach(lc, data)
2886  {
2887  if (!first)
2888  appendStringInfoString(es->str, ", ");
2889  appendStringInfoString(es->str, (const char *) lfirst(lc));
2890  first = false;
2891  }
2892  appendStringInfoChar(es->str, '\n');
2893  break;
2894 
2895  case EXPLAIN_FORMAT_XML:
2896  ExplainXMLTag(qlabel, X_OPENING, es);
2897  foreach(lc, data)
2898  {
2899  char *str;
2900 
2901  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
2902  appendStringInfoString(es->str, "<Item>");
2903  str = escape_xml((const char *) lfirst(lc));
2904  appendStringInfoString(es->str, str);
2905  pfree(str);
2906  appendStringInfoString(es->str, "</Item>\n");
2907  }
2908  ExplainXMLTag(qlabel, X_CLOSING, es);
2909  break;
2910 
2911  case EXPLAIN_FORMAT_JSON:
2913  appendStringInfoSpaces(es->str, es->indent * 2);
2914  escape_json(es->str, qlabel);
2915  appendStringInfoString(es->str, ": [");
2916  foreach(lc, data)
2917  {
2918  if (!first)
2919  appendStringInfoString(es->str, ", ");
2920  escape_json(es->str, (const char *) lfirst(lc));
2921  first = false;
2922  }
2923  appendStringInfoChar(es->str, ']');
2924  break;
2925 
2926  case EXPLAIN_FORMAT_YAML:
2928  appendStringInfo(es->str, "%s: ", qlabel);
2929  foreach(lc, data)
2930  {
2931  appendStringInfoChar(es->str, '\n');
2932  appendStringInfoSpaces(es->str, es->indent * 2 + 2);
2933  appendStringInfoString(es->str, "- ");
2934  escape_yaml(es->str, (const char *) lfirst(lc));
2935  }
2936  break;
2937  }
2938 }
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:3342
#define X_CLOSING
Definition: explain.c:52
void pfree(void *pointer)
Definition: mcxt.c:992
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3389
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3414
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3369
#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:2170
StringInfo str
Definition: explain.h:30
void ExplainPropertyListNested ( const char *  qlabel,
List data,
ExplainState es 
)

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

2946 {
2947  ListCell *lc;
2948  bool first = true;
2949 
2950  switch (es->format)
2951  {
2952  case EXPLAIN_FORMAT_TEXT:
2953  case EXPLAIN_FORMAT_XML:
2954  ExplainPropertyList(qlabel, data, es);
2955  return;
2956 
2957  case EXPLAIN_FORMAT_JSON:
2959  appendStringInfoSpaces(es->str, es->indent * 2);
2960  appendStringInfoChar(es->str, '[');
2961  foreach(lc, data)
2962  {
2963  if (!first)
2964  appendStringInfoString(es->str, ", ");
2965  escape_json(es->str, (const char *) lfirst(lc));
2966  first = false;
2967  }
2968  appendStringInfoChar(es->str, ']');
2969  break;
2970 
2971  case EXPLAIN_FORMAT_YAML:
2973  appendStringInfoString(es->str, "- [");
2974  foreach(lc, data)
2975  {
2976  if (!first)
2977  appendStringInfoString(es->str, ", ");
2978  escape_yaml(es->str, (const char *) lfirst(lc));
2979  first = false;
2980  }
2981  appendStringInfoChar(es->str, ']');
2982  break;
2983  }
2984 }
void escape_json(StringInfo buf, const char *str)
Definition: json.c:2433
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
static void ExplainYAMLLineStarting(ExplainState *es)
Definition: explain.c:3389
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
static void escape_yaml(StringInfo buf, const char *str)
Definition: explain.c:3414
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
static void ExplainJSONLineEnding(ExplainState *es)
Definition: explain.c:3369
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:2875
#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 3067 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().

3068 {
3069  char buf[32];
3070 
3071  snprintf(buf, sizeof(buf), "%ld", value);
3072  ExplainProperty(qlabel, buf, true, es);
3073 }
static struct @76 value
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:2996
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static char * buf
Definition: pg_test_fsync.c:65
void ExplainPropertyText ( const char *  qlabel,
const char *  value,
ExplainState es 
)

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

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

Definition at line 144 of file explain.c.

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

Referenced by standard_ProcessUtility().

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

Definition at line 670 of file explain.c.

References ExplainPropertyText(), and QueryDesc::sourceText.

Referenced by explain_ExecutorEnd().

671 {
672  if (queryDesc->sourceText)
673  ExplainPropertyText("Query Text", queryDesc->sourceText, es);
674 }
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3046
const char * sourceText
Definition: execdesc.h:38
TupleDesc ExplainResultDesc ( ExplainStmt stmt)

Definition at line 294 of file explain.c.

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

Referenced by ExplainQuery(), and UtilityTupleDescriptor().

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

Definition at line 2512 of file explain.c.

References ExplainTargetRel(), and Scan::scanrelid.

Referenced by ExplainNode().

2513 {
2514  ExplainTargetRel((Plan *) plan, plan->scanrelid, es);
2515 }
Index scanrelid
Definition: plannodes.h:306
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:2534
void ExplainSeparatePlans ( ExplainState es)

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

3314 {
3315  switch (es->format)
3316  {
3317  case EXPLAIN_FORMAT_TEXT:
3318  /* add a blank line */
3319  appendStringInfoChar(es->str, '\n');
3320  break;
3321 
3322  case EXPLAIN_FORMAT_XML:
3323  case EXPLAIN_FORMAT_JSON:
3324  case EXPLAIN_FORMAT_YAML:
3325  /* nothing to do */
3326  break;
3327  }
3328 }
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
static void ExplainSubPlans ( List plans,
List ancestors,
const char *  relationship,
ExplainState es 
)
static

Definition at line 2826 of file explain.c.

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

Referenced by ExplainNode().

2828 {
2829  ListCell *lst;
2830 
2831  foreach(lst, plans)
2832  {
2833  SubPlanState *sps = (SubPlanState *) lfirst(lst);
2834  SubPlan *sp = (SubPlan *) sps->xprstate.expr;
2835 
2836  /*
2837  * There can be multiple SubPlan nodes referencing the same physical
2838  * subplan (same plan_id, which is its index in PlannedStmt.subplans).
2839  * We should print a subplan only once, so track which ones we already
2840  * printed. This state must be global across the plan tree, since the
2841  * duplicate nodes could be in different plan nodes, eg both a bitmap
2842  * indexscan's indexqual and its parent heapscan's recheck qual. (We
2843  * do not worry too much about which plan node we show the subplan as
2844  * attached to in such cases.)
2845  */
2846  if (bms_is_member(sp->plan_id, es->printed_subplans))
2847  continue;
2849  sp->plan_id);
2850 
2851  ExplainNode(sps->planstate, ancestors,
2852  relationship, sp->plan_name, es);
2853  }
2854 }
int plan_id
Definition: primnodes.h:666
ExprState xprstate
Definition: execnodes.h:785
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:833
struct PlanState * planstate
Definition: execnodes.h:786
Expr * expr
Definition: execnodes.h:598
char * plan_name
Definition: primnodes.h:668
#define lfirst(lc)
Definition: pg_list.h:106
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:668
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:419
static void ExplainTargetRel ( Plan plan,
Index  rti,
ExplainState es 
)
static

Definition at line 2534 of file explain.c.

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

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

2535 {
2536  char *objectname = NULL;
2537  char *namespace = NULL;
2538  const char *objecttag = NULL;
2539  RangeTblEntry *rte;
2540  char *refname;
2541 
2542  rte = rt_fetch(rti, es->rtable);
2543  refname = (char *) list_nth(es->rtable_names, rti - 1);
2544  if (refname == NULL)
2545  refname = rte->eref->aliasname;
2546 
2547  switch (nodeTag(plan))
2548  {
2549  case T_SeqScan:
2550  case T_SampleScan:
2551  case T_IndexScan:
2552  case T_IndexOnlyScan:
2553  case T_BitmapHeapScan:
2554  case T_TidScan:
2555  case T_ForeignScan:
2556  case T_CustomScan:
2557  case T_ModifyTable:
2558  /* Assert it's on a real relation */
2559  Assert(rte->rtekind == RTE_RELATION);
2560  objectname = get_rel_name(rte->relid);
2561  if (es->verbose)
2562  namespace = get_namespace_name(get_rel_namespace(rte->relid));
2563  objecttag = "Relation Name";
2564  break;
2565  case T_FunctionScan:
2566  {
2567  FunctionScan *fscan = (FunctionScan *) plan;
2568 
2569  /* Assert it's on a RangeFunction */
2570  Assert(rte->rtekind == RTE_FUNCTION);
2571 
2572  /*
2573  * If the expression is still a function call of a single
2574  * function, we can get the real name of the function.
2575  * Otherwise, punt. (Even if it was a single function call
2576  * originally, the optimizer could have simplified it away.)
2577  */
2578  if (list_length(fscan->functions) == 1)
2579  {
2580  RangeTblFunction *rtfunc = (RangeTblFunction *) linitial(fscan->functions);
2581 
2582  if (IsA(rtfunc->funcexpr, FuncExpr))
2583  {
2584  FuncExpr *funcexpr = (FuncExpr *) rtfunc->funcexpr;
2585  Oid funcid = funcexpr->funcid;
2586 
2587  objectname = get_func_name(funcid);
2588  if (es->verbose)
2589  namespace =
2591  }
2592  }
2593  objecttag = "Function Name";
2594  }
2595  break;
2596  case T_ValuesScan:
2597  Assert(rte->rtekind == RTE_VALUES);
2598  break;
2599  case T_CteScan:
2600  /* Assert it's on a non-self-reference CTE */
2601  Assert(rte->rtekind == RTE_CTE);
2602  Assert(!rte->self_reference);
2603  objectname = rte->ctename;
2604  objecttag = "CTE Name";
2605  break;
2606  case T_WorkTableScan:
2607  /* Assert it's on a self-reference CTE */
2608  Assert(rte->rtekind == RTE_CTE);
2609  Assert(rte->self_reference);
2610  objectname = rte->ctename;
2611  objecttag = "CTE Name";
2612  break;
2613  default:
2614  break;
2615  }
2616 
2617  if (es->format == EXPLAIN_FORMAT_TEXT)
2618  {
2619  appendStringInfoString(es->str, " on");
2620  if (namespace != NULL)
2621  appendStringInfo(es->str, " %s.%s", quote_identifier(namespace),
2622  quote_identifier(objectname));
2623  else if (objectname != NULL)
2624  appendStringInfo(es->str, " %s", quote_identifier(objectname));
2625  if (objectname == NULL || strcmp(refname, objectname) != 0)
2626  appendStringInfo(es->str, " %s", quote_identifier(refname));
2627  }
2628  else
2629  {
2630  if (objecttag != NULL && objectname != NULL)
2631  ExplainPropertyText(objecttag, objectname, es);
2632  if (namespace != NULL)
2633  ExplainPropertyText("Schema", namespace, es);
2634  ExplainPropertyText("Alias", refname, es);
2635  }
2636 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:9968
Oid get_func_namespace(Oid funcid)
Definition: lsyscache.c:1404
List * functions
Definition: plannodes.h:484
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1718
unsigned int Oid
Definition: postgres_ext.h:31
List * rtable_names
Definition: explain.h:45
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3046
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
#define linitial(l)
Definition: pg_list.h:110
Oid funcid
Definition: primnodes.h:426
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1380
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3006
void * list_nth(const List *list, int n)
Definition: list.c:410
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
bool self_reference
Definition: parsenodes.h:944
bool verbose
Definition: explain.h:32
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
char * aliasname
Definition: primnodes.h:41
static int list_length(const List *l)
Definition: pg_list.h:89
ExplainFormat format
Definition: explain.h:38
#define nodeTag(nodeptr)
Definition: nodes.h:513
RTEKind rtekind
Definition: parsenodes.h:882
char * ctename
Definition: parsenodes.h:942
Alias * eref
Definition: parsenodes.h:961
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1694
StringInfo str
Definition: explain.h:30
List * rtable
Definition: explain.h:44
static void ExplainXMLTag ( const char *  tagname,
int  flags,
ExplainState es 
)
static

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

3343 {
3344  const char *s;
3345  const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
3346 
3347  if ((flags & X_NOWHITESPACE) == 0)
3348  appendStringInfoSpaces(es->str, 2 * es->indent);
3349  appendStringInfoCharMacro(es->str, '<');
3350  if ((flags & X_CLOSING) != 0)
3351  appendStringInfoCharMacro(es->str, '/');
3352  for (s = tagname; *s; s++)
3353  appendStringInfoChar(es->str, strchr(valid, *s) ? *s : '-');
3354  if ((flags & X_CLOSE_IMMEDIATE) != 0)
3355  appendStringInfoString(es->str, " /");
3356  appendStringInfoCharMacro(es->str, '>');
3357  if ((flags & X_NOWHITESPACE) == 0)
3358  appendStringInfoCharMacro(es->str, '\n');
3359 }
#define X_CLOSING
Definition: explain.c:52
#define appendStringInfoCharMacro(str, ch)
Definition: stringinfo.h:135
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
#define X_NOWHITESPACE
Definition: explain.c:54
#define X_CLOSE_IMMEDIATE
Definition: explain.c:53
StringInfo str
Definition: explain.h:30
static void ExplainYAMLLineStarting ( ExplainState es)
static

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

3390 {
3392  if (linitial_int(es->grouping_stack) == 0)
3393  {
3394  linitial_int(es->grouping_stack) = 1;
3395  }
3396  else
3397  {
3398  appendStringInfoChar(es->str, '\n');
3399  appendStringInfoSpaces(es->str, es->indent * 2);
3400  }
3401 }
#define linitial_int(l)
Definition: pg_list.h:111
List * grouping_stack
Definition: explain.h:41
int indent
Definition: explain.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
#define Assert(condition)
Definition: c.h:671
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
ExplainState* NewExplainState ( void  )

Definition at line 277 of file explain.c.

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

Referenced by explain_ExecutorEnd(), and ExplainQuery().

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

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

682 {
683  int nt;
684 
685  if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
686  return;
687  for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
688  {
689  Trigger *trig = rInfo->ri_TrigDesc->triggers + nt;
690  Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
691  char *relname;
692  char *conname = NULL;
693 
694  /* Must clean up instrumentation state */
695  InstrEndLoop(instr);
696 
697  /*
698  * We ignore triggers that were never invoked; they likely aren't
699  * relevant to the current query type.
700  */
701  if (instr->ntuples == 0)
702  continue;
703 
704  ExplainOpenGroup("Trigger", NULL, true, es);
705 
706  relname = RelationGetRelationName(rInfo->ri_RelationDesc);
707  if (OidIsValid(trig->tgconstraint))
708  conname = get_constraint_name(trig->tgconstraint);
709 
710  /*
711  * In text format, we avoid printing both the trigger name and the
712  * constraint name unless VERBOSE is specified. In non-text formats
713  * we just print everything.
714  */
715  if (es->format == EXPLAIN_FORMAT_TEXT)
716  {
717  if (es->verbose || conname == NULL)
718  appendStringInfo(es->str, "Trigger %s", trig->tgname);
719  else
720  appendStringInfoString(es->str, "Trigger");
721  if (conname)
722  appendStringInfo(es->str, " for constraint %s", conname);
723  if (show_relname)
724  appendStringInfo(es->str, " on %s", relname);
725  if (es->timing)
726  appendStringInfo(es->str, ": time=%.3f calls=%.0f\n",
727  1000.0 * instr->total, instr->ntuples);
728  else
729  appendStringInfo(es->str, ": calls=%.0f\n", instr->ntuples);
730  }
731  else
732  {
733  ExplainPropertyText("Trigger Name", trig->tgname, es);
734  if (conname)
735  ExplainPropertyText("Constraint Name", conname, es);
736  ExplainPropertyText("Relation", relname, es);
737  if (es->timing)
738  ExplainPropertyFloat("Time", 1000.0 * instr->total, 3, es);
739  ExplainPropertyFloat("Calls", instr->ntuples, 0, es);
740  }
741 
742  if (conname)
743  pfree(conname);
744 
745  ExplainCloseGroup("Trigger", NULL, true, es);
746  }
747 }
Relation ri_RelationDesc
Definition: execnodes.h:335
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:965
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3080
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:342
#define OidIsValid(objectId)
Definition: c.h:534
static void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3108
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:114
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3046
void pfree(void *pointer)
Definition: mcxt.c:992
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
Oid tgconstraint
Definition: reltrigger.h:34
char * tgname
Definition: reltrigger.h:27
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
Trigger * triggers
Definition: reltrigger.h:48
#define RelationGetRelationName(relation)
Definition: rel.h:433
static void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3171
double ntuples
Definition: instrument.h:59
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:339
bool timing
Definition: explain.h:36
int numtriggers
Definition: reltrigger.h:49
bool verbose
Definition: explain.h:32
#define NULL
Definition: c.h:226
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 1863 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().

1865 {
1866  Agg *plan = (Agg *) astate->ss.ps.plan;
1867 
1868  if (plan->numCols > 0 || plan->groupingSets)
1869  {
1870  /* The key columns refer to the tlist of the child plan */
1871  ancestors = lcons(astate, ancestors);
1872 
1873  if (plan->groupingSets)
1874  show_grouping_sets(outerPlanState(astate), plan, ancestors, es);
1875  else
1876  show_sort_group_keys(outerPlanState(astate), "Group Key",
1877  plan->numCols, plan->grpColIdx,
1878  NULL, NULL, NULL,
1879  ancestors, es);
1880 
1881  ancestors = list_delete_first(ancestors);
1882  }
1883 }
int numCols
Definition: plannodes.h:735
AttrNumber * grpColIdx
Definition: plannodes.h:736
ScanState ss
Definition: execnodes.h:1867
PlanState ps
Definition: execnodes.h:1288
#define outerPlanState(node)
Definition: execnodes.h:1090
static void show_grouping_sets(PlanState *planstate, Agg *agg, List *ancestors, ExplainState *es)
Definition: explain.c:1886
List * groupingSets
Definition: plannodes.h:741
Plan * plan
Definition: execnodes.h:1047
List * lcons(void *datum, List *list)
Definition: list.c:259
#define NULL
Definition: c.h:226
Definition: plannodes.h:730
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:2002
List * list_delete_first(List *list)
Definition: list.c:666
static void show_buffer_usage ( ExplainState es,
const BufferUsage usage 
)
static

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

2364 {
2365  if (es->format == EXPLAIN_FORMAT_TEXT)
2366  {
2367  bool has_shared = (usage->shared_blks_hit > 0 ||
2368  usage->shared_blks_read > 0 ||
2369  usage->shared_blks_dirtied > 0 ||
2370  usage->shared_blks_written > 0);
2371  bool has_local = (usage->local_blks_hit > 0 ||
2372  usage->local_blks_read > 0 ||
2373  usage->local_blks_dirtied > 0 ||
2374  usage->local_blks_written > 0);
2375  bool has_temp = (usage->temp_blks_read > 0 ||
2376  usage->temp_blks_written > 0);
2377  bool has_timing = (!INSTR_TIME_IS_ZERO(usage->blk_read_time) ||
2379 
2380  /* Show only positive counter values. */
2381  if (has_shared || has_local || has_temp)
2382  {
2383  appendStringInfoSpaces(es->str, es->indent * 2);
2384  appendStringInfoString(es->str, "Buffers:");
2385 
2386  if (has_shared)
2387  {
2388  appendStringInfoString(es->str, " shared");
2389  if (usage->shared_blks_hit > 0)
2390  appendStringInfo(es->str, " hit=%ld",
2391  usage->shared_blks_hit);
2392  if (usage->shared_blks_read > 0)
2393  appendStringInfo(es->str, " read=%ld",
2394  usage->shared_blks_read);
2395  if (usage->shared_blks_dirtied > 0)
2396  appendStringInfo(es->str, " dirtied=%ld",
2397  usage->shared_blks_dirtied);
2398  if (usage->shared_blks_written > 0)
2399  appendStringInfo(es->str, " written=%ld",
2400  usage->shared_blks_written);
2401  if (has_local || has_temp)
2402  appendStringInfoChar(es->str, ',');
2403  }
2404  if (has_local)
2405  {
2406  appendStringInfoString(es->str, " local");
2407  if (usage->local_blks_hit > 0)
2408  appendStringInfo(es->str, " hit=%ld",
2409  usage->local_blks_hit);
2410  if (usage->local_blks_read > 0)
2411  appendStringInfo(es->str, " read=%ld",
2412  usage->local_blks_read);
2413  if (usage->local_blks_dirtied > 0)
2414  appendStringInfo(es->str, " dirtied=%ld",
2415  usage->local_blks_dirtied);
2416  if (usage->local_blks_written > 0)
2417  appendStringInfo(es->str, " written=%ld",
2418  usage->local_blks_written);
2419  if (has_temp)
2420  appendStringInfoChar(es->str, ',');
2421  }
2422  if (has_temp)
2423  {
2424  appendStringInfoString(es->str, " temp");
2425  if (usage->temp_blks_read > 0)
2426  appendStringInfo(es->str, " read=%ld",
2427  usage->temp_blks_read);
2428  if (usage->temp_blks_written > 0)
2429  appendStringInfo(es->str, " written=%ld",
2430  usage->temp_blks_written);
2431  }
2432  appendStringInfoChar(es->str, '\n');
2433  }
2434 
2435  /* As above, show only positive counter values. */
2436  if (has_timing)
2437  {
2438  appendStringInfoSpaces(es->str, es->indent * 2);
2439  appendStringInfoString(es->str, "I/O Timings:");
2440  if (!INSTR_TIME_IS_ZERO(usage->blk_read_time))
2441  appendStringInfo(es->str, " read=%0.3f",
2443  if (!INSTR_TIME_IS_ZERO(usage->blk_write_time))
2444  appendStringInfo(es->str, " write=%0.3f",
2446  appendStringInfoChar(es->str, '\n');
2447  }
2448  }
2449  else
2450  {
2451  ExplainPropertyLong("Shared Hit Blocks", usage->shared_blks_hit, es);
2452  ExplainPropertyLong("Shared Read Blocks", usage->shared_blks_read, es);
2453  ExplainPropertyLong("Shared Dirtied Blocks", usage->shared_blks_dirtied, es);
2454  ExplainPropertyLong("Shared Written Blocks", usage->shared_blks_written, es);
2455  ExplainPropertyLong("Local Hit Blocks", usage->local_blks_hit, es);
2456  ExplainPropertyLong("Local Read Blocks", usage->local_blks_read, es);
2457  ExplainPropertyLong("Local Dirtied Blocks", usage->local_blks_dirtied, es);
2458  ExplainPropertyLong("Local Written Blocks", usage->local_blks_written, es);
2459  ExplainPropertyLong("Temp Read Blocks", usage->temp_blks_read, es);
2460  ExplainPropertyLong("Temp Written Blocks", usage->temp_blks_written, es);
2461  if (track_io_timing)
2462  {
2463  ExplainPropertyFloat("I/O Read Time", INSTR_TIME_GET_MILLISEC(usage->blk_read_time), 3, es);
2464  ExplainPropertyFloat("I/O Write Time", INSTR_TIME_GET_MILLISEC(usage->blk_write_time), 3, es);
2465  }
2466  }
2467 }
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:3067
#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:3080
long temp_blks_written
Definition: instrument.h:30
#define INSTR_TIME_IS_ZERO(t)
Definition: instr_time.h:149
long shared_blks_written
Definition: instrument.h:24
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
long shared_blks_dirtied
Definition: instrument.h:23
int indent
Definition: explain.h:40
long temp_blks_read
Definition: instrument.h:29
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
instr_time blk_write_time
Definition: instrument.h:32
ExplainFormat format
Definition: explain.h:38
long shared_blks_hit
Definition: instrument.h:21
long local_blks_written
Definition: instrument.h:28
StringInfo str
Definition: explain.h:30
bool track_io_timing
Definition: bufmgr.c:111
static void show_expression ( Node node,
const char *  qlabel,
PlanState planstate,
List ancestors,
bool  useprefix,
ExplainState es 
)
static

Definition at line 1760 of file explain.c.

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

Referenced by ExplainNode(), and show_qual().

1763 {
1764  List *context;
1765  char *exprstr;
1766 
1767  /* Set up deparsing context */
1769  (Node *) planstate,
1770  ancestors);
1771 
1772  /* Deparse the expression */
1773  exprstr = deparse_expression(node, context, useprefix, false);
1774 
1775  /* And add to es->str */
1776  ExplainPropertyText(qlabel, exprstr, es);
1777 }
Definition: nodes.h:508
List * deparse_cxt
Definition: explain.h:46
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3046
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:2947
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:2795
Definition: pg_list.h:45
static void show_foreignscan_info ( ForeignScanState fsstate,
ExplainState es 
)
static

Definition at line 2316 of file explain.c.

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

Referenced by ExplainNode().

2317 {
2318  FdwRoutine *fdwroutine = fsstate->fdwroutine;
2319 
2320  /* Let the FDW emit whatever fields it wants */
2321  if (((ForeignScan *) fsstate->ss.ps.plan)->operation != CMD_SELECT)
2322  {
2323  if (fdwroutine->ExplainDirectModify != NULL)
2324  fdwroutine->ExplainDirectModify(fsstate, es);
2325  }
2326  else
2327  {
2328  if (fdwroutine->ExplainForeignScan != NULL)
2329  fdwroutine->ExplainForeignScan(fsstate, es);
2330  }
2331 }
ScanState ss
Definition: execnodes.h:1632
ExplainForeignScan_function ExplainForeignScan
Definition: fdwapi.h:212
PlanState ps
Definition: execnodes.h:1288
ExplainDirectModify_function ExplainDirectModify
Definition: fdwapi.h:214
struct FdwRoutine * fdwroutine
Definition: execnodes.h:1636
Plan * plan
Definition: execnodes.h:1047
#define NULL
Definition: c.h:226
static void show_group_keys ( GroupState gstate,
List ancestors,
ExplainState es 
)
static

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

1984 {
1985  Group *plan = (Group *) gstate->ss.ps.plan;
1986 
1987  /* The key columns refer to the tlist of the child plan */
1988  ancestors = lcons(gstate, ancestors);
1989  show_sort_group_keys(outerPlanState(gstate), "Group Key",
1990  plan->numCols, plan->grpColIdx,
1991  NULL, NULL, NULL,
1992  ancestors, es);
1993  ancestors = list_delete_first(ancestors);
1994 }
ScanState ss
Definition: execnodes.h:1842
PlanState ps
Definition: execnodes.h:1288
#define outerPlanState(node)
Definition: execnodes.h:1090
int numCols
Definition: plannodes.h:711
Plan * plan
Definition: execnodes.h:1047
List * lcons(void *datum, List *list)
Definition: list.c:259
#define NULL
Definition: c.h:226
AttrNumber * grpColIdx
Definition: plannodes.h:712
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:2002
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 1917 of file explain.c.

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

Referenced by show_grouping_sets().

1921 {
1922  Plan *plan = planstate->plan;
1923  char *exprstr;
1924  ListCell *lc;
1925  List *gsets = aggnode->groupingSets;
1926  AttrNumber *keycols = aggnode->grpColIdx;
1927 
1928  ExplainOpenGroup("Grouping Set", NULL, true, es);
1929 
1930  if (sortnode)
1931  {
1932  show_sort_group_keys(planstate, "Sort Key",
1933  sortnode->numCols, sortnode->sortColIdx,
1934  sortnode->sortOperators, sortnode->collations,
1935  sortnode->nullsFirst,
1936  ancestors, es);
1937  if (es->format == EXPLAIN_FORMAT_TEXT)
1938  es->indent++;
1939  }
1940 
1941  ExplainOpenGroup("Group Keys", "Group Keys", false, es);
1942 
1943  foreach(lc, gsets)
1944  {
1945  List *result = NIL;
1946  ListCell *lc2;
1947 
1948  foreach(lc2, (List *) lfirst(lc))
1949  {
1950  Index i = lfirst_int(lc2);
1951  AttrNumber keyresno = keycols[i];
1952  TargetEntry *target = get_tle_by_resno(plan->targetlist,
1953  keyresno);
1954 
1955  if (!target)
1956  elog(ERROR, "no tlist entry for key %d", keyresno);
1957  /* Deparse the expression, showing any top-level cast */
1958  exprstr = deparse_expression((Node *) target->expr, context,
1959  useprefix, true);
1960 
1961  result = lappend(result, exprstr);
1962  }
1963 
1964  if (!result && es->format == EXPLAIN_FORMAT_TEXT)
1965  ExplainPropertyText("Group Key", "()", es);
1966  else
1967  ExplainPropertyListNested("Group Key", result, es);
1968  }
1969 
1970  ExplainCloseGroup("Group Keys", "Group Keys", false, es);
1971 
1972  if (sortnode && es->format == EXPLAIN_FORMAT_TEXT)
1973  es->indent--;
1974 
1975  ExplainCloseGroup("Grouping Set", NULL, true, es);
1976 }
#define NIL
Definition: pg_list.h:69
AttrNumber * grpColIdx
Definition: plannodes.h:736
Definition: nodes.h:508
bool * nullsFirst
Definition: plannodes.h:699
Oid * sortOperators
Definition: plannodes.h:697
static void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3108
void ExplainPropertyListNested(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:2945
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:3046
#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:3171
int indent
Definition: explain.h:40
List * lappend(List *list, void *datum)
Definition: list.c:128
int numCols
Definition: plannodes.h:695
List * groupingSets
Definition: plannodes.h:741
unsigned int Index
Definition: c.h:362
Plan * plan
Definition: execnodes.h:1047
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1330
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:2795
ExplainFormat format
Definition: explain.h:38
List * targetlist
Definition: plannodes.h:129
AttrNumber * sortColIdx
Definition: plannodes.h:696
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:2002
Oid * collations
Definition: plannodes.h:698
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 1886 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().

1888 {
1889  List *context;
1890  bool useprefix;
1891  ListCell *lc;
1892 
1893  /* Set up deparsing context */
1895  (Node *) planstate,
1896  ancestors);
1897  useprefix = (list_length(es->rtable) > 1 || es->verbose);
1898 
1899  ExplainOpenGroup("Grouping Sets", "Grouping Sets", false, es);
1900 
1901  show_grouping_set_keys(planstate, agg, NULL,
1902  context, useprefix, ancestors, es);
1903 
1904  foreach(lc, agg->chain)
1905  {
1906  Agg *aggnode = lfirst(lc);
1907  Sort *sortnode = (Sort *) aggnode->plan.lefttree;
1908 
1909  show_grouping_set_keys(planstate, aggnode, sortnode,
1910  context, useprefix, ancestors, es);
1911  }
1912 
1913  ExplainCloseGroup("Grouping Sets", "Grouping Sets", false, es);
1914 }
Definition: nodes.h:508
List * deparse_cxt
Definition: explain.h:46
static void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3108
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:2947
static void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3171
Plan plan
Definition: plannodes.h:732
bool verbose
Definition: explain.h:32
#define NULL
Definition: c.h:226
#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:131
static void show_grouping_set_keys(PlanState *planstate, Agg *aggnode, Sort *sortnode, List *context, bool useprefix, List *ancestors, ExplainState *es)
Definition: explain.c:1917
List * chain
Definition: plannodes.h:742
Definition: plannodes.h:730
Definition: pg_list.h:45
List * rtable
Definition: explain.h:44
static void show_hash_info ( HashState hashstate,
ExplainState es 
)
static

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

2213 {
2214  HashJoinTable hashtable;
2215 
2216  hashtable = hashstate->hashtable;
2217 
2218  if (hashtable)
2219  {
2220  long spacePeakKb = (hashtable->spacePeak + 1023) / 1024;
2221 
2222  if (es->format != EXPLAIN_FORMAT_TEXT)
2223  {
2224  ExplainPropertyLong("Hash Buckets", hashtable->nbuckets, es);
2225  ExplainPropertyLong("Original Hash Buckets",
2226  hashtable->nbuckets_original, es);
2227  ExplainPropertyLong("Hash Batches", hashtable->nbatch, es);
2228  ExplainPropertyLong("Original Hash Batches",
2229  hashtable->nbatch_original, es);
2230  ExplainPropertyLong("Peak Memory Usage", spacePeakKb, es);
2231  }
2232  else if (hashtable->nbatch_original != hashtable->nbatch ||
2233  hashtable->nbuckets_original != hashtable->nbuckets)
2234  {
2235  appendStringInfoSpaces(es->str, es->indent * 2);
2236  appendStringInfo(es->str,
2237  "Buckets: %d (originally %d) Batches: %d (originally %d) Memory Usage: %ldkB\n",
2238  hashtable->nbuckets,
2239  hashtable->nbuckets_original,
2240  hashtable->nbatch,
2241  hashtable->nbatch_original,
2242  spacePeakKb);
2243  }
2244  else
2245  {
2246  appendStringInfoSpaces(es->str, es->indent * 2);
2247  appendStringInfo(es->str,
2248  "Buckets: %d Batches: %d Memory Usage: %ldkB\n",
2249  hashtable->nbuckets, hashtable->nbatch,
2250  spacePeakKb);
2251  }
2252  }
2253 }
void ExplainPropertyLong(const char *qlabel, long value, ExplainState *es)
Definition: explain.c:3067
HashJoinTable hashtable
Definition: execnodes.h:2022
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
int indent
Definition: explain.h:40
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
ExplainFormat format
Definition: explain.h:38
StringInfo str
Definition: explain.h:30
static void show_instrumentation_count ( const char *  qlabel,
int  which,
PlanState planstate,
ExplainState es 
)
static

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

2289 {
2290  double nfiltered;
2291  double nloops;
2292 
2293  if (!es->analyze || !planstate->instrument)
2294  return;
2295 
2296  if (which == 2)
2297  nfiltered = planstate->instrument->nfiltered2;
2298  else
2299  nfiltered = planstate->instrument->nfiltered1;
2300  nloops = planstate->instrument->nloops;
2301 
2302  /* In text mode, suppress zero counts; they're not interesting enough */
2303  if (nfiltered > 0 || es->format != EXPLAIN_FORMAT_TEXT)
2304  {
2305  if (nloops > 0)
2306  ExplainPropertyFloat(qlabel, nfiltered / nloops, 0, es);
2307  else
2308  ExplainPropertyFloat(qlabel, 0.0, 0, es);
2309  }
2310 }
double nfiltered1
Definition: instrument.h:61
Instrumentation * instrument
Definition: execnodes.h:1053
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3080
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 1847 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().

1849 {
1850  MergeAppend *plan = (MergeAppend *) mstate->ps.plan;
1851 
1852  show_sort_group_keys((PlanState *) mstate, "Sort Key",
1853  plan->numCols, plan->sortColIdx,
1854  plan->sortOperators, plan->collations,
1855  plan->nullsFirst,
1856  ancestors, es);
1857 }
Oid * collations
Definition: plannodes.h:246
Plan * plan
Definition: execnodes.h:1047
PlanState ps
Definition: execnodes.h:1209
AttrNumber * sortColIdx
Definition: plannodes.h:244
bool * nullsFirst
Definition: plannodes.h:247
Oid * sortOperators
Definition: plannodes.h:245
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:2002
static void show_modifytable_info ( ModifyTableState mtstate,
List ancestors,
ExplainState es 
)
static

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

2649 {
2650  ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
2651  const char *operation;
2652  const char *foperation;
2653  bool labeltargets;
2654  int j;
2655  List *idxNames = NIL;
2656  ListCell *lst;
2657 
2658  switch (node->operation)
2659  {
2660  case CMD_INSERT:
2661  operation = "Insert";
2662  foperation = "Foreign Insert";
2663  break;
2664  case CMD_UPDATE:
2665  operation = "Update";
2666  foperation = "Foreign Update";
2667  break;
2668  case CMD_DELETE:
2669  operation = "Delete";
2670  foperation = "Foreign Delete";
2671  break;
2672  default:
2673  operation = "???";
2674  foperation = "Foreign ???";
2675  break;
2676  }
2677 
2678  /* Should we explicitly label target relations? */
2679  labeltargets = (mtstate->mt_nplans > 1 ||
2680  (mtstate->mt_nplans == 1 &&
2681  mtstate->resultRelInfo->ri_RangeTableIndex != node->nominalRelation));
2682 
2683  if (labeltargets)
2684  ExplainOpenGroup("Target Tables", "Target Tables", false, es);
2685 
2686  for (j = 0; j < mtstate->mt_nplans; j++)
2687  {
2688  ResultRelInfo *resultRelInfo = mtstate->resultRelInfo + j;
2689  FdwRoutine *fdwroutine = resultRelInfo->ri_FdwRoutine;
2690 
2691  if (labeltargets)
2692  {
2693  /* Open a group for this target */
2694  ExplainOpenGroup("Target Table", NULL, true, es);
2695 
2696  /*
2697  * In text mode, decorate each target with operation type, so that
2698  * ExplainTargetRel's output of " on foo" will read nicely.
2699  */
2700  if (es->format == EXPLAIN_FORMAT_TEXT)
2701  {
2702  appendStringInfoSpaces(es->str, es->indent * 2);
2704  fdwroutine ? foperation : operation);
2705  }
2706 
2707  /* Identify target */
2708  ExplainTargetRel((Plan *) node,
2709  resultRelInfo->ri_RangeTableIndex,
2710  es);
2711 
2712  if (es->format == EXPLAIN_FORMAT_TEXT)
2713  {
2714  appendStringInfoChar(es->str, '\n');
2715  es->indent++;
2716  }
2717  }
2718 
2719  /* Give FDW a chance if needed */
2720  if (!resultRelInfo->ri_usesFdwDirectModify &&
2721  fdwroutine != NULL &&
2722  fdwroutine->ExplainForeignModify != NULL)
2723  {
2724  List *fdw_private = (List *) list_nth(node->fdwPrivLists, j);
2725 
2726  fdwroutine->ExplainForeignModify(mtstate,
2727  resultRelInfo,
2728  fdw_private,
2729  j,
2730  es);
2731  }
2732 
2733  if (labeltargets)
2734  {
2735  /* Undo the indentation we added in text format */
2736  if (es->format == EXPLAIN_FORMAT_TEXT)
2737  es->indent--;
2738 
2739  /* Close the group */
2740  ExplainCloseGroup("Target Table", NULL, true, es);
2741  }
2742  }
2743 
2744  /* Gather names of ON CONFLICT arbiter indexes */
2745  foreach(lst, node->arbiterIndexes)
2746  {
2747  char *indexname = get_rel_name(lfirst_oid(lst));
2748 
2749  idxNames = lappend(idxNames, indexname);
2750  }
2751 
2752  if (node->onConflictAction != ONCONFLICT_NONE)
2753  {
2754  ExplainProperty("Conflict Resolution",
2756  "NOTHING" : "UPDATE",
2757  false, es);
2758 
2759  /*
2760  * Don't display arbiter indexes at all when DO NOTHING variant
2761  * implicitly ignores all conflicts
2762  */
2763  if (idxNames)
2764  ExplainPropertyList("Conflict Arbiter Indexes", idxNames, es);
2765 
2766  /* ON CONFLICT DO UPDATE WHERE qual is specially displayed */
2767  if (node->onConflictWhere)
2768  {
2769  show_upper_qual((List *) node->onConflictWhere, "Conflict Filter",
2770  &mtstate->ps, ancestors, es);
2771  show_instrumentation_count("Rows Removed by Conflict Filter", 1, &mtstate->ps, es);
2772  }
2773 
2774  /* EXPLAIN ANALYZE display of actual outcome for each tuple proposed */
2775  if (es->analyze && mtstate->ps.instrument)
2776  {
2777  double total;
2778  double insert_path;
2779  double other_path;
2780 
2781  InstrEndLoop(mtstate->mt_plans[0]->instrument);
2782 
2783  /* count the number of source rows */
2784  total = mtstate->mt_plans[0]->instrument->ntuples;
2785  other_path = mtstate->ps.instrument->nfiltered2;
2786  insert_path = total - other_path;
2787 
2788  ExplainPropertyFloat("Tuples Inserted", insert_path, 0, es);
2789  ExplainPropertyFloat("Conflicting Tuples", other_path, 0, es);
2790  }
2791  }
2792 
2793  if (labeltargets)
2794  ExplainCloseGroup("Target Tables", "Target Tables", false, es);
2795 }
#define NIL
Definition: pg_list.h:69
List * arbiterIndexes
Definition: plannodes.h:215
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
Definition: explain.c:2996
Index nominalRelation
Definition: plannodes.h:204
Instrumentation * instrument
Definition: execnodes.h:1053
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1157
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
Definition: explain.c:3080
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:1818
Index ri_RangeTableIndex
Definition: execnodes.h:334
static void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3108
static void show_instrumentation_count(const char *qlabel, int which, PlanState *planstate, ExplainState *es)
Definition: explain.c:2287
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:114
PlanState ps
Definition: execnodes.h:1150
double nfiltered2
Definition: instrument.h:62
bool ri_usesFdwDirectModify
Definition: execnodes.h:345
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
void * list_nth(const List *list, int n)
Definition: list.c:410
List * fdwPrivLists
Definition: plannodes.h:210
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:343
static void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
Definition: explain.c:3171
double ntuples
Definition: instrument.h:59
int indent
Definition: explain.h:40
List * lappend(List *list, void *datum)
Definition: list.c:128
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
PlanState ** mt_plans
Definition: execnodes.h:1154
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
Definition: explain.c:2534
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
Plan * plan
Definition: execnodes.h:1047
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:2875
#define NULL
Definition: c.h:226
OnConflictAction onConflictAction
Definition: plannodes.h:214
ExplainFormat format
Definition: explain.h:38
CmdType operation
Definition: plannodes.h:202
ExplainForeignModify_function ExplainForeignModify
Definition: fdwapi.h:213
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1694
StringInfo str
Definition: explain.h:30
#define lfirst_oid(lc)
Definition: pg_list.h:108
Node * onConflictWhere
Definition: plannodes.h:217
static void show_plan_tlist ( PlanState planstate,
List ancestors,
ExplainState es 
)
static

Definition at line 1702 of file explain.c.

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

Referenced by ExplainNode().

1703 {
1704  Plan *plan = planstate->plan;
1705  List *context;
1706  List *result = NIL;
1707  bool useprefix;
1708  ListCell *lc;
1709 
1710  /* No work if empty tlist (this occurs eg in bitmap indexscans) */
1711  if (plan->targetlist == NIL)
1712  return;
1713  /* The tlist of an Append isn't real helpful, so suppress it */
1714  if (IsA(plan, Append))
1715  return;
1716  /* Likewise for MergeAppend and RecursiveUnion */
1717  if (IsA(plan, MergeAppend))
1718  return;
1719  if (IsA(plan, RecursiveUnion))
1720  return;
1721 
1722  /*
1723  * Likewise for ForeignScan that executes a direct INSERT/UPDATE/DELETE
1724  *
1725  * Note: the tlist for a ForeignScan that executes a direct INSERT/UPDATE
1726  * might contain subplan output expressions that are confusing in this
1727  * context. The tlist for a ForeignScan that executes a direct UPDATE/
1728  * DELETE always contains "junk" target columns to identify the exact row
1729  * to update or delete, which would be confusing in this context. So, we
1730  * suppress it in all the cases.
1731  */
1732  if (IsA(plan, ForeignScan) &&
1733  ((ForeignScan *) plan)->operation != CMD_SELECT)
1734  return;
1735 
1736  /* Set up deparsing context */
1738  (Node *) planstate,
1739  ancestors);
1740  useprefix = list_length(es->rtable) > 1;
1741 
1742  /* Deparse each result column (we now include resjunk ones) */
1743  foreach(lc, plan->targetlist)
1744  {
1745  TargetEntry *tle = (TargetEntry *) lfirst(lc);
1746 
1747  result = lappend(result,
1748  deparse_expression((Node *) tle->expr, context,
1749  useprefix, false));
1750  }
1751 
1752  /* Print results */
1753  ExplainPropertyList("Output", result, es);
1754 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
Definition: nodes.h:508
List * deparse_cxt
Definition: explain.h:46
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:2947
List * lappend(List *list, void *datum)
Definition: list.c:128
Plan * plan
Definition: execnodes.h:1047
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:2875
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1330
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:2795
static int list_length(const List *l)
Definition: pg_list.h:89
List * targetlist
Definition: plannodes.h:129
Definition: pg_list.h:45
List * rtable
Definition: explain.h:44
static void show_qual ( List qual,
const char *  qlabel,
PlanState planstate,
List ancestors,
bool  useprefix,
ExplainState es 
)
static

Definition at line 1783 of file explain.c.

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

Referenced by show_scan_qual(), and show_upper_qual().

1786 {
1787  Node *node;
1788 
1789  /* No work if empty qual */
1790  if (qual == NIL)
1791  return;
1792 
1793  /* Convert AND list to explicit AND */
1794  node = (Node *) make_ands_explicit(qual);
1795 
1796  /* And show it */
1797  show_expression(node, qlabel, planstate, ancestors, useprefix, es);
1798 }
#define NIL
Definition: pg_list.h:69
Definition: nodes.h:508
Expr * make_ands_explicit(List *andclauses)
Definition: clauses.c:366
static void show_expression(Node *node, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
Definition: explain.c:1760
static void show_scan_qual ( List qual,
const char *  qlabel,
PlanState planstate,
List ancestors,
ExplainState es 
)
static

Definition at line 1804 of file explain.c.

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

Referenced by ExplainNode().

1807 {
1808  bool useprefix;
1809 
1810  useprefix = (IsA(planstate->plan, SubqueryScan) ||es->verbose);
1811  show_qual(qual, qlabel, planstate, ancestors, useprefix, es);
1812 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
static void show_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
Definition: explain.c:1783
bool verbose
Definition: explain.h:32
Plan * plan
Definition: execnodes.h:1047
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

Definition at line 2002 of file explain.c.

References appendStringInfoString(), StringInfoData::data, ExplainState::deparse_cxt, deparse_expression(), elog, ERROR, ExplainPropertyList(), TargetEntry::expr, get_tle_by_resno(), initStringInfo(), lappend(), list_length(), NIL, NULL, PlanState::plan, pstrdup(), resetStringInfo(), ExplainState::rtable, set_deparse_context_planstate(), show_sortorder_options(), Plan::targetlist, and ExplainState::verbose.

Referenced by show_agg_keys(), show_group_keys(), show_grouping_set_keys(), show_merge_append_keys(), and show_sort_keys().

2006 {
2007  Plan *plan = planstate->plan;
2008  List *context;
2009  List *result = NIL;
2010  StringInfoData sortkeybuf;
2011  bool useprefix;
2012  int keyno;
2013 
2014  if (nkeys <= 0)
2015  return;
2016 
2017  initStringInfo(&sortkeybuf);
2018 
2019  /* Set up deparsing context */
2021  (Node *) planstate,
2022  ancestors);
2023  useprefix = (list_length(es->rtable) > 1 || es->verbose);
2024 
2025  for (keyno = 0; keyno < nkeys; keyno++)
2026  {
2027  /* find key expression in tlist */
2028  AttrNumber keyresno = keycols[keyno];
2029  TargetEntry *target = get_tle_by_resno(plan->targetlist,
2030  keyresno);
2031  char *exprstr;
2032 
2033  if (!target)
2034  elog(ERROR, "no tlist entry for key %d", keyresno);
2035  /* Deparse the expression, showing any top-level cast */
2036  exprstr = deparse_expression((Node *) target->expr, context,
2037  useprefix, true);
2038  resetStringInfo(&sortkeybuf);
2039  appendStringInfoString(&sortkeybuf, exprstr);
2040  /* Append sort order information, if relevant */
2041  if (sortOperators != NULL)
2042  show_sortorder_options(&sortkeybuf,
2043  (Node *) target->expr,
2044  sortOperators[keyno],
2045  collations[keyno],
2046  nullsFirst[keyno]);
2047  /* Emit one property-list item per sort key */
2048  result = lappend(result, pstrdup(sortkeybuf.data));
2049  }
2050 
2051  ExplainPropertyList(qlabel, result, es);
2052 }
#define NIL
Definition: pg_list.h:69
char * pstrdup(const char *in)
Definition: mcxt.c:1165
Definition: nodes.h:508
List * deparse_cxt
Definition: explain.h:46
#define ERROR
Definition: elog.h:43
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
Definition: ruleutils.c:2947
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:94
List * lappend(List *list, void *datum)
Definition: list.c:128
void initStringInfo(StringInfo str)
Definition: stringinfo.c:65
bool verbose
Definition: explain.h:32
Plan * plan
Definition: execnodes.h:1047
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
Definition: explain.c:2875
#define NULL
Definition: c.h:226