PostgreSQL Source Code git master
joininfo.c
Go to the documentation of this file.
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"
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 */
38bool
40 RelOptInfo *rel1, RelOptInfo *rel2)
41{
42 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 if (list_length(rel1->joininfo) <= list_length(rel2->joininfo))
52 {
53 joininfo = rel1->joininfo;
54 other_relids = rel2->relids;
55 }
56 else
57 {
58 joininfo = rel2->joininfo;
59 other_relids = rel1->relids;
60 }
61
62 foreach(l, joininfo)
63 {
64 RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
65
66 if (bms_overlap(other_relids, rinfo->required_relids))
67 {
68 result = true;
69 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 if (!result && rel1->has_eclass_joins && rel2->has_eclass_joins)
78 result = have_relevant_eclass_joinclause(root, rel1, rel2);
79
80 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 */
97void
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 if (restriction_is_always_true(root, restrictinfo))
106 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 if (restriction_is_always_false(root, restrictinfo))
119 {
120 int save_rinfo_serial = restrictinfo->rinfo_serial;
121 int save_last_rinfo_serial = root->last_rinfo_serial;
122
123 restrictinfo = make_restrictinfo(root,
124 (Expr *) makeBoolConst(false, false),
125 restrictinfo->is_pushed_down,
126 restrictinfo->has_clone,
127 restrictinfo->is_clone,
128 restrictinfo->pseudoconstant,
129 0, /* security_level */
130 restrictinfo->required_relids,
131 restrictinfo->incompatible_relids,
132 restrictinfo->outer_relids);
133 restrictinfo->rinfo_serial = save_rinfo_serial;
134 root->last_rinfo_serial = save_last_rinfo_serial;
135 }
136
137 cur_relid = -1;
138 while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0)
139 {
140 RelOptInfo *rel = find_base_rel_ignore_join(root, cur_relid);
141
142 /* We only need to add the clause to baserels */
143 if (rel == NULL)
144 continue;
145 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 */
160void
162 RestrictInfo *restrictinfo,
163 Relids join_relids)
164{
165 int cur_relid;
166
167 cur_relid = -1;
168 while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0)
169 {
170 RelOptInfo *rel = find_base_rel_ignore_join(root, cur_relid);
171
172 /* We would only have added the clause to baserels */
173 if (rel == NULL)
174 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 rel->joininfo = list_delete_ptr(rel->joininfo, restrictinfo);
182 }
183}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:582
bool have_relevant_eclass_joinclause(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
Definition: equivclass.c:3147
Assert(PointerIsAligned(start, uint64))
bool restriction_is_always_true(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:3091
bool restriction_is_always_false(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:3149
void remove_join_clause_from_rels(PlannerInfo *root, RestrictInfo *restrictinfo, Relids join_relids)
Definition: joininfo.c:161
void add_join_clause_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo, Relids join_relids)
Definition: joininfo.c:98
bool have_relevant_joinclause(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
Definition: joininfo.c:39
List * list_delete_ptr(List *list, void *datum)
Definition: list.c:872
List * lappend(List *list, void *datum)
Definition: list.c:339
bool list_member_ptr(const List *list, const void *datum)
Definition: list.c:682
Node * makeBoolConst(bool value, bool isnull)
Definition: makefuncs.c:408
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
tree ctl root
Definition: radixtree.h:1857
RelOptInfo * find_base_rel_ignore_join(PlannerInfo *root, int relid)
Definition: relnode.c:454
RestrictInfo * make_restrictinfo(PlannerInfo *root, Expr *clause, bool is_pushed_down, bool has_clone, bool is_clone, bool pseudoconstant, Index security_level, Relids required_relids, Relids incompatible_relids, Relids outer_relids)
Definition: restrictinfo.c:52
Definition: pg_list.h:54
List * joininfo
Definition: pathnodes.h:1018
Relids relids
Definition: pathnodes.h:898
bool has_eclass_joins
Definition: pathnodes.h:1020
bool is_pushed_down
Definition: pathnodes.h:2605
Relids required_relids
Definition: pathnodes.h:2633
int rinfo_serial
Definition: pathnodes.h:2674
Relids outer_relids
Definition: pathnodes.h:2639
Relids incompatible_relids
Definition: pathnodes.h:2636
bool has_clone
Definition: pathnodes.h:2614