]> granicus.if.org Git - postgresql/commitdiff
Change EXPLAIN output so that subplans and initplans (particularly CTEs)
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 5 Apr 2009 19:59:40 +0000 (19:59 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 5 Apr 2009 19:59:40 +0000 (19:59 +0000)
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.

src/backend/commands/explain.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/optimizer/plan/subselect.c
src/backend/utils/adt/ruleutils.c
src/include/nodes/primnodes.h

index 8ad877e1652af27dff6b932d1d0d8c80f4761c1f..d8f27a1175b412d0dc3f893c175f4f7586da4d96 100644 (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, "    ->  ");
index bbeac65597083d324a9821ca1282a468a4289201..5fac94f86317f082ee835c29c5dd9be0baf82e69 100644 (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);
index c5f09cab82ae006903eea3836fca54a317f3e7d0..36f2bcc2d517b4203b06766bfcab7998061352d4 100644 (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);
index f3ca8d36228a07c5aa7e72ded6c0f13c741baef2..67f051311fd37570a0e75fae2cff3960ce8073e1 100644 (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);
index 2cf177ab01eebfcbaac63aa803cd954ab34d0b52..595ff1d46bb6338e05867b776802c8c8767f3e9f 100644 (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;
 }
index f05e6a2cb938c675cbaa0194d14ac0021d32d768..8d06f54e479d46b32eae5ab7a471a498ca068a5a 100644 (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:
index 9cb4e8e50ee3398cc58c13e45ad09ae808d986f9..7fc7c00d63eb31914985c72682dddb1a71bb7558 100644 (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 */