54 #define X_CLOSE_IMMEDIATE 2 55 #define X_NOWHITESPACE 4 68 const char *relationship,
const char *plan_name,
96 List *context,
bool useprefix,
101 int nkeys,
int nPresortedKeys,
AttrNumber *keycols,
102 Oid *sortOperators,
Oid *collations,
bool *nullsFirst,
105 Oid sortOperator,
Oid collation,
bool nullsFirst);
173 bool timing_set =
false;
174 bool summary_set =
false;
181 if (strcmp(opt->
defname,
"analyze") == 0)
183 else if (strcmp(opt->
defname,
"verbose") == 0)
185 else if (strcmp(opt->
defname,
"costs") == 0)
187 else if (strcmp(opt->
defname,
"buffers") == 0)
189 else if (strcmp(opt->
defname,
"wal") == 0)
191 else if (strcmp(opt->
defname,
"settings") == 0)
193 else if (strcmp(opt->
defname,
"timing") == 0)
198 else if (strcmp(opt->
defname,
"summary") == 0)
203 else if (strcmp(opt->
defname,
"format") == 0)
207 if (strcmp(p,
"text") == 0)
209 else if (strcmp(p,
"xml") == 0)
211 else if (strcmp(p,
"json") == 0)
213 else if (strcmp(p,
"yaml") == 0)
217 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
218 errmsg(
"unrecognized value for EXPLAIN option \"%s\": \"%s\"",
224 (
errcode(ERRCODE_SYNTAX_ERROR),
225 errmsg(
"unrecognized EXPLAIN option \"%s\"",
232 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
233 errmsg(
"EXPLAIN option WAL requires ANALYZE")));
241 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
242 errmsg(
"EXPLAIN option TIMING requires ANALYZE")));
252 (*post_parse_analyze_hook) (pstate, query, jstate);
271 if (rewritten ==
NIL)
285 foreach(l, rewritten)
289 pstate->p_sourcetext, params, pstate->p_queryEnv);
292 if (
lnext(rewritten, l) != NULL)
338 Oid result_type = TEXTOID;
345 if (strcmp(opt->
defname,
"format") == 0)
349 if (strcmp(p,
"xml") == 0)
350 result_type = XMLOID;
351 else if (strcmp(p,
"json") == 0)
352 result_type = JSONOID;
354 result_type = TEXTOID;
388 (*ExplainOneQuery_hook) (query, cursorOptions, into, es,
389 queryString, params, queryEnv);
403 plan =
pg_plan_query(query, queryString, cursorOptions, params);
417 &planduration, (es->buffers ? &bufusage : NULL));
437 if (utilityStmt == NULL)
461 elog(
ERROR,
"unexpected object type: %d",
470 queryString, params, queryEnv);
489 queryString, params, queryEnv);
493 queryString, params, queryEnv);
505 "Utility statements have no plan structure\n");
532 double totaltime = 0;
534 int instrument_option = 0;
574 dest, params, queryEnv, instrument_option);
629 if (es->
summary && planduration)
701 for (
int i = 0;
i < num;
i++)
723 for (
int i = 0;
i < num;
i++)
820 routerels !=
NIL || targrels !=
NIL);
821 foreach(l, resultrels)
827 foreach(l, routerels)
901 "Inlining", jit_flags &
PGJIT_INLINE ?
"true" :
"false",
902 "Optimization", jit_flags &
PGJIT_OPT3 ?
"true" :
"false",
903 "Expressions", jit_flags &
PGJIT_EXPR ?
"true" :
"false",
904 "Deforming", jit_flags &
PGJIT_DEFORM ?
"true" :
"false");
910 "Timing: %s %.3f ms, %s %.3f ms, %s %.3f ms, %s %.3f ms, %s %.3f ms\n",
989 char *conname = NULL;
1014 if (es->
verbose || conname == NULL)
1089 ((
Scan *) plan)->scanrelid);
1108 ((
Append *) plan)->apprelids);
1144 const char *relationship,
const char *plan_name,
1150 const char *strategy = NULL;
1151 const char *partialmode = NULL;
1152 const char *operation = NULL;
1153 const char *custom_name = NULL;
1155 int save_indent = es->
indent;
1171 pname = sname =
"Result";
1174 pname = sname =
"ProjectSet";
1177 sname =
"ModifyTable";
1181 pname = operation =
"Insert";
1184 pname = operation =
"Update";
1187 pname = operation =
"Delete";
1195 pname = sname =
"Append";
1198 pname = sname =
"Merge Append";
1201 pname = sname =
"Recursive Union";
1204 pname = sname =
"BitmapAnd";
1207 pname = sname =
"BitmapOr";
1210 pname = sname =
"Nested Loop";
1214 sname =
"Merge Join";
1218 sname =
"Hash Join";
1221 pname = sname =
"Seq Scan";
1224 pname = sname =
"Sample Scan";
1227 pname = sname =
"Gather";
1230 pname = sname =
"Gather Merge";
1233 pname = sname =
"Index Scan";
1236 pname = sname =
"Index Only Scan";
1239 pname = sname =
"Bitmap Index Scan";
1242 pname = sname =
"Bitmap Heap Scan";
1245 pname = sname =
"Tid Scan";
1248 pname = sname =
"Tid Range Scan";
1251 pname = sname =
"Subquery Scan";
1254 pname = sname =
"Function Scan";
1257 pname = sname =
"Table Function Scan";
1260 pname = sname =
"Values Scan";
1263 pname = sname =
"CTE Scan";
1266 pname = sname =
"Named Tuplestore Scan";
1269 pname = sname =
"WorkTable Scan";
1272 sname =
"Foreign Scan";
1276 pname =
"Foreign Scan";
1277 operation =
"Select";
1280 pname =
"Foreign Insert";
1281 operation =
"Insert";
1284 pname =
"Foreign Update";
1285 operation =
"Update";
1288 pname =
"Foreign Delete";
1289 operation =
"Delete";
1297 sname =
"Custom Scan";
1298 custom_name = ((
CustomScan *) plan)->methods->CustomName;
1300 pname =
psprintf(
"Custom Scan (%s)", custom_name);
1305 pname = sname =
"Materialize";
1308 pname = sname =
"Result Cache";
1311 pname = sname =
"Sort";
1314 pname = sname =
"Incremental Sort";
1317 pname = sname =
"Group";
1323 sname =
"Aggregate";
1327 pname =
"Aggregate";
1331 pname =
"GroupAggregate";
1332 strategy =
"Sorted";
1335 pname =
"HashAggregate";
1336 strategy =
"Hashed";
1339 pname =
"MixedAggregate";
1343 pname =
"Aggregate ???";
1350 partialmode =
"Partial";
1351 pname =
psprintf(
"%s %s", partialmode, pname);
1355 partialmode =
"Finalize";
1356 pname =
psprintf(
"%s %s", partialmode, pname);
1359 partialmode =
"Simple";
1363 pname = sname =
"WindowAgg";
1366 pname = sname =
"Unique";
1370 switch (((
SetOp *) plan)->strategy)
1374 strategy =
"Sorted";
1377 pname =
"HashSetOp";
1378 strategy =
"Hashed";
1381 pname =
"SetOp ???";
1387 pname = sname =
"LockRows";
1390 pname = sname =
"Limit";
1393 pname = sname =
"Hash";
1396 pname = sname =
"???";
1401 relationship ? NULL :
"Plan",
1461 if (((
Scan *) plan)->scanrelid > 0)
1487 const char *indexname =
1504 const char *jointype;
1506 switch (((
Join *) plan)->jointype)
1547 const char *setopcmd;
1549 switch (((
SetOp *) plan)->cmd)
1552 setopcmd =
"Intersect";
1555 setopcmd =
"Intersect All";
1558 setopcmd =
"Except";
1561 setopcmd =
"Except All";
1623 " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",
1624 startup_ms, total_ms, rows, nloops);
1627 " (actual rows=%.0f loops=%.0f)",
1671 double nloops = instrument->
nloops;
1678 startup_ms = 1000.0 * instrument->
startup / nloops;
1679 total_ms = 1000.0 * instrument->
total / nloops;
1680 rows = instrument->
ntuples / nloops;
1689 "actual time=%.3f..%.3f rows=%.0f loops=%.0f\n",
1690 startup_ms, total_ms, rows, nloops);
1693 "actual rows=%.0f loops=%.0f\n",
1727 ((
Join *) plan)->inner_unique,
1739 "Index Cond", planstate, ancestors, es);
1740 if (((
IndexScan *) plan)->indexqualorig)
1744 "Order By", planstate, ancestors, es);
1752 "Index Cond", planstate, ancestors, es);
1757 "Order By", planstate, ancestors, es);
1768 "Index Cond", planstate, ancestors, es);
1772 "Recheck Cond", planstate, ancestors, es);
1785 planstate, ancestors, es);
1818 nworkers = ((
GatherState *) planstate)->nworkers_launched;
1866 "Function Call", planstate, ancestors,
1880 "Table Function Call", planstate, ancestors,
1943 "Join Filter", planstate, ancestors, es);
1944 if (((
NestLoop *) plan)->join.joinqual)
1954 "Merge Cond", planstate, ancestors, es);
1956 "Join Filter", planstate, ancestors, es);
1957 if (((
MergeJoin *) plan)->join.joinqual)
1967 "Hash Cond", planstate, ancestors, es);
1969 "Join Filter", planstate, ancestors, es);
1970 if (((
HashJoin *) plan)->join.joinqual)
2009 "One-Time Filter", planstate, ancestors, es);
2064 double nloops = instrument->
nloops;
2108 haschildren = planstate->
initPlan ||
2123 ancestors =
lcons(plan, ancestors);
2165 "Subquery", NULL, es);
2188 es->
indent = save_indent;
2191 relationship ? NULL :
"Plan",
2240 foreach(lc, plan->targetlist)
2308 show_qual(qual, qlabel, planstate, ancestors, useprefix, es);
2322 show_qual(qual, qlabel, planstate, ancestors, useprefix, es);
2385 ancestors =
lcons(plan, ancestors);
2416 context, useprefix, ancestors, es);
2418 foreach(lc, agg->
chain)
2424 context, useprefix, ancestors, es);
2441 const char *keyname;
2442 const char *keysetname;
2446 keyname =
"Hash Key";
2447 keysetname =
"Hash Keys";
2451 keyname =
"Group Key";
2452 keysetname =
"Group Keys";
2483 elog(
ERROR,
"no tlist entry for key %d", keyresno);
2488 result =
lappend(result, exprstr);
2515 ancestors =
lcons(plan, ancestors);
2530 int nkeys,
int nPresortedKeys,
AttrNumber *keycols,
2531 Oid *sortOperators,
Oid *collations,
bool *nullsFirst,
2553 for (keyno = 0; keyno < nkeys; keyno++)
2562 elog(
ERROR,
"no tlist entry for key %d", keyresno);
2569 if (sortOperators != NULL)
2572 sortOperators[keyno],
2577 if (keyno < nPresortedKeys)
2578 resultPresorted =
lappend(resultPresorted, exprstr);
2582 if (nPresortedKeys > 0)
2592 Oid sortOperator,
Oid collation,
bool nullsFirst)
2595 bool reverse =
false;
2612 if (collname == NULL)
2613 elog(
ERROR,
"cache lookup failed for collation %u", collation);
2618 if (sortOperator == typentry->
gt_opr)
2623 else if (sortOperator != typentry->
lt_opr)
2628 elog(
ERROR,
"cache lookup failed for operator %u", sortOperator);
2635 if (nullsFirst && !reverse)
2639 else if (!nullsFirst && reverse)
2669 foreach(lc, tsc->
args)
2724 const char *sortMethod;
2725 const char *spaceType;
2731 spaceUsed = stats.spaceUsed;
2737 sortMethod, spaceType, spaceUsed);
2763 const char *sortMethod;
2764 const char *spaceType;
2782 sortMethod, spaceType, spaceUsed);
2836 foreach(methodCell, methodNames)
2846 const char *spaceTypeName;
2850 spaceTypeName, avgSpace,
2858 const char *spaceTypeName;
2862 spaceTypeName, avgSpace,
2880 const char *spaceTypeName;
2897 const char *spaceTypeName;
2957 bool indent_first_line;
2985 indent_first_line, es);
3053 if (hinstrument.
nbatch > 0)
3055 long spacePeakKb = (hinstrument.
space_peak + 1023) / 1024;
3075 "Buckets: %d (originally %d) Batches: %d (originally %d) Memory Usage: %ldkB\n",
3086 "Buckets: %d Batches: %d Memory Usage: %ldkB\n",
3104 char *seperator =
"";
3154 memPeakKb = (rcstate->
mem_used + 1023) / 1024;
3198 memPeakKb = (si->
mem_peak + 1023) / 1024;
3264 bool gotone =
false;
3308 uint64 hash_disk_used;
3309 int hash_batches_used;
3327 hash_batches_used, memPeakKb);
3330 if (hash_batches_used > 1)
3338 hash_batches_used, es);
3445 snprintf(param,
sizeof(param),
"$%d", paramid);
3469 result = (*explain_get_index_name_hook) (indexId);
3477 elog(
ERROR,
"cache lookup failed for index %u", indexId);
3502 bool show_planning = (planning && (has_shared ||
3503 has_local || has_temp || has_timing));
3513 if (has_shared || has_local || has_temp)
3533 if (has_local || has_temp)
3673 const char *scandir;
3675 switch (indexorderdir)
3678 scandir =
"Backward";
3681 scandir =
"NoMovement";
3684 scandir =
"Forward";
3723 char *objectname = NULL;
3724 char *
namespace = NULL;
3725 const char *objecttag = NULL;
3731 if (refname == NULL)
3751 objecttag =
"Relation Name";
3781 objecttag =
"Function Name";
3786 objectname =
"xmltable";
3787 objecttag =
"Table Function Name";
3795 Assert(!rte->self_reference);
3796 objectname = rte->ctename;
3797 objecttag =
"CTE Name";
3801 objectname = rte->enrname;
3802 objecttag =
"Tuplestore Name";
3807 Assert(rte->self_reference);
3808 objectname = rte->ctename;
3809 objecttag =
"CTE Name";
3818 if (
namespace != NULL)
3821 else if (objectname != NULL)
3823 if (objectname == NULL || strcmp(refname, objectname) != 0)
3828 if (objecttag != NULL && objectname != NULL)
3830 if (
namespace != NULL)
3849 const char *operation;
3850 const char *foperation;
3859 operation =
"Insert";
3860 foperation =
"Foreign Insert";
3863 operation =
"Update";
3864 foperation =
"Foreign Update";
3867 operation =
"Delete";
3868 foperation =
"Foreign Delete";
3872 foperation =
"Foreign ???";
3877 labeltargets = (mtstate->
mt_nrels > 1 ||
3884 for (j = 0; j < mtstate->
mt_nrels; j++)
3902 fdwroutine ? foperation : operation);
3919 fdwroutine != NULL &&
3947 idxNames =
lappend(idxNames, indexname);
3954 "NOTHING" :
"UPDATE",
3968 &mtstate->
ps, ancestors, es);
3984 insert_path = total - other_path;
3987 insert_path, 0, es);
4010 for (j = 0; j < nplans; j++)
4012 "Member", NULL, es);
4027 nchildren - nplans, es);
4067 ancestors =
lcons(sp, ancestors);
4124 Assert(n >= 0 && n < wstate->num_workers);
4186 Assert(n >= 0 && n < wstate->num_workers);
4464 buf =
psprintf(
"%.*f", ndigits, value);
4754 "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
4836 const char *valid =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
4843 for (s = tagname; *s; s++)
4848 if ((flags & X_NOWHITESPACE) == 0)
void ExplainPropertyUInteger(const char *qlabel, const char *unit, uint64 value, ExplainState *es)
void ExplainQuery(ParseState *pstate, ExplainStmt *stmt, ParamListInfo params, DestReceiver *dest)
static ExplainWorkersState * ExplainCreateWorkersState(int num_workers)
static void ExplainPrintSettings(ExplainState *es)
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
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
IncrementalSortInfo sinfo[FLEXIBLE_ARRAY_MEMBER]
const char * tuplesort_space_type_name(TuplesortSpaceType t)
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)
struct JitContext * es_jit
static ListCell * lnext(const List *l, const ListCell *c)
TupleDesc CreateTemplateTupleDesc(int natts)
List * lcons_int(int datum, List *list)
static void show_sort_group_keys(PlanState *planstate, const char *qlabel, int nkeys, int nPresortedKeys, AttrNumber *keycols, Oid *sortOperators, Oid *collations, bool *nullsFirst, List *ancestors, ExplainState *es)
char * get_constraint_name(Oid conoid)
#define castNode(_type_, nodeptr)
void FreeQueryDesc(QueryDesc *qdesc)
ResultRelInfo * resultRelInfo
instr_time generation_counter
struct config_generic ** get_explain_guc_options(int *num)
void ExplainPropertyFloat(const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
char * get_collation_name(Oid colloid)
char * pstrdup(const char *in)
Bitmapset * printed_subplans
char * psprintf(const char *fmt,...)
struct JitInstrumentation * es_jit_worker_instr
#define INSTR_TIME_GET_MILLISEC(t)
struct timeval instr_time
Oid get_equality_op_for_ordering_op(Oid opno, bool *reverse)
StringInfo makeStringInfo(void)
int bms_next_member(const Bitmapset *a, int prevbit)
const TupleTableSlotOps TTSOpsVirtual
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Snapshot GetActiveSnapshot(void)
Instrumentation * ri_TrigInstrument
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
SharedSortInfo * shared_info
int errcode(int sqlerrcode)
IncrementalSortGroupInfo prefixsortGroupInfo
static void show_incremental_sort_info(IncrementalSortState *incrsortstate, ExplainState *es)
#define INSTR_TIME_SET_ZERO(t)
static void ExplainOpenWorker(int n, ExplainState *es)
static void ExplainCloseWorker(int n, ExplainState *es)
SharedResultCacheInfo * shared_info
void PopActiveSnapshot(void)
static void ExplainPrintJIT(ExplainState *es, int jit_flags, JitInstrumentation *ji)
#define INSTR_TIME_GET_DOUBLE(t)
AggregateInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
ResultCacheInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Expr * make_orclause(List *orclauses)
#define linitial_node(type, l)
List * set_deparse_context_plan(List *dpcontext, Plan *plan, List *ancestors)
DestReceiver * None_Receiver
void tuplesort_get_stats(Tuplesortstate *state, TuplesortInstrumentation *stats)
#define OidIsValid(objectId)
JitInstrumentation jit_instr[FLEXIBLE_ARRAY_MEMBER]
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)
const char * tuplesort_method_name(TuplesortMethod m)
static void ExplainRestoreGroup(ExplainState *es, int depth, int *state_save)
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)
void BufferUsageAccumDiff(BufferUsage *dst, const BufferUsage *add, const BufferUsage *sub)
static void show_instrumentation_count(const char *qlabel, int which, PlanState *planstate, ExplainState *es)
void InstrEndLoop(Instrumentation *instr)
SharedHashInfo * shared_info
const struct CustomExecMethods * methods
ResultCacheInstrumentation stats
void ExplainPropertyListNested(const char *qlabel, List *data, ExplainState *es)
int64 totalMemorySpaceUsed
#define NUM_TUPLESORTMETHODS
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)
IncrementalSortInfo incsort_info
void appendStringInfo(StringInfo str, const char *fmt,...)
void ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
char * GetConfigOptionByName(const char *name, const char **varname, bool missing_ok)
void end_tup_output(TupOutputState *tstate)
void ExplainBeginOutput(ExplainState *es)
void ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
struct PlanState * planstate
static void show_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, bool useprefix, ExplainState *es)
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
static void * list_nth(const List *list, int n)
char * get_func_name(Oid funcid)
TupleDesc ExplainResultDesc(ExplainStmt *stmt)