PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pg_overexplain.c File Reference
#include "postgres.h"
#include "catalog/pg_class.h"
#include "commands/defrem.h"
#include "commands/explain.h"
#include "commands/explain_format.h"
#include "commands/explain_state.h"
#include "fmgr.h"
#include "parser/parsetree.h"
#include "storage/lock.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
Include dependency graph for pg_overexplain.c:

Go to the source code of this file.

Data Structures

struct  overexplain_options
 

Functions

 PG_MODULE_MAGIC_EXT (.name="pg_overexplain",.version=PG_VERSION)
 
static overexplain_optionsoverexplain_ensure_options (ExplainState *es)
 
static void overexplain_debug_handler (ExplainState *es, DefElem *opt, ParseState *pstate)
 
static void overexplain_range_table_handler (ExplainState *es, DefElem *opt, ParseState *pstate)
 
static void overexplain_per_node_hook (PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
 
static void overexplain_per_plan_hook (PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
 
static void overexplain_debug (PlannedStmt *plannedstmt, ExplainState *es)
 
static void overexplain_range_table (PlannedStmt *plannedstmt, ExplainState *es)
 
static void overexplain_alias (const char *qlabel, Alias *alias, ExplainState *es)
 
static void overexplain_bitmapset (const char *qlabel, Bitmapset *bms, ExplainState *es)
 
static void overexplain_bitmapset_list (const char *qlabel, List *bms_list, ExplainState *es)
 
static void overexplain_intlist (const char *qlabel, List *list, ExplainState *es)
 
void _PG_init (void)
 

Variables

static int es_extension_id
 
static explain_per_node_hook_type prev_explain_per_node_hook
 
static explain_per_plan_hook_type prev_explain_per_plan_hook
 

Function Documentation

◆ _PG_init()

void _PG_init ( void  )

Definition at line 70 of file pg_overexplain.c.

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}
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
int GetExplainExtensionId(const char *extension_name)
void RegisterExtensionExplainOption(const char *option_name, ExplainOptionHandler handler)
static void overexplain_per_plan_hook(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
static explain_per_plan_hook_type prev_explain_per_plan_hook
static explain_per_node_hook_type prev_explain_per_node_hook
static void overexplain_per_node_hook(PlanState *planstate, List *ancestors, const char *relationship, const char *plan_name, ExplainState *es)
static void overexplain_debug_handler(ExplainState *es, DefElem *opt, ParseState *pstate)
static int es_extension_id
static void overexplain_range_table_handler(ExplainState *es, DefElem *opt, ParseState *pstate)

References es_extension_id, explain_per_node_hook, explain_per_plan_hook, GetExplainExtensionId(), overexplain_debug_handler(), overexplain_per_node_hook(), overexplain_per_plan_hook(), overexplain_range_table_handler(), prev_explain_per_node_hook, prev_explain_per_plan_hook, and RegisterExtensionExplainOption().

◆ overexplain_alias()

static void overexplain_alias ( const char qlabel,
Alias alias,
ExplainState es 
)
static

Definition at line 778 of file pg_overexplain.c.

779{
781 bool first = true;
782
783 Assert(alias != NULL);
784
787
789 {
790 appendStringInfo(&buf, "%s%s",
791 first ? "" : ", ",
792 quote_identifier(cn->sval));
793 first = false;
794 }
795
797 ExplainPropertyText(qlabel, buf.data, es);
798 pfree(buf.data);
799}
#define Assert(condition)
Definition c.h:885
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
void pfree(void *pointer)
Definition mcxt.c:1616
#define foreach_node(type, var, lst)
Definition pg_list.h:496
static char buf[DEFAULT_XLOG_SEG_SIZE]
static int fb(int x)
const char * quote_identifier(const char *ident)
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:52
List * colnames
Definition primnodes.h:53
Definition value.h:64

References Alias::aliasname, appendStringInfo(), appendStringInfoChar(), Assert, buf, Alias::colnames, ExplainPropertyText(), fb(), foreach_node, initStringInfo(), pfree(), and quote_identifier().

Referenced by overexplain_range_table().

◆ overexplain_bitmapset()

static void overexplain_bitmapset ( const char qlabel,
Bitmapset bms,
ExplainState es 
)
static

Definition at line 807 of file pg_overexplain.c.

808{
809 int x = -1;
810
812
813 if (bms_is_empty(bms))
814 {
815 ExplainPropertyText(qlabel, "none", es);
816 return;
817 }
818
820 while ((x = bms_next_member(bms, x)) >= 0)
821 appendStringInfo(&buf, " %d", x);
822 Assert(buf.data[0] == ' ');
823 ExplainPropertyText(qlabel, buf.data + 1, es);
824 pfree(buf.data);
825}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1290
#define bms_is_empty(a)
Definition bitmapset.h:118
int x
Definition isn.c:75

References appendStringInfo(), Assert, bms_is_empty, bms_next_member(), buf, ExplainPropertyText(), fb(), initStringInfo(), pfree(), and x.

Referenced by overexplain_debug(), overexplain_per_node_hook(), and overexplain_range_table().

◆ overexplain_bitmapset_list()

static void overexplain_bitmapset_list ( const char qlabel,
List bms_list,
ExplainState es 
)
static

Definition at line 835 of file pg_overexplain.c.

837{
839
841
843 {
846 else
847 {
848 int x = -1;
849 bool first = true;
850
852 while ((x = bms_next_member(bms, x)) >= 0)
853 {
854 if (first)
855 first = false;
856 else
858 appendStringInfo(&buf, "%d", x);
859 }
861 }
862 }
863
864 if (buf.len == 0)
865 {
866 ExplainPropertyText(qlabel, "none", es);
867 return;
868 }
869
870 Assert(buf.data[0] == ' ');
871 ExplainPropertyText(qlabel, buf.data + 1, es);
872 pfree(buf.data);
873}
int bms_singleton_member(const Bitmapset *a)
Definition bitmapset.c:665
BMS_Membership bms_membership(const Bitmapset *a)
Definition bitmapset.c:765
@ BMS_SINGLETON
Definition bitmapset.h:72
void appendStringInfoString(StringInfo str, const char *s)
Definition stringinfo.c:230

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert, bms_membership(), bms_next_member(), BMS_SINGLETON, bms_singleton_member(), buf, ExplainPropertyText(), fb(), foreach_node, initStringInfo(), pfree(), and x.

Referenced by overexplain_per_node_hook().

◆ overexplain_debug()

static void overexplain_debug ( PlannedStmt plannedstmt,
ExplainState es 
)
static

Definition at line 345 of file pg_overexplain.c.

346{
347 char *commandType = NULL;
348 StringInfoData flags;
349
350 /* Even in text mode, we want to set this output apart as its own group. */
351 ExplainOpenGroup("PlannedStmt", "PlannedStmt", true, es);
352 if (es->format == EXPLAIN_FORMAT_TEXT)
353 {
355 appendStringInfoString(es->str, "PlannedStmt:\n");
356 es->indent++;
357 }
358
359 /* Print the command type. */
360 switch (plannedstmt->commandType)
361 {
362 case CMD_UNKNOWN:
363 commandType = "unknown";
364 break;
365 case CMD_SELECT:
366 commandType = "select";
367 break;
368 case CMD_UPDATE:
369 commandType = "update";
370 break;
371 case CMD_INSERT:
372 commandType = "insert";
373 break;
374 case CMD_DELETE:
375 commandType = "delete";
376 break;
377 case CMD_MERGE:
378 commandType = "merge";
379 break;
380 case CMD_UTILITY:
381 commandType = "utility";
382 break;
383 case CMD_NOTHING:
384 commandType = "nothing";
385 break;
386 }
387 ExplainPropertyText("Command Type", commandType, es);
388
389 /* Print various properties as a comma-separated list of flags. */
390 initStringInfo(&flags);
391 if (plannedstmt->hasReturning)
392 appendStringInfoString(&flags, ", hasReturning");
393 if (plannedstmt->hasModifyingCTE)
394 appendStringInfoString(&flags, ", hasModifyingCTE");
395 if (plannedstmt->canSetTag)
396 appendStringInfoString(&flags, ", canSetTag");
397 if (plannedstmt->transientPlan)
398 appendStringInfoString(&flags, ", transientPlan");
399 if (plannedstmt->dependsOnRole)
400 appendStringInfoString(&flags, ", dependsOnRole");
401 if (plannedstmt->parallelModeNeeded)
402 appendStringInfoString(&flags, ", parallelModeNeeded");
403 if (flags.len == 0)
404 appendStringInfoString(&flags, ", none");
405 ExplainPropertyText("Flags", flags.data + 2, es);
406
407 /* Various lists of integers. */
408 overexplain_bitmapset("Subplans Needing Rewind",
409 plannedstmt->rewindPlanIDs, es);
410 overexplain_intlist("Relation OIDs",
411 plannedstmt->relationOids, es);
412 overexplain_intlist("Executor Parameter Types",
413 plannedstmt->paramExecTypes, es);
414
415 /*
416 * Print the statement location. (If desired, we could alternatively print
417 * stmt_location and stmt_len as two separate fields.)
418 */
419 if (plannedstmt->stmt_location == -1)
420 ExplainPropertyText("Parse Location", "Unknown", es);
421 else if (plannedstmt->stmt_len == 0)
422 ExplainPropertyText("Parse Location",
423 psprintf("%d to end", plannedstmt->stmt_location),
424 es);
425 else
426 ExplainPropertyText("Parse Location",
427 psprintf("%d for %d bytes",
428 plannedstmt->stmt_location,
429 plannedstmt->stmt_len),
430 es);
431
432 /* Done with this group. */
433 if (es->format == EXPLAIN_FORMAT_TEXT)
434 es->indent--;
435 ExplainCloseGroup("PlannedStmt", "PlannedStmt", true, es);
436}
void ExplainOpenGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
void ExplainIndentText(ExplainState *es)
void ExplainCloseGroup(const char *objtype, const char *labelname, bool labeled, ExplainState *es)
@ EXPLAIN_FORMAT_TEXT
@ 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
static void overexplain_bitmapset(const char *qlabel, Bitmapset *bms, ExplainState *es)
static void overexplain_intlist(const char *qlabel, List *list, ExplainState *es)
char * psprintf(const char *fmt,...)
Definition psprintf.c:43
StringInfo str
ExplainFormat format
bool hasModifyingCTE
Definition plannodes.h:83
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 * relationOids
Definition plannodes.h:144
bool dependsOnRole
Definition plannodes.h:92
CmdType commandType
Definition plannodes.h:68
List * paramExecTypes
Definition plannodes.h:150
bool parallelModeNeeded
Definition plannodes.h:95

References appendStringInfoString(), PlannedStmt::canSetTag, CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_NOTHING, CMD_SELECT, CMD_UNKNOWN, CMD_UPDATE, CMD_UTILITY, PlannedStmt::commandType, StringInfoData::data, PlannedStmt::dependsOnRole, EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), ExplainIndentText(), ExplainOpenGroup(), ExplainPropertyText(), fb(), ExplainState::format, PlannedStmt::hasModifyingCTE, PlannedStmt::hasReturning, ExplainState::indent, initStringInfo(), StringInfoData::len, overexplain_bitmapset(), overexplain_intlist(), PlannedStmt::parallelModeNeeded, PlannedStmt::paramExecTypes, psprintf(), PlannedStmt::relationOids, PlannedStmt::rewindPlanIDs, PlannedStmt::stmt_len, PlannedStmt::stmt_location, ExplainState::str, and PlannedStmt::transientPlan.

Referenced by overexplain_per_plan_hook().

◆ overexplain_debug_handler()

static void overexplain_debug_handler ( ExplainState es,
DefElem opt,
ParseState pstate 
)
static

Definition at line 111 of file pg_overexplain.c.

112{
114
115 options->debug = defGetBoolean(opt);
116}
bool defGetBoolean(DefElem *def)
Definition define.c:93
static overexplain_options * overexplain_ensure_options(ExplainState *es)

References defGetBoolean(), and overexplain_ensure_options().

Referenced by _PG_init().

◆ overexplain_ensure_options()

static overexplain_options * overexplain_ensure_options ( ExplainState es)
static

Definition at line 92 of file pg_overexplain.c.

93{
95
97
98 if (options == NULL)
99 {
102 }
103
104 return options;
105}
void * GetExplainExtensionState(ExplainState *es, int extension_id)
void SetExplainExtensionState(ExplainState *es, int extension_id, void *opaque)
#define palloc0_object(type)
Definition fe_memutils.h:75

References es_extension_id, fb(), GetExplainExtensionState(), palloc0_object, and SetExplainExtensionState().

Referenced by overexplain_debug_handler(), and overexplain_range_table_handler().

◆ overexplain_intlist()

static void overexplain_intlist ( const char qlabel,
List list,
ExplainState es 
)
static

Definition at line 881 of file pg_overexplain.c.

882{
884
886
887 if (list == NIL)
888 {
889 ExplainPropertyText(qlabel, "none", es);
890 return;
891 }
892
893 if (IsA(list, IntList))
894 {
895 foreach_int(i, list)
896 appendStringInfo(&buf, " %d", i);
897 }
898 else if (IsA(list, OidList))
899 {
900 foreach_oid(o, list)
901 appendStringInfo(&buf, " %u", o);
902 }
903 else if (IsA(list, XidList))
904 {
905 foreach_xid(x, list)
906 appendStringInfo(&buf, " %u", x);
907 }
908 else
909 {
910 appendStringInfoString(&buf, " not an integer list");
911 Assert(false);
912 }
913
914 if (buf.len > 0)
915 ExplainPropertyText(qlabel, buf.data + 1, es);
916
917 pfree(buf.data);
918}
int i
Definition isn.c:77
#define IsA(nodeptr, _type_)
Definition nodes.h:164
#define NIL
Definition pg_list.h:68
#define foreach_xid(var, lst)
Definition pg_list.h:472
#define foreach_oid(var, lst)
Definition pg_list.h:471
#define foreach_int(var, lst)
Definition pg_list.h:470

References appendStringInfo(), appendStringInfoString(), Assert, buf, ExplainPropertyText(), fb(), foreach_int, foreach_oid, foreach_xid, i, initStringInfo(), IsA, NIL, pfree(), and x.

Referenced by overexplain_debug(), and overexplain_range_table().

◆ overexplain_per_node_hook()

static void overexplain_per_node_hook ( PlanState planstate,
List ancestors,
const char relationship,
const char plan_name,
ExplainState es 
)
static

Definition at line 136 of file pg_overexplain.c.

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 break;
262 default:
263 break;
264 }
265
267 {
268 char *elidednodetag;
269
270 if (n->plan_node_id != plan->plan_node_id)
271 continue;
272
274 {
275 ExplainOpenGroup("Elided Nodes", "Elided Nodes", false, es);
276 opened_elided_nodes = true;
277 }
278
279 switch (n->elided_type)
280 {
281 case T_Append:
282 elidednodetag = "Append";
283 break;
284 case T_MergeAppend:
285 elidednodetag = "MergeAppend";
286 break;
287 case T_SubqueryScan:
288 elidednodetag = "SubqueryScan";
289 break;
290 default:
291 elidednodetag = psprintf("%d", n->elided_type);
292 break;
293 }
294
295 ExplainOpenGroup("Elided Node", NULL, true, es);
296 ExplainPropertyText("Elided Node Type", elidednodetag, es);
297 overexplain_bitmapset("Elided Node RTIs", n->relids, es);
298 ExplainCloseGroup("Elided Node", NULL, true, es);
299 }
301 ExplainCloseGroup("Elided Nodes", "Elided Nodes", false, es);
302 }
303}
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
void ExplainPropertyBool(const char *qlabel, bool value, ExplainState *es)
#define nodeTag(nodeptr)
Definition nodes.h:139
static void overexplain_bitmapset_list(const char *qlabel, List *bms_list, ExplainState *es)
#define plan(x)
Definition pg_regress.c:161
PlannedStmt * pstmt
Plan * plan
Definition execnodes.h:1168
List * elidedNodes
Definition plannodes.h:156

References bms_is_empty, PlannedStmt::elidedNodes, es_extension_id, EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), ExplainOpenGroup(), ExplainPropertyBool(), ExplainPropertyInteger(), ExplainPropertyText(), fb(), foreach_node, ExplainState::format, GetExplainExtensionState(), nodeTag, overexplain_bitmapset(), overexplain_bitmapset_list(), PlanState::plan, plan, prev_explain_per_node_hook, psprintf(), and ExplainState::pstmt.

Referenced by _PG_init().

◆ overexplain_per_plan_hook()

static void overexplain_per_plan_hook ( PlannedStmt plannedstmt,
IntoClause into,
ExplainState es,
const char queryString,
ParamListInfo  params,
QueryEnvironment queryEnv 
)
static

Definition at line 312 of file pg_overexplain.c.

318{
320
322 (*prev_explain_per_plan_hook) (plannedstmt, into, es, queryString,
323 params, queryEnv);
324
326 if (options == NULL)
327 return;
328
329 if (options->debug)
330 overexplain_debug(plannedstmt, es);
331
332 if (options->range_table)
333 overexplain_range_table(plannedstmt, es);
334}
static void overexplain_range_table(PlannedStmt *plannedstmt, ExplainState *es)
static void overexplain_debug(PlannedStmt *plannedstmt, ExplainState *es)

References es_extension_id, fb(), GetExplainExtensionState(), overexplain_debug(), overexplain_range_table(), and prev_explain_per_plan_hook.

Referenced by _PG_init().

◆ overexplain_range_table()

static void overexplain_range_table ( PlannedStmt plannedstmt,
ExplainState es 
)
static

Definition at line 443 of file pg_overexplain.c.

444{
445 Index rti;
446 ListCell *lc_subrtinfo = list_head(plannedstmt->subrtinfos);
448
449 /* Open group, one entry per RangeTblEntry */
450 ExplainOpenGroup("Range Table", "Range Table", false, es);
451
452 /* Iterate over the range table */
453 for (rti = 1; rti <= list_length(plannedstmt->rtable); ++rti)
454 {
455 RangeTblEntry *rte = rt_fetch(rti, plannedstmt->rtable);
456 char *kind = NULL;
457 char *relkind;
459
460 /* Advance to next SubRTInfo, if it's time. */
461 if (lc_subrtinfo != NULL)
462 {
464 if (rti > next_rtinfo->rtoffset)
465 {
467 lc_subrtinfo = lnext(plannedstmt->subrtinfos, lc_subrtinfo);
468 }
469 }
470
471 /* NULL entries are possible; skip them */
472 if (rte == NULL)
473 continue;
474
475 /* Translate rtekind to a string */
476 switch (rte->rtekind)
477 {
478 case RTE_RELATION:
479 kind = "relation";
480 break;
481 case RTE_SUBQUERY:
482 kind = "subquery";
483 break;
484 case RTE_JOIN:
485 kind = "join";
486 break;
487 case RTE_FUNCTION:
488 kind = "function";
489 break;
490 case RTE_TABLEFUNC:
491 kind = "tablefunc";
492 break;
493 case RTE_VALUES:
494 kind = "values";
495 break;
496 case RTE_CTE:
497 kind = "cte";
498 break;
500 kind = "namedtuplestore";
501 break;
502 case RTE_RESULT:
503 kind = "result";
504 break;
505 case RTE_GROUP:
506 kind = "group";
507 break;
508 }
509
510 /* Begin group for this specific RTE */
511 ExplainOpenGroup("Range Table Entry", NULL, true, es);
512
513 /*
514 * In text format, the summary line displays the range table index and
515 * rtekind, plus indications if rte->inh and/or rte->inFromCl are set.
516 * In other formats, we display those as separate properties.
517 */
518 if (es->format == EXPLAIN_FORMAT_TEXT)
519 {
521 appendStringInfo(es->str, "RTI %u (%s%s%s):\n", rti, kind,
522 rte->inh ? ", inherited" : "",
523 rte->inFromCl ? ", in-from-clause" : "");
524 es->indent++;
525 }
526 else
527 {
528 ExplainPropertyUInteger("RTI", NULL, rti, es);
529 ExplainPropertyText("Kind", kind, es);
530 ExplainPropertyBool("Inherited", rte->inh, es);
531 ExplainPropertyBool("In From Clause", rte->inFromCl, es);
532 }
533
534 /*
535 * Indicate which subplan is the origin of which RTE. Note dummy
536 * subplans. Here again, we crunch more onto one line in text format.
537 */
538 if (rtinfo != NULL)
539 {
540 if (es->format == EXPLAIN_FORMAT_TEXT)
541 {
542 if (!rtinfo->dummy)
543 ExplainPropertyText("Subplan", rtinfo->plan_name, es);
544 else
545 ExplainPropertyText("Subplan",
546 psprintf("%s (dummy)",
547 rtinfo->plan_name), es);
548 }
549 else
550 {
551 ExplainPropertyText("Subplan", rtinfo->plan_name, es);
552 ExplainPropertyBool("Subplan Is Dummy", rtinfo->dummy, es);
553 }
554 }
555
556 /* rte->alias is optional; rte->eref is requested */
557 if (rte->alias != NULL)
558 overexplain_alias("Alias", rte->alias, es);
559 overexplain_alias("Eref", rte->eref, es);
560
561 /*
562 * We adhere to the usual EXPLAIN convention that schema names are
563 * displayed only in verbose mode, and we emit nothing if there is no
564 * relation OID.
565 */
566 if (rte->relid != 0)
567 {
568 const char *relname;
569 const char *qualname;
570
572
573 if (es->verbose)
574 {
576 char *nspname;
577
579 qualname = psprintf("%s.%s", quote_identifier(nspname),
580 relname);
581 }
582 else
584
585 ExplainPropertyText("Relation", qualname, es);
586 }
587
588 /* Translate relkind, if any, to a string */
589 switch (rte->relkind)
590 {
591 case RELKIND_RELATION:
592 relkind = "relation";
593 break;
594 case RELKIND_INDEX:
595 relkind = "index";
596 break;
597 case RELKIND_SEQUENCE:
598 relkind = "sequence";
599 break;
601 relkind = "toastvalue";
602 break;
603 case RELKIND_VIEW:
604 relkind = "view";
605 break;
606 case RELKIND_MATVIEW:
607 relkind = "matview";
608 break;
610 relkind = "composite_type";
611 break;
613 relkind = "foreign_table";
614 break;
616 relkind = "partitioned_table";
617 break;
619 relkind = "partitioned_index";
620 break;
621 case '\0':
622 relkind = NULL;
623 break;
624 default:
625 relkind = psprintf("%c", rte->relkind);
626 break;
627 }
628
629 /* If there is a relkind, show it */
630 if (relkind != NULL)
631 ExplainPropertyText("Relation Kind", relkind, es);
632
633 /* If there is a lock mode, show it */
634 if (rte->rellockmode != 0)
635 ExplainPropertyText("Relation Lock Mode",
637 rte->rellockmode), es);
638
639 /*
640 * If there is a perminfoindex, show it. We don't try to display
641 * information from the RTEPermissionInfo node here because they are
642 * just indexes plannedstmt->permInfos which could be separately
643 * dumped if someone wants to add EXPLAIN (PERMISSIONS) or similar.
644 */
645 if (rte->perminfoindex != 0)
646 ExplainPropertyInteger("Permission Info Index", NULL,
647 rte->perminfoindex, es);
648
649 /*
650 * add_rte_to_flat_rtable will clear rte->tablesample and
651 * rte->subquery in the finished plan, so skip those fields.
652 *
653 * However, the security_barrier flag is not shown by the core code,
654 * so let's print it here.
655 */
656 if (es->format != EXPLAIN_FORMAT_TEXT || rte->security_barrier)
657 ExplainPropertyBool("Security Barrier", rte->security_barrier, es);
658
659 /*
660 * If this is a join, print out the fields that are specifically valid
661 * for joins.
662 */
663 if (rte->rtekind == RTE_JOIN)
664 {
665 char *jointype;
666
667 switch (rte->jointype)
668 {
669 case JOIN_INNER:
670 jointype = "Inner";
671 break;
672 case JOIN_LEFT:
673 jointype = "Left";
674 break;
675 case JOIN_FULL:
676 jointype = "Full";
677 break;
678 case JOIN_RIGHT:
679 jointype = "Right";
680 break;
681 case JOIN_SEMI:
682 jointype = "Semi";
683 break;
684 case JOIN_ANTI:
685 jointype = "Anti";
686 break;
687 case JOIN_RIGHT_SEMI:
688 jointype = "Right Semi";
689 break;
690 case JOIN_RIGHT_ANTI:
691 jointype = "Right Anti";
692 break;
693 default:
694 jointype = "???";
695 break;
696 }
697
698 /* Join type */
699 ExplainPropertyText("Join Type", jointype, es);
700
701 /* # of JOIN USING columns */
702 if (es->format != EXPLAIN_FORMAT_TEXT || rte->joinmergedcols != 0)
703 ExplainPropertyInteger("JOIN USING Columns", NULL,
704 rte->joinmergedcols, es);
705
706 /*
707 * add_rte_to_flat_rtable will clear joinaliasvars, joinleftcols,
708 * joinrightcols, and join_using_alias here, so skip those fields.
709 */
710 }
711
712 /*
713 * add_rte_to_flat_rtable will clear functions, tablefunc, and
714 * values_lists, but we can display funcordinality.
715 */
716 if (rte->rtekind == RTE_FUNCTION)
717 ExplainPropertyBool("WITH ORDINALITY", rte->funcordinality, es);
718
719 /*
720 * If this is a CTE, print out CTE-related properties.
721 */
722 if (rte->rtekind == RTE_CTE)
723 {
724 ExplainPropertyText("CTE Name", rte->ctename, es);
725 ExplainPropertyUInteger("CTE Levels Up", NULL, rte->ctelevelsup,
726 es);
727 ExplainPropertyBool("CTE Self-Reference", rte->self_reference, es);
728 }
729
730 /*
731 * add_rte_to_flat_rtable will clear coltypes, coltypmods, and
732 * colcollations, so skip those fields.
733 *
734 * If this is an ephemeral named relation, print out ENR-related
735 * properties.
736 */
737 if (rte->rtekind == RTE_NAMEDTUPLESTORE)
738 {
739 ExplainPropertyText("ENR Name", rte->enrname, es);
740 ExplainPropertyFloat("ENR Tuples", NULL, rte->enrtuples, 0, es);
741 }
742
743 /*
744 * add_rte_to_flat_rtable will clear groupexprs and securityQuals, so
745 * skip that field. We have handled inFromCl above, so the only thing
746 * left to handle here is rte->lateral.
747 */
748 if (es->format != EXPLAIN_FORMAT_TEXT || rte->lateral)
749 ExplainPropertyBool("Lateral", rte->lateral, es);
750
751 /* Done with this RTE */
752 if (es->format == EXPLAIN_FORMAT_TEXT)
753 es->indent--;
754 ExplainCloseGroup("Range Table Entry", NULL, true, es);
755 }
756
757 /* Print PlannedStmt fields that contain RTIs. */
758 if (es->format != EXPLAIN_FORMAT_TEXT ||
759 !bms_is_empty(plannedstmt->unprunableRelids))
760 overexplain_bitmapset("Unprunable RTIs", plannedstmt->unprunableRelids,
761 es);
762 if (es->format != EXPLAIN_FORMAT_TEXT ||
763 plannedstmt->resultRelations != NIL)
764 overexplain_intlist("Result RTIs", plannedstmt->resultRelations, es);
765
766 /* Close group, we're all done */
767 ExplainCloseGroup("Range Table", "Range Table", false, es);
768}
unsigned int Index
Definition c.h:640
void ExplainPropertyUInteger(const char *qlabel, const char *unit, uint64 value, ExplainState *es)
void ExplainPropertyFloat(const char *qlabel, const char *unit, double value, int ndigits, ExplainState *es)
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:3542
@ 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:40
#define lfirst(lc)
Definition pg_list.h:172
static int list_length(const List *l)
Definition pg_list.h:152
static ListCell * list_head(const List *l)
Definition pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition pg_list.h:343
static void overexplain_alias(const char *qlabel, Alias *alias, ExplainState *es)
unsigned int Oid
List * resultRelations
Definition plannodes.h:124
List * subrtinfos
Definition plannodes.h:135
Bitmapset * unprunableRelids
Definition plannodes.h:115
List * rtable
Definition plannodes.h:109

References appendStringInfo(), bms_is_empty, DEFAULT_LOCKMETHOD, EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), ExplainIndentText(), ExplainOpenGroup(), ExplainPropertyBool(), ExplainPropertyFloat(), ExplainPropertyInteger(), ExplainPropertyText(), ExplainPropertyUInteger(), fb(), ExplainState::format, get_namespace_name_or_temp(), get_rel_name(), get_rel_namespace(), GetLockmodeName(), ExplainState::indent, JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, JOIN_RIGHT_ANTI, JOIN_RIGHT_SEMI, JOIN_SEMI, lfirst, list_head(), list_length(), lnext(), NIL, overexplain_alias(), overexplain_bitmapset(), overexplain_intlist(), psprintf(), quote_identifier(), relname, PlannedStmt::resultRelations, rt_fetch, PlannedStmt::rtable, RTE_CTE, RTE_FUNCTION, RTE_GROUP, RTE_JOIN, RTE_NAMEDTUPLESTORE, RTE_RELATION, RTE_RESULT, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, ExplainState::str, PlannedStmt::subrtinfos, PlannedStmt::unprunableRelids, and ExplainState::verbose.

Referenced by overexplain_per_plan_hook().

◆ overexplain_range_table_handler()

static void overexplain_range_table_handler ( ExplainState es,
DefElem opt,
ParseState pstate 
)
static

Definition at line 122 of file pg_overexplain.c.

124{
126
127 options->range_table = defGetBoolean(opt);
128}

References defGetBoolean(), and overexplain_ensure_options().

Referenced by _PG_init().

◆ PG_MODULE_MAGIC_EXT()

PG_MODULE_MAGIC_EXT ( name = "pg_overexplain",
version = PG_VERSION 
)

Variable Documentation

◆ es_extension_id

int es_extension_id
static

◆ prev_explain_per_node_hook

explain_per_node_hook_type prev_explain_per_node_hook
static

Definition at line 63 of file pg_overexplain.c.

Referenced by _PG_init(), and overexplain_per_node_hook().

◆ prev_explain_per_plan_hook

explain_per_plan_hook_type prev_explain_per_plan_hook
static

Definition at line 64 of file pg_overexplain.c.

Referenced by _PG_init(), and overexplain_per_plan_hook().