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-2025, 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
6843 tgl@sss.pgh.pa.us 39 :CBC 191703 : have_relevant_joinclause(PlannerInfo *root,
40 : : RelOptInfo *rel1, RelOptInfo *rel2)
41 : : {
7394 42 : 191703 : 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 [ + + ]: 191703 : if (list_length(rel1->joininfo) <= list_length(rel2->joininfo))
52 : : {
53 : 143507 : joininfo = rel1->joininfo;
4894 54 : 143507 : other_relids = rel2->relids;
55 : : }
56 : : else
57 : : {
7394 58 : 48196 : joininfo = rel2->joininfo;
4894 59 : 48196 : other_relids = rel1->relids;
60 : : }
61 : :
7394 62 [ + + + + : 208235 : foreach(l, joininfo)
+ + ]
63 : : {
64 : 93876 : RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
65 : :
4894 66 [ + + ]: 93876 : if (bms_overlap(other_relids, rinfo->required_relids))
67 : : {
7394 68 : 77344 : result = true;
69 : 77344 : 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 : : */
6804 77 [ + + + + : 191703 : if (!result && rel1->has_eclass_joins && rel2->has_eclass_joins)
+ + ]
78 : 86892 : result = have_relevant_eclass_joinclause(root, rel1, rel2);
79 : :
7394 80 : 191703 : 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
7398 98 : 34656 : 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 */
592 drowley@postgresql.o 105 [ - + ]: 34656 : if (restriction_is_always_true(root, restrictinfo))
592 drowley@postgresql.o 106 :LBC (6) : return;
107 : :
108 : : /*
109 : : * Substitute the origin qual with constant-FALSE if it is provably always
110 : : * false.
111 : : *
112 : : * Note that we need to keep the same rinfo_serial, since it is in
113 : : * practice the same condition. We also need to reset the
114 : : * last_rinfo_serial counter, which is essential to ensure that the
115 : : * RestrictInfos for the "same" qual condition get identical serial
116 : : * numbers (see deconstruct_distribute_oj_quals).
117 : : */
592 drowley@postgresql.o 118 [ - + ]:CBC 34656 : if (restriction_is_always_false(root, restrictinfo))
119 : : {
592 drowley@postgresql.o 120 :LBC (6) : int save_rinfo_serial = restrictinfo->rinfo_serial;
302 rguo@postgresql.org 121 : (6) : int save_last_rinfo_serial = root->last_rinfo_serial;
122 : :
592 drowley@postgresql.o 123 : (6) : restrictinfo = make_restrictinfo(root,
124 : (6) : (Expr *) makeBoolConst(false, false),
125 : (6) : restrictinfo->is_pushed_down,
126 : (6) : restrictinfo->has_clone,
127 : (6) : restrictinfo->is_clone,
128 : (6) : restrictinfo->pseudoconstant,
129 : : 0, /* security_level */
130 : : restrictinfo->required_relids,
131 : : restrictinfo->incompatible_relids,
132 : : restrictinfo->outer_relids);
133 : (6) : restrictinfo->rinfo_serial = save_rinfo_serial;
302 rguo@postgresql.org 134 : (6) : root->last_rinfo_serial = save_last_rinfo_serial;
135 : : }
136 : :
3935 tgl@sss.pgh.pa.us 137 :CBC 34656 : cur_relid = -1;
138 [ + + ]: 111722 : while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0)
139 : : {
950 140 : 77066 : RelOptInfo *rel = find_base_rel_ignore_join(root, cur_relid);
141 : :
142 : : /* We only need to add the clause to baserels */
143 [ + + ]: 77066 : if (rel == NULL)
144 : 4727 : continue;
7394 145 : 72339 : rel->joininfo = lappend(rel->joininfo, restrictinfo);
146 : : }
147 : : }
148 : :
149 : : /*
150 : : * remove_join_clause_from_rels
151 : : * Delete 'restrictinfo' from all the joininfo lists it is in
152 : : *
153 : : * This reverses the effect of add_join_clause_to_rels. It's used when we
154 : : * discover that a relation need not be joined at all.
155 : : *
156 : : * 'restrictinfo' describes the join clause
157 : : * 'join_relids' is the set of relations participating in the join clause
158 : : * (some of these could be outer joins)
159 : : */
160 : : void
5471 161 : 5428 : remove_join_clause_from_rels(PlannerInfo *root,
162 : : RestrictInfo *restrictinfo,
163 : : Relids join_relids)
164 : : {
165 : : int cur_relid;
166 : :
3935 167 : 5428 : cur_relid = -1;
168 [ + + ]: 16507 : while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0)
169 : : {
950 170 : 11079 : RelOptInfo *rel = find_base_rel_ignore_join(root, cur_relid);
171 : :
172 : : /* We would only have added the clause to baserels */
173 [ + + ]: 11079 : if (rel == NULL)
174 : 126 : continue;
175 : :
176 : : /*
177 : : * Remove the restrictinfo from the list. Pointer comparison is
178 : : * sufficient.
179 : : */
5471 180 [ - + ]: 10953 : Assert(list_member_ptr(rel->joininfo, restrictinfo));
181 : 10953 : rel->joininfo = list_delete_ptr(rel->joininfo, restrictinfo);
182 : : }
183 : 5428 : }
|