Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * joininfo.c
4 : : * joininfo list manipulation routines
5 : : *
6 : : * Portions Copyright (c) 1996-2024, 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 "nodes/makefuncs.h"
18 : : #include "optimizer/joininfo.h"
19 : : #include "optimizer/pathnode.h"
20 : : #include "optimizer/paths.h"
21 : : #include "optimizer/planmain.h"
22 : : #include "optimizer/restrictinfo.h"
23 : :
24 : :
25 : : /*
26 : : * have_relevant_joinclause
27 : : * Detect whether there is a joinclause that involves
28 : : * the two given relations.
29 : : *
30 : : * Note: the joinclause does not have to be evaluable with only these two
31 : : * relations. This is intentional. For example consider
32 : : * SELECT * FROM a, b, c WHERE a.x = (b.y + c.z)
33 : : * If a is much larger than the other tables, it may be worthwhile to
34 : : * cross-join b and c and then use an inner indexscan on a.x. Therefore
35 : : * we should consider this joinclause as reason to join b to c, even though
36 : : * it can't be applied at that join step.
37 : : */
38 : : bool
6333 tgl@sss.pgh.pa.us 39 :CBC 169207 : have_relevant_joinclause(PlannerInfo *root,
40 : : RelOptInfo *rel1, RelOptInfo *rel2)
41 : : {
6884 42 : 169207 : bool result = false;
43 : : List *joininfo;
44 : : Relids other_relids;
45 : : ListCell *l;
46 : :
47 : : /*
48 : : * We could scan either relation's joininfo list; may as well use the
49 : : * shorter one.
50 : : */
51 [ + + ]: 169207 : if (list_length(rel1->joininfo) <= list_length(rel2->joininfo))
52 : : {
53 : 124686 : joininfo = rel1->joininfo;
4384 54 : 124686 : other_relids = rel2->relids;
55 : : }
56 : : else
57 : : {
6884 58 : 44521 : joininfo = rel2->joininfo;
4384 59 : 44521 : other_relids = rel1->relids;
60 : : }
61 : :
6884 62 [ + + + + : 186737 : foreach(l, joininfo)
+ + ]
63 : : {
64 : 90546 : RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
65 : :
4384 66 [ + + ]: 90546 : if (bms_overlap(other_relids, rinfo->required_relids))
67 : : {
6884 68 : 73016 : result = true;
69 : 73016 : break;
70 : : }
71 : : }
72 : :
73 : : /*
74 : : * We also need to check the EquivalenceClass data structure, which might
75 : : * contain relationships not emitted into the joininfo lists.
76 : : */
6294 77 [ + + + + : 169207 : if (!result && rel1->has_eclass_joins && rel2->has_eclass_joins)
+ + ]
78 : 70924 : result = have_relevant_eclass_joinclause(root, rel1, rel2);
79 : :
6884 80 : 169207 : return result;
81 : : }
82 : :
83 : :
84 : : /*
85 : : * add_join_clause_to_rels
86 : : * Add 'restrictinfo' to the joininfo list of each relation it requires.
87 : : *
88 : : * Note that the same copy of the restrictinfo node is linked to by all the
89 : : * lists it is in. This allows us to exploit caching of information about
90 : : * the restriction clause (but we must be careful that the information does
91 : : * not depend on context).
92 : : *
93 : : * 'restrictinfo' describes the join clause
94 : : * 'join_relids' is the set of relations participating in the join clause
95 : : * (some of these could be outer joins)
96 : : */
97 : : void
6888 98 : 31846 : add_join_clause_to_rels(PlannerInfo *root,
99 : : RestrictInfo *restrictinfo,
100 : : Relids join_relids)
101 : : {
102 : : int cur_relid;
103 : :
104 : : /* Don't add the clause if it is always true */
82 drowley@postgresql.o 105 [ + + ]:GNC 31846 : if (restriction_is_always_true(root, restrictinfo))
106 : 12 : return;
107 : :
108 : : /*
109 : : * Substitute constant-FALSE for the origin qual if it is always false.
110 : : * Note that we keep the same rinfo_serial.
111 : : */
112 [ + + ]: 31834 : if (restriction_is_always_false(root, restrictinfo))
113 : : {
114 : 6 : int save_rinfo_serial = restrictinfo->rinfo_serial;
115 : :
116 : 6 : restrictinfo = make_restrictinfo(root,
117 : 6 : (Expr *) makeBoolConst(false, false),
118 : 6 : restrictinfo->is_pushed_down,
119 : 6 : restrictinfo->has_clone,
120 : 6 : restrictinfo->is_clone,
121 : 6 : restrictinfo->pseudoconstant,
122 : : 0, /* security_level */
123 : : restrictinfo->required_relids,
124 : : restrictinfo->incompatible_relids,
125 : : restrictinfo->outer_relids);
126 : 6 : restrictinfo->rinfo_serial = save_rinfo_serial;
127 : : }
128 : :
3425 tgl@sss.pgh.pa.us 129 :CBC 31834 : cur_relid = -1;
130 [ + + ]: 102652 : while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0)
131 : : {
440 132 : 70818 : RelOptInfo *rel = find_base_rel_ignore_join(root, cur_relid);
133 : :
134 : : /* We only need to add the clause to baserels */
135 [ + + ]: 70818 : if (rel == NULL)
136 : 4158 : continue;
6884 137 : 66660 : rel->joininfo = lappend(rel->joininfo, restrictinfo);
138 : : }
7751 tgl@sss.pgh.pa.us 139 :ECB (28636) : }
140 : :
141 : : /*
142 : : * remove_join_clause_from_rels
143 : : * Delete 'restrictinfo' from all the joininfo lists it is in
144 : : *
145 : : * This reverses the effect of add_join_clause_to_rels. It's used when we
146 : : * discover that a relation need not be joined at all.
147 : : *
148 : : * 'restrictinfo' describes the join clause
149 : : * 'join_relids' is the set of relations participating in the join clause
150 : : * (some of these could be outer joins)
151 : : */
152 : : void
4961 tgl@sss.pgh.pa.us 153 :CBC 4872 : remove_join_clause_from_rels(PlannerInfo *root,
154 : : RestrictInfo *restrictinfo,
155 : : Relids join_relids)
156 : : {
157 : : int cur_relid;
158 : :
3425 159 : 4872 : cur_relid = -1;
160 [ + + ]: 14812 : while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0)
161 : : {
440 162 : 9940 : RelOptInfo *rel = find_base_rel_ignore_join(root, cur_relid);
163 : :
164 : : /* We would only have added the clause to baserels */
165 [ + + ]: 9940 : if (rel == NULL)
166 : 121 : continue;
167 : :
168 : : /*
169 : : * Remove the restrictinfo from the list. Pointer comparison is
170 : : * sufficient.
171 : : */
4961 172 [ - + ]: 9819 : Assert(list_member_ptr(rel->joininfo, restrictinfo));
173 : 9819 : rel->joininfo = list_delete_ptr(rel->joininfo, restrictinfo);
174 : : }
175 : 4872 : }
|