Fix inheritance_planner() to delete dummy subplans from its Append plan
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 5 Aug 2006 17:21:52 +0000 (17:21 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 5 Aug 2006 17:21:52 +0000 (17:21 +0000)
list, when some of the child rels have been excluded by constraint
exclusion.  This doesn't save a huge amount of time but it'll save some,
and it makes the EXPLAIN output look saner.  We already did the
equivalent thing in set_append_rel_pathlist(), but not here.

src/backend/optimizer/plan/planner.c

index 42ae15cd4832fdc029dec3ccc5263f943dac43e3..0eeaff064ff4f1f25499436b544a687da7cc4f13 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.206 2006/08/02 01:59:46 joe Exp $
+ *   $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.207 2006/08/05 17:21:52 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -58,6 +58,7 @@ static Node *preprocess_expression(PlannerInfo *root, Node *expr, int kind);
 static void preprocess_qual_conditions(PlannerInfo *root, Node *jtnode);
 static Plan *inheritance_planner(PlannerInfo *root);
 static Plan *grouping_planner(PlannerInfo *root, double tuple_fraction);
+static bool is_dummy_plan(Plan *plan);
 static double preprocess_limit(PlannerInfo *root,
                 double tuple_fraction,
                 int64 *offset_est, int64 *count_est);
@@ -553,12 +554,11 @@ inheritance_planner(PlannerInfo *root)
    Query      *parse = root->parse;
    int         parentRTindex = parse->resultRelation;
    List       *subplans = NIL;
+   List       *rtable = NIL;
    List       *tlist = NIL;
    PlannerInfo subroot;
    ListCell   *l;
 
-   subroot.parse = NULL;       /* catch it if no matches in loop */
-
    parse->resultRelations = NIL;
 
    foreach(l, root->append_rel_list)
@@ -570,10 +570,6 @@ inheritance_planner(PlannerInfo *root)
        if (appinfo->parent_relid != parentRTindex)
            continue;
 
-       /* Build target-relations list for the executor */
-       parse->resultRelations = lappend_int(parse->resultRelations,
-                                            appinfo->child_relid);
-
        /*
         * Generate modified query with this rel as target.  We have to be
         * prepared to translate varnos in in_info_list as well as in the
@@ -592,13 +588,39 @@ inheritance_planner(PlannerInfo *root)
        /* Generate plan */
        subplan = grouping_planner(&subroot, 0.0 /* retrieve all tuples */ );
 
-       subplans = lappend(subplans, subplan);
+       /*
+        * If this child rel was excluded by constraint exclusion, exclude
+        * it from the plan.
+        */
+       if (is_dummy_plan(subplan))
+           continue;
 
-       /* Save preprocessed tlist from first rel for use in Append */
-       if (tlist == NIL)
+       /* Save rtable and tlist from first rel for use below */
+       if (subplans == NIL)
+       {
+           rtable = subroot.parse->rtable;
            tlist = subplan->targetlist;
+       }
+
+       subplans = lappend(subplans, subplan);
+
+       /* Build target-relations list for the executor */
+       parse->resultRelations = lappend_int(parse->resultRelations,
+                                            appinfo->child_relid);
    }
 
+   /* Mark result as unordered (probably unnecessary) */
+   root->query_pathkeys = NIL;
+
+   /*
+    * If we managed to exclude every child rel, return a dummy plan
+    */
+   if (subplans == NIL)
+       return (Plan *) make_result(tlist,
+                                   (Node *) list_make1(makeBoolConst(false,
+                                                                     false)),
+                                   NULL);
+
    /*
     * Planning might have modified the rangetable, due to changes of the
     * Query structures inside subquery RTEs.  We have to ensure that this
@@ -610,10 +632,7 @@ inheritance_planner(PlannerInfo *root)
     *
     * XXX should clean this up someday
     */
-   parse->rtable = subroot.parse->rtable;
-
-   /* Mark result as unordered (probably unnecessary) */
-   root->query_pathkeys = NIL;
+   parse->rtable = rtable;
 
    return (Plan *) make_append(subplans, true, tlist);
 }
@@ -1072,6 +1091,35 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
    return result_plan;
 }
 
+/*
+ * Detect whether a plan node is a "dummy" plan created when a relation
+ * is deemed not to need scanning due to constraint exclusion.
+ *
+ * Currently, such dummy plans are Result nodes with constant FALSE
+ * filter quals.
+ */
+static bool
+is_dummy_plan(Plan *plan)
+{
+   if (IsA(plan, Result))
+   {
+       List *rcqual = (List *) ((Result *) plan)->resconstantqual;
+
+       if (list_length(rcqual) == 1)
+       {
+           Const *constqual = (Const *) linitial(rcqual);
+
+           if (constqual && IsA(constqual, Const))
+           {
+               if (!constqual->constisnull &&
+                   !DatumGetBool(constqual->constvalue))
+                   return true;
+           }
+       }
+   }
+   return false;
+}
+
 /*
  * preprocess_limit - do pre-estimation for LIMIT and/or OFFSET clauses
  *