PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
pg_overexplain.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * pg_overexplain.c
4 * allow EXPLAIN to dump even more details
5 *
6 * Copyright (c) 2016-2025, PostgreSQL Global Development Group
7 *
8 * contrib/pg_overexplain/pg_overexplain.c
9 *-------------------------------------------------------------------------
10 */
11#include "postgres.h"
12
13#include "catalog/pg_class.h"
14#include "commands/defrem.h"
15#include "commands/explain.h"
18#include "fmgr.h"
19#include "parser/parsetree.h"
20#include "storage/lock.h"
21#include "utils/builtins.h"
22#include "utils/lsyscache.h"
23
25 .name = "pg_overexplain",
26 .version = PG_VERSION
27);
28
29typedef struct
30{
31 bool debug;
34
37 ParseState *pstate);
39 ParseState *pstate);
40static void overexplain_per_node_hook(PlanState *planstate, List *ancestors,
41 const char *relationship,
42 const char *plan_name,
43 ExplainState *es);
44static void overexplain_per_plan_hook(PlannedStmt *plannedstmt,
45 IntoClause *into,
46 ExplainState *es,
47 const char *queryString,
48 ParamListInfo params,
49 QueryEnvironment *queryEnv);
50static void overexplain_debug(PlannedStmt *plannedstmt, ExplainState *es);
51static void overexplain_range_table(PlannedStmt *plannedstmt,
52 ExplainState *es);
53static void overexplain_alias(const char *qlabel, Alias *alias,
54 ExplainState *es);
55static void overexplain_bitmapset(const char *qlabel, Bitmapset *bms,
56 ExplainState *es);
57static void overexplain_intlist(const char *qlabel, List *intlist,
58 ExplainState *es);
59
60static int es_extension_id;
63
64/*
65 * Initialization we do when this module is loaded.
66 */
67void
69{
70 /* Get an ID that we can use to cache data in an ExplainState. */
71 es_extension_id = GetExplainExtensionId("pg_overexplain");
72
73 /* Register the new EXPLAIN options implemented by this module. */
77
78 /* Use the per-node and per-plan hooks to make our options do something. */
83}
84
85/*
86 * Get the overexplain_options structure from an ExplainState; if there is
87 * none, create one, attach it to the ExplainState, and return it.
88 */
91{
93
95
96 if (options == NULL)
97 {
100 }
101
102 return options;
103}
104
105/*
106 * Parse handler for EXPLAIN (DEBUG).
107 */
108static void
110{
112
113 options->debug = defGetBoolean(opt);
114}
115
116/*
117 * Parse handler for EXPLAIN (RANGE_TABLE).
118 */
119static void
121 ParseState *pstate)
122{
124
125 options->range_table = defGetBoolean(opt);
126}
127
128/*
129 * Print out additional per-node information as appropriate. If the user didn't
130 * specify any of the options we support, do nothing; else, print whatever is
131 * relevant to the specified options.
132 */
133static void
135 const char *relationship, const char *plan_name,
136 ExplainState *es)
137{
139 Plan *plan = planstate->plan;
140
142 (*prev_explain_per_node_hook) (planstate, ancestors, relationship,
143 plan_name, es);
144
146 if (options == NULL)
147 return;
148
149 /*
150 * If the "debug" option was given, display miscellaneous fields from the
151 * "Plan" node that would not otherwise be displayed.
152 */
153 if (options->debug)
154 {
155 /*
156 * Normal EXPLAIN will display "Disabled: true" if the node is
157 * disabled; but that is based on noticing that plan->disabled_nodes
158 * is higher than the sum of its children; here, we display the raw
159 * value, for debugging purposes.
160 */
161 ExplainPropertyInteger("Disabled Nodes", NULL, plan->disabled_nodes,
162 es);
163
164 /*
165 * Normal EXPLAIN will display the parallel_aware flag; here, we show
166 * the parallel_safe flag as well.
167 */
168 ExplainPropertyBool("Parallel Safe", plan->parallel_safe, es);
169
170 /*
171 * The plan node ID isn't normally displayed, since it is only useful
172 * for debugging.
173 */
174 ExplainPropertyInteger("Plan Node ID", NULL, plan->plan_node_id, es);
175
176 /*
177 * It is difficult to explain what extParam and allParam mean in plain
178 * language, so we simply display these fields labelled with the
179 * structure member name. For compactness, the text format omits the
180 * display of this information when the bitmapset is empty.
181 */
182 if (es->format != EXPLAIN_FORMAT_TEXT || !bms_is_empty(plan->extParam))
183 overexplain_bitmapset("extParam", plan->extParam, es);
184 if (es->format != EXPLAIN_FORMAT_TEXT || !bms_is_empty(plan->allParam))
185 overexplain_bitmapset("allParam", plan->allParam, es);
186 }
187
188 /*
189 * If the "range_table" option was specified, display information about
190 * the range table indexes for this node.
191 */
192 if (options->range_table)
193 {
194 switch (nodeTag(plan))
195 {
196 case T_SeqScan:
197 case T_SampleScan:
198 case T_IndexScan:
199 case T_IndexOnlyScan:
200 case T_BitmapHeapScan:
201 case T_TidScan:
202 case T_TidRangeScan:
203 case T_SubqueryScan:
204 case T_FunctionScan:
205 case T_TableFuncScan:
206 case T_ValuesScan:
207 case T_CteScan:
208 case T_NamedTuplestoreScan:
209 case T_WorkTableScan:
210 ExplainPropertyInteger("Scan RTI", NULL,
211 ((Scan *) plan)->scanrelid, es);
212 break;
213 case T_ForeignScan:
214 overexplain_bitmapset("Scan RTIs",
215 ((ForeignScan *) plan)->fs_base_relids,
216 es);
217 break;
218 case T_CustomScan:
219 overexplain_bitmapset("Scan RTIs",
220 ((CustomScan *) plan)->custom_relids,
221 es);
222 break;
223 case T_ModifyTable:
224 ExplainPropertyInteger("Nominal RTI", NULL,
225 ((ModifyTable *) plan)->nominalRelation, es);
226 ExplainPropertyInteger("Exclude Relation RTI", NULL,
227 ((ModifyTable *) plan)->exclRelRTI, es);
228 break;
229 case T_Append:
230 overexplain_bitmapset("Append RTIs",
231 ((Append *) plan)->apprelids,
232 es);
233 break;
234 case T_MergeAppend:
235 overexplain_bitmapset("Append RTIs",
236 ((MergeAppend *) plan)->apprelids,
237 es);
238 break;
239 default:
240 break;
241 }
242 }
243}
244
245/*
246 * Print out additional per-query information as appropriate. Here again, if
247 * the user didn't specify any of the options implemented by this module, do
248 * nothing; otherwise, call the appropriate function for each specified
249 * option.
250 */
251static void
253 IntoClause *into,
254 ExplainState *es,
255 const char *queryString,
256 ParamListInfo params,
257 QueryEnvironment *queryEnv)
258{
260
262 (*prev_explain_per_plan_hook) (plannedstmt, into, es, queryString,
263 params, queryEnv);
264
266 if (options == NULL)
267 return;
268
269 if (options->debug)
270 overexplain_debug(plannedstmt, es);
271
272 if (options->range_table)
273 overexplain_range_table(plannedstmt, es);
274}
275
276/*
277 * Print out various details from the PlannedStmt that wouldn't otherwise
278 * be displayed.
279 *
280 * We don't try to print everything here. Information that would be displyed
281 * anyway doesn't need to be printed again here, and things with lots of
282 * substructure probably should be printed via separate options, or not at all.
283 */
284static void
286{
287 char *commandType = NULL;
288 StringInfoData flags;
289
290 /* Even in text mode, we want to set this output apart as its own group. */
291 ExplainOpenGroup("PlannedStmt", "PlannedStmt", true, es);
292 if (es->format == EXPLAIN_FORMAT_TEXT)
293 {
295 appendStringInfo(es->str, "PlannedStmt:\n");
296 es->indent++;
297 }
298
299 /* Print the command type. */
300 switch (plannedstmt->commandType)
301 {
302 case CMD_UNKNOWN:
303 commandType = "unknown";
304 break;
305 case CMD_SELECT:
306 commandType = "select";
307 break;
308 case CMD_UPDATE:
309 commandType = "update";
310 break;
311 case CMD_INSERT:
312 commandType = "insert";
313 break;
314 case CMD_DELETE:
315 commandType = "delete";
316 break;
317 case CMD_MERGE:
318 commandType = "merge";
319 break;
320 case CMD_UTILITY:
321 commandType = "utility";
322 break;
323 case CMD_NOTHING:
324 commandType = "nothing";
325 break;
326 }
327 ExplainPropertyText("Command Type", commandType, es);
328
329 /* Print various properties as a comma-separated list of flags. */
330 initStringInfo(&flags);
331 if (plannedstmt->hasReturning)
332 appendStringInfo(&flags, ", hasReturning");
333 if (plannedstmt->hasModifyingCTE)
334 appendStringInfo(&flags, ", hasModifyingCTE");
335 if (plannedstmt->canSetTag)
336 appendStringInfo(&flags, ", canSetTag");
337 if (plannedstmt->transientPlan)
338 appendStringInfo(&flags, ", transientPlan");
339 if (plannedstmt->dependsOnRole)
340 appendStringInfo(&flags, ", dependsOnRole");
341 if (plannedstmt->parallelModeNeeded)
342 appendStringInfo(&flags, ", parallelModeNeeded");
343 if (flags.len == 0)
344 appendStringInfo(&flags, ", none");
345 ExplainPropertyText("Flags", flags.data + 2, es);
346
347 /* Various lists of integers. */
348 overexplain_bitmapset("Subplans Needing Rewind",
349 plannedstmt->rewindPlanIDs, es);
350 overexplain_intlist("Relation OIDs",
351 plannedstmt->relationOids, es);
352 overexplain_intlist("Executor Parameter Types",
353 plannedstmt->paramExecTypes, es);
354
355 /*
356 * Print the statement location. (If desired, we could alternatively print
357 * stmt_location and stmt_len as two separate fields.)
358 */
359 if (plannedstmt->stmt_location == -1)
360 ExplainPropertyText("Parse Location", "Unknown", es);
361 else if (plannedstmt->stmt_len == 0)
362 ExplainPropertyText("Parse Location",
363 psprintf("%d to end", plannedstmt->stmt_location),
364 es);
365 else
366 ExplainPropertyText("Parse Location",
367 psprintf("%d for %d bytes",
368 plannedstmt->stmt_location,
369 plannedstmt->stmt_len),
370 es);
371
372 /* Done with this group. */
373 if (es->format == EXPLAIN_FORMAT_TEXT)
374 es->indent--;
375 ExplainCloseGroup("PlannedStmt", "PlannedStmt", true, es);
376}
377
378/*
379 * Provide detailed information about the contents of the PlannedStmt's
380 * range table.
381 */
382static void
384{
385 Index rti;
386
387 /* Open group, one entry per RangeTblEntry */
388 ExplainOpenGroup("Range Table", "Range Table", false, es);
389
390 /* Iterate over the range table */
391 for (rti = 1; rti <= list_length(plannedstmt->rtable); ++rti)
392 {
393 RangeTblEntry *rte = rt_fetch(rti, plannedstmt->rtable);
394 char *kind = NULL;
395 char *relkind;
396
397 /* NULL entries are possible; skip them */
398 if (rte == NULL)
399 continue;
400
401 /* Translate rtekind to a string */
402 switch (rte->rtekind)
403 {
404 case RTE_RELATION:
405 kind = "relation";
406 break;
407 case RTE_SUBQUERY:
408 kind = "subquery";
409 break;
410 case RTE_JOIN:
411 kind = "join";
412 break;
413 case RTE_FUNCTION:
414 kind = "function";
415 break;
416 case RTE_TABLEFUNC:
417 kind = "tablefunc";
418 break;
419 case RTE_VALUES:
420 kind = "values";
421 break;
422 case RTE_CTE:
423 kind = "cte";
424 break;
426 kind = "namedtuplestore";
427 break;
428 case RTE_RESULT:
429 kind = "result";
430 break;
431 case RTE_GROUP:
432 kind = "group";
433 break;
434 }
435
436 /* Begin group for this specific RTE */
437 ExplainOpenGroup("Range Table Entry", NULL, true, es);
438
439 /*
440 * In text format, the summary line displays the range table index and
441 * rtekind, plus indications if rte->inh and/or rte->inFromCl are set.
442 * In other formats, we display those as separate properties.
443 */
444 if (es->format == EXPLAIN_FORMAT_TEXT)
445 {
447 appendStringInfo(es->str, "RTI %u (%s%s%s):\n", rti, kind,
448 rte->inh ? ", inherited" : "",
449 rte->inFromCl ? ", in-from-clause" : "");
450 es->indent++;
451 }
452 else
453 {
454 ExplainPropertyUInteger("RTI", NULL, rti, es);
455 ExplainPropertyText("Kind", kind, es);
456 ExplainPropertyBool("Inherited", rte->inh, es);
457 ExplainPropertyBool("In From Clause", rte->inFromCl, es);
458 }
459
460 /* rte->alias is optional; rte->eref is requested */
461 if (rte->alias != NULL)
462 overexplain_alias("Alias", rte->alias, es);
463 overexplain_alias("Eref", rte->eref, es);
464
465 /*
466 * We adhere to the usual EXPLAIN convention that schema names are
467 * displayed only in verbose mode, and we emit nothing if there is no
468 * relation OID.
469 */
470 if (rte->relid != 0)
471 {
472 const char *relname;
473 const char *qualname;
474
476
477 if (es->verbose)
478 {
479 Oid nspoid = get_rel_namespace(rte->relid);
480 char *nspname;
481
482 nspname = get_namespace_name_or_temp(nspoid);
483 qualname = psprintf("%s.%s", quote_identifier(nspname),
484 relname);
485 }
486 else
487 qualname = relname;
488
489 ExplainPropertyText("Relation", qualname, es);
490 }
491
492 /* Translate relkind, if any, to a string */
493 switch (rte->relkind)
494 {
495 case RELKIND_RELATION:
496 relkind = "relation";
497 break;
498 case RELKIND_INDEX:
499 relkind = "index";
500 break;
501 case RELKIND_SEQUENCE:
502 relkind = "sequence";
503 break;
504 case RELKIND_TOASTVALUE:
505 relkind = "toastvalue";
506 break;
507 case RELKIND_VIEW:
508 relkind = "view";
509 break;
510 case RELKIND_MATVIEW:
511 relkind = "matview";
512 break;
513 case RELKIND_COMPOSITE_TYPE:
514 relkind = "composite_type";
515 break;
516 case RELKIND_FOREIGN_TABLE:
517 relkind = "foreign_table";
518 break;
519 case RELKIND_PARTITIONED_TABLE:
520 relkind = "parititioned_table";
521 break;
522 case RELKIND_PARTITIONED_INDEX:
523 relkind = "parititioned_index";
524 break;
525 case '\0':
526 relkind = NULL;
527 break;
528 default:
529 relkind = psprintf("%c", rte->relkind);
530 break;
531 }
532
533 /* If there is a relkind, show it */
534 if (relkind != NULL)
535 ExplainPropertyText("Relation Kind", relkind, es);
536
537 /* If there is a lock mode, show it */
538 if (rte->rellockmode != 0)
539 ExplainPropertyText("Relation Lock Mode",
541 rte->rellockmode), es);
542
543 /*
544 * If there is a perminfoindex, show it. We don't try to display
545 * information from the RTEPermissionInfo node here because they are
546 * just indexes plannedstmt->permInfos which could be separately
547 * dumped if someone wants to add EXPLAIN (PERMISSIONS) or similar.
548 */
549 if (rte->perminfoindex != 0)
550 ExplainPropertyInteger("Permission Info Index", NULL,
551 rte->perminfoindex, es);
552
553 /*
554 * add_rte_to_flat_rtable will clear rte->tablesample and
555 * rte->subquery in the finished plan, so skip those fields.
556 *
557 * However, the security_barrier flag is not shown by the core code,
558 * so let's print it here.
559 */
560 if (es->format != EXPLAIN_FORMAT_TEXT || rte->security_barrier)
561 ExplainPropertyBool("Security Barrier", rte->security_barrier, es);
562
563 /*
564 * If this is a join, print out the fields that are specifically valid
565 * for joins.
566 */
567 if (rte->rtekind == RTE_JOIN)
568 {
569 char *jointype;
570
571 switch (rte->jointype)
572 {
573 case JOIN_INNER:
574 jointype = "Inner";
575 break;
576 case JOIN_LEFT:
577 jointype = "Left";
578 break;
579 case JOIN_FULL:
580 jointype = "Full";
581 break;
582 case JOIN_RIGHT:
583 jointype = "Right";
584 break;
585 case JOIN_SEMI:
586 jointype = "Semi";
587 break;
588 case JOIN_ANTI:
589 jointype = "Anti";
590 break;
591 case JOIN_RIGHT_SEMI:
592 jointype = "Right Semi";
593 break;
594 case JOIN_RIGHT_ANTI:
595 jointype = "Right Anti";
596 break;
597 default:
598 jointype = "???";
599 break;
600 }
601
602 /* Join type */
603 ExplainPropertyText("Join Type", jointype, es);
604
605 /* # of JOIN USING columns */
606 if (es->format != EXPLAIN_FORMAT_TEXT || rte->joinmergedcols != 0)
607 ExplainPropertyInteger("JOIN USING Columns", NULL,
608 rte->joinmergedcols, es);
609
610 /*
611 * add_rte_to_flat_rtable will clear joinaliasvars, joinleftcols,
612 * joinrightcols, and join_using_alias here, so skip those fields.
613 */
614 }
615
616 /*
617 * add_rte_to_flat_rtable will clear functions, tablefunc, and
618 * values_lists, but we can display funcordinality.
619 */
620 if (rte->rtekind == RTE_FUNCTION)
621 ExplainPropertyBool("WITH ORDINALITY", rte->funcordinality, es);
622
623 /*
624 * If this is a CTE, print out CTE-related properties.
625 */
626 if (rte->rtekind == RTE_CTE)
627 {
628 ExplainPropertyText("CTE Name", rte->ctename, es);
629 ExplainPropertyUInteger("CTE Levels Up", NULL, rte->ctelevelsup,
630 es);
631 ExplainPropertyBool("CTE Self-Reference", rte->self_reference, es);
632 }
633
634 /*
635 * add_rte_to_flat_rtable will clear coltypes, coltypemods, and
636 * colcollations, so skip those fields.
637 *
638 * If this is an ephemeral named relation, print out ENR-related
639 * properties.
640 */
641 if (rte->rtekind == RTE_NAMEDTUPLESTORE)
642 {
643 ExplainPropertyText("ENR Name", rte->enrname, es);
644 ExplainPropertyFloat("ENR Tuples", NULL, rte->enrtuples, 0, es);
645 }
646
647 /*
648 * add_rte_to_flat_rtable will clear groupexprs and securityQuals, so
649 * skip that field. We have handled inFromCl above, so the only thing
650 * left to handle here is rte->lateral.
651 */
652 if (es->format != EXPLAIN_FORMAT_TEXT || rte->lateral)
653 ExplainPropertyBool("Lateral", rte->lateral, es);
654
655 /* Done with this RTE */
656 if (es->format == EXPLAIN_FORMAT_TEXT)
657 es->indent--;
658 ExplainCloseGroup("Range Table Entry", NULL, true, es);
659 }
660
661 /* Print PlannedStmt fields that contain RTIs. */
662 if (es->format != EXPLAIN_FORMAT_TEXT ||
663 !bms_is_empty(plannedstmt->unprunableRelids))
664 overexplain_bitmapset("Unprunable RTIs", plannedstmt->unprunableRelids,
665 es);
666 if (es->format != EXPLAIN_FORMAT_TEXT ||
667 plannedstmt->resultRelations != NIL)
668 overexplain_intlist("Result RTIs", plannedstmt->resultRelations, es);
669
670 /* Close group, we're all done */
671 ExplainCloseGroup("Range Table", "Range Table", false, es);
672}
673
674/*
675 * Emit a text property describing the contents of an Alias.
676 *
677 * Column lists can be quite long here, so perhaps we should have an option
678 * to limit the display length by # of columsn or # of characters, but for
679 * now, just display everything.
680 */
681static void
682overexplain_alias(const char *qlabel, Alias *alias, ExplainState *es)
683{
685 bool first = true;
686
687 Assert(alias != NULL);
688
691
692 foreach_node(String, cn, alias->colnames)
693 {
694 appendStringInfo(&buf, "%s%s",
695 first ? "" : ", ",
696 quote_identifier(cn->sval));
697 first = false;
698 }
699
701 ExplainPropertyText(qlabel, buf.data, es);
702 pfree(buf.data);
703}
704
705/*
706 * Emit a text property describing the contents of a bitmapset -- either a
707 * space-separated list of integer members, or the word "none" if the bitmapset
708 * is empty.
709 */
710static void
711overexplain_bitmapset(const char *qlabel, Bitmapset *bms, ExplainState *es)
712{
713 int x = -1;
714
716
717 if (bms_is_empty(bms))
718 {
719 ExplainPropertyText(qlabel, "none", es);
720 return;
721 }
722
724 while ((x = bms_next_member(bms, x)) >= 0)
725 appendStringInfo(&buf, " %d", x);
726 Assert(buf.data[0] == ' ');
727 ExplainPropertyText(qlabel, buf.data + 1, es);
728 pfree(buf.data);
729}
730
731/*
732 * Emit a text property describing the contents of a list of integers, OIDs,
733 * or XIDs -- either a space-separated list of integer members, or the word
734 * "none" if the list is empty.
735 */
736static void
737overexplain_intlist(const char *qlabel, List *list, ExplainState *es)
738{
740
742
743 if (list == NIL)
744 {
745 ExplainPropertyText(qlabel, "none", es);
746 return;
747 }
748
749 if (IsA(list, IntList))
750 {
752 appendStringInfo(&buf, " %d", i);
753 }
754 else if (IsA(list, OidList))
755 {
756 foreach_oid(o, list)
757 appendStringInfo(&buf, " %u", o);
758 }
759 else if (IsA(list, XidList))
760 {
762 appendStringInfo(&buf, " %u", x);
763 }
764 else
765 {
766 appendStringInfo(&buf, " not an integer list");
767 Assert(false);
768 }
769
770 if (buf.len > 0)
771 ExplainPropertyText(qlabel, buf.data + 1, es);
772
773 pfree(buf.data);
774}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
#define bms_is_empty(a)
Definition: bitmapset.h:118
unsigned int Index
Definition: c.h:585
bool defGetBoolean(DefElem *def)
Definition: define.c:94
explain_per_node_hook_type explain_per_node_hook
Definition: explain.c:57
explain_per_plan_hook_type explain_per_plan_hook
Definition: explain.c:56
void(* explain_per_plan_hook_type)(PlannedStmt *plannedstmt, IntoClause *into, struct ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: explain.h:32
void(* explain_per_node_hook_type)(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, struct ExplainState *es)
Definition: explain.h:41
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
void ExplainPropertyUInteger(const char *qlabel, const char *unit, uint64 value, ExplainState *es)
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, 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)
void ExplainPropertyBool(const char *qlabel, bool value, ExplainState *es)
int GetExplainExtensionId(const char *extension_name)
void * GetExplainExtensionState(ExplainState *es, int extension_id)
void SetExplainExtensionState(ExplainState *es, int extension_id, void *opaque)
void RegisterExtensionExplainOption(const char *option_name, ExplainOptionHandler handler)
@ EXPLAIN_FORMAT_TEXT
Definition: explain_state.h:29
Assert(PointerIsAligned(start, uint64))
int x
Definition: isn.c:75
int i
Definition: isn.c:77
const char * GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode)
Definition: lock.c:4220
#define DEFAULT_LOCKMETHOD
Definition: lock.h:126
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2011
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:2035
char * get_namespace_name_or_temp(Oid nspid)
Definition: lsyscache.c:3473
void pfree(void *pointer)
Definition: mcxt.c:1524
void * palloc0(Size size)
Definition: mcxt.c:1347
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define nodeTag(nodeptr)
Definition: nodes.h:139
@ CMD_MERGE
Definition: nodes.h:275
@ CMD_UTILITY
Definition: nodes.h:276
@ CMD_INSERT
Definition: nodes.h:273
@ CMD_DELETE
Definition: nodes.h:274
@ CMD_UNKNOWN
Definition: nodes.h:270
@ CMD_UPDATE
Definition: nodes.h:272
@ CMD_SELECT
Definition: nodes.h:271
@ CMD_NOTHING
Definition: nodes.h:278
@ JOIN_SEMI
Definition: nodes.h:313
@ JOIN_FULL
Definition: nodes.h:301
@ JOIN_INNER
Definition: nodes.h:299
@ JOIN_RIGHT
Definition: nodes.h:302
@ JOIN_RIGHT_SEMI
Definition: nodes.h:315
@ JOIN_LEFT
Definition: nodes.h:300
@ JOIN_RIGHT_ANTI
Definition: nodes.h:316
@ JOIN_ANTI
Definition: nodes.h:314
@ RTE_JOIN
Definition: parsenodes.h:1028
@ RTE_CTE
Definition: parsenodes.h:1032
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1033
@ RTE_VALUES
Definition: parsenodes.h:1031
@ RTE_SUBQUERY
Definition: parsenodes.h:1027
@ RTE_RESULT
Definition: parsenodes.h:1034
@ RTE_FUNCTION
Definition: parsenodes.h:1029
@ RTE_TABLEFUNC
Definition: parsenodes.h:1030
@ RTE_GROUP
Definition: parsenodes.h:1037
@ RTE_RELATION
Definition: parsenodes.h:1026
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
NameData relname
Definition: pg_class.h:38
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define foreach_xid(var, lst)
Definition: pg_list.h:472
#define foreach_node(type, var, lst)
Definition: pg_list.h:496
#define foreach_oid(var, lst)
Definition: pg_list.h:471
#define foreach_int(var, lst)
Definition: pg_list.h:470
static void overexplain_per_plan_hook(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
void _PG_init(void)
static void overexplain_bitmapset(const char *qlabel, Bitmapset *bms, ExplainState *es)
static void overexplain_range_table(PlannedStmt *plannedstmt, ExplainState *es)
static explain_per_plan_hook_type prev_explain_per_plan_hook
static explain_per_node_hook_type prev_explain_per_node_hook
static overexplain_options * overexplain_ensure_options(ExplainState *es)
static void overexplain_per_node_hook(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
PG_MODULE_MAGIC_EXT(.name="pg_overexplain",.version=PG_VERSION)
static void overexplain_debug_handler(ExplainState *es, DefElem *opt, ParseState *pstate)
static void overexplain_intlist(const char *qlabel, List *intlist, ExplainState *es)
static void overexplain_alias(const char *qlabel, Alias *alias, ExplainState *es)
static int es_extension_id
static void overexplain_debug(PlannedStmt *plannedstmt, ExplainState *es)
static void overexplain_range_table_handler(ExplainState *es, DefElem *opt, ParseState *pstate)
static char ** options
#define plan(x)
Definition: pg_regress.c:161
static char * buf
Definition: pg_test_fsync.c:72
unsigned int Oid
Definition: postgres_ext.h:30
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:13019
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:242
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
char * aliasname
Definition: primnodes.h:51
List * colnames
Definition: primnodes.h:52
StringInfo str
Definition: explain_state.h:46
ExplainFormat format
Definition: explain_state.h:59
Definition: pg_list.h:54
Plan * plan
Definition: execnodes.h:1159
bool hasModifyingCTE
Definition: plannodes.h:65
bool canSetTag
Definition: plannodes.h:68
Bitmapset * rewindPlanIDs
Definition: plannodes.h:124
ParseLoc stmt_len
Definition: plannodes.h:145
bool hasReturning
Definition: plannodes.h:62
ParseLoc stmt_location
Definition: plannodes.h:143
bool transientPlan
Definition: plannodes.h:71
List * resultRelations
Definition: plannodes.h:106
List * relationOids
Definition: plannodes.h:130
bool dependsOnRole
Definition: plannodes.h:74
Bitmapset * unprunableRelids
Definition: plannodes.h:97
CmdType commandType
Definition: plannodes.h:53
List * rtable
Definition: plannodes.h:91
List * paramExecTypes
Definition: plannodes.h:136
bool parallelModeNeeded
Definition: plannodes.h:77
char * ctename
Definition: parsenodes.h:1210
Index ctelevelsup
Definition: parsenodes.h:1212
bool funcordinality
Definition: parsenodes.h:1193
char * enrname
Definition: parsenodes.h:1245
JoinType jointype
Definition: parsenodes.h:1165
RTEKind rtekind
Definition: parsenodes.h:1061
Definition: value.h:64
const char * name