1 /*-------------------------------------------------------------------------
4 * Routines to plan a single query
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.42 1999/08/22 20:14:48 tgl Exp $
12 *-------------------------------------------------------------------------
14 #include <sys/types.h>
19 #include "optimizer/clauses.h"
20 #include "optimizer/cost.h"
21 #include "optimizer/paths.h"
22 #include "optimizer/planmain.h"
23 #include "optimizer/prep.h"
24 #include "optimizer/subselect.h"
25 #include "optimizer/tlist.h"
26 #include "utils/lsyscache.h"
29 static Plan *subplanner(Query *root, List *flat_tlist, List *qual);
33 * Routine to create a query plan. It does so by first creating a
34 * subplan for the topmost level of attributes in the query. Then,
35 * it modifies all target list and qualifications to consider the next
36 * level of nesting and creates a plan for this modified query by
37 * recursively calling itself. The two pieces are then merged together
38 * by creating a result node that indicates which attributes should
39 * be placed where and any relation level qualifications to be
42 * command-type is the query command, e.g., select, delete, etc.
43 * tlist is the target list of the query
44 * qual is the qualification of the query
46 * Note: the Query node now also includes a query_pathkeys field, which
47 * signals query_planner that the indicated sort order is wanted in the
48 * final output plan. If, for some reason, query_planner is unable to
49 * comply, it sets query_pathkeys to NIL before returning. (The reason
50 * query_pathkeys is a Query field and not a passed parameter is that
51 * the low-level routines in indxpath.c need to see it.)
53 * Returns a query plan.
56 query_planner(Query *root,
61 List *constant_qual = NIL;
66 if (PlannerQueryLevel > 1)
68 /* should copy be made ? */
69 tlist = (List *) SS_replace_correlation_vars((Node *) tlist);
70 qual = (List *) SS_replace_correlation_vars((Node *) qual);
72 if (root->hasSubLinks)
73 qual = (List *) SS_process_sublinks((Node *) qual);
75 qual = cnfify((Expr *) qual, true);
76 #ifdef OPTIMIZER_DEBUG
77 printf("After cnfify()\n");
82 * Pull out any non-variable qualifications so these can be put in the
83 * topmost result node.
85 qual = pull_constant_clauses(qual, &constant_qual);
88 * Create a target list that consists solely of (resdom var) target
89 * list entries, i.e., contains no arbitrary expressions.
91 var_only_tlist = flatten_tlist(tlist);
93 level_tlist = var_only_tlist;
95 /* from old code. the logic is beyond me. - ay 2/95 */
99 * A query may have a non-variable target list and a non-variable
100 * qualification only under certain conditions: - the query creates
101 * all-new tuples, or - the query is a replace (a scan must still be
102 * done in this case).
104 if (var_only_tlist == NULL && qual == NULL)
106 root->query_pathkeys = NIL; /* these plans make unordered results */
108 switch (command_type)
112 return ((Plan *) make_result(tlist,
113 (Node *) constant_qual,
119 SeqScan *scan = make_seqscan(tlist,
121 root->resultRelation);
123 if (constant_qual != NULL)
124 return ((Plan *) make_result(tlist,
125 (Node *) constant_qual,
128 return (Plan *) scan;
132 return (Plan *) NULL;
137 * Choose the best access path and build a plan for it.
139 subplan = subplanner(root, level_tlist, qual);
142 * Build a result node linking the plan if we have constant quals
146 subplan = (Plan *) make_result(tlist,
147 (Node *) constant_qual,
150 root->query_pathkeys = NIL; /* result is unordered, no? */
156 * Replace the toplevel plan node's flattened target list with the
157 * targetlist given by my caller, so that expressions are evaluated.
159 * This implies that all expression evaluations are done at the root
160 * of the plan tree. Once upon a time there was code to try to push
161 * expensive function calls down to lower plan nodes, but that's dead
162 * code and has been for a long time...
166 subplan->targetlist = tlist;
174 * Destructively modify the query plan's targetlist to add fjoin lists
175 * to flatten functions that return sets of base types
177 subplan->targetlist = generate_fjoin(subplan->targetlist);
185 * Subplanner creates an entire plan consisting of joins and scans
186 * for processing a single level of attributes.
188 * flat_tlist is the flattened target list
189 * qual is the qualification to be satisfied
195 subplanner(Query *root,
199 RelOptInfo *final_rel;
204 * Initialize the targetlist and qualification, adding entries to
205 * base_rel_list as relation references are found (e.g., in the
206 * qualification, the targetlist, etc.)
208 root->base_rel_list = NIL;
209 root->join_rel_list = NIL;
211 make_var_only_tlist(root, flat_tlist);
212 add_restrict_and_join_to_rels(root, qual);
213 add_missing_vars_to_tlist(root, flat_tlist);
215 set_joininfo_mergeable_hashable(root->base_rel_list);
217 final_rel = make_one_rel(root, root->base_rel_list);
219 #ifdef NOT_USED /* fix xfunc */
222 * Perform Predicate Migration on each path, to optimize and correctly
223 * assess the cost of each before choosing the cheapest one. -- JMH,
226 * Needn't do so if the top rel is pruneable: that means there's no
227 * expensive functions left to pull up. -- JMH, 11/22/92
229 if (XfuncMode != XFUNC_OFF && XfuncMode != XFUNC_NOPM &&
230 XfuncMode != XFUNC_NOPULL && !final_rel->pruneable)
234 foreach(pathnode, final_rel->pathlist)
236 if (xfunc_do_predmig((Path *) lfirst(pathnode)))
237 set_cheapest(final_rel, final_rel->pathlist);
244 elog(NOTICE, "final relation is null");
245 root->query_pathkeys = NIL; /* result is unordered, no? */
246 return create_plan((Path *) NULL);
250 * Determine the cheapest path and create a subplan to execute it.
252 * If no special sort order is wanted, or if the cheapest path is
253 * already appropriately ordered, just use the cheapest path.
255 if (root->query_pathkeys == NIL ||
256 pathkeys_contained_in(root->query_pathkeys,
257 final_rel->cheapestpath->pathkeys))
258 return create_plan(final_rel->cheapestpath);
260 * Otherwise, look to see if we have an already-ordered path that is
261 * cheaper than doing an explicit sort on cheapestpath.
263 cheapest_cost = final_rel->cheapestpath->path_cost +
264 cost_sort(root->query_pathkeys, final_rel->size, final_rel->width);
266 sortedpath = get_cheapest_path_for_pathkeys(final_rel->pathlist,
267 root->query_pathkeys,
271 if (sortedpath->path_cost <= cheapest_cost)
273 /* Found a better presorted path, use it */
274 return create_plan(sortedpath);
276 /* otherwise, doing it the hard way is still cheaper */
281 * If we found no usable presorted path at all, it is possible
282 * that the user asked for descending sort order. Check to see
283 * if we can satisfy the pathkeys by using a backwards indexscan.
284 * To do this, we commute all the operators in the pathkeys and
285 * then look for a matching path that is an IndexPath.
287 List *commuted_pathkeys = copyObject(root->query_pathkeys);
289 if (commute_pathkeys(commuted_pathkeys))
291 /* pass 'true' to force only IndexPaths to be considered */
292 sortedpath = get_cheapest_path_for_pathkeys(final_rel->pathlist,
295 if (sortedpath && sortedpath->path_cost <= cheapest_cost)
298 * Kluge here: since IndexPath has no representation for
299 * backwards scan, we have to convert to Plan format and
300 * then poke the result.
302 Plan *sortedplan = create_plan(sortedpath);
304 Assert(IsA(sortedplan, IndexScan));
305 ((IndexScan *) sortedplan)->indxorderdir = BackwardScanDirection;
311 /* Nothing for it but to sort the cheapestpath...
313 * We indicate we failed to sort the plan, and let the caller
314 * stick the appropriate sort node on top. union_planner has to be
315 * able to add a sort node anyway, so no need for extra code here.
317 root->query_pathkeys = NIL; /* sorry, it ain't sorted */
319 return create_plan(final_rel->cheapestpath);