Seq Scan on daucus vegetables
Filter: (genus = 'daucus'::text)
Scan RTI: 2
+ Elided Node Type: Append
+ Elided Node RTIs: 1
RTI 1 (relation, inherited, in-from-clause):
Eref: vegetables (id, name, genus)
Relation: vegetables
Relation Kind: relation
Relation Lock Mode: AccessShareLock
Unprunable RTIs: 1 2
-(16 rows)
+(18 rows)
-- Also test a case that involves a write.
EXPLAIN (RANGE_TABLE, COSTS OFF)
*/
if (options->range_table)
{
+ bool opened_elided_nodes = false;
+
switch (nodeTag(plan))
{
case T_SeqScan:
default:
break;
}
+
+ foreach_node(ElidedNode, n, es->pstmt->elidedNodes)
+ {
+ char *elidednodetag;
+
+ if (n->plan_node_id != plan->plan_node_id)
+ continue;
+
+ if (!opened_elided_nodes)
+ {
+ ExplainOpenGroup("Elided Nodes", "Elided Nodes", false, es);
+ opened_elided_nodes = true;
+ }
+
+ switch (n->elided_type)
+ {
+ case T_Append:
+ elidednodetag = "Append";
+ break;
+ case T_MergeAppend:
+ elidednodetag = "MergeAppend";
+ break;
+ case T_SubqueryScan:
+ elidednodetag = "SubqueryScan";
+ break;
+ default:
+ elidednodetag = psprintf("%d", n->elided_type);
+ break;
+ }
+
+ ExplainOpenGroup("Elided Node", NULL, true, es);
+ ExplainPropertyText("Elided Node Type", elidednodetag, es);
+ overexplain_bitmapset("Elided Node RTIs", n->relids, es);
+ ExplainCloseGroup("Elided Node", NULL, true, es);
+ }
+ if (opened_elided_nodes)
+ ExplainCloseGroup("Elided Nodes", "Elided Nodes", false, es);
}
}
result->paramExecTypes = glob->paramExecTypes;
/* utilityStmt should be null, but we might as well copy it */
result->utilityStmt = parse->utilityStmt;
+ result->elidedNodes = glob->elidedNodes;
result->stmt_location = parse->stmt_location;
result->stmt_len = parse->stmt_len;
List *runcondition,
Plan *plan);
+static void record_elided_node(PlannerGlobal *glob, int plan_node_id,
+ NodeTag elided_type, Bitmapset *relids);
+
/*****************************************************************************
*
if (trivial_subqueryscan(plan))
{
+ Index scanrelid;
+
/*
* We can omit the SubqueryScan node and just pull up the subplan.
*/
result = clean_up_removed_plan_level((Plan *) plan, plan->subplan);
+
+ /* Remember that we removed a SubqueryScan */
+ scanrelid = plan->scan.scanrelid + rtoffset;
+ record_elided_node(root->glob, plan->subplan->plan_node_id,
+ T_SubqueryScan, bms_make_singleton(scanrelid));
}
else
{
Plan *p = (Plan *) linitial(aplan->appendplans);
if (p->parallel_aware == aplan->plan.parallel_aware)
- return clean_up_removed_plan_level((Plan *) aplan, p);
+ {
+ Plan *result;
+
+ result = clean_up_removed_plan_level((Plan *) aplan, p);
+
+ /* Remember that we removed an Append */
+ record_elided_node(root->glob, p->plan_node_id, T_Append,
+ offset_relid_set(aplan->apprelids, rtoffset));
+
+ return result;
+ }
}
/*
Plan *p = (Plan *) linitial(mplan->mergeplans);
if (p->parallel_aware == mplan->plan.parallel_aware)
- return clean_up_removed_plan_level((Plan *) mplan, p);
+ {
+ Plan *result;
+
+ result = clean_up_removed_plan_level((Plan *) mplan, p);
+
+ /* Remember that we removed a MergeAppend */
+ record_elided_node(root->glob, p->plan_node_id, T_MergeAppend,
+ offset_relid_set(mplan->apprelids, rtoffset));
+
+ return result;
+ }
}
/*
return expression_tree_walker(node, extract_query_dependencies_walker,
context);
}
+
+/*
+ * Record some details about a node removed from the plan during setrefs
+ * procesing, for the benefit of code trying to reconstruct planner decisions
+ * from examination of the final plan tree.
+ */
+static void
+record_elided_node(PlannerGlobal *glob, int plan_node_id,
+ NodeTag elided_type, Bitmapset *relids)
+{
+ ElidedNode *n = makeNode(ElidedNode);
+
+ n->plan_node_id = plan_node_id;
+ n->elided_type = elided_type;
+ n->relids = relids;
+
+ glob->elidedNodes = lappend(glob->elidedNodes, n);
+}
/* type OIDs for PARAM_EXEC Params */
List *paramExecTypes;
+ /* info about nodes elided from the plan during setrefs processing */
+ List *elidedNodes;
+
/* highest PlaceHolderVar ID assigned */
Index lastPHId;
/* non-null if this is utility stmt */
Node *utilityStmt;
+ /* info about nodes elided from the plan during setrefs processing */
+ List *elidedNodes;
+
/* statement location in source string (copied from Query) */
/* start location, or -1 if unknown */
ParseLoc stmt_location;
bool dummy;
} SubPlanRTInfo;
+/*
+ * ElidedNode
+ *
+ * Information about nodes elided from the final plan tree: trivial subquery
+ * scans, and single-child Append and MergeAppend nodes.
+ */
+typedef struct ElidedNode
+{
+ NodeTag type;
+ int plan_node_id;
+ NodeTag elided_type;
+ Bitmapset *relids;
+} ElidedNode;
+
#endif /* PLANNODES_H */
ExplainOptionHandler
overexplain_options
SubPlanRTInfo
+ElidedNode