MySQL 8.0.39
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) {
85 case AccessPath::REF:
91 case AccessPath::MRR:
103 // No children.
104 break;
106 WalkAccessPaths(path->nested_loop_join().outer, join, cross_query_blocks,
107 std::forward<Func &&>(func), post_order_traversal);
108 WalkAccessPaths(path->nested_loop_join().inner, join, cross_query_blocks,
109 std::forward<Func &&>(func), post_order_traversal);
110 break;
112 WalkAccessPaths(path->nested_loop_semijoin_with_duplicate_removal().outer,
113 join, cross_query_blocks, std::forward<Func &&>(func),
114 post_order_traversal);
115 WalkAccessPaths(path->nested_loop_semijoin_with_duplicate_removal().inner,
116 join, cross_query_blocks, std::forward<Func &&>(func),
117 post_order_traversal);
118 break;
120 WalkAccessPaths(path->bka_join().outer, join, cross_query_blocks,
121 std::forward<Func &&>(func), post_order_traversal);
122 WalkAccessPaths(path->bka_join().inner, join, cross_query_blocks,
123 std::forward<Func &&>(func), post_order_traversal);
124 break;
126 WalkAccessPaths(path->hash_join().outer, join, cross_query_blocks,
127 std::forward<Func &&>(func), post_order_traversal);
128 WalkAccessPaths(path->hash_join().inner, join, cross_query_blocks,
129 std::forward<Func &&>(func), post_order_traversal);
130 break;
132 WalkAccessPaths(path->filter().child, join, cross_query_blocks,
133 std::forward<Func &&>(func), post_order_traversal);
134 break;
135 case AccessPath::SORT:
136 WalkAccessPaths(path->sort().child, join, cross_query_blocks,
137 std::forward<Func &&>(func), post_order_traversal);
138 break;
140 WalkAccessPaths(path->aggregate().child, join, cross_query_blocks,
141 std::forward<Func &&>(func), post_order_traversal);
142 break;
144 WalkAccessPaths(path->temptable_aggregate().subquery_path, join,
145 cross_query_blocks, std::forward<Func &&>(func),
146 post_order_traversal);
147 WalkAccessPaths(path->temptable_aggregate().table_path, join,
148 cross_query_blocks, std::forward<Func &&>(func),
149 post_order_traversal);
150 break;
152 WalkAccessPaths(path->limit_offset().child, join, cross_query_blocks,
153 std::forward<Func &&>(func), post_order_traversal);
154 break;
156 if (cross_query_blocks == WalkAccessPathPolicy::ENTIRE_TREE ||
157 (cross_query_blocks == WalkAccessPathPolicy::ENTIRE_QUERY_BLOCK &&
158 path->stream().join == join)) {
159 WalkAccessPaths(path->stream().child, path->stream().join,
160 cross_query_blocks, std::forward<Func &&>(func),
161 post_order_traversal);
162 }
163 break;
165 WalkAccessPaths(path->materialize().table_path, join, cross_query_blocks,
166 std::forward<Func &&>(func), post_order_traversal);
167 for (const MaterializePathParameters::QueryBlock &query_block :
168 path->materialize().param->query_blocks) {
169 if (cross_query_blocks == WalkAccessPathPolicy::ENTIRE_TREE ||
170 (cross_query_blocks == WalkAccessPathPolicy::ENTIRE_QUERY_BLOCK &&
171 query_block.join == join)) {
172 WalkAccessPaths(query_block.subquery_path, query_block.join,
173 cross_query_blocks, std::forward<Func &&>(func),
174 post_order_traversal);
175 }
176 }
177 break;
179 WalkAccessPaths(path->materialize_information_schema_table().table_path,
180 join, cross_query_blocks, std::forward<Func &&>(func),
181 post_order_traversal);
182 break;
184 if (cross_query_blocks == WalkAccessPathPolicy::ENTIRE_TREE) {
185 for (const AppendPathParameters &child : *path->append().children) {
186 WalkAccessPaths(child.path, child.join, cross_query_blocks,
187 std::forward<Func &&>(func), post_order_traversal);
188 }
189 }
190 break;
192 WalkAccessPaths(path->window().child, join, cross_query_blocks,
193 std::forward<Func &&>(func), post_order_traversal);
194 break;
196 WalkAccessPaths(path->weedout().child, join, cross_query_blocks,
197 std::forward<Func &&>(func), post_order_traversal);
198 break;
200 WalkAccessPaths(path->remove_duplicates().child, join, cross_query_blocks,
201 std::forward<Func &&>(func), post_order_traversal);
202 break;
204 WalkAccessPaths(path->remove_duplicates_on_index().child, join,
205 cross_query_blocks, std::forward<Func &&>(func),
206 post_order_traversal);
207 break;
209 WalkAccessPaths(path->alternative().child, join, cross_query_blocks,
210 std::forward<Func &&>(func), post_order_traversal);
211 break;
213 WalkAccessPaths(path->cache_invalidator().child, join, cross_query_blocks,
214 std::forward<Func &&>(func), post_order_traversal);
215 break;
217 for (AccessPath *child : *path->index_merge().children) {
218 WalkAccessPaths(child, join, cross_query_blocks,
219 std::forward<Func &&>(func), post_order_traversal);
220 }
221 break;
223 for (AccessPath *child : *path->rowid_intersection().children) {
224 WalkAccessPaths(child, join, cross_query_blocks,
225 std::forward<Func &&>(func), post_order_traversal);
226 }
227 break;
229 for (AccessPath *child : *path->rowid_union().children) {
230 WalkAccessPaths(child, join, cross_query_blocks,
231 std::forward<Func &&>(func), post_order_traversal);
232 }
233 break;
235 WalkAccessPaths(path->delete_rows().child, join, cross_query_blocks,
236 std::forward<Func &&>(func), post_order_traversal);
237 break;
239 WalkAccessPaths(path->update_rows().child, join, cross_query_blocks,
240 std::forward<Func &&>(func), post_order_traversal);
241 break;
242 }
243 if (post_order_traversal) {
244 if (func(path, join)) {
245 // Stop recursing in this branch. In practice a no-op, since we are
246 // already done with this branch.
247 return;
248 }
249 }
250}
251
252/**
253 A wrapper around WalkAccessPaths() that collects all tables under
254 “root_path” and calls the given functor, stopping at materializations.
255 This is typically used to know which tables to sort or the like.
256
257 func() must have signature func(TABLE *), and return true upon error.
258 */
259template <class Func>
260void WalkTablesUnderAccessPath(AccessPath *root_path, Func &&func,
261 bool include_pruned_tables) {
263 root_path, /*join=*/nullptr,
265 [&](AccessPath *path, const JOIN *) {
266 switch (path->type) {
267 case AccessPath::TABLE_SCAN:
268 return func(path->table_scan().table);
269 case AccessPath::INDEX_SCAN:
270 return func(path->index_scan().table);
271 case AccessPath::REF:
272 return func(path->ref().table);
273 case AccessPath::REF_OR_NULL:
274 return func(path->ref_or_null().table);
275 case AccessPath::EQ_REF:
276 return func(path->eq_ref().table);
277 case AccessPath::PUSHED_JOIN_REF:
278 return func(path->pushed_join_ref().table);
279 case AccessPath::FULL_TEXT_SEARCH:
280 return func(path->full_text_search().table);
281 case AccessPath::CONST_TABLE:
282 return func(path->const_table().table);
283 case AccessPath::MRR:
284 return func(path->mrr().table);
285 case AccessPath::FOLLOW_TAIL:
286 return func(path->follow_tail().table);
287 case AccessPath::INDEX_RANGE_SCAN:
288 return func(path->index_range_scan().used_key_part[0].field->table);
289 case AccessPath::INDEX_SKIP_SCAN:
290 return func(path->index_skip_scan().table);
291 case AccessPath::GROUP_INDEX_SKIP_SCAN:
292 return func(path->group_index_skip_scan().table);
293 case AccessPath::DYNAMIC_INDEX_RANGE_SCAN:
294 return func(path->dynamic_index_range_scan().table);
295 case AccessPath::STREAM:
296 return func(path->stream().table);
297 case AccessPath::MATERIALIZE:
298 return func(path->materialize().param->table);
299 case AccessPath::MATERIALIZED_TABLE_FUNCTION:
300 return func(path->materialized_table_function().table);
301 case AccessPath::ALTERNATIVE:
302 return func(
303 path->alternative().table_scan_path->table_scan().table);
304 case AccessPath::UNQUALIFIED_COUNT:
305 // Should never be below anything that needs
306 // WalkTablesUnderAccessPath().
307 assert(false);
308 return true;
309 case AccessPath::ZERO_ROWS:
310 if (include_pruned_tables && path->zero_rows().child != nullptr) {
311 WalkTablesUnderAccessPath(path->zero_rows().child, func,
312 include_pruned_tables);
313 }
314 return false;
316 return func(path->window().temp_table);
330 case AccessPath::SORT:
340 return false;
341 }
342 assert(false);
343 return true;
344 });
345}
346
347#endif // SQL_JOIN_OPTIMIZER_WALK_ACCESS_PATHS_H
Definition: sql_optimizer.h:133
static char * path
Definition: mysqldump.cc:137
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:193
@ FOLLOW_TAIL
Definition: access_path.h:221
@ FILTER
Definition: access_path.h:245
@ PUSHED_JOIN_REF
Definition: access_path.h:217
@ ZERO_ROWS_AGGREGATED
Definition: access_path.h:234
@ UPDATE_ROWS
Definition: access_path.h:263
@ AGGREGATE
Definition: access_path.h:247
@ BKA_JOIN
Definition: access_path.h:241
@ ZERO_ROWS
Definition: access_path.h:233
@ CONST_TABLE
Definition: access_path.h:219
@ GROUP_INDEX_SKIP_SCAN
Definition: access_path.h:227
@ INDEX_RANGE_SCAN
Definition: access_path.h:222
@ UNQUALIFIED_COUNT
Definition: access_path.h:236
@ EQ_REF
Definition: access_path.h:216
@ FAKE_SINGLE_ROW
Definition: access_path.h:232
@ MATERIALIZE_INFORMATION_SCHEMA_TABLE
Definition: access_path.h:252
@ WINDOW
Definition: access_path.h:254
@ REF_OR_NULL
Definition: access_path.h:215
@ MATERIALIZE
Definition: access_path.h:251
@ NESTED_LOOP_SEMIJOIN_WITH_DUPLICATE_REMOVAL
Definition: access_path.h:240
@ ROWID_UNION
Definition: access_path.h:225
@ INDEX_SKIP_SCAN
Definition: access_path.h:226
@ MRR
Definition: access_path.h:220
@ CACHE_INVALIDATOR
Definition: access_path.h:259
@ INDEX_SCAN
Definition: access_path.h:213
@ TABLE_VALUE_CONSTRUCTOR
Definition: access_path.h:231
@ WEEDOUT
Definition: access_path.h:255
@ MATERIALIZED_TABLE_FUNCTION
Definition: access_path.h:235
@ REMOVE_DUPLICATES_ON_INDEX
Definition: access_path.h:257
@ TABLE_SCAN
Definition: access_path.h:212
@ REF
Definition: access_path.h:214
@ TEMPTABLE_AGGREGATE
Definition: access_path.h:248
@ LIMIT_OFFSET
Definition: access_path.h:249
@ APPEND
Definition: access_path.h:253
@ NESTED_LOOP_JOIN
Definition: access_path.h:239
@ INDEX_MERGE
Definition: access_path.h:223
@ FULL_TEXT_SEARCH
Definition: access_path.h:218
@ ALTERNATIVE
Definition: access_path.h:258
@ STREAM
Definition: access_path.h:250
@ REMOVE_DUPLICATES
Definition: access_path.h:256
@ ROWID_INTERSECTION
Definition: access_path.h:224
@ DYNAMIC_INDEX_RANGE_SCAN
Definition: access_path.h:228
@ DELETE_ROWS
Definition: access_path.h:262
@ SORT
Definition: access_path.h:246
@ HASH_JOIN
Definition: access_path.h:242
Definition: access_path.h:163
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:260