diff options
Diffstat (limited to 'src/backend/optimizer/plan/planmain.c')
-rw-r--r-- | src/backend/optimizer/plan/planmain.c | 102 |
1 files changed, 91 insertions, 11 deletions
diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index 76e010c9d22..f6f62abfe08 100644 --- a/src/backend/optimizer/plan/planmain.c +++ b/src/backend/optimizer/plan/planmain.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.40 1999/07/16 04:59:19 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.41 1999/08/21 03:49:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,11 +17,13 @@ #include "optimizer/clauses.h" +#include "optimizer/cost.h" #include "optimizer/paths.h" #include "optimizer/planmain.h" #include "optimizer/prep.h" #include "optimizer/subselect.h" #include "optimizer/tlist.h" +#include "utils/lsyscache.h" static Plan *subplanner(Query *root, List *flat_tlist, List *qual); @@ -42,6 +44,13 @@ static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan); * tlist is the target list of the query * qual is the qualification of the query * + * Note: the Query node now also includes a query_pathkeys field, which + * signals query_planner that the indicated sort order is wanted in the + * final output plan. If, for some reason, query_planner is unable to + * comply, it sets query_pathkeys to NIL before returning. (The reason + * query_pathkeys is a Query field and not a passed parameter is that + * the low-level routines in indxpath.c need to see it.) + * * Returns a query plan. */ Plan * @@ -100,6 +109,8 @@ query_planner(Query *root, */ if (var_only_tlist == NULL && qual == NULL) { + root->query_pathkeys = NIL; /* these plans make unordered results */ + switch (command_type) { case CMD_SELECT: @@ -152,6 +163,8 @@ query_planner(Query *root, */ set_tlist_references(subplan); + root->query_pathkeys = NIL; /* result is unordered, no? */ + return subplan; } @@ -163,15 +176,15 @@ query_planner(Query *root, * responsibility to optimally push these expressions down the plan * tree. -- Wei * - * Note: formerly there was a test here to skip the flatten call if we - * expected union_planner to insert a Group or Agg node above our + * Note: formerly there was a test here to skip the unflatten call if + * we expected union_planner to insert a Group or Agg node above our * result. However, now union_planner tells us exactly what it wants * returned, and we just do it. Much cleaner. */ else { - subplan->targetlist = flatten_tlist_vars(tlist, - subplan->targetlist); + subplan->targetlist = unflatten_tlist(tlist, + subplan->targetlist); return subplan; } @@ -204,6 +217,8 @@ subplanner(Query *root, List *qual) { RelOptInfo *final_rel; + Cost cheapest_cost; + Path *sortedpath; /* * Initialize the targetlist and qualification, adding entries to @@ -244,18 +259,83 @@ subplanner(Query *root, } #endif + if (! final_rel) + { + elog(NOTICE, "final relation is null"); + root->query_pathkeys = NIL; /* result is unordered, no? */ + return create_plan((Path *) NULL); + } + + /* + * Determine the cheapest path and create a subplan to execute it. + * + * If no special sort order is wanted, or if the cheapest path is + * already appropriately ordered, just use the cheapest path. + */ + if (root->query_pathkeys == NIL || + pathkeys_contained_in(root->query_pathkeys, + final_rel->cheapestpath->pathkeys)) + return create_plan(final_rel->cheapestpath); /* - * Determine the cheapest path and create a subplan corresponding to - * it. + * Otherwise, look to see if we have an already-ordered path that is + * cheaper than doing an explicit sort on cheapestpath. */ - if (final_rel) - return create_plan((Path *) final_rel->cheapestpath); + cheapest_cost = final_rel->cheapestpath->path_cost + + cost_sort(root->query_pathkeys, final_rel->size, final_rel->width); + + sortedpath = get_cheapest_path_for_pathkeys(final_rel->pathlist, + root->query_pathkeys, + false); + if (sortedpath) + { + if (sortedpath->path_cost <= cheapest_cost) + { + /* Found a better presorted path, use it */ + return create_plan(sortedpath); + } + /* otherwise, doing it the hard way is still cheaper */ + } else { - elog(NOTICE, "final relation is null"); - return create_plan((Path *) NULL); + /* + * If we found no usable presorted path at all, it is possible + * that the user asked for descending sort order. Check to see + * if we can satisfy the pathkeys by using a backwards indexscan. + * To do this, we commute all the operators in the pathkeys and + * then look for a matching path that is an IndexPath. + */ + List *commuted_pathkeys = copyObject(root->query_pathkeys); + + if (commute_pathkeys(commuted_pathkeys)) + { + /* pass 'true' to force only IndexPaths to be considered */ + sortedpath = get_cheapest_path_for_pathkeys(final_rel->pathlist, + commuted_pathkeys, + true); + if (sortedpath && sortedpath->path_cost <= cheapest_cost) + { + /* + * Kluge here: since IndexPath has no representation for + * backwards scan, we have to convert to Plan format and + * then poke the result. + */ + Plan *sortedplan = create_plan(sortedpath); + + Assert(IsA(sortedplan, IndexScan)); + ((IndexScan *) sortedplan)->indxorderdir = BackwardScanDirection; + return sortedplan; + } + } } + /* Nothing for it but to sort the cheapestpath... + * + * we indicate we failed to sort the plan, and let the caller + * stick the appropriate sortplan on top. + */ + root->query_pathkeys = NIL; /* sorry, it ain't sorted */ + + return create_plan(final_rel->cheapestpath); } /***************************************************************************** |