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. */
81
82 /* Use the per-node and per-plan hooks to make our options do something. */
87}
explain_per_node_hook_type explain_per_node_hook
Definition explain.c:59
explain_per_plan_hook_type explain_per_plan_hook
Definition explain.c:58
int GetExplainExtensionId(const char *extension_name)
void RegisterExtensionExplainOption(const char *option_name, ExplainOptionHandler handler, ExplainOptionGUCCheckHandler guc_check_handler)
bool GUCCheckBooleanExplainOption(const char *option_name, const char *option_value, NodeTag option_type)
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(), GUCCheckBooleanExplainOption(), 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 819 of file pg_overexplain.c.

820{
822 bool first = true;
823
824 Assert(alias != NULL);
825
828
830 {
831 appendStringInfo(&buf, "%s%s",
832 first ? "" : ", ",
833 quote_identifier(cn->sval));
834 first = false;
835 }
836
838 ExplainPropertyText(qlabel, buf.data, es);
839 pfree(buf.data);
840}
#define Assert(condition)
Definition c.h:1002
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
void pfree(void *pointer)
Definition mcxt.c:1619
#define foreach_node(type, var, lst)
Definition pg_list.h:528
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 848 of file pg_overexplain.c.

849{
850 int x = -1;
851
853
854 if (bms_is_empty(bms))
855 {
856 ExplainPropertyText(qlabel, "none", es);
857 return;
858 }
859
861 while ((x = bms_next_member(bms, x)) >= 0)
862 appendStringInfo(&buf, " %d", x);
863 Assert(buf.data[0] == ' ');
864 ExplainPropertyText(qlabel, buf.data + 1, es);
865 pfree(buf.data);
866}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1425
#define bms_is_empty(a)
Definition bitmapset.h:119
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 876 of file pg_overexplain.c.

878{
880
882
884 {
887 else
888 {
889 int x = -1;
890 bool first = true;
891
893 while ((x = bms_next_member(bms, x)) >= 0)
894 {
895 if (first)
896 first = false;
897 else
899 appendStringInfo(&buf, "%d", x);
900 }
902 }
903 }
904
905 if (buf.len == 0)
906 {
907 ExplainPropertyText(qlabel, "none", es);
908 return;
909 }
910
911 Assert(buf.data[0] == ' ');
912 ExplainPropertyText(qlabel, buf.data + 1, es);
913 pfree(buf.data);
914}
int bms_singleton_member(const Bitmapset *a)
Definition bitmapset.c:800
BMS_Membership bms_membership(const Bitmapset *a)
Definition bitmapset.c:900
@ 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 361 of file pg_overexplain.c.

362{
363 char *commandType = NULL;
364 StringInfoData flags;
365
366 /* Even in text mode, we want to set this output apart as its own group. */
367 ExplainOpenGroup("PlannedStmt", "PlannedStmt", true, es);
368 if (es->format == EXPLAIN_FORMAT_TEXT)
369 {
371 appendStringInfoString(es->str, "PlannedStmt:\n");
372 es->indent++;
373 }
374
375 /* Print the command type. */
376 switch (plannedstmt->commandType)
377 {
378 case CMD_UNKNOWN:
379 commandType = "unknown";
380 break;
381 case CMD_SELECT:
382 commandType = "select";
383 break;
384 case CMD_UPDATE:
385 commandType = "update";
386 break;
387 case CMD_INSERT:
388 commandType = "insert";
389 break;
390 case CMD_DELETE:
391 commandType = "delete";
392 break;
393 case CMD_MERGE:
394 commandType = "merge";
395 break;
396 case CMD_UTILITY:
397 commandType = "utility";
398 break;
399 case CMD_NOTHING:
400 commandType = "nothing";
401 break;
402 }
403 ExplainPropertyText("Command Type", commandType, es);
404
405 /* Print various properties as a comma-separated list of flags. */
406 initStringInfo(&flags);
407 if (plannedstmt->hasReturning)
408 appendStringInfoString(&flags, ", hasReturning");
409 if (plannedstmt->hasModifyingCTE)
410 appendStringInfoString(&flags, ", hasModifyingCTE");
411 if (plannedstmt->canSetTag)
412 appendStringInfoString(&flags, ", canSetTag");
413 if (plannedstmt->transientPlan)
414 appendStringInfoString(&flags, ", transientPlan");
415 if (plannedstmt->dependsOnRole)
416 appendStringInfoString(&flags, ", dependsOnRole");
417 if (plannedstmt->parallelModeNeeded)
418 appendStringInfoString(&flags, ", parallelModeNeeded");
419 if (flags.len == 0)
420 appendStringInfoString(&flags, ", none");
421 ExplainPropertyText("Flags", flags.data + 2, es);
422
423 /* Various lists of integers. */
424 overexplain_bitmapset("Subplans Needing Rewind",
425 plannedstmt->rewindPlanIDs, es);
426 overexplain_intlist("Relation OIDs",
427 plannedstmt->relationOids, es);
428 overexplain_intlist("Executor Parameter Types",
429 plannedstmt->paramExecTypes, es);
430
431 /*
432 * Print the statement location. (If desired, we could alternatively print
433 * stmt_location and stmt_len as two separate fields.)
434 */
435 if (plannedstmt->stmt_location == -1)
436 ExplainPropertyText("Parse Location", "Unknown", es);
437 else if (plannedstmt->stmt_len == 0)
438 ExplainPropertyText("Parse Location",
439 psprintf("%d to end", plannedstmt->stmt_location),
440 es);
441 else
442 ExplainPropertyText("Parse Location",
443 psprintf("%d for %d bytes",
444 plannedstmt->stmt_location,
445 plannedstmt->stmt_len),
446 es);
447
448 /* Done with this group. */
449 if (es->format == EXPLAIN_FORMAT_TEXT)
450 es->indent--;
451 ExplainCloseGroup("PlannedStmt", "PlannedStmt", true, es);
452}
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:277
@ CMD_UTILITY
Definition nodes.h:278
@ CMD_INSERT
Definition nodes.h:275
@ CMD_DELETE
Definition nodes.h:276
@ CMD_UNKNOWN
Definition nodes.h:272
@ CMD_UPDATE
Definition nodes.h:274
@ CMD_SELECT
Definition nodes.h:273
@ CMD_NOTHING
Definition nodes.h:280
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:81
bool canSetTag
Definition plannodes.h:84
Bitmapset * rewindPlanIDs
Definition plannodes.h:135
ParseLoc stmt_len
Definition plannodes.h:171
bool hasReturning
Definition plannodes.h:78
ParseLoc stmt_location
Definition plannodes.h:169
bool transientPlan
Definition plannodes.h:87
List * relationOids
Definition plannodes.h:144
bool dependsOnRole
Definition plannodes.h:90
CmdType commandType
Definition plannodes.h:66
List * paramExecTypes
Definition plannodes.h:150
bool parallelModeNeeded
Definition plannodes.h:93

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 113 of file pg_overexplain.c.

114{
116
117 options->debug = defGetBoolean(opt);
118}
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 94 of file pg_overexplain.c.

95{
97
99
100 if (options == NULL)
101 {
104 }
105
106 return options;
107}
void * GetExplainExtensionState(ExplainState *es, int extension_id)
void SetExplainExtensionState(ExplainState *es, int extension_id, void *opaque)
#define palloc0_object(type)
Definition fe_memutils.h:90

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 922 of file pg_overexplain.c.

923{
925
927
928 if (list == NIL)
929 {
930 ExplainPropertyText(qlabel, "none", es);
931 return;
932 }
933
934 if (IsA(list, IntList))
935 {
936 foreach_int(i, list)
937 appendStringInfo(&buf, " %d", i);
938 }
939 else if (IsA(list, OidList))
940 {
941 foreach_oid(o, list)
942 appendStringInfo(&buf, " %u", o);
943 }
944 else if (IsA(list, XidList))
945 {
946 foreach_xid(x, list)
947 appendStringInfo(&buf, " %u", x);
948 }
949 else
950 {
951 appendStringInfoString(&buf, " not an integer list");
952 Assert(false);
953 }
954
955 if (buf.len > 0)
956 ExplainPropertyText(qlabel, buf.data + 1, es);
957
958 pfree(buf.data);
959}
int i
Definition isn.c:77
#define IsA(nodeptr, _type_)
Definition nodes.h:162
#define NIL
Definition pg_list.h:68
#define foreach_xid(var, lst)
Definition pg_list.h:504
#define foreach_oid(var, lst)
Definition pg_list.h:503
#define foreach_int(var, lst)
Definition pg_list.h:502

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

Referenced by overexplain_debug().

◆ 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 138 of file pg_overexplain.c.

141{
143 Plan *plan = planstate->plan;
144
146 (*prev_explain_per_node_hook) (planstate, ancestors, relationship,
147 plan_name, es);
148
150 if (options == NULL)
151 return;
152
153 /*
154 * If the "debug" option was given, display miscellaneous fields from the
155 * "Plan" node that would not otherwise be displayed.
156 */
157 if (options->debug)
158 {
159 /*
160 * Normal EXPLAIN will display "Disabled: true" if the node is
161 * disabled; but that is based on noticing that plan->disabled_nodes
162 * is higher than the sum of its children; here, we display the raw
163 * value, for debugging purposes.
164 */
165 ExplainPropertyInteger("Disabled Nodes", NULL, plan->disabled_nodes,
166 es);
167
168 /*
169 * Normal EXPLAIN will display the parallel_aware flag; here, we show
170 * the parallel_safe flag as well.
171 */
172 ExplainPropertyBool("Parallel Safe", plan->parallel_safe, es);
173
174 /*
175 * The plan node ID isn't normally displayed, since it is only useful
176 * for debugging.
177 */
178 ExplainPropertyInteger("Plan Node ID", NULL, plan->plan_node_id, es);
179
180 /*
181 * It is difficult to explain what extParam and allParam mean in plain
182 * language, so we simply display these fields labelled with the
183 * structure member name. For compactness, the text format omits the
184 * display of this information when the bitmapset is empty.
185 */
186 if (es->format != EXPLAIN_FORMAT_TEXT || !bms_is_empty(plan->extParam))
187 overexplain_bitmapset("extParam", plan->extParam, es);
188 if (es->format != EXPLAIN_FORMAT_TEXT || !bms_is_empty(plan->allParam))
189 overexplain_bitmapset("allParam", plan->allParam, es);
190 }
191
192 /*
193 * If the "range_table" option was specified, display information about
194 * the range table indexes for this node.
195 */
196 if (options->range_table)
197 {
198 bool opened_elided_nodes = false;
199
200 switch (nodeTag(plan))
201 {
202 case T_SeqScan:
203 case T_SampleScan:
204 case T_IndexScan:
205 case T_IndexOnlyScan:
206 case T_BitmapHeapScan:
207 case T_TidScan:
208 case T_TidRangeScan:
209 case T_SubqueryScan:
210 case T_FunctionScan:
211 case T_TableFuncScan:
212 case T_ValuesScan:
213 case T_CteScan:
215 case T_WorkTableScan:
216 ExplainPropertyInteger("Scan RTI", NULL,
217 ((Scan *) plan)->scanrelid, es);
218 break;
219 case T_ForeignScan:
220 overexplain_bitmapset("Scan RTIs",
221 ((ForeignScan *) plan)->fs_base_relids,
222 es);
223 break;
224 case T_CustomScan:
225 overexplain_bitmapset("Scan RTIs",
226 ((CustomScan *) plan)->custom_relids,
227 es);
228 break;
229 case T_ModifyTable:
230 ExplainPropertyInteger("Nominal RTI", NULL,
231 ((ModifyTable *) plan)->nominalRelation, es);
232 ExplainPropertyInteger("Exclude Relation RTI", NULL,
233 ((ModifyTable *) plan)->exclRelRTI, es);
234 break;
235 case T_Append:
236 overexplain_bitmapset("Append RTIs",
237 ((Append *) plan)->apprelids,
238 es);
239 overexplain_bitmapset_list("Child Append RTIs",
240 ((Append *) plan)->child_append_relid_sets,
241 es);
242 break;
243 case T_MergeAppend:
244 overexplain_bitmapset("Append RTIs",
245 ((MergeAppend *) plan)->apprelids,
246 es);
247 overexplain_bitmapset_list("Child Append RTIs",
248 ((MergeAppend *) plan)->child_append_relid_sets,
249 es);
250 break;
251 case T_Result:
252
253 /*
254 * 'relids' is only meaningful when plan->lefttree is NULL,
255 * but if somehow it ends up set when plan->lefttree is not
256 * NULL, print it anyway.
257 */
258 if (plan->lefttree == NULL ||
259 ((Result *) plan)->relids != NULL)
261 ((Result *) plan)->relids,
262 es);
263 break;
264 case T_MergeJoin:
265 case T_NestLoop:
266 case T_HashJoin:
267
268 /*
269 * 'ojrelids' is only meaningful for non-inner joins, but if
270 * it somehow ends up set for an inner join, print it anyway.
271 */
272 if (((Join *) plan)->jointype != JOIN_INNER ||
273 ((Join *) plan)->ojrelids != NULL)
274 overexplain_bitmapset("Outer Join RTIs",
275 ((Join *) plan)->ojrelids,
276 es);
277 break;
278 default:
279 break;
280 }
281
283 {
284 char *elidednodetag;
285
286 if (n->plan_node_id != plan->plan_node_id)
287 continue;
288
290 {
291 ExplainOpenGroup("Elided Nodes", "Elided Nodes", false, es);
292 opened_elided_nodes = true;
293 }
294
295 switch (n->elided_type)
296 {
297 case T_Append:
298 elidednodetag = "Append";
299 break;
300 case T_MergeAppend:
301 elidednodetag = "MergeAppend";
302 break;
303 case T_SubqueryScan:
304 elidednodetag = "SubqueryScan";
305 break;
306 default:
307 elidednodetag = psprintf("%d", n->elided_type);
308 break;
309 }
310
311 ExplainOpenGroup("Elided Node", NULL, true, es);
312 ExplainPropertyText("Elided Node Type", elidednodetag, es);
313 overexplain_bitmapset("Elided Node RTIs", n->relids, es);
314 ExplainCloseGroup("Elided Node", NULL, true, es);
315 }
317 ExplainCloseGroup("Elided Nodes", "Elided Nodes", false, es);
318 }
319}
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:137
@ JOIN_INNER
Definition nodes.h:301
static void overexplain_bitmapset_list(const char *qlabel, List *bms_list, ExplainState *es)
#define plan(x)
Definition pg_regress.c:164
PlannedStmt * pstmt
Plan * plan
Definition execnodes.h:1202
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(), JOIN_INNER, 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 328 of file pg_overexplain.c.

334{
336
338 (*prev_explain_per_plan_hook) (plannedstmt, into, es, queryString,
339 params, queryEnv);
340
342 if (options == NULL)
343 return;
344
345 if (options->debug)
346 overexplain_debug(plannedstmt, es);
347
348 if (options->range_table)
349 overexplain_range_table(plannedstmt, es);
350}
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 459 of file pg_overexplain.c.

460{
461 Index rti;
462 ListCell *lc_subrtinfo = list_head(plannedstmt->subrtinfos);
464
465 /* Open group, one entry per RangeTblEntry */
466 ExplainOpenGroup("Range Table", "Range Table", false, es);
467
468 /* Iterate over the range table */
469 for (rti = 1; rti <= list_length(plannedstmt->rtable); ++rti)
470 {
471 RangeTblEntry *rte = rt_fetch(rti, plannedstmt->rtable);
472 char *kind = NULL;
473 char *relkind;
475
476 /* Advance to next SubPlanRTInfo, if it's time. */
477 if (lc_subrtinfo != NULL)
478 {
480 if (rti > next_rtinfo->rtoffset)
481 {
483 lc_subrtinfo = lnext(plannedstmt->subrtinfos, lc_subrtinfo);
484 }
485 }
486
487 /* NULL entries are possible; skip them */
488 if (rte == NULL)
489 continue;
490
491 /* Translate rtekind to a string */
492 switch (rte->rtekind)
493 {
494 case RTE_RELATION:
495 kind = "relation";
496 break;
497 case RTE_SUBQUERY:
498 kind = "subquery";
499 break;
500 case RTE_JOIN:
501 kind = "join";
502 break;
503 case RTE_FUNCTION:
504 kind = "function";
505 break;
506 case RTE_TABLEFUNC:
507 kind = "tablefunc";
508 break;
509 case RTE_VALUES:
510 kind = "values";
511 break;
512 case RTE_CTE:
513 kind = "cte";
514 break;
516 kind = "namedtuplestore";
517 break;
518 case RTE_RESULT:
519 kind = "result";
520 break;
521 case RTE_GROUP:
522 kind = "group";
523 break;
524 case RTE_GRAPH_TABLE:
525
526 /*
527 * We should not see RTE of this kind here since property
528 * graph RTE gets converted to subquery RTE in
529 * rewriteGraphTable(). In case we decide not to do the
530 * conversion and leave RTE kind unchanged in future, print
531 * correct name of RTE kind.
532 */
533 kind = "graph_table";
534 break;
535 }
536
537 /* Begin group for this specific RTE */
538 ExplainOpenGroup("Range Table Entry", NULL, true, es);
539
540 /*
541 * In text format, the summary line displays the range table index and
542 * rtekind, plus indications if rte->inh and/or rte->inFromCl are set.
543 * In other formats, we display those as separate properties.
544 */
545 if (es->format == EXPLAIN_FORMAT_TEXT)
546 {
548 appendStringInfo(es->str, "RTI %u (%s%s%s):\n", rti, kind,
549 rte->inh ? ", inherited" : "",
550 rte->inFromCl ? ", in-from-clause" : "");
551 es->indent++;
552 }
553 else
554 {
555 ExplainPropertyUInteger("RTI", NULL, rti, es);
556 ExplainPropertyText("Kind", kind, es);
557 ExplainPropertyBool("Inherited", rte->inh, es);
558 ExplainPropertyBool("In From Clause", rte->inFromCl, es);
559 }
560
561 /*
562 * Indicate which subplan is the origin of which RTE. Note dummy
563 * subplans. Here again, we crunch more onto one line in text format.
564 */
565 if (rtinfo != NULL)
566 {
567 if (es->format == EXPLAIN_FORMAT_TEXT)
568 {
569 if (!rtinfo->dummy)
570 ExplainPropertyText("Subplan", rtinfo->plan_name, es);
571 else
572 ExplainPropertyText("Subplan",
573 psprintf("%s (dummy)",
574 rtinfo->plan_name), es);
575 }
576 else
577 {
578 ExplainPropertyText("Subplan", rtinfo->plan_name, es);
579 ExplainPropertyBool("Subplan Is Dummy", rtinfo->dummy, es);
580 }
581 }
582
583 /* rte->alias is optional; rte->eref is requested */
584 if (rte->alias != NULL)
585 overexplain_alias("Alias", rte->alias, es);
586 overexplain_alias("Eref", rte->eref, es);
587
588 /*
589 * We adhere to the usual EXPLAIN convention that schema names are
590 * displayed only in verbose mode, and we emit nothing if there is no
591 * relation OID.
592 */
593 if (rte->relid != 0)
594 {
595 const char *relname;
596 const char *qualname;
597
599
600 if (es->verbose)
601 {
603 char *nspname;
604
606 qualname = psprintf("%s.%s", quote_identifier(nspname),
607 relname);
608 }
609 else
611
612 ExplainPropertyText("Relation", qualname, es);
613 }
614
615 /* Translate relkind, if any, to a string */
616 switch (rte->relkind)
617 {
618 case RELKIND_RELATION:
619 relkind = "relation";
620 break;
621 case RELKIND_INDEX:
622 relkind = "index";
623 break;
624 case RELKIND_SEQUENCE:
625 relkind = "sequence";
626 break;
628 relkind = "toastvalue";
629 break;
630 case RELKIND_VIEW:
631 relkind = "view";
632 break;
633 case RELKIND_MATVIEW:
634 relkind = "matview";
635 break;
637 relkind = "composite_type";
638 break;
640 relkind = "foreign_table";
641 break;
643 relkind = "partitioned_table";
644 break;
646 relkind = "partitioned_index";
647 break;
649 relkind = "property_graph";
650 break;
651 case '\0':
652 relkind = NULL;
653 break;
654 default:
655 relkind = psprintf("%c", rte->relkind);
656 break;
657 }
658
659 /* If there is a relkind, show it */
660 if (relkind != NULL)
661 ExplainPropertyText("Relation Kind", relkind, es);
662
663 /* If there is a lock mode, show it */
664 if (rte->rellockmode != 0)
665 ExplainPropertyText("Relation Lock Mode",
667 rte->rellockmode), es);
668
669 /*
670 * If there is a perminfoindex, show it. We don't try to display
671 * information from the RTEPermissionInfo node here because they are
672 * just indexes plannedstmt->permInfos which could be separately
673 * dumped if someone wants to add EXPLAIN (PERMISSIONS) or similar.
674 */
675 if (rte->perminfoindex != 0)
676 ExplainPropertyInteger("Permission Info Index", NULL,
677 rte->perminfoindex, es);
678
679 /*
680 * add_rte_to_flat_rtable will clear rte->tablesample and
681 * rte->subquery in the finished plan, so skip those fields.
682 *
683 * However, the security_barrier flag is not shown by the core code,
684 * so let's print it here.
685 */
686 if (es->format != EXPLAIN_FORMAT_TEXT || rte->security_barrier)
687 ExplainPropertyBool("Security Barrier", rte->security_barrier, es);
688
689 /*
690 * If this is a join, print out the fields that are specifically valid
691 * for joins.
692 */
693 if (rte->rtekind == RTE_JOIN)
694 {
695 char *jointype;
696
697 switch (rte->jointype)
698 {
699 case JOIN_INNER:
700 jointype = "Inner";
701 break;
702 case JOIN_LEFT:
703 jointype = "Left";
704 break;
705 case JOIN_FULL:
706 jointype = "Full";
707 break;
708 case JOIN_RIGHT:
709 jointype = "Right";
710 break;
711 case JOIN_SEMI:
712 jointype = "Semi";
713 break;
714 case JOIN_ANTI:
715 jointype = "Anti";
716 break;
717 case JOIN_RIGHT_SEMI:
718 jointype = "Right Semi";
719 break;
720 case JOIN_RIGHT_ANTI:
721 jointype = "Right Anti";
722 break;
723 default:
724 jointype = "???";
725 break;
726 }
727
728 /* Join type */
729 ExplainPropertyText("Join Type", jointype, es);
730
731 /* # of JOIN USING columns */
732 if (es->format != EXPLAIN_FORMAT_TEXT || rte->joinmergedcols != 0)
733 ExplainPropertyInteger("JOIN USING Columns", NULL,
734 rte->joinmergedcols, es);
735
736 /*
737 * add_rte_to_flat_rtable will clear joinaliasvars, joinleftcols,
738 * joinrightcols, and join_using_alias here, so skip those fields.
739 */
740 }
741
742 /*
743 * add_rte_to_flat_rtable will clear functions, tablefunc, and
744 * values_lists, but we can display funcordinality.
745 */
746 if (rte->rtekind == RTE_FUNCTION)
747 ExplainPropertyBool("WITH ORDINALITY", rte->funcordinality, es);
748
749 /*
750 * If this is a CTE, print out CTE-related properties.
751 */
752 if (rte->rtekind == RTE_CTE)
753 {
754 ExplainPropertyText("CTE Name", rte->ctename, es);
755 ExplainPropertyUInteger("CTE Levels Up", NULL, rte->ctelevelsup,
756 es);
757 ExplainPropertyBool("CTE Self-Reference", rte->self_reference, es);
758 }
759
760 /*
761 * add_rte_to_flat_rtable will clear coltypes, coltypmods, and
762 * colcollations, so skip those fields.
763 *
764 * If this is an ephemeral named relation, print out ENR-related
765 * properties.
766 */
767 if (rte->rtekind == RTE_NAMEDTUPLESTORE)
768 {
769 ExplainPropertyText("ENR Name", rte->enrname, es);
770 ExplainPropertyFloat("ENR Tuples", NULL, rte->enrtuples, 0, es);
771 }
772
773 /*
774 * rewriteGraphTable() clears graph_pattern and graph_table_columns
775 * fields, so skip them. No graph table specific fields are required
776 * to be printed.
777 */
778
779 /*
780 * add_rte_to_flat_rtable will clear groupexprs and securityQuals, so
781 * skip that field. We have handled inFromCl above, so the only thing
782 * left to handle here is rte->lateral.
783 */
784 if (es->format != EXPLAIN_FORMAT_TEXT || rte->lateral)
785 ExplainPropertyBool("Lateral", rte->lateral, es);
786
787 /* Done with this RTE */
788 if (es->format == EXPLAIN_FORMAT_TEXT)
789 es->indent--;
790 ExplainCloseGroup("Range Table Entry", NULL, true, es);
791 }
792
793 /* Close the Range Table array before emitting PlannedStmt-level fields. */
794 ExplainCloseGroup("Range Table", "Range Table", false, es);
795
796 /*
797 * Print PlannedStmt fields that contain RTIs. These are properties of
798 * the PlannedStmt, not of individual RTEs, so they belong outside the
799 * Range Table array.
800 */
801 if (es->format != EXPLAIN_FORMAT_TEXT ||
802 !bms_is_empty(plannedstmt->unprunableRelids))
803 overexplain_bitmapset("Unprunable RTIs", plannedstmt->unprunableRelids,
804 es);
805 if (es->format != EXPLAIN_FORMAT_TEXT ||
806 !bms_is_empty(plannedstmt->resultRelationRelids))
807 overexplain_bitmapset("Result RTIs", plannedstmt->resultRelationRelids,
808 es);
809}
unsigned int Index
Definition c.h:757
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:4235
#define DEFAULT_LOCKMETHOD
Definition locktag.h:25
char * get_rel_name(Oid relid)
Definition lsyscache.c:2242
Oid get_rel_namespace(Oid relid)
Definition lsyscache.c:2266
char * get_namespace_name_or_temp(Oid nspid)
Definition lsyscache.c:3706
@ JOIN_SEMI
Definition nodes.h:315
@ JOIN_FULL
Definition nodes.h:303
@ JOIN_RIGHT
Definition nodes.h:304
@ JOIN_RIGHT_SEMI
Definition nodes.h:317
@ JOIN_LEFT
Definition nodes.h:302
@ JOIN_RIGHT_ANTI
Definition nodes.h:318
@ JOIN_ANTI
Definition nodes.h:316
@ RTE_JOIN
@ RTE_CTE
@ RTE_NAMEDTUPLESTORE
@ RTE_VALUES
@ RTE_SUBQUERY
@ RTE_RESULT
@ RTE_FUNCTION
@ RTE_TABLEFUNC
@ RTE_GROUP
@ RTE_GRAPH_TABLE
@ 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:375
static void overexplain_alias(const char *qlabel, Alias *alias, ExplainState *es)
unsigned int Oid
Bitmapset * resultRelationRelids
Definition plannodes.h:121
List * subrtinfos
Definition plannodes.h:132
Bitmapset * unprunableRelids
Definition plannodes.h:113
List * rtable
Definition plannodes.h:107

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(), overexplain_alias(), overexplain_bitmapset(), psprintf(), quote_identifier(), relname, PlannedStmt::resultRelationRelids, rt_fetch, PlannedStmt::rtable, RTE_CTE, RTE_FUNCTION, RTE_GRAPH_TABLE, 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 124 of file pg_overexplain.c.

126{
128
129 options->range_table = defGetBoolean(opt);
130}

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().