Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * joininfo.c
4 : * joininfo list manipulation routines
5 : *
6 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/optimizer/util/joininfo.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #include "postgres.h"
16 :
17 : #include "optimizer/joininfo.h"
18 : #include "optimizer/pathnode.h"
19 : #include "optimizer/paths.h"
20 :
21 :
22 : /*
23 : * have_relevant_joinclause
24 : * Detect whether there is a joinclause that involves
25 : * the two given relations.
26 : *
27 : * Note: the joinclause does not have to be evaluable with only these two
28 : * relations. This is intentional. For example consider
29 : * SELECT * FROM a, b, c WHERE a.x = (b.y + c.z)
30 : * If a is much larger than the other tables, it may be worthwhile to
31 : * cross-join b and c and then use an inner indexscan on a.x. Therefore
32 : * we should consider this joinclause as reason to join b to c, even though
33 : * it can't be applied at that join step.
34 : */
35 : bool
5962 tgl 36 CBC 141471 : have_relevant_joinclause(PlannerInfo *root,
37 : RelOptInfo *rel1, RelOptInfo *rel2)
38 : {
6513 39 141471 : bool result = false;
40 : List *joininfo;
41 : Relids other_relids;
42 : ListCell *l;
43 :
44 : /*
45 : * We could scan either relation's joininfo list; may as well use the
46 : * shorter one.
47 : */
48 141471 : if (list_length(rel1->joininfo) <= list_length(rel2->joininfo))
49 : {
50 106996 : joininfo = rel1->joininfo;
4013 51 106996 : other_relids = rel2->relids;
52 : }
53 : else
54 : {
6513 55 34475 : joininfo = rel2->joininfo;
4013 56 34475 : other_relids = rel1->relids;
57 : }
58 :
6513 59 156764 : foreach(l, joininfo)
60 : {
61 75709 : RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
62 :
4013 63 75709 : if (bms_overlap(other_relids, rinfo->required_relids))
64 : {
6513 65 60416 : result = true;
66 60416 : break;
67 : }
68 : }
69 :
70 : /*
71 : * We also need to check the EquivalenceClass data structure, which might
72 : * contain relationships not emitted into the joininfo lists.
73 : */
5923 74 141471 : if (!result && rel1->has_eclass_joins && rel2->has_eclass_joins)
75 60654 : result = have_relevant_eclass_joinclause(root, rel1, rel2);
76 :
6513 77 141471 : return result;
78 : }
79 :
80 :
81 : /*
82 : * add_join_clause_to_rels
83 : * Add 'restrictinfo' to the joininfo list of each relation it requires.
84 : *
85 : * Note that the same copy of the restrictinfo node is linked to by all the
86 : * lists it is in. This allows us to exploit caching of information about
87 : * the restriction clause (but we must be careful that the information does
88 : * not depend on context).
89 : *
90 : * 'restrictinfo' describes the join clause
91 : * 'join_relids' is the set of relations participating in the join clause
92 : * (some of these could be outer joins)
93 : */
94 : void
6517 95 27014 : add_join_clause_to_rels(PlannerInfo *root,
96 : RestrictInfo *restrictinfo,
97 : Relids join_relids)
98 : {
99 : int cur_relid;
100 :
3054 101 27014 : cur_relid = -1;
102 87039 : while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0)
103 : {
69 tgl 104 GNC 60025 : RelOptInfo *rel = find_base_rel_ignore_join(root, cur_relid);
105 :
106 : /* We only need to add the clause to baserels */
107 60025 : if (rel == NULL)
108 3094 : continue;
6513 tgl 109 GIC 56931 : rel->joininfo = lappend(rel->joininfo, restrictinfo);
7380 tgl 110 ECB : }
7380 tgl 111 CBC 27014 : }
4590 tgl 112 ECB :
113 : /*
114 : * remove_join_clause_from_rels
115 : * Delete 'restrictinfo' from all the joininfo lists it is in
116 : *
117 : * This reverses the effect of add_join_clause_to_rels. It's used when we
118 : * discover that a relation need not be joined at all.
119 : *
120 : * 'restrictinfo' describes the join clause
121 : * 'join_relids' is the set of relations participating in the join clause
122 : * (some of these could be outer joins)
123 : */
124 : void
4590 tgl 125 GIC 4096 : remove_join_clause_from_rels(PlannerInfo *root,
126 : RestrictInfo *restrictinfo,
127 : Relids join_relids)
4590 tgl 128 ECB : {
129 : int cur_relid;
130 :
3054 tgl 131 GIC 4096 : cur_relid = -1;
132 12385 : while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0)
133 : {
69 tgl 134 GNC 8289 : RelOptInfo *rel = find_base_rel_ignore_join(root, cur_relid);
135 :
136 : /* We would only have added the clause to baserels */
137 8289 : if (rel == NULL)
138 79 : continue;
4590 tgl 139 ECB :
140 : /*
141 : * Remove the restrictinfo from the list. Pointer comparison is
142 : * sufficient.
143 : */
4590 tgl 144 CBC 8210 : Assert(list_member_ptr(rel->joininfo, restrictinfo));
145 8210 : rel->joininfo = list_delete_ptr(rel->joininfo, restrictinfo);
146 : }
4590 tgl 147 GIC 4096 : }
|