diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2013-04-29 14:49:01 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2013-04-29 14:50:03 -0400 |
commit | db9f0e1d9a4a0842c814a464cdc9758c3f20b96c (patch) | |
tree | b97cbce399e36caa8aa4bf556e716547fa278163 /src/backend/optimizer/plan/planmain.c | |
parent | 5fc893760f60d57aca30163796db1abe516b3fac (diff) | |
download | postgresql-db9f0e1d9a4a0842c814a464cdc9758c3f20b96c.tar.gz postgresql-db9f0e1d9a4a0842c814a464cdc9758c3f20b96c.zip |
Postpone creation of pathkeys lists to fix bug #8049.
This patch gets rid of the concept of, and infrastructure for,
non-canonical PathKeys; we now only ever create canonical pathkey lists.
The need for non-canonical pathkeys came from the desire to have
grouping_planner initialize query_pathkeys and related pathkey lists before
calling query_planner. However, since query_planner didn't actually *do*
anything with those lists before they'd been made canonical, we can get rid
of the whole mess by just not creating the lists at all until the point
where we formerly canonicalized them.
There are several ways in which we could implement that without making
query_planner itself deal with grouping/sorting features (which are
supposed to be the province of grouping_planner). I chose to add a
callback function to query_planner's API; other alternatives would have
required adding more fields to PlannerInfo, which while not bad in itself
would create an ABI break for planner-related plugins in the 9.2 release
series. This still breaks ABI for anything that calls query_planner
directly, but it seems somewhat unlikely that there are any such plugins.
I had originally conceived of this change as merely a step on the way to
fixing bug #8049 from Teun Hoogendoorn; but it turns out that this fixes
that bug all by itself, as per the added regression test. The reason is
that now get_eclass_for_sort_expr is adding the ORDER BY expression at the
end of EquivalenceClass creation not the start, and so anything that is in
a multi-member EquivalenceClass has already been created with correct
em_nullable_relids. I am suspicious that there are related scenarios in
which we still need to teach get_eclass_for_sort_expr to compute correct
nullable_relids, but am not eager to risk destabilizing either 9.2 or 9.3
to fix bugs that are only hypothetical. So for the moment, do this and
stop here.
Back-patch to 9.2 but not to earlier branches, since they don't exhibit
this bug for lack of join-clause-movement logic that depends on
em_nullable_relids being correct. (We might have to revisit that choice
if any related bugs turn up.) In 9.2, don't change the signature of
make_pathkeys_for_sortclauses nor remove canonicalize_pathkeys, so as
not to risk more plugin breakage than we have to.
Diffstat (limited to 'src/backend/optimizer/plan/planmain.c')
-rw-r--r-- | src/backend/optimizer/plan/planmain.c | 52 |
1 files changed, 14 insertions, 38 deletions
diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index a919914f944..42a98945a38 100644 --- a/src/backend/optimizer/plan/planmain.c +++ b/src/backend/optimizer/plan/planmain.c @@ -30,10 +30,6 @@ #include "utils/selfuncs.h" -/* Local functions */ -static void canonicalize_all_pathkeys(PlannerInfo *root); - - /* * query_planner * Generate a path (that is, a simplified plan) for a basic query, @@ -55,6 +51,8 @@ static void canonicalize_all_pathkeys(PlannerInfo *root); * tuple_fraction is the fraction of tuples we expect will be retrieved * limit_tuples is a hard limit on number of tuples to retrieve, * or -1 if no limit + * qp_callback is a function to compute query_pathkeys once it's safe to do so + * qp_extra is optional extra data to pass to qp_callback * * Output parameters: * *cheapest_path receives the overall-cheapest path for the query @@ -63,18 +61,11 @@ static void canonicalize_all_pathkeys(PlannerInfo *root); * *num_groups receives the estimated number of groups, or 1 if query * does not use grouping * - * Note: the PlannerInfo node also includes a query_pathkeys field, which is - * both an input and an output of query_planner(). The input value signals - * query_planner that the indicated sort order is wanted in the final output - * plan. But this value has not yet been "canonicalized", since the needed - * info does not get computed until we scan the qual clauses. We canonicalize - * it as soon as that task is done. (The main reason query_pathkeys is a - * PlannerInfo field and not a passed parameter is that the low-level routines - * in indxpath.c need to see it.) - * - * Note: the PlannerInfo node includes other pathkeys fields besides - * query_pathkeys, all of which need to be canonicalized once the info is - * available. See canonicalize_all_pathkeys. + * Note: the PlannerInfo node also includes a query_pathkeys field, which + * tells query_planner the sort order that is desired in the final output + * plan. This value is *not* available at call time, but is computed by + * qp_callback once we have completed merging the query's equivalence classes. + * (We cannot construct canonical pathkeys until that's done.) * * tuple_fraction is interpreted as follows: * 0: expect all tuples to be retrieved (normal case) @@ -89,6 +80,7 @@ static void canonicalize_all_pathkeys(PlannerInfo *root); void query_planner(PlannerInfo *root, List *tlist, double tuple_fraction, double limit_tuples, + query_pathkeys_callback qp_callback, void *qp_extra, Path **cheapest_path, Path **sorted_path, double *num_groups) { @@ -118,11 +110,11 @@ query_planner(PlannerInfo *root, List *tlist, *sorted_path = NULL; /* - * We still are required to canonicalize any pathkeys, in case it's - * something like "SELECT 2+2 ORDER BY 1". + * We still are required to call qp_callback, in case it's something + * like "SELECT 2+2 ORDER BY 1". */ root->canon_pathkeys = NIL; - canonicalize_all_pathkeys(root); + (*qp_callback) (root, qp_extra); return; } @@ -205,10 +197,10 @@ query_planner(PlannerInfo *root, List *tlist, /* * We have completed merging equivalence sets, so it's now possible to - * convert previously generated pathkeys (in particular, the requested - * query_pathkeys) to canonical form. + * generate pathkeys in canonical form; so compute query_pathkeys and + * other pathkeys fields in PlannerInfo. */ - canonicalize_all_pathkeys(root); + (*qp_callback) (root, qp_extra); /* * Examine any "placeholder" expressions generated during subquery pullup. @@ -429,19 +421,3 @@ query_planner(PlannerInfo *root, List *tlist, *cheapest_path = cheapestpath; *sorted_path = sortedpath; } - - -/* - * canonicalize_all_pathkeys - * Canonicalize all pathkeys that were generated before entering - * query_planner and then stashed in PlannerInfo. - */ -static void -canonicalize_all_pathkeys(PlannerInfo *root) -{ - root->query_pathkeys = canonicalize_pathkeys(root, root->query_pathkeys); - root->group_pathkeys = canonicalize_pathkeys(root, root->group_pathkeys); - root->window_pathkeys = canonicalize_pathkeys(root, root->window_pathkeys); - root->distinct_pathkeys = canonicalize_pathkeys(root, root->distinct_pathkeys); - root->sort_pathkeys = canonicalize_pathkeys(root, root->sort_pathkeys); -} |