PostgreSQL Source Code: contrib/pg_overexplain/pg_overexplain.c Source File

PostgreSQL Source Code git master
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"
16#include "commands/explain_format.h"
17#include "commands/explain_state.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
24 PG_MODULE_MAGIC_EXT(
25 .name = "pg_overexplain",
26 .version = PG_VERSION
27);
28
29 typedef struct
30{
31 bool debug;
32 bool range_table;
33} overexplain_options;
34
35static overexplain_options *overexplain_ensure_options(ExplainState *es);
36static void overexplain_debug_handler(ExplainState *es, DefElem *opt,
37 ParseState *pstate);
38static void overexplain_range_table_handler(ExplainState *es, DefElem *opt,
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 *list,
58 ExplainState *es);
59
60 static int es_extension_id;
61 static explain_per_node_hook_type prev_explain_per_node_hook;
62 static explain_per_plan_hook_type prev_explain_per_plan_hook;
63
64/*
65 * Initialization we do when this module is loaded.
66 */
67void
68 _PG_init(void)
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. */
74 RegisterExtensionExplainOption("debug", overexplain_debug_handler);
75 RegisterExtensionExplainOption("range_table",
76 overexplain_range_table_handler);
77
78 /* Use the per-node and per-plan hooks to make our options do something. */
79 prev_explain_per_node_hook = explain_per_node_hook;
80 explain_per_node_hook = overexplain_per_node_hook;
81 prev_explain_per_plan_hook = explain_per_plan_hook;
82 explain_per_plan_hook = overexplain_per_plan_hook;
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 */
89static overexplain_options *
90 overexplain_ensure_options(ExplainState *es)
91{
92 overexplain_options *options;
93
94 options = GetExplainExtensionState(es, es_extension_id);
95
96 if (options == NULL)
97 {
98 options = palloc0(sizeof(overexplain_options));
99 SetExplainExtensionState(es, es_extension_id, options);
100 }
101
102 return options;
103}
104
105/*
106 * Parse handler for EXPLAIN (DEBUG).
107 */
108static void
109 overexplain_debug_handler(ExplainState *es, DefElem *opt, ParseState *pstate)
110{
111 overexplain_options *options = overexplain_ensure_options(es);
112
113 options->debug = defGetBoolean(opt);
114}
115
116/*
117 * Parse handler for EXPLAIN (RANGE_TABLE).
118 */
119static void
120 overexplain_range_table_handler(ExplainState *es, DefElem *opt,
121 ParseState *pstate)
122{
123 overexplain_options *options = overexplain_ensure_options(es);
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
134 overexplain_per_node_hook(PlanState *planstate, List *ancestors,
135 const char *relationship, const char *plan_name,
136 ExplainState *es)
137{
138 overexplain_options *options;
139 Plan *plan = planstate->plan;
140
141 if (prev_explain_per_node_hook)
142 (*prev_explain_per_node_hook) (planstate, ancestors, relationship,
143 plan_name, es);
144
145 options = GetExplainExtensionState(es, es_extension_id);
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 case T_Result:
240
241 /*
242 * 'relids' is only meaningful when plan->lefttree is NULL,
243 * but if somehow it ends up set when plan->lefttree is not
244 * NULL, print it anyway.
245 */
246 if (plan->lefttree == NULL ||
247 ((Result *) plan)->relids != NULL)
248 overexplain_bitmapset("RTIs",
249 ((Result *) plan)->relids,
250 es);
251 default:
252 break;
253 }
254 }
255}
256
257/*
258 * Print out additional per-query information as appropriate. Here again, if
259 * the user didn't specify any of the options implemented by this module, do
260 * nothing; otherwise, call the appropriate function for each specified
261 * option.
262 */
263static void
264 overexplain_per_plan_hook(PlannedStmt *plannedstmt,
265 IntoClause *into,
266 ExplainState *es,
267 const char *queryString,
268 ParamListInfo params,
269 QueryEnvironment *queryEnv)
270{
271 overexplain_options *options;
272
273 if (prev_explain_per_plan_hook)
274 (*prev_explain_per_plan_hook) (plannedstmt, into, es, queryString,
275 params, queryEnv);
276
277 options = GetExplainExtensionState(es, es_extension_id);
278 if (options == NULL)
279 return;
280
281 if (options->debug)
282 overexplain_debug(plannedstmt, es);
283
284 if (options->range_table)
285 overexplain_range_table(plannedstmt, es);
286}
287
288/*
289 * Print out various details from the PlannedStmt that wouldn't otherwise
290 * be displayed.
291 *
292 * We don't try to print everything here. Information that would be displayed
293 * anyway doesn't need to be printed again here, and things with lots of
294 * substructure probably should be printed via separate options, or not at all.
295 */
296static void
297 overexplain_debug(PlannedStmt *plannedstmt, ExplainState *es)
298{
299 char *commandType = NULL;
300 StringInfoData flags;
301
302 /* Even in text mode, we want to set this output apart as its own group. */
303 ExplainOpenGroup("PlannedStmt", "PlannedStmt", true, es);
304 if (es->format == EXPLAIN_FORMAT_TEXT)
305 {
306 ExplainIndentText(es);
307 appendStringInfoString(es->str, "PlannedStmt:\n");
308 es->indent++;
309 }
310
311 /* Print the command type. */
312 switch (plannedstmt->commandType)
313 {
314 case CMD_UNKNOWN:
315 commandType = "unknown";
316 break;
317 case CMD_SELECT:
318 commandType = "select";
319 break;
320 case CMD_UPDATE:
321 commandType = "update";
322 break;
323 case CMD_INSERT:
324 commandType = "insert";
325 break;
326 case CMD_DELETE:
327 commandType = "delete";
328 break;
329 case CMD_MERGE:
330 commandType = "merge";
331 break;
332 case CMD_UTILITY:
333 commandType = "utility";
334 break;
335 case CMD_NOTHING:
336 commandType = "nothing";
337 break;
338 }
339 ExplainPropertyText("Command Type", commandType, es);
340
341 /* Print various properties as a comma-separated list of flags. */
342 initStringInfo(&flags);
343 if (plannedstmt->hasReturning)
344 appendStringInfoString(&flags, ", hasReturning");
345 if (plannedstmt->hasModifyingCTE)
346 appendStringInfoString(&flags, ", hasModifyingCTE");
347 if (plannedstmt->canSetTag)
348 appendStringInfoString(&flags, ", canSetTag");
349 if (plannedstmt->transientPlan)
350 appendStringInfoString(&flags, ", transientPlan");
351 if (plannedstmt->dependsOnRole)
352 appendStringInfoString(&flags, ", dependsOnRole");
353 if (plannedstmt->parallelModeNeeded)
354 appendStringInfoString(&flags, ", parallelModeNeeded");
355 if (flags.len == 0)
356 appendStringInfoString(&flags, ", none");
357 ExplainPropertyText("Flags", flags.data + 2, es);
358
359 /* Various lists of integers. */
360 overexplain_bitmapset("Subplans Needing Rewind",
361 plannedstmt->rewindPlanIDs, es);
362 overexplain_intlist("Relation OIDs",
363 plannedstmt->relationOids, es);
364 overexplain_intlist("Executor Parameter Types",
365 plannedstmt->paramExecTypes, es);
366
367 /*
368 * Print the statement location. (If desired, we could alternatively print
369 * stmt_location and stmt_len as two separate fields.)
370 */
371 if (plannedstmt->stmt_location == -1)
372 ExplainPropertyText("Parse Location", "Unknown", es);
373 else if (plannedstmt->stmt_len == 0)
374 ExplainPropertyText("Parse Location",
375 psprintf("%d to end", plannedstmt->stmt_location),
376 es);
377 else
378 ExplainPropertyText("Parse Location",
379 psprintf("%d for %d bytes",
380 plannedstmt->stmt_location,
381 plannedstmt->stmt_len),
382 es);
383
384 /* Done with this group. */
385 if (es->format == EXPLAIN_FORMAT_TEXT)
386 es->indent--;
387 ExplainCloseGroup("PlannedStmt", "PlannedStmt", true, es);
388}
389
390/*
391 * Provide detailed information about the contents of the PlannedStmt's
392 * range table.
393 */
394static void
395 overexplain_range_table(PlannedStmt *plannedstmt, ExplainState *es)
396{
397 Index rti;
398
399 /* Open group, one entry per RangeTblEntry */
400 ExplainOpenGroup("Range Table", "Range Table", false, es);
401
402 /* Iterate over the range table */
403 for (rti = 1; rti <= list_length(plannedstmt->rtable); ++rti)
404 {
405 RangeTblEntry *rte = rt_fetch(rti, plannedstmt->rtable);
406 char *kind = NULL;
407 char *relkind;
408
409 /* NULL entries are possible; skip them */
410 if (rte == NULL)
411 continue;
412
413 /* Translate rtekind to a string */
414 switch (rte->rtekind)
415 {
416 case RTE_RELATION:
417 kind = "relation";
418 break;
419 case RTE_SUBQUERY:
420 kind = "subquery";
421 break;
422 case RTE_JOIN:
423 kind = "join";
424 break;
425 case RTE_FUNCTION:
426 kind = "function";
427 break;
428 case RTE_TABLEFUNC:
429 kind = "tablefunc";
430 break;
431 case RTE_VALUES:
432 kind = "values";
433 break;
434 case RTE_CTE:
435 kind = "cte";
436 break;
437 case RTE_NAMEDTUPLESTORE:
438 kind = "namedtuplestore";
439 break;
440 case RTE_RESULT:
441 kind = "result";
442 break;
443 case RTE_GROUP:
444 kind = "group";
445 break;
446 }
447
448 /* Begin group for this specific RTE */
449 ExplainOpenGroup("Range Table Entry", NULL, true, es);
450
451 /*
452 * In text format, the summary line displays the range table index and
453 * rtekind, plus indications if rte->inh and/or rte->inFromCl are set.
454 * In other formats, we display those as separate properties.
455 */
456 if (es->format == EXPLAIN_FORMAT_TEXT)
457 {
458 ExplainIndentText(es);
459 appendStringInfo(es->str, "RTI %u (%s%s%s):\n", rti, kind,
460 rte->inh ? ", inherited" : "",
461 rte->inFromCl ? ", in-from-clause" : "");
462 es->indent++;
463 }
464 else
465 {
466 ExplainPropertyUInteger("RTI", NULL, rti, es);
467 ExplainPropertyText("Kind", kind, es);
468 ExplainPropertyBool("Inherited", rte->inh, es);
469 ExplainPropertyBool("In From Clause", rte->inFromCl, es);
470 }
471
472 /* rte->alias is optional; rte->eref is requested */
473 if (rte->alias != NULL)
474 overexplain_alias("Alias", rte->alias, es);
475 overexplain_alias("Eref", rte->eref, es);
476
477 /*
478 * We adhere to the usual EXPLAIN convention that schema names are
479 * displayed only in verbose mode, and we emit nothing if there is no
480 * relation OID.
481 */
482 if (rte->relid != 0)
483 {
484 const char *relname;
485 const char *qualname;
486
487 relname = quote_identifier(get_rel_name(rte->relid));
488
489 if (es->verbose)
490 {
491 Oid nspoid = get_rel_namespace(rte->relid);
492 char *nspname;
493
494 nspname = get_namespace_name_or_temp(nspoid);
495 qualname = psprintf("%s.%s", quote_identifier(nspname),
496 relname);
497 }
498 else
499 qualname = relname;
500
501 ExplainPropertyText("Relation", qualname, es);
502 }
503
504 /* Translate relkind, if any, to a string */
505 switch (rte->relkind)
506 {
507 case RELKIND_RELATION:
508 relkind = "relation";
509 break;
510 case RELKIND_INDEX:
511 relkind = "index";
512 break;
513 case RELKIND_SEQUENCE:
514 relkind = "sequence";
515 break;
516 case RELKIND_TOASTVALUE:
517 relkind = "toastvalue";
518 break;
519 case RELKIND_VIEW:
520 relkind = "view";
521 break;
522 case RELKIND_MATVIEW:
523 relkind = "matview";
524 break;
525 case RELKIND_COMPOSITE_TYPE:
526 relkind = "composite_type";
527 break;
528 case RELKIND_FOREIGN_TABLE:
529 relkind = "foreign_table";
530 break;
531 case RELKIND_PARTITIONED_TABLE:
532 relkind = "partitioned_table";
533 break;
534 case RELKIND_PARTITIONED_INDEX:
535 relkind = "partitioned_index";
536 break;
537 case '0円':
538 relkind = NULL;
539 break;
540 default:
541 relkind = psprintf("%c", rte->relkind);
542 break;
543 }
544
545 /* If there is a relkind, show it */
546 if (relkind != NULL)
547 ExplainPropertyText("Relation Kind", relkind, es);
548
549 /* If there is a lock mode, show it */
550 if (rte->rellockmode != 0)
551 ExplainPropertyText("Relation Lock Mode",
552 GetLockmodeName(DEFAULT_LOCKMETHOD,
553 rte->rellockmode), es);
554
555 /*
556 * If there is a perminfoindex, show it. We don't try to display
557 * information from the RTEPermissionInfo node here because they are
558 * just indexes plannedstmt->permInfos which could be separately
559 * dumped if someone wants to add EXPLAIN (PERMISSIONS) or similar.
560 */
561 if (rte->perminfoindex != 0)
562 ExplainPropertyInteger("Permission Info Index", NULL,
563 rte->perminfoindex, es);
564
565 /*
566 * add_rte_to_flat_rtable will clear rte->tablesample and
567 * rte->subquery in the finished plan, so skip those fields.
568 *
569 * However, the security_barrier flag is not shown by the core code,
570 * so let's print it here.
571 */
572 if (es->format != EXPLAIN_FORMAT_TEXT || rte->security_barrier)
573 ExplainPropertyBool("Security Barrier", rte->security_barrier, es);
574
575 /*
576 * If this is a join, print out the fields that are specifically valid
577 * for joins.
578 */
579 if (rte->rtekind == RTE_JOIN)
580 {
581 char *jointype;
582
583 switch (rte->jointype)
584 {
585 case JOIN_INNER:
586 jointype = "Inner";
587 break;
588 case JOIN_LEFT:
589 jointype = "Left";
590 break;
591 case JOIN_FULL:
592 jointype = "Full";
593 break;
594 case JOIN_RIGHT:
595 jointype = "Right";
596 break;
597 case JOIN_SEMI:
598 jointype = "Semi";
599 break;
600 case JOIN_ANTI:
601 jointype = "Anti";
602 break;
603 case JOIN_RIGHT_SEMI:
604 jointype = "Right Semi";
605 break;
606 case JOIN_RIGHT_ANTI:
607 jointype = "Right Anti";
608 break;
609 default:
610 jointype = "???";
611 break;
612 }
613
614 /* Join type */
615 ExplainPropertyText("Join Type", jointype, es);
616
617 /* # of JOIN USING columns */
618 if (es->format != EXPLAIN_FORMAT_TEXT || rte->joinmergedcols != 0)
619 ExplainPropertyInteger("JOIN USING Columns", NULL,
620 rte->joinmergedcols, es);
621
622 /*
623 * add_rte_to_flat_rtable will clear joinaliasvars, joinleftcols,
624 * joinrightcols, and join_using_alias here, so skip those fields.
625 */
626 }
627
628 /*
629 * add_rte_to_flat_rtable will clear functions, tablefunc, and
630 * values_lists, but we can display funcordinality.
631 */
632 if (rte->rtekind == RTE_FUNCTION)
633 ExplainPropertyBool("WITH ORDINALITY", rte->funcordinality, es);
634
635 /*
636 * If this is a CTE, print out CTE-related properties.
637 */
638 if (rte->rtekind == RTE_CTE)
639 {
640 ExplainPropertyText("CTE Name", rte->ctename, es);
641 ExplainPropertyUInteger("CTE Levels Up", NULL, rte->ctelevelsup,
642 es);
643 ExplainPropertyBool("CTE Self-Reference", rte->self_reference, es);
644 }
645
646 /*
647 * add_rte_to_flat_rtable will clear coltypes, coltypmods, and
648 * colcollations, so skip those fields.
649 *
650 * If this is an ephemeral named relation, print out ENR-related
651 * properties.
652 */
653 if (rte->rtekind == RTE_NAMEDTUPLESTORE)
654 {
655 ExplainPropertyText("ENR Name", rte->enrname, es);
656 ExplainPropertyFloat("ENR Tuples", NULL, rte->enrtuples, 0, es);
657 }
658
659 /*
660 * add_rte_to_flat_rtable will clear groupexprs and securityQuals, so
661 * skip that field. We have handled inFromCl above, so the only thing
662 * left to handle here is rte->lateral.
663 */
664 if (es->format != EXPLAIN_FORMAT_TEXT || rte->lateral)
665 ExplainPropertyBool("Lateral", rte->lateral, es);
666
667 /* Done with this RTE */
668 if (es->format == EXPLAIN_FORMAT_TEXT)
669 es->indent--;
670 ExplainCloseGroup("Range Table Entry", NULL, true, es);
671 }
672
673 /* Print PlannedStmt fields that contain RTIs. */
674 if (es->format != EXPLAIN_FORMAT_TEXT ||
675 !bms_is_empty(plannedstmt->unprunableRelids))
676 overexplain_bitmapset("Unprunable RTIs", plannedstmt->unprunableRelids,
677 es);
678 if (es->format != EXPLAIN_FORMAT_TEXT ||
679 plannedstmt->resultRelations != NIL)
680 overexplain_intlist("Result RTIs", plannedstmt->resultRelations, es);
681
682 /* Close group, we're all done */
683 ExplainCloseGroup("Range Table", "Range Table", false, es);
684}
685
686/*
687 * Emit a text property describing the contents of an Alias.
688 *
689 * Column lists can be quite long here, so perhaps we should have an option
690 * to limit the display length by # of column or # of characters, but for
691 * now, just display everything.
692 */
693static void
694 overexplain_alias(const char *qlabel, Alias *alias, ExplainState *es)
695{
696 StringInfoData buf;
697 bool first = true;
698
699 Assert(alias != NULL);
700
701 initStringInfo(&buf);
702 appendStringInfo(&buf, "%s (", quote_identifier(alias->aliasname));
703
704 foreach_node(String, cn, alias->colnames)
705 {
706 appendStringInfo(&buf, "%s%s",
707 first ? "" : ", ",
708 quote_identifier(cn->sval));
709 first = false;
710 }
711
712 appendStringInfoChar(&buf, ')');
713 ExplainPropertyText(qlabel, buf.data, es);
714 pfree(buf.data);
715}
716
717/*
718 * Emit a text property describing the contents of a bitmapset -- either a
719 * space-separated list of integer members, or the word "none" if the bitmapset
720 * is empty.
721 */
722static void
723 overexplain_bitmapset(const char *qlabel, Bitmapset *bms, ExplainState *es)
724{
725 int x = -1;
726
727 StringInfoData buf;
728
729 if (bms_is_empty(bms))
730 {
731 ExplainPropertyText(qlabel, "none", es);
732 return;
733 }
734
735 initStringInfo(&buf);
736 while ((x = bms_next_member(bms, x)) >= 0)
737 appendStringInfo(&buf, " %d", x);
738 Assert(buf.data[0] == ' ');
739 ExplainPropertyText(qlabel, buf.data + 1, es);
740 pfree(buf.data);
741}
742
743/*
744 * Emit a text property describing the contents of a list of integers, OIDs,
745 * or XIDs -- either a space-separated list of integer members, or the word
746 * "none" if the list is empty.
747 */
748static void
749 overexplain_intlist(const char *qlabel, List *list, ExplainState *es)
750{
751 StringInfoData buf;
752
753 initStringInfo(&buf);
754
755 if (list == NIL)
756 {
757 ExplainPropertyText(qlabel, "none", es);
758 return;
759 }
760
761 if (IsA(list, IntList))
762 {
763 foreach_int(i, list)
764 appendStringInfo(&buf, " %d", i);
765 }
766 else if (IsA(list, OidList))
767 {
768 foreach_oid(o, list)
769 appendStringInfo(&buf, " %u", o);
770 }
771 else if (IsA(list, XidList))
772 {
773 foreach_xid(x, list)
774 appendStringInfo(&buf, " %u", x);
775 }
776 else
777 {
778 appendStringInfoString(&buf, " not an integer list");
779 Assert(false);
780 }
781
782 if (buf.len > 0)
783 ExplainPropertyText(qlabel, buf.data + 1, es);
784
785 pfree(buf.data);
786}
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:619
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, 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)
Definition: explain_state.c:220
void * GetExplainExtensionState(ExplainState *es, int extension_id)
Definition: explain_state.c:258
void SetExplainExtensionState(ExplainState *es, int extension_id, void *opaque)
Definition: explain_state.c:277
void RegisterExtensionExplainOption(const char *option_name, ExplainOptionHandler handler)
Definition: explain_state.c:317
@ EXPLAIN_FORMAT_TEXT
Definition: explain_state.h:29
Assert(PointerIsAligned(start, uint64))
x
int x
Definition: isn.c:75
i
int i
Definition: isn.c:77
const char * GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode)
Definition: lock.c:4255
#define DEFAULT_LOCKMETHOD
Definition: lock.h:127
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2095
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:2119
char * get_namespace_name_or_temp(Oid nspid)
Definition: lsyscache.c:3557
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc0(Size size)
Definition: mcxt.c:1395
#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
Definition: parsenodes.h:1045
@ RTE_CTE
Definition: parsenodes.h:1049
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1050
@ RTE_VALUES
Definition: parsenodes.h:1048
@ RTE_SUBQUERY
Definition: parsenodes.h:1044
@ RTE_RESULT
Definition: parsenodes.h:1051
@ RTE_FUNCTION
Definition: parsenodes.h:1046
@ RTE_TABLEFUNC
Definition: parsenodes.h:1047
@ RTE_GROUP
Definition: parsenodes.h:1054
@ RTE_RELATION
Definition: parsenodes.h:1043
#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)
Definition: pg_overexplain.c:68
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
Definition: pg_overexplain.c:62
static explain_per_node_hook_type prev_explain_per_node_hook
Definition: pg_overexplain.c:61
static overexplain_options * overexplain_ensure_options(ExplainState *es)
Definition: pg_overexplain.c:90
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)
PG_MODULE_MAGIC_EXT(.name="pg_overexplain",.version=PG_VERSION)
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
Definition: pg_overexplain.c:60
static void overexplain_debug(PlannedStmt *plannedstmt, ExplainState *es)
static void overexplain_range_table_handler(ExplainState *es, DefElem *opt, ParseState *pstate)
static char ** options
Definition: pg_recvlogical.c:59
#define plan(x)
Definition: pg_regress.c:161
static char * buf
Definition: pg_test_fsync.c:72
unsigned int Oid
Definition: postgres_ext.h:32
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:13058
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
Definition: primnodes.h:49
char * aliasname
Definition: primnodes.h:51
List * colnames
Definition: primnodes.h:52
Definition: plannodes.h:382
bool verbose
Definition: explain_state.h:48
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
Definition: plannodes.h:177
bool hasModifyingCTE
Definition: plannodes.h:83
bool canSetTag
Definition: plannodes.h:86
Bitmapset * rewindPlanIDs
Definition: plannodes.h:135
ParseLoc stmt_len
Definition: plannodes.h:156
bool hasReturning
Definition: plannodes.h:80
ParseLoc stmt_location
Definition: plannodes.h:154
bool transientPlan
Definition: plannodes.h:89
List * resultRelations
Definition: plannodes.h:124
List * relationOids
Definition: plannodes.h:141
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:147
bool parallelModeNeeded
Definition: plannodes.h:95
char * ctename
Definition: parsenodes.h:1227
Index ctelevelsup
Definition: parsenodes.h:1229
bool funcordinality
Definition: parsenodes.h:1210
char * enrname
Definition: parsenodes.h:1262
JoinType jointype
Definition: parsenodes.h:1182
RTEKind rtekind
Definition: parsenodes.h:1078
Definition: plannodes.h:287
Definition: plannodes.h:511
char * data
Definition: stringinfo.h:48
Definition: value.h:64
Definition: oid2name.c:30
const char * name

AltStyle によって変換されたページ (->オリジナル) /