Finish refactoring make_foo() functions in createplan.c.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 8 Mar 2016 21:28:27 +0000 (16:28 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 8 Mar 2016 21:28:34 +0000 (16:28 -0500)
This patch removes some redundant cost calculations that I left for later
cleanup in commit 3fc6e2d7f5b652b4.  There's now a uniform policy that the
make_foo() convenience functions don't do any cost calculations.  Most of
their callers copy costs from the source Path node, and for those that
don't, the calculation in the make_foo() function wasn't necessarily right
anyhow.  (make_result() was particularly a mess, as it was serving multiple
callers using cost calcs designed for only the first one or two that had
ever existed.)  Aside from saving a few cycles, this ensures that what
EXPLAIN prints matches the costs we used for planning purposes.  It does
not change any planner decisions, since the decisions are already made.

src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/planmain.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/util/pathnode.c
src/include/optimizer/pathnode.h

index 88c72792c58686c7228328752f465122232a6b3b..3024ff9f7880525f436fdf7397bd4196e31281dd 100644 (file)
@@ -87,6 +87,7 @@ static Plan *create_unique_plan(PlannerInfo *root, UniquePath *best_path,
                   int flags);
 static Gather *create_gather_plan(PlannerInfo *root, GatherPath *best_path);
 static Plan *create_projection_plan(PlannerInfo *root, ProjectionPath *best_path);
+static Plan *inject_projection_plan(Plan *subplan, List *tlist);
 static Sort *create_sort_plan(PlannerInfo *root, SortPath *best_path, int flags);
 static Group *create_group_plan(PlannerInfo *root, GroupPath *best_path);
 static Unique *create_upper_unique_plan(PlannerInfo *root, UpperUniquePath *best_path,
@@ -155,6 +156,8 @@ static List *get_switched_clauses(List *clauses, Relids outerrelids);
 static List *order_qual_clauses(PlannerInfo *root, List *clauses);
 static void copy_generic_path_info(Plan *dest, Path *src);
 static void copy_plan_costsize(Plan *dest, Plan *src);
+static void label_sort_with_costsize(PlannerInfo *root, Sort *plan,
+                        double limit_tuples);
 static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid);
 static SampleScan *make_samplescan(List *qptlist, List *qpqual, Index scanrelid,
                TableSampleClause *tsc);
@@ -223,12 +226,10 @@ static MergeJoin *make_mergejoin(List *tlist,
               bool *mergenullsfirst,
               Plan *lefttree, Plan *righttree,
               JoinType jointype);
-static Sort *make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
+static Sort *make_sort(Plan *lefttree, int numCols,
          AttrNumber *sortColIdx, Oid *sortOperators,
-         Oid *collations, bool *nullsFirst,
-         double limit_tuples);
-static Plan *prepare_sort_from_pathkeys(PlannerInfo *root,
-                          Plan *lefttree, List *pathkeys,
+         Oid *collations, bool *nullsFirst);
+static Plan *prepare_sort_from_pathkeys(Plan *lefttree, List *pathkeys,
                           Relids relids,
                           const AttrNumber *reqColIdx,
                           bool adjust_tlist_in_place,
@@ -240,12 +241,9 @@ static Plan *prepare_sort_from_pathkeys(PlannerInfo *root,
 static EquivalenceMember *find_ec_member_for_tle(EquivalenceClass *ec,
                       TargetEntry *tle,
                       Relids relids);
-static Sort *make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree,
-                       List *pathkeys, double limit_tuples);
-static Sort *make_sort_from_sortclauses(PlannerInfo *root, List *sortcls,
-                          Plan *lefttree);
-static Sort *make_sort_from_groupcols(PlannerInfo *root,
-                        List *groupcls,
+static Sort *make_sort_from_pathkeys(Plan *lefttree, List *pathkeys);
+static Sort *make_sort_from_sortclauses(List *sortcls, Plan *lefttree);
+static Sort *make_sort_from_groupcols(List *groupcls,
                         AttrNumber *grpColIdx,
                         Plan *lefttree);
 static Material *make_material(Plan *lefttree);
@@ -272,10 +270,7 @@ static SetOp *make_setop(SetOpCmd cmd, SetOpStrategy strategy, Plan *lefttree,
           long numGroups);
 static LockRows *make_lockrows(Plan *lefttree, List *rowMarks, int epqParam);
 static Limit *make_limit(Plan *lefttree, Node *limitOffset, Node *limitCount);
-static Result *make_result(PlannerInfo *root,
-           List *tlist,
-           Node *resconstantqual,
-           Plan *subplan);
+static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
 static ModifyTable *make_modifytable(PlannerInfo *root,
                 CmdType operation, bool canSetTag,
                 Index nominalRelation,
@@ -831,22 +826,13 @@ get_gating_quals(PlannerInfo *root, List *quals)
  *   Deal with pseudoconstant qual clauses
  *
  * Add a gating Result node atop the already-built plan.
- *
- * Note that we don't change cost or size estimates when doing gating.
- * The costs of qual eval were already folded into the plan's startup cost.
- * Leaving the size alone amounts to assuming that the gating qual will
- * succeed, which is the conservative estimate for planning upper queries.
- * We certainly don't want to assume the output size is zero (unless the
- * gating qual is actually constant FALSE, and that case is dealt with in
- * clausesel.c).  Interpolating between the two cases is silly, because
- * it doesn't reflect what will really happen at runtime, and besides which
- * in most cases we have only a very bad idea of the probability of the gating
- * qual being true.
  */
 static Plan *
 create_gating_plan(PlannerInfo *root, Path *path, Plan *plan,
                   List *gating_quals)
 {
+   Plan       *gplan;
+
    Assert(gating_quals);
 
    /*
@@ -854,10 +840,25 @@ create_gating_plan(PlannerInfo *root, Path *path, Plan *plan,
     * tlist; that's never a wrong choice, even if the parent node didn't ask
     * for CP_EXACT_TLIST.
     */
-   return (Plan *) make_result(root,
-                               build_path_tlist(root, path),
-                               (Node *) gating_quals,
-                               plan);
+   gplan = (Plan *) make_result(build_path_tlist(root, path),
+                                (Node *) gating_quals,
+                                plan);
+
+   /*
+    * Notice that we don't change cost or size estimates when doing gating.
+    * The costs of qual eval were already included in the subplan's cost.
+    * Leaving the size alone amounts to assuming that the gating qual will
+    * succeed, which is the conservative estimate for planning upper queries.
+    * We certainly don't want to assume the output size is zero (unless the
+    * gating qual is actually constant FALSE, and that case is dealt with in
+    * clausesel.c).  Interpolating between the two cases is silly, because it
+    * doesn't reflect what will really happen at runtime, and besides which
+    * in most cases we have only a very bad idea of the probability of the
+    * gating qual being true.
+    */
+   copy_plan_costsize(gplan, plan);
+
+   return gplan;
 }
 
 /*
@@ -945,11 +946,16 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
    if (best_path->subpaths == NIL)
    {
        /* Generate a Result plan with constant-FALSE gating qual */
-       return (Plan *) make_result(root,
-                                   tlist,
+       Plan       *plan;
+
+       plan = (Plan *) make_result(tlist,
                                    (Node *) list_make1(makeBoolConst(false,
                                                                      false)),
                                    NULL);
+
+       copy_generic_path_info(plan, (Path *) best_path);
+
+       return plan;
    }
 
    /* Build the plan for each child */
@@ -973,6 +979,8 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
 
    plan = make_append(subplans, tlist);
 
+   copy_generic_path_info(&plan->plan, (Path *) best_path);
+
    return (Plan *) plan;
 }
 
@@ -1006,7 +1014,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
    plan->righttree = NULL;
 
    /* Compute sort column info, and adjust MergeAppend's tlist as needed */
-   (void) prepare_sort_from_pathkeys(root, plan, pathkeys,
+   (void) prepare_sort_from_pathkeys(plan, pathkeys,
                                      best_path->path.parent->relids,
                                      NULL,
                                      true,
@@ -1036,7 +1044,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
        subplan = create_plan_recurse(root, subpath, CP_EXACT_TLIST);
 
        /* Compute sort column info, and adjust subplan's tlist as needed */
-       subplan = prepare_sort_from_pathkeys(root, subplan, pathkeys,
+       subplan = prepare_sort_from_pathkeys(subplan, pathkeys,
                                             subpath->parent->relids,
                                             node->sortColIdx,
                                             false,
@@ -1065,10 +1073,14 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
 
        /* Now, insert a Sort node if subplan isn't sufficiently ordered */
        if (!pathkeys_contained_in(pathkeys, subpath->pathkeys))
-           subplan = (Plan *) make_sort(root, subplan, numsortkeys,
+       {
+           Sort       *sort = make_sort(subplan, numsortkeys,
                                         sortColIdx, sortOperators,
-                                        collations, nullsFirst,
-                                        best_path->limit_tuples);
+                                        collations, nullsFirst);
+
+           label_sort_with_costsize(root, sort, best_path->limit_tuples);
+           subplan = (Plan *) sort;
+       }
 
        subplans = lappend(subplans, subplan);
    }
@@ -1081,24 +1093,28 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
 /*
  * create_result_plan
  *   Create a Result plan for 'best_path'.
- *   This is only used for the case of a query with an empty jointree.
+ *   This is only used for degenerate cases, such as a query with an empty
+ *   jointree.
  *
  *   Returns a Plan node.
  */
 static Result *
 create_result_plan(PlannerInfo *root, ResultPath *best_path)
 {
+   Result     *plan;
    List       *tlist;
    List       *quals;
 
-   /* This is a bit useless currently, because rel will have empty tlist */
    tlist = build_path_tlist(root, &best_path->path);
 
    /* best_path->quals is just bare clauses */
-
    quals = order_qual_clauses(root, best_path->quals);
 
-   return make_result(root, tlist, (Node *) quals, NULL);
+   plan = make_result(tlist, (Node *) quals, NULL);
+
+   copy_generic_path_info(&plan->plan, (Path *) best_path);
+
+   return plan;
 }
 
 /*
@@ -1209,7 +1225,7 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path, int flags)
         */
        if (!is_projection_capable_plan(subplan) &&
            !tlist_same_exprs(newtlist, subplan->targetlist))
-           subplan = (Plan *) make_result(root, newtlist, NULL, subplan);
+           subplan = inject_projection_plan(subplan, newtlist);
        else
            subplan->targetlist = newtlist;
    }
@@ -1280,6 +1296,7 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path, int flags)
    else
    {
        List       *sortList = NIL;
+       Sort       *sort;
 
        /* Create an ORDER BY list to sort the input compatibly */
        groupColPos = 0;
@@ -1321,8 +1338,9 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path, int flags)
            sortList = lappend(sortList, sortcl);
            groupColPos++;
        }
-       plan = (Plan *) make_sort_from_sortclauses(root, sortList, subplan);
-       plan = (Plan *) make_unique_from_sortclauses(plan, sortList);
+       sort = make_sort_from_sortclauses(sortList, subplan);
+       label_sort_with_costsize(root, sort, -1.0);
+       plan = (Plan *) make_unique_from_sortclauses((Plan *) sort, sortList);
    }
 
    /* Copy cost data from Path to Plan */
@@ -1402,7 +1420,7 @@ create_projection_plan(PlannerInfo *root, ProjectionPath *best_path)
    }
    else
    {
-       plan = (Plan *) make_result(root, tlist, NULL, subplan);
+       plan = (Plan *) make_result(tlist, NULL, subplan);
 
        copy_generic_path_info(plan, (Path *) best_path);
    }
@@ -1410,6 +1428,33 @@ create_projection_plan(PlannerInfo *root, ProjectionPath *best_path)
    return plan;
 }
 
+/*
+ * inject_projection_plan
+ *   Insert a Result node to do a projection step.
+ *
+ * This is used in a few places where we decide on-the-fly that we need a
+ * projection step as part of the tree generated for some Path node.
+ * We should try to get rid of this in favor of doing it more honestly.
+ */
+static Plan *
+inject_projection_plan(Plan *subplan, List *tlist)
+{
+   Plan       *plan;
+
+   plan = (Plan *) make_result(tlist, NULL, subplan);
+
+   /*
+    * In principle, we should charge tlist eval cost plus cpu_per_tuple per
+    * row for the Result node.  But the former has probably been factored in
+    * already and the latter was not accounted for during Path construction,
+    * so being formally correct might just make the EXPLAIN output look less
+    * consistent not more so.  Hence, just copy the subplan's cost.
+    */
+   copy_plan_costsize(plan, subplan);
+
+   return plan;
+}
+
 /*
  * create_sort_plan
  *
@@ -1430,15 +1475,7 @@ create_sort_plan(PlannerInfo *root, SortPath *best_path, int flags)
    subplan = create_plan_recurse(root, best_path->subpath,
                                  flags | CP_SMALL_TLIST);
 
-   /*
-    * Don't need to have correct limit_tuples; that only affects the cost
-    * estimate, which we'll overwrite.  (XXX should refactor so that we don't
-    * have a useless cost_sort call in here.)
-    */
-   plan = make_sort_from_pathkeys(root,
-                                  subplan,
-                                  best_path->path.pathkeys,
-                                  -1.0);
+   plan = make_sort_from_pathkeys(subplan, best_path->path.pathkeys);
 
    copy_generic_path_info(&plan->plan, (Path *) best_path);
 
@@ -1683,8 +1720,7 @@ create_groupingsets_plan(PlannerInfo *root, GroupingSetsPath *best_path)
            new_grpColIdx = remap_groupColIdx(root, groupClause);
 
            sort_plan = (Plan *)
-               make_sort_from_groupcols(root,
-                                        groupClause,
+               make_sort_from_groupcols(groupClause,
                                         new_grpColIdx,
                                         subplan);
 
@@ -1791,7 +1827,7 @@ create_minmaxagg_plan(PlannerInfo *root, MinMaxAggPath *best_path)
    /* Generate the output plan --- basically just a Result */
    tlist = build_path_tlist(root, &best_path->path);
 
-   plan = make_result(root, tlist, (Node *) best_path->quals, NULL);
+   plan = make_result(tlist, (Node *) best_path->quals, NULL);
 
    copy_generic_path_info(&plan->plan, (Path *) best_path);
 
@@ -1849,8 +1885,7 @@ create_windowagg_plan(PlannerInfo *root, WindowAggPath *best_path)
     * We shouldn't need to actually sort, but it's convenient to use
     * prepare_sort_from_pathkeys to identify the input's sort columns.
     */
-   subplan = prepare_sort_from_pathkeys(root,
-                                        subplan,
+   subplan = prepare_sort_from_pathkeys(subplan,
                                         best_path->winpathkeys,
                                         NULL,
                                         NULL,
@@ -2646,6 +2681,7 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
        plan->plan_rows =
            clamp_row_est(apath->bitmapselectivity * apath->path.parent->tuples);
        plan->plan_width = 0;   /* meaningless */
+       plan->parallel_aware = false;
        *qual = subquals;
        *indexqual = subindexquals;
        *indexECs = subindexECs;
@@ -2708,6 +2744,7 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
            plan->plan_rows =
                clamp_row_est(opath->bitmapselectivity * opath->path.parent->tuples);
            plan->plan_width = 0;       /* meaningless */
+           plan->parallel_aware = false;
        }
 
        /*
@@ -2745,11 +2782,13 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
                                              iscan->indexid,
                                              iscan->indexqual,
                                              iscan->indexqualorig);
+       /* and set its cost/width fields appropriately */
        plan->startup_cost = 0.0;
        plan->total_cost = ipath->indextotalcost;
        plan->plan_rows =
            clamp_row_est(ipath->indexselectivity * ipath->path.parent->tuples);
        plan->plan_width = 0;   /* meaningless */
+       plan->parallel_aware = false;
        *qual = get_actual_clauses(ipath->indexclauses);
        *indexqual = get_actual_clauses(ipath->indexquals);
        foreach(l, ipath->indexinfo->indpred)
@@ -3533,11 +3572,11 @@ create_mergejoin_plan(PlannerInfo *root,
     */
    if (best_path->outersortkeys)
    {
-       outer_plan = (Plan *)
-           make_sort_from_pathkeys(root,
-                                   outer_plan,
-                                   best_path->outersortkeys,
-                                   -1.0);
+       Sort       *sort = make_sort_from_pathkeys(outer_plan,
+                                                  best_path->outersortkeys);
+
+       label_sort_with_costsize(root, sort, -1.0);
+       outer_plan = (Plan *) sort;
        outerpathkeys = best_path->outersortkeys;
    }
    else
@@ -3545,11 +3584,11 @@ create_mergejoin_plan(PlannerInfo *root,
 
    if (best_path->innersortkeys)
    {
-       inner_plan = (Plan *)
-           make_sort_from_pathkeys(root,
-                                   inner_plan,
-                                   best_path->innersortkeys,
-                                   -1.0);
+       Sort       *sort = make_sort_from_pathkeys(inner_plan,
+                                                  best_path->innersortkeys);
+
+       label_sort_with_costsize(root, sort, -1.0);
+       inner_plan = (Plan *) sort;
        innerpathkeys = best_path->innersortkeys;
    }
    else
@@ -3870,6 +3909,14 @@ create_hashjoin_plan(PlannerInfo *root,
                          skewInherit,
                          skewColType,
                          skewColTypmod);
+
+   /*
+    * Set Hash node's startup & total costs equal to total cost of input
+    * plan; this only affects EXPLAIN display not decisions.
+    */
+   copy_plan_costsize(&hash_plan->plan, inner_plan);
+   hash_plan->plan.startup_cost = hash_plan->plan.total_cost;
+
    join_plan = make_hashjoin(tlist,
                              joinclauses,
                              otherclauses,
@@ -4514,28 +4561,16 @@ order_qual_clauses(PlannerInfo *root, List *clauses)
 /*
  * Copy cost and size info from a Path node to the Plan node created from it.
  * The executor usually won't use this info, but it's needed by EXPLAIN.
- *
- * Also copy the parallel-aware flag, which the executor will use.
+ * Also copy the parallel-aware flag, which the executor *will* use.
  */
 static void
 copy_generic_path_info(Plan *dest, Path *src)
 {
-   if (src)
-   {
-       dest->startup_cost = src->startup_cost;
-       dest->total_cost = src->total_cost;
-       dest->plan_rows = src->rows;
-       dest->plan_width = src->pathtarget->width;
-       dest->parallel_aware = src->parallel_aware;
-   }
-   else
-   {
-       dest->startup_cost = 0;
-       dest->total_cost = 0;
-       dest->plan_rows = 0;
-       dest->plan_width = 0;
-       dest->parallel_aware = false;
-   }
+   dest->startup_cost = src->startup_cost;
+   dest->total_cost = src->total_cost;
+   dest->plan_rows = src->rows;
+   dest->plan_width = src->pathtarget->width;
+   dest->parallel_aware = src->parallel_aware;
 }
 
 /*
@@ -4545,20 +4580,41 @@ copy_generic_path_info(Plan *dest, Path *src)
 static void
 copy_plan_costsize(Plan *dest, Plan *src)
 {
-   if (src)
-   {
-       dest->startup_cost = src->startup_cost;
-       dest->total_cost = src->total_cost;
-       dest->plan_rows = src->plan_rows;
-       dest->plan_width = src->plan_width;
-   }
-   else
-   {
-       dest->startup_cost = 0;
-       dest->total_cost = 0;
-       dest->plan_rows = 0;
-       dest->plan_width = 0;
-   }
+   dest->startup_cost = src->startup_cost;
+   dest->total_cost = src->total_cost;
+   dest->plan_rows = src->plan_rows;
+   dest->plan_width = src->plan_width;
+   /* Assume the inserted node is not parallel-aware. */
+   dest->parallel_aware = false;
+}
+
+/*
+ * Some places in this file build Sort nodes that don't have a directly
+ * corresponding Path node.  The cost of the sort is, or should have been,
+ * included in the cost of the Path node we're working from, but since it's
+ * not split out, we have to re-figure it using cost_sort().  This is just
+ * to label the Sort node nicely for EXPLAIN.
+ *
+ * limit_tuples is as for cost_sort (in particular, pass -1 if no limit)
+ */
+static void
+label_sort_with_costsize(PlannerInfo *root, Sort *plan, double limit_tuples)
+{
+   Plan       *lefttree = plan->plan.lefttree;
+   Path        sort_path;      /* dummy for result of cost_sort */
+
+   cost_sort(&sort_path, root, NIL,
+             lefttree->total_cost,
+             lefttree->plan_rows,
+             lefttree->plan_width,
+             0.0,
+             work_mem,
+             limit_tuples);
+   plan->plan.startup_cost = sort_path.startup_cost;
+   plan->plan.total_cost = sort_path.total_cost;
+   plan->plan.plan_rows = lefttree->plan_rows;
+   plan->plan.plan_width = lefttree->plan_width;
+   plan->plan.parallel_aware = false;
 }
 
 
@@ -4566,8 +4622,13 @@ copy_plan_costsize(Plan *dest, Plan *src)
  *
  * PLAN NODE BUILDING ROUTINES
  *
- * Some of these are exported because they are called to build plan nodes
- * in contexts where we're not deriving the plan node from a path node.
+ * In general, these functions are not passed the original Path and therefore
+ * leave it to the caller to fill in the cost/width fields from the Path,
+ * typically by calling copy_generic_path_info().  This convention is
+ * somewhat historical, but it does support a few places above where we build
+ * a plan node without having an exactly corresponding Path node.  Under no
+ * circumstances should one of these functions do its own cost calculations,
+ * as that would be redundant with calculations done while building Paths.
  *
  *****************************************************************************/
 
@@ -4579,7 +4640,6 @@ make_seqscan(List *qptlist,
    SeqScan    *node = makeNode(SeqScan);
    Plan       *plan = &node->plan;
 
-   /* cost should be inserted by caller */
    plan->targetlist = qptlist;
    plan->qual = qpqual;
    plan->lefttree = NULL;
@@ -4598,7 +4658,6 @@ make_samplescan(List *qptlist,
    SampleScan *node = makeNode(SampleScan);
    Plan       *plan = &node->scan.plan;
 
-   /* cost should be inserted by caller */
    plan->targetlist = qptlist;
    plan->qual = qpqual;
    plan->lefttree = NULL;
@@ -4624,7 +4683,6 @@ make_indexscan(List *qptlist,
    IndexScan  *node = makeNode(IndexScan);
    Plan       *plan = &node->scan.plan;
 
-   /* cost should be inserted by caller */
    plan->targetlist = qptlist;
    plan->qual = qpqual;
    plan->lefttree = NULL;
@@ -4654,7 +4712,6 @@ make_indexonlyscan(List *qptlist,
    IndexOnlyScan *node = makeNode(IndexOnlyScan);
    Plan       *plan = &node->scan.plan;
 
-   /* cost should be inserted by caller */
    plan->targetlist = qptlist;
    plan->qual = qpqual;
    plan->lefttree = NULL;
@@ -4678,7 +4735,6 @@ make_bitmap_indexscan(Index scanrelid,
    BitmapIndexScan *node = makeNode(BitmapIndexScan);
    Plan       *plan = &node->scan.plan;
 
-   /* cost should be inserted by caller */
    plan->targetlist = NIL;     /* not used */
    plan->qual = NIL;           /* not used */
    plan->lefttree = NULL;
@@ -4701,7 +4757,6 @@ make_bitmap_heapscan(List *qptlist,
    BitmapHeapScan *node = makeNode(BitmapHeapScan);
    Plan       *plan = &node->scan.plan;
 
-   /* cost should be inserted by caller */
    plan->targetlist = qptlist;
    plan->qual = qpqual;
    plan->lefttree = lefttree;
@@ -4721,7 +4776,6 @@ make_tidscan(List *qptlist,
    TidScan    *node = makeNode(TidScan);
    Plan       *plan = &node->scan.plan;
 
-   /* cost should be inserted by caller */
    plan->targetlist = qptlist;
    plan->qual = qpqual;
    plan->lefttree = NULL;
@@ -4741,14 +4795,6 @@ make_subqueryscan(List *qptlist,
    SubqueryScan *node = makeNode(SubqueryScan);
    Plan       *plan = &node->scan.plan;
 
-   /*
-    * Cost is figured here for the convenience of prepunion.c.  Note this is
-    * only correct for the case where qpqual is empty; otherwise caller
-    * should overwrite cost with a better estimate.
-    */
-   copy_plan_costsize(plan, subplan);
-   plan->total_cost += cpu_tuple_cost * subplan->plan_rows;
-
    plan->targetlist = qptlist;
    plan->qual = qpqual;
    plan->lefttree = NULL;
@@ -4769,7 +4815,6 @@ make_functionscan(List *qptlist,
    FunctionScan *node = makeNode(FunctionScan);
    Plan       *plan = &node->scan.plan;
 
-   /* cost should be inserted by caller */
    plan->targetlist = qptlist;
    plan->qual = qpqual;
    plan->lefttree = NULL;
@@ -4790,7 +4835,6 @@ make_valuesscan(List *qptlist,
    ValuesScan *node = makeNode(ValuesScan);
    Plan       *plan = &node->scan.plan;
 
-   /* cost should be inserted by caller */
    plan->targetlist = qptlist;
    plan->qual = qpqual;
    plan->lefttree = NULL;
@@ -4811,7 +4855,6 @@ make_ctescan(List *qptlist,
    CteScan    *node = makeNode(CteScan);
    Plan       *plan = &node->scan.plan;
 
-   /* cost should be inserted by caller */
    plan->targetlist = qptlist;
    plan->qual = qpqual;
    plan->lefttree = NULL;
@@ -4832,7 +4875,6 @@ make_worktablescan(List *qptlist,
    WorkTableScan *node = makeNode(WorkTableScan);
    Plan       *plan = &node->scan.plan;
 
-   /* cost should be inserted by caller */
    plan->targetlist = qptlist;
    plan->qual = qpqual;
    plan->lefttree = NULL;
@@ -4881,38 +4923,6 @@ make_append(List *appendplans, List *tlist)
 {
    Append     *node = makeNode(Append);
    Plan       *plan = &node->plan;
-   double      total_size;
-   ListCell   *subnode;
-
-   /*
-    * Compute cost as sum of subplan costs.  We charge nothing extra for the
-    * Append itself, which perhaps is too optimistic, but since it doesn't do
-    * any selection or projection, it is a pretty cheap node.
-    *
-    * If you change this, see also create_append_path().  Also, the size
-    * calculations should match set_append_rel_pathlist().  It'd be better
-    * not to duplicate all this logic, but some callers of this function
-    * aren't working from an appendrel or AppendPath, so there's noplace to
-    * copy the data from.
-    */
-   plan->startup_cost = 0;
-   plan->total_cost = 0;
-   plan->plan_rows = 0;
-   total_size = 0;
-   foreach(subnode, appendplans)
-   {
-       Plan       *subplan = (Plan *) lfirst(subnode);
-
-       if (subnode == list_head(appendplans))  /* first node? */
-           plan->startup_cost = subplan->startup_cost;
-       plan->total_cost += subplan->total_cost;
-       plan->plan_rows += subplan->plan_rows;
-       total_size += subplan->plan_width * subplan->plan_rows;
-   }
-   if (plan->plan_rows > 0)
-       plan->plan_width = rint(total_size / plan->plan_rows);
-   else
-       plan->plan_width = 0;
 
    plan->targetlist = tlist;
    plan->qual = NIL;
@@ -4981,7 +4991,6 @@ make_bitmap_and(List *bitmapplans)
    BitmapAnd  *node = makeNode(BitmapAnd);
    Plan       *plan = &node->plan;
 
-   /* cost should be inserted by caller */
    plan->targetlist = NIL;
    plan->qual = NIL;
    plan->lefttree = NULL;
@@ -4997,7 +5006,6 @@ make_bitmap_or(List *bitmapplans)
    BitmapOr   *node = makeNode(BitmapOr);
    Plan       *plan = &node->plan;
 
-   /* cost should be inserted by caller */
    plan->targetlist = NIL;
    plan->qual = NIL;
    plan->lefttree = NULL;
@@ -5019,7 +5027,6 @@ make_nestloop(List *tlist,
    NestLoop   *node = makeNode(NestLoop);
    Plan       *plan = &node->join.plan;
 
-   /* cost should be inserted by caller */
    plan->targetlist = tlist;
    plan->qual = otherclauses;
    plan->lefttree = lefttree;
@@ -5043,7 +5050,6 @@ make_hashjoin(List *tlist,
    HashJoin   *node = makeNode(HashJoin);
    Plan       *plan = &node->join.plan;
 
-   /* cost should be inserted by caller */
    plan->targetlist = tlist;
    plan->qual = otherclauses;
    plan->lefttree = lefttree;
@@ -5066,13 +5072,6 @@ make_hash(Plan *lefttree,
    Hash       *node = makeNode(Hash);
    Plan       *plan = &node->plan;
 
-   copy_plan_costsize(plan, lefttree);
-
-   /*
-    * For plausibility, make startup & total costs equal total cost of input
-    * plan; this only affects EXPLAIN display not decisions.
-    */
-   plan->startup_cost = plan->total_cost;
    plan->targetlist = lefttree->targetlist;
    plan->qual = NIL;
    plan->lefttree = lefttree;
@@ -5103,7 +5102,6 @@ make_mergejoin(List *tlist,
    MergeJoin  *node = makeNode(MergeJoin);
    Plan       *plan = &node->join.plan;
 
-   /* cost should be inserted by caller */
    plan->targetlist = tlist;
    plan->qual = otherclauses;
    plan->lefttree = lefttree;
@@ -5124,28 +5122,15 @@ make_mergejoin(List *tlist,
  *
  * Caller must have built the sortColIdx, sortOperators, collations, and
  * nullsFirst arrays already.
- * limit_tuples is as for cost_sort (in particular, pass -1 if no limit)
  */
 static Sort *
-make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
+make_sort(Plan *lefttree, int numCols,
          AttrNumber *sortColIdx, Oid *sortOperators,
-         Oid *collations, bool *nullsFirst,
-         double limit_tuples)
+         Oid *collations, bool *nullsFirst)
 {
    Sort       *node = makeNode(Sort);
    Plan       *plan = &node->plan;
-   Path        sort_path;      /* dummy for result of cost_sort */
 
-   copy_plan_costsize(plan, lefttree); /* only care about copying size */
-   cost_sort(&sort_path, root, NIL,
-             lefttree->total_cost,
-             lefttree->plan_rows,
-             lefttree->plan_width,
-             0.0,
-             work_mem,
-             limit_tuples);
-   plan->startup_cost = sort_path.startup_cost;
-   plan->total_cost = sort_path.total_cost;
    plan->targetlist = lefttree->targetlist;
    plan->qual = NIL;
    plan->lefttree = lefttree;
@@ -5200,7 +5185,7 @@ make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
  * or a Result stacked atop lefttree).
  */
 static Plan *
-prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
+prepare_sort_from_pathkeys(Plan *lefttree, List *pathkeys,
                           Relids relids,
                           const AttrNumber *reqColIdx,
                           bool adjust_tlist_in_place,
@@ -5369,8 +5354,7 @@ prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
            {
                /* copy needed so we don't modify input's tlist below */
                tlist = copyObject(tlist);
-               lefttree = (Plan *) make_result(root, tlist, NULL,
-                                               lefttree);
+               lefttree = inject_projection_plan(lefttree, tlist);
            }
 
            /* Don't bother testing is_projection_capable_plan again */
@@ -5474,12 +5458,9 @@ find_ec_member_for_tle(EquivalenceClass *ec,
  *
  *   'lefttree' is the node which yields input tuples
  *   'pathkeys' is the list of pathkeys by which the result is to be sorted
- *   'limit_tuples' is the bound on the number of output tuples;
- *             -1 if no bound
  */
 static Sort *
-make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
-                       double limit_tuples)
+make_sort_from_pathkeys(Plan *lefttree, List *pathkeys)
 {
    int         numsortkeys;
    AttrNumber *sortColIdx;
@@ -5488,7 +5469,7 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
    bool       *nullsFirst;
 
    /* Compute sort column info, and adjust lefttree as needed */
-   lefttree = prepare_sort_from_pathkeys(root, lefttree, pathkeys,
+   lefttree = prepare_sort_from_pathkeys(lefttree, pathkeys,
                                          NULL,
                                          NULL,
                                          false,
@@ -5499,9 +5480,9 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
                                          &nullsFirst);
 
    /* Now build the Sort node */
-   return make_sort(root, lefttree, numsortkeys,
-                    sortColIdx, sortOperators, collations,
-                    nullsFirst, limit_tuples);
+   return make_sort(lefttree, numsortkeys,
+                    sortColIdx, sortOperators,
+                    collations, nullsFirst);
 }
 
 /*
@@ -5512,7 +5493,7 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
  *   'lefttree' is the node which yields input tuples
  */
 static Sort *
-make_sort_from_sortclauses(PlannerInfo *root, List *sortcls, Plan *lefttree)
+make_sort_from_sortclauses(List *sortcls, Plan *lefttree)
 {
    List       *sub_tlist = lefttree->targetlist;
    ListCell   *l;
@@ -5542,9 +5523,9 @@ make_sort_from_sortclauses(PlannerInfo *root, List *sortcls, Plan *lefttree)
        numsortkeys++;
    }
 
-   return make_sort(root, lefttree, numsortkeys,
-                    sortColIdx, sortOperators, collations,
-                    nullsFirst, -1.0);
+   return make_sort(lefttree, numsortkeys,
+                    sortColIdx, sortOperators,
+                    collations, nullsFirst);
 }
 
 /*
@@ -5561,8 +5542,7 @@ make_sort_from_sortclauses(PlannerInfo *root, List *sortcls, Plan *lefttree)
  * is used from the SortGroupClause entries.
  */
 static Sort *
-make_sort_from_groupcols(PlannerInfo *root,
-                        List *groupcls,
+make_sort_from_groupcols(List *groupcls,
                         AttrNumber *grpColIdx,
                         Plan *lefttree)
 {
@@ -5597,9 +5577,9 @@ make_sort_from_groupcols(PlannerInfo *root,
        numsortkeys++;
    }
 
-   return make_sort(root, lefttree, numsortkeys,
-                    sortColIdx, sortOperators, collations,
-                    nullsFirst, -1.0);
+   return make_sort(lefttree, numsortkeys,
+                    sortColIdx, sortOperators,
+                    collations, nullsFirst);
 }
 
 static Material *
@@ -5608,7 +5588,6 @@ make_material(Plan *lefttree)
    Material   *node = makeNode(Material);
    Plan       *plan = &node->plan;
 
-   /* cost should be inserted by caller */
    plan->targetlist = lefttree->targetlist;
    plan->qual = NIL;
    plan->lefttree = lefttree;
@@ -5622,6 +5601,8 @@ make_material(Plan *lefttree)
  *
  * There are a couple of places where we want to attach a Material node
  * after completion of create_plan(), without any MaterialPath path.
+ * Those places should probably be refactored someday to do this on the
+ * Path representation, but it's not worth the trouble yet.
  */
 Plan *
 materialize_finished_plan(Plan *subplan)
@@ -5720,8 +5701,6 @@ make_group(List *tlist,
    Group      *node = makeNode(Group);
    Plan       *plan = &node->plan;
 
-   /* caller must fill cost/size fields */
-
    node->numCols = numGroupCols;
    node->grpColIdx = grpColIdx;
    node->grpOperators = grpOperators;
@@ -5896,7 +5875,6 @@ make_gather(List *qptlist,
    Gather     *node = makeNode(Gather);
    Plan       *plan = &node->plan;
 
-   /* cost should be inserted by caller */
    plan->targetlist = qptlist;
    plan->qual = qpqual;
    plan->lefttree = subplan;
@@ -6007,41 +5985,15 @@ make_limit(Plan *lefttree, Node *limitOffset, Node *limitCount)
 /*
  * make_result
  *   Build a Result plan node
- *
- * If we have a subplan, assume that any evaluation costs for the gating qual
- * were already factored into the subplan's startup cost, and just copy the
- * subplan cost.  If there's no subplan, we should include the qual eval
- * cost.  In either case, tlist eval cost is not to be included here.
- * XXX really we don't want to be doing cost estimation here.
  */
 static Result *
-make_result(PlannerInfo *root,
-           List *tlist,
+make_result(List *tlist,
            Node *resconstantqual,
            Plan *subplan)
 {
    Result     *node = makeNode(Result);
    Plan       *plan = &node->plan;
 
-   if (subplan)
-       copy_plan_costsize(plan, subplan);
-   else
-   {
-       plan->startup_cost = 0;
-       plan->total_cost = cpu_tuple_cost;
-       plan->plan_rows = 1;    /* wrong if we have a set-valued function? */
-       plan->plan_width = 0;   /* XXX is it worth being smarter? */
-       if (resconstantqual)
-       {
-           QualCost    qual_cost;
-
-           cost_qual_eval(&qual_cost, (List *) resconstantqual, root);
-           /* resconstantqual is evaluated once at startup */
-           plan->startup_cost += qual_cost.startup + qual_cost.per_tuple;
-           plan->total_cost += qual_cost.startup + qual_cost.per_tuple;
-       }
-   }
-
    plan->targetlist = tlist;
    plan->qual = NIL;
    plan->lefttree = subplan;
index da2c7f66060be3d63ff90bf9cee68314b5bfa4d7..443e64e9691bff381d72e9fe6b28b1d5842d9f7c 100644 (file)
@@ -82,7 +82,7 @@ query_planner(PlannerInfo *root, List *tlist,
 
        /* The only path for it is a trivial Result path */
        add_path(final_rel, (Path *)
-                create_result_path(final_rel,
+                create_result_path(root, final_rel,
                                    &(final_rel->reltarget),
                                    (List *) parse->jointree->quals));
 
index 5fc8e5bd362323325472a35ac17dbee64bfca805..cbeceeb1fbf7b097765356c4b4ccf7ce0ec3651b 100644 (file)
@@ -3143,7 +3143,7 @@ create_grouping_paths(PlannerInfo *root,
            while (--nrows >= 0)
            {
                path = (Path *)
-                   create_result_path(grouped_rel,
+                   create_result_path(root, grouped_rel,
                                       target,
                                       (List *) parse->havingQual);
                paths = lappend(paths, path);
@@ -3159,7 +3159,7 @@ create_grouping_paths(PlannerInfo *root,
        {
            /* No grouping sets, or just one, so one output row */
            path = (Path *)
-               create_result_path(grouped_rel,
+               create_result_path(root, grouped_rel,
                                   target,
                                   (List *) parse->havingQual);
        }
index 19c15709a45cd068b79bc9947a95cab7b0f72c54..fe5e830385a69a79eebb0135b8c73142e57cff62 100644 (file)
@@ -1328,7 +1328,8 @@ create_merge_append_path(PlannerInfo *root,
  * jointree.
  */
 ResultPath *
-create_result_path(RelOptInfo *rel, PathTarget *target, List *quals)
+create_result_path(PlannerInfo *root, RelOptInfo *rel,
+                  PathTarget *target, List *resconstantqual)
 {
    ResultPath *pathnode = makeNode(ResultPath);
 
@@ -1340,23 +1341,22 @@ create_result_path(RelOptInfo *rel, PathTarget *target, List *quals)
    pathnode->path.parallel_safe = rel->consider_parallel;
    pathnode->path.parallel_degree = 0;
    pathnode->path.pathkeys = NIL;
-   pathnode->quals = quals;
+   pathnode->quals = resconstantqual;
 
    /* Hardly worth defining a cost_result() function ... just do it */
    pathnode->path.rows = 1;
    pathnode->path.startup_cost = target->cost.startup;
    pathnode->path.total_cost = target->cost.startup +
        cpu_tuple_cost + target->cost.per_tuple;
+   if (resconstantqual)
+   {
+       QualCost    qual_cost;
 
-   /*
-    * In theory we should include the qual eval cost as well, but at present
-    * that doesn't accomplish much except duplicate work that will be done
-    * again in make_result; since this is only used for degenerate cases,
-    * nothing interesting will be done with the path cost values.
-    *
-    * XXX should refactor so that make_result does not do costing work, at
-    * which point this will need to do it honestly.
-    */
+       cost_qual_eval(&qual_cost, resconstantqual, root);
+       /* resconstantqual is evaluated once at startup */
+       pathnode->path.startup_cost += qual_cost.startup + qual_cost.per_tuple;
+       pathnode->path.total_cost += qual_cost.startup + qual_cost.per_tuple;
+   }
 
    return pathnode;
 }
@@ -2162,7 +2162,7 @@ create_projection_path(PlannerInfo *root,
 
    /*
     * The Result node's cost is cpu_tuple_cost per row, plus the cost of
-    * evaluating the tlist.
+    * evaluating the tlist.  There is no qual to worry about.
     */
    pathnode->path.rows = subpath->rows;
    pathnode->path.startup_cost = subpath->startup_cost + target->cost.startup;
index 37744bf97251adbc1e2b39ff31116e9124619aac..df4be93bae51ff22a0fab23c6bc1b9d9caeaaf4c 100644 (file)
@@ -68,8 +68,8 @@ extern MergeAppendPath *create_merge_append_path(PlannerInfo *root,
                         List *subpaths,
                         List *pathkeys,
                         Relids required_outer);
-extern ResultPath *create_result_path(RelOptInfo *rel,
-                  PathTarget *target, List *quals);
+extern ResultPath *create_result_path(PlannerInfo *root, RelOptInfo *rel,
+                  PathTarget *target, List *resconstantqual);
 extern MaterialPath *create_material_path(RelOptInfo *rel, Path *subpath);
 extern UniquePath *create_unique_path(PlannerInfo *root, RelOptInfo *rel,
                   Path *subpath, SpecialJoinInfo *sjinfo);