PostgreSQL Source Code git master
explain.h File Reference
Include dependency graph for explain.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Typedefs

typedef void(* ExplainOneQuery_hook_type) (Query *query, int cursorOptions, IntoClause *into, struct ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
 
typedef void(* explain_per_plan_hook_type) (PlannedStmt *plannedstmt, IntoClause *into, struct ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
 
typedef void(* explain_per_node_hook_type) (PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, struct ExplainState *es)
 
typedef const char *(* explain_get_index_name_hook_type) (Oid indexId)
 

Functions

void ExplainQuery (ParseState *pstate, ExplainStmt *stmt, ParamListInfo params, DestReceiver *dest)
 
void standard_ExplainOneQuery (Query *query, int cursorOptions, IntoClause *into, struct ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
 
TupleDesc ExplainResultDesc (ExplainStmt *stmt)
 
void ExplainOneUtility (Node *utilityStmt, IntoClause *into, struct ExplainState *es, ParseState *pstate, ParamListInfo params)
 
void ExplainOnePlan (PlannedStmt *plannedstmt, CachedPlan *cplan, CachedPlanSource *plansource, int query_index, IntoClause *into, struct ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv, const instr_time *planduration, const BufferUsage *bufusage, const MemoryContextCounters *mem_counters)
 
void ExplainPrintPlan (struct ExplainState *es, QueryDesc *queryDesc)
 
void ExplainPrintTriggers (struct ExplainState *es, QueryDesc *queryDesc)
 
void ExplainPrintJITSummary (struct ExplainState *es, QueryDesc *queryDesc)
 
void ExplainQueryText (struct ExplainState *es, QueryDesc *queryDesc)
 
void ExplainQueryParameters (struct ExplainState *es, ParamListInfo params, int maxlen)
 

Variables

PGDLLIMPORT ExplainOneQuery_hook_type ExplainOneQuery_hook
 
PGDLLIMPORT explain_per_plan_hook_type explain_per_plan_hook
 
PGDLLIMPORT explain_per_node_hook_type explain_per_node_hook
 
PGDLLIMPORT explain_get_index_name_hook_type explain_get_index_name_hook
 

Typedef Documentation

◆ explain_get_index_name_hook_type

typedef const char *(* explain_get_index_name_hook_type) (Oid indexId)

Definition at line 49 of file explain.h.

◆ explain_per_node_hook_type

typedef void(* explain_per_node_hook_type) (PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, struct ExplainState *es)

Definition at line 41 of file explain.h.

◆ explain_per_plan_hook_type

typedef void(* explain_per_plan_hook_type) (PlannedStmt *plannedstmt, IntoClause *into, struct ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)

Definition at line 32 of file explain.h.

◆ ExplainOneQuery_hook_type

typedef void(* ExplainOneQuery_hook_type) (Query *query, int cursorOptions, IntoClause *into, struct ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)

Definition at line 22 of file explain.h.

Function Documentation

◆ ExplainOnePlan()

void ExplainOnePlan ( PlannedStmt plannedstmt,
CachedPlan cplan,
CachedPlanSource plansource,
int  query_index,
IntoClause into,
struct ExplainState es,
const char *  queryString,
ParamListInfo  params,
QueryEnvironment queryEnv,
const instr_time planduration,
const BufferUsage bufusage,
const MemoryContextCounters mem_counters 
)

Definition at line 495 of file explain.c.

502{
504 QueryDesc *queryDesc;
505 instr_time starttime;
506 double totaltime = 0;
507 int eflags;
508 int instrument_option = 0;
509 SerializeMetrics serializeMetrics = {0};
510
511 Assert(plannedstmt->commandType != CMD_UTILITY);
512
513 if (es->analyze && es->timing)
514 instrument_option |= INSTRUMENT_TIMER;
515 else if (es->analyze)
516 instrument_option |= INSTRUMENT_ROWS;
517
518 if (es->buffers)
519 instrument_option |= INSTRUMENT_BUFFERS;
520 if (es->wal)
521 instrument_option |= INSTRUMENT_WAL;
522
523 /*
524 * We always collect timing for the entire statement, even when node-level
525 * timing is off, so we don't look at es->timing here. (We could skip
526 * this if !es->summary, but it's hardly worth the complication.)
527 */
528 INSTR_TIME_SET_CURRENT(starttime);
529
530 /*
531 * Use a snapshot with an updated command ID to ensure this query sees
532 * results of any previously executed queries.
533 */
536
537 /*
538 * We discard the output if we have no use for it. If we're explaining
539 * CREATE TABLE AS, we'd better use the appropriate tuple receiver, while
540 * the SERIALIZE option requires its own tuple receiver. (If you specify
541 * SERIALIZE while explaining CREATE TABLE AS, you'll see zeroes for the
542 * results, which is appropriate since no data would have gone to the
543 * client.)
544 */
545 if (into)
547 else if (es->serialize != EXPLAIN_SERIALIZE_NONE)
549 else
551
552 /* Create a QueryDesc for the query */
553 queryDesc = CreateQueryDesc(plannedstmt, cplan, queryString,
555 dest, params, queryEnv, instrument_option);
556
557 /* Select execution options */
558 if (es->analyze)
559 eflags = 0; /* default run-to-completion flags */
560 else
561 eflags = EXEC_FLAG_EXPLAIN_ONLY;
562 if (es->generic)
564 if (into)
565 eflags |= GetIntoRelEFlags(into);
566
567 /* Prepare the plan for execution. */
568 if (queryDesc->cplan)
569 {
570 ExecutorStartCachedPlan(queryDesc, eflags, plansource, query_index);
571 Assert(queryDesc->planstate);
572 }
573 else
574 {
575 if (!ExecutorStart(queryDesc, eflags))
576 elog(ERROR, "ExecutorStart() failed unexpectedly");
577 }
578
579 /* Execute the plan for statistics if asked for */
580 if (es->analyze)
581 {
582 ScanDirection dir;
583
584 /* EXPLAIN ANALYZE CREATE TABLE AS WITH NO DATA is weird */
585 if (into && into->skipData)
587 else
589
590 /* run the plan */
591 ExecutorRun(queryDesc, dir, 0);
592
593 /* run cleanup too */
594 ExecutorFinish(queryDesc);
595
596 /* We can't run ExecutorEnd 'till we're done printing the stats... */
597 totaltime += elapsed_time(&starttime);
598 }
599
600 /* grab serialization metrics before we destroy the DestReceiver */
602 serializeMetrics = GetSerializationMetrics(dest);
603
604 /* call the DestReceiver's destroy method even during explain */
605 dest->rDestroy(dest);
606
607 ExplainOpenGroup("Query", NULL, true, es);
608
609 /* Create textual dump of plan tree */
610 ExplainPrintPlan(es, queryDesc);
611
612 /* Show buffer and/or memory usage in planning */
613 if (peek_buffer_usage(es, bufusage) || mem_counters)
614 {
615 ExplainOpenGroup("Planning", "Planning", true, es);
616
617 if (es->format == EXPLAIN_FORMAT_TEXT)
618 {
620 appendStringInfoString(es->str, "Planning:\n");
621 es->indent++;
622 }
623
624 if (bufusage)
625 show_buffer_usage(es, bufusage);
626
627 if (mem_counters)
628 show_memory_counters(es, mem_counters);
629
630 if (es->format == EXPLAIN_FORMAT_TEXT)
631 es->indent--;
632
633 ExplainCloseGroup("Planning", "Planning", true, es);
634 }
635
636 if (es->summary && planduration)
637 {
638 double plantime = INSTR_TIME_GET_DOUBLE(*planduration);
639
640 ExplainPropertyFloat("Planning Time", "ms", 1000.0 * plantime, 3, es);
641 }
642
643 /* Print info about runtime of triggers */
644 if (es->analyze)
645 ExplainPrintTriggers(es, queryDesc);
646
647 /*
648 * Print info about JITing. Tied to es->costs because we don't want to
649 * display this in regression tests, as it'd cause output differences
650 * depending on build options. Might want to separate that out from COSTS
651 * at a later stage.
652 */
653 if (es->costs)
654 ExplainPrintJITSummary(es, queryDesc);
655
656 /* Print info about serialization of output */
658 ExplainPrintSerialize(es, &serializeMetrics);
659
660 /* Allow plugins to print additional information */
662 (*explain_per_plan_hook) (plannedstmt, into, es, queryString,
663 params, queryEnv);
664
665 /*
666 * Close down the query and free resources. Include time for this in the
667 * total execution time (although it should be pretty minimal).
668 */
669 INSTR_TIME_SET_CURRENT(starttime);
670
671 ExecutorEnd(queryDesc);
672
673 FreeQueryDesc(queryDesc);
674
676
677 /* We need a CCI just in case query expanded to multiple plans */
678 if (es->analyze)
680
681 totaltime += elapsed_time(&starttime);
682
683 /*
684 * We only report execution time if we actually ran the query (that is,
685 * the user specified ANALYZE), and if summary reporting is enabled (the
686 * user can set SUMMARY OFF to not have the timing information included in
687 * the output). By default, ANALYZE sets SUMMARY to true.
688 */
689 if (es->summary && es->analyze)
690 ExplainPropertyFloat("Execution Time", "ms", 1000.0 * totaltime, 3,
691 es);
692
693 ExplainCloseGroup("Query", NULL, true, es);
694}
int GetIntoRelEFlags(IntoClause *intoClause)
Definition: createas.c:376
DestReceiver * CreateIntoRelDestReceiver(IntoClause *intoClause)
Definition: createas.c:441
DestReceiver * None_Receiver
Definition: dest.c:96
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
bool ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:128
void ExecutorStartCachedPlan(QueryDesc *queryDesc, int eflags, CachedPlanSource *plansource, int query_index)
Definition: execMain.c:295
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:538
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:475
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
Definition: execMain.c:365
#define EXEC_FLAG_EXPLAIN_GENERIC
Definition: executor.h:67
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:66
static bool peek_buffer_usage(ExplainState *es, const BufferUsage *usage)
Definition: explain.c:4058
void ExplainPrintJITSummary(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:891
static double elapsed_time(instr_time *starttime)
Definition: explain.c:1179
explain_per_plan_hook_type explain_per_plan_hook
Definition: explain.c:56
static void show_memory_counters(ExplainState *es, const MemoryContextCounters *mem_counters)
Definition: explain.c:4310
void ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:771
static void ExplainPrintSerialize(ExplainState *es, SerializeMetrics *metrics)
Definition: explain.c:1015
void ExplainPrintTriggers(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:848
static void show_buffer_usage(ExplainState *es, const BufferUsage *usage)
Definition: explain.c:4098
SerializeMetrics GetSerializationMetrics(DestReceiver *dest)
Definition: explain_dr.c:299
DestReceiver * CreateExplainSerializeDestReceiver(ExplainState *es)
Definition: explain_dr.c:274
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
void ExplainIndentText(ExplainState *es)
void ExplainPropertyFloat(const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
@ EXPLAIN_SERIALIZE_NONE
Definition: explain_state.h:22
@ EXPLAIN_FORMAT_TEXT
Definition: explain_state.h:29
Assert(PointerIsAligned(start, uint64))
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:122
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:188
@ INSTRUMENT_TIMER
Definition: instrument.h:62
@ INSTRUMENT_BUFFERS
Definition: instrument.h:63
@ INSTRUMENT_WAL
Definition: instrument.h:65
@ INSTRUMENT_ROWS
Definition: instrument.h:64
@ CMD_UTILITY
Definition: nodes.h:276
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:112
QueryDesc * CreateQueryDesc(PlannedStmt *plannedstmt, CachedPlan *cplan, const char *sourceText, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, QueryEnvironment *queryEnv, int instrument_options)
Definition: pquery.c:72
ScanDirection
Definition: sdir.h:25
@ NoMovementScanDirection
Definition: sdir.h:27
@ ForwardScanDirection
Definition: sdir.h:28
void UpdateActiveSnapshotCommandId(void)
Definition: snapmgr.c:731
void PopActiveSnapshot(void)
Definition: snapmgr.c:762
void PushCopiedSnapshot(Snapshot snapshot)
Definition: snapmgr.c:719
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:787
#define InvalidSnapshot
Definition: snapshot.h:119
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:230
StringInfo str
Definition: explain_state.h:46
ExplainFormat format
Definition: explain_state.h:59
ExplainSerializeOption serialize
Definition: explain_state.h:58
bool skipData
Definition: primnodes.h:171
CmdType commandType
Definition: plannodes.h:53
CachedPlan * cplan
Definition: execdesc.h:38
PlanState * planstate
Definition: execdesc.h:50
void CommandCounterIncrement(void)
Definition: xact.c:1100

References ExplainState::analyze, appendStringInfoString(), Assert(), ExplainState::buffers, CMD_UTILITY, CommandCounterIncrement(), PlannedStmt::commandType, ExplainState::costs, QueryDesc::cplan, CreateExplainSerializeDestReceiver(), CreateIntoRelDestReceiver(), CreateQueryDesc(), generate_unaccent_rules::dest, elapsed_time(), elog, ERROR, EXEC_FLAG_EXPLAIN_GENERIC, EXEC_FLAG_EXPLAIN_ONLY, ExecutorEnd(), ExecutorFinish(), ExecutorRun(), ExecutorStart(), ExecutorStartCachedPlan(), EXPLAIN_FORMAT_TEXT, explain_per_plan_hook, EXPLAIN_SERIALIZE_NONE, ExplainCloseGroup(), ExplainIndentText(), ExplainOpenGroup(), ExplainPrintJITSummary(), ExplainPrintPlan(), ExplainPrintSerialize(), ExplainPrintTriggers(), ExplainPropertyFloat(), ExplainState::format, ForwardScanDirection, FreeQueryDesc(), ExplainState::generic, GetActiveSnapshot(), GetIntoRelEFlags(), GetSerializationMetrics(), ExplainState::indent, INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, INSTRUMENT_BUFFERS, INSTRUMENT_ROWS, INSTRUMENT_TIMER, INSTRUMENT_WAL, InvalidSnapshot, NoMovementScanDirection, None_Receiver, peek_buffer_usage(), QueryDesc::planstate, PopActiveSnapshot(), PushCopiedSnapshot(), ExplainState::serialize, show_buffer_usage(), show_memory_counters(), IntoClause::skipData, ExplainState::str, ExplainState::summary, ExplainState::timing, UpdateActiveSnapshotCommandId(), and ExplainState::wal.

Referenced by ExplainExecuteQuery(), and standard_ExplainOneQuery().

◆ ExplainOneUtility()

void ExplainOneUtility ( Node utilityStmt,
IntoClause into,
struct ExplainState es,
ParseState pstate,
ParamListInfo  params 
)

Definition at line 391 of file explain.c.

393{
394 if (utilityStmt == NULL)
395 return;
396
397 if (IsA(utilityStmt, CreateTableAsStmt))
398 {
399 /*
400 * We have to rewrite the contained SELECT and then pass it back to
401 * ExplainOneQuery. Copy to be safe in the EXPLAIN EXECUTE case.
402 */
403 CreateTableAsStmt *ctas = (CreateTableAsStmt *) utilityStmt;
404 Query *ctas_query;
405 List *rewritten;
406 JumbleState *jstate = NULL;
407
408 /*
409 * Check if the relation exists or not. This is done at this stage to
410 * avoid query planning or execution.
411 */
412 if (CreateTableAsRelExists(ctas))
413 {
414 if (ctas->objtype == OBJECT_TABLE)
415 ExplainDummyGroup("CREATE TABLE AS", NULL, es);
416 else if (ctas->objtype == OBJECT_MATVIEW)
417 ExplainDummyGroup("CREATE MATERIALIZED VIEW", NULL, es);
418 else
419 elog(ERROR, "unexpected object type: %d",
420 (int) ctas->objtype);
421 return;
422 }
423
424 ctas_query = castNode(Query, copyObject(ctas->query));
425 if (IsQueryIdEnabled())
426 jstate = JumbleQuery(ctas_query);
428 (*post_parse_analyze_hook) (pstate, ctas_query, jstate);
429 rewritten = QueryRewrite(ctas_query);
430 Assert(list_length(rewritten) == 1);
432 CURSOR_OPT_PARALLEL_OK, ctas->into, es,
433 pstate, params);
434 }
435 else if (IsA(utilityStmt, DeclareCursorStmt))
436 {
437 /*
438 * Likewise for DECLARE CURSOR.
439 *
440 * Notice that if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll
441 * actually run the query. This is different from pre-8.3 behavior
442 * but seems more useful than not running the query. No cursor will
443 * be created, however.
444 */
445 DeclareCursorStmt *dcs = (DeclareCursorStmt *) utilityStmt;
446 Query *dcs_query;
447 List *rewritten;
448 JumbleState *jstate = NULL;
449
450 dcs_query = castNode(Query, copyObject(dcs->query));
451 if (IsQueryIdEnabled())
452 jstate = JumbleQuery(dcs_query);
454 (*post_parse_analyze_hook) (pstate, dcs_query, jstate);
455
456 rewritten = QueryRewrite(dcs_query);
457 Assert(list_length(rewritten) == 1);
459 dcs->options, NULL, es,
460 pstate, params);
461 }
462 else if (IsA(utilityStmt, ExecuteStmt))
463 ExplainExecuteQuery((ExecuteStmt *) utilityStmt, into, es,
464 pstate, params);
465 else if (IsA(utilityStmt, NotifyStmt))
466 {
467 if (es->format == EXPLAIN_FORMAT_TEXT)
468 appendStringInfoString(es->str, "NOTIFY\n");
469 else
470 ExplainDummyGroup("Notify", NULL, es);
471 }
472 else
473 {
474 if (es->format == EXPLAIN_FORMAT_TEXT)
476 "Utility statements have no plan structure\n");
477 else
478 ExplainDummyGroup("Utility Statement", NULL, es);
479 }
480}
void ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es, ParseState *pstate, ParamListInfo params)
Definition: prepare.c:572
bool CreateTableAsRelExists(CreateTableAsStmt *ctas)
Definition: createas.c:394
static void ExplainOneQuery(Query *query, int cursorOptions, IntoClause *into, ExplainState *es, ParseState *pstate, ParamListInfo params)
Definition: explain.c:293
void ExplainDummyGroup(const char *objtype, const char *labelname, ExplainState *es)
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define copyObject(obj)
Definition: nodes.h:230
#define castNode(_type_, nodeptr)
Definition: nodes.h:182
@ OBJECT_MATVIEW
Definition: parsenodes.h:2340
@ OBJECT_TABLE
Definition: parsenodes.h:2358
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:3385
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:59
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial_node(type, l)
Definition: pg_list.h:181
static bool IsQueryIdEnabled(void)
Definition: queryjumble.h:95
JumbleState * JumbleQuery(Query *query)
List * QueryRewrite(Query *parsetree)
IntoClause * into
Definition: parsenodes.h:3988
ObjectType objtype
Definition: parsenodes.h:3989
Definition: pg_list.h:54

References appendStringInfoString(), Assert(), castNode, copyObject, CreateTableAsRelExists(), CURSOR_OPT_PARALLEL_OK, elog, ERROR, EXPLAIN_FORMAT_TEXT, ExplainDummyGroup(), ExplainExecuteQuery(), ExplainOneQuery(), ExplainState::format, CreateTableAsStmt::into, IsA, IsQueryIdEnabled(), JumbleQuery(), linitial_node, list_length(), OBJECT_MATVIEW, OBJECT_TABLE, CreateTableAsStmt::objtype, DeclareCursorStmt::options, post_parse_analyze_hook, DeclareCursorStmt::query, CreateTableAsStmt::query, QueryRewrite(), and ExplainState::str.

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

◆ ExplainPrintJITSummary()

void ExplainPrintJITSummary ( struct ExplainState es,
QueryDesc queryDesc 
)

Definition at line 891 of file explain.c.

892{
893 JitInstrumentation ji = {0};
894
895 if (!(queryDesc->estate->es_jit_flags & PGJIT_PERFORM))
896 return;
897
898 /*
899 * Work with a copy instead of modifying the leader state, since this
900 * function may be called twice
901 */
902 if (queryDesc->estate->es_jit)
903 InstrJitAgg(&ji, &queryDesc->estate->es_jit->instr);
904
905 /* If this process has done JIT in parallel workers, merge stats */
906 if (queryDesc->estate->es_jit_worker_instr)
907 InstrJitAgg(&ji, queryDesc->estate->es_jit_worker_instr);
908
909 ExplainPrintJIT(es, queryDesc->estate->es_jit_flags, &ji);
910}
static void ExplainPrintJIT(ExplainState *es, int jit_flags, JitInstrumentation *ji)
Definition: explain.c:917
void InstrJitAgg(JitInstrumentation *dst, JitInstrumentation *add)
Definition: jit.c:182
#define PGJIT_PERFORM
Definition: jit.h:20
struct JitContext * es_jit
Definition: execnodes.h:763
struct JitInstrumentation * es_jit_worker_instr
Definition: execnodes.h:764
int es_jit_flags
Definition: execnodes.h:762
JitInstrumentation instr
Definition: jit.h:62
EState * estate
Definition: execdesc.h:49

References EState::es_jit, EState::es_jit_flags, EState::es_jit_worker_instr, QueryDesc::estate, ExplainPrintJIT(), JitContext::instr, InstrJitAgg(), and PGJIT_PERFORM.

Referenced by explain_ExecutorEnd(), and ExplainOnePlan().

◆ ExplainPrintPlan()

void ExplainPrintPlan ( struct ExplainState es,
QueryDesc queryDesc 
)

Definition at line 771 of file explain.c.

772{
773 Bitmapset *rels_used = NULL;
774 PlanState *ps;
775 ListCell *lc;
776
777 /* Set up ExplainState fields associated with this plan tree */
778 Assert(queryDesc->plannedstmt != NULL);
779 es->pstmt = queryDesc->plannedstmt;
780 es->rtable = queryDesc->plannedstmt->rtable;
781 ExplainPreScanNode(queryDesc->planstate, &rels_used);
784 es->rtable_names);
785 es->printed_subplans = NULL;
786 es->rtable_size = list_length(es->rtable);
787 foreach(lc, es->rtable)
788 {
790
791 if (rte->rtekind == RTE_GROUP)
792 {
793 es->rtable_size--;
794 break;
795 }
796 }
797
798 /*
799 * Sometimes we mark a Gather node as "invisible", which means that it's
800 * not to be displayed in EXPLAIN output. The purpose of this is to allow
801 * running regression tests with debug_parallel_query=regress to get the
802 * same results as running the same tests with debug_parallel_query=off.
803 * Such marking is currently only supported on a Gather at the top of the
804 * plan. We skip that node, and we must also hide per-worker detail data
805 * further down in the plan tree.
806 */
807 ps = queryDesc->planstate;
808 if (IsA(ps, GatherState) && ((Gather *) ps->plan)->invisible)
809 {
811 es->hide_workers = true;
812 }
813 ExplainNode(ps, NIL, NULL, NULL, es);
814
815 /*
816 * If requested, include information about GUC parameters with values that
817 * don't match the built-in defaults.
818 */
820
821 /*
822 * COMPUTE_QUERY_ID_REGRESS means COMPUTE_QUERY_ID_AUTO, but we don't show
823 * the queryid in any of the EXPLAIN plans to keep stable the results
824 * generated by regression test suites.
825 */
826 if (es->verbose && queryDesc->plannedstmt->queryId != UINT64CONST(0) &&
828 {
829 /*
830 * Output the queryid as an int64 rather than a uint64 so we match
831 * what would be seen in the BIGINT pg_stat_statements.queryid column.
832 */
833 ExplainPropertyInteger("Query Identifier", NULL, (int64)
834 queryDesc->plannedstmt->queryId, es);
835 }
836}
int64_t int64
Definition: c.h:499
#define UINT64CONST(x)
Definition: c.h:517
#define outerPlanState(node)
Definition: execnodes.h:1255
static void ExplainNode(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
Definition: explain.c:1363
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
Definition: explain.c:1198
static void ExplainPrintSettings(ExplainState *es)
Definition: explain.c:701
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
struct parser_state ps
@ RTE_GROUP
Definition: parsenodes.h:1037
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define NIL
Definition: pg_list.h:68
@ COMPUTE_QUERY_ID_REGRESS
Definition: queryjumble.h:77
int compute_query_id
List * deparse_context_for_plan_tree(PlannedStmt *pstmt, List *rtable_names)
Definition: ruleutils.c:3753
List * select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
Definition: ruleutils.c:3855
Bitmapset * printed_subplans
Definition: explain_state.h:68
List * rtable_names
Definition: explain_state.h:66
PlannedStmt * pstmt
Definition: explain_state.h:64
List * deparse_cxt
Definition: explain_state.h:67
List * rtable
Definition: plannodes.h:91
uint64 queryId
Definition: plannodes.h:56
PlannedStmt * plannedstmt
Definition: execdesc.h:37
RTEKind rtekind
Definition: parsenodes.h:1061

References Assert(), compute_query_id, COMPUTE_QUERY_ID_REGRESS, deparse_context_for_plan_tree(), ExplainState::deparse_cxt, ExplainNode(), ExplainPreScanNode(), ExplainPrintSettings(), ExplainPropertyInteger(), ExplainState::hide_workers, IsA, lfirst_node, list_length(), NIL, outerPlanState, QueryDesc::plannedstmt, QueryDesc::planstate, ExplainState::printed_subplans, ps, ExplainState::pstmt, PlannedStmt::queryId, ExplainState::rtable, PlannedStmt::rtable, ExplainState::rtable_names, ExplainState::rtable_size, RTE_GROUP, RangeTblEntry::rtekind, select_rtable_names_for_explain(), UINT64CONST, and ExplainState::verbose.

Referenced by explain_ExecutorEnd(), and ExplainOnePlan().

◆ ExplainPrintTriggers()

void ExplainPrintTriggers ( struct ExplainState es,
QueryDesc queryDesc 
)

Definition at line 848 of file explain.c.

849{
850 ResultRelInfo *rInfo;
851 bool show_relname;
852 List *resultrels;
853 List *routerels;
854 List *targrels;
855 ListCell *l;
856
857 resultrels = queryDesc->estate->es_opened_result_relations;
858 routerels = queryDesc->estate->es_tuple_routing_result_relations;
859 targrels = queryDesc->estate->es_trig_target_relations;
860
861 ExplainOpenGroup("Triggers", "Triggers", false, es);
862
863 show_relname = (list_length(resultrels) > 1 ||
864 routerels != NIL || targrels != NIL);
865 foreach(l, resultrels)
866 {
867 rInfo = (ResultRelInfo *) lfirst(l);
868 report_triggers(rInfo, show_relname, es);
869 }
870
871 foreach(l, routerels)
872 {
873 rInfo = (ResultRelInfo *) lfirst(l);
874 report_triggers(rInfo, show_relname, es);
875 }
876
877 foreach(l, targrels)
878 {
879 rInfo = (ResultRelInfo *) lfirst(l);
880 report_triggers(rInfo, show_relname, es);
881 }
882
883 ExplainCloseGroup("Triggers", "Triggers", false, es);
884}
static void report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
Definition: explain.c:1108
#define lfirst(lc)
Definition: pg_list.h:172
List * es_tuple_routing_result_relations
Definition: execnodes.h:696
List * es_trig_target_relations
Definition: execnodes.h:699
List * es_opened_result_relations
Definition: execnodes.h:686

References EState::es_opened_result_relations, EState::es_trig_target_relations, EState::es_tuple_routing_result_relations, QueryDesc::estate, ExplainCloseGroup(), ExplainOpenGroup(), lfirst, list_length(), NIL, and report_triggers().

Referenced by explain_ExecutorEnd(), and ExplainOnePlan().

◆ ExplainQuery()

void ExplainQuery ( ParseState pstate,
ExplainStmt stmt,
ParamListInfo  params,
DestReceiver dest 
)

Definition at line 176 of file explain.c.

178{
180 TupOutputState *tstate;
181 JumbleState *jstate = NULL;
182 Query *query;
183 List *rewritten;
184
185 /* Configure the ExplainState based on the provided options */
186 ParseExplainOptionList(es, stmt->options, pstate);
187
188 /* Extract the query and, if enabled, jumble it */
189 query = castNode(Query, stmt->query);
190 if (IsQueryIdEnabled())
191 jstate = JumbleQuery(query);
192
194 (*post_parse_analyze_hook) (pstate, query, jstate);
195
196 /*
197 * Parse analysis was done already, but we still have to run the rule
198 * rewriter. We do not do AcquireRewriteLocks: we assume the query either
199 * came straight from the parser, or suitable locks were acquired by
200 * plancache.c.
201 */
202 rewritten = QueryRewrite(castNode(Query, stmt->query));
203
204 /* emit opening boilerplate */
206
207 if (rewritten == NIL)
208 {
209 /*
210 * In the case of an INSTEAD NOTHING, tell at least that. But in
211 * non-text format, the output is delimited, so this isn't necessary.
212 */
213 if (es->format == EXPLAIN_FORMAT_TEXT)
214 appendStringInfoString(es->str, "Query rewrites to nothing\n");
215 }
216 else
217 {
218 ListCell *l;
219
220 /* Explain every plan */
221 foreach(l, rewritten)
222 {
224 CURSOR_OPT_PARALLEL_OK, NULL, es,
225 pstate, params);
226
227 /* Separate plans with an appropriate separator */
228 if (lnext(rewritten, l) != NULL)
230 }
231 }
232
233 /* emit closing boilerplate */
235 Assert(es->indent == 0);
236
237 /* output tuples */
240 if (es->format == EXPLAIN_FORMAT_TEXT)
241 do_text_output_multiline(tstate, es->str->data);
242 else
243 do_text_output_oneline(tstate, es->str->data);
244 end_tup_output(tstate);
245
246 pfree(es->str->data);
247}
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:84
void end_tup_output(TupOutputState *tstate)
Definition: execTuples.c:2522
void do_text_output_multiline(TupOutputState *tstate, const char *txt)
Definition: execTuples.c:2492
TupOutputState * begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:2444
#define do_text_output_oneline(tstate, str_to_emit)
Definition: executor.h:650
TupleDesc ExplainResultDesc(ExplainStmt *stmt)
Definition: explain.c:254
void ExplainSeparatePlans(ExplainState *es)
void ExplainEndOutput(ExplainState *es)
void ExplainBeginOutput(ExplainState *es)
ExplainState * NewExplainState(void)
Definition: explain_state.c:61
void ParseExplainOptionList(ExplainState *es, List *options, ParseState *pstate)
Definition: explain_state.c:77
#define stmt
Definition: indent_codes.h:59
void pfree(void *pointer)
Definition: mcxt.c:2152
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343

References appendStringInfoString(), Assert(), begin_tup_output_tupdesc(), castNode, CURSOR_OPT_PARALLEL_OK, StringInfoData::data, generate_unaccent_rules::dest, do_text_output_multiline(), do_text_output_oneline, end_tup_output(), EXPLAIN_FORMAT_TEXT, ExplainBeginOutput(), ExplainEndOutput(), ExplainOneQuery(), ExplainResultDesc(), ExplainSeparatePlans(), ExplainState::format, ExplainState::indent, IsQueryIdEnabled(), JumbleQuery(), lfirst_node, lnext(), NewExplainState(), NIL, ParseExplainOptionList(), pfree(), post_parse_analyze_hook, QueryRewrite(), stmt, ExplainState::str, and TTSOpsVirtual.

Referenced by standard_ProcessUtility().

◆ ExplainQueryParameters()

void ExplainQueryParameters ( struct ExplainState es,
ParamListInfo  params,
int  maxlen 
)

Definition at line 1090 of file explain.c.

1091{
1092 char *str;
1093
1094 /* This check is consistent with errdetail_params() */
1095 if (params == NULL || params->numParams <= 0 || maxlen == 0)
1096 return;
1097
1098 str = BuildParamLogString(params, NULL, maxlen);
1099 if (str && str[0] != '\0')
1100 ExplainPropertyText("Query Parameters", str, es);
1101}
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
const char * str
char * BuildParamLogString(ParamListInfo params, char **knownTextValues, int maxlen)
Definition: params.c:335

References BuildParamLogString(), ExplainPropertyText(), ParamListInfoData::numParams, and str.

Referenced by explain_ExecutorEnd().

◆ ExplainQueryText()

void ExplainQueryText ( struct ExplainState es,
QueryDesc queryDesc 
)

Definition at line 1075 of file explain.c.

1076{
1077 if (queryDesc->sourceText)
1078 ExplainPropertyText("Query Text", queryDesc->sourceText, es);
1079}
const char * sourceText
Definition: execdesc.h:39

References ExplainPropertyText(), and QueryDesc::sourceText.

Referenced by explain_ExecutorEnd().

◆ ExplainResultDesc()

TupleDesc ExplainResultDesc ( ExplainStmt stmt)

Definition at line 254 of file explain.c.

255{
256 TupleDesc tupdesc;
257 ListCell *lc;
258 Oid result_type = TEXTOID;
259
260 /* Check for XML format option */
261 foreach(lc, stmt->options)
262 {
263 DefElem *opt = (DefElem *) lfirst(lc);
264
265 if (strcmp(opt->defname, "format") == 0)
266 {
267 char *p = defGetString(opt);
268
269 if (strcmp(p, "xml") == 0)
270 result_type = XMLOID;
271 else if (strcmp(p, "json") == 0)
272 result_type = JSONOID;
273 else
274 result_type = TEXTOID;
275 /* don't "break", as ExplainQuery will use the last value */
276 }
277 }
278
279 /* Need a tuple descriptor representing a single TEXT or XML column */
280 tupdesc = CreateTemplateTupleDesc(1);
281 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
282 result_type, -1, 0);
283 return tupdesc;
284}
int16 AttrNumber
Definition: attnum.h:21
char * defGetString(DefElem *def)
Definition: define.c:35
unsigned int Oid
Definition: postgres_ext.h:30
char * defname
Definition: parsenodes.h:826
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:175
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:835

References CreateTemplateTupleDesc(), defGetString(), DefElem::defname, lfirst, stmt, and TupleDescInitEntry().

Referenced by ExplainQuery(), and UtilityTupleDescriptor().

◆ standard_ExplainOneQuery()

void standard_ExplainOneQuery ( Query query,
int  cursorOptions,
IntoClause into,
struct ExplainState es,
const char *  queryString,
ParamListInfo  params,
QueryEnvironment queryEnv 
)

Definition at line 318 of file explain.c.

322{
324 instr_time planstart,
325 planduration;
326 BufferUsage bufusage_start,
327 bufusage;
328 MemoryContextCounters mem_counters;
329 MemoryContext planner_ctx = NULL;
330 MemoryContext saved_ctx = NULL;
331
332 if (es->memory)
333 {
334 /*
335 * Create a new memory context to measure planner's memory consumption
336 * accurately. Note that if the planner were to be modified to use a
337 * different memory context type, here we would be changing that to
338 * AllocSet, which might be undesirable. However, we don't have a way
339 * to create a context of the same type as another, so we pray and
340 * hope that this is OK.
341 */
343 "explain analyze planner context",
345 saved_ctx = MemoryContextSwitchTo(planner_ctx);
346 }
347
348 if (es->buffers)
349 bufusage_start = pgBufferUsage;
350 INSTR_TIME_SET_CURRENT(planstart);
351
352 /* plan the query */
353 plan = pg_plan_query(query, queryString, cursorOptions, params);
354
355 INSTR_TIME_SET_CURRENT(planduration);
356 INSTR_TIME_SUBTRACT(planduration, planstart);
357
358 if (es->memory)
359 {
360 MemoryContextSwitchTo(saved_ctx);
361 MemoryContextMemConsumed(planner_ctx, &mem_counters);
362 }
363
364 /* calc differences of buffer counters. */
365 if (es->buffers)
366 {
367 memset(&bufusage, 0, sizeof(BufferUsage));
368 BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
369 }
370
371 /* run it (if needed) and produce output */
372 ExplainOnePlan(plan, NULL, NULL, -1, into, es, queryString, params,
373 queryEnv,
374 &planduration, (es->buffers ? &bufusage : NULL),
375 es->memory ? &mem_counters : NULL);
376}
void ExplainOnePlan(PlannedStmt *plannedstmt, CachedPlan *cplan, CachedPlanSource *plansource, int query_index, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv, const instr_time *planduration, const BufferUsage *bufusage, const MemoryContextCounters *mem_counters)
Definition: explain.c:495
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:181
BufferUsage pgBufferUsage
Definition: instrument.c:20
void BufferUsageAccumDiff(BufferUsage *dst, const BufferUsage *add, const BufferUsage *sub)
Definition: instrument.c:248
void MemoryContextMemConsumed(MemoryContext context, MemoryContextCounters *consumed)
Definition: mcxt.c:817
MemoryContext CurrentMemoryContext
Definition: mcxt.c:159
#define AllocSetContextCreate
Definition: memutils.h:149
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:180
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define plan(x)
Definition: pg_regress.c:161
PlannedStmt * pg_plan_query(Query *querytree, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:882

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, ExplainState::buffers, BufferUsageAccumDiff(), CurrentMemoryContext, ExplainOnePlan(), INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, ExplainState::memory, MemoryContextMemConsumed(), MemoryContextSwitchTo(), pg_plan_query(), pgBufferUsage, and plan.

Referenced by ExplainOneQuery().

Variable Documentation

◆ explain_get_index_name_hook

PGDLLIMPORT explain_get_index_name_hook_type explain_get_index_name_hook
extern

Definition at line 53 of file explain.c.

Referenced by explain_get_index_name().

◆ explain_per_node_hook

PGDLLIMPORT explain_per_node_hook_type explain_per_node_hook
extern

Definition at line 57 of file explain.c.

Referenced by _PG_init(), and ExplainNode().

◆ explain_per_plan_hook

PGDLLIMPORT explain_per_plan_hook_type explain_per_plan_hook
extern

Definition at line 56 of file explain.c.

Referenced by _PG_init(), and ExplainOnePlan().

◆ ExplainOneQuery_hook

PGDLLIMPORT ExplainOneQuery_hook_type ExplainOneQuery_hook
extern

Definition at line 50 of file explain.c.

Referenced by ExplainOneQuery().