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-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
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  */
97 void
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 constant-FALSE for the origin qual if it is always false.
110  * Note that we keep the same rinfo_serial.
111  */
112  if (restriction_is_always_false(root, restrictinfo))
113  {
114  int save_rinfo_serial = restrictinfo->rinfo_serial;
115 
116  restrictinfo = make_restrictinfo(root,
117  (Expr *) makeBoolConst(false, false),
118  restrictinfo->is_pushed_down,
119  restrictinfo->has_clone,
120  restrictinfo->is_clone,
121  restrictinfo->pseudoconstant,
122  0, /* security_level */
123  restrictinfo->required_relids,
124  restrictinfo->incompatible_relids,
125  restrictinfo->outer_relids);
126  restrictinfo->rinfo_serial = save_rinfo_serial;
127  }
128 
129  cur_relid = -1;
130  while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0)
131  {
132  RelOptInfo *rel = find_base_rel_ignore_join(root, cur_relid);
133 
134  /* We only need to add the clause to baserels */
135  if (rel == NULL)
136  continue;
137  rel->joininfo = lappend(rel->joininfo, restrictinfo);
138  }
139 }
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
154  RestrictInfo *restrictinfo,
155  Relids join_relids)
156 {
157  int cur_relid;
158 
159  cur_relid = -1;
160  while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0)
161  {
162  RelOptInfo *rel = find_base_rel_ignore_join(root, cur_relid);
163 
164  /* We would only have added the clause to baserels */
165  if (rel == NULL)
166  continue;
167 
168  /*
169  * Remove the restrictinfo from the list. Pointer comparison is
170  * sufficient.
171  */
172  Assert(list_member_ptr(rel->joininfo, restrictinfo));
173  rel->joininfo = list_delete_ptr(rel->joininfo, restrictinfo);
174  }
175 }
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
#define Assert(condition)
Definition: c.h:858
bool have_relevant_eclass_joinclause(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
Definition: equivclass.c:3103
bool restriction_is_always_true(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2732
bool restriction_is_always_false(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2781
void remove_join_clause_from_rels(PlannerInfo *root, RestrictInfo *restrictinfo, Relids join_relids)
Definition: joininfo.c:153
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:359
#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:1880
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:63
Definition: pg_list.h:54
List * joininfo
Definition: pathnodes.h:981
Relids relids
Definition: pathnodes.h:861
bool has_eclass_joins
Definition: pathnodes.h:983
bool is_pushed_down
Definition: pathnodes.h:2555
Relids required_relids
Definition: pathnodes.h:2583
int rinfo_serial
Definition: pathnodes.h:2624
Relids outer_relids
Definition: pathnodes.h:2589
Relids incompatible_relids
Definition: pathnodes.h:2586
bool has_clone
Definition: pathnodes.h:2564