#include "postgres.h"
#include "access/xact.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 "optimizer/clauses.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteHandler.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/json.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/tuplesort.h"
#include "utils/xml.h"
Go to the source code of this file.
Defines | |
#define | X_OPENING 0 |
#define | X_CLOSING 1 |
#define | X_CLOSE_IMMEDIATE 2 |
#define | X_NOWHITESPACE 4 |
Functions | |
static void | ExplainOneQuery (Query *query, 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 void | ExplainPreScanNode (PlanState *planstate, Bitmapset **rels_used) |
static void | ExplainPreScanMemberNodes (List *plans, PlanState **planstates, Bitmapset **rels_used) |
static void | ExplainPreScanSubPlans (List *plans, 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_sort_keys_common (PlanState *planstate, int nkeys, AttrNumber *keycols, 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_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 | 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, 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 | 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 (ExplainStmt *stmt, const char *queryString, ParamListInfo params, DestReceiver *dest) |
void | ExplainInitState (ExplainState *es) |
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) |
void | ExplainPrintPlan (ExplainState *es, QueryDesc *queryDesc) |
void | ExplainQueryText (ExplainState *es, QueryDesc *queryDesc) |
void | ExplainPropertyList (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 | 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 |
#define X_CLOSE_IMMEDIATE 2 |
Definition at line 46 of file explain.c.
Referenced by ExplainDummyGroup(), and ExplainXMLTag().
#define X_CLOSING 1 |
Definition at line 45 of file explain.c.
Referenced by ExplainCloseGroup(), ExplainProperty(), ExplainPropertyList(), and ExplainXMLTag().
#define X_NOWHITESPACE 4 |
Definition at line 47 of file explain.c.
Referenced by ExplainProperty(), and ExplainXMLTag().
#define X_OPENING 0 |
Definition at line 44 of file explain.c.
Referenced by ExplainOpenGroup(), ExplainProperty(), and ExplainPropertyList().
static double elapsed_time | ( | instr_time * | starttime | ) | [static] |
Definition at line 643 of file explain.c.
References INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, and INSTR_TIME_SUBTRACT.
Referenced by ExplainOnePlan().
{ instr_time endtime; INSTR_TIME_SET_CURRENT(endtime); INSTR_TIME_SUBTRACT(endtime, *starttime); return INSTR_TIME_GET_DOUBLE(endtime); }
static void escape_yaml | ( | StringInfo | buf, | |
const char * | str | |||
) | [static] |
Definition at line 2608 of file explain.c.
References escape_json().
Referenced by ExplainDummyGroup(), ExplainProperty(), and ExplainPropertyList().
{ escape_json(buf, str); }
static const char * explain_get_index_name | ( | Oid | indexId | ) | [static] |
Definition at line 1863 of file explain.c.
References elog, ERROR, explain_get_index_name_hook, get_rel_name(), NULL, and quote_identifier().
Referenced by ExplainIndexScanDetails(), and ExplainNode().
{ const char *result; if (explain_get_index_name_hook) result = (*explain_get_index_name_hook) (indexId); else result = NULL; if (result == NULL) { /* default behavior: look in the catalogs and quote it */ result = get_rel_name(indexId); if (result == NULL) elog(ERROR, "cache lookup failed for index %u", indexId); result = quote_identifier(result); } return result; }
void ExplainBeginOutput | ( | ExplainState * | es | ) |
Definition at line 2449 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().
{ switch (es->format) { case EXPLAIN_FORMAT_TEXT: /* nothing to do */ break; case EXPLAIN_FORMAT_XML: appendStringInfoString(es->str, "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n"); es->indent++; break; case EXPLAIN_FORMAT_JSON: /* top-level structure is an array of plans */ appendStringInfoChar(es->str, '['); es->grouping_stack = lcons_int(0, es->grouping_stack); es->indent++; break; case EXPLAIN_FORMAT_YAML: es->grouping_stack = lcons_int(0, es->grouping_stack); break; } }
static void ExplainCloseGroup | ( | const char * | objtype, | |
const char * | labelname, | |||
bool | labeled, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 2367 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(), and report_triggers().
{ switch (es->format) { case EXPLAIN_FORMAT_TEXT: /* nothing to do */ break; case EXPLAIN_FORMAT_XML: es->indent--; ExplainXMLTag(objtype, X_CLOSING, es); break; case EXPLAIN_FORMAT_JSON: es->indent--; appendStringInfoChar(es->str, '\n'); appendStringInfoSpaces(es->str, 2 * es->indent); appendStringInfoChar(es->str, labeled ? '}' : ']'); es->grouping_stack = list_delete_first(es->grouping_stack); break; case EXPLAIN_FORMAT_YAML: es->indent--; es->grouping_stack = list_delete_first(es->grouping_stack); break; } }
static void ExplainDummyGroup | ( | const char * | objtype, | |
const char * | labelname, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 2403 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().
{ switch (es->format) { case EXPLAIN_FORMAT_TEXT: /* nothing to do */ break; case EXPLAIN_FORMAT_XML: ExplainXMLTag(objtype, X_CLOSE_IMMEDIATE, es); break; case EXPLAIN_FORMAT_JSON: ExplainJSONLineEnding(es); appendStringInfoSpaces(es->str, 2 * es->indent); if (labelname) { escape_json(es->str, labelname); appendStringInfoString(es->str, ": "); } escape_json(es->str, objtype); break; case EXPLAIN_FORMAT_YAML: ExplainYAMLLineStarting(es); if (labelname) { escape_yaml(es->str, labelname); appendStringInfoString(es->str, ": "); } else { appendStringInfoString(es->str, "- "); } escape_yaml(es->str, objtype); break; } }
void ExplainEndOutput | ( | ExplainState * | es | ) |
Definition at line 2480 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().
{ switch (es->format) { case EXPLAIN_FORMAT_TEXT: /* nothing to do */ break; case EXPLAIN_FORMAT_XML: es->indent--; appendStringInfoString(es->str, "</explain>"); break; case EXPLAIN_FORMAT_JSON: es->indent--; appendStringInfoString(es->str, "\n]"); es->grouping_stack = list_delete_first(es->grouping_stack); break; case EXPLAIN_FORMAT_YAML: es->grouping_stack = list_delete_first(es->grouping_stack); break; } }
static void ExplainIndexScanDetails | ( | Oid | indexid, | |
ScanDirection | indexorderdir, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 1886 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().
{ const char *indexname = explain_get_index_name(indexid); if (es->format == EXPLAIN_FORMAT_TEXT) { if (ScanDirectionIsBackward(indexorderdir)) appendStringInfoString(es->str, " Backward"); appendStringInfo(es->str, " using %s", indexname); } else { const char *scandir; switch (indexorderdir) { case BackwardScanDirection: scandir = "Backward"; break; case NoMovementScanDirection: scandir = "NoMovement"; break; case ForwardScanDirection: scandir = "Forward"; break; default: scandir = "???"; break; } ExplainPropertyText("Scan Direction", scandir, es); ExplainPropertyText("Index Name", indexname, es); } }
void ExplainInitState | ( | ExplainState * | es | ) |
Definition at line 249 of file explain.c.
References ExplainState::costs, makeStringInfo(), and ExplainState::str.
Referenced by explain_ExecutorEnd(), and ExplainQuery().
{ /* Set default options. */ memset(es, 0, sizeof(ExplainState)); es->costs = true; /* Prepare output buffer. */ es->str = makeStringInfo(); }
static void ExplainJSONLineEnding | ( | ExplainState * | es | ) | [static] |
Definition at line 2563 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(), and ExplainPropertyList().
{ Assert(es->format == EXPLAIN_FORMAT_JSON); if (linitial_int(es->grouping_stack) != 0) appendStringInfoChar(es->str, ','); else linitial_int(es->grouping_stack) = 1; appendStringInfoChar(es->str, '\n'); }
static void ExplainMemberNodes | ( | List * | plans, | |
PlanState ** | planstates, | |||
List * | ancestors, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 2088 of file explain.c.
References ExplainNode(), list_length(), and NULL.
Referenced by ExplainNode().
{ int nplans = list_length(plans); int j; for (j = 0; j < nplans; j++) ExplainNode(planstates[j], ancestors, "Member", NULL, es); }
static void ExplainModifyTarget | ( | ModifyTable * | plan, | |
ExplainState * | es | |||
) | [static] |
Definition at line 1934 of file explain.c.
References Assert, ExplainTargetRel(), linitial_int, NIL, and ModifyTable::resultRelations.
Referenced by ExplainNode().
{ Index rti; /* * We show the name of the first target relation. In multi-target-table * cases this should always be the parent of the inheritance tree. */ Assert(plan->resultRelations != NIL); rti = linitial_int(plan->resultRelations); ExplainTargetRel((Plan *) plan, rti, es); }
static void ExplainNode | ( | PlanState * | planstate, | |
List * | ancestors, | |||
const char * | relationship, | |||
const char * | plan_name, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 799 of file explain.c.
References AGG_HASHED, AGG_PLAIN, AGG_SORTED, ExplainState::analyze, appendStringInfo(), appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), BufferUsage::blk_read_time, BufferUsage::blk_write_time, ExplainState::buffers, Instrumentation::bufusage, CMD_DELETE, CMD_INSERT, CMD_UPDATE, ExplainState::costs, EXPLAIN_FORMAT_TEXT, explain_get_index_name(), ExplainCloseGroup(), ExplainIndexScanDetails(), ExplainMemberNodes(), ExplainModifyTarget(), ExplainOpenGroup(), ExplainPropertyFloat(), ExplainPropertyInteger(), ExplainPropertyLong(), ExplainPropertyText(), ExplainScanTarget(), ExplainSubPlans(), ExplainState::format, ExplainState::indent, BitmapIndexScan::indexid, IndexOnlyScan::indexid, IndexScan::indexid, IndexOnlyScan::indexorderdir, IndexScan::indexorderdir, PlanState::initPlan, innerPlanState, INSTR_TIME_GET_MILLISEC, INSTR_TIME_IS_ZERO, InstrEndLoop(), PlanState::instrument, IsA, JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, JOIN_SEMI, lcons(), list_delete_first(), list_length(), list_make1, BufferUsage::local_blks_dirtied, BufferUsage::local_blks_hit, BufferUsage::local_blks_read, BufferUsage::local_blks_written, make_orclause(), Instrumentation::need_timer, Instrumentation::nloops, nodeTag, Instrumentation::ntuples, NULL, outerPlanState, PlanState::plan, Plan::plan_rows, Plan::plan_width, SETOP_HASHED, SETOP_SORTED, SETOPCMD_EXCEPT, SETOPCMD_EXCEPT_ALL, SETOPCMD_INTERSECT, SETOPCMD_INTERSECT_ALL, BufferUsage::shared_blks_dirtied, BufferUsage::shared_blks_hit, BufferUsage::shared_blks_read, BufferUsage::shared_blks_written, show_expression(), show_foreignscan_info(), 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_upper_qual(), Instrumentation::startup, Plan::startup_cost, ExplainState::str, PlanState::subPlan, T_Agg, T_Append, T_BitmapAnd, T_BitmapHeapScan, T_BitmapIndexScan, T_BitmapOr, T_CteScan, T_ForeignScan, T_FunctionScan, 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_RecursiveUnion, T_Result, T_SeqScan, T_SetOp, T_Sort, T_SubqueryScan, T_TidScan, T_Unique, T_ValuesScan, T_WindowAgg, T_WorkTableScan, BufferUsage::temp_blks_read, BufferUsage::temp_blks_written, Instrumentation::total, Plan::total_cost, usage(), and ExplainState::verbose.
Referenced by ExplainMemberNodes(), ExplainPrintPlan(), and ExplainSubPlans().
{ Plan *plan = planstate->plan; const char *pname; /* node type name for text output */ const char *sname; /* node type name for non-text output */ const char *strategy = NULL; const char *operation = NULL; int save_indent = es->indent; bool haschildren; switch (nodeTag(plan)) { case T_Result: pname = sname = "Result"; break; case T_ModifyTable: sname = "ModifyTable"; switch (((ModifyTable *) plan)->operation) { case CMD_INSERT: pname = operation = "Insert"; break; case CMD_UPDATE: pname = operation = "Update"; break; case CMD_DELETE: pname = operation = "Delete"; break; default: pname = "???"; break; } break; case T_Append: pname = sname = "Append"; break; case T_MergeAppend: pname = sname = "Merge Append"; break; case T_RecursiveUnion: pname = sname = "Recursive Union"; break; case T_BitmapAnd: pname = sname = "BitmapAnd"; break; case T_BitmapOr: pname = sname = "BitmapOr"; break; case T_NestLoop: pname = sname = "Nested Loop"; break; case T_MergeJoin: pname = "Merge"; /* "Join" gets added by jointype switch */ sname = "Merge Join"; break; case T_HashJoin: pname = "Hash"; /* "Join" gets added by jointype switch */ sname = "Hash Join"; break; case T_SeqScan: pname = sname = "Seq Scan"; break; case T_IndexScan: pname = sname = "Index Scan"; break; case T_IndexOnlyScan: pname = sname = "Index Only Scan"; break; case T_BitmapIndexScan: pname = sname = "Bitmap Index Scan"; break; case T_BitmapHeapScan: pname = sname = "Bitmap Heap Scan"; break; case T_TidScan: pname = sname = "Tid Scan"; break; case T_SubqueryScan: pname = sname = "Subquery Scan"; break; case T_FunctionScan: pname = sname = "Function Scan"; break; case T_ValuesScan: pname = sname = "Values Scan"; break; case T_CteScan: pname = sname = "CTE Scan"; break; case T_WorkTableScan: pname = sname = "WorkTable Scan"; break; case T_ForeignScan: pname = sname = "Foreign Scan"; break; case T_Material: pname = sname = "Materialize"; break; case T_Sort: pname = sname = "Sort"; break; case T_Group: pname = sname = "Group"; break; case T_Agg: sname = "Aggregate"; switch (((Agg *) plan)->aggstrategy) { case AGG_PLAIN: pname = "Aggregate"; strategy = "Plain"; break; case AGG_SORTED: pname = "GroupAggregate"; strategy = "Sorted"; break; case AGG_HASHED: pname = "HashAggregate"; strategy = "Hashed"; break; default: pname = "Aggregate ???"; strategy = "???"; break; } break; case T_WindowAgg: pname = sname = "WindowAgg"; break; case T_Unique: pname = sname = "Unique"; break; case T_SetOp: sname = "SetOp"; switch (((SetOp *) plan)->strategy) { case SETOP_SORTED: pname = "SetOp"; strategy = "Sorted"; break; case SETOP_HASHED: pname = "HashSetOp"; strategy = "Hashed"; break; default: pname = "SetOp ???"; strategy = "???"; break; } break; case T_LockRows: pname = sname = "LockRows"; break; case T_Limit: pname = sname = "Limit"; break; case T_Hash: pname = sname = "Hash"; break; default: pname = sname = "???"; break; } ExplainOpenGroup("Plan", relationship ? NULL : "Plan", true, es); if (es->format == EXPLAIN_FORMAT_TEXT) { if (plan_name) { appendStringInfoSpaces(es->str, es->indent * 2); appendStringInfo(es->str, "%s\n", plan_name); es->indent++; } if (es->indent) { appendStringInfoSpaces(es->str, es->indent * 2); appendStringInfoString(es->str, "-> "); es->indent += 2; } appendStringInfoString(es->str, pname); es->indent++; } else { ExplainPropertyText("Node Type", sname, es); if (strategy) ExplainPropertyText("Strategy", strategy, es); if (operation) ExplainPropertyText("Operation", operation, es); if (relationship) ExplainPropertyText("Parent Relationship", relationship, es); if (plan_name) ExplainPropertyText("Subplan Name", plan_name, es); } switch (nodeTag(plan)) { case T_SeqScan: case T_BitmapHeapScan: case T_TidScan: case T_SubqueryScan: case T_FunctionScan: case T_ValuesScan: case T_CteScan: case T_WorkTableScan: case T_ForeignScan: ExplainScanTarget((Scan *) plan, es); break; case T_IndexScan: { IndexScan *indexscan = (IndexScan *) plan; ExplainIndexScanDetails(indexscan->indexid, indexscan->indexorderdir, es); ExplainScanTarget((Scan *) indexscan, es); } break; case T_IndexOnlyScan: { IndexOnlyScan *indexonlyscan = (IndexOnlyScan *) plan; ExplainIndexScanDetails(indexonlyscan->indexid, indexonlyscan->indexorderdir, es); ExplainScanTarget((Scan *) indexonlyscan, es); } break; case T_BitmapIndexScan: { BitmapIndexScan *bitmapindexscan = (BitmapIndexScan *) plan; const char *indexname = explain_get_index_name(bitmapindexscan->indexid); if (es->format == EXPLAIN_FORMAT_TEXT) appendStringInfo(es->str, " on %s", indexname); else ExplainPropertyText("Index Name", indexname, es); } break; case T_ModifyTable: ExplainModifyTarget((ModifyTable *) plan, es); break; case T_NestLoop: case T_MergeJoin: case T_HashJoin: { const char *jointype; switch (((Join *) plan)->jointype) { case JOIN_INNER: jointype = "Inner"; break; case JOIN_LEFT: jointype = "Left"; break; case JOIN_FULL: jointype = "Full"; break; case JOIN_RIGHT: jointype = "Right"; break; case JOIN_SEMI: jointype = "Semi"; break; case JOIN_ANTI: jointype = "Anti"; break; default: jointype = "???"; break; } if (es->format == EXPLAIN_FORMAT_TEXT) { /* * For historical reasons, the join type is interpolated * into the node type name... */ if (((Join *) plan)->jointype != JOIN_INNER) appendStringInfo(es->str, " %s Join", jointype); else if (!IsA(plan, NestLoop)) appendStringInfo(es->str, " Join"); } else ExplainPropertyText("Join Type", jointype, es); } break; case T_SetOp: { const char *setopcmd; switch (((SetOp *) plan)->cmd) { case SETOPCMD_INTERSECT: setopcmd = "Intersect"; break; case SETOPCMD_INTERSECT_ALL: setopcmd = "Intersect All"; break; case SETOPCMD_EXCEPT: setopcmd = "Except"; break; case SETOPCMD_EXCEPT_ALL: setopcmd = "Except All"; break; default: setopcmd = "???"; break; } if (es->format == EXPLAIN_FORMAT_TEXT) appendStringInfo(es->str, " %s", setopcmd); else ExplainPropertyText("Command", setopcmd, es); } break; default: break; } if (es->costs) { if (es->format == EXPLAIN_FORMAT_TEXT) { appendStringInfo(es->str, " (cost=%.2f..%.2f rows=%.0f width=%d)", plan->startup_cost, plan->total_cost, plan->plan_rows, plan->plan_width); } else { ExplainPropertyFloat("Startup Cost", plan->startup_cost, 2, es); ExplainPropertyFloat("Total Cost", plan->total_cost, 2, es); ExplainPropertyFloat("Plan Rows", plan->plan_rows, 0, es); ExplainPropertyInteger("Plan Width", plan->plan_width, es); } } /* * We have to forcibly clean up the instrumentation state because we * haven't done ExecutorEnd yet. This is pretty grotty ... */ if (planstate->instrument) InstrEndLoop(planstate->instrument); if (planstate->instrument && planstate->instrument->nloops > 0) { double nloops = planstate->instrument->nloops; double startup_sec = 1000.0 * planstate->instrument->startup / nloops; double total_sec = 1000.0 * planstate->instrument->total / nloops; double rows = planstate->instrument->ntuples / nloops; if (es->format == EXPLAIN_FORMAT_TEXT) { if (planstate->instrument->need_timer) appendStringInfo(es->str, " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)", startup_sec, total_sec, rows, nloops); else appendStringInfo(es->str, " (actual rows=%.0f loops=%.0f)", rows, nloops); } else { if (planstate->instrument->need_timer) { ExplainPropertyFloat("Actual Startup Time", startup_sec, 3, es); ExplainPropertyFloat("Actual Total Time", total_sec, 3, es); } ExplainPropertyFloat("Actual Rows", rows, 0, es); ExplainPropertyFloat("Actual Loops", nloops, 0, es); } } else if (es->analyze) { if (es->format == EXPLAIN_FORMAT_TEXT) appendStringInfo(es->str, " (never executed)"); else if (planstate->instrument->need_timer) { ExplainPropertyFloat("Actual Startup Time", 0.0, 3, es); ExplainPropertyFloat("Actual Total Time", 0.0, 3, es); } else { ExplainPropertyFloat("Actual Rows", 0.0, 0, es); ExplainPropertyFloat("Actual Loops", 0.0, 0, es); } } /* in text format, first line ends here */ if (es->format == EXPLAIN_FORMAT_TEXT) appendStringInfoChar(es->str, '\n'); /* target list */ if (es->verbose) show_plan_tlist(planstate, ancestors, es); /* quals, sort keys, etc */ switch (nodeTag(plan)) { case T_IndexScan: show_scan_qual(((IndexScan *) plan)->indexqualorig, "Index Cond", planstate, ancestors, es); if (((IndexScan *) plan)->indexqualorig) show_instrumentation_count("Rows Removed by Index Recheck", 2, planstate, es); show_scan_qual(((IndexScan *) plan)->indexorderbyorig, "Order By", planstate, ancestors, es); show_scan_qual(plan->qual, "Filter", planstate, ancestors, es); if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, planstate, es); break; case T_IndexOnlyScan: show_scan_qual(((IndexOnlyScan *) plan)->indexqual, "Index Cond", planstate, ancestors, es); if (((IndexOnlyScan *) plan)->indexqual) show_instrumentation_count("Rows Removed by Index Recheck", 2, planstate, es); show_scan_qual(((IndexOnlyScan *) plan)->indexorderby, "Order By", planstate, ancestors, es); show_scan_qual(plan->qual, "Filter", planstate, ancestors, es); if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, planstate, es); if (es->analyze) ExplainPropertyLong("Heap Fetches", ((IndexOnlyScanState *) planstate)->ioss_HeapFetches, es); break; case T_BitmapIndexScan: show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig, "Index Cond", planstate, ancestors, es); break; case T_BitmapHeapScan: show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig, "Recheck Cond", planstate, ancestors, es); if (((BitmapHeapScan *) plan)->bitmapqualorig) show_instrumentation_count("Rows Removed by Index Recheck", 2, planstate, es); /* FALL THRU */ case T_SeqScan: case T_ValuesScan: case T_CteScan: case T_WorkTableScan: case T_SubqueryScan: show_scan_qual(plan->qual, "Filter", planstate, ancestors, es); if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, planstate, es); break; case T_FunctionScan: if (es->verbose) show_expression(((FunctionScan *) plan)->funcexpr, "Function Call", planstate, ancestors, es->verbose, es); show_scan_qual(plan->qual, "Filter", planstate, ancestors, es); if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, planstate, es); break; case T_TidScan: { /* * The tidquals list has OR semantics, so be sure to show it * as an OR condition. */ List *tidquals = ((TidScan *) plan)->tidquals; if (list_length(tidquals) > 1) tidquals = list_make1(make_orclause(tidquals)); show_scan_qual(tidquals, "TID Cond", planstate, ancestors, es); show_scan_qual(plan->qual, "Filter", planstate, ancestors, es); if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, planstate, es); } break; case T_ForeignScan: show_scan_qual(plan->qual, "Filter", planstate, ancestors, es); if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, planstate, es); show_foreignscan_info((ForeignScanState *) planstate, es); break; case T_NestLoop: show_upper_qual(((NestLoop *) plan)->join.joinqual, "Join Filter", planstate, ancestors, es); if (((NestLoop *) plan)->join.joinqual) show_instrumentation_count("Rows Removed by Join Filter", 1, planstate, es); show_upper_qual(plan->qual, "Filter", planstate, ancestors, es); if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 2, planstate, es); break; case T_MergeJoin: show_upper_qual(((MergeJoin *) plan)->mergeclauses, "Merge Cond", planstate, ancestors, es); show_upper_qual(((MergeJoin *) plan)->join.joinqual, "Join Filter", planstate, ancestors, es); if (((MergeJoin *) plan)->join.joinqual) show_instrumentation_count("Rows Removed by Join Filter", 1, planstate, es); show_upper_qual(plan->qual, "Filter", planstate, ancestors, es); if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 2, planstate, es); break; case T_HashJoin: show_upper_qual(((HashJoin *) plan)->hashclauses, "Hash Cond", planstate, ancestors, es); show_upper_qual(((HashJoin *) plan)->join.joinqual, "Join Filter", planstate, ancestors, es); if (((HashJoin *) plan)->join.joinqual) show_instrumentation_count("Rows Removed by Join Filter", 1, planstate, es); show_upper_qual(plan->qual, "Filter", planstate, ancestors, es); if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 2, planstate, es); break; case T_Agg: case T_Group: show_upper_qual(plan->qual, "Filter", planstate, ancestors, es); if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, planstate, es); break; case T_Sort: show_sort_keys((SortState *) planstate, ancestors, es); show_sort_info((SortState *) planstate, es); break; case T_MergeAppend: show_merge_append_keys((MergeAppendState *) planstate, ancestors, es); break; case T_Result: show_upper_qual((List *) ((Result *) plan)->resconstantqual, "One-Time Filter", planstate, ancestors, es); show_upper_qual(plan->qual, "Filter", planstate, ancestors, es); if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, planstate, es); break; case T_ModifyTable: show_modifytable_info((ModifyTableState *) planstate, es); break; case T_Hash: show_hash_info((HashState *) planstate, es); break; default: break; } /* Show buffer usage */ if (es->buffers) { const BufferUsage *usage = &planstate->instrument->bufusage; if (es->format == EXPLAIN_FORMAT_TEXT) { bool has_shared = (usage->shared_blks_hit > 0 || usage->shared_blks_read > 0 || usage->shared_blks_dirtied > 0 || usage->shared_blks_written > 0); bool has_local = (usage->local_blks_hit > 0 || usage->local_blks_read > 0 || usage->local_blks_dirtied > 0 || usage->local_blks_written > 0); bool has_temp = (usage->temp_blks_read > 0 || usage->temp_blks_written > 0); bool has_timing = (!INSTR_TIME_IS_ZERO(usage->blk_read_time) || !INSTR_TIME_IS_ZERO(usage->blk_write_time)); /* Show only positive counter values. */ if (has_shared || has_local || has_temp) { appendStringInfoSpaces(es->str, es->indent * 2); appendStringInfoString(es->str, "Buffers:"); if (has_shared) { appendStringInfoString(es->str, " shared"); if (usage->shared_blks_hit > 0) appendStringInfo(es->str, " hit=%ld", usage->shared_blks_hit); if (usage->shared_blks_read > 0) appendStringInfo(es->str, " read=%ld", usage->shared_blks_read); if (usage->shared_blks_dirtied > 0) appendStringInfo(es->str, " dirtied=%ld", usage->shared_blks_dirtied); if (usage->shared_blks_written > 0) appendStringInfo(es->str, " written=%ld", usage->shared_blks_written); if (has_local || has_temp) appendStringInfoChar(es->str, ','); } if (has_local) { appendStringInfoString(es->str, " local"); if (usage->local_blks_hit > 0) appendStringInfo(es->str, " hit=%ld", usage->local_blks_hit); if (usage->local_blks_read > 0) appendStringInfo(es->str, " read=%ld", usage->local_blks_read); if (usage->local_blks_dirtied > 0) appendStringInfo(es->str, " dirtied=%ld", usage->local_blks_dirtied); if (usage->local_blks_written > 0) appendStringInfo(es->str, " written=%ld", usage->local_blks_written); if (has_temp) appendStringInfoChar(es->str, ','); } if (has_temp) { appendStringInfoString(es->str, " temp"); if (usage->temp_blks_read > 0) appendStringInfo(es->str, " read=%ld", usage->temp_blks_read); if (usage->temp_blks_written > 0) appendStringInfo(es->str, " written=%ld", usage->temp_blks_written); } appendStringInfoChar(es->str, '\n'); } /* As above, show only positive counter values. */ if (has_timing) { appendStringInfoSpaces(es->str, es->indent * 2); appendStringInfoString(es->str, "I/O Timings:"); if (!INSTR_TIME_IS_ZERO(usage->blk_read_time)) appendStringInfo(es->str, " read=%0.3f", INSTR_TIME_GET_MILLISEC(usage->blk_read_time)); if (!INSTR_TIME_IS_ZERO(usage->blk_write_time)) appendStringInfo(es->str, " write=%0.3f", INSTR_TIME_GET_MILLISEC(usage->blk_write_time)); appendStringInfoChar(es->str, '\n'); } } else { ExplainPropertyLong("Shared Hit Blocks", usage->shared_blks_hit, es); ExplainPropertyLong("Shared Read Blocks", usage->shared_blks_read, es); ExplainPropertyLong("Shared Dirtied Blocks", usage->shared_blks_dirtied, es); ExplainPropertyLong("Shared Written Blocks", usage->shared_blks_written, es); ExplainPropertyLong("Local Hit Blocks", usage->local_blks_hit, es); ExplainPropertyLong("Local Read Blocks", usage->local_blks_read, es); ExplainPropertyLong("Local Dirtied Blocks", usage->local_blks_dirtied, es); ExplainPropertyLong("Local Written Blocks", usage->local_blks_written, es); ExplainPropertyLong("Temp Read Blocks", usage->temp_blks_read, es); ExplainPropertyLong("Temp Written Blocks", usage->temp_blks_written, es); ExplainPropertyFloat("I/O Read Time", INSTR_TIME_GET_MILLISEC(usage->blk_read_time), 3, es); ExplainPropertyFloat("I/O Write Time", INSTR_TIME_GET_MILLISEC(usage->blk_write_time), 3, es); } } /* Get ready to display the child plans */ haschildren = planstate->initPlan || outerPlanState(planstate) || innerPlanState(planstate) || IsA(plan, ModifyTable) || IsA(plan, Append) || IsA(plan, MergeAppend) || IsA(plan, BitmapAnd) || IsA(plan, BitmapOr) || IsA(plan, SubqueryScan) || planstate->subPlan; if (haschildren) { ExplainOpenGroup("Plans", "Plans", false, es); /* Pass current PlanState as head of ancestors list for children */ ancestors = lcons(planstate, ancestors); } /* initPlan-s */ if (planstate->initPlan) ExplainSubPlans(planstate->initPlan, ancestors, "InitPlan", es); /* lefttree */ if (outerPlanState(planstate)) ExplainNode(outerPlanState(planstate), ancestors, "Outer", NULL, es); /* righttree */ if (innerPlanState(planstate)) ExplainNode(innerPlanState(planstate), ancestors, "Inner", NULL, es); /* special child plans */ switch (nodeTag(plan)) { case T_ModifyTable: ExplainMemberNodes(((ModifyTable *) plan)->plans, ((ModifyTableState *) planstate)->mt_plans, ancestors, es); break; case T_Append: ExplainMemberNodes(((Append *) plan)->appendplans, ((AppendState *) planstate)->appendplans, ancestors, es); break; case T_MergeAppend: ExplainMemberNodes(((MergeAppend *) plan)->mergeplans, ((MergeAppendState *) planstate)->mergeplans, ancestors, es); break; case T_BitmapAnd: ExplainMemberNodes(((BitmapAnd *) plan)->bitmapplans, ((BitmapAndState *) planstate)->bitmapplans, ancestors, es); break; case T_BitmapOr: ExplainMemberNodes(((BitmapOr *) plan)->bitmapplans, ((BitmapOrState *) planstate)->bitmapplans, ancestors, es); break; case T_SubqueryScan: ExplainNode(((SubqueryScanState *) planstate)->subplan, ancestors, "Subquery", NULL, es); break; default: break; } /* subPlan-s */ if (planstate->subPlan) ExplainSubPlans(planstate->subPlan, ancestors, "SubPlan", es); /* end of child plans */ if (haschildren) { ancestors = list_delete_first(ancestors); ExplainCloseGroup("Plans", "Plans", false, es); } /* in text format, undo whatever indentation we added */ if (es->format == EXPLAIN_FORMAT_TEXT) es->indent = save_indent; ExplainCloseGroup("Plan", relationship ? NULL : "Plan", true, es); }
void ExplainOnePlan | ( | PlannedStmt * | plannedstmt, | |
IntoClause * | into, | |||
ExplainState * | es, | |||
const char * | queryString, | |||
ParamListInfo | params | |||
) |
Definition at line 399 of file explain.c.
References ExplainState::analyze, appendStringInfo(), ExplainState::buffers, CommandCounterIncrement(), CreateIntoRelDestReceiver(), CreateQueryDesc(), elapsed_time(), EState::es_num_result_relations, EState::es_result_relations, EState::es_trig_target_relations, QueryDesc::estate, ExecutorEnd(), ExecutorFinish(), ExecutorRun(), ExecutorStart(), EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), ExplainOpenGroup(), ExplainPrintPlan(), ExplainPropertyFloat(), ExplainState::format, FreeQueryDesc(), GetActiveSnapshot(), GetIntoRelEFlags(), INSTR_TIME_SET_CURRENT, InvalidSnapshot, lfirst, None_Receiver, NULL, PopActiveSnapshot(), PushCopiedSnapshot(), report_triggers(), IntoClause::skipData, ExplainState::str, ExplainState::timing, and UpdateActiveSnapshotCommandId().
Referenced by ExplainExecuteQuery(), and ExplainOneQuery().
{ DestReceiver *dest; QueryDesc *queryDesc; instr_time starttime; double totaltime = 0; int eflags; int instrument_option = 0; if (es->analyze && es->timing) instrument_option |= INSTRUMENT_TIMER; else if (es->analyze) instrument_option |= INSTRUMENT_ROWS; if (es->buffers) instrument_option |= INSTRUMENT_BUFFERS; INSTR_TIME_SET_CURRENT(starttime); /* * Use a snapshot with an updated command ID to ensure this query sees * results of any previously executed queries. */ PushCopiedSnapshot(GetActiveSnapshot()); UpdateActiveSnapshotCommandId(); /* * Normally we discard the query's output, but if explaining CREATE TABLE * AS, we'd better use the appropriate tuple receiver. */ if (into) dest = CreateIntoRelDestReceiver(into); else dest = None_Receiver; /* Create a QueryDesc for the query */ queryDesc = CreateQueryDesc(plannedstmt, queryString, GetActiveSnapshot(), InvalidSnapshot, dest, params, instrument_option); /* Select execution options */ if (es->analyze) eflags = 0; /* default run-to-completion flags */ else eflags = EXEC_FLAG_EXPLAIN_ONLY; if (into) eflags |= GetIntoRelEFlags(into); /* call ExecutorStart to prepare the plan for execution */ ExecutorStart(queryDesc, eflags); /* Execute the plan for statistics if asked for */ if (es->analyze) { ScanDirection dir; /* EXPLAIN ANALYZE CREATE TABLE AS WITH NO DATA is weird */ if (into && into->skipData) dir = NoMovementScanDirection; else dir = ForwardScanDirection; /* run the plan */ ExecutorRun(queryDesc, dir, 0L); /* run cleanup too */ ExecutorFinish(queryDesc); /* We can't run ExecutorEnd 'till we're done printing the stats... */ totaltime += elapsed_time(&starttime); } ExplainOpenGroup("Query", NULL, true, es); /* Create textual dump of plan tree */ ExplainPrintPlan(es, queryDesc); /* Print info about runtime of triggers */ if (es->analyze) { ResultRelInfo *rInfo; bool show_relname; int numrels = queryDesc->estate->es_num_result_relations; List *targrels = queryDesc->estate->es_trig_target_relations; int nr; ListCell *l; ExplainOpenGroup("Triggers", "Triggers", false, es); show_relname = (numrels > 1 || targrels != NIL); rInfo = queryDesc->estate->es_result_relations; for (nr = 0; nr < numrels; rInfo++, nr++) report_triggers(rInfo, show_relname, es); foreach(l, targrels) { rInfo = (ResultRelInfo *) lfirst(l); report_triggers(rInfo, show_relname, es); } ExplainCloseGroup("Triggers", "Triggers", false, es); } /* * Close down the query and free resources. Include time for this in the * total runtime (although it should be pretty minimal). */ INSTR_TIME_SET_CURRENT(starttime); ExecutorEnd(queryDesc); FreeQueryDesc(queryDesc); PopActiveSnapshot(); /* We need a CCI just in case query expanded to multiple plans */ if (es->analyze) CommandCounterIncrement(); totaltime += elapsed_time(&starttime); if (es->analyze) { if (es->format == EXPLAIN_FORMAT_TEXT) appendStringInfo(es->str, "Total runtime: %.3f ms\n", 1000.0 * totaltime); else ExplainPropertyFloat("Total Runtime", 1000.0 * totaltime, 3, es); } ExplainCloseGroup("Query", NULL, true, es); }
static void ExplainOneQuery | ( | Query * | query, | |
IntoClause * | into, | |||
ExplainState * | es, | |||
const char * | queryString, | |||
ParamListInfo | params | |||
) | [static] |
Definition at line 302 of file explain.c.
References CMD_UTILITY, Query::commandType, ExplainOnePlan(), ExplainOneQuery_hook, ExplainOneUtility(), pg_plan_query(), and Query::utilityStmt.
Referenced by ExplainOneUtility(), and ExplainQuery().
{ /* planner will not cope with utility statements */ if (query->commandType == CMD_UTILITY) { ExplainOneUtility(query->utilityStmt, into, es, queryString, params); return; } /* if an advisor plugin is present, let it manage things */ if (ExplainOneQuery_hook) (*ExplainOneQuery_hook) (query, into, es, queryString, params); else { PlannedStmt *plan; /* plan the query */ plan = pg_plan_query(query, 0, params); /* run it (if needed) and produce output */ ExplainOnePlan(plan, into, es, queryString, params); } }
void ExplainOneUtility | ( | Node * | utilityStmt, | |
IntoClause * | into, | |||
ExplainState * | es, | |||
const char * | queryString, | |||
ParamListInfo | params | |||
) |
Definition at line 339 of file explain.c.
References appendStringInfoString(), Assert, copyObject(), EXPLAIN_FORMAT_TEXT, ExplainDummyGroup(), ExplainExecuteQuery(), ExplainOneQuery(), ExplainState::format, CreateTableAsStmt::into, IsA, linitial, list_length(), NULL, CreateTableAsStmt::query, QueryRewrite(), and ExplainState::str.
Referenced by ExplainExecuteQuery(), and ExplainOneQuery().
{ if (utilityStmt == NULL) return; if (IsA(utilityStmt, CreateTableAsStmt)) { /* * We have to rewrite the contained SELECT and then pass it back to * ExplainOneQuery. It's probably not really necessary to copy the * contained parsetree another time, but let's be safe. */ CreateTableAsStmt *ctas = (CreateTableAsStmt *) utilityStmt; List *rewritten; Assert(IsA(ctas->query, Query)); rewritten = QueryRewrite((Query *) copyObject(ctas->query)); Assert(list_length(rewritten) == 1); ExplainOneQuery((Query *) linitial(rewritten), ctas->into, es, queryString, params); } else if (IsA(utilityStmt, ExecuteStmt)) ExplainExecuteQuery((ExecuteStmt *) utilityStmt, into, es, queryString, params); else if (IsA(utilityStmt, NotifyStmt)) { if (es->format == EXPLAIN_FORMAT_TEXT) appendStringInfoString(es->str, "NOTIFY\n"); else ExplainDummyGroup("Notify", NULL, es); } else { if (es->format == EXPLAIN_FORMAT_TEXT) appendStringInfoString(es->str, "Utility statements have no plan structure\n"); else ExplainDummyGroup("Utility Statement", NULL, es); } }
static void ExplainOpenGroup | ( | const char * | objtype, | |
const char * | labelname, | |||
bool | labeled, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 2304 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(), and report_triggers().
{ switch (es->format) { case EXPLAIN_FORMAT_TEXT: /* nothing to do */ break; case EXPLAIN_FORMAT_XML: ExplainXMLTag(objtype, X_OPENING, es); es->indent++; break; case EXPLAIN_FORMAT_JSON: ExplainJSONLineEnding(es); appendStringInfoSpaces(es->str, 2 * es->indent); if (labelname) { escape_json(es->str, labelname); appendStringInfoString(es->str, ": "); } appendStringInfoChar(es->str, labeled ? '{' : '['); /* * In JSON format, the grouping_stack is an integer list. 0 means * we've emitted nothing at this grouping level, 1 means we've * emitted something (and so the next item needs a comma). See * ExplainJSONLineEnding(). */ es->grouping_stack = lcons_int(0, es->grouping_stack); es->indent++; break; case EXPLAIN_FORMAT_YAML: /* * In YAML format, the grouping stack is an integer list. 0 means * we've emitted nothing at this grouping level AND this grouping * level is unlabelled and must be marked with "- ". See * ExplainYAMLLineStarting(). */ ExplainYAMLLineStarting(es); if (labelname) { appendStringInfo(es->str, "%s: ", labelname); es->grouping_stack = lcons_int(1, es->grouping_stack); } else { appendStringInfoString(es->str, "- "); es->grouping_stack = lcons_int(0, es->grouping_stack); } es->indent++; break; } }
static void ExplainPreScanMemberNodes | ( | List * | plans, | |
PlanState ** | planstates, | |||
Bitmapset ** | rels_used | |||
) | [static] |
Definition at line 752 of file explain.c.
References ExplainPreScanNode(), and list_length().
Referenced by ExplainPreScanNode().
{ int nplans = list_length(plans); int j; for (j = 0; j < nplans; j++) ExplainPreScanNode(planstates[j], rels_used); }
Definition at line 662 of file explain.c.
References bms_add_member(), ExplainPreScanMemberNodes(), ExplainPreScanSubPlans(), PlanState::initPlan, innerPlanState, linitial_int, nodeTag, outerPlanState, PlanState::plan, PlanState::subPlan, T_Append, T_BitmapAnd, T_BitmapHeapScan, T_BitmapOr, T_CteScan, T_ForeignScan, T_FunctionScan, T_IndexOnlyScan, T_IndexScan, T_MergeAppend, T_ModifyTable, T_SeqScan, T_SubqueryScan, T_TidScan, T_ValuesScan, and T_WorkTableScan.
Referenced by ExplainPreScanMemberNodes(), ExplainPreScanSubPlans(), and ExplainPrintPlan().
{ Plan *plan = planstate->plan; switch (nodeTag(plan)) { case T_SeqScan: case T_IndexScan: case T_IndexOnlyScan: case T_BitmapHeapScan: case T_TidScan: case T_SubqueryScan: case T_FunctionScan: case T_ValuesScan: case T_CteScan: case T_WorkTableScan: case T_ForeignScan: *rels_used = bms_add_member(*rels_used, ((Scan *) plan)->scanrelid); break; case T_ModifyTable: /* cf ExplainModifyTarget */ *rels_used = bms_add_member(*rels_used, linitial_int(((ModifyTable *) plan)->resultRelations)); break; default: break; } /* initPlan-s */ if (planstate->initPlan) ExplainPreScanSubPlans(planstate->initPlan, rels_used); /* lefttree */ if (outerPlanState(planstate)) ExplainPreScanNode(outerPlanState(planstate), rels_used); /* righttree */ if (innerPlanState(planstate)) ExplainPreScanNode(innerPlanState(planstate), rels_used); /* special child plans */ switch (nodeTag(plan)) { case T_ModifyTable: ExplainPreScanMemberNodes(((ModifyTable *) plan)->plans, ((ModifyTableState *) planstate)->mt_plans, rels_used); break; case T_Append: ExplainPreScanMemberNodes(((Append *) plan)->appendplans, ((AppendState *) planstate)->appendplans, rels_used); break; case T_MergeAppend: ExplainPreScanMemberNodes(((MergeAppend *) plan)->mergeplans, ((MergeAppendState *) planstate)->mergeplans, rels_used); break; case T_BitmapAnd: ExplainPreScanMemberNodes(((BitmapAnd *) plan)->bitmapplans, ((BitmapAndState *) planstate)->bitmapplans, rels_used); break; case T_BitmapOr: ExplainPreScanMemberNodes(((BitmapOr *) plan)->bitmapplans, ((BitmapOrState *) planstate)->bitmapplans, rels_used); break; case T_SubqueryScan: ExplainPreScanNode(((SubqueryScanState *) planstate)->subplan, rels_used); break; default: break; } /* subPlan-s */ if (planstate->subPlan) ExplainPreScanSubPlans(planstate->subPlan, rels_used); }
Definition at line 766 of file explain.c.
References ExplainPreScanNode(), lfirst, and SubPlanState::planstate.
Referenced by ExplainPreScanNode().
{ ListCell *lst; foreach(lst, plans) { SubPlanState *sps = (SubPlanState *) lfirst(lst); ExplainPreScanNode(sps->planstate, rels_used); } }
void ExplainPrintPlan | ( | ExplainState * | es, | |
QueryDesc * | queryDesc | |||
) |
Definition at line 545 of file explain.c.
References Assert, ExplainNode(), ExplainPreScanNode(), NIL, NULL, QueryDesc::plannedstmt, QueryDesc::planstate, ExplainState::pstmt, PlannedStmt::rtable, ExplainState::rtable, ExplainState::rtable_names, and select_rtable_names_for_explain().
Referenced by explain_ExecutorEnd(), and ExplainOnePlan().
{ Bitmapset *rels_used = NULL; Assert(queryDesc->plannedstmt != NULL); es->pstmt = queryDesc->plannedstmt; es->rtable = queryDesc->plannedstmt->rtable; ExplainPreScanNode(queryDesc->planstate, &rels_used); es->rtable_names = select_rtable_names_for_explain(es->rtable, rels_used); ExplainNode(queryDesc->planstate, NIL, NULL, NULL, es); }
static void ExplainProperty | ( | const char * | qlabel, | |
const char * | value, | |||
bool | numeric, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 2201 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 ExplainPropertyFloat(), ExplainPropertyInteger(), ExplainPropertyLong(), and ExplainPropertyText().
{ switch (es->format) { case EXPLAIN_FORMAT_TEXT: appendStringInfoSpaces(es->str, es->indent * 2); appendStringInfo(es->str, "%s: %s\n", qlabel, value); break; case EXPLAIN_FORMAT_XML: { char *str; appendStringInfoSpaces(es->str, es->indent * 2); ExplainXMLTag(qlabel, X_OPENING | X_NOWHITESPACE, es); str = escape_xml(value); appendStringInfoString(es->str, str); pfree(str); ExplainXMLTag(qlabel, X_CLOSING | X_NOWHITESPACE, es); appendStringInfoChar(es->str, '\n'); } break; case EXPLAIN_FORMAT_JSON: ExplainJSONLineEnding(es); appendStringInfoSpaces(es->str, es->indent * 2); escape_json(es->str, qlabel); appendStringInfoString(es->str, ": "); if (numeric) appendStringInfoString(es->str, value); else escape_json(es->str, value); break; case EXPLAIN_FORMAT_YAML: ExplainYAMLLineStarting(es); appendStringInfo(es->str, "%s: ", qlabel); if (numeric) appendStringInfoString(es->str, value); else escape_yaml(es->str, value); break; } }
void ExplainPropertyFloat | ( | const char * | qlabel, | |
double | value, | |||
int | ndigits, | |||
ExplainState * | es | |||
) |
Definition at line 2285 of file explain.c.
References buf, ExplainProperty(), and snprintf().
Referenced by ExplainNode(), ExplainOnePlan(), report_triggers(), and show_instrumentation_count().
{ char buf[256]; snprintf(buf, sizeof(buf), "%.*f", ndigits, value); ExplainProperty(qlabel, buf, true, es); }
void ExplainPropertyInteger | ( | const char * | qlabel, | |
int | value, | |||
ExplainState * | es | |||
) |
Definition at line 2260 of file explain.c.
References buf, ExplainProperty(), and snprintf().
Referenced by ExplainNode().
{ char buf[32]; snprintf(buf, sizeof(buf), "%d", value); ExplainProperty(qlabel, buf, true, es); }
void ExplainPropertyList | ( | const char * | qlabel, | |
List * | data, | |||
ExplainState * | es | |||
) |
Definition at line 2126 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 show_plan_tlist(), and show_sort_keys_common().
{ ListCell *lc; bool first = true; switch (es->format) { case EXPLAIN_FORMAT_TEXT: appendStringInfoSpaces(es->str, es->indent * 2); appendStringInfo(es->str, "%s: ", qlabel); foreach(lc, data) { if (!first) appendStringInfoString(es->str, ", "); appendStringInfoString(es->str, (const char *) lfirst(lc)); first = false; } appendStringInfoChar(es->str, '\n'); break; case EXPLAIN_FORMAT_XML: ExplainXMLTag(qlabel, X_OPENING, es); foreach(lc, data) { char *str; appendStringInfoSpaces(es->str, es->indent * 2 + 2); appendStringInfoString(es->str, "<Item>"); str = escape_xml((const char *) lfirst(lc)); appendStringInfoString(es->str, str); pfree(str); appendStringInfoString(es->str, "</Item>\n"); } ExplainXMLTag(qlabel, X_CLOSING, es); break; case EXPLAIN_FORMAT_JSON: ExplainJSONLineEnding(es); appendStringInfoSpaces(es->str, es->indent * 2); escape_json(es->str, qlabel); appendStringInfoString(es->str, ": ["); foreach(lc, data) { if (!first) appendStringInfoString(es->str, ", "); escape_json(es->str, (const char *) lfirst(lc)); first = false; } appendStringInfoChar(es->str, ']'); break; case EXPLAIN_FORMAT_YAML: ExplainYAMLLineStarting(es); appendStringInfo(es->str, "%s: ", qlabel); foreach(lc, data) { appendStringInfoChar(es->str, '\n'); appendStringInfoSpaces(es->str, es->indent * 2 + 2); appendStringInfoString(es->str, "- "); escape_yaml(es->str, (const char *) lfirst(lc)); } break; } }
void ExplainPropertyLong | ( | const char * | qlabel, | |
long | value, | |||
ExplainState * | es | |||
) |
Definition at line 2272 of file explain.c.
References buf, ExplainProperty(), and snprintf().
Referenced by ExplainNode(), fileExplainForeignScan(), show_hash_info(), and show_sort_info().
{ char buf[32]; snprintf(buf, sizeof(buf), "%ld", value); ExplainProperty(qlabel, buf, true, es); }
void ExplainPropertyText | ( | const char * | qlabel, | |
const char * | value, | |||
ExplainState * | es | |||
) |
Definition at line 2251 of file explain.c.
References ExplainProperty().
Referenced by ExplainIndexScanDetails(), ExplainNode(), ExplainQueryText(), ExplainTargetRel(), fileExplainForeignScan(), postgresExplainForeignModify(), postgresExplainForeignScan(), report_triggers(), show_expression(), and show_sort_info().
{ ExplainProperty(qlabel, value, false, es); }
void ExplainQuery | ( | ExplainStmt * | stmt, | |
const char * | queryString, | |||
ParamListInfo | params, | |||
DestReceiver * | dest | |||
) |
Definition at line 118 of file explain.c.
References ExplainState::analyze, appendStringInfoString(), Assert, begin_tup_output_tupdesc(), ExplainState::buffers, copyObject(), ExplainState::costs, StringInfoData::data, defGetBoolean(), defGetString(), DefElem::defname, do_text_output_multiline(), do_text_output_oneline, end_tup_output(), ereport, errcode(), errmsg(), ERROR, EXPLAIN_FORMAT_TEXT, ExplainBeginOutput(), ExplainEndOutput(), ExplainInitState(), ExplainOneQuery(), ExplainResultDesc(), ExplainSeparatePlans(), ExplainState::format, ExplainState::indent, IsA, lfirst, lnext, NIL, NULL, ExplainStmt::options, pfree(), ExplainStmt::query, QueryRewrite(), ExplainState::str, ExplainState::timing, and ExplainState::verbose.
Referenced by standard_ProcessUtility().
{ ExplainState es; TupOutputState *tstate; List *rewritten; ListCell *lc; bool timing_set = false; /* Initialize ExplainState. */ ExplainInitState(&es); /* Parse options list. */ foreach(lc, stmt->options) { DefElem *opt = (DefElem *) lfirst(lc); if (strcmp(opt->defname, "analyze") == 0) es.analyze = defGetBoolean(opt); else if (strcmp(opt->defname, "verbose") == 0) es.verbose = defGetBoolean(opt); else if (strcmp(opt->defname, "costs") == 0) es.costs = defGetBoolean(opt); else if (strcmp(opt->defname, "buffers") == 0) es.buffers = defGetBoolean(opt); else if (strcmp(opt->defname, "timing") == 0) { timing_set = true; es.timing = defGetBoolean(opt); } else if (strcmp(opt->defname, "format") == 0) { char *p = defGetString(opt); if (strcmp(p, "text") == 0) es.format = EXPLAIN_FORMAT_TEXT; else if (strcmp(p, "xml") == 0) es.format = EXPLAIN_FORMAT_XML; else if (strcmp(p, "json") == 0) es.format = EXPLAIN_FORMAT_JSON; else if (strcmp(p, "yaml") == 0) es.format = EXPLAIN_FORMAT_YAML; else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized value for EXPLAIN option \"%s\": \"%s\"", opt->defname, p))); } else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("unrecognized EXPLAIN option \"%s\"", opt->defname))); } if (es.buffers && !es.analyze) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("EXPLAIN option BUFFERS requires ANALYZE"))); /* if the timing was not set explicitly, set default value */ es.timing = (timing_set) ? es.timing : es.analyze; /* check that timing is used with EXPLAIN ANALYZE */ if (es.timing && !es.analyze) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("EXPLAIN option TIMING requires ANALYZE"))); /* * Parse analysis was done already, but we still have to run the rule * rewriter. We do not do AcquireRewriteLocks: we assume the query either * came straight from the parser, or suitable locks were acquired by * plancache.c. * * Because the rewriter and planner tend to scribble on the input, we make * a preliminary copy of the source querytree. This prevents problems in * the case that the EXPLAIN is in a portal or plpgsql function and is * executed repeatedly. (See also the same hack in DECLARE CURSOR and * PREPARE.) XXX FIXME someday. */ Assert(IsA(stmt->query, Query)); rewritten = QueryRewrite((Query *) copyObject(stmt->query)); /* emit opening boilerplate */ ExplainBeginOutput(&es); if (rewritten == NIL) { /* * In the case of an INSTEAD NOTHING, tell at least that. But in * non-text format, the output is delimited, so this isn't necessary. */ if (es.format == EXPLAIN_FORMAT_TEXT) appendStringInfoString(es.str, "Query rewrites to nothing\n"); } else { ListCell *l; /* Explain every plan */ foreach(l, rewritten) { ExplainOneQuery((Query *) lfirst(l), NULL, &es, queryString, params); /* Separate plans with an appropriate separator */ if (lnext(l) != NULL) ExplainSeparatePlans(&es); } } /* emit closing boilerplate */ ExplainEndOutput(&es); Assert(es.indent == 0); /* output tuples */ tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt)); if (es.format == EXPLAIN_FORMAT_TEXT) do_text_output_multiline(tstate, es.str->data); else do_text_output_oneline(tstate, es.str->data); end_tup_output(tstate); pfree(es.str->data); }
void ExplainQueryText | ( | ExplainState * | es, | |
QueryDesc * | queryDesc | |||
) |
Definition at line 566 of file explain.c.
References ExplainPropertyText(), and QueryDesc::sourceText.
Referenced by explain_ExecutorEnd().
{ if (queryDesc->sourceText) ExplainPropertyText("Query Text", queryDesc->sourceText, es); }
TupleDesc ExplainResultDesc | ( | ExplainStmt * | stmt | ) |
Definition at line 263 of file explain.c.
References CreateTemplateTupleDesc(), defGetString(), DefElem::defname, lfirst, ExplainStmt::options, and TupleDescInitEntry().
Referenced by ExplainQuery(), and UtilityTupleDescriptor().
{ TupleDesc tupdesc; ListCell *lc; Oid result_type = TEXTOID; /* Check for XML format option */ foreach(lc, stmt->options) { DefElem *opt = (DefElem *) lfirst(lc); if (strcmp(opt->defname, "format") == 0) { char *p = defGetString(opt); if (strcmp(p, "xml") == 0) result_type = XMLOID; else if (strcmp(p, "json") == 0) result_type = JSONOID; else result_type = TEXTOID; /* don't "break", as ExplainQuery will use the last value */ } } /* Need a tuple descriptor representing a single TEXT or XML column */ tupdesc = CreateTemplateTupleDesc(1, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN", result_type, -1, 0); return tupdesc; }
static void ExplainScanTarget | ( | Scan * | plan, | |
ExplainState * | es | |||
) | [static] |
Definition at line 1925 of file explain.c.
References ExplainTargetRel().
Referenced by ExplainNode().
{ ExplainTargetRel((Plan *) plan, plan->scanrelid, es); }
void ExplainSeparatePlans | ( | ExplainState * | es | ) |
Definition at line 2509 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().
{ switch (es->format) { case EXPLAIN_FORMAT_TEXT: /* add a blank line */ appendStringInfoChar(es->str, '\n'); break; case EXPLAIN_FORMAT_XML: case EXPLAIN_FORMAT_JSON: case EXPLAIN_FORMAT_YAML: /* nothing to do */ break; } }
static void ExplainSubPlans | ( | List * | plans, | |
List * | ancestors, | |||
const char * | relationship, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 2106 of file explain.c.
References ExplainNode(), ExprState::expr, lfirst, SubPlan::plan_name, SubPlanState::planstate, and SubPlanState::xprstate.
Referenced by ExplainNode().
{ ListCell *lst; foreach(lst, plans) { SubPlanState *sps = (SubPlanState *) lfirst(lst); SubPlan *sp = (SubPlan *) sps->xprstate.expr; ExplainNode(sps->planstate, ancestors, relationship, sp->plan_name, es); } }
static void ExplainTargetRel | ( | Plan * | plan, | |
Index | rti, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 1952 of file explain.c.
References Alias::aliasname, appendStringInfo(), appendStringInfoString(), Assert, RangeTblEntry::eref, EXPLAIN_FORMAT_TEXT, ExplainPropertyText(), ExplainState::format, get_func_name(), get_namespace_name(), get_rel_name(), IsA, 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_ForeignScan, T_FunctionScan, T_IndexOnlyScan, T_IndexScan, T_ModifyTable, T_SeqScan, T_TidScan, T_ValuesScan, T_WorkTableScan, and ExplainState::verbose.
Referenced by ExplainModifyTarget(), and ExplainScanTarget().
{ char *objectname = NULL; char *namespace = NULL; const char *objecttag = NULL; RangeTblEntry *rte; char *refname; rte = rt_fetch(rti, es->rtable); refname = (char *) list_nth(es->rtable_names, rti - 1); if (refname == NULL) refname = rte->eref->aliasname; switch (nodeTag(plan)) { case T_SeqScan: case T_IndexScan: case T_IndexOnlyScan: case T_BitmapHeapScan: case T_TidScan: case T_ForeignScan: case T_ModifyTable: /* Assert it's on a real relation */ Assert(rte->rtekind == RTE_RELATION); objectname = get_rel_name(rte->relid); if (es->verbose) namespace = get_namespace_name(get_rel_namespace(rte->relid)); objecttag = "Relation Name"; break; case T_FunctionScan: { Node *funcexpr; /* Assert it's on a RangeFunction */ Assert(rte->rtekind == RTE_FUNCTION); /* * If the expression is still a function call, we can get the * real name of the function. Otherwise, punt (this can * happen if the optimizer simplified away the function call, * for example). */ funcexpr = ((FunctionScan *) plan)->funcexpr; if (funcexpr && IsA(funcexpr, FuncExpr)) { Oid funcid = ((FuncExpr *) funcexpr)->funcid; objectname = get_func_name(funcid); if (es->verbose) namespace = get_namespace_name(get_func_namespace(funcid)); } objecttag = "Function Name"; } break; case T_ValuesScan: Assert(rte->rtekind == RTE_VALUES); break; case T_CteScan: /* Assert it's on a non-self-reference CTE */ Assert(rte->rtekind == RTE_CTE); Assert(!rte->self_reference); objectname = rte->ctename; objecttag = "CTE Name"; break; case T_WorkTableScan: /* Assert it's on a self-reference CTE */ Assert(rte->rtekind == RTE_CTE); Assert(rte->self_reference); objectname = rte->ctename; objecttag = "CTE Name"; break; default: break; } if (es->format == EXPLAIN_FORMAT_TEXT) { appendStringInfoString(es->str, " on"); if (namespace != NULL) appendStringInfo(es->str, " %s.%s", quote_identifier(namespace), quote_identifier(objectname)); else if (objectname != NULL) appendStringInfo(es->str, " %s", quote_identifier(objectname)); if (objectname == NULL || strcmp(refname, objectname) != 0) appendStringInfo(es->str, " %s", quote_identifier(refname)); } else { if (objecttag != NULL && objectname != NULL) ExplainPropertyText(objecttag, objectname, es); if (namespace != NULL) ExplainPropertyText("Schema", namespace, es); ExplainPropertyText("Alias", refname, es); } }
static void ExplainXMLTag | ( | const char * | tagname, | |
int | flags, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 2537 of file explain.c.
References appendStringInfoCharMacro, appendStringInfoSpaces(), appendStringInfoString(), ExplainState::indent, ExplainState::str, X_CLOSE_IMMEDIATE, X_CLOSING, and X_NOWHITESPACE.
Referenced by ExplainCloseGroup(), ExplainDummyGroup(), ExplainOpenGroup(), ExplainProperty(), and ExplainPropertyList().
{ const char *s; if ((flags & X_NOWHITESPACE) == 0) appendStringInfoSpaces(es->str, 2 * es->indent); appendStringInfoCharMacro(es->str, '<'); if ((flags & X_CLOSING) != 0) appendStringInfoCharMacro(es->str, '/'); for (s = tagname; *s; s++) appendStringInfoCharMacro(es->str, (*s == ' ') ? '-' : *s); if ((flags & X_CLOSE_IMMEDIATE) != 0) appendStringInfoString(es->str, " /"); appendStringInfoCharMacro(es->str, '>'); if ((flags & X_NOWHITESPACE) == 0) appendStringInfoCharMacro(es->str, '\n'); }
static void ExplainYAMLLineStarting | ( | ExplainState * | es | ) | [static] |
Definition at line 2583 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(), and ExplainPropertyList().
{ Assert(es->format == EXPLAIN_FORMAT_YAML); if (linitial_int(es->grouping_stack) == 0) { linitial_int(es->grouping_stack) = 1; } else { appendStringInfoChar(es->str, '\n'); appendStringInfoSpaces(es->str, es->indent * 2); } }
static void report_triggers | ( | ResultRelInfo * | rInfo, | |
bool | show_relname, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 577 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, Instrumentation::total, TriggerDesc::triggers, and ExplainState::verbose.
Referenced by ExplainOnePlan().
{ int nt; if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument) return; for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++) { Trigger *trig = rInfo->ri_TrigDesc->triggers + nt; Instrumentation *instr = rInfo->ri_TrigInstrument + nt; char *relname; char *conname = NULL; /* Must clean up instrumentation state */ InstrEndLoop(instr); /* * We ignore triggers that were never invoked; they likely aren't * relevant to the current query type. */ if (instr->ntuples == 0) continue; ExplainOpenGroup("Trigger", NULL, true, es); relname = RelationGetRelationName(rInfo->ri_RelationDesc); if (OidIsValid(trig->tgconstraint)) conname = get_constraint_name(trig->tgconstraint); /* * In text format, we avoid printing both the trigger name and the * constraint name unless VERBOSE is specified. In non-text formats * we just print everything. */ if (es->format == EXPLAIN_FORMAT_TEXT) { if (es->verbose || conname == NULL) appendStringInfo(es->str, "Trigger %s", trig->tgname); else appendStringInfoString(es->str, "Trigger"); if (conname) appendStringInfo(es->str, " for constraint %s", conname); if (show_relname) appendStringInfo(es->str, " on %s", relname); appendStringInfo(es->str, ": time=%.3f calls=%.0f\n", 1000.0 * instr->total, instr->ntuples); } else { ExplainPropertyText("Trigger Name", trig->tgname, es); if (conname) ExplainPropertyText("Constraint Name", conname, es); ExplainPropertyText("Relation", relname, es); ExplainPropertyFloat("Time", 1000.0 * instr->total, 3, es); ExplainPropertyFloat("Calls", instr->ntuples, 0, es); } if (conname) pfree(conname); ExplainCloseGroup("Trigger", NULL, true, es); } }
static void show_expression | ( | Node * | node, | |
const char * | qlabel, | |||
PlanState * | planstate, | |||
List * | ancestors, | |||
bool | useprefix, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 1603 of file explain.c.
References deparse_context_for_planstate(), deparse_expression(), ExplainPropertyText(), ExplainState::rtable, and ExplainState::rtable_names.
Referenced by ExplainNode(), and show_qual().
{ List *context; char *exprstr; /* Set up deparsing context */ context = deparse_context_for_planstate((Node *) planstate, ancestors, es->rtable, es->rtable_names); /* Deparse the expression */ exprstr = deparse_expression(node, context, useprefix, false); /* And add to es->str */ ExplainPropertyText(qlabel, exprstr, es); }
static void show_foreignscan_info | ( | ForeignScanState * | fsstate, | |
ExplainState * | es | |||
) | [static] |
Definition at line 1847 of file explain.c.
References FdwRoutine::ExplainForeignScan, ForeignScanState::fdwroutine, and NULL.
Referenced by ExplainNode().
{ FdwRoutine *fdwroutine = fsstate->fdwroutine; /* Let the FDW emit whatever fields it wants */ if (fdwroutine->ExplainForeignScan != NULL) fdwroutine->ExplainForeignScan(fsstate, es); }
static void show_hash_info | ( | HashState * | hashstate, | |
ExplainState * | es | |||
) | [static] |
Definition at line 1774 of file explain.c.
References appendStringInfo(), appendStringInfoSpaces(), Assert, EXPLAIN_FORMAT_TEXT, ExplainPropertyLong(), ExplainState::format, HashState::hashtable, ExplainState::indent, IsA, HashJoinTableData::nbatch, HashJoinTableData::nbatch_original, HashJoinTableData::nbuckets, HashJoinTableData::spacePeak, and ExplainState::str.
Referenced by ExplainNode().
{ HashJoinTable hashtable; Assert(IsA(hashstate, HashState)); hashtable = hashstate->hashtable; if (hashtable) { long spacePeakKb = (hashtable->spacePeak + 1023) / 1024; if (es->format != EXPLAIN_FORMAT_TEXT) { ExplainPropertyLong("Hash Buckets", hashtable->nbuckets, es); ExplainPropertyLong("Hash Batches", hashtable->nbatch, es); ExplainPropertyLong("Original Hash Batches", hashtable->nbatch_original, es); ExplainPropertyLong("Peak Memory Usage", spacePeakKb, es); } else if (hashtable->nbatch_original != hashtable->nbatch) { appendStringInfoSpaces(es->str, es->indent * 2); appendStringInfo(es->str, "Buckets: %d Batches: %d (originally %d) Memory Usage: %ldkB\n", hashtable->nbuckets, hashtable->nbatch, hashtable->nbatch_original, spacePeakKb); } else { appendStringInfoSpaces(es->str, es->indent * 2); appendStringInfo(es->str, "Buckets: %d Batches: %d Memory Usage: %ldkB\n", hashtable->nbuckets, hashtable->nbatch, spacePeakKb); } } }
static void show_instrumentation_count | ( | const char * | qlabel, | |
int | which, | |||
PlanState * | planstate, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 1818 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().
{ double nfiltered; double nloops; if (!es->analyze || !planstate->instrument) return; if (which == 2) nfiltered = planstate->instrument->nfiltered2; else nfiltered = planstate->instrument->nfiltered1; nloops = planstate->instrument->nloops; /* In text mode, suppress zero counts; they're not interesting enough */ if (nfiltered > 0 || es->format != EXPLAIN_FORMAT_TEXT) { if (nloops > 0) ExplainPropertyFloat(qlabel, nfiltered / nloops, 0, es); else ExplainPropertyFloat(qlabel, 0.0, 0, es); } }
static void show_merge_append_keys | ( | MergeAppendState * | mstate, | |
List * | ancestors, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 1689 of file explain.c.
References MergeAppend::numCols, PlanState::plan, MergeAppendState::ps, show_sort_keys_common(), and MergeAppend::sortColIdx.
Referenced by ExplainNode().
{ MergeAppend *plan = (MergeAppend *) mstate->ps.plan; show_sort_keys_common((PlanState *) mstate, plan->numCols, plan->sortColIdx, ancestors, es); }
static void show_modifytable_info | ( | ModifyTableState * | mtstate, | |
ExplainState * | es | |||
) | [static] |
Definition at line 2053 of file explain.c.
References FdwRoutine::ExplainForeignModify, ModifyTable::fdwPrivLists, linitial, NULL, PlanState::plan, ModifyTableState::ps, ModifyTableState::resultRelInfo, and ResultRelInfo::ri_FdwRoutine.
Referenced by ExplainNode().
{ FdwRoutine *fdwroutine = mtstate->resultRelInfo->ri_FdwRoutine; /* * If the first target relation is a foreign table, call its FDW to * display whatever additional fields it wants to. For now, we ignore the * possibility of other targets being foreign tables, although the API for * ExplainForeignModify is designed to allow them to be processed. */ if (fdwroutine != NULL && fdwroutine->ExplainForeignModify != NULL) { ModifyTable *node = (ModifyTable *) mtstate->ps.plan; List *fdw_private = (List *) linitial(node->fdwPrivLists); fdwroutine->ExplainForeignModify(mtstate, mtstate->resultRelInfo, fdw_private, 0, es); } }
static void show_plan_tlist | ( | PlanState * | planstate, | |
List * | ancestors, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 1558 of file explain.c.
References deparse_context_for_planstate(), deparse_expression(), ExplainPropertyList(), TargetEntry::expr, IsA, lappend(), lfirst, list_length(), NIL, PlanState::plan, ExplainState::rtable, ExplainState::rtable_names, and Plan::targetlist.
Referenced by ExplainNode().
{ Plan *plan = planstate->plan; List *context; List *result = NIL; bool useprefix; ListCell *lc; /* No work if empty tlist (this occurs eg in bitmap indexscans) */ if (plan->targetlist == NIL) return; /* The tlist of an Append isn't real helpful, so suppress it */ if (IsA(plan, Append)) return; /* Likewise for MergeAppend and RecursiveUnion */ if (IsA(plan, MergeAppend)) return; if (IsA(plan, RecursiveUnion)) return; /* Set up deparsing context */ context = deparse_context_for_planstate((Node *) planstate, ancestors, es->rtable, es->rtable_names); useprefix = list_length(es->rtable) > 1; /* Deparse each result column (we now include resjunk ones) */ foreach(lc, plan->targetlist) { TargetEntry *tle = (TargetEntry *) lfirst(lc); result = lappend(result, deparse_expression((Node *) tle->expr, context, useprefix, false)); } /* Print results */ ExplainPropertyList("Output", result, es); }
static void show_qual | ( | List * | qual, | |
const char * | qlabel, | |||
PlanState * | planstate, | |||
List * | ancestors, | |||
bool | useprefix, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 1627 of file explain.c.
References make_ands_explicit(), NIL, and show_expression().
Referenced by show_scan_qual(), and show_upper_qual().
{ Node *node; /* No work if empty qual */ if (qual == NIL) return; /* Convert AND list to explicit AND */ node = (Node *) make_ands_explicit(qual); /* And show it */ show_expression(node, qlabel, planstate, ancestors, useprefix, es); }
static void show_scan_qual | ( | List * | qual, | |
const char * | qlabel, | |||
PlanState * | planstate, | |||
List * | ancestors, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 1648 of file explain.c.
References IsA, PlanState::plan, show_qual(), and ExplainState::verbose.
Referenced by ExplainNode().
{ bool useprefix; useprefix = (IsA(planstate->plan, SubqueryScan) ||es->verbose); show_qual(qual, qlabel, planstate, ancestors, useprefix, es); }
static void show_sort_info | ( | SortState * | sortstate, | |
ExplainState * | es | |||
) | [static] |
Definition at line 1742 of file explain.c.
References ExplainState::analyze, appendStringInfo(), appendStringInfoSpaces(), Assert, EXPLAIN_FORMAT_TEXT, ExplainPropertyLong(), ExplainPropertyText(), ExplainState::format, ExplainState::indent, IsA, NULL, SortState::sort_Done, ExplainState::str, tuplesort_get_stats(), and SortState::tuplesortstate.
Referenced by ExplainNode().
{ Assert(IsA(sortstate, SortState)); if (es->analyze && sortstate->sort_Done && sortstate->tuplesortstate != NULL) { Tuplesortstate *state = (Tuplesortstate *) sortstate->tuplesortstate; const char *sortMethod; const char *spaceType; long spaceUsed; tuplesort_get_stats(state, &sortMethod, &spaceType, &spaceUsed); if (es->format == EXPLAIN_FORMAT_TEXT) { appendStringInfoSpaces(es->str, es->indent * 2); appendStringInfo(es->str, "Sort Method: %s %s: %ldkB\n", sortMethod, spaceType, spaceUsed); } else { ExplainPropertyText("Sort Method", sortMethod, es); ExplainPropertyLong("Sort Space Used", spaceUsed, es); ExplainPropertyText("Sort Space Type", spaceType, es); } } }
static void show_sort_keys | ( | SortState * | sortstate, | |
List * | ancestors, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 1676 of file explain.c.
References Sort::numCols, PlanState::plan, ScanState::ps, show_sort_keys_common(), Sort::sortColIdx, and SortState::ss.
Referenced by ExplainNode().
{ Sort *plan = (Sort *) sortstate->ss.ps.plan; show_sort_keys_common((PlanState *) sortstate, plan->numCols, plan->sortColIdx, ancestors, es); }
static void show_sort_keys_common | ( | PlanState * | planstate, | |
int | nkeys, | |||
AttrNumber * | keycols, | |||
List * | ancestors, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 1700 of file explain.c.
References deparse_context_for_planstate(), deparse_expression(), elog, ERROR, ExplainPropertyList(), TargetEntry::expr, get_tle_by_resno(), lappend(), list_length(), PlanState::plan, ExplainState::rtable, ExplainState::rtable_names, Plan::targetlist, and ExplainState::verbose.
Referenced by show_merge_append_keys(), and show_sort_keys().
{ Plan *plan = planstate->plan; List *context; List *result = NIL; bool useprefix; int keyno; char *exprstr; if (nkeys <= 0) return; /* Set up deparsing context */ context = deparse_context_for_planstate((Node *) planstate, ancestors, es->rtable, es->rtable_names); useprefix = (list_length(es->rtable) > 1 || es->verbose); for (keyno = 0; keyno < nkeys; keyno++) { /* find key expression in tlist */ AttrNumber keyresno = keycols[keyno]; TargetEntry *target = get_tle_by_resno(plan->targetlist, keyresno); if (!target) elog(ERROR, "no tlist entry for key %d", keyresno); /* Deparse the expression, showing any top-level cast */ exprstr = deparse_expression((Node *) target->expr, context, useprefix, true); result = lappend(result, exprstr); } ExplainPropertyList("Sort Key", result, es); }
static void show_upper_qual | ( | List * | qual, | |
const char * | qlabel, | |||
PlanState * | planstate, | |||
List * | ancestors, | |||
ExplainState * | es | |||
) | [static] |
Definition at line 1662 of file explain.c.
References list_length(), ExplainState::rtable, show_qual(), and ExplainState::verbose.
Referenced by ExplainNode().
{ bool useprefix; useprefix = (list_length(es->rtable) > 1 || es->verbose); show_qual(qual, qlabel, planstate, ancestors, useprefix, es); }
Definition at line 40 of file explain.c.
Referenced by explain_get_index_name().
Definition at line 37 of file explain.c.
Referenced by ExplainOneQuery().