Change EXPLAIN output so that subplans and initplans (particularly CTEs)

are individually labeled, rather than just grouped under an "InitPlan"
or "SubPlan" heading.  This in turn makes it possible for decompilation of
a subplan reference to usefully identify which subplan it's referencing.
I also made InitPlans identify which parameter symbol(s) they compute,
so that references to those parameters elsewhere in the plan tree can
be connected to the initplan that will be executed.  Per a gripe from
Robert Haas about EXPLAIN output of a WITH query being inadequate,
plus some longstanding pet peeves of my own.
This commit is contained in:
Tom Lane 2009-04-05 19:59:40 +00:00
parent 329a5322e9
commit fbcce08046
7 changed files with 82 additions and 22 deletions

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.184 2009/01/02 20:42:00 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.185 2009/04/05 19:59:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -951,14 +951,14 @@ explain_outNode(StringInfo str,
{
ListCell *lst;
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " InitPlan\n");
foreach(lst, planstate->initPlan)
{
SubPlanState *sps = (SubPlanState *) lfirst(lst);
SubPlan *sp = (SubPlan *) sps->xprstate.expr;
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " %s\n", sp->plan_name);
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
@ -1099,14 +1099,14 @@ explain_outNode(StringInfo str,
{
ListCell *lst;
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " SubPlan\n");
foreach(lst, planstate->subPlan)
{
SubPlanState *sps = (SubPlanState *) lfirst(lst);
SubPlan *sp = (SubPlan *) sps->xprstate.expr;
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " %s\n", sp->plan_name);
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");

View File

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.428 2009/04/04 21:12:31 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.429 2009/04/05 19:59:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1116,6 +1116,7 @@ _copySubPlan(SubPlan *from)
COPY_NODE_FIELD(testexpr);
COPY_NODE_FIELD(paramIds);
COPY_SCALAR_FIELD(plan_id);
COPY_STRING_FIELD(plan_name);
COPY_SCALAR_FIELD(firstColType);
COPY_SCALAR_FIELD(firstColTypmod);
COPY_SCALAR_FIELD(useHashTable);

View File

@ -22,7 +22,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.351 2009/04/04 21:12:31 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.352 2009/04/05 19:59:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -341,6 +341,7 @@ _equalSubPlan(SubPlan *a, SubPlan *b)
COMPARE_NODE_FIELD(testexpr);
COMPARE_NODE_FIELD(paramIds);
COMPARE_SCALAR_FIELD(plan_id);
COMPARE_STRING_FIELD(plan_name);
COMPARE_SCALAR_FIELD(firstColType);
COMPARE_SCALAR_FIELD(firstColTypmod);
COMPARE_SCALAR_FIELD(useHashTable);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.357 2009/04/04 21:12:31 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.358 2009/04/05 19:59:40 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
@ -961,6 +961,7 @@ _outSubPlan(StringInfo str, SubPlan *node)
WRITE_NODE_FIELD(testexpr);
WRITE_NODE_FIELD(paramIds);
WRITE_INT_FIELD(plan_id);
WRITE_STRING_FIELD(plan_name);
WRITE_OID_FIELD(firstColType);
WRITE_INT_FIELD(firstColTypmod);
WRITE_BOOL_FIELD(useHashTable);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.147 2009/03/10 22:09:26 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.148 2009/04/05 19:59:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -412,8 +412,8 @@ build_subplan(PlannerInfo *root, Plan *plan, List *rtable,
int paramid;
/*
* Initialize the SubPlan node. Note plan_id isn't set till further down,
* likewise the cost fields.
* Initialize the SubPlan node. Note plan_id, plan_name, and cost fields
* are set further down.
*/
splan = makeNode(SubPlan);
splan->subLinkType = subLinkType;
@ -606,6 +606,30 @@ build_subplan(PlannerInfo *root, Plan *plan, List *rtable,
root->glob->rewindPlanIDs = bms_add_member(root->glob->rewindPlanIDs,
splan->plan_id);
/* Label the subplan for EXPLAIN purposes */
if (isInitPlan)
{
ListCell *lc;
int offset;
splan->plan_name = palloc(32 + 12 * list_length(splan->setParam));
sprintf(splan->plan_name, "InitPlan %d (returns ", splan->plan_id);
offset = strlen(splan->plan_name);
foreach(lc, splan->setParam)
{
sprintf(splan->plan_name + offset, "$%d%s",
lfirst_int(lc),
lnext(lc) ? "," : "");
offset += strlen(splan->plan_name + offset);
}
sprintf(splan->plan_name + offset, ")");
}
else
{
splan->plan_name = palloc(32);
sprintf(splan->plan_name, "SubPlan %d", splan->plan_id);
}
/* Lastly, fill in the cost estimates for use later */
cost_subplan(root, splan, plan);
@ -875,7 +899,7 @@ SS_process_ctes(PlannerInfo *root)
* Make a SubPlan node for it. This is just enough unlike
* build_subplan that we can't share code.
*
* Note plan_id isn't set till further down, likewise the cost fields.
* Note plan_id, plan_name, and cost fields are set further down.
*/
splan = makeNode(SubPlan);
splan->subLinkType = CTE_SUBLINK;
@ -931,6 +955,10 @@ SS_process_ctes(PlannerInfo *root)
root->cte_plan_ids = lappend_int(root->cte_plan_ids, splan->plan_id);
/* Label the subplan for EXPLAIN purposes */
splan->plan_name = palloc(4 + strlen(cte->ctename) + 1);
sprintf(splan->plan_name, "CTE %s", cte->ctename);
/* Lastly, fill in the cost estimates for use later */
cost_subplan(root, splan, plan);
}
@ -2134,5 +2162,10 @@ SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
prm = generate_new_param(root, resulttype, resulttypmod);
node->setParam = list_make1_int(prm->paramid);
/* Label the subplan for EXPLAIN purposes */
node->plan_name = palloc(64);
sprintf(node->plan_name, "InitPlan %d (returns $%d)",
node->plan_id, prm->paramid);
return prm;
}

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.296 2009/02/25 18:00:01 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.297 2009/04/05 19:59:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -4404,20 +4404,42 @@ get_rule_expr(Node *node, deparse_context *context,
case T_SubPlan:
{
SubPlan *subplan = (SubPlan *) node;
/*
* We cannot see an already-planned subplan in rule deparsing,
* only while EXPLAINing a query plan. For now, just punt.
* only while EXPLAINing a query plan. We don't try to
* reconstruct the original SQL, just reference the subplan
* that appears elsewhere in EXPLAIN's result.
*/
if (((SubPlan *) node)->useHashTable)
appendStringInfo(buf, "(hashed subplan)");
if (subplan->useHashTable)
appendStringInfo(buf, "(hashed %s)", subplan->plan_name);
else
appendStringInfo(buf, "(subplan)");
appendStringInfo(buf, "(%s)", subplan->plan_name);
}
break;
case T_AlternativeSubPlan:
/* As above, just punt */
appendStringInfo(buf, "(alternative subplans)");
{
AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
ListCell *lc;
/* As above, this can only happen during EXPLAIN */
appendStringInfo(buf, "(alternatives: ");
foreach(lc, asplan->subplans)
{
SubPlan *splan = (SubPlan *) lfirst(lc);
Assert(IsA(splan, SubPlan));
if (splan->useHashTable)
appendStringInfo(buf, "hashed %s", splan->plan_name);
else
appendStringInfo(buf, "%s", splan->plan_name);
if (lnext(lc))
appendStringInfo(buf, " or ");
}
appendStringInfo(buf, ")");
}
break;
case T_FieldSelect:

View File

@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.147 2009/03/10 22:09:26 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.148 2009/04/05 19:59:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -502,6 +502,8 @@ typedef struct SubPlan
List *paramIds; /* IDs of Params embedded in the above */
/* Identification of the Plan tree to use: */
int plan_id; /* Index (from 1) in PlannedStmt.subplans */
/* Identification of the SubPlan for EXPLAIN and debugging purposes: */
char *plan_name; /* A name assigned during planning */
/* Extra data useful for determining subplan's output type: */
Oid firstColType; /* Type of first column of subplan result */
int32 firstColTypmod; /* Typmod of first column of subplan result */