52 #define X_CLOSE_IMMEDIATE 2
53 #define X_NOWHITESPACE 4
62 const char *relationship,
const char *plan_name,
88 List *context,
bool useprefix,
94 Oid *sortOperators,
Oid *collations,
bool *nullsFirst,
97 Oid sortOperator,
Oid collation,
bool nullsFirst);
149 bool timing_set =
false;
156 if (strcmp(opt->
defname,
"analyze") == 0)
158 else if (strcmp(opt->
defname,
"verbose") == 0)
160 else if (strcmp(opt->
defname,
"costs") == 0)
162 else if (strcmp(opt->
defname,
"buffers") == 0)
164 else if (strcmp(opt->
defname,
"timing") == 0)
169 else if (strcmp(opt->
defname,
"format") == 0)
173 if (strcmp(p,
"text") == 0)
175 else if (strcmp(p,
"xml") == 0)
177 else if (strcmp(p,
"json") == 0)
179 else if (strcmp(p,
"yaml") == 0)
183 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
184 errmsg(
"unrecognized value for EXPLAIN option \"%s\": \"%s\"",
189 (
errcode(ERRCODE_SYNTAX_ERROR),
190 errmsg(
"unrecognized EXPLAIN option \"%s\"",
196 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
197 errmsg(
"EXPLAIN option BUFFERS requires ANALYZE")));
205 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
206 errmsg(
"EXPLAIN option TIMING requires ANALYZE")));
229 if (rewritten ==
NIL)
243 foreach(l, rewritten)
246 queryString, params);
301 if (strcmp(opt->
defname,
"format") == 0)
305 if (strcmp(p,
"xml") == 0)
307 else if (strcmp(p,
"json") == 0)
341 (*ExplainOneQuery_hook) (query, into, es, queryString, params);
357 ExplainOnePlan(plan, into, es, queryString, params, &planduration);
376 if (utilityStmt ==
NULL)
393 queryString, params);
397 queryString, params);
409 "Utility statements have no plan structure\n");
440 double totaltime = 0;
442 int instrument_option = 0;
478 dest, params, instrument_option);
517 if (es->
summary && planduration)
620 show_relname = (numrels > 1 || targrels !=
NIL);
622 for (nr = 0; nr < numrels; rInfo++, nr++)
665 char *conname =
NULL;
757 ((
Scan *) plan)->scanrelid);
803 const char *relationship,
const char *plan_name,
809 const char *strategy =
NULL;
810 const char *partialmode =
NULL;
811 const char *operation =
NULL;
812 const char *custom_name =
NULL;
813 int save_indent = es->
indent;
819 pname = sname =
"Result";
822 sname =
"ModifyTable";
826 pname = operation =
"Insert";
829 pname = operation =
"Update";
832 pname = operation =
"Delete";
840 pname = sname =
"Append";
843 pname = sname =
"Merge Append";
846 pname = sname =
"Recursive Union";
849 pname = sname =
"BitmapAnd";
852 pname = sname =
"BitmapOr";
855 pname = sname =
"Nested Loop";
859 sname =
"Merge Join";
866 pname = sname =
"Seq Scan";
869 pname = sname =
"Sample Scan";
872 pname = sname =
"Gather";
875 pname = sname =
"Index Scan";
878 pname = sname =
"Index Only Scan";
881 pname = sname =
"Bitmap Index Scan";
884 pname = sname =
"Bitmap Heap Scan";
887 pname = sname =
"Tid Scan";
890 pname = sname =
"Subquery Scan";
893 pname = sname =
"Function Scan";
896 pname = sname =
"Values Scan";
899 pname = sname =
"CTE Scan";
902 pname = sname =
"WorkTable Scan";
905 sname =
"Foreign Scan";
909 pname =
"Foreign Scan";
910 operation =
"Select";
913 pname =
"Foreign Insert";
914 operation =
"Insert";
917 pname =
"Foreign Update";
918 operation =
"Update";
921 pname =
"Foreign Delete";
922 operation =
"Delete";
930 sname =
"Custom Scan";
931 custom_name = ((
CustomScan *) plan)->methods->CustomName;
933 pname =
psprintf(
"Custom Scan (%s)", custom_name);
938 pname = sname =
"Materialize";
941 pname = sname =
"Sort";
944 pname = sname =
"Group";
958 pname =
"GroupAggregate";
962 pname =
"HashAggregate";
966 pname =
"Aggregate ???";
973 partialmode =
"Partial";
974 pname =
psprintf(
"%s %s", partialmode, pname);
978 partialmode =
"Finalize";
979 pname =
psprintf(
"%s %s", partialmode, pname);
982 partialmode =
"Simple";
986 pname = sname =
"WindowAgg";
989 pname = sname =
"Unique";
993 switch (((
SetOp *) plan)->strategy)
1000 pname =
"HashSetOp";
1001 strategy =
"Hashed";
1004 pname =
"SetOp ???";
1010 pname = sname =
"LockRows";
1013 pname = sname =
"Limit";
1016 pname = sname =
"Hash";
1019 pname = sname =
"???";
1024 relationship ?
NULL :
"Plan",
1079 if (((
Scan *) plan)->scanrelid > 0)
1105 const char *indexname =
1121 const char *jointype;
1123 switch (((
Join *) plan)->jointype)
1164 const char *setopcmd;
1166 switch (((
SetOp *) plan)->cmd)
1169 setopcmd =
"Intersect";
1172 setopcmd =
"Intersect All";
1175 setopcmd =
"Except";
1178 setopcmd =
"Except All";
1236 " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",
1237 startup_sec, total_sec, rows, nloops);
1240 " (actual rows=%.0f loops=%.0f)",
1283 "Index Cond", planstate, ancestors, es);
1284 if (((
IndexScan *) plan)->indexqualorig)
1288 "Order By", planstate, ancestors, es);
1296 "Index Cond", planstate, ancestors, es);
1301 "Order By", planstate, ancestors, es);
1312 "Index Cond", planstate, ancestors, es);
1316 "Recheck Cond", planstate, ancestors, es);
1329 planstate, ancestors, es);
1355 nworkers = ((
GatherState *) planstate)->nworkers_launched;
1377 "Function Call", planstate, ancestors,
1423 "Join Filter", planstate, ancestors, es);
1424 if (((
NestLoop *) plan)->join.joinqual)
1434 "Merge Cond", planstate, ancestors, es);
1436 "Join Filter", planstate, ancestors, es);
1437 if (((
MergeJoin *) plan)->join.joinqual)
1447 "Hash Cond", planstate, ancestors, es);
1449 "Join Filter", planstate, ancestors, es);
1450 if (((
HashJoin *) plan)->join.joinqual)
1482 "One-Time Filter", planstate, ancestors, es);
1507 bool opened_group =
false;
1513 double nloops = instrument->
nloops;
1520 startup_sec = 1000.0 * instrument->
startup / nloops;
1521 total_sec = 1000.0 * instrument->
total / nloops;
1522 rows = instrument->
ntuples / nloops;
1530 "actual time=%.3f..%.3f rows=%.0f loops=%.0f\n",
1531 startup_sec, total_sec, rows, nloops);
1534 "actual rows=%.0f loops=%.0f\n",
1546 opened_group =
true;
1571 haschildren = planstate->
initPlan ||
1587 ancestors =
lcons(planstate, ancestors);
1634 "Subquery", NULL, es);
1657 es->
indent = save_indent;
1660 relationship ? NULL :
"Plan",
1777 show_qual(qual, qlabel, planstate, ancestors, useprefix, es);
1791 show_qual(qual, qlabel, planstate, ancestors, useprefix, es);
1837 ancestors =
lcons(astate, ancestors);
1868 context, useprefix, ancestors, es);
1870 foreach(lc, agg->
chain)
1876 context, useprefix, ancestors, es);
1885 List *context,
bool useprefix,
1922 elog(
ERROR,
"no tlist entry for key %d", keyresno);
1927 result =
lappend(result, exprstr);
1954 ancestors =
lcons(gstate, ancestors);
1970 Oid *sortOperators,
Oid *collations,
bool *nullsFirst,
1991 for (keyno = 0; keyno < nkeys; keyno++)
2000 elog(
ERROR,
"no tlist entry for key %d", keyresno);
2007 if (sortOperators !=
NULL)
2010 sortOperators[keyno],
2026 Oid sortOperator,
Oid collation,
bool nullsFirst)
2029 bool reverse =
false;
2044 if (collname ==
NULL)
2045 elog(
ERROR,
"cache lookup failed for collation %u", collation);
2050 if (sortOperator == typentry->
gt_opr)
2055 else if (sortOperator != typentry->
lt_opr)
2060 elog(
ERROR,
"cache lookup failed for operator %u", sortOperator);
2067 if (nullsFirst && !reverse)
2071 else if (!nullsFirst && reverse)
2101 foreach(lc, tsc->
args)
2154 const char *sortMethod;
2155 const char *spaceType;
2164 sortMethod, spaceType, spaceUsed);
2188 long spacePeakKb = (hashtable->
spacePeak + 1023) / 1024;
2205 "Buckets: %d (originally %d) Batches: %d (originally %d) Memory Usage: %ldkB\n",
2216 "Buckets: %d Batches: %d Memory Usage: %ldkB\n",
2313 result = (*explain_get_index_name_hook) (indexId);
2321 elog(
ERROR,
"cache lookup failed for index %u", indexId);
2349 if (has_shared || has_local || has_temp)
2369 if (has_local || has_temp)
2451 const char *scandir;
2453 switch (indexorderdir)
2456 scandir =
"Backward";
2459 scandir =
"NoMovement";
2462 scandir =
"Forward";
2501 char *objectname =
NULL;
2502 char *
namespace =
NULL;
2503 const char *objecttag =
NULL;
2509 if (refname ==
NULL)
2528 objecttag =
"Relation Name";
2558 objecttag =
"Function Name";
2567 Assert(!rte->self_reference);
2568 objectname = rte->ctename;
2569 objecttag =
"CTE Name";
2574 Assert(rte->self_reference);
2575 objectname = rte->ctename;
2576 objecttag =
"CTE Name";
2585 if (
namespace !=
NULL)
2588 else if (objectname !=
NULL)
2590 if (objectname ==
NULL || strcmp(refname, objectname) != 0)
2595 if (objecttag !=
NULL && objectname !=
NULL)
2597 if (
namespace !=
NULL)
2616 const char *operation;
2617 const char *foperation;
2626 operation =
"Insert";
2627 foperation =
"Foreign Insert";
2630 operation =
"Update";
2631 foperation =
"Foreign Update";
2634 operation =
"Delete";
2635 foperation =
"Foreign Delete";
2639 foperation =
"Foreign ???";
2644 labeltargets = (mtstate->
mt_nplans > 1 ||
2651 for (j = 0; j < mtstate->
mt_nplans; j++)
2669 fdwroutine ? foperation : operation);
2686 fdwroutine !=
NULL &&
2714 idxNames =
lappend(idxNames, indexname);
2721 "NOTHING" :
"UPDATE",
2735 &mtstate->
ps, ancestors, es);
2751 insert_path = total - other_path;
2779 for (j = 0; j < nplans; j++)
2781 "Member",
NULL, es);
3009 snprintf(buf,
sizeof(buf),
"%d", value);
3021 snprintf(buf,
sizeof(buf),
"%ld", value);
3035 snprintf(buf,
sizeof(buf),
"%.*f", ndigits, value);
3213 "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
3300 for (s = tagname; *s; s++)
3305 if ((flags & X_NOWHITESPACE) == 0)
static void ExplainMemberNodes(List *plans, PlanState **planstates, List *ancestors, ExplainState *es)
void ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params)
void ExplainPropertyBool(const char *qlabel, bool value, ExplainState *es)
ScanDirection indexorderdir
void UpdateActiveSnapshotCommandId(void)
#define IsA(nodeptr, _type_)
ExplainState * NewExplainState(void)
List * QueryRewrite(Query *parsetree)
WorkerInstrumentation * worker_instrument
static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es)
ExplainForeignScan_function ExplainForeignScan
void escape_json(StringInfo buf, const char *str)
Instrumentation * instrument
void ExplainSeparatePlans(ExplainState *es)
const char * quote_identifier(const char *ident)
static void show_modifytable_info(ModifyTableState *mtstate, List *ancestors, ExplainState *es)
List * lcons_int(int datum, List *list)
char * get_constraint_name(Oid conoid)
void FreeQueryDesc(QueryDesc *qdesc)
void ExplainPropertyLong(const char *qlabel, long value, ExplainState *es)
ResultRelInfo * resultRelInfo
char * get_collation_name(Oid colloid)
char * pstrdup(const char *in)
char * psprintf(const char *fmt,...)
#define INSTR_TIME_GET_MILLISEC(t)
struct timeval instr_time
Oid get_equality_op_for_ordering_op(Oid opno, bool *reverse)
StringInfo makeStringInfo(void)
void(* ExplainCustomScan)(CustomScanState *node, List *ancestors, ExplainState *es)
void ExplainPropertyFloat(const char *qlabel, double value, int ndigits, ExplainState *es)
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Snapshot GetActiveSnapshot(void)
Instrumentation * ri_TrigInstrument
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
int errcode(int sqlerrcode)
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void PopActiveSnapshot(void)
#define INSTR_TIME_GET_DOUBLE(t)
QueryDesc * CreateQueryDesc(PlannedStmt *plannedstmt, const char *sourceText, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, int instrument_options)
DestReceiver * None_Receiver
#define OidIsValid(objectId)
static void show_scan_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
#define DO_AGGSPLIT_COMBINE(as)
static void ExplainDummyGroup(const char *objtype, const char *labelname, ExplainState *es)
static void ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params)
void ExplainPropertyInteger(const char *qlabel, int value, ExplainState *es)
static void show_sort_info(SortState *sortstate, ExplainState *es)
static void show_upper_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es)
#define INSTR_TIME_IS_ZERO(t)
static void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
static void show_instrumentation_count(const char *qlabel, int which, PlanState *planstate, ExplainState *es)
void * copyObject(const void *from)
void InstrEndLoop(Instrumentation *instr)
const struct CustomExecMethods * methods
static char * relname(char const *dir, char const *base)
Expr * make_ands_explicit(List *andclauses)
void ExplainPropertyListNested(const char *qlabel, List *data, ExplainState *es)
void ExecutorEnd(QueryDesc *queryDesc)
#define ScanDirectionIsBackward(direction)
List * select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
char * get_opname(Oid opno)
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
void ExplainEndOutput(ExplainState *es)
int GetIntoRelEFlags(IntoClause *intoClause)
bool defGetBoolean(DefElem *def)
#define appendStringInfoCharMacro(str, ch)
void ExplainPrintTriggers(ExplainState *es, QueryDesc *queryDesc)
void pfree(void *pointer)
void appendStringInfo(StringInfo str, const char *fmt,...)
void ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
void end_tup_output(TupOutputState *tstate)
void ExplainBeginOutput(ExplainState *es)
struct PlanState * planstate
static void show_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
char * get_func_name(Oid funcid)
TupleDesc ExplainResultDesc(ExplainStmt *stmt)
#define INSTR_TIME_SUBTRACT(x, y)
char * defGetString(DefElem *def)
void PushCopiedSnapshot(Snapshot snapshot)
ExplainOneQuery_hook_type ExplainOneQuery_hook
List * set_deparse_context_planstate(List *dpcontext, Node *planstate, List *ancestors)
bool ri_usesFdwDirectModify
#define outerPlanState(node)
void appendStringInfoString(StringInfo str, const char *s)
char * get_namespace_name(Oid nspid)
void * list_nth(const List *list, int n)
#define DEFAULT_COLLATION_OID
void ExplainQueryText(ExplainState *es, QueryDesc *queryDesc)
ResultRelInfo * es_result_relations
static void ExplainYAMLLineStarting(ExplainState *es)
static void show_grouping_sets(PlanState *planstate, Agg *agg, List *ancestors, ExplainState *es)
static void show_tablesample(TableSampleClause *tsc, PlanState *planstate, List *ancestors, ExplainState *es)
ExplainDirectModify_function ExplainDirectModify
DestReceiver * CreateIntoRelDestReceiver(IntoClause *intoClause)
#define RelationGetRelationName(relation)
void resetStringInfo(StringInfo str)
struct FdwRoutine * ri_FdwRoutine
struct FdwRoutine * fdwroutine
ScanDirection indexorderdir
static void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
static void show_tidbitmap_info(BitmapHeapScanState *planstate, ExplainState *es)
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
static void ExplainModifyTarget(ModifyTable *plan, ExplainState *es)
#define ereport(elevel, rest)
#define rt_fetch(rangetable_index, rangetable)
static void ExplainIndexScanDetails(Oid indexid, ScanDirection indexorderdir, ExplainState *es)
static void show_group_keys(GroupState *gstate, List *ancestors, ExplainState *es)
void tuplesort_get_stats(Tuplesortstate *state, const char **sortMethod, const char **spaceType, long *spaceUsed)
TriggerDesc * ri_TrigDesc
static void show_buffer_usage(ExplainState *es, const BufferUsage *usage)
void ExecutorFinish(QueryDesc *queryDesc)
static void show_plan_tlist(PlanState *planstate, List *ancestors, ExplainState *es)
List * lappend(List *list, void *datum)
static void report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
TupOutputState * begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc)
void appendStringInfoChar(StringInfo str, char ch)
void initStringInfo(StringInfo str)
static void escape_yaml(StringInfo buf, const char *str)
List * es_trig_target_relations
void do_text_output_multiline(TupOutputState *tstate, const char *txt)
Instrumentation instrument[FLEXIBLE_ARRAY_MEMBER]
void * palloc0(Size size)
void CommandCounterIncrement(void)
const char *(* explain_get_index_name_hook_type)(Oid indexId)
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
int es_num_result_relations
void appendStringInfoSpaces(StringInfo str, int count)
static void ExplainCustomChildren(CustomScanState *css, List *ancestors, ExplainState *es)
static void ExplainJSONLineEnding(ExplainState *es)
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
static void show_merge_append_keys(MergeAppendState *mstate, List *ancestors, ExplainState *es)
List * lcons(void *datum, List *list)
void ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, const instr_time *planduration)
void ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
#define Assert(condition)
static void ExplainSubPlans(List *plans, List *ancestors, const char *relationship, ExplainState *es)
static void show_hash_info(HashState *hashstate, ExplainState *es)
OnConflictAction onConflictAction
void(* ExplainOneQuery_hook_type)(Query *query, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params)
instr_time blk_write_time
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Oid exprType(const Node *expr)
static void show_sort_keys(SortState *sortstate, List *ancestors, ExplainState *es)
static int list_length(const List *l)
void ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params)
#define DO_AGGSPLIT_SKIPFINAL(as)
static const struct fns functions
static double elapsed_time(instr_time *starttime)
#define do_text_output_oneline(tstate, str_to_emit)
explain_get_index_name_hook_type explain_get_index_name_hook
static const char * explain_get_index_name(Oid indexId)
Bitmapset * bms_add_member(Bitmapset *a, int x)
TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid)
#define INSTR_TIME_SET_CURRENT(t)
static void show_expression(Node *node, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
#define X_CLOSE_IMMEDIATE
static void show_grouping_set_keys(PlanState *planstate, Agg *aggnode, Sort *sortnode, List *context, bool useprefix, List *ancestors, ExplainState *es)
#define CURSOR_OPT_PARALLEL_OK
int errmsg(const char *fmt,...)
void ExplainQuery(ExplainStmt *stmt, const char *queryString, ParamListInfo params, DestReceiver *dest)
ExplainForeignModify_function ExplainForeignModify
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
static void show_foreignscan_info(ForeignScanState *fsstate, ExplainState *es)
static void ExplainScanTarget(Scan *plan, ExplainState *es)
char * escape_xml(const char *str)
PlannedStmt * plannedstmt
static void show_sortorder_options(StringInfo buf, Node *sortexpr, Oid sortOperator, Oid collation, bool nullsFirst)
#define innerPlanState(node)
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)
char * get_rel_name(Oid relid)
bool planstate_tree_walker(PlanState *planstate, bool(*walker)(), void *context)
#define EXEC_FLAG_EXPLAIN_ONLY
List * deparse_context_for_plan_rtable(List *rtable, List *rtable_names)
Expr * make_orclause(List *orclauses)
static void show_agg_keys(AggState *astate, List *ancestors, ExplainState *es)
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
List * list_delete_first(List *list)
PlannedStmt * pg_plan_query(Query *querytree, int cursorOptions, ParamListInfo boundParams)