MySQL 8.4.0
Source Code Documentation
walk_access_paths.h
Go to the documentation of this file.
1/* Copyright (c) 2020, 2024, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is designed to work with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have either included with
13 the program or referenced in the documentation.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
23
24#ifndef SQL_JOIN_OPTIMIZER_WALK_ACCESS_PATHS_H
25#define SQL_JOIN_OPTIMIZER_WALK_ACCESS_PATHS_H
26
27#include <type_traits>
28
31
33 // Stop on _any_ MATERIALIZE or STREAM path, even if they do not cross query
34 // blocks.
35 // Also stops on APPEND paths, which always cross query blocks.
37
38 // Stop on MATERIALIZE, STREAM or APPEND paths that cross query blocks.
40
41 // Do not stop at any kind of access path, unless func() returns true.
43};
44
45/**
46 Traverse every access path below `path` (possibly limited to the current query
47 block with the `cross_query_blocks` parameter), calling func() for each one
48 with pre- or post-order traversal. If func() returns true, the traversal does
49 not descend into the children of the current path. For post-order traversal,
50 the children have already been traversed when func() is called, so it is too
51 late to skip them, and the return value of func() is effectively ignored.
52
53 The `join` parameter signifies what query block `path` is part of, since that
54 is not implicit from the path itself. The function will track this as it
55 changes throughout the tree (in MATERIALIZE or STREAM access paths), and
56 will give the correct value to the func() callback. It is only used by
57 WalkAccessPaths() itself if the policy is ENTIRE_QUERY_BLOCK; if not, it is
58 only used for the func() callback, and you can set it to nullptr if you wish.
59 func() must have signature func(AccessPath *, const JOIN *), or it could be
60 JOIN * if a non-const JOIN is given in.
61 */
62template <class AccessPathPtr, class Func, class JoinPtr>
63void WalkAccessPaths(AccessPathPtr path, JoinPtr join,
64 WalkAccessPathPolicy cross_query_blocks, Func &&func,
65 bool post_order_traversal = false) {
66 static_assert(
67 std::is_convertible<AccessPathPtr, const AccessPath *>::value,
68 "The “path” argument must be AccessPath * or const AccessPath *.");
69 static_assert(
70 std::is_convertible<JoinPtr, const JOIN *>::value,
71 "The “join” argument must be JOIN * or const JOIN * (or nullptr).");
72
73 if (cross_query_blocks == WalkAccessPathPolicy::ENTIRE_QUERY_BLOCK) {
74 assert(join != nullptr);
75 }
76 if (!post_order_traversal) {
77 if (func(path, join)) {
78 // Stop recursing in this branch.
79 return;
80 }
81 }
82 switch (path->type) {
87 case AccessPath::REF:
93 case AccessPath::MRR:
105 // No children.
106 break;
108 WalkAccessPaths(path->nested_loop_join().outer, join, cross_query_blocks,
109 std::forward<Func &&>(func), post_order_traversal);
110 WalkAccessPaths(path->nested_loop_join().inner, join, cross_query_blocks,
111 std::forward<Func &&>(func), post_order_traversal);
112 break;
114 WalkAccessPaths(path->nested_loop_semijoin_with_duplicate_removal().outer,
115 join, cross_query_blocks, std::forward<Func &&>(func),
116 post_order_traversal);
117 WalkAccessPaths(path->nested_loop_semijoin_with_duplicate_removal().inner,
118 join, cross_query_blocks, std::forward<Func &&>(func),
119 post_order_traversal);
120 break;
122 WalkAccessPaths(path->bka_join().outer, join, cross_query_blocks,
123 std::forward<Func &&>(func), post_order_traversal);
124 WalkAccessPaths(path->bka_join().inner, join, cross_query_blocks,
125 std::forward<Func &&>(func), post_order_traversal);
126 break;
128 WalkAccessPaths(path->hash_join().outer, join, cross_query_blocks,
129 std::forward<Func &&>(func), post_order_traversal);
130 WalkAccessPaths(path->hash_join().inner, join, cross_query_blocks,
131 std::forward<Func &&>(func), post_order_traversal);
132 break;
134 WalkAccessPaths(path->filter().child, join, cross_query_blocks,
135 std::forward<Func &&>(func), post_order_traversal);
136 break;
137 case AccessPath::SORT:
138 WalkAccessPaths(path->sort().child, join, cross_query_blocks,
139 std::forward<Func &&>(func), post_order_traversal);
140 break;
142 WalkAccessPaths(path->aggregate().child, join, cross_query_blocks,
143 std::forward<Func &&>(func), post_order_traversal);
144 break;
146 WalkAccessPaths(path->temptable_aggregate().subquery_path, join,
147 cross_query_blocks, std::forward<Func &&>(func),
148 post_order_traversal);
149 WalkAccessPaths(path->temptable_aggregate().table_path, join,
150 cross_query_blocks, std::forward<Func &&>(func),
151 post_order_traversal);
152 break;
154 WalkAccessPaths(path->limit_offset().child, join, cross_query_blocks,
155 std::forward<Func &&>(func), post_order_traversal);
156 break;
158 if (cross_query_blocks == WalkAccessPathPolicy::ENTIRE_TREE ||
159 (cross_query_blocks == WalkAccessPathPolicy::ENTIRE_QUERY_BLOCK &&
160 path->stream().join == join)) {
161 WalkAccessPaths(path->stream().child, path->stream().join,
162 cross_query_blocks, std::forward<Func &&>(func),
163 post_order_traversal);
164 }
165 break;
167 WalkAccessPaths(path->materialize().table_path, join, cross_query_blocks,
168 std::forward<Func &&>(func), post_order_traversal);
169 for (const MaterializePathParameters::Operand &operand :
170 path->materialize().param->m_operands) {
171 if (cross_query_blocks == WalkAccessPathPolicy::ENTIRE_TREE ||
172 (cross_query_blocks == WalkAccessPathPolicy::ENTIRE_QUERY_BLOCK &&
173 operand.join == join)) {
174 WalkAccessPaths(operand.subquery_path, operand.join,
175 cross_query_blocks, std::forward<Func &&>(func),
176 post_order_traversal);
177 }
178 }
179 break;
181 WalkAccessPaths(path->materialize_information_schema_table().table_path,
182 join, cross_query_blocks, std::forward<Func &&>(func),
183 post_order_traversal);
184 break;
186 if (cross_query_blocks == WalkAccessPathPolicy::ENTIRE_TREE) {
187 for (const AppendPathParameters &child : *path->append().children) {
188 WalkAccessPaths(child.path, child.join, cross_query_blocks,
189 std::forward<Func &&>(func), post_order_traversal);
190 }
191 }
192 break;
194 WalkAccessPaths(path->window().child, join, cross_query_blocks,
195 std::forward<Func &&>(func), post_order_traversal);
196 break;
198 WalkAccessPaths(path->weedout().child, join, cross_query_blocks,
199 std::forward<Func &&>(func), post_order_traversal);
200 break;
202 WalkAccessPaths(path->remove_duplicates().child, join, cross_query_blocks,
203 std::forward<Func &&>(func), post_order_traversal);
204 break;
206 WalkAccessPaths(path->remove_duplicates_on_index().child, join,
207 cross_query_blocks, std::forward<Func &&>(func),
208 post_order_traversal);
209 break;
211 WalkAccessPaths(path->alternative().child, join, cross_query_blocks,
212 std::forward<Func &&>(func), post_order_traversal);
213 break;
215 WalkAccessPaths(path->cache_invalidator().child, join, cross_query_blocks,
216 std::forward<Func &&>(func), post_order_traversal);
217 break;
219 for (AccessPath *child : *path->index_merge().children) {
220 WalkAccessPaths(child, join, cross_query_blocks,
221 std::forward<Func &&>(func), post_order_traversal);
222 }
223 break;
225 for (AccessPath *child : *path->rowid_intersection().children) {
226 WalkAccessPaths(child, join, cross_query_blocks,
227 std::forward<Func &&>(func), post_order_traversal);
228 }
229 break;
231 for (AccessPath *child : *path->rowid_union().children) {
232 WalkAccessPaths(child, join, cross_query_blocks,
233 std::forward<Func &&>(func), post_order_traversal);
234 }
235 break;
237 WalkAccessPaths(path->delete_rows().child, join, cross_query_blocks,
238 std::forward<Func &&>(func), post_order_traversal);
239 break;
241 WalkAccessPaths(path->update_rows().child, join, cross_query_blocks,
242 std::forward<Func &&>(func), post_order_traversal);
243 break;
244 }
245 if (post_order_traversal) {
246 if (func(path, join)) {
247 // Stop recursing in this branch. In practice a no-op, since we are
248 // already done with this branch.
249 return;
250 }
251 }
252}
253
254/**
255 A wrapper around WalkAccessPaths() that collects all tables under
256 “root_path” and calls the given functor, stopping at materializations.
257 This is typically used to know which tables to sort or the like.
258
259 func() must have signature func(TABLE *), and return true upon error.
260 */
261template <class Func>
262void WalkTablesUnderAccessPath(AccessPath *root_path, Func &&func,
263 bool include_pruned_tables) {
265 root_path, /*join=*/nullptr,
267 [&](AccessPath *path, const JOIN *) {
268 switch (path->type) {
269 case AccessPath::TABLE_SCAN:
270 return func(path->table_scan().table);
271 case AccessPath::SAMPLE_SCAN:
272 // SampleScan can be executed only in the secondary engine.
273 return false; /* LCOV_EXCL_LINE */
274 case AccessPath::INDEX_SCAN:
275 return func(path->index_scan().table);
276 case AccessPath::INDEX_DISTANCE_SCAN:
277 return func(path->index_distance_scan().table);
278 case AccessPath::REF:
279 return func(path->ref().table);
280 case AccessPath::REF_OR_NULL:
281 return func(path->ref_or_null().table);
282 case AccessPath::EQ_REF:
283 return func(path->eq_ref().table);
284 case AccessPath::PUSHED_JOIN_REF:
285 return func(path->pushed_join_ref().table);
286 case AccessPath::FULL_TEXT_SEARCH:
287 return func(path->full_text_search().table);
288 case AccessPath::CONST_TABLE:
289 return func(path->const_table().table);
290 case AccessPath::MRR:
291 return func(path->mrr().table);
292 case AccessPath::FOLLOW_TAIL:
293 return func(path->follow_tail().table);
294 case AccessPath::INDEX_RANGE_SCAN:
295 return func(path->index_range_scan().used_key_part[0].field->table);
296 case AccessPath::INDEX_SKIP_SCAN:
297 return func(path->index_skip_scan().table);
298 case AccessPath::GROUP_INDEX_SKIP_SCAN:
299 return func(path->group_index_skip_scan().table);
300 case AccessPath::DYNAMIC_INDEX_RANGE_SCAN:
301 return func(path->dynamic_index_range_scan().table);
302 case AccessPath::STREAM:
303 return func(path->stream().table);
304 case AccessPath::MATERIALIZED_TABLE_FUNCTION:
305 return func(path->materialized_table_function().table);
306 case AccessPath::ALTERNATIVE:
307 return func(
308 path->alternative().table_scan_path->table_scan().table);
309 case AccessPath::UNQUALIFIED_COUNT:
310 // Should never be below anything that needs
311 // WalkTablesUnderAccessPath().
312 assert(false);
313 return true;
314 case AccessPath::ZERO_ROWS:
315 if (include_pruned_tables && path->zero_rows().child != nullptr) {
316 WalkTablesUnderAccessPath(path->zero_rows().child, func,
317 include_pruned_tables);
318 }
319 return false;
321 return func(path->window().temp_table);
336 case AccessPath::SORT:
346 return false;
347 }
348 assert(false);
349 return true;
350 });
351}
352
353#endif // SQL_JOIN_OPTIMIZER_WALK_ACCESS_PATHS_H
Definition: sql_optimizer.h:133
static char * path
Definition: mysqldump.cc:149
std::string join(Container cont, const std::string &delim)
join elements of an container into a string separated by a delimiter.
Definition: string.h:151
Access paths are a query planning structure that correspond 1:1 to iterators, in that an access path ...
Definition: access_path.h:213
@ FOLLOW_TAIL
Definition: access_path.h:244
@ FILTER
Definition: access_path.h:268
@ PUSHED_JOIN_REF
Definition: access_path.h:240
@ ZERO_ROWS_AGGREGATED
Definition: access_path.h:257
@ UPDATE_ROWS
Definition: access_path.h:286
@ AGGREGATE
Definition: access_path.h:270
@ BKA_JOIN
Definition: access_path.h:264
@ ZERO_ROWS
Definition: access_path.h:256
@ CONST_TABLE
Definition: access_path.h:242
@ GROUP_INDEX_SKIP_SCAN
Definition: access_path.h:250
@ SAMPLE_SCAN
Definition: access_path.h:234
@ INDEX_RANGE_SCAN
Definition: access_path.h:245
@ UNQUALIFIED_COUNT
Definition: access_path.h:259
@ EQ_REF
Definition: access_path.h:239
@ FAKE_SINGLE_ROW
Definition: access_path.h:255
@ MATERIALIZE_INFORMATION_SCHEMA_TABLE
Definition: access_path.h:275
@ WINDOW
Definition: access_path.h:277
@ REF_OR_NULL
Definition: access_path.h:238
@ MATERIALIZE
Definition: access_path.h:274
@ NESTED_LOOP_SEMIJOIN_WITH_DUPLICATE_REMOVAL
Definition: access_path.h:263
@ ROWID_UNION
Definition: access_path.h:248
@ INDEX_SKIP_SCAN
Definition: access_path.h:249
@ MRR
Definition: access_path.h:243
@ CACHE_INVALIDATOR
Definition: access_path.h:282
@ INDEX_SCAN
Definition: access_path.h:235
@ TABLE_VALUE_CONSTRUCTOR
Definition: access_path.h:254
@ WEEDOUT
Definition: access_path.h:278
@ MATERIALIZED_TABLE_FUNCTION
Definition: access_path.h:258
@ REMOVE_DUPLICATES_ON_INDEX
Definition: access_path.h:280
@ TABLE_SCAN
Definition: access_path.h:233
@ REF
Definition: access_path.h:237
@ TEMPTABLE_AGGREGATE
Definition: access_path.h:271
@ LIMIT_OFFSET
Definition: access_path.h:272
@ APPEND
Definition: access_path.h:276
@ NESTED_LOOP_JOIN
Definition: access_path.h:262
@ INDEX_MERGE
Definition: access_path.h:246
@ FULL_TEXT_SEARCH
Definition: access_path.h:241
@ ALTERNATIVE
Definition: access_path.h:281
@ STREAM
Definition: access_path.h:273
@ REMOVE_DUPLICATES
Definition: access_path.h:279
@ ROWID_INTERSECTION
Definition: access_path.h:247
@ DYNAMIC_INDEX_RANGE_SCAN
Definition: access_path.h:251
@ DELETE_ROWS
Definition: access_path.h:285
@ SORT
Definition: access_path.h:269
@ INDEX_DISTANCE_SCAN
Definition: access_path.h:236
@ HASH_JOIN
Definition: access_path.h:265
Definition: access_path.h:178
Definition: materialize_path_parameters.h:42
void WalkAccessPaths(AccessPathPtr path, JoinPtr join, WalkAccessPathPolicy cross_query_blocks, Func &&func, bool post_order_traversal=false)
Traverse every access path below path (possibly limited to the current query block with the cross_que...
Definition: walk_access_paths.h:63
WalkAccessPathPolicy
Definition: walk_access_paths.h:32
void WalkTablesUnderAccessPath(AccessPath *root_path, Func &&func, bool include_pruned_tables)
A wrapper around WalkAccessPaths() that collects all tables under “root_path” and calls the given fun...
Definition: walk_access_paths.h:262