1 /*-------------------------------------------------------------------------
4 * Routines to manipulate pathlists and create path nodes
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.20 1999/02/08 04:29:21 momjian Exp $
12 *-------------------------------------------------------------------------
18 #include "nodes/relation.h"
19 #include "utils/elog.h"
21 #include "optimizer/internal.h"
22 #include "optimizer/pathnode.h"
23 #include "optimizer/restrictinfo.h"
24 #include "optimizer/plancat.h"
25 #include "optimizer/cost.h"
26 #include "optimizer/keys.h"
27 #include "optimizer/xfunc.h"
28 #include "optimizer/ordering.h"
30 #include "parser/parsetree.h" /* for getrelid() */
32 static Path *better_path(Path *new_path, List *unique_paths, bool *noOther);
35 /*****************************************************************************
36 * MISC. PATH UTILITIES
37 *****************************************************************************/
41 * Returns t iff 'path1' is cheaper than 'path2'.
45 path_is_cheaper(Path *path1, Path *path2)
47 Cost cost1 = path1->path_cost;
48 Cost cost2 = path2->path_cost;
50 return (bool) (cost1 < cost2);
55 * Finds the minimum cost path from among a relation's paths.
57 * 'parent-rel' is the parent relation
58 * 'pathlist' is a list of path nodes corresponding to 'parent-rel'
60 * Returns and sets the relation entry field with the pathnode that
65 set_cheapest(RelOptInfo *parent_rel, List *pathlist)
68 Path *cheapest_so_far;
70 Assert(pathlist != NIL);
71 Assert(IsA(parent_rel, RelOptInfo));
73 cheapest_so_far = (Path *) lfirst(pathlist);
75 foreach(p, lnext(pathlist))
77 Path *path = (Path *) lfirst(p);
79 if (path_is_cheaper(path, cheapest_so_far))
80 cheapest_so_far = path;
83 parent_rel->cheapestpath = cheapest_so_far;
85 return cheapest_so_far;
90 * For each path in the list 'new-paths', add to the list 'unique-paths'
91 * only those paths that are unique (i.e., unique ordering and ordering
92 * keys). Should a conflict arise, the more expensive path is thrown out,
93 * thereby pruning the plan space. But we don't prune if xfunc
96 * 'parent-rel' is the relation entry to which these paths correspond.
98 * Returns the list of unique pathnodes.
102 add_pathlist(RelOptInfo *parent_rel, List *unique_paths, List *new_paths)
106 foreach(p1, new_paths)
108 Path *new_path = (Path *) lfirst(p1);
112 /* Is this new path already in unique_paths? */
113 if (member(new_path, unique_paths))
116 /* Find best matching path */
117 old_path = better_path(new_path, unique_paths, &noOther);
121 /* This is a brand new path. */
122 new_path->parent = parent_rel;
123 unique_paths = lcons(new_path, unique_paths);
125 else if (old_path == NULL)
127 ; /* do nothing if path is not cheaper */
129 else if (old_path != NULL)
130 { /* (IsA(old_path,Path)) { */
131 new_path->parent = parent_rel;
132 if (!parent_rel->pruneable)
133 unique_paths = lcons(new_path, unique_paths);
135 unique_paths = lcons(new_path,
136 LispRemove(old_path, unique_paths));
144 * Determines whether 'new-path' has the same ordering and keys as some
145 * path in the list 'unique-paths'. If there is a redundant path,
146 * eliminate the more expensive path.
149 * The old path - if 'new-path' matches some path in 'unique-paths' and is
151 * nil - if 'new-path' matches but isn't cheaper
152 * t - if there is no path in the list with the same ordering and keys
156 better_path(Path *new_path, List *unique_paths, bool *noOther)
158 Path *old_path = (Path *) NULL;
159 Path *path = (Path *) NULL;
163 foreach(temp, unique_paths)
165 path = (Path *) lfirst(temp);
167 if (samekeys(path->keys, new_path->keys) &&
168 equal_path_ordering(&path->path_order,
169 &new_path->path_order))
176 if (old_path == NULL)
181 if (path_is_cheaper(new_path, old_path))
190 /*****************************************************************************
191 * PATH NODE CREATION ROUTINES
192 *****************************************************************************/
195 * create_seqscan_path--
196 * Creates a path corresponding to a sequential scan, returning the
201 create_seqscan_path(RelOptInfo * rel)
205 Path *pathnode = makeNode(Path);
207 pathnode->pathtype = T_SeqScan;
208 pathnode->parent = rel;
209 pathnode->path_cost = 0.0;
210 pathnode->path_order.ordtype = SORTOP_ORDER;
211 pathnode->path_order.ord.sortop = NULL;
212 pathnode->keys = NIL;
215 * copy restrictinfo list into path for expensive function processing --
218 pathnode->loc_restrictinfo = (List *) copyObject((Node *) rel->restrictinfo);
220 if (rel->relids != NULL)
221 relid = lfirsti(rel->relids);
223 pathnode->path_cost = cost_seqscan(relid,
224 rel->pages, rel->tuples);
225 /* add in expensive functions cost! -- JMH, 7/7/92 */
227 if (XfuncMode != XFUNC_OFF)
229 pathnode->path_cost += xfunc_get_path_cost(pathnode);
236 * create_index_path--
237 * Creates a single path node for an index scan.
239 * 'rel' is the parent rel
240 * 'index' is the pathnode for the index on 'rel'
241 * 'restriction-clauses' is a list of restriction clause nodes.
242 * 'is-join-scan' is a flag indicating whether or not the index is being
243 * considered because of its sort order.
245 * Returns the new path node.
249 create_index_path(Query *root,
252 List *restriction_clauses,
255 IndexPath *pathnode = makeNode(IndexPath);
257 pathnode->path.pathtype = T_IndexScan;
258 pathnode->path.parent = rel;
259 pathnode->path.path_order.ordtype = SORTOP_ORDER;
260 pathnode->path.path_order.ord.sortop = index->ordering;
262 pathnode->indexid = index->relids;
263 pathnode->indexkeys = index->indexkeys;
264 pathnode->indexqual = NIL;
267 * copy restrictinfo list into path for expensive function processing --
270 pathnode->path.loc_restrictinfo = set_difference((List *) copyObject((Node *) rel->restrictinfo),
271 (List *) restriction_clauses);
274 * The index must have an ordering for the path to have (ordering)
275 * keys, and vice versa.
277 if (pathnode->path.path_order.ord.sortop)
279 pathnode->path.keys = collect_index_pathkeys(index->indexkeys,
283 * Check that the keys haven't 'disappeared', since they may no
284 * longer be in the target list (i.e., index keys that are not
285 * relevant to the scan are not applied to the scan path node, so
286 * if no index keys were found, we can't order the path).
288 if (pathnode->path.keys == NULL)
289 pathnode->path.path_order.ord.sortop = NULL;
292 pathnode->path.keys = NULL;
294 if (is_join_scan || restriction_clauses == NULL)
298 * Indices used for joins or sorting result nodes don't restrict
299 * the result at all, they simply order it, so compute the scan
300 * cost accordingly -- use a selectivity of 1.0.
302 /* is the statement above really true? what about IndexScan as the
304 pathnode->path.path_cost = cost_index(lfirsti(index->relids),
312 /* add in expensive functions cost! -- JMH, 7/7/92 */
314 if (XfuncMode != XFUNC_OFF)
316 pathnode->path_cost = (pathnode->path_cost +
317 xfunc_get_path_cost((Path *) pathnode));
325 * Compute scan cost for the case when 'index' is used with a
326 * restriction clause.
335 get_relattvals(restriction_clauses,
339 index_selectivity(lfirsti(index->relids),
341 get_opnos(restriction_clauses),
342 getrelid(lfirsti(rel->relids),
347 length(restriction_clauses),
350 /* each clause gets an equal selectivity */
351 clausesel = pow(selec, 1.0 / (double) length(restriction_clauses));
353 pathnode->indexqual = restriction_clauses;
354 pathnode->path.path_cost = cost_index(lfirsti(index->relids),
364 /* add in expensive functions cost! -- JMH, 7/7/92 */
365 if (XfuncMode != XFUNC_OFF)
367 pathnode->path_cost += xfunc_get_path_cost((Path *) pathnode);
372 * Set selectivities of clauses used with index to the selectivity
373 * of this index, subdividing the selectivity equally over each of
377 /* XXX Can this divide the selectivities in a better way? */
378 set_clause_selectivities(restriction_clauses, clausesel);
384 * create_nestloop_path--
385 * Creates a pathnode corresponding to a nestloop join between two
388 * 'joinrel' is the join relation.
389 * 'outer_rel' is the outer join relation
390 * 'outer_path' is the outer join path.
391 * 'inner_path' is the inner join path.
392 * 'keys' are the keys of the path
394 * Returns the resulting path node.
398 create_nestloop_path(RelOptInfo * joinrel,
399 RelOptInfo * outer_rel,
404 JoinPath *pathnode = makeNode(JoinPath);
406 pathnode->path.pathtype = T_NestLoop;
407 pathnode->path.parent = joinrel;
408 pathnode->outerjoinpath = outer_path;
409 pathnode->innerjoinpath = inner_path;
410 pathnode->pathinfo = joinrel->restrictinfo;
411 pathnode->path.keys = keys;
412 pathnode->path.joinid = NIL;
413 pathnode->path.outerjoincost = (Cost) 0.0;
414 pathnode->path.loc_restrictinfo = NIL;
418 pathnode->path.path_order.ordtype = outer_path->path_order.ordtype;
419 if (outer_path->path_order.ordtype == SORTOP_ORDER)
421 pathnode->path.path_order.ord.sortop = outer_path->path_order.ord.sortop;
425 pathnode->path.path_order.ord.merge = outer_path->path_order.ord.merge;
430 pathnode->path.path_order.ordtype = SORTOP_ORDER;
431 pathnode->path.path_order.ord.sortop = NULL;
434 pathnode->path.path_cost = cost_nestloop(outer_path->path_cost,
435 inner_path->path_cost,
437 inner_path->parent->size,
438 page_size(outer_rel->size,
440 IsA(inner_path, IndexPath));
441 /* add in expensive function costs -- JMH 7/7/92 */
443 if (XfuncMode != XFUNC_OFF)
444 pathnode->path_cost += xfunc_get_path_cost((Path *) pathnode);
450 * create_mergejoin_path--
451 * Creates a pathnode corresponding to a mergejoin join between
454 * 'joinrel' is the join relation
455 * 'outersize' is the number of tuples in the outer relation
456 * 'innersize' is the number of tuples in the inner relation
457 * 'outerwidth' is the number of bytes per tuple in the outer relation
458 * 'innerwidth' is the number of bytes per tuple in the inner relation
459 * 'outer_path' is the outer path
460 * 'inner_path' is the inner path
461 * 'keys' are the new keys of the join relation
462 * 'order' is the sort order required for the merge
463 * 'mergeclauses' are the applicable join/restriction clauses
464 * 'outersortkeys' are the sort varkeys for the outer relation
465 * 'innersortkeys' are the sort varkeys for the inner relation
469 create_mergejoin_path(RelOptInfo * joinrel,
482 MergePath *pathnode = makeNode(MergePath);
484 pathnode->jpath.path.pathtype = T_MergeJoin;
485 pathnode->jpath.path.parent = joinrel;
486 pathnode->jpath.outerjoinpath = outer_path;
487 pathnode->jpath.innerjoinpath = inner_path;
488 pathnode->jpath.pathinfo = joinrel->restrictinfo;
489 pathnode->jpath.path.keys = keys;
490 pathnode->jpath.path.path_order.ordtype = MERGE_ORDER;
491 pathnode->jpath.path.path_order.ord.merge = order;
492 pathnode->path_mergeclauses = mergeclauses;
493 pathnode->jpath.path.loc_restrictinfo = NIL;
494 pathnode->outersortkeys = outersortkeys;
495 pathnode->innersortkeys = innersortkeys;
496 pathnode->jpath.path.path_cost = cost_mergejoin(outer_path->path_cost,
497 inner_path->path_cost,
504 /* add in expensive function costs -- JMH 7/7/92 */
506 if (XfuncMode != XFUNC_OFF)
508 pathnode->path_cost += xfunc_get_path_cost((Path *) pathnode);
515 * create_hashjoin_path-- XXX HASH
516 * Creates a pathnode corresponding to a hash join between two relations.
518 * 'joinrel' is the join relation
519 * 'outersize' is the number of tuples in the outer relation
520 * 'innersize' is the number of tuples in the inner relation
521 * 'outerwidth' is the number of bytes per tuple in the outer relation
522 * 'innerwidth' is the number of bytes per tuple in the inner relation
523 * 'outer_path' is the outer path
524 * 'inner_path' is the inner path
525 * 'keys' are the new keys of the join relation
526 * 'operator' is the hashjoin operator
527 * 'hashclauses' are the applicable join/restriction clauses
528 * 'outerkeys' are the sort varkeys for the outer relation
529 * 'innerkeys' are the sort varkeys for the inner relation
533 create_hashjoin_path(RelOptInfo * joinrel,
546 HashPath *pathnode = makeNode(HashPath);
548 pathnode->jpath.path.pathtype = T_HashJoin;
549 pathnode->jpath.path.parent = joinrel;
550 pathnode->jpath.outerjoinpath = outer_path;
551 pathnode->jpath.innerjoinpath = inner_path;
552 pathnode->jpath.pathinfo = joinrel->restrictinfo;
553 pathnode->jpath.path.loc_restrictinfo = NIL;
554 pathnode->jpath.path.keys = keys;
555 pathnode->jpath.path.path_order.ordtype = SORTOP_ORDER;
556 pathnode->jpath.path.path_order.ord.sortop = NULL;
557 pathnode->jpath.path.outerjoincost = (Cost) 0.0;
558 pathnode->jpath.path.joinid = (Relid) NULL;
559 /* pathnode->hashjoinoperator = operator; */
560 pathnode->path_hashclauses = hashclauses;
561 pathnode->outerhashkeys = outerkeys;
562 pathnode->innerhashkeys = innerkeys;
563 pathnode->jpath.path.path_cost = cost_hashjoin(outer_path->path_cost,
564 inner_path->path_cost,
567 outersize, innersize,
568 outerwidth, innerwidth);
569 /* add in expensive function costs -- JMH 7/7/92 */
571 if (XfuncMode != XFUNC_OFF)
573 pathnode->path_cost += xfunc_get_path_cost((Path *) pathnode);