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 39 336246 : have_relevant_joinclause(PlannerInfo *root, 40 : RelOptInfo *rel1, RelOptInfo *rel2) 41 : { 42 336246 : 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 336246 : if (list_length(rel1->joininfo) <= list_length(rel2->joininfo)) 52 : { 53 254484 : joininfo = rel1->joininfo; 54 254484 : other_relids = rel2->relids; 55 : } 56 : else 57 : { 58 81762 : joininfo = rel2->joininfo; 59 81762 : other_relids = rel1->relids; 60 : } 61 : 62 360578 : foreach(l, joininfo) 63 : { 64 159322 : RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); 65 : 66 159322 : if (bms_overlap(other_relids, rinfo->required_relids)) 67 : { 68 134990 : result = true; 69 134990 : 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 336246 : if (!result && rel1->has_eclass_joins && rel2->has_eclass_joins) 78 153708 : result = have_relevant_eclass_joinclause(root, rel1, rel2); 79 : 80 336246 : 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 61718 : 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 61718 : if (restriction_is_always_true(root, restrictinfo)) 106 24 : 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 61694 : if (restriction_is_always_false(root, restrictinfo)) 119 : { 120 18 : int save_rinfo_serial = restrictinfo->rinfo_serial; 121 18 : int save_last_rinfo_serial = root->last_rinfo_serial; 122 : 123 18 : restrictinfo = make_restrictinfo(root, 124 18 : (Expr *) makeBoolConst(false, false), 125 18 : restrictinfo->is_pushed_down, 126 18 : restrictinfo->has_clone, 127 18 : restrictinfo->is_clone, 128 18 : restrictinfo->pseudoconstant, 129 : 0, /* security_level */ 130 : restrictinfo->required_relids, 131 : restrictinfo->incompatible_relids, 132 : restrictinfo->outer_relids); 133 18 : restrictinfo->rinfo_serial = save_rinfo_serial; 134 18 : root->last_rinfo_serial = save_last_rinfo_serial; 135 : } 136 : 137 61694 : cur_relid = -1; 138 198884 : while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0) 139 : { 140 137190 : RelOptInfo *rel = find_base_rel_ignore_join(root, cur_relid); 141 : 142 : /* We only need to add the clause to baserels */ 143 137190 : if (rel == NULL) 144 8154 : continue; 145 129036 : 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 9914 : remove_join_clause_from_rels(PlannerInfo *root, 162 : RestrictInfo *restrictinfo, 163 : Relids join_relids) 164 : { 165 : int cur_relid; 166 : 167 9914 : cur_relid = -1; 168 30118 : while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0) 169 : { 170 20204 : RelOptInfo *rel = find_base_rel_ignore_join(root, cur_relid); 171 : 172 : /* We would only have added the clause to baserels */ 173 20204 : if (rel == NULL) 174 256 : 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 19948 : rel->joininfo = list_delete_ptr(rel->joininfo, restrictinfo); 182 : } 183 9914 : }