|
20 | 20 | */
|
21 | 21 | #include "postgres.h"
|
22 | 22 |
|
23 |
| -#include "miscadmin.h" |
24 |
| -#include "optimizer/cost.h" |
25 | 23 | #include "optimizer/pathnode.h"
|
26 | 24 | #include "optimizer/paths.h"
|
27 | 25 | #include "optimizer/placeholder.h"
|
28 | 26 | #include "optimizer/planmain.h"
|
29 |
| -#include "optimizer/tlist.h" |
30 |
| -#include "utils/selfuncs.h" |
31 | 27 |
|
32 | 28 |
|
33 | 29 | /*
|
|
36 | 32 | * which may involve joins but not any fancier features.
|
37 | 33 | *
|
38 | 34 | * Since query_planner does not handle the toplevel processing (grouping,
|
39 |
| - * sorting, etc) it cannot select the best path by itself. It selects |
40 |
| - * two paths: the cheapest path that produces all the required tuples, |
41 |
| - * independent of any ordering considerations, and the cheapest path that |
42 |
| - * produces the expected fraction of the required tuples in the required |
43 |
| - * ordering, if there is a path that is cheaper for this than just sorting |
44 |
| - * the output of the cheapest overall path. The caller (grouping_planner) |
45 |
| - * will make the final decision about which to use. |
| 35 | + * sorting, etc) it cannot select the best path by itself. Instead, it |
| 36 | + * returns the RelOptInfo for the top level of joining, and the caller |
| 37 | + * (grouping_planner) can choose one of the surviving paths for the rel. |
| 38 | + * Normally it would choose either the rel's cheapest path, or the cheapest |
| 39 | + * path for the desired sort order. |
46 | 40 | *
|
47 |
| - * Input parameters: |
48 | 41 | * root describes the query to plan
|
49 | 42 | * tlist is the target list the query should produce
|
50 | 43 | * (this is NOT necessarily root->parse->targetList!)
|
51 |
| - * tuple_fraction is the fraction of tuples we expect will be retrieved |
52 |
| - * limit_tuples is a hard limit on number of tuples to retrieve, |
53 |
| - * or -1 if no limit |
54 | 44 | * qp_callback is a function to compute query_pathkeys once it's safe to do so
|
55 | 45 | * qp_extra is optional extra data to pass to qp_callback
|
56 | 46 | *
|
57 |
| - * Output parameters: |
58 |
| - * *cheapest_path receives the overall-cheapest path for the query |
59 |
| - * *sorted_path receives the cheapest presorted path for the query, |
60 |
| - * if any (NULL if there is no useful presorted path) |
61 |
| - * *num_groups receives the estimated number of groups, or 1 if query |
62 |
| - * does not use grouping |
63 |
| - * |
64 | 47 | * Note: the PlannerInfo node also includes a query_pathkeys field, which
|
65 | 48 | * tells query_planner the sort order that is desired in the final output
|
66 | 49 | * plan. This value is *not* available at call time, but is computed by
|
67 | 50 | * qp_callback once we have completed merging the query's equivalence classes.
|
68 | 51 | * (We cannot construct canonical pathkeys until that's done.)
|
69 |
| - * |
70 |
| - * tuple_fraction is interpreted as follows: |
71 |
| - * 0: expect all tuples to be retrieved (normal case) |
72 |
| - * 0 < tuple_fraction < 1: expect the given fraction of tuples available |
73 |
| - * from the plan to be retrieved |
74 |
| - * tuple_fraction >= 1: tuple_fraction is the absolute number of tuples |
75 |
| - * expected to be retrieved (ie, a LIMIT specification) |
76 |
| - * Note that a nonzero tuple_fraction could come from outer context; it is |
77 |
| - * therefore not redundant with limit_tuples. We use limit_tuples to determine |
78 |
| - * whether a bounded sort can be used at runtime. |
79 | 52 | */
|
80 |
| -void |
| 53 | +RelOptInfo * |
81 | 54 | query_planner(PlannerInfo *root, List *tlist,
|
82 |
| - double tuple_fraction, double limit_tuples, |
83 |
| - query_pathkeys_callback qp_callback, void *qp_extra, |
84 |
| - Path **cheapest_path, Path **sorted_path, |
85 |
| - double *num_groups) |
| 55 | + query_pathkeys_callback qp_callback, void *qp_extra) |
86 | 56 | {
|
87 | 57 | Query *parse = root->parse;
|
88 | 58 | List *joinlist;
|
89 | 59 | RelOptInfo *final_rel;
|
90 |
| - Path *cheapestpath; |
91 |
| - Path *sortedpath; |
92 | 60 | Index rti;
|
93 | 61 | double total_pages;
|
94 | 62 |
|
95 |
| - /* Make tuple_fraction, limit_tuples accessible to lower-level routines */ |
96 |
| - root->tuple_fraction = tuple_fraction; |
97 |
| - root->limit_tuples = limit_tuples; |
98 |
| - |
99 |
| - *num_groups = 1; /* default result */ |
100 |
| - |
101 | 63 | /*
|
102 | 64 | * If the query has an empty join tree, then it's something easy like
|
103 | 65 | * "SELECT 2+2;" or "INSERT ... VALUES()". Fall through quickly.
|
104 | 66 | */
|
105 | 67 | if (parse->jointree->fromlist == NIL)
|
106 | 68 | {
|
107 |
| - /* We need a trivial path result */ |
108 |
| - *cheapest_path = (Path *) |
109 |
| - create_result_path((List *) parse->jointree->quals); |
110 |
| - *sorted_path = NULL; |
| 69 | + /* We need a dummy joinrel to describe the empty set of baserels */ |
| 70 | + final_rel = build_empty_join_rel(root); |
| 71 | + |
| 72 | + /* The only path for it is a trivial Result path */ |
| 73 | + add_path(final_rel, (Path *) |
| 74 | + create_result_path((List *) parse->jointree->quals)); |
| 75 | + |
| 76 | + /* Select cheapest path (pretty easy in this case...) */ |
| 77 | + set_cheapest(final_rel); |
111 | 78 |
|
112 | 79 | /*
|
113 | 80 | * We still are required to call qp_callback, in case it's something
|
114 | 81 | * like "SELECT 2+2 ORDER BY 1".
|
115 | 82 | */
|
116 | 83 | root->canon_pathkeys = NIL;
|
117 | 84 | (*qp_callback) (root, qp_extra);
|
118 |
| - return; |
| 85 | + |
| 86 | + return final_rel; |
119 | 87 | }
|
120 | 88 |
|
121 | 89 | /*
|
@@ -259,165 +227,10 @@ query_planner(PlannerInfo *root, List *tlist,
|
259 | 227 | */
|
260 | 228 | final_rel = make_one_rel(root, joinlist);
|
261 | 229 |
|
| 230 | + /* Check that we got at least one usable path */ |
262 | 231 | if (!final_rel || !final_rel->cheapest_total_path ||
|
263 | 232 | final_rel->cheapest_total_path->param_info != NULL)
|
264 | 233 | elog(ERROR, "failed to construct the join relation");
|
265 | 234 |
|
266 |
| - /* |
267 |
| - * If there's grouping going on, estimate the number of result groups. We |
268 |
| - * couldn't do this any earlier because it depends on relation size |
269 |
| - * estimates that were set up above. |
270 |
| - * |
271 |
| - * Then convert tuple_fraction to fractional form if it is absolute, and |
272 |
| - * adjust it based on the knowledge that grouping_planner will be doing |
273 |
| - * grouping or aggregation work with our result. |
274 |
| - * |
275 |
| - * This introduces some undesirable coupling between this code and |
276 |
| - * grouping_planner, but the alternatives seem even uglier; we couldn't |
277 |
| - * pass back completed paths without making these decisions here. |
278 |
| - */ |
279 |
| - if (parse->groupClause) |
280 |
| - { |
281 |
| - List *groupExprs; |
282 |
| - |
283 |
| - groupExprs = get_sortgrouplist_exprs(parse->groupClause, |
284 |
| - parse->targetList); |
285 |
| - *num_groups = estimate_num_groups(root, |
286 |
| - groupExprs, |
287 |
| - final_rel->rows); |
288 |
| - |
289 |
| - /* |
290 |
| - * In GROUP BY mode, an absolute LIMIT is relative to the number of |
291 |
| - * groups not the number of tuples. If the caller gave us a fraction, |
292 |
| - * keep it as-is. (In both cases, we are effectively assuming that |
293 |
| - * all the groups are about the same size.) |
294 |
| - */ |
295 |
| - if (tuple_fraction >= 1.0) |
296 |
| - tuple_fraction /= *num_groups; |
297 |
| - |
298 |
| - /* |
299 |
| - * If both GROUP BY and ORDER BY are specified, we will need two |
300 |
| - * levels of sort --- and, therefore, certainly need to read all the |
301 |
| - * tuples --- unless ORDER BY is a subset of GROUP BY. Likewise if we |
302 |
| - * have both DISTINCT and GROUP BY, or if we have a window |
303 |
| - * specification not compatible with the GROUP BY. |
304 |
| - */ |
305 |
| - if (!pathkeys_contained_in(root->sort_pathkeys, root->group_pathkeys) || |
306 |
| - !pathkeys_contained_in(root->distinct_pathkeys, root->group_pathkeys) || |
307 |
| - !pathkeys_contained_in(root->window_pathkeys, root->group_pathkeys)) |
308 |
| - tuple_fraction = 0.0; |
309 |
| - |
310 |
| - /* In any case, limit_tuples shouldn't be specified here */ |
311 |
| - Assert(limit_tuples < 0); |
312 |
| - } |
313 |
| - else if (parse->hasAggs || root->hasHavingQual) |
314 |
| - { |
315 |
| - /* |
316 |
| - * Ungrouped aggregate will certainly want to read all the tuples, and |
317 |
| - * it will deliver a single result row (so leave *num_groups 1). |
318 |
| - */ |
319 |
| - tuple_fraction = 0.0; |
320 |
| - |
321 |
| - /* limit_tuples shouldn't be specified here */ |
322 |
| - Assert(limit_tuples < 0); |
323 |
| - } |
324 |
| - else if (parse->distinctClause) |
325 |
| - { |
326 |
| - /* |
327 |
| - * Since there was no grouping or aggregation, it's reasonable to |
328 |
| - * assume the UNIQUE filter has effects comparable to GROUP BY. Return |
329 |
| - * the estimated number of output rows for use by caller. (If DISTINCT |
330 |
| - * is used with grouping, we ignore its effects for rowcount |
331 |
| - * estimation purposes; this amounts to assuming the grouped rows are |
332 |
| - * distinct already.) |
333 |
| - */ |
334 |
| - List *distinctExprs; |
335 |
| - |
336 |
| - distinctExprs = get_sortgrouplist_exprs(parse->distinctClause, |
337 |
| - parse->targetList); |
338 |
| - *num_groups = estimate_num_groups(root, |
339 |
| - distinctExprs, |
340 |
| - final_rel->rows); |
341 |
| - |
342 |
| - /* |
343 |
| - * Adjust tuple_fraction the same way as for GROUP BY, too. |
344 |
| - */ |
345 |
| - if (tuple_fraction >= 1.0) |
346 |
| - tuple_fraction /= *num_groups; |
347 |
| - |
348 |
| - /* limit_tuples shouldn't be specified here */ |
349 |
| - Assert(limit_tuples < 0); |
350 |
| - } |
351 |
| - else |
352 |
| - { |
353 |
| - /* |
354 |
| - * Plain non-grouped, non-aggregated query: an absolute tuple fraction |
355 |
| - * can be divided by the number of tuples. |
356 |
| - */ |
357 |
| - if (tuple_fraction >= 1.0) |
358 |
| - tuple_fraction /= final_rel->rows; |
359 |
| - } |
360 |
| - |
361 |
| - /* |
362 |
| - * Pick out the cheapest-total path and the cheapest presorted path for |
363 |
| - * the requested pathkeys (if there is one). We should take the tuple |
364 |
| - * fraction into account when selecting the cheapest presorted path, but |
365 |
| - * not when selecting the cheapest-total path, since if we have to sort |
366 |
| - * then we'll have to fetch all the tuples. (But there's a special case: |
367 |
| - * if query_pathkeys is NIL, meaning order doesn't matter, then the |
368 |
| - * "cheapest presorted" path will be the cheapest overall for the tuple |
369 |
| - * fraction.) |
370 |
| - * |
371 |
| - * The cheapest-total path is also the one to use if grouping_planner |
372 |
| - * decides to use hashed aggregation, so we return it separately even if |
373 |
| - * this routine thinks the presorted path is the winner. |
374 |
| - */ |
375 |
| - cheapestpath = final_rel->cheapest_total_path; |
376 |
| - |
377 |
| - sortedpath = |
378 |
| - get_cheapest_fractional_path_for_pathkeys(final_rel->pathlist, |
379 |
| - root->query_pathkeys, |
380 |
| - NULL, |
381 |
| - tuple_fraction); |
382 |
| - |
383 |
| - /* Don't return same path in both guises; just wastes effort */ |
384 |
| - if (sortedpath == cheapestpath) |
385 |
| - sortedpath = NULL; |
386 |
| - |
387 |
| - /* |
388 |
| - * Forget about the presorted path if it would be cheaper to sort the |
389 |
| - * cheapest-total path. Here we need consider only the behavior at the |
390 |
| - * tuple fraction point. |
391 |
| - */ |
392 |
| - if (sortedpath) |
393 |
| - { |
394 |
| - Path sort_path; /* dummy for result of cost_sort */ |
395 |
| - |
396 |
| - if (root->query_pathkeys == NIL || |
397 |
| - pathkeys_contained_in(root->query_pathkeys, |
398 |
| - cheapestpath->pathkeys)) |
399 |
| - { |
400 |
| - /* No sort needed for cheapest path */ |
401 |
| - sort_path.startup_cost = cheapestpath->startup_cost; |
402 |
| - sort_path.total_cost = cheapestpath->total_cost; |
403 |
| - } |
404 |
| - else |
405 |
| - { |
406 |
| - /* Figure cost for sorting */ |
407 |
| - cost_sort(&sort_path, root, root->query_pathkeys, |
408 |
| - cheapestpath->total_cost, |
409 |
| - final_rel->rows, final_rel->width, |
410 |
| - 0.0, work_mem, limit_tuples); |
411 |
| - } |
412 |
| - |
413 |
| - if (compare_fractional_path_costs(sortedpath, &sort_path, |
414 |
| - tuple_fraction) > 0) |
415 |
| - { |
416 |
| - /* Presorted path is a loser */ |
417 |
| - sortedpath = NULL; |
418 |
| - } |
419 |
| - } |
420 |
| - |
421 |
| - *cheapest_path = cheapestpath; |
422 |
| - *sorted_path = sortedpath; |
| 235 | + return final_rel; |
423 | 236 | }
|
0 commit comments