Include the target table in EXPLAIN output for ModifyTable nodes.

Per discussion, this seems important for plans involving writable CTEs,
since there can now be more than one ModifyTable node in the plan.

To retain the same formatting as for target tables of scan nodes, we
show only one target table, which will be the parent table in case of
an UPDATE or DELETE on an inheritance tree.  Individual child tables
can be determined by inspecting the child plan trees if needed.
This commit is contained in:
Tom Lane 2011-03-01 11:32:13 -05:00
parent 59d6a75942
commit 97c4ee94ad

View File

@ -84,6 +84,8 @@ static void show_hash_info(HashState *hashstate, ExplainState *es);
static void show_foreignscan_info(ForeignScanState *fsstate, ExplainState *es); static void show_foreignscan_info(ForeignScanState *fsstate, ExplainState *es);
static const char *explain_get_index_name(Oid indexId); static const char *explain_get_index_name(Oid indexId);
static void ExplainScanTarget(Scan *plan, ExplainState *es); static void ExplainScanTarget(Scan *plan, ExplainState *es);
static void ExplainModifyTarget(ModifyTable *plan, ExplainState *es);
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es);
static void ExplainMemberNodes(List *plans, PlanState **planstates, static void ExplainMemberNodes(List *plans, PlanState **planstates,
List *ancestors, ExplainState *es); List *ancestors, ExplainState *es);
static void ExplainSubPlans(List *plans, List *ancestors, static void ExplainSubPlans(List *plans, List *ancestors,
@ -851,6 +853,9 @@ ExplainNode(PlanState *planstate, List *ancestors,
ExplainPropertyText("Index Name", indexname, es); ExplainPropertyText("Index Name", indexname, es);
} }
break; break;
case T_ModifyTable:
ExplainModifyTarget((ModifyTable *) plan, es);
break;
case T_NestLoop: case T_NestLoop:
case T_MergeJoin: case T_MergeJoin:
case T_HashJoin: case T_HashJoin:
@ -1553,15 +1558,40 @@ explain_get_index_name(Oid indexId)
*/ */
static void static void
ExplainScanTarget(Scan *plan, ExplainState *es) ExplainScanTarget(Scan *plan, ExplainState *es)
{
ExplainTargetRel((Plan *) plan, plan->scanrelid, es);
}
/*
* Show the target of a ModifyTable node
*/
static void
ExplainModifyTarget(ModifyTable *plan, ExplainState *es)
{
Index rti;
/*
* We show the name of the first target relation. In multi-target-table
* cases this should always be the parent of the inheritance tree.
*/
Assert(plan->resultRelations != NIL);
rti = linitial_int(plan->resultRelations);
ExplainTargetRel((Plan *) plan, rti, es);
}
/*
* Show the target relation of a scan or modify node
*/
static void
ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
{ {
char *objectname = NULL; char *objectname = NULL;
char *namespace = NULL; char *namespace = NULL;
const char *objecttag = NULL; const char *objecttag = NULL;
RangeTblEntry *rte; RangeTblEntry *rte;
if (plan->scanrelid <= 0) /* Is this still possible? */ rte = rt_fetch(rti, es->rtable);
return;
rte = rt_fetch(plan->scanrelid, es->rtable);
switch (nodeTag(plan)) switch (nodeTag(plan))
{ {
@ -1570,6 +1600,7 @@ ExplainScanTarget(Scan *plan, ExplainState *es)
case T_BitmapHeapScan: case T_BitmapHeapScan:
case T_TidScan: case T_TidScan:
case T_ForeignScan: case T_ForeignScan:
case T_ModifyTable:
/* Assert it's on a real relation */ /* Assert it's on a real relation */
Assert(rte->rtekind == RTE_RELATION); Assert(rte->rtekind == RTE_RELATION);
objectname = get_rel_name(rte->relid); objectname = get_rel_name(rte->relid);