Fix EXPLAIN output for cases where parent table is excluded by constraints.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 17 Feb 2015 23:04:11 +0000 (18:04 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 17 Feb 2015 23:04:11 +0000 (18:04 -0500)
The previous coding in EXPLAIN always labeled a ModifyTable node with the
name of the target table affected by its first child plan.  When originally
written, this was necessarily the parent table of the inheritance tree,
so everything was unconfusing.  But when we added NO INHERIT constraints,
it became possible for the parent table to be deleted from the plan by
constraint exclusion while still leaving child tables present.  This led to
the ModifyTable plan node being labeled with the first surviving child,
which was deemed confusing.  Fix it by retaining the parent table's RT
index in a new field in ModifyTable.

Etsuro Fujita, reviewed by Ashutosh Bapat and myself

src/backend/commands/explain.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/outfuncs.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/plan/setrefs.c
src/include/nodes/plannodes.h
src/include/optimizer/planmain.h

index 7cfc9bb612a83f3b4ee938bb835508ab19daa5e4..a951c55ed3468da75f7707168583eae4e45ebeb4 100644 (file)
@@ -736,9 +736,8 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
                                        ((Scan *) plan)->scanrelid);
            break;
        case T_ModifyTable:
-           /* cf ExplainModifyTarget */
            *rels_used = bms_add_member(*rels_used,
-                     linitial_int(((ModifyTable *) plan)->resultRelations));
+                                   ((ModifyTable *) plan)->nominalRelation);
            break;
        default:
            break;
@@ -2192,16 +2191,7 @@ ExplainScanTarget(Scan *plan, ExplainState *es)
 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);
+   ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
 }
 
 /*
index f1a24f58af336d968e114a454f8a935a696ea3b5..e5b0dce477d2489bac096cc007202f8be1891539 100644 (file)
@@ -175,6 +175,7 @@ _copyModifyTable(const ModifyTable *from)
     */
    COPY_SCALAR_FIELD(operation);
    COPY_SCALAR_FIELD(canSetTag);
+   COPY_SCALAR_FIELD(nominalRelation);
    COPY_NODE_FIELD(resultRelations);
    COPY_SCALAR_FIELD(resultRelIndex);
    COPY_NODE_FIELD(plans);
index dd1278bba8ddcb0e854ca93caa55ec4b390e6996..84864480624129fb4c3a8e05c9c435ace8960e73 100644 (file)
@@ -327,6 +327,7 @@ _outModifyTable(StringInfo str, const ModifyTable *node)
 
    WRITE_ENUM_FIELD(operation, CmdType);
    WRITE_BOOL_FIELD(canSetTag);
+   WRITE_UINT_FIELD(nominalRelation);
    WRITE_NODE_FIELD(resultRelations);
    WRITE_INT_FIELD(resultRelIndex);
    WRITE_NODE_FIELD(plans);
index 655be8155a43bec44ea72a46bf3287ceb101bbc3..76ba1bfa8d28fcbea8421c44b32d9daa624fdcc4 100644 (file)
@@ -4809,6 +4809,7 @@ make_result(PlannerInfo *root,
 ModifyTable *
 make_modifytable(PlannerInfo *root,
                 CmdType operation, bool canSetTag,
+                Index nominalRelation,
                 List *resultRelations, List *subplans,
                 List *withCheckOptionLists, List *returningLists,
                 List *rowMarks, int epqParam)
@@ -4857,6 +4858,7 @@ make_modifytable(PlannerInfo *root,
 
    node->operation = operation;
    node->canSetTag = canSetTag;
+   node->nominalRelation = nominalRelation;
    node->resultRelations = resultRelations;
    node->resultRelIndex = -1;  /* will be set correctly in setrefs.c */
    node->plans = subplans;
index 9cbbcfb19d49a6ea2391000ccbb592cf033af3f0..5c4884f46b9c0ce9b4f80640dcbc4be7e50d0e47 100644 (file)
@@ -607,6 +607,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
            plan = (Plan *) make_modifytable(root,
                                             parse->commandType,
                                             parse->canSetTag,
+                                            parse->resultRelation,
                                       list_make1_int(parse->resultRelation),
                                             list_make1(plan),
                                             withCheckOptionLists,
@@ -790,6 +791,7 @@ inheritance_planner(PlannerInfo *root)
 {
    Query      *parse = root->parse;
    int         parentRTindex = parse->resultRelation;
+   int         nominalRelation = -1;
    List       *final_rtable = NIL;
    int         save_rel_array_size = 0;
    RelOptInfo **save_rel_array = NULL;
@@ -924,6 +926,20 @@ inheritance_planner(PlannerInfo *root)
         */
        appinfo->child_relid = subroot.parse->resultRelation;
 
+       /*
+        * We'll use the first child relation (even if it's excluded) as the
+        * nominal target relation of the ModifyTable node.  Because of the
+        * way expand_inherited_rtentry works, this should always be the RTE
+        * representing the parent table in its role as a simple member of the
+        * inheritance set.  (It would be logically cleaner to use the
+        * inheritance parent RTE as the nominal target; but since that RTE
+        * will not be otherwise referenced in the plan, doing so would give
+        * rise to confusing use of multiple aliases in EXPLAIN output for
+        * what the user will think is the "same" table.)
+        */
+       if (nominalRelation < 0)
+           nominalRelation = appinfo->child_relid;
+
        /*
         * If this child rel was excluded by constraint exclusion, exclude it
         * from the result plan.
@@ -1051,6 +1067,7 @@ inheritance_planner(PlannerInfo *root)
    return (Plan *) make_modifytable(root,
                                     parse->commandType,
                                     parse->canSetTag,
+                                    nominalRelation,
                                     resultRelations,
                                     subplans,
                                     withCheckOptionLists,
@@ -2260,7 +2277,7 @@ preprocess_rowmarks(PlannerInfo *root)
            newrc->markType = ROW_MARK_REFERENCE;
        else
            newrc->markType = ROW_MARK_COPY;
-       newrc->waitPolicy = LockWaitBlock;  /* doesn't matter */
+       newrc->waitPolicy = LockWaitBlock;      /* doesn't matter */
        newrc->isParent = false;
 
        prowmarks = lappend(prowmarks, newrc);
index 7703946c853abb4579dec27357f2721b2edbcd09..57195e5d68ff8e1563d03b69acf693cceafca900 100644 (file)
@@ -754,6 +754,8 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
                    splan->plan.targetlist = copyObject(linitial(newRL));
                }
 
+               splan->nominalRelation += rtoffset;
+
                foreach(l, splan->resultRelations)
                {
                    lfirst_int(l) += rtoffset;
index 316c9ced599dce75ba3ab30a631bbd1e9a4a295e..f6683f05e301fe3426297029f62cfdcc05605d26 100644 (file)
@@ -70,7 +70,7 @@ typedef struct PlannedStmt
 
    int         nParamExec;     /* number of PARAM_EXEC Params used */
 
-   bool        hasRowSecurity; /* row security applied? */
+   bool        hasRowSecurity; /* row security applied? */
 
 } PlannedStmt;
 
@@ -174,6 +174,7 @@ typedef struct ModifyTable
    Plan        plan;
    CmdType     operation;      /* INSERT, UPDATE, or DELETE */
    bool        canSetTag;      /* do we set the command tag/es_processed? */
+   Index       nominalRelation;    /* Parent RT index for use of EXPLAIN */
    List       *resultRelations;    /* integer list of RT indexes */
    int         resultRelIndex; /* index of first resultRel in plan's list */
    List       *plans;          /* plan(s) producing source data */
index 082f7d7f145626bf216cdf3cd8ed4937be22f8fa..fa72918d1bbadad9e2865814f58abd08bbe0c579 100644 (file)
@@ -82,6 +82,7 @@ extern Result *make_result(PlannerInfo *root, List *tlist,
            Node *resconstantqual, Plan *subplan);
 extern ModifyTable *make_modifytable(PlannerInfo *root,
                 CmdType operation, bool canSetTag,
+                Index nominalRelation,
                 List *resultRelations, List *subplans,
                 List *withCheckOptionLists, List *returningLists,
                 List *rowMarks, int epqParam);