PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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-2026, 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_bitmapset_list(const char *qlabel, List *bms_list,
58 ExplainState *es);
59static void overexplain_intlist(const char *qlabel, List *list,
60 ExplainState *es);
61
62static int es_extension_id;
65
66/*
67 * Initialization we do when this module is loaded.
68 */
69void
71{
72 /* Get an ID that we can use to cache data in an ExplainState. */
73 es_extension_id = GetExplainExtensionId("pg_overexplain");
74
75 /* Register the new EXPLAIN options implemented by this module. */
79
80 /* Use the per-node and per-plan hooks to make our options do something. */
85}
86
87/*
88 * Get the overexplain_options structure from an ExplainState; if there is
89 * none, create one, attach it to the ExplainState, and return it.
90 */
106
107/*
108 * Parse handler for EXPLAIN (DEBUG).
109 */
110static void
117
118/*
119 * Parse handler for EXPLAIN (RANGE_TABLE).
120 */
121static void
129
130/*
131 * Print out additional per-node information as appropriate. If the user didn't
132 * specify any of the options we support, do nothing; else, print whatever is
133 * relevant to the specified options.
134 */
135static void
137 const char *relationship, const char *plan_name,
138 ExplainState *es)
139{
141 Plan *plan = planstate->plan;
142
144 (*prev_explain_per_node_hook) (planstate, ancestors, relationship,
145 plan_name, es);
146
148 if (options == NULL)
149 return;
150
151 /*
152 * If the "debug" option was given, display miscellaneous fields from the
153 * "Plan" node that would not otherwise be displayed.
154 */
155 if (options->debug)
156 {
157 /*
158 * Normal EXPLAIN will display "Disabled: true" if the node is
159 * disabled; but that is based on noticing that plan->disabled_nodes
160 * is higher than the sum of its children; here, we display the raw
161 * value, for debugging purposes.
162 */
163 ExplainPropertyInteger("Disabled Nodes", NULL, plan->disabled_nodes,
164 es);
165
166 /*
167 * Normal EXPLAIN will display the parallel_aware flag; here, we show
168 * the parallel_safe flag as well.
169 */
170 ExplainPropertyBool("Parallel Safe", plan->parallel_safe, es);
171
172 /*
173 * The plan node ID isn't normally displayed, since it is only useful
174 * for debugging.
175 */
176 ExplainPropertyInteger("Plan Node ID", NULL, plan->plan_node_id, es);
177
178 /*
179 * It is difficult to explain what extParam and allParam mean in plain
180 * language, so we simply display these fields labelled with the
181 * structure member name. For compactness, the text format omits the
182 * display of this information when the bitmapset is empty.
183 */
184 if (es->format != EXPLAIN_FORMAT_TEXT || !bms_is_empty(plan->extParam))
185 overexplain_bitmapset("extParam", plan->extParam, es);
186 if (es->format != EXPLAIN_FORMAT_TEXT || !bms_is_empty(plan->allParam))
187 overexplain_bitmapset("allParam", plan->allParam, es);
188 }
189
190 /*
191 * If the "range_table" option was specified, display information about
192 * the range table indexes for this node.
193 */
194 if (options->range_table)
195 {
196 bool opened_elided_nodes = false;
197
198 switch (nodeTag(plan))
199 {
200 case T_SeqScan:
201 case T_SampleScan:
202 case T_IndexScan:
203 case T_IndexOnlyScan:
204 case T_BitmapHeapScan:
205 case T_TidScan:
206 case T_TidRangeScan:
207 case T_SubqueryScan:
208 case T_FunctionScan:
209 case T_TableFuncScan:
210 case T_ValuesScan:
211 case T_CteScan:
213 case T_WorkTableScan:
214 ExplainPropertyInteger("Scan RTI", NULL,
215 ((Scan *) plan)->scanrelid, es);
216 break;
217 case T_ForeignScan:
218 overexplain_bitmapset("Scan RTIs",
219 ((ForeignScan *) plan)->fs_base_relids,
220 es);
221 break;
222 case T_CustomScan:
223 overexplain_bitmapset("Scan RTIs",
224 ((CustomScan *) plan)->custom_relids,
225 es);
226 break;
227 case T_ModifyTable:
228 ExplainPropertyInteger("Nominal RTI", NULL,
229 ((ModifyTable *) plan)->nominalRelation, es);
230 ExplainPropertyInteger("Exclude Relation RTI", NULL,
231 ((ModifyTable *) plan)->exclRelRTI, es);
232 break;
233 case T_Append:
234 overexplain_bitmapset("Append RTIs",
235 ((Append *) plan)->apprelids,
236 es);
237 overexplain_bitmapset_list("Child Append RTIs",
238 ((Append *) plan)->child_append_relid_sets,
239 es);
240 break;
241 case T_MergeAppend:
242 overexplain_bitmapset("Append RTIs",
243 ((MergeAppend *) plan)->apprelids,
244 es);
245 overexplain_bitmapset_list("Child Append RTIs",
246 ((MergeAppend *) plan)->child_append_relid_sets,
247 es);
248 break;
249 case T_Result:
250
251 /*
252 * 'relids' is only meaningful when plan->lefttree is NULL,
253 * but if somehow it ends up set when plan->lefttree is not
254 * NULL, print it anyway.
255 */
256 if (plan->lefttree == NULL ||
257 ((Result *) plan)->relids != NULL)
259 ((Result *) plan)->relids,
260 es);
261 default:
262 break;
263 }
264
266 {
267 char *elidednodetag;
268
269 if (n->plan_node_id != plan->plan_node_id)
270 continue;
271
273 {
274 ExplainOpenGroup("Elided Nodes", "Elided Nodes", false, es);
275 opened_elided_nodes = true;
276 }
277
278 switch (n->elided_type)
279 {
280 case T_Append:
281 elidednodetag = "Append";
282 break;
283 case T_MergeAppend:
284 elidednodetag = "MergeAppend";
285 break;
286 case T_SubqueryScan:
287 elidednodetag = "SubqueryScan";
288 break;
289 default:
290 elidednodetag = psprintf("%d", n->elided_type);
291 break;
292 }
293
294 ExplainOpenGroup("Elided Node", NULL, true, es);
295 ExplainPropertyText("Elided Node Type", elidednodetag, es);
296 overexplain_bitmapset("Elided Node RTIs", n->relids, es);
297 ExplainCloseGroup("Elided Node", NULL, true, es);
298 }
300 ExplainCloseGroup("Elided Nodes", "Elided Nodes", false, es);
301 }
302}
303
304/*
305 * Print out additional per-query information as appropriate. Here again, if
306 * the user didn't specify any of the options implemented by this module, do
307 * nothing; otherwise, call the appropriate function for each specified
308 * option.
309 */
310static void
312 IntoClause *into,
313 ExplainState *es,
314 const char *queryString,
315 ParamListInfo params,
316 QueryEnvironment *queryEnv)
317{
319
321 (*prev_explain_per_plan_hook) (plannedstmt, into, es, queryString,
322 params, queryEnv);
323
325 if (options == NULL)
326 return;
327
328 if (options->debug)
329 overexplain_debug(plannedstmt, es);
330
331 if (options->range_table)
332 overexplain_range_table(plannedstmt, es);
333}
334
335/*
336 * Print out various details from the PlannedStmt that wouldn't otherwise
337 * be displayed.
338 *
339 * We don't try to print everything here. Information that would be displayed
340 * anyway doesn't need to be printed again here, and things with lots of
341 * substructure probably should be printed via separate options, or not at all.
342 */
343static void
345{
346 char *commandType = NULL;
347 StringInfoData flags;
348
349 /* Even in text mode, we want to set this output apart as its own group. */
350 ExplainOpenGroup("PlannedStmt", "PlannedStmt", true, es);
351 if (es->format == EXPLAIN_FORMAT_TEXT)
352 {
354 appendStringInfoString(es->str, "PlannedStmt:\n");
355 es->indent++;
356 }
357
358 /* Print the command type. */
359 switch (plannedstmt->commandType)
360 {
361 case CMD_UNKNOWN:
362 commandType = "unknown";
363 break;
364 case CMD_SELECT:
365 commandType = "select";
366 break;
367 case CMD_UPDATE:
368 commandType = "update";
369 break;
370 case CMD_INSERT:
371 commandType = "insert";
372 break;
373 case CMD_DELETE:
374 commandType = "delete";
375 break;
376 case CMD_MERGE:
377 commandType = "merge";
378 break;
379 case CMD_UTILITY:
380 commandType = "utility";
381 break;
382 case CMD_NOTHING:
383 commandType = "nothing";
384 break;
385 }
386 ExplainPropertyText("Command Type", commandType, es);
387
388 /* Print various properties as a comma-separated list of flags. */
389 initStringInfo(&flags);
390 if (plannedstmt->hasReturning)
391 appendStringInfoString(&flags, ", hasReturning");
392 if (plannedstmt->hasModifyingCTE)
393 appendStringInfoString(&flags, ", hasModifyingCTE");
394 if (plannedstmt->canSetTag)
395 appendStringInfoString(&flags, ", canSetTag");
396 if (plannedstmt->transientPlan)
397 appendStringInfoString(&flags, ", transientPlan");
398 if (plannedstmt->dependsOnRole)
399 appendStringInfoString(&flags, ", dependsOnRole");
400 if (plannedstmt->parallelModeNeeded)
401 appendStringInfoString(&flags, ", parallelModeNeeded");
402 if (flags.len == 0)
403 appendStringInfoString(&flags, ", none");
404 ExplainPropertyText("Flags", flags.data + 2, es);
405
406 /* Various lists of integers. */
407 overexplain_bitmapset("Subplans Needing Rewind",
408 plannedstmt->rewindPlanIDs, es);
409 overexplain_intlist("Relation OIDs",
410 plannedstmt->relationOids, es);
411 overexplain_intlist("Executor Parameter Types",
412 plannedstmt->paramExecTypes, es);
413
414 /*
415 * Print the statement location. (If desired, we could alternatively print
416 * stmt_location and stmt_len as two separate fields.)
417 */
418 if (plannedstmt->stmt_location == -1)
419 ExplainPropertyText("Parse Location", "Unknown", es);
420 else if (plannedstmt->stmt_len == 0)
421 ExplainPropertyText("Parse Location",
422 psprintf("%d to end", plannedstmt->stmt_location),
423 es);
424 else
425 ExplainPropertyText("Parse Location",
426 psprintf("%d for %d bytes",
427 plannedstmt->stmt_location,
428 plannedstmt->stmt_len),
429 es);
430
431 /* Done with this group. */
432 if (es->format == EXPLAIN_FORMAT_TEXT)
433 es->indent--;
434 ExplainCloseGroup("PlannedStmt", "PlannedStmt", true, es);
435}
436
437/*
438 * Provide detailed information about the contents of the PlannedStmt's
439 * range table.
440 */
441static void
443{
444 Index rti;
445 ListCell *lc_subrtinfo = list_head(plannedstmt->subrtinfos);
447
448 /* Open group, one entry per RangeTblEntry */
449 ExplainOpenGroup("Range Table", "Range Table", false, es);
450
451 /* Iterate over the range table */
452 for (rti = 1; rti <= list_length(plannedstmt->rtable); ++rti)
453 {
454 RangeTblEntry *rte = rt_fetch(rti, plannedstmt->rtable);
455 char *kind = NULL;
456 char *relkind;
458
459 /* Advance to next SubRTInfo, if it's time. */
460 if (lc_subrtinfo != NULL)
461 {
463 if (rti > next_rtinfo->rtoffset)
464 {
466 lc_subrtinfo = lnext(plannedstmt->subrtinfos, lc_subrtinfo);
467 }
468 }
469
470 /* NULL entries are possible; skip them */
471 if (rte == NULL)
472 continue;
473
474 /* Translate rtekind to a string */
475 switch (rte->rtekind)
476 {
477 case RTE_RELATION:
478 kind = "relation";
479 break;
480 case RTE_SUBQUERY:
481 kind = "subquery";
482 break;
483 case RTE_JOIN:
484 kind = "join";
485 break;
486 case RTE_FUNCTION:
487 kind = "function";
488 break;
489 case RTE_TABLEFUNC:
490 kind = "tablefunc";
491 break;
492 case RTE_VALUES:
493 kind = "values";
494 break;
495 case RTE_CTE:
496 kind = "cte";
497 break;
499 kind = "namedtuplestore";
500 break;
501 case RTE_RESULT:
502 kind = "result";
503 break;
504 case RTE_GROUP:
505 kind = "group";
506 break;
507 }
508
509 /* Begin group for this specific RTE */
510 ExplainOpenGroup("Range Table Entry", NULL, true, es);
511
512 /*
513 * In text format, the summary line displays the range table index and
514 * rtekind, plus indications if rte->inh and/or rte->inFromCl are set.
515 * In other formats, we display those as separate properties.
516 */
517 if (es->format == EXPLAIN_FORMAT_TEXT)
518 {
520 appendStringInfo(es->str, "RTI %u (%s%s%s):\n", rti, kind,
521 rte->inh ? ", inherited" : "",
522 rte->inFromCl ? ", in-from-clause" : "");
523 es->indent++;
524 }
525 else
526 {
527 ExplainPropertyUInteger("RTI", NULL, rti, es);
528 ExplainPropertyText("Kind", kind, es);
529 ExplainPropertyBool("Inherited", rte->inh, es);
530 ExplainPropertyBool("In From Clause", rte->inFromCl, es);
531 }
532
533 /*
534 * Indicate which subplan is the origin of which RTE. Note dummy
535 * subplans. Here again, we crunch more onto one line in text format.
536 */
537 if (rtinfo != NULL)
538 {
539 if (es->format == EXPLAIN_FORMAT_TEXT)
540 {
541 if (!rtinfo->dummy)
542 ExplainPropertyText("Subplan", rtinfo->plan_name, es);
543 else
544 ExplainPropertyText("Subplan",
545 psprintf("%s (dummy)",
546 rtinfo->plan_name), es);
547 }
548 else
549 {
550 ExplainPropertyText("Subplan", rtinfo->plan_name, es);
551 ExplainPropertyBool("Subplan Is Dummy", rtinfo->dummy, es);
552 }
553 }
554
555 /* rte->alias is optional; rte->eref is requested */
556 if (rte->alias != NULL)
557 overexplain_alias("Alias", rte->alias, es);
558 overexplain_alias("Eref", rte->eref, es);
559
560 /*
561 * We adhere to the usual EXPLAIN convention that schema names are
562 * displayed only in verbose mode, and we emit nothing if there is no
563 * relation OID.
564 */
565 if (rte->relid != 0)
566 {
567 const char *relname;
568 const char *qualname;
569
571
572 if (es->verbose)
573 {
575 char *nspname;
576
578 qualname = psprintf("%s.%s", quote_identifier(nspname),
579 relname);
580 }
581 else
583
584 ExplainPropertyText("Relation", qualname, es);
585 }
586
587 /* Translate relkind, if any, to a string */
588 switch (rte->relkind)
589 {
590 case RELKIND_RELATION:
591 relkind = "relation";
592 break;
593 case RELKIND_INDEX:
594 relkind = "index";
595 break;
596 case RELKIND_SEQUENCE:
597 relkind = "sequence";
598 break;
600 relkind = "toastvalue";
601 break;
602 case RELKIND_VIEW:
603 relkind = "view";
604 break;
605 case RELKIND_MATVIEW:
606 relkind = "matview";
607 break;
609 relkind = "composite_type";
610 break;
612 relkind = "foreign_table";
613 break;
615 relkind = "partitioned_table";
616 break;
618 relkind = "partitioned_index";
619 break;
620 case '\0':
621 relkind = NULL;
622 break;
623 default:
624 relkind = psprintf("%c", rte->relkind);
625 break;
626 }
627
628 /* If there is a relkind, show it */
629 if (relkind != NULL)
630 ExplainPropertyText("Relation Kind", relkind, es);
631
632 /* If there is a lock mode, show it */
633 if (rte->rellockmode != 0)
634 ExplainPropertyText("Relation Lock Mode",
636 rte->rellockmode), es);
637
638 /*
639 * If there is a perminfoindex, show it. We don't try to display
640 * information from the RTEPermissionInfo node here because they are
641 * just indexes plannedstmt->permInfos which could be separately
642 * dumped if someone wants to add EXPLAIN (PERMISSIONS) or similar.
643 */
644 if (rte->perminfoindex != 0)
645 ExplainPropertyInteger("Permission Info Index", NULL,
646 rte->perminfoindex, es);
647
648 /*
649 * add_rte_to_flat_rtable will clear rte->tablesample and
650 * rte->subquery in the finished plan, so skip those fields.
651 *
652 * However, the security_barrier flag is not shown by the core code,
653 * so let's print it here.
654 */
655 if (es->format != EXPLAIN_FORMAT_TEXT || rte->security_barrier)
656 ExplainPropertyBool("Security Barrier", rte->security_barrier, es);
657
658 /*
659 * If this is a join, print out the fields that are specifically valid
660 * for joins.
661 */
662 if (rte->rtekind == RTE_JOIN)
663 {
664 char *jointype;
665
666 switch (rte->jointype)
667 {
668 case JOIN_INNER:
669 jointype = "Inner";
670 break;
671 case JOIN_LEFT:
672 jointype = "Left";
673 break;
674 case JOIN_FULL:
675 jointype = "Full";
676 break;
677 case JOIN_RIGHT:
678 jointype = "Right";
679 break;
680 case JOIN_SEMI:
681 jointype = "Semi";
682 break;
683 case JOIN_ANTI:
684 jointype = "Anti";
685 break;
686 case JOIN_RIGHT_SEMI:
687 jointype = "Right Semi";
688 break;
689 case JOIN_RIGHT_ANTI:
690 jointype = "Right Anti";
691 break;
692 default:
693 jointype = "???";
694 break;
695 }
696
697 /* Join type */
698 ExplainPropertyText("Join Type", jointype, es);
699
700 /* # of JOIN USING columns */
701 if (es->format != EXPLAIN_FORMAT_TEXT || rte->joinmergedcols != 0)
702 ExplainPropertyInteger("JOIN USING Columns", NULL,
703 rte->joinmergedcols, es);
704
705 /*
706 * add_rte_to_flat_rtable will clear joinaliasvars, joinleftcols,
707 * joinrightcols, and join_using_alias here, so skip those fields.
708 */
709 }
710
711 /*
712 * add_rte_to_flat_rtable will clear functions, tablefunc, and
713 * values_lists, but we can display funcordinality.
714 */
715 if (rte->rtekind == RTE_FUNCTION)
716 ExplainPropertyBool("WITH ORDINALITY", rte->funcordinality, es);
717
718 /*
719 * If this is a CTE, print out CTE-related properties.
720 */
721 if (rte->rtekind == RTE_CTE)
722 {
723 ExplainPropertyText("CTE Name", rte->ctename, es);
724 ExplainPropertyUInteger("CTE Levels Up", NULL, rte->ctelevelsup,
725 es);
726 ExplainPropertyBool("CTE Self-Reference", rte->self_reference, es);
727 }
728
729 /*
730 * add_rte_to_flat_rtable will clear coltypes, coltypmods, and
731 * colcollations, so skip those fields.
732 *
733 * If this is an ephemeral named relation, print out ENR-related
734 * properties.
735 */
736 if (rte->rtekind == RTE_NAMEDTUPLESTORE)
737 {
738 ExplainPropertyText("ENR Name", rte->enrname, es);
739 ExplainPropertyFloat("ENR Tuples", NULL, rte->enrtuples, 0, es);
740 }
741
742 /*
743 * add_rte_to_flat_rtable will clear groupexprs and securityQuals, so
744 * skip that field. We have handled inFromCl above, so the only thing
745 * left to handle here is rte->lateral.
746 */
747 if (es->format != EXPLAIN_FORMAT_TEXT || rte->lateral)
748 ExplainPropertyBool("Lateral", rte->lateral, es);
749
750 /* Done with this RTE */
751 if (es->format == EXPLAIN_FORMAT_TEXT)
752 es->indent--;
753 ExplainCloseGroup("Range Table Entry", NULL, true, es);
754 }
755
756 /* Print PlannedStmt fields that contain RTIs. */
757 if (es->format != EXPLAIN_FORMAT_TEXT ||
758 !bms_is_empty(plannedstmt->unprunableRelids))
759 overexplain_bitmapset("Unprunable RTIs", plannedstmt->unprunableRelids,
760 es);
761 if (es->format != EXPLAIN_FORMAT_TEXT ||
762 plannedstmt->resultRelations != NIL)
763 overexplain_intlist("Result RTIs", plannedstmt->resultRelations, es);
764
765 /* Close group, we're all done */
766 ExplainCloseGroup("Range Table", "Range Table", false, es);
767}
768
769/*
770 * Emit a text property describing the contents of an Alias.
771 *
772 * Column lists can be quite long here, so perhaps we should have an option
773 * to limit the display length by # of column or # of characters, but for
774 * now, just display everything.
775 */
776static void
778{
780 bool first = true;
781
782 Assert(alias != NULL);
783
786
788 {
789 appendStringInfo(&buf, "%s%s",
790 first ? "" : ", ",
791 quote_identifier(cn->sval));
792 first = false;
793 }
794
796 ExplainPropertyText(qlabel, buf.data, es);
797 pfree(buf.data);
798}
799
800/*
801 * Emit a text property describing the contents of a bitmapset -- either a
802 * space-separated list of integer members, or the word "none" if the bitmapset
803 * is empty.
804 */
805static void
807{
808 int x = -1;
809
811
812 if (bms_is_empty(bms))
813 {
814 ExplainPropertyText(qlabel, "none", es);
815 return;
816 }
817
819 while ((x = bms_next_member(bms, x)) >= 0)
820 appendStringInfo(&buf, " %d", x);
821 Assert(buf.data[0] == ' ');
822 ExplainPropertyText(qlabel, buf.data + 1, es);
823 pfree(buf.data);
824}
825
826/*
827 * Emit a text property describing the contents of a list of bitmapsets.
828 * If a bitmapset contains exactly 1 member, we just print an integer;
829 * otherwise, we surround the list of members by parentheses.
830 *
831 * If there are no bitmapsets in the list, we print the word "none".
832 */
833static void
835 ExplainState *es)
836{
838
840
842 {
845 else
846 {
847 int x = -1;
848 bool first = true;
849
851 while ((x = bms_next_member(bms, x)) >= 0)
852 {
853 if (first)
854 first = false;
855 else
857 appendStringInfo(&buf, "%d", x);
858 }
860 }
861 }
862
863 if (buf.len == 0)
864 {
865 ExplainPropertyText(qlabel, "none", es);
866 return;
867 }
868
869 Assert(buf.data[0] == ' ');
870 ExplainPropertyText(qlabel, buf.data + 1, es);
871 pfree(buf.data);
872}
873
874/*
875 * Emit a text property describing the contents of a list of integers, OIDs,
876 * or XIDs -- either a space-separated list of integer members, or the word
877 * "none" if the list is empty.
878 */
879static void
881{
883
885
886 if (list == NIL)
887 {
888 ExplainPropertyText(qlabel, "none", es);
889 return;
890 }
891
892 if (IsA(list, IntList))
893 {
894 foreach_int(i, list)
895 appendStringInfo(&buf, " %d", i);
896 }
897 else if (IsA(list, OidList))
898 {
899 foreach_oid(o, list)
900 appendStringInfo(&buf, " %u", o);
901 }
902 else if (IsA(list, XidList))
903 {
904 foreach_xid(x, list)
905 appendStringInfo(&buf, " %u", x);
906 }
907 else
908 {
909 appendStringInfoString(&buf, " not an integer list");
910 Assert(false);
911 }
912
913 if (buf.len > 0)
914 ExplainPropertyText(qlabel, buf.data + 1, es);
915
916 pfree(buf.data);
917}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1305
int bms_singleton_member(const Bitmapset *a)
Definition bitmapset.c:671
BMS_Membership bms_membership(const Bitmapset *a)
Definition bitmapset.c:780
#define bms_is_empty(a)
Definition bitmapset.h:118
@ BMS_SINGLETON
Definition bitmapset.h:72
#define Assert(condition)
Definition c.h:873
unsigned int Index
Definition c.h:628
bool defGetBoolean(DefElem *def)
Definition define.c:93
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, 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, 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
#define palloc0_object(type)
Definition fe_memutils.h:75
#define PG_MODULE_MAGIC_EXT(...)
Definition fmgr.h:540
int x
Definition isn.c:75
int i
Definition isn.c:77
const char * GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode)
Definition lock.c:4252
#define DEFAULT_LOCKMETHOD
Definition lock.h:127
char * get_rel_name(Oid relid)
Definition lsyscache.c:2078
Oid get_rel_namespace(Oid relid)
Definition lsyscache.c:2102
char * get_namespace_name_or_temp(Oid nspid)
Definition lsyscache.c:3540
void pfree(void *pointer)
Definition mcxt.c:1616
#define IsA(nodeptr, _type_)
Definition nodes.h:164
#define nodeTag(nodeptr)
Definition nodes.h:139
@ CMD_MERGE
Definition nodes.h:279
@ CMD_UTILITY
Definition nodes.h:280
@ CMD_INSERT
Definition nodes.h:277
@ CMD_DELETE
Definition nodes.h:278
@ CMD_UNKNOWN
Definition nodes.h:274
@ CMD_UPDATE
Definition nodes.h:276
@ CMD_SELECT
Definition nodes.h:275
@ CMD_NOTHING
Definition nodes.h:282
@ JOIN_SEMI
Definition nodes.h:317
@ JOIN_FULL
Definition nodes.h:305
@ JOIN_INNER
Definition nodes.h:303
@ JOIN_RIGHT
Definition nodes.h:306
@ JOIN_RIGHT_SEMI
Definition nodes.h:319
@ JOIN_LEFT
Definition nodes.h:304
@ JOIN_RIGHT_ANTI
Definition nodes.h:320
@ JOIN_ANTI
Definition nodes.h:318
@ RTE_JOIN
@ RTE_CTE
@ RTE_NAMEDTUPLESTORE
@ RTE_VALUES
@ RTE_SUBQUERY
@ RTE_RESULT
@ RTE_FUNCTION
@ RTE_TABLEFUNC
@ RTE_GROUP
@ RTE_RELATION
#define rt_fetch(rangetable_index, rangetable)
Definition parsetree.h:31
NameData relname
Definition pg_class.h:38
#define lfirst(lc)
Definition pg_list.h:172
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
static ListCell * list_head(const List *l)
Definition pg_list.h:128
#define foreach_oid(var, lst)
Definition pg_list.h:471
static ListCell * lnext(const List *l, const ListCell *c)
Definition pg_list.h:343
#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_bitmapset_list(const char *qlabel, List *bms_list, ExplainState *es)
static void overexplain_per_node_hook(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
static void overexplain_intlist(const char *qlabel, List *list, ExplainState *es)
static void overexplain_debug_handler(ExplainState *es, DefElem *opt, ParseState *pstate)
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)
#define plan(x)
Definition pg_regress.c:161
static char buf[DEFAULT_XLOG_SEG_SIZE]
unsigned int Oid
static int fb(int x)
char * psprintf(const char *fmt,...)
Definition psprintf.c:43
const char * quote_identifier(const char *ident)
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition stringinfo.c:145
void appendStringInfoString(StringInfo str, const char *s)
Definition stringinfo.c:230
void appendStringInfoChar(StringInfo str, char ch)
Definition stringinfo.c:242
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
char * aliasname
Definition primnodes.h:52
List * colnames
Definition primnodes.h:53
StringInfo str
ExplainFormat format
PlannedStmt * pstmt
Definition pg_list.h:54
Plan * plan
Definition execnodes.h:1168
bool hasModifyingCTE
Definition plannodes.h:83
List * elidedNodes
Definition plannodes.h:156
bool canSetTag
Definition plannodes.h:86
Bitmapset * rewindPlanIDs
Definition plannodes.h:138
ParseLoc stmt_len
Definition plannodes.h:171
bool hasReturning
Definition plannodes.h:80
ParseLoc stmt_location
Definition plannodes.h:169
bool transientPlan
Definition plannodes.h:89
List * resultRelations
Definition plannodes.h:124
List * relationOids
Definition plannodes.h:144
List * subrtinfos
Definition plannodes.h:135
bool dependsOnRole
Definition plannodes.h:92
Bitmapset * unprunableRelids
Definition plannodes.h:115
CmdType commandType
Definition plannodes.h:68
List * rtable
Definition plannodes.h:109
List * paramExecTypes
Definition plannodes.h:150
bool parallelModeNeeded
Definition plannodes.h:95
Definition value.h:64
const char * name