]> granicus.if.org Git - postgresql/blob - src/backend/optimizer/util/relnode.c
457826f5d316ff7484a096c3ffbf8b3d6fee03fd
[postgresql] / src / backend / optimizer / util / relnode.c
1 /*-------------------------------------------------------------------------
2  *
3  * relnode.c
4  *        Relation-node lookup/construction routines
5  *
6  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.35 2001/10/25 05:49:34 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "optimizer/cost.h"
18 #include "optimizer/joininfo.h"
19 #include "optimizer/pathnode.h"
20 #include "optimizer/paths.h"
21 #include "optimizer/plancat.h"
22 #include "optimizer/tlist.h"
23 #include "parser/parsetree.h"
24
25
26 static RelOptInfo *make_base_rel(Query *root, int relid);
27 static List *new_join_tlist(List *tlist, int first_resdomno);
28 static List *build_joinrel_restrictlist(Query *root,
29                                                    RelOptInfo *joinrel,
30                                                    RelOptInfo *outer_rel,
31                                                    RelOptInfo *inner_rel);
32 static void build_joinrel_joinlist(RelOptInfo *joinrel,
33                                            RelOptInfo *outer_rel,
34                                            RelOptInfo *inner_rel);
35 static List *subbuild_joinrel_restrictlist(RelOptInfo *joinrel,
36                                                           List *joininfo_list);
37 static void subbuild_joinrel_joinlist(RelOptInfo *joinrel,
38                                                   List *joininfo_list);
39
40
41 /*
42  * build_base_rel
43  *        Returns relation entry corresponding to 'relid', creating a new one
44  *        if necessary.  This is for base relations.
45  */
46 RelOptInfo *
47 build_base_rel(Query *root, int relid)
48 {
49         List       *rels;
50         RelOptInfo *rel;
51
52         /* Already made? */
53         foreach(rels, root->base_rel_list)
54         {
55                 rel = (RelOptInfo *) lfirst(rels);
56
57                 /* length(rel->relids) == 1 for all members of base_rel_list */
58                 if (lfirsti(rel->relids) == relid)
59                         return rel;
60         }
61
62         /* It should not exist as an "other" rel */
63         foreach(rels, root->other_rel_list)
64         {
65                 rel = (RelOptInfo *) lfirst(rels);
66
67                 if (lfirsti(rel->relids) == relid)
68                         elog(ERROR, "build_base_rel: rel already exists as 'other' rel");
69         }
70
71         /* No existing RelOptInfo for this base rel, so make a new one */
72         rel = make_base_rel(root, relid);
73
74         /* and add it to the list */
75         root->base_rel_list = lcons(rel, root->base_rel_list);
76
77         return rel;
78 }
79
80 /*
81  * build_other_rel
82  *        Returns relation entry corresponding to 'relid', creating a new one
83  *        if necessary.  This is for 'other' relations, which are just like
84  *        base relations except that they live in a different list.
85  */
86 RelOptInfo *
87 build_other_rel(Query *root, int relid)
88 {
89         List       *rels;
90         RelOptInfo *rel;
91
92         /* Already made? */
93         foreach(rels, root->other_rel_list)
94         {
95                 rel = (RelOptInfo *) lfirst(rels);
96
97                 /* length(rel->relids) == 1 for all members of other_rel_list */
98                 if (lfirsti(rel->relids) == relid)
99                         return rel;
100         }
101
102         /* It should not exist as a base rel */
103         foreach(rels, root->base_rel_list)
104         {
105                 rel = (RelOptInfo *) lfirst(rels);
106
107                 if (lfirsti(rel->relids) == relid)
108                         elog(ERROR, "build_other_rel: rel already exists as base rel");
109         }
110
111         /* No existing RelOptInfo for this other rel, so make a new one */
112         rel = make_base_rel(root, relid);
113
114         /* and add it to the list */
115         root->other_rel_list = lcons(rel, root->other_rel_list);
116
117         return rel;
118 }
119
120 /*
121  * make_base_rel
122  *        Construct a base-relation RelOptInfo for the specified rangetable index.
123  *
124  * Common code for build_base_rel and build_other_rel.
125  */
126 static RelOptInfo *
127 make_base_rel(Query *root, int relid)
128 {
129         RelOptInfo *rel = makeNode(RelOptInfo);
130         Oid                     relationObjectId;
131
132         rel->relids = makeListi1(relid);
133         rel->rows = 0;
134         rel->width = 0;
135         rel->targetlist = NIL;
136         rel->pathlist = NIL;
137         rel->cheapest_startup_path = NULL;
138         rel->cheapest_total_path = NULL;
139         rel->pruneable = true;
140         rel->issubquery = false;
141         rel->indexlist = NIL;
142         rel->pages = 0;
143         rel->tuples = 0;
144         rel->subplan = NULL;
145         rel->baserestrictinfo = NIL;
146         rel->baserestrictcost = 0;
147         rel->outerjoinset = NIL;
148         rel->joininfo = NIL;
149         rel->innerjoin = NIL;
150
151         /* Check rtable to see if it's a plain relation or a subquery */
152         relationObjectId = getrelid(relid, root->rtable);
153
154         if (relationObjectId != InvalidOid)
155         {
156                 /* Plain relation --- retrieve statistics from the system catalogs */
157                 bool            indexed;
158
159                 get_relation_info(relationObjectId,
160                                                   &indexed, &rel->pages, &rel->tuples);
161                 if (indexed)
162                         rel->indexlist = find_secondary_indexes(relationObjectId);
163         }
164         else
165         {
166                 /* subquery --- mark it as such for later processing */
167                 rel->issubquery = true;
168         }
169
170         return rel;
171 }
172
173 /*
174  * find_base_rel
175  *        Find a base or other relation entry, which must already exist
176  *        (since we'd have no idea which list to add it to).
177  */
178 RelOptInfo *
179 find_base_rel(Query *root, int relid)
180 {
181         List       *rels;
182         RelOptInfo *rel;
183
184         foreach(rels, root->base_rel_list)
185         {
186                 rel = (RelOptInfo *) lfirst(rels);
187
188                 /* length(rel->relids) == 1 for all members of base_rel_list */
189                 if (lfirsti(rel->relids) == relid)
190                         return rel;
191         }
192
193         foreach(rels, root->other_rel_list)
194         {
195                 rel = (RelOptInfo *) lfirst(rels);
196
197                 if (lfirsti(rel->relids) == relid)
198                         return rel;
199         }
200
201         elog(ERROR, "find_base_rel: no relation entry for relid %d", relid);
202
203         return NULL;                            /* keep compiler quiet */
204 }
205
206 /*
207  * find_join_rel
208  *        Returns relation entry corresponding to 'relids' (a list of RT indexes),
209  *        or NULL if none exists.  This is for join relations.
210  *
211  * Note: there is probably no good reason for this to be called from
212  * anywhere except build_join_rel, but keep it as a separate routine
213  * just in case.
214  */
215 static RelOptInfo *
216 find_join_rel(Query *root, Relids relids)
217 {
218         List       *joinrels;
219
220         foreach(joinrels, root->join_rel_list)
221         {
222                 RelOptInfo *rel = (RelOptInfo *) lfirst(joinrels);
223
224                 if (sameseti(rel->relids, relids))
225                         return rel;
226         }
227
228         return NULL;
229 }
230
231 /*
232  * build_join_rel
233  *        Returns relation entry corresponding to the union of two given rels,
234  *        creating a new relation entry if none already exists.
235  *
236  * 'outer_rel' and 'inner_rel' are relation nodes for the relations to be
237  *              joined
238  * 'jointype': type of join (inner/outer)
239  * 'restrictlist_ptr': result variable.  If not NULL, *restrictlist_ptr
240  *              receives the list of RestrictInfo nodes that apply to this
241  *              particular pair of joinable relations.
242  *
243  * restrictlist_ptr makes the routine's API a little grotty, but it saves
244  * duplicated calculation of the restrictlist...
245  */
246 RelOptInfo *
247 build_join_rel(Query *root,
248                            RelOptInfo *outer_rel,
249                            RelOptInfo *inner_rel,
250                            JoinType jointype,
251                            List **restrictlist_ptr)
252 {
253         List       *joinrelids;
254         RelOptInfo *joinrel;
255         List       *restrictlist;
256         List       *new_outer_tlist;
257         List       *new_inner_tlist;
258
259         /* We should never try to join two overlapping sets of rels. */
260         Assert(nonoverlap_setsi(outer_rel->relids, inner_rel->relids));
261
262         /*
263          * See if we already have a joinrel for this set of base rels.
264          *
265          * nconc(listCopy(x), y) is an idiom for making a new list without
266          * changing either input list.
267          */
268         joinrelids = nconc(listCopy(outer_rel->relids), inner_rel->relids);
269         joinrel = find_join_rel(root, joinrelids);
270
271         if (joinrel)
272         {
273                 /*
274                  * Yes, so we only need to figure the restrictlist for this
275                  * particular pair of component relations.
276                  */
277                 if (restrictlist_ptr)
278                         *restrictlist_ptr = build_joinrel_restrictlist(root,
279                                                                                                                    joinrel,
280                                                                                                                    outer_rel,
281                                                                                                                    inner_rel);
282                 return joinrel;
283         }
284
285         /*
286          * Nope, so make one.
287          */
288         joinrel = makeNode(RelOptInfo);
289         joinrel->relids = joinrelids;
290         joinrel->rows = 0;
291         joinrel->width = 0;
292         joinrel->targetlist = NIL;
293         joinrel->pathlist = NIL;
294         joinrel->cheapest_startup_path = NULL;
295         joinrel->cheapest_total_path = NULL;
296         joinrel->pruneable = true;
297         joinrel->issubquery = false;
298         joinrel->indexlist = NIL;
299         joinrel->pages = 0;
300         joinrel->tuples = 0;
301         joinrel->subplan = NULL;
302         joinrel->baserestrictinfo = NIL;
303         joinrel->baserestrictcost = 0;
304         joinrel->outerjoinset = NIL;
305         joinrel->joininfo = NIL;
306         joinrel->innerjoin = NIL;
307
308         /*
309          * Create a new tlist by removing irrelevant elements from both tlists
310          * of the outer and inner join relations and then merging the results
311          * together.
312          *
313          * NOTE: the tlist order for a join rel will depend on which pair of
314          * outer and inner rels we first try to build it from.  But the
315          * contents should be the same regardless.
316          *
317          * XXX someday: consider pruning vars from the join's targetlist if they
318          * are needed only to evaluate restriction clauses of this join, and
319          * will never be accessed at higher levels of the plantree.
320          */
321         new_outer_tlist = new_join_tlist(outer_rel->targetlist, 1);
322         new_inner_tlist = new_join_tlist(inner_rel->targetlist,
323                                                                          length(new_outer_tlist) + 1);
324         joinrel->targetlist = nconc(new_outer_tlist, new_inner_tlist);
325
326         /*
327          * Construct restrict and join clause lists for the new joinrel. (The
328          * caller might or might not need the restrictlist, but I need it
329          * anyway for set_joinrel_size_estimates().)
330          */
331         restrictlist = build_joinrel_restrictlist(root,
332                                                                                           joinrel,
333                                                                                           outer_rel,
334                                                                                           inner_rel);
335         if (restrictlist_ptr)
336                 *restrictlist_ptr = restrictlist;
337         build_joinrel_joinlist(joinrel, outer_rel, inner_rel);
338
339         /*
340          * Set estimates of the joinrel's size.
341          */
342         set_joinrel_size_estimates(root, joinrel, outer_rel, inner_rel,
343                                                            jointype, restrictlist);
344
345         /*
346          * Add the joinrel to the query's joinrel list.
347          */
348         root->join_rel_list = lcons(joinrel, root->join_rel_list);
349
350         return joinrel;
351 }
352
353 /*
354  * new_join_tlist
355  *        Builds a join relation's target list by keeping those elements that
356  *        will be in the final target list and any other elements that are still
357  *        needed for future joins.      For a target list entry to still be needed
358  *        for future joins, its 'joinlist' field must not be empty after removal
359  *        of all relids in 'other_relids'.
360  *
361  *        XXX the above comment refers to code that is long dead and gone;
362  *        we don't keep track of joinlists for individual targetlist entries
363  *        anymore.      For now, all vars present in either input tlist will be
364  *        emitted in the join's tlist.
365  *
366  * 'tlist' is the target list of one of the join relations
367  * 'first_resdomno' is the resdom number to use for the first created
368  *                              target list entry
369  *
370  * Returns the new target list.
371  */
372 static List *
373 new_join_tlist(List *tlist,
374                            int first_resdomno)
375 {
376         int                     resdomno = first_resdomno - 1;
377         List       *t_list = NIL;
378         List       *i;
379
380         foreach(i, tlist)
381         {
382                 TargetEntry *xtl = lfirst(i);
383
384                 resdomno += 1;
385                 t_list = lappend(t_list,
386                                                  create_tl_element(get_expr(xtl), resdomno));
387         }
388
389         return t_list;
390 }
391
392 /*
393  * build_joinrel_restrictlist
394  * build_joinrel_joinlist
395  *        These routines build lists of restriction and join clauses for a
396  *        join relation from the joininfo lists of the relations it joins.
397  *
398  *        These routines are separate because the restriction list must be
399  *        built afresh for each pair of input sub-relations we consider, whereas
400  *        the join lists need only be computed once for any join RelOptInfo.
401  *        The join lists are fully determined by the set of rels making up the
402  *        joinrel, so we should get the same results (up to ordering) from any
403  *        candidate pair of sub-relations.      But the restriction list is whatever
404  *        is not handled in the sub-relations, so it depends on which
405  *        sub-relations are considered.
406  *
407  *        If a join clause from an input relation refers to base rels still not
408  *        present in the joinrel, then it is still a join clause for the joinrel;
409  *        we put it into an appropriate JoinInfo list for the joinrel.  Otherwise,
410  *        the clause is now a restrict clause for the joined relation, and we
411  *        return it to the caller of build_joinrel_restrictlist() to be stored in
412  *        join paths made from this pair of sub-relations.      (It will not need to
413  *        be considered further up the join tree.)
414  *
415  *        When building a restriction list, we eliminate redundant clauses.
416  *        We don't try to do that for join clause lists, since the join clauses
417  *        aren't really doing anything, just waiting to become part of higher
418  *        levels' restriction lists.
419  *
420  * 'joinrel' is a join relation node
421  * 'outer_rel' and 'inner_rel' are a pair of relations that can be joined
422  *              to form joinrel.
423  *
424  * build_joinrel_restrictlist() returns a list of relevant restrictinfos,
425  * whereas build_joinrel_joinlist() stores its results in the joinrel's
426  * joininfo lists.      One or the other must accept each given clause!
427  *
428  * NB: Formerly, we made deep(!) copies of each input RestrictInfo to pass
429  * up to the join relation.  I believe this is no longer necessary, because
430  * RestrictInfo nodes are no longer context-dependent.  Instead, just include
431  * the original nodes in the lists made for the join relation.
432  */
433 static List *
434 build_joinrel_restrictlist(Query *root,
435                                                    RelOptInfo *joinrel,
436                                                    RelOptInfo *outer_rel,
437                                                    RelOptInfo *inner_rel)
438 {
439         List       *result = NIL;
440         List       *rlist;
441         List       *item;
442
443         /*
444          * Collect all the clauses that syntactically belong at this level.
445          */
446         rlist = nconc(subbuild_joinrel_restrictlist(joinrel,
447                                                                                                 outer_rel->joininfo),
448                                   subbuild_joinrel_restrictlist(joinrel,
449                                                                                                 inner_rel->joininfo));
450
451         /*
452          * Eliminate duplicate and redundant clauses.
453          *
454          * We must eliminate duplicates, since we will see many of the same
455          * clauses arriving from both input relations.  Also, if a clause is a
456          * mergejoinable clause, it's possible that it is redundant with
457          * previous clauses (see optimizer/README for discussion).      We detect
458          * that case and omit the redundant clause from the result list.
459          *
460          * We can detect redundant mergejoinable clauses very cheaply by using
461          * their left and right pathkeys, which uniquely identify the sets of
462          * equijoined variables in question.  All the members of a pathkey set
463          * that are in the left relation have already been forced to be equal;
464          * likewise for those in the right relation.  So, we need to have only
465          * one clause that checks equality between any set member on the left
466          * and any member on the right; by transitivity, all the rest are then
467          * equal.
468          */
469         foreach(item, rlist)
470         {
471                 RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
472
473                 /* eliminate duplicates */
474                 if (member(rinfo, result))
475                         continue;
476
477                 /* check for redundant merge clauses */
478                 if (rinfo->mergejoinoperator != InvalidOid)
479                 {
480                         bool            redundant = false;
481                         List       *olditem;
482
483                         cache_mergeclause_pathkeys(root, rinfo);
484
485                         foreach(olditem, result)
486                         {
487                                 RestrictInfo *oldrinfo = (RestrictInfo *) lfirst(olditem);
488
489                                 if (oldrinfo->mergejoinoperator != InvalidOid &&
490                                         rinfo->left_pathkey == oldrinfo->left_pathkey &&
491                                         rinfo->right_pathkey == oldrinfo->right_pathkey)
492                                 {
493                                         redundant = true;
494                                         break;
495                                 }
496                         }
497
498                         if (redundant)
499                                 continue;
500                 }
501
502                 /* otherwise, add it to result list */
503                 result = lappend(result, rinfo);
504         }
505
506         freeList(rlist);
507
508         return result;
509 }
510
511 static void
512 build_joinrel_joinlist(RelOptInfo *joinrel,
513                                            RelOptInfo *outer_rel,
514                                            RelOptInfo *inner_rel)
515 {
516         subbuild_joinrel_joinlist(joinrel, outer_rel->joininfo);
517         subbuild_joinrel_joinlist(joinrel, inner_rel->joininfo);
518 }
519
520 static List *
521 subbuild_joinrel_restrictlist(RelOptInfo *joinrel,
522                                                           List *joininfo_list)
523 {
524         List       *restrictlist = NIL;
525         List       *xjoininfo;
526
527         foreach(xjoininfo, joininfo_list)
528         {
529                 JoinInfo   *joininfo = (JoinInfo *) lfirst(xjoininfo);
530
531                 if (is_subseti(joininfo->unjoined_relids, joinrel->relids))
532                 {
533                         /*
534                          * Clauses in this JoinInfo list become restriction clauses
535                          * for the joinrel, since they refer to no outside rels.
536                          *
537                          * We must copy the list to avoid disturbing the input relation,
538                          * but we can use a shallow copy.
539                          */
540                         restrictlist = nconc(restrictlist,
541                                                                  listCopy(joininfo->jinfo_restrictinfo));
542                 }
543                 else
544                 {
545                         /*
546                          * These clauses are still join clauses at this level, so we
547                          * ignore them in this routine.
548                          */
549                 }
550         }
551
552         return restrictlist;
553 }
554
555 static void
556 subbuild_joinrel_joinlist(RelOptInfo *joinrel,
557                                                   List *joininfo_list)
558 {
559         List       *xjoininfo;
560
561         foreach(xjoininfo, joininfo_list)
562         {
563                 JoinInfo   *joininfo = (JoinInfo *) lfirst(xjoininfo);
564                 Relids          new_unjoined_relids;
565
566                 new_unjoined_relids = set_differencei(joininfo->unjoined_relids,
567                                                                                           joinrel->relids);
568                 if (new_unjoined_relids == NIL)
569                 {
570                         /*
571                          * Clauses in this JoinInfo list become restriction clauses
572                          * for the joinrel, since they refer to no outside rels. So we
573                          * can ignore them in this routine.
574                          */
575                 }
576                 else
577                 {
578                         /*
579                          * These clauses are still join clauses at this level, so find
580                          * or make the appropriate JoinInfo item for the joinrel, and
581                          * add the clauses to it (eliminating duplicates).
582                          */
583                         JoinInfo   *new_joininfo;
584
585                         new_joininfo = find_joininfo_node(joinrel, new_unjoined_relids);
586                         new_joininfo->jinfo_restrictinfo =
587                                 set_union(new_joininfo->jinfo_restrictinfo,
588                                                   joininfo->jinfo_restrictinfo);
589                 }
590         }
591 }