Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * joininfo.c
4 : * joininfo list manipulation routines
5 : *
6 : * Portions Copyright (c) 1996-2026, 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
39 242035 : have_relevant_joinclause(PlannerInfo *root,
40 : RelOptInfo *rel1, RelOptInfo *rel2)
41 : {
42 242035 : 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 242035 : if (list_length(rel1->joininfo) <= list_length(rel2->joininfo))
52 : {
53 183620 : joininfo = rel1->joininfo;
54 183620 : other_relids = rel2->relids;
55 : }
56 : else
57 : {
58 58415 : joininfo = rel2->joininfo;
59 58415 : other_relids = rel1->relids;
60 : }
61 :
62 260644 : foreach(l, joininfo)
63 : {
64 106928 : RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
65 :
66 106928 : if (bms_overlap(other_relids, rinfo->required_relids))
67 : {
68 88319 : result = true;
69 88319 : 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 : */
77 242035 : if (!result && rel1->has_eclass_joins && rel2->has_eclass_joins)
78 119665 : result = have_relevant_eclass_joinclause(root, rel1, rel2);
79 :
80 242035 : 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
98 38475 : 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 */
105 38475 : if (restriction_is_always_true(root, restrictinfo))
106 0 : 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 : */
118 38475 : if (restriction_is_always_false(root, restrictinfo))
119 : {
120 0 : int save_rinfo_serial = restrictinfo->rinfo_serial;
121 0 : int save_last_rinfo_serial = root->last_rinfo_serial;
122 :
123 0 : restrictinfo = make_restrictinfo(root,
124 0 : (Expr *) makeBoolConst(false, false),
125 0 : restrictinfo->is_pushed_down,
126 0 : restrictinfo->has_clone,
127 0 : restrictinfo->is_clone,
128 0 : restrictinfo->pseudoconstant,
129 : 0, /* security_level */
130 : restrictinfo->required_relids,
131 : restrictinfo->incompatible_relids,
132 : restrictinfo->outer_relids);
133 0 : restrictinfo->rinfo_serial = save_rinfo_serial;
134 0 : root->last_rinfo_serial = save_last_rinfo_serial;
135 : }
136 :
137 38475 : cur_relid = -1;
138 123632 : while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0)
139 : {
140 85157 : RelOptInfo *rel = find_base_rel_ignore_join(root, cur_relid);
141 :
142 : /* We only need to add the clause to baserels */
143 85157 : if (rel == NULL)
144 5107 : continue;
145 80050 : 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
161 6481 : remove_join_clause_from_rels(PlannerInfo *root,
162 : RestrictInfo *restrictinfo,
163 : Relids join_relids)
164 : {
165 : int cur_relid;
166 :
167 6481 : cur_relid = -1;
168 19670 : while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0)
169 : {
170 13189 : RelOptInfo *rel = find_base_rel_ignore_join(root, cur_relid);
171 :
172 : /* We would only have added the clause to baserels */
173 13189 : if (rel == NULL)
174 128 : continue;
175 :
176 : /*
177 : * Remove the restrictinfo from the list. Pointer comparison is
178 : * sufficient.
179 : */
180 : Assert(list_member_ptr(rel->joininfo, restrictinfo));
181 13061 : rel->joininfo = list_delete_ptr(rel->joininfo, restrictinfo);
182 : }
183 6481 : }
|