]> granicus.if.org Git - postgresql/commitdiff
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);