1237.13.44
by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files. |
1 |
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
|
2 |
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
|
|
3 |
*
|
|
1999.6.1
by kalebral at gmail
update Copyright strings to a more common format to help with creating the master debian copyright file |
4 |
* Copyright (C) 2008-2009 Sun Microsystems, Inc.
|
1237.13.44
by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files. |
5 |
*
|
6 |
* This program is free software; you can redistribute it and/or modify
|
|
7 |
* it under the terms of the GNU General Public License as published by
|
|
8 |
* the Free Software Foundation; version 2 of the License.
|
|
9 |
*
|
|
10 |
* This program is distributed in the hope that it will be useful,
|
|
11 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13 |
* GNU General Public License for more details.
|
|
14 |
*
|
|
15 |
* You should have received a copy of the GNU General Public License
|
|
16 |
* along with this program; if not, write to the Free Software
|
|
17 |
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
18 |
*/
|
|
19 |
||
2173.2.1
by Monty Taylor
Fixes incorrect usage of include |
20 |
#include <config.h> |
1237.13.44
by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files. |
21 |
|
2173.2.1
by Monty Taylor
Fixes incorrect usage of include |
22 |
#include <drizzled/sql_base.h> |
23 |
#include <drizzled/sql_select.h> |
|
24 |
#include <drizzled/memory/sql_alloc.h> |
|
25 |
#include <drizzled/optimizer/range.h> |
|
26 |
#include <drizzled/optimizer/range_param.h> |
|
27 |
#include <drizzled/optimizer/sel_arg.h> |
|
28 |
#include <drizzled/optimizer/sel_tree.h> |
|
29 |
#include <drizzled/optimizer/sel_imerge.h> |
|
1237.13.44
by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files. |
30 |
|
31 |
using namespace std; |
|
32 |
using namespace drizzled; |
|
33 |
||
34 |
static optimizer::SEL_ARG *key_or(optimizer::RangeParameter *param, optimizer::SEL_ARG *key1, optimizer::SEL_ARG *key2); |
|
35 |
static bool eq_tree(optimizer::SEL_ARG* a, optimizer::SEL_ARG *b); |
|
36 |
||
2318.6.47
by Olaf van der Spek
Refactor |
37 |
bool optimizer::sel_trees_can_be_ored(const SEL_TREE& tree1, const SEL_TREE& tree2, const RangeParameter& param) |
1237.13.44
by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files. |
38 |
{
|
2318.6.47
by Olaf van der Spek
Refactor |
39 |
key_map common_keys= tree1.keys_map; |
40 |
common_keys&= tree2.keys_map; |
|
1237.13.44
by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files. |
41 |
|
42 |
if (common_keys.none()) |
|
43 |
return false; |
|
44 |
||
45 |
/* trees have a common key, check if they refer to same key part */
|
|
2318.6.47
by Olaf van der Spek
Refactor |
46 |
for (uint32_t key_no= 0; key_no < param.keys; key_no++) |
1237.13.44
by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files. |
47 |
{
|
2318.6.47
by Olaf van der Spek
Refactor |
48 |
if (common_keys.test(key_no) && tree1.keys[key_no]->part == tree2.keys[key_no]->part) |
49 |
return true; |
|
1237.13.44
by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files. |
50 |
}
|
51 |
return false; |
|
52 |
}
|
|
53 |
||
54 |
||
55 |
/*
|
|
56 |
Perform OR operation on 2 index_merge lists, storing result in first list.
|
|
57 |
||
58 |
NOTES
|
|
59 |
The following conversion is implemented:
|
|
60 |
(a_1 &&...&& a_N)||(b_1 &&...&& b_K) = AND_i,j(a_i || b_j) =>
|
|
61 |
=> (a_1||b_1).
|
|
62 |
||
63 |
i.e. all conjuncts except the first one are currently dropped.
|
|
64 |
This is done to avoid producing N*K ways to do index_merge.
|
|
65 |
||
66 |
If (a_1||b_1) produce a condition that is always true, NULL is returned
|
|
67 |
and index_merge is discarded (while it is actually possible to try
|
|
68 |
harder).
|
|
69 |
||
70 |
As a consequence of this, choice of keys to do index_merge read may depend
|
|
71 |
on the order of conditions in WHERE part of the query.
|
|
72 |
||
73 |
RETURN
|
|
74 |
0 OK, result is stored in *im1
|
|
75 |
other Error, both passed lists are unusable
|
|
76 |
*/
|
|
77 |
||
2318.6.49
by Olaf van der Spek
Refactor |
78 |
static int imerge_list_or_list(optimizer::RangeParameter *param, List<optimizer::SEL_IMERGE> *im1, List<optimizer::SEL_IMERGE> *im2) |
1237.13.44
by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files. |
79 |
{
|
2183.2.21
by Olaf van der Spek
Use List::front() |
80 |
optimizer::SEL_IMERGE *imerge= &im1->front(); |
2179.2.1
by Olaf van der Spek
Rename List::empty to clear (std::list uses clear) |
81 |
im1->clear(); |
1237.13.44
by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files. |
82 |
im1->push_back(imerge); |
83 |
||
2318.6.49
by Olaf van der Spek
Refactor |
84 |
return imerge->or_sel_imerge_with_checks(*param, im2->front()); |
1237.13.44
by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files. |
85 |
}
|
86 |
||
87 |
||
88 |
/*
|
|
89 |
Perform OR operation on index_merge list and key tree.
|
|
90 |
||
91 |
RETURN
|
|
92 |
0 OK, result is stored in *im1.
|
|
93 |
other Error
|
|
94 |
*/
|
|
95 |
||
2318.6.49
by Olaf van der Spek
Refactor |
96 |
static int imerge_list_or_tree(optimizer::RangeParameter *param, List<optimizer::SEL_IMERGE> *im1, optimizer::SEL_TREE *tree) |
1237.13.44
by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files. |
97 |
{
|
2183.2.12
by Olaf van der Spek
Use List::begin() |
98 |
List_iterator<optimizer::SEL_IMERGE> it(im1->begin()); |
2318.6.48
by Olaf van der Spek
Refactor |
99 |
while (optimizer::SEL_IMERGE* imerge= it++) |
1237.13.44
by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files. |
100 |
{
|
2318.6.48
by Olaf van der Spek
Refactor |
101 |
if (imerge->or_sel_tree_with_checks(*param, *tree)) |
1237.13.44
by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files. |
102 |
it.remove(); |
103 |
}
|
|
104 |
return im1->is_empty(); |
|
105 |
}
|
|
106 |
||
107 |
||
108 |
optimizer::SEL_TREE * |
|
109 |
optimizer::tree_or(optimizer::RangeParameter *param, |
|
110 |
optimizer::SEL_TREE *tree1, |
|
111 |
optimizer::SEL_TREE *tree2) |
|
112 |
{
|
|
113 |
if (! tree1 || ! tree2) |
|
114 |
{
|
|
115 |
return 0; |
|
116 |
}
|
|
117 |
||
118 |
if (tree1->type == optimizer::SEL_TREE::IMPOSSIBLE || tree2->type == optimizer::SEL_TREE::ALWAYS) |
|
119 |
{
|
|
120 |
return tree2; |
|
121 |
}
|
|
122 |
||
123 |
if (tree2->type == optimizer::SEL_TREE::IMPOSSIBLE || tree1->type == optimizer::SEL_TREE::ALWAYS) |
|
124 |
{
|
|
125 |
return tree1; |
|
126 |
}
|
|
127 |
||
128 |
if (tree1->type == optimizer::SEL_TREE::MAYBE) |
|
129 |
{
|
|
130 |
return tree1; // Can't use this |
|
131 |
}
|
|
132 |
||
133 |
if (tree2->type == optimizer::SEL_TREE::MAYBE) |
|
134 |
{
|
|
135 |
return tree2; |
|
136 |
}
|
|
137 |
||
138 |
optimizer::SEL_TREE *result= NULL; |
|
139 |
key_map result_keys; |
|
140 |
result_keys.reset(); |
|
2318.6.47
by Olaf van der Spek
Refactor |
141 |
if (sel_trees_can_be_ored(*tree1, *tree2, *param)) |
1237.13.44
by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files. |
142 |
{
|
143 |
/* Join the trees key per key */
|
|
144 |
optimizer::SEL_ARG **key1= NULL; |
|
145 |
optimizer::SEL_ARG **key2= NULL; |
|
146 |
optimizer::SEL_ARG **end= NULL; |
|
147 |
for (key1= tree1->keys,key2= tree2->keys,end= key1+param->keys; |
|
148 |
key1 != end; |
|
149 |
key1++, key2++) |
|
150 |
{
|
|
151 |
*key1= key_or(param, *key1, *key2); |
|
152 |
if (*key1) |
|
153 |
{
|
|
154 |
result= tree1; // Added to tree1 |
|
155 |
result_keys.set(key1 - tree1->keys); |
|
156 |
}
|
|
157 |
}
|
|
158 |
if (result) |
|
159 |
result->keys_map= result_keys; |
|
160 |
}
|
|
161 |
else
|
|
162 |
{
|
|
163 |
/* ok, two trees have KEY type but cannot be used without index merge */
|
|
164 |
if (tree1->merges.is_empty() && tree2->merges.is_empty()) |
|
165 |
{
|
|
166 |
if (param->remove_jump_scans) |
|
167 |
{
|
|
168 |
bool no_trees= optimizer::remove_nonrange_trees(param, tree1); |
|
169 |
no_trees= no_trees || optimizer::remove_nonrange_trees(param, tree2); |
|
170 |
if (no_trees) |
|
171 |
{
|
|
172 |
return (new optimizer::SEL_TREE(optimizer::SEL_TREE::ALWAYS)); |
|
173 |
}
|
|
174 |
}
|
|
175 |
optimizer::SEL_IMERGE *merge= NULL; |
|
176 |
/* both trees are "range" trees, produce new index merge structure */
|
|
2241.2.11
by Olaf van der Spek
Refactor |
177 |
result= new optimizer::SEL_TREE(); |
178 |
merge= new optimizer::SEL_IMERGE(); |
|
179 |
result->merges.push_back(merge); |
|
2318.6.46
by Olaf van der Spek
Refactor |
180 |
merge->or_sel_tree(param, tree1); |
181 |
merge->or_sel_tree(param, tree2); |
|
182 |
result->type= tree1->type; |
|
1237.13.44
by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files. |
183 |
}
|
184 |
else if (!tree1->merges.is_empty() && !tree2->merges.is_empty()) |
|
185 |
{
|
|
186 |
if (imerge_list_or_list(param, &tree1->merges, &tree2->merges)) |
|
187 |
result= new optimizer::SEL_TREE(optimizer::SEL_TREE::ALWAYS); |
|
188 |
else
|
|
189 |
result= tree1; |
|
190 |
}
|
|
191 |
else
|
|
192 |
{
|
|
193 |
/* one tree is index merge tree and another is range tree */
|
|
194 |
if (tree1->merges.is_empty()) |
|
195 |
std::swap(tree1, tree2); |
|
196 |
||
197 |
if (param->remove_jump_scans && optimizer::remove_nonrange_trees(param, tree2)) |
|
198 |
return(new optimizer::SEL_TREE(optimizer::SEL_TREE::ALWAYS)); |
|
199 |
/* add tree2 to tree1->merges, checking if it collapses to ALWAYS */
|
|
200 |
if (imerge_list_or_tree(param, &tree1->merges, tree2)) |
|
201 |
result= new optimizer::SEL_TREE(optimizer::SEL_TREE::ALWAYS); |
|
202 |
else
|
|
203 |
result= tree1; |
|
204 |
}
|
|
205 |
}
|
|
206 |
return result; |
|
207 |
}
|
|
208 |
||
209 |
||
210 |
static optimizer::SEL_ARG * |
|
211 |
key_or(optimizer::RangeParameter *param, optimizer::SEL_ARG *key1, optimizer::SEL_ARG *key2) |
|
212 |
{
|
|
213 |
if (! key1) |
|
214 |
{
|
|
215 |
if (key2) |
|
216 |
{
|
|
217 |
key2->use_count--; |
|
218 |
key2->free_tree(); |
|
219 |
}
|
|
220 |
return 0; |
|
221 |
}
|
|
222 |
if (! key2) |
|
223 |
{
|
|
224 |
key1->use_count--; |
|
225 |
key1->free_tree(); |
|
226 |
return 0; |
|
227 |
}
|
|
228 |
key1->use_count--; |
|
229 |
key2->use_count--; |
|
230 |
||
231 |
if (key1->part != key2->part) |
|
232 |
{
|
|
233 |
key1->free_tree(); |
|
234 |
key2->free_tree(); |
|
235 |
return 0; // Can't optimize this |
|
236 |
}
|
|
237 |
||
238 |
// If one of the key is MAYBE_KEY then the found region may be bigger
|
|
239 |
if (key1->type == optimizer::SEL_ARG::MAYBE_KEY) |
|
240 |
{
|
|
241 |
key2->free_tree(); |
|
242 |
key1->use_count++; |
|
243 |
return key1; |
|
244 |
}
|
|
245 |
if (key2->type == optimizer::SEL_ARG::MAYBE_KEY) |
|
246 |
{
|
|
247 |
key1->free_tree(); |
|
248 |
key2->use_count++; |
|
249 |
return key2; |
|
250 |
}
|
|
251 |
||
252 |
if (key1->use_count > 0) |
|
253 |
{
|
|
254 |
if (key2->use_count == 0 || key1->elements > key2->elements) |
|
255 |
{
|
|
256 |
std::swap(key1,key2); |
|
257 |
}
|
|
258 |
if (key1->use_count > 0 || !(key1=key1->clone_tree(param))) |
|
259 |
return 0; // OOM |
|
260 |
}
|
|
261 |
||
262 |
// Add tree at key2 to tree at key1
|
|
263 |
bool key2_shared= key2->use_count != 0; |
|
264 |
key1->maybe_flag|= key2->maybe_flag; |
|
265 |
||
266 |
for (key2=key2->first(); key2; ) |
|
267 |
{
|
|
268 |
optimizer::SEL_ARG *tmp= key1->find_range(key2); // Find key1.min <= key2.min |
|
269 |
int cmp; |
|
270 |
||
271 |
if (! tmp) |
|
272 |
{
|
|
273 |
tmp=key1->first(); // tmp.min > key2.min |
|
274 |
cmp= -1; |
|
275 |
}
|
|
276 |
else if ((cmp=tmp->cmp_max_to_min(key2)) < 0) |
|
277 |
{ // Found tmp.max < key2.min |
|
278 |
optimizer::SEL_ARG *next= tmp->next; |
|
279 |
if (cmp == -2 && eq_tree(tmp->next_key_part,key2->next_key_part)) |
|
280 |
{
|
|
281 |
// Join near ranges like tmp.max < 0 and key2.min >= 0
|
|
282 |
optimizer::SEL_ARG *key2_next=key2->next; |
|
283 |
if (key2_shared) |
|
284 |
{
|
|
285 |
if (! (key2=new optimizer::SEL_ARG(*key2))) |
|
286 |
return 0; // out of memory |
|
287 |
key2->increment_use_count(key1->use_count+1); |
|
288 |
key2->next= key2_next; // New copy of key2 |
|
289 |
}
|
|
290 |
key2->copy_min(tmp); |
|
291 |
if (! (key1=key1->tree_delete(tmp))) |
|
292 |
{ // Only one key in tree |
|
293 |
key1= key2; |
|
294 |
key1->make_root(); |
|
295 |
key2= key2_next; |
|
296 |
break; |
|
297 |
}
|
|
298 |
}
|
|
299 |
if (! (tmp= next)) // tmp.min > key2.min |
|
300 |
break; // Copy rest of key2 |
|
301 |
}
|
|
302 |
if (cmp < 0) |
|
303 |
{ // tmp.min > key2.min |
|
304 |
int tmp_cmp; |
|
305 |
if ((tmp_cmp= tmp->cmp_min_to_max(key2)) > 0) // if tmp.min > key2.max |
|
306 |
{
|
|
307 |
if (tmp_cmp == 2 && eq_tree(tmp->next_key_part,key2->next_key_part)) |
|
308 |
{ // ranges are connected |
|
309 |
tmp->copy_min_to_min(key2); |
|
310 |
key1->merge_flags(key2); |
|
311 |
if (tmp->min_flag & NO_MIN_RANGE && |
|
312 |
tmp->max_flag & NO_MAX_RANGE) |
|
313 |
{
|
|
314 |
if (key1->maybe_flag) |
|
315 |
return new optimizer::SEL_ARG(optimizer::SEL_ARG::MAYBE_KEY); |
|
316 |
return 0; |
|
317 |
}
|
|
318 |
key2->increment_use_count(-1); // Free not used tree |
|
319 |
key2= key2->next; |
|
320 |
continue; |
|
321 |
}
|
|
322 |
else
|
|
323 |
{
|
|
324 |
optimizer::SEL_ARG *next= key2->next; // Keys are not overlapping |
|
325 |
if (key2_shared) |
|
326 |
{
|
|
327 |
optimizer::SEL_ARG *cpy= new optimizer::SEL_ARG(*key2); // Must make copy |
|
328 |
if (! cpy) |
|
329 |
return 0; // OOM |
|
330 |
key1= key1->insert(cpy); |
|
331 |
key2->increment_use_count(key1->use_count+1); |
|
332 |
}
|
|
333 |
else
|
|
334 |
key1= key1->insert(key2); // Will destroy key2_root |
|
335 |
key2= next; |
|
336 |
continue; |
|
337 |
}
|
|
338 |
}
|
|
339 |
}
|
|
340 |
||
341 |
// tmp.max >= key2.min && tmp.min <= key.cmax(overlapping ranges)
|
|
342 |
if (eq_tree(tmp->next_key_part,key2->next_key_part)) |
|
343 |
{
|
|
344 |
if (tmp->is_same(key2)) |
|
345 |
{
|
|
346 |
tmp->merge_flags(key2); // Copy maybe flags |
|
347 |
key2->increment_use_count(-1); // Free not used tree |
|
348 |
}
|
|
349 |
else
|
|
350 |
{
|
|
351 |
optimizer::SEL_ARG *last= tmp; |
|
352 |
while (last->next && last->next->cmp_min_to_max(key2) <= 0 && |
|
353 |
eq_tree(last->next->next_key_part,key2->next_key_part)) |
|
354 |
{
|
|
355 |
optimizer::SEL_ARG *save= last; |
|
356 |
last= last->next; |
|
357 |
key1= key1->tree_delete(save); |
|
358 |
}
|
|
359 |
last->copy_min(tmp); |
|
360 |
if (last->copy_min(key2) || last->copy_max(key2)) |
|
361 |
{ // Full range |
|
362 |
key1->free_tree(); |
|
363 |
for (; key2; key2= key2->next) |
|
364 |
key2->increment_use_count(-1); // Free not used tree |
|
365 |
if (key1->maybe_flag) |
|
366 |
return new optimizer::SEL_ARG(optimizer::SEL_ARG::MAYBE_KEY); |
|
367 |
return 0; |
|
368 |
}
|
|
369 |
}
|
|
370 |
key2= key2->next; |
|
371 |
continue; |
|
372 |
}
|
|
373 |
||
374 |
if (cmp >= 0 && tmp->cmp_min_to_min(key2) < 0) |
|
375 |
{ // tmp.min <= x < key2.min |
|
376 |
optimizer::SEL_ARG *new_arg= tmp->clone_first(key2); |
|
377 |
if (! new_arg) |
|
378 |
return 0; // OOM |
|
379 |
if ((new_arg->next_key_part= key1->next_key_part)) |
|
380 |
new_arg->increment_use_count(key1->use_count+1); |
|
381 |
tmp->copy_min_to_min(key2); |
|
382 |
key1= key1->insert(new_arg); |
|
383 |
}
|
|
384 |
||
385 |
// tmp.min >= key2.min && tmp.min <= key2.max
|
|
386 |
optimizer::SEL_ARG key(*key2); // Get copy we can modify |
|
387 |
for (;;) |
|
388 |
{
|
|
389 |
if (tmp->cmp_min_to_min(&key) > 0) |
|
390 |
{ // key.min <= x < tmp.min |
|
391 |
optimizer::SEL_ARG *new_arg= key.clone_first(tmp); |
|
392 |
if (! new_arg) |
|
393 |
return 0; // OOM |
|
394 |
if ((new_arg->next_key_part=key.next_key_part)) |
|
395 |
new_arg->increment_use_count(key1->use_count+1); |
|
396 |
key1= key1->insert(new_arg); |
|
397 |
}
|
|
398 |
if ((cmp=tmp->cmp_max_to_max(&key)) <= 0) |
|
399 |
{ // tmp.min. <= x <= tmp.max |
|
400 |
tmp->maybe_flag|= key.maybe_flag; |
|
401 |
key.increment_use_count(key1->use_count+1); |
|
402 |
tmp->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part); |
|
403 |
if (! cmp) // Key2 is ready |
|
404 |
break; |
|
405 |
key.copy_max_to_min(tmp); |
|
406 |
if (! (tmp= tmp->next)) |
|
407 |
{
|
|
408 |
optimizer::SEL_ARG *tmp2= new optimizer::SEL_ARG(key); |
|
409 |
if (! tmp2) |
|
410 |
return 0; // OOM |
|
411 |
key1= key1->insert(tmp2); |
|
412 |
key2= key2->next; |
|
413 |
goto end; |
|
414 |
}
|
|
415 |
if (tmp->cmp_min_to_max(&key) > 0) |
|
416 |
{
|
|
417 |
optimizer::SEL_ARG *tmp2= new optimizer::SEL_ARG(key); |
|
418 |
if (! tmp2) |
|
419 |
return 0; // OOM |
|
420 |
key1= key1->insert(tmp2); |
|
421 |
break; |
|
422 |
}
|
|
423 |
}
|
|
424 |
else
|
|
425 |
{
|
|
426 |
optimizer::SEL_ARG *new_arg= tmp->clone_last(&key); // tmp.min <= x <= key.max |
|
427 |
if (! new_arg) |
|
428 |
return 0; // OOM |
|
429 |
tmp->copy_max_to_min(&key); |
|
430 |
tmp->increment_use_count(key1->use_count+1); |
|
431 |
/* Increment key count as it may be used for next loop */
|
|
432 |
key.increment_use_count(1); |
|
433 |
new_arg->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part); |
|
434 |
key1= key1->insert(new_arg); |
|
435 |
break; |
|
436 |
}
|
|
437 |
}
|
|
438 |
key2= key2->next; |
|
439 |
}
|
|
440 |
||
441 |
end: |
|
442 |
while (key2) |
|
443 |
{
|
|
444 |
optimizer::SEL_ARG *next= key2->next; |
|
445 |
if (key2_shared) |
|
446 |
{
|
|
447 |
optimizer::SEL_ARG *tmp= new optimizer::SEL_ARG(*key2); // Must make copy |
|
448 |
if (! tmp) |
|
449 |
return 0; |
|
450 |
key2->increment_use_count(key1->use_count+1); |
|
451 |
key1= key1->insert(tmp); |
|
452 |
}
|
|
453 |
else
|
|
454 |
key1= key1->insert(key2); // Will destroy key2_root |
|
455 |
key2= next; |
|
456 |
}
|
|
457 |
key1->use_count++; |
|
458 |
return key1; |
|
459 |
}
|
|
460 |
||
461 |
||
462 |
/*
|
|
463 |
Remove the trees that are not suitable for record retrieval.
|
|
464 |
SYNOPSIS
|
|
465 |
param Range analysis parameter
|
|
466 |
tree Tree to be processed, tree->type is KEY or KEY_SMALLER
|
|
467 |
||
468 |
DESCRIPTION
|
|
469 |
This function walks through tree->keys[] and removes the SEL_ARG* trees
|
|
470 |
that are not "maybe" trees (*) and cannot be used to construct quick range
|
|
471 |
selects.
|
|
472 |
(*) - have type MAYBE or MAYBE_KEY. Perhaps we should remove trees of
|
|
473 |
these types here as well.
|
|
474 |
||
475 |
A SEL_ARG* tree cannot be used to construct quick select if it has
|
|
476 |
tree->part != 0. (e.g. it could represent "keypart2 < const").
|
|
477 |
||
478 |
WHY THIS FUNCTION IS NEEDED
|
|
479 |
||
480 |
Normally we allow construction of optimizer::SEL_TREE objects that have SEL_ARG
|
|
481 |
trees that do not allow quick range select construction. For example for
|
|
482 |
" keypart1=1 AND keypart2=2 " the execution will proceed as follows:
|
|
483 |
tree1= optimizer::SEL_TREE { SEL_ARG{keypart1=1} }
|
|
484 |
tree2= optimizer::SEL_TREE { SEL_ARG{keypart2=2} } -- can't make quick range select
|
|
485 |
from this
|
|
486 |
call tree_and(tree1, tree2) -- this joins SEL_ARGs into a usable SEL_ARG
|
|
487 |
tree.
|
|
488 |
||
489 |
There is an exception though: when we construct index_merge optimizer::SEL_TREE,
|
|
490 |
any SEL_ARG* tree that cannot be used to construct quick range select can
|
|
491 |
be removed, because current range analysis code doesn't provide any way
|
|
492 |
that tree could be later combined with another tree.
|
|
493 |
Consider an example: we should not construct
|
|
494 |
st1 = optimizer::SEL_TREE {
|
|
495 |
merges = SEL_IMERGE {
|
|
496 |
optimizer::SEL_TREE(t.key1part1 = 1),
|
|
497 |
optimizer::SEL_TREE(t.key2part2 = 2) -- (*)
|
|
498 |
}
|
|
499 |
};
|
|
500 |
because
|
|
501 |
- (*) cannot be used to construct quick range select,
|
|
502 |
- There is no execution path that would cause (*) to be converted to
|
|
503 |
a tree that could be used.
|
|
504 |
||
505 |
The latter is easy to verify: first, notice that the only way to convert
|
|
506 |
(*) into a usable tree is to call tree_and(something, (*)).
|
|
507 |
||
508 |
Second look at what tree_and/tree_or function would do when passed a
|
|
509 |
optimizer::SEL_TREE that has the structure like st1 tree has, and conlcude that
|
|
510 |
tree_and(something, (*)) will not be called.
|
|
511 |
||
512 |
RETURN
|
|
513 |
0 Ok, some suitable trees left
|
|
514 |
1 No tree->keys[] left.
|
|
515 |
*/
|
|
516 |
bool optimizer::remove_nonrange_trees(optimizer::RangeParameter *param, optimizer::SEL_TREE *tree) |
|
517 |
{
|
|
518 |
bool res= false; |
|
519 |
for (uint32_t i= 0; i < param->keys; i++) |
|
520 |
{
|
|
521 |
if (tree->keys[i]) |
|
522 |
{
|
|
523 |
if (tree->keys[i]->part) |
|
524 |
{
|
|
525 |
tree->keys[i]= NULL; |
|
526 |
tree->keys_map.reset(i); |
|
527 |
}
|
|
528 |
else
|
|
529 |
res= true; |
|
530 |
}
|
|
531 |
}
|
|
532 |
return ! res; |
|
533 |
}
|
|
534 |
||
535 |
||
536 |
/* Compare if two trees are equal */
|
|
537 |
static bool eq_tree(optimizer::SEL_ARG *a, optimizer::SEL_ARG *b) |
|
538 |
{
|
|
539 |
if (a == b) |
|
540 |
{
|
|
541 |
return true; |
|
542 |
}
|
|
543 |
||
544 |
if (! a || ! b || ! a->is_same(b)) |
|
545 |
{
|
|
546 |
return false; |
|
547 |
}
|
|
548 |
||
549 |
if (a->left != &optimizer::null_element && b->left != &optimizer::null_element) |
|
550 |
{
|
|
551 |
if (! eq_tree(a->left,b->left)) |
|
552 |
return false; |
|
553 |
}
|
|
554 |
else if (a->left != &optimizer::null_element || b->left != &optimizer::null_element) |
|
555 |
{
|
|
556 |
return false; |
|
557 |
}
|
|
558 |
||
559 |
if (a->right != &optimizer::null_element && b->right != &optimizer::null_element) |
|
560 |
{
|
|
561 |
if (! eq_tree(a->right,b->right)) |
|
562 |
return false; |
|
563 |
}
|
|
564 |
else if (a->right != &optimizer::null_element || b->right != &optimizer::null_element) |
|
565 |
{
|
|
566 |
return false; |
|
567 |
}
|
|
568 |
||
569 |
if (a->next_key_part != b->next_key_part) |
|
570 |
{ // Sub range |
|
571 |
if (! a->next_key_part != ! b->next_key_part || |
|
572 |
! eq_tree(a->next_key_part, b->next_key_part)) |
|
573 |
return false; |
|
574 |
}
|
|
575 |
||
576 |
return true; |
|
577 |
}
|