overexplain_range_table(PlannedStmt *plannedstmt, ExplainState *es)
{
Index rti;
+ ListCell *lc_subrtinfo = list_head(plannedstmt->subrtinfos);
+ SubPlanRTInfo *rtinfo = NULL;
/* Open group, one entry per RangeTblEntry */
ExplainOpenGroup("Range Table", "Range Table", false, es);
RangeTblEntry *rte = rt_fetch(rti, plannedstmt->rtable);
char *kind = NULL;
char *relkind;
+ SubPlanRTInfo *next_rtinfo;
+
+ /* Advance to next SubRTInfo, if it's time. */
+ if (lc_subrtinfo != NULL)
+ {
+ next_rtinfo = lfirst(lc_subrtinfo);
+ if (rti > next_rtinfo->rtoffset)
+ {
+ rtinfo = next_rtinfo;
+ lc_subrtinfo = lnext(plannedstmt->subrtinfos, lc_subrtinfo);
+ }
+ }
/* NULL entries are possible; skip them */
if (rte == NULL)
ExplainPropertyBool("In From Clause", rte->inFromCl, es);
}
+ /*
+ * Indicate which subplan is the origin of which RTE. Note dummy
+ * subplans. Here again, we crunch more onto one line in text format.
+ */
+ if (rtinfo != NULL)
+ {
+ if (es->format == EXPLAIN_FORMAT_TEXT)
+ {
+ if (!rtinfo->dummy)
+ ExplainPropertyText("Subplan", rtinfo->plan_name, es);
+ else
+ ExplainPropertyText("Subplan",
+ psprintf("%s (dummy)",
+ rtinfo->plan_name), es);
+ }
+ else
+ {
+ ExplainPropertyText("Subplan", rtinfo->plan_name, es);
+ ExplainPropertyBool("Subplan Is Dummy", rtinfo->dummy, es);
+ }
+ }
+
/* rte->alias is optional; rte->eref is requested */
if (rte->alias != NULL)
overexplain_alias("Alias", rte->alias, es);
result->unprunableRelids = bms_difference(glob->allRelids,
glob->prunableRelids);
result->permInfos = glob->finalrteperminfos;
+ result->subrtinfos = glob->subrtinfos;
result->resultRelations = glob->resultRelations;
result->firstResultRels = glob->firstResultRels;
result->appendRelations = glob->appendRelations;
Index rti;
ListCell *lc;
+ /*
+ * Record enough information to make it possible for code that looks at
+ * the final range table to understand how it was constructed. (If
+ * finalrtable is still NIL, then this is the very topmost PlannerInfo,
+ * which will always have plan_name == NULL and rtoffset == 0; we omit the
+ * degenerate list entry.)
+ */
+ if (root->glob->finalrtable != NIL)
+ {
+ SubPlanRTInfo *rtinfo = makeNode(SubPlanRTInfo);
+
+ rtinfo->plan_name = root->plan_name;
+ rtinfo->rtoffset = list_length(root->glob->finalrtable);
+
+ /* When recursing = true, it's an unplanned or dummy subquery. */
+ rtinfo->dummy = recursing;
+
+ root->glob->subrtinfos = lappend(root->glob->subrtinfos, rtinfo);
+ }
+
/*
* Add the query's own RTEs to the flattened rangetable.
*
*/
List *subplans;
+ /* a list of SubPlanRTInfo objects */
+ List *subrtinfos;
+
/* indices of subplans that require REWIND */
Bitmapset *rewindPlanIDs;
MONOTONICFUNC_BOTH = MONOTONICFUNC_INCREASING | MONOTONICFUNC_DECREASING,
} MonotonicFunction;
+/*
+ * SubPlanRTInfo
+ *
+ * Information about which range table entries came from which subquery
+ * planning cycles.
+ */
+typedef struct SubPlanRTInfo
+{
+ NodeTag type;
+ char *plan_name;
+ Index rtoffset;
+ bool dummy;
+} SubPlanRTInfo;
+
#endif /* PLANNODES_H */