1
by brian
clean slate |
1 |
/* Copyright (C) 2000-2006 MySQL AB
|
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 as published by
|
|
5 |
the Free Software Foundation; version 2 of the License.
|
|
6 |
||
7 |
This program is distributed in the hope that it will be useful,
|
|
8 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
9 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
10 |
GNU General Public License for more details.
|
|
11 |
||
12 |
You should have received a copy of the GNU General Public License
|
|
13 |
along with this program; if not, write to the Free Software
|
|
14 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
15 |
||
16 |
/*
|
|
17 |
TODO:
|
|
18 |
Fix that MAYBE_KEY are stored in the tree so that we can detect use
|
|
19 |
of full hash keys for queries like:
|
|
20 |
||
21 |
select s.id, kws.keyword_id from sites as s,kws where s.id=kws.site_id and kws.keyword_id in (204,205);
|
|
22 |
||
23 |
*/
|
|
24 |
||
25 |
/*
|
|
26 |
This file contains:
|
|
27 |
||
28 |
RangeAnalysisModule
|
|
29 |
A module that accepts a condition, index (or partitioning) description,
|
|
30 |
and builds lists of intervals (in index/partitioning space), such that
|
|
31 |
all possible records that match the condition are contained within the
|
|
32 |
intervals.
|
|
33 |
The entry point for the range analysis module is get_mm_tree() function.
|
|
34 |
|
|
35 |
The lists are returned in form of complicated structure of interlinked
|
|
36 |
SEL_TREE/SEL_IMERGE/SEL_ARG objects.
|
|
37 |
See quick_range_seq_next, find_used_partitions for examples of how to walk
|
|
38 |
this structure.
|
|
39 |
All direct "users" of this module are located within this file, too.
|
|
40 |
||
41 |
||
42 |
PartitionPruningModule
|
|
43 |
A module that accepts a partitioned table, condition, and finds which
|
|
44 |
partitions we will need to use in query execution. Search down for
|
|
45 |
"PartitionPruningModule" for description.
|
|
46 |
The module has single entry point - prune_partitions() function.
|
|
47 |
||
48 |
||
49 |
Range/index_merge/groupby-minmax optimizer module
|
|
50 |
A module that accepts a table, condition, and returns
|
|
51 |
- a QUICK_*_SELECT object that can be used to retrieve rows that match
|
|
52 |
the specified condition, or a "no records will match the condition"
|
|
53 |
statement.
|
|
54 |
||
55 |
The module entry points are
|
|
56 |
test_quick_select()
|
|
57 |
get_quick_select_for_ref()
|
|
58 |
||
59 |
||
60 |
Record retrieval code for range/index_merge/groupby-min-max.
|
|
61 |
Implementations of QUICK_*_SELECT classes.
|
|
62 |
||
63 |
KeyTupleFormat
|
|
64 |
~~~~~~~~~~~~~~
|
|
65 |
The code in this file (and elsewhere) makes operations on key value tuples.
|
|
66 |
Those tuples are stored in the following format:
|
|
67 |
|
|
68 |
The tuple is a sequence of key part values. The length of key part value
|
|
69 |
depends only on its type (and not depends on the what value is stored)
|
|
70 |
|
|
71 |
KeyTuple: keypart1-data, keypart2-data, ...
|
|
72 |
|
|
73 |
The value of each keypart is stored in the following format:
|
|
74 |
|
|
75 |
keypart_data: [isnull_byte] keypart-value-bytes
|
|
76 |
||
77 |
If a keypart may have a NULL value (key_part->field->real_maybe_null() can
|
|
78 |
be used to check this), then the first byte is a NULL indicator with the
|
|
79 |
following valid values:
|
|
80 |
1 - keypart has NULL value.
|
|
81 |
0 - keypart has non-NULL value.
|
|
82 |
||
83 |
<questionable-statement> If isnull_byte==1 (NULL value), then the following
|
|
84 |
keypart->length bytes must be 0.
|
|
85 |
</questionable-statement>
|
|
86 |
||
87 |
keypart-value-bytes holds the value. Its format depends on the field type.
|
|
88 |
The length of keypart-value-bytes may or may not depend on the value being
|
|
89 |
stored. The default is that length is static and equal to
|
|
90 |
KEY_PART_INFO::length.
|
|
91 |
|
|
92 |
Key parts with (key_part_flag & HA_BLOB_PART) have length depending of the
|
|
93 |
value:
|
|
94 |
|
|
95 |
keypart-value-bytes: value_length value_bytes
|
|
96 |
||
97 |
The value_length part itself occupies HA_KEY_BLOB_LENGTH=2 bytes.
|
|
98 |
||
99 |
See key_copy() and key_restore() for code to move data between index tuple
|
|
100 |
and table record
|
|
101 |
||
102 |
CAUTION: the above description is only sergefp's understanding of the
|
|
103 |
subject and may omit some details.
|
|
104 |
*/
|
|
105 |
||
243.1.17
by Jay Pipes
FINAL PHASE removal of mysql_priv.h (Bye, bye my friend.) |
106 |
#include <drizzled/server_includes.h> |
107 |
#include <drizzled/sql_select.h> |
|
1
by brian
clean slate |
108 |
|
109 |
#ifndef EXTRA_DEBUG
|
|
110 |
#define test_rb_tree(A,B) {}
|
|
111 |
#define test_use_count(A) {}
|
|
112 |
#endif
|
|
113 |
||
114 |
/*
|
|
115 |
Convert double value to #rows. Currently this does floor(), and we
|
|
116 |
might consider using round() instead.
|
|
117 |
*/
|
|
118 |
#define double2rows(x) ((ha_rows)(x))
|
|
119 |
||
206
by Brian Aker
Removed final uint dead types. |
120 |
static int sel_cmp(Field *f,uchar *a,uchar *b,uint8_t a_flag,uint8_t b_flag); |
1
by brian
clean slate |
121 |
|
122 |
static uchar is_null_string[2]= {1,0}; |
|
123 |
||
124 |
class RANGE_OPT_PARAM; |
|
125 |
/*
|
|
126 |
A construction block of the SEL_ARG-graph.
|
|
127 |
|
|
128 |
The following description only covers graphs of SEL_ARG objects with
|
|
129 |
sel_arg->type==KEY_RANGE:
|
|
130 |
||
131 |
One SEL_ARG object represents an "elementary interval" in form
|
|
132 |
|
|
133 |
min_value <=? table.keypartX <=? max_value
|
|
134 |
|
|
135 |
The interval is a non-empty interval of any kind: with[out] minimum/maximum
|
|
136 |
bound, [half]open/closed, single-point interval, etc.
|
|
137 |
||
138 |
1. SEL_ARG GRAPH STRUCTURE
|
|
139 |
|
|
140 |
SEL_ARG objects are linked together in a graph. The meaning of the graph
|
|
141 |
is better demostrated by an example:
|
|
142 |
|
|
143 |
tree->keys[i]
|
|
144 |
|
|
|
145 |
| $ $
|
|
146 |
| part=1 $ part=2 $ part=3
|
|
147 |
| $ $
|
|
148 |
| +-------+ $ +-------+ $ +--------+
|
|
149 |
| | kp1<1 |--$-->| kp2=5 |--$-->| kp3=10 |
|
|
150 |
| +-------+ $ +-------+ $ +--------+
|
|
151 |
| | $ $ |
|
|
152 |
| | $ $ +--------+
|
|
153 |
| | $ $ | kp3=12 |
|
|
154 |
| | $ $ +--------+
|
|
155 |
| +-------+ $ $
|
|
156 |
\->| kp1=2 |--$--------------$-+
|
|
157 |
+-------+ $ $ | +--------+
|
|
158 |
| $ $ ==>| kp3=11 |
|
|
159 |
+-------+ $ $ | +--------+
|
|
160 |
| kp1=3 |--$--------------$-+ |
|
|
161 |
+-------+ $ $ +--------+
|
|
162 |
| $ $ | kp3=14 |
|
|
163 |
... $ $ +--------+
|
|
164 |
|
|
165 |
The entire graph is partitioned into "interval lists".
|
|
166 |
||
167 |
An interval list is a sequence of ordered disjoint intervals over the same
|
|
168 |
key part. SEL_ARG are linked via "next" and "prev" pointers. Additionally,
|
|
169 |
all intervals in the list form an RB-tree, linked via left/right/parent
|
|
170 |
pointers. The RB-tree root SEL_ARG object will be further called "root of the
|
|
171 |
interval list".
|
|
172 |
|
|
173 |
In the example pic, there are 4 interval lists:
|
|
174 |
"kp<1 OR kp1=2 OR kp1=3", "kp2=5", "kp3=10 OR kp3=12", "kp3=11 OR kp3=13".
|
|
175 |
The vertical lines represent SEL_ARG::next/prev pointers.
|
|
176 |
|
|
177 |
In an interval list, each member X may have SEL_ARG::next_key_part pointer
|
|
178 |
pointing to the root of another interval list Y. The pointed interval list
|
|
179 |
must cover a key part with greater number (i.e. Y->part > X->part).
|
|
180 |
|
|
181 |
In the example pic, the next_key_part pointers are represented by
|
|
182 |
horisontal lines.
|
|
183 |
||
184 |
2. SEL_ARG GRAPH SEMANTICS
|
|
185 |
||
186 |
It represents a condition in a special form (we don't have a name for it ATM)
|
|
187 |
The SEL_ARG::next/prev is "OR", and next_key_part is "AND".
|
|
188 |
|
|
189 |
For example, the picture represents the condition in form:
|
|
190 |
(kp1 < 1 AND kp2=5 AND (kp3=10 OR kp3=12)) OR
|
|
191 |
(kp1=2 AND (kp3=11 OR kp3=14)) OR
|
|
192 |
(kp1=3 AND (kp3=11 OR kp3=14))
|
|
193 |
||
194 |
||
195 |
3. SEL_ARG GRAPH USE
|
|
196 |
||
197 |
Use get_mm_tree() to construct SEL_ARG graph from WHERE condition.
|
|
198 |
Then walk the SEL_ARG graph and get a list of dijsoint ordered key
|
|
199 |
intervals (i.e. intervals in form
|
|
200 |
|
|
201 |
(constA1, .., const1_K) < (keypart1,.., keypartK) < (constB1, .., constB_K)
|
|
202 |
||
203 |
Those intervals can be used to access the index. The uses are in:
|
|
204 |
- check_quick_select() - Walk the SEL_ARG graph and find an estimate of
|
|
205 |
how many table records are contained within all
|
|
206 |
intervals.
|
|
207 |
- get_quick_select() - Walk the SEL_ARG, materialize the key intervals,
|
|
208 |
and create QUICK_RANGE_SELECT object that will
|
|
209 |
read records within these intervals.
|
|
210 |
||
211 |
4. SPACE COMPLEXITY NOTES
|
|
212 |
||
213 |
SEL_ARG graph is a representation of an ordered disjoint sequence of
|
|
214 |
intervals over the ordered set of index tuple values.
|
|
215 |
||
216 |
For multi-part keys, one can construct a WHERE expression such that its
|
|
217 |
list of intervals will be of combinatorial size. Here is an example:
|
|
218 |
|
|
219 |
(keypart1 IN (1,2, ..., n1)) AND
|
|
220 |
(keypart2 IN (1,2, ..., n2)) AND
|
|
221 |
(keypart3 IN (1,2, ..., n3))
|
|
222 |
|
|
223 |
For this WHERE clause the list of intervals will have n1*n2*n3 intervals
|
|
224 |
of form
|
|
225 |
|
|
226 |
(keypart1, keypart2, keypart3) = (k1, k2, k3), where 1 <= k{i} <= n{i}
|
|
227 |
|
|
228 |
SEL_ARG graph structure aims to reduce the amount of required space by
|
|
229 |
"sharing" the elementary intervals when possible (the pic at the
|
|
230 |
beginning of this comment has examples of such sharing). The sharing may
|
|
231 |
prevent combinatorial blowup:
|
|
232 |
||
233 |
There are WHERE clauses that have combinatorial-size interval lists but
|
|
234 |
will be represented by a compact SEL_ARG graph.
|
|
235 |
Example:
|
|
236 |
(keypartN IN (1,2, ..., n1)) AND
|
|
237 |
...
|
|
238 |
(keypart2 IN (1,2, ..., n2)) AND
|
|
239 |
(keypart1 IN (1,2, ..., n3))
|
|
240 |
||
241 |
but not in all cases:
|
|
242 |
||
243 |
- There are WHERE clauses that do have a compact SEL_ARG-graph
|
|
244 |
representation but get_mm_tree() and its callees will construct a
|
|
245 |
graph of combinatorial size.
|
|
246 |
Example:
|
|
247 |
(keypart1 IN (1,2, ..., n1)) AND
|
|
248 |
(keypart2 IN (1,2, ..., n2)) AND
|
|
249 |
...
|
|
250 |
(keypartN IN (1,2, ..., n3))
|
|
251 |
||
252 |
- There are WHERE clauses for which the minimal possible SEL_ARG graph
|
|
253 |
representation will have combinatorial size.
|
|
254 |
Example:
|
|
255 |
By induction: Let's take any interval on some keypart in the middle:
|
|
256 |
||
257 |
kp15=c0
|
|
258 |
|
|
259 |
Then let's AND it with this interval 'structure' from preceding and
|
|
260 |
following keyparts:
|
|
261 |
||
262 |
(kp14=c1 AND kp16=c3) OR keypart14=c2) (*)
|
|
263 |
|
|
264 |
We will obtain this SEL_ARG graph:
|
|
265 |
|
|
266 |
kp14 $ kp15 $ kp16
|
|
267 |
$ $
|
|
268 |
+---------+ $ +---------+ $ +---------+
|
|
269 |
| kp14=c1 |--$-->| kp15=c0 |--$-->| kp16=c3 |
|
|
270 |
+---------+ $ +---------+ $ +---------+
|
|
271 |
| $ $
|
|
272 |
+---------+ $ +---------+ $
|
|
273 |
| kp14=c2 |--$-->| kp15=c0 | $
|
|
274 |
+---------+ $ +---------+ $
|
|
275 |
$ $
|
|
276 |
|
|
277 |
Note that we had to duplicate "kp15=c0" and there was no way to avoid
|
|
278 |
that.
|
|
279 |
The induction step: AND the obtained expression with another "wrapping"
|
|
280 |
expression like (*).
|
|
281 |
When the process ends because of the limit on max. number of keyparts
|
|
282 |
we'll have:
|
|
283 |
||
284 |
WHERE clause length is O(3*#max_keyparts)
|
|
285 |
SEL_ARG graph size is O(2^(#max_keyparts/2))
|
|
286 |
||
287 |
(it is also possible to construct a case where instead of 2 in 2^n we
|
|
288 |
have a bigger constant, e.g. 4, and get a graph with 4^(31/2)= 2^31
|
|
289 |
nodes)
|
|
290 |
||
291 |
We avoid consuming too much memory by setting a limit on the number of
|
|
292 |
SEL_ARG object we can construct during one range analysis invocation.
|
|
293 |
*/
|
|
294 |
||
295 |
class SEL_ARG :public Sql_alloc |
|
296 |
{
|
|
297 |
public: |
|
206
by Brian Aker
Removed final uint dead types. |
298 |
uint8_t min_flag,max_flag,maybe_flag; |
299 |
uint8_t part; // Which key part |
|
300 |
uint8_t maybe_null; |
|
1
by brian
clean slate |
301 |
/*
|
302 |
Number of children of this element in the RB-tree, plus 1 for this
|
|
303 |
element itself.
|
|
304 |
*/
|
|
206
by Brian Aker
Removed final uint dead types. |
305 |
uint16_t elements; |
1
by brian
clean slate |
306 |
/*
|
307 |
Valid only for elements which are RB-tree roots: Number of times this
|
|
308 |
RB-tree is referred to (it is referred by SEL_ARG::next_key_part or by
|
|
309 |
SEL_TREE::keys[i] or by a temporary SEL_ARG* variable)
|
|
310 |
*/
|
|
311 |
ulong use_count; |
|
312 |
||
313 |
Field *field; |
|
314 |
uchar *min_value,*max_value; // Pointer to range |
|
315 |
||
316 |
/*
|
|
317 |
eq_tree() requires that left == right == 0 if the type is MAYBE_KEY.
|
|
318 |
*/
|
|
319 |
SEL_ARG *left,*right; /* R-B tree children */ |
|
320 |
SEL_ARG *next,*prev; /* Links for bi-directional interval list */ |
|
321 |
SEL_ARG *parent; /* R-B tree parent */ |
|
322 |
SEL_ARG *next_key_part; |
|
323 |
enum leaf_color { BLACK,RED } color; |
|
324 |
enum Type { IMPOSSIBLE, MAYBE, MAYBE_KEY, KEY_RANGE } type; |
|
325 |
||
326 |
enum { MAX_SEL_ARGS = 16000 }; |
|
327 |
||
328 |
SEL_ARG() {} |
|
329 |
SEL_ARG(SEL_ARG &); |
|
330 |
SEL_ARG(Field *,const uchar *, const uchar *); |
|
206
by Brian Aker
Removed final uint dead types. |
331 |
SEL_ARG(Field *field, uint8_t part, uchar *min_value, uchar *max_value, |
332 |
uint8_t min_flag, uint8_t max_flag, uint8_t maybe_flag); |
|
1
by brian
clean slate |
333 |
SEL_ARG(enum Type type_arg) |
334 |
:min_flag(0),elements(1),use_count(1),left(0),right(0),next_key_part(0), |
|
335 |
color(BLACK), type(type_arg) |
|
336 |
{}
|
|
337 |
inline bool is_same(SEL_ARG *arg) |
|
338 |
{
|
|
339 |
if (type != arg->type || part != arg->part) |
|
340 |
return 0; |
|
341 |
if (type != KEY_RANGE) |
|
342 |
return 1; |
|
343 |
return cmp_min_to_min(arg) == 0 && cmp_max_to_max(arg) == 0; |
|
344 |
}
|
|
345 |
inline void merge_flags(SEL_ARG *arg) { maybe_flag|=arg->maybe_flag; } |
|
346 |
inline void maybe_smaller() { maybe_flag=1; } |
|
347 |
/* Return true iff it's a single-point null interval */
|
|
348 |
inline bool is_null_interval() { return maybe_null && max_value[0] == 1; } |
|
349 |
inline int cmp_min_to_min(SEL_ARG* arg) |
|
350 |
{
|
|
351 |
return sel_cmp(field,min_value, arg->min_value, min_flag, arg->min_flag); |
|
352 |
}
|
|
353 |
inline int cmp_min_to_max(SEL_ARG* arg) |
|
354 |
{
|
|
355 |
return sel_cmp(field,min_value, arg->max_value, min_flag, arg->max_flag); |
|
356 |
}
|
|
357 |
inline int cmp_max_to_max(SEL_ARG* arg) |
|
358 |
{
|
|
359 |
return sel_cmp(field,max_value, arg->max_value, max_flag, arg->max_flag); |
|
360 |
}
|
|
361 |
inline int cmp_max_to_min(SEL_ARG* arg) |
|
362 |
{
|
|
363 |
return sel_cmp(field,max_value, arg->min_value, max_flag, arg->min_flag); |
|
364 |
}
|
|
365 |
SEL_ARG *clone_and(SEL_ARG* arg) |
|
366 |
{ // Get overlapping range |
|
367 |
uchar *new_min,*new_max; |
|
206
by Brian Aker
Removed final uint dead types. |
368 |
uint8_t flag_min,flag_max; |
1
by brian
clean slate |
369 |
if (cmp_min_to_min(arg) >= 0) |
370 |
{
|
|
371 |
new_min=min_value; flag_min=min_flag; |
|
372 |
}
|
|
373 |
else
|
|
374 |
{
|
|
375 |
new_min=arg->min_value; flag_min=arg->min_flag; /* purecov: deadcode */ |
|
376 |
}
|
|
377 |
if (cmp_max_to_max(arg) <= 0) |
|
378 |
{
|
|
379 |
new_max=max_value; flag_max=max_flag; |
|
380 |
}
|
|
381 |
else
|
|
382 |
{
|
|
383 |
new_max=arg->max_value; flag_max=arg->max_flag; |
|
384 |
}
|
|
385 |
return new SEL_ARG(field, part, new_min, new_max, flag_min, flag_max, |
|
386 |
test(maybe_flag && arg->maybe_flag)); |
|
387 |
}
|
|
388 |
SEL_ARG *clone_first(SEL_ARG *arg) |
|
389 |
{ // min <= X < arg->min |
|
390 |
return new SEL_ARG(field,part, min_value, arg->min_value, |
|
391 |
min_flag, arg->min_flag & NEAR_MIN ? 0 : NEAR_MAX, |
|
392 |
maybe_flag | arg->maybe_flag); |
|
393 |
}
|
|
394 |
SEL_ARG *clone_last(SEL_ARG *arg) |
|
395 |
{ // min <= X <= key_max |
|
396 |
return new SEL_ARG(field, part, min_value, arg->max_value, |
|
397 |
min_flag, arg->max_flag, maybe_flag | arg->maybe_flag); |
|
398 |
}
|
|
399 |
SEL_ARG *clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent, SEL_ARG **next); |
|
400 |
||
401 |
bool copy_min(SEL_ARG* arg) |
|
402 |
{ // Get overlapping range |
|
403 |
if (cmp_min_to_min(arg) > 0) |
|
404 |
{
|
|
405 |
min_value=arg->min_value; min_flag=arg->min_flag; |
|
406 |
if ((max_flag & (NO_MAX_RANGE | NO_MIN_RANGE)) == |
|
407 |
(NO_MAX_RANGE | NO_MIN_RANGE)) |
|
408 |
return 1; // Full range |
|
409 |
}
|
|
410 |
maybe_flag|=arg->maybe_flag; |
|
411 |
return 0; |
|
412 |
}
|
|
413 |
bool copy_max(SEL_ARG* arg) |
|
414 |
{ // Get overlapping range |
|
415 |
if (cmp_max_to_max(arg) <= 0) |
|
416 |
{
|
|
417 |
max_value=arg->max_value; max_flag=arg->max_flag; |
|
418 |
if ((max_flag & (NO_MAX_RANGE | NO_MIN_RANGE)) == |
|
419 |
(NO_MAX_RANGE | NO_MIN_RANGE)) |
|
420 |
return 1; // Full range |
|
421 |
}
|
|
422 |
maybe_flag|=arg->maybe_flag; |
|
423 |
return 0; |
|
424 |
}
|
|
425 |
||
426 |
void copy_min_to_min(SEL_ARG *arg) |
|
427 |
{
|
|
428 |
min_value=arg->min_value; min_flag=arg->min_flag; |
|
429 |
}
|
|
430 |
void copy_min_to_max(SEL_ARG *arg) |
|
431 |
{
|
|
432 |
max_value=arg->min_value; |
|
433 |
max_flag=arg->min_flag & NEAR_MIN ? 0 : NEAR_MAX; |
|
434 |
}
|
|
435 |
void copy_max_to_min(SEL_ARG *arg) |
|
436 |
{
|
|
437 |
min_value=arg->max_value; |
|
438 |
min_flag=arg->max_flag & NEAR_MAX ? 0 : NEAR_MIN; |
|
439 |
}
|
|
440 |
/* returns a number of keypart values (0 or 1) appended to the key buffer */
|
|
441 |
int store_min(uint length, uchar **min_key,uint min_key_flag) |
|
442 |
{
|
|
443 |
/* "(kp1 > c1) AND (kp2 OP c2) AND ..." -> (kp1 > c1) */
|
|
444 |
if ((!(min_flag & NO_MIN_RANGE) && |
|
445 |
!(min_key_flag & (NO_MIN_RANGE | NEAR_MIN)))) |
|
446 |
{
|
|
447 |
if (maybe_null && *min_value) |
|
448 |
{
|
|
449 |
**min_key=1; |
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
450 |
memset(*min_key+1, 0, length-1); |
1
by brian
clean slate |
451 |
}
|
452 |
else
|
|
453 |
memcpy(*min_key,min_value,length); |
|
454 |
(*min_key)+= length; |
|
455 |
return 1; |
|
456 |
}
|
|
457 |
return 0; |
|
458 |
}
|
|
459 |
/* returns a number of keypart values (0 or 1) appended to the key buffer */
|
|
460 |
int store_max(uint length, uchar **max_key, uint max_key_flag) |
|
461 |
{
|
|
462 |
if (!(max_flag & NO_MAX_RANGE) && |
|
463 |
!(max_key_flag & (NO_MAX_RANGE | NEAR_MAX))) |
|
464 |
{
|
|
465 |
if (maybe_null && *max_value) |
|
466 |
{
|
|
467 |
**max_key=1; |
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
468 |
memset(*max_key+1, 0, length-1); |
1
by brian
clean slate |
469 |
}
|
470 |
else
|
|
471 |
memcpy(*max_key,max_value,length); |
|
472 |
(*max_key)+= length; |
|
473 |
return 1; |
|
474 |
}
|
|
475 |
return 0; |
|
476 |
}
|
|
477 |
||
478 |
/* returns a number of keypart values appended to the key buffer */
|
|
479 |
int store_min_key(KEY_PART *key, uchar **range_key, uint *range_key_flag) |
|
480 |
{
|
|
481 |
SEL_ARG *key_tree= first(); |
|
482 |
uint res= key_tree->store_min(key[key_tree->part].store_length, |
|
483 |
range_key, *range_key_flag); |
|
484 |
*range_key_flag|= key_tree->min_flag; |
|
485 |
||
486 |
if (key_tree->next_key_part && |
|
487 |
key_tree->next_key_part->part == key_tree->part+1 && |
|
488 |
!(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN)) && |
|
489 |
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) |
|
490 |
res+= key_tree->next_key_part->store_min_key(key, range_key, |
|
491 |
range_key_flag); |
|
492 |
return res; |
|
493 |
}
|
|
494 |
||
495 |
/* returns a number of keypart values appended to the key buffer */
|
|
496 |
int store_max_key(KEY_PART *key, uchar **range_key, uint *range_key_flag) |
|
497 |
{
|
|
498 |
SEL_ARG *key_tree= last(); |
|
499 |
uint res=key_tree->store_max(key[key_tree->part].store_length, |
|
500 |
range_key, *range_key_flag); |
|
501 |
(*range_key_flag)|= key_tree->max_flag; |
|
502 |
if (key_tree->next_key_part && |
|
503 |
key_tree->next_key_part->part == key_tree->part+1 && |
|
504 |
!(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX)) && |
|
505 |
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) |
|
506 |
res+= key_tree->next_key_part->store_max_key(key, range_key, |
|
507 |
range_key_flag); |
|
508 |
return res; |
|
509 |
}
|
|
510 |
||
511 |
SEL_ARG *insert(SEL_ARG *key); |
|
512 |
SEL_ARG *tree_delete(SEL_ARG *key); |
|
513 |
SEL_ARG *find_range(SEL_ARG *key); |
|
514 |
SEL_ARG *rb_insert(SEL_ARG *leaf); |
|
515 |
friend SEL_ARG *rb_delete_fixup(SEL_ARG *root,SEL_ARG *key, SEL_ARG *par); |
|
516 |
#ifdef EXTRA_DEBUG
|
|
517 |
friend int test_rb_tree(SEL_ARG *element,SEL_ARG *parent); |
|
518 |
void test_use_count(SEL_ARG *root); |
|
519 |
#endif
|
|
520 |
SEL_ARG *first(); |
|
521 |
SEL_ARG *last(); |
|
522 |
void make_root(); |
|
523 |
inline bool simple_key() |
|
524 |
{
|
|
525 |
return !next_key_part && elements == 1; |
|
526 |
}
|
|
527 |
void increment_use_count(long count) |
|
528 |
{
|
|
529 |
if (next_key_part) |
|
530 |
{
|
|
531 |
next_key_part->use_count+=count; |
|
532 |
count*= (next_key_part->use_count-count); |
|
533 |
for (SEL_ARG *pos=next_key_part->first(); pos ; pos=pos->next) |
|
534 |
if (pos->next_key_part) |
|
535 |
pos->increment_use_count(count); |
|
536 |
}
|
|
537 |
}
|
|
538 |
void free_tree() |
|
539 |
{
|
|
540 |
for (SEL_ARG *pos=first(); pos ; pos=pos->next) |
|
541 |
if (pos->next_key_part) |
|
542 |
{
|
|
543 |
pos->next_key_part->use_count--; |
|
544 |
pos->next_key_part->free_tree(); |
|
545 |
}
|
|
546 |
}
|
|
547 |
||
548 |
inline SEL_ARG **parent_ptr() |
|
549 |
{
|
|
550 |
return parent->left == this ? &parent->left : &parent->right; |
|
551 |
}
|
|
552 |
||
553 |
||
554 |
/*
|
|
555 |
Check if this SEL_ARG object represents a single-point interval
|
|
556 |
||
557 |
SYNOPSIS
|
|
558 |
is_singlepoint()
|
|
559 |
|
|
560 |
DESCRIPTION
|
|
561 |
Check if this SEL_ARG object (not tree) represents a single-point
|
|
562 |
interval, i.e. if it represents a "keypart = const" or
|
|
563 |
"keypart IS NULL".
|
|
564 |
||
565 |
RETURN
|
|
55
by brian
Update for using real bool types. |
566 |
true This SEL_ARG object represents a singlepoint interval
|
567 |
false Otherwise
|
|
1
by brian
clean slate |
568 |
*/
|
569 |
||
570 |
bool is_singlepoint() |
|
571 |
{
|
|
572 |
/*
|
|
573 |
Check for NEAR_MIN ("strictly less") and NO_MIN_RANGE (-inf < field)
|
|
574 |
flags, and the same for right edge.
|
|
575 |
*/
|
|
576 |
if (min_flag || max_flag) |
|
55
by brian
Update for using real bool types. |
577 |
return false; |
1
by brian
clean slate |
578 |
uchar *min_val= min_value; |
579 |
uchar *max_val= max_value; |
|
580 |
||
581 |
if (maybe_null) |
|
582 |
{
|
|
583 |
/* First byte is a NULL value indicator */
|
|
584 |
if (*min_val != *max_val) |
|
55
by brian
Update for using real bool types. |
585 |
return false; |
1
by brian
clean slate |
586 |
|
587 |
if (*min_val) |
|
55
by brian
Update for using real bool types. |
588 |
return true; /* This "x IS NULL" */ |
1
by brian
clean slate |
589 |
min_val++; |
590 |
max_val++; |
|
591 |
}
|
|
592 |
return !field->key_cmp(min_val, max_val); |
|
593 |
}
|
|
594 |
SEL_ARG *clone_tree(RANGE_OPT_PARAM *param); |
|
595 |
};
|
|
596 |
||
597 |
class SEL_IMERGE; |
|
598 |
||
599 |
||
600 |
class SEL_TREE :public Sql_alloc |
|
601 |
{
|
|
602 |
public: |
|
603 |
/*
|
|
604 |
Starting an effort to document this field:
|
|
605 |
(for some i, keys[i]->type == SEL_ARG::IMPOSSIBLE) =>
|
|
606 |
(type == SEL_TREE::IMPOSSIBLE)
|
|
607 |
*/
|
|
608 |
enum Type { IMPOSSIBLE, ALWAYS, MAYBE, KEY, KEY_SMALLER } type; |
|
609 |
SEL_TREE(enum Type type_arg) :type(type_arg) {} |
|
610 |
SEL_TREE() :type(KEY) |
|
611 |
{
|
|
612 |
keys_map.clear_all(); |
|
212.6.6
by Mats Kindahl
Removing redundant use of casts in drizzled/ for memcmp(), memcpy(), memset(), and memmove(). |
613 |
memset(keys, 0, sizeof(keys)); |
1
by brian
clean slate |
614 |
}
|
615 |
/*
|
|
616 |
Note: there may exist SEL_TREE objects with sel_tree->type=KEY and
|
|
617 |
keys[i]=0 for all i. (SergeyP: it is not clear whether there is any
|
|
618 |
merit in range analyzer functions (e.g. get_mm_parts) returning a
|
|
619 |
pointer to such SEL_TREE instead of NULL)
|
|
620 |
*/
|
|
621 |
SEL_ARG *keys[MAX_KEY]; |
|
622 |
key_map keys_map; /* bitmask of non-NULL elements in keys */ |
|
623 |
||
624 |
/*
|
|
625 |
Possible ways to read rows using index_merge. The list is non-empty only
|
|
626 |
if type==KEY. Currently can be non empty only if keys_map.is_clear_all().
|
|
627 |
*/
|
|
628 |
List<SEL_IMERGE> merges; |
|
629 |
||
630 |
/* The members below are filled/used only after get_mm_tree is done */
|
|
631 |
key_map ror_scans_map; /* bitmask of ROR scan-able elements in keys */ |
|
632 |
uint n_ror_scans; /* number of set bits in ror_scans_map */ |
|
633 |
||
634 |
struct st_ror_scan_info **ror_scans; /* list of ROR key scans */ |
|
635 |
struct st_ror_scan_info **ror_scans_end; /* last ROR scan */ |
|
636 |
/* Note that #records for each key scan is stored in table->quick_rows */
|
|
637 |
};
|
|
638 |
||
639 |
class RANGE_OPT_PARAM |
|
640 |
{
|
|
641 |
public: |
|
642 |
THD *thd; /* Current thread handle */ |
|
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
643 |
Table *table; /* Table being analyzed */ |
1
by brian
clean slate |
644 |
COND *cond; /* Used inside get_mm_tree(). */ |
645 |
table_map prev_tables; |
|
646 |
table_map read_tables; |
|
647 |
table_map current_table; /* Bit of the table being analyzed */ |
|
648 |
||
649 |
/* Array of parts of all keys for which range analysis is performed */
|
|
650 |
KEY_PART *key_parts; |
|
651 |
KEY_PART *key_parts_end; |
|
652 |
MEM_ROOT *mem_root; /* Memory that will be freed when range analysis completes */ |
|
653 |
MEM_ROOT *old_root; /* Memory that will last until the query end */ |
|
654 |
/*
|
|
655 |
Number of indexes used in range analysis (In SEL_TREE::keys only first
|
|
656 |
#keys elements are not empty)
|
|
657 |
*/
|
|
658 |
uint keys; |
|
659 |
||
660 |
/*
|
|
661 |
If true, the index descriptions describe real indexes (and it is ok to
|
|
662 |
call field->optimize_range(real_keynr[...], ...).
|
|
663 |
Otherwise index description describes fake indexes.
|
|
664 |
*/
|
|
665 |
bool using_real_indexes; |
|
666 |
||
667 |
bool remove_jump_scans; |
|
668 |
||
669 |
/*
|
|
670 |
used_key_no -> table_key_no translation table. Only makes sense if
|
|
55
by brian
Update for using real bool types. |
671 |
using_real_indexes==true
|
1
by brian
clean slate |
672 |
*/
|
673 |
uint real_keynr[MAX_KEY]; |
|
674 |
/* Number of SEL_ARG objects allocated by SEL_ARG::clone_tree operations */
|
|
675 |
uint alloced_sel_args; |
|
676 |
bool force_default_mrr; |
|
677 |
};
|
|
678 |
||
679 |
class PARAM : public RANGE_OPT_PARAM |
|
680 |
{
|
|
681 |
public: |
|
682 |
KEY_PART *key[MAX_KEY]; /* First key parts of keys used in the query */ |
|
152
by Brian Aker
longlong replacement |
683 |
int64_t baseflag; |
1
by brian
clean slate |
684 |
uint max_key_part; |
685 |
/* Number of ranges in the last checked tree->key */
|
|
686 |
uint range_count; |
|
687 |
uchar min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH], |
|
688 |
max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; |
|
689 |
bool quick; // Don't calulate possible keys |
|
690 |
||
691 |
uint fields_bitmap_size; |
|
692 |
MY_BITMAP needed_fields; /* bitmask of fields needed by the query */ |
|
693 |
MY_BITMAP tmp_covered_fields; |
|
694 |
||
695 |
key_map *needed_reg; /* ptr to SQL_SELECT::needed_reg */ |
|
696 |
||
697 |
uint *imerge_cost_buff; /* buffer for index_merge cost estimates */ |
|
698 |
uint imerge_cost_buff_size; /* size of the buffer */ |
|
699 |
||
55
by brian
Update for using real bool types. |
700 |
/* true if last checked tree->key can be used for ROR-scan */
|
1
by brian
clean slate |
701 |
bool is_ror_scan; |
702 |
/* Number of ranges in the last checked tree->key */
|
|
703 |
uint n_ranges; |
|
704 |
};
|
|
705 |
||
706 |
class TABLE_READ_PLAN; |
|
707 |
class TRP_RANGE; |
|
708 |
class TRP_ROR_INTERSECT; |
|
709 |
class TRP_ROR_UNION; |
|
710 |
class TRP_ROR_INDEX_MERGE; |
|
711 |
class TRP_GROUP_MIN_MAX; |
|
712 |
||
713 |
struct st_ror_scan_info; |
|
714 |
||
715 |
static SEL_TREE * get_mm_parts(RANGE_OPT_PARAM *param,COND *cond_func,Field *field, |
|
716 |
Item_func::Functype type,Item *value, |
|
717 |
Item_result cmp_type); |
|
718 |
static SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param,COND *cond_func,Field *field, |
|
719 |
KEY_PART *key_part, |
|
720 |
Item_func::Functype type,Item *value); |
|
721 |
static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond); |
|
722 |
||
206
by Brian Aker
Removed final uint dead types. |
723 |
static bool is_key_scan_ror(PARAM *param, uint keynr, uint8_t nparts); |
1
by brian
clean slate |
724 |
static ha_rows check_quick_select(PARAM *param, uint idx, bool index_only, |
725 |
SEL_ARG *tree, bool update_tbl_stats, |
|
726 |
uint *mrr_flags, uint *bufsize, |
|
727 |
COST_VECT *cost); |
|
728 |
//bool update_tbl_stats);
|
|
729 |
/*static ha_rows check_quick_keys(PARAM *param,uint index,SEL_ARG *key_tree,
|
|
730 |
uchar *min_key, uint min_key_flag, int,
|
|
731 |
uchar *max_key, uint max_key_flag, int);
|
|
732 |
*/
|
|
733 |
||
734 |
QUICK_RANGE_SELECT *get_quick_select(PARAM *param,uint index, |
|
735 |
SEL_ARG *key_tree, uint mrr_flags, |
|
736 |
uint mrr_buf_size, MEM_ROOT *alloc); |
|
737 |
static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, |
|
738 |
bool index_read_must_be_used, |
|
739 |
bool update_tbl_stats, |
|
740 |
double read_time); |
|
741 |
static
|
|
742 |
TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree, |
|
743 |
double read_time, |
|
744 |
bool *are_all_covering); |
|
745 |
static
|
|
746 |
TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param, |
|
747 |
SEL_TREE *tree, |
|
748 |
double read_time); |
|
749 |
static
|
|
750 |
TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, |
|
751 |
double read_time); |
|
752 |
static
|
|
753 |
TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree); |
|
754 |
||
755 |
static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map, |
|
756 |
const char *msg); |
|
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
757 |
static void print_ror_scans_arr(Table *table, const char *msg, |
1
by brian
clean slate |
758 |
struct st_ror_scan_info **start, |
759 |
struct st_ror_scan_info **end); |
|
760 |
||
761 |
static SEL_TREE *tree_and(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2); |
|
762 |
static SEL_TREE *tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2); |
|
763 |
static SEL_ARG *sel_add(SEL_ARG *key1,SEL_ARG *key2); |
|
764 |
static SEL_ARG *key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2); |
|
765 |
static SEL_ARG *key_and(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, |
|
766 |
uint clone_flag); |
|
767 |
static bool get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1); |
|
768 |
bool get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, |
|
769 |
SEL_ARG *key_tree, uchar *min_key,uint min_key_flag, |
|
770 |
uchar *max_key,uint max_key_flag); |
|
771 |
static bool eq_tree(SEL_ARG* a,SEL_ARG *b); |
|
772 |
||
773 |
static SEL_ARG null_element(SEL_ARG::IMPOSSIBLE); |
|
774 |
static bool null_part_in_key(KEY_PART *key_part, const uchar *key, |
|
775 |
uint length); |
|
776 |
bool sel_trees_can_be_ored(SEL_TREE *tree1, SEL_TREE *tree2, RANGE_OPT_PARAM* param); |
|
777 |
||
778 |
||
779 |
/*
|
|
780 |
SEL_IMERGE is a list of possible ways to do index merge, i.e. it is
|
|
781 |
a condition in the following form:
|
|
782 |
(t_1||t_2||...||t_N) && (next)
|
|
783 |
||
784 |
where all t_i are SEL_TREEs, next is another SEL_IMERGE and no pair
|
|
785 |
(t_i,t_j) contains SEL_ARGS for the same index.
|
|
786 |
||
787 |
SEL_TREE contained in SEL_IMERGE always has merges=NULL.
|
|
788 |
||
789 |
This class relies on memory manager to do the cleanup.
|
|
790 |
*/
|
|
791 |
||
792 |
class SEL_IMERGE : public Sql_alloc |
|
793 |
{
|
|
794 |
enum { PREALLOCED_TREES= 10}; |
|
795 |
public: |
|
796 |
SEL_TREE *trees_prealloced[PREALLOCED_TREES]; |
|
797 |
SEL_TREE **trees; /* trees used to do index_merge */ |
|
798 |
SEL_TREE **trees_next; /* last of these trees */ |
|
799 |
SEL_TREE **trees_end; /* end of allocated space */ |
|
800 |
||
801 |
SEL_ARG ***best_keys; /* best keys to read in SEL_TREEs */ |
|
802 |
||
803 |
SEL_IMERGE() : |
|
804 |
trees(&trees_prealloced[0]), |
|
805 |
trees_next(trees), |
|
806 |
trees_end(trees + PREALLOCED_TREES) |
|
807 |
{}
|
|
808 |
int or_sel_tree(RANGE_OPT_PARAM *param, SEL_TREE *tree); |
|
809 |
int or_sel_tree_with_checks(RANGE_OPT_PARAM *param, SEL_TREE *new_tree); |
|
810 |
int or_sel_imerge_with_checks(RANGE_OPT_PARAM *param, SEL_IMERGE* imerge); |
|
811 |
};
|
|
812 |
||
813 |
||
814 |
/*
|
|
815 |
Add SEL_TREE to this index_merge without any checks,
|
|
816 |
||
817 |
NOTES
|
|
818 |
This function implements the following:
|
|
819 |
(x_1||...||x_N) || t = (x_1||...||x_N||t), where x_i, t are SEL_TREEs
|
|
820 |
||
821 |
RETURN
|
|
822 |
0 - OK
|
|
823 |
-1 - Out of memory.
|
|
824 |
*/
|
|
825 |
||
826 |
int SEL_IMERGE::or_sel_tree(RANGE_OPT_PARAM *param, SEL_TREE *tree) |
|
827 |
{
|
|
828 |
if (trees_next == trees_end) |
|
829 |
{
|
|
830 |
const int realloc_ratio= 2; /* Double size for next round */ |
|
831 |
uint old_elements= (trees_end - trees); |
|
832 |
uint old_size= sizeof(SEL_TREE**) * old_elements; |
|
833 |
uint new_size= old_size * realloc_ratio; |
|
834 |
SEL_TREE **new_trees; |
|
835 |
if (!(new_trees= (SEL_TREE**)alloc_root(param->mem_root, new_size))) |
|
836 |
return -1; |
|
837 |
memcpy(new_trees, trees, old_size); |
|
838 |
trees= new_trees; |
|
839 |
trees_next= trees + old_elements; |
|
840 |
trees_end= trees + old_elements * realloc_ratio; |
|
841 |
}
|
|
842 |
*(trees_next++)= tree; |
|
843 |
return 0; |
|
844 |
}
|
|
845 |
||
846 |
||
847 |
/*
|
|
848 |
Perform OR operation on this SEL_IMERGE and supplied SEL_TREE new_tree,
|
|
849 |
combining new_tree with one of the trees in this SEL_IMERGE if they both
|
|
850 |
have SEL_ARGs for the same key.
|
|
851 |
||
852 |
SYNOPSIS
|
|
853 |
or_sel_tree_with_checks()
|
|
854 |
param PARAM from SQL_SELECT::test_quick_select
|
|
855 |
new_tree SEL_TREE with type KEY or KEY_SMALLER.
|
|
856 |
||
857 |
NOTES
|
|
858 |
This does the following:
|
|
859 |
(t_1||...||t_k)||new_tree =
|
|
860 |
either
|
|
861 |
= (t_1||...||t_k||new_tree)
|
|
862 |
or
|
|
863 |
= (t_1||....||(t_j|| new_tree)||...||t_k),
|
|
864 |
||
865 |
where t_i, y are SEL_TREEs.
|
|
866 |
new_tree is combined with the first t_j it has a SEL_ARG on common
|
|
867 |
key with. As a consequence of this, choice of keys to do index_merge
|
|
868 |
read may depend on the order of conditions in WHERE part of the query.
|
|
869 |
||
870 |
RETURN
|
|
871 |
0 OK
|
|
872 |
1 One of the trees was combined with new_tree to SEL_TREE::ALWAYS,
|
|
873 |
and (*this) should be discarded.
|
|
874 |
-1 An error occurred.
|
|
875 |
*/
|
|
876 |
||
877 |
int SEL_IMERGE::or_sel_tree_with_checks(RANGE_OPT_PARAM *param, SEL_TREE *new_tree) |
|
878 |
{
|
|
879 |
for (SEL_TREE** tree = trees; |
|
880 |
tree != trees_next; |
|
881 |
tree++) |
|
882 |
{
|
|
883 |
if (sel_trees_can_be_ored(*tree, new_tree, param)) |
|
884 |
{
|
|
885 |
*tree = tree_or(param, *tree, new_tree); |
|
886 |
if (!*tree) |
|
887 |
return 1; |
|
888 |
if (((*tree)->type == SEL_TREE::MAYBE) || |
|
889 |
((*tree)->type == SEL_TREE::ALWAYS)) |
|
890 |
return 1; |
|
891 |
/* SEL_TREE::IMPOSSIBLE is impossible here */
|
|
892 |
return 0; |
|
893 |
}
|
|
894 |
}
|
|
895 |
||
896 |
/* New tree cannot be combined with any of existing trees. */
|
|
897 |
return or_sel_tree(param, new_tree); |
|
898 |
}
|
|
899 |
||
900 |
||
901 |
/*
|
|
902 |
Perform OR operation on this index_merge and supplied index_merge list.
|
|
903 |
||
904 |
RETURN
|
|
905 |
0 - OK
|
|
55
by brian
Update for using real bool types. |
906 |
1 - One of conditions in result is always true and this SEL_IMERGE
|
1
by brian
clean slate |
907 |
should be discarded.
|
908 |
-1 - An error occurred
|
|
909 |
*/
|
|
910 |
||
911 |
int SEL_IMERGE::or_sel_imerge_with_checks(RANGE_OPT_PARAM *param, SEL_IMERGE* imerge) |
|
912 |
{
|
|
913 |
for (SEL_TREE** tree= imerge->trees; |
|
914 |
tree != imerge->trees_next; |
|
915 |
tree++) |
|
916 |
{
|
|
917 |
if (or_sel_tree_with_checks(param, *tree)) |
|
918 |
return 1; |
|
919 |
}
|
|
920 |
return 0; |
|
921 |
}
|
|
922 |
||
923 |
||
924 |
/*
|
|
925 |
Perform AND operation on two index_merge lists and store result in *im1.
|
|
926 |
*/
|
|
927 |
||
928 |
inline void imerge_list_and_list(List<SEL_IMERGE> *im1, List<SEL_IMERGE> *im2) |
|
929 |
{
|
|
930 |
im1->concat(im2); |
|
931 |
}
|
|
932 |
||
933 |
||
934 |
/*
|
|
935 |
Perform OR operation on 2 index_merge lists, storing result in first list.
|
|
936 |
||
937 |
NOTES
|
|
938 |
The following conversion is implemented:
|
|
939 |
(a_1 &&...&& a_N)||(b_1 &&...&& b_K) = AND_i,j(a_i || b_j) =>
|
|
940 |
=> (a_1||b_1).
|
|
941 |
||
942 |
i.e. all conjuncts except the first one are currently dropped.
|
|
943 |
This is done to avoid producing N*K ways to do index_merge.
|
|
944 |
||
55
by brian
Update for using real bool types. |
945 |
If (a_1||b_1) produce a condition that is always true, NULL is returned
|
1
by brian
clean slate |
946 |
and index_merge is discarded (while it is actually possible to try
|
947 |
harder).
|
|
948 |
||
949 |
As a consequence of this, choice of keys to do index_merge read may depend
|
|
950 |
on the order of conditions in WHERE part of the query.
|
|
951 |
||
952 |
RETURN
|
|
953 |
0 OK, result is stored in *im1
|
|
954 |
other Error, both passed lists are unusable
|
|
955 |
*/
|
|
956 |
||
957 |
int imerge_list_or_list(RANGE_OPT_PARAM *param, |
|
958 |
List<SEL_IMERGE> *im1, |
|
959 |
List<SEL_IMERGE> *im2) |
|
960 |
{
|
|
961 |
SEL_IMERGE *imerge= im1->head(); |
|
962 |
im1->empty(); |
|
963 |
im1->push_back(imerge); |
|
964 |
||
965 |
return imerge->or_sel_imerge_with_checks(param, im2->head()); |
|
966 |
}
|
|
967 |
||
968 |
||
969 |
/*
|
|
970 |
Perform OR operation on index_merge list and key tree.
|
|
971 |
||
972 |
RETURN
|
|
973 |
0 OK, result is stored in *im1.
|
|
974 |
other Error
|
|
975 |
*/
|
|
976 |
||
977 |
int imerge_list_or_tree(RANGE_OPT_PARAM *param, |
|
978 |
List<SEL_IMERGE> *im1, |
|
979 |
SEL_TREE *tree) |
|
980 |
{
|
|
981 |
SEL_IMERGE *imerge; |
|
982 |
List_iterator<SEL_IMERGE> it(*im1); |
|
983 |
while ((imerge= it++)) |
|
984 |
{
|
|
985 |
if (imerge->or_sel_tree_with_checks(param, tree)) |
|
986 |
it.remove(); |
|
987 |
}
|
|
988 |
return im1->is_empty(); |
|
989 |
}
|
|
990 |
||
991 |
||
992 |
/***************************************************************************
|
|
993 |
** Basic functions for SQL_SELECT and QUICK_RANGE_SELECT
|
|
994 |
***************************************************************************/
|
|
995 |
||
996 |
/* make a select from mysql info
|
|
997 |
Error is set as following:
|
|
998 |
0 = ok
|
|
999 |
1 = Got some error (out of memory?)
|
|
1000 |
*/
|
|
1001 |
||
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
1002 |
SQL_SELECT *make_select(Table *head, table_map const_tables, |
1
by brian
clean slate |
1003 |
table_map read_tables, COND *conds, |
1004 |
bool allow_null_cond, |
|
1005 |
int *error) |
|
1006 |
{
|
|
1007 |
SQL_SELECT *select; |
|
1008 |
||
1009 |
*error=0; |
|
1010 |
||
1011 |
if (!conds && !allow_null_cond) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1012 |
return(0); |
1
by brian
clean slate |
1013 |
if (!(select= new SQL_SELECT)) |
1014 |
{
|
|
1015 |
*error= 1; // out of memory |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1016 |
return(0); /* purecov: inspected */ |
1
by brian
clean slate |
1017 |
}
|
1018 |
select->read_tables=read_tables; |
|
1019 |
select->const_tables=const_tables; |
|
1020 |
select->head=head; |
|
1021 |
select->cond=conds; |
|
1022 |
||
1023 |
if (head->sort.io_cache) |
|
1024 |
{
|
|
1025 |
select->file= *head->sort.io_cache; |
|
1026 |
select->records=(ha_rows) (select->file.end_of_file/ |
|
1027 |
head->file->ref_length); |
|
1028 |
my_free(head->sort.io_cache, MYF(0)); |
|
1029 |
head->sort.io_cache=0; |
|
1030 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1031 |
return(select); |
1
by brian
clean slate |
1032 |
}
|
1033 |
||
1034 |
||
1035 |
SQL_SELECT::SQL_SELECT() :quick(0),cond(0),free_cond(0) |
|
1036 |
{
|
|
1037 |
quick_keys.clear_all(); needed_reg.clear_all(); |
|
1038 |
my_b_clear(&file); |
|
1039 |
}
|
|
1040 |
||
1041 |
||
1042 |
void SQL_SELECT::cleanup() |
|
1043 |
{
|
|
1044 |
delete quick; |
|
1045 |
quick= 0; |
|
1046 |
if (free_cond) |
|
1047 |
{
|
|
1048 |
free_cond=0; |
|
1049 |
delete cond; |
|
1050 |
cond= 0; |
|
1051 |
}
|
|
1052 |
close_cached_file(&file); |
|
1053 |
}
|
|
1054 |
||
1055 |
||
1056 |
SQL_SELECT::~SQL_SELECT() |
|
1057 |
{
|
|
1058 |
cleanup(); |
|
1059 |
}
|
|
1060 |
||
1061 |
QUICK_SELECT_I::QUICK_SELECT_I() |
|
1062 |
:max_used_key_length(0), |
|
1063 |
used_key_parts(0) |
|
1064 |
{}
|
|
1065 |
||
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
1066 |
QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, Table *table, uint key_nr, |
1
by brian
clean slate |
1067 |
bool no_alloc, MEM_ROOT *parent_alloc, |
1068 |
bool *create_error) |
|
1069 |
:free_file(0),cur_range(NULL),last_range(0),dont_free(0) |
|
1070 |
{
|
|
1071 |
my_bitmap_map *bitmap; |
|
1072 |
||
1073 |
in_ror_merged_scan= 0; |
|
1074 |
sorted= 0; |
|
1075 |
index= key_nr; |
|
1076 |
head= table; |
|
1077 |
key_part_info= head->key_info[index].key_part; |
|
1078 |
my_init_dynamic_array(&ranges, sizeof(QUICK_RANGE*), 16, 16); |
|
1079 |
||
1080 |
/* 'thd' is not accessible in QUICK_RANGE_SELECT::reset(). */
|
|
1081 |
mrr_buf_size= thd->variables.read_rnd_buff_size; |
|
1082 |
mrr_buf_desc= NULL; |
|
1083 |
||
1084 |
if (!no_alloc && !parent_alloc) |
|
1085 |
{
|
|
1086 |
// Allocates everything through the internal memroot
|
|
1087 |
init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0); |
|
1088 |
thd->mem_root= &alloc; |
|
1089 |
}
|
|
1090 |
else
|
|
212.6.6
by Mats Kindahl
Removing redundant use of casts in drizzled/ for memcmp(), memcpy(), memset(), and memmove(). |
1091 |
memset(&alloc, 0, sizeof(alloc)); |
1
by brian
clean slate |
1092 |
file= head->file; |
1093 |
record= head->record[0]; |
|
1094 |
save_read_set= head->read_set; |
|
1095 |
save_write_set= head->write_set; |
|
1096 |
||
1097 |
/* Allocate a bitmap for used columns (Q: why not on MEM_ROOT?) */
|
|
1098 |
if (!(bitmap= (my_bitmap_map*) my_malloc(head->s->column_bitmap_size, |
|
1099 |
MYF(MY_WME)))) |
|
1100 |
{
|
|
1101 |
column_bitmap.bitmap= 0; |
|
1102 |
*create_error= 1; |
|
1103 |
}
|
|
1104 |
else
|
|
55
by brian
Update for using real bool types. |
1105 |
bitmap_init(&column_bitmap, bitmap, head->s->fields, false); |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1106 |
return; |
1
by brian
clean slate |
1107 |
}
|
1108 |
||
1109 |
||
1110 |
int QUICK_RANGE_SELECT::init() |
|
1111 |
{
|
|
1112 |
if (file->inited != handler::NONE) |
|
1113 |
file->ha_index_or_rnd_end(); |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1114 |
return(file->ha_index_init(index, 1)); |
1
by brian
clean slate |
1115 |
}
|
1116 |
||
1117 |
||
1118 |
void QUICK_RANGE_SELECT::range_end() |
|
1119 |
{
|
|
1120 |
if (file->inited != handler::NONE) |
|
1121 |
file->ha_index_or_rnd_end(); |
|
1122 |
}
|
|
1123 |
||
1124 |
||
1125 |
QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() |
|
1126 |
{
|
|
1127 |
if (!dont_free) |
|
1128 |
{
|
|
1129 |
/* file is NULL for CPK scan on covering ROR-intersection */
|
|
1130 |
if (file) |
|
1131 |
{
|
|
1132 |
range_end(); |
|
1133 |
if (head->key_read) |
|
1134 |
{
|
|
1135 |
head->key_read= 0; |
|
1136 |
file->extra(HA_EXTRA_NO_KEYREAD); |
|
1137 |
}
|
|
1138 |
if (free_file) |
|
1139 |
{
|
|
1140 |
file->ha_external_lock(current_thd, F_UNLCK); |
|
1141 |
file->close(); |
|
1142 |
delete file; |
|
1143 |
}
|
|
1144 |
}
|
|
1145 |
delete_dynamic(&ranges); /* ranges are allocated in alloc */ |
|
1146 |
free_root(&alloc,MYF(0)); |
|
1147 |
my_free((char*) column_bitmap.bitmap, MYF(MY_ALLOW_ZERO_PTR)); |
|
1148 |
}
|
|
1149 |
head->column_bitmaps_set(save_read_set, save_write_set); |
|
1150 |
x_free(mrr_buf_desc); |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1151 |
return; |
1
by brian
clean slate |
1152 |
}
|
1153 |
||
1154 |
||
1155 |
QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT(THD *thd_param, |
|
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
1156 |
Table *table) |
1
by brian
clean slate |
1157 |
:pk_quick_select(NULL), thd(thd_param) |
1158 |
{
|
|
1159 |
index= MAX_KEY; |
|
1160 |
head= table; |
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
1161 |
memset(&read_record, 0, sizeof(read_record)); |
1
by brian
clean slate |
1162 |
init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0); |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1163 |
return; |
1
by brian
clean slate |
1164 |
}
|
1165 |
||
1166 |
int QUICK_INDEX_MERGE_SELECT::init() |
|
1167 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1168 |
return(0); |
1
by brian
clean slate |
1169 |
}
|
1170 |
||
1171 |
int QUICK_INDEX_MERGE_SELECT::reset() |
|
1172 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1173 |
return(read_keys_and_merge()); |
1
by brian
clean slate |
1174 |
}
|
1175 |
||
1176 |
bool
|
|
1177 |
QUICK_INDEX_MERGE_SELECT::push_quick_back(QUICK_RANGE_SELECT *quick_sel_range) |
|
1178 |
{
|
|
1179 |
/*
|
|
1180 |
Save quick_select that does scan on clustered primary key as it will be
|
|
1181 |
processed separately.
|
|
1182 |
*/
|
|
1183 |
if (head->file->primary_key_is_clustered() && |
|
1184 |
quick_sel_range->index == head->s->primary_key) |
|
1185 |
pk_quick_select= quick_sel_range; |
|
1186 |
else
|
|
1187 |
return quick_selects.push_back(quick_sel_range); |
|
1188 |
return 0; |
|
1189 |
}
|
|
1190 |
||
1191 |
QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT() |
|
1192 |
{
|
|
1193 |
List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects); |
|
1194 |
QUICK_RANGE_SELECT* quick; |
|
1195 |
quick_it.rewind(); |
|
1196 |
while ((quick= quick_it++)) |
|
1197 |
quick->file= NULL; |
|
1198 |
quick_selects.delete_elements(); |
|
1199 |
delete pk_quick_select; |
|
1200 |
free_root(&alloc,MYF(0)); |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1201 |
return; |
1
by brian
clean slate |
1202 |
}
|
1203 |
||
1204 |
||
1205 |
QUICK_ROR_INTERSECT_SELECT::QUICK_ROR_INTERSECT_SELECT(THD *thd_param, |
|
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
1206 |
Table *table, |
1
by brian
clean slate |
1207 |
bool retrieve_full_rows, |
1208 |
MEM_ROOT *parent_alloc) |
|
1209 |
: cpk_quick(NULL), thd(thd_param), need_to_fetch_row(retrieve_full_rows), |
|
55
by brian
Update for using real bool types. |
1210 |
scans_inited(false) |
1
by brian
clean slate |
1211 |
{
|
1212 |
index= MAX_KEY; |
|
1213 |
head= table; |
|
1214 |
record= head->record[0]; |
|
1215 |
if (!parent_alloc) |
|
1216 |
init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0); |
|
1217 |
else
|
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
1218 |
memset(&alloc, 0, sizeof(MEM_ROOT)); |
1
by brian
clean slate |
1219 |
last_rowid= (uchar*) alloc_root(parent_alloc? parent_alloc : &alloc, |
1220 |
head->file->ref_length); |
|
1221 |
}
|
|
1222 |
||
1223 |
||
1224 |
/*
|
|
1225 |
Do post-constructor initialization.
|
|
1226 |
SYNOPSIS
|
|
1227 |
QUICK_ROR_INTERSECT_SELECT::init()
|
|
1228 |
||
1229 |
RETURN
|
|
1230 |
0 OK
|
|
1231 |
other Error code
|
|
1232 |
*/
|
|
1233 |
||
1234 |
int QUICK_ROR_INTERSECT_SELECT::init() |
|
1235 |
{
|
|
1236 |
/* Check if last_rowid was successfully allocated in ctor */
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1237 |
return(!last_rowid); |
1
by brian
clean slate |
1238 |
}
|
1239 |
||
1240 |
||
1241 |
/*
|
|
1242 |
Initialize this quick select to be a ROR-merged scan.
|
|
1243 |
||
1244 |
SYNOPSIS
|
|
1245 |
QUICK_RANGE_SELECT::init_ror_merged_scan()
|
|
55
by brian
Update for using real bool types. |
1246 |
reuse_handler If true, use head->file, otherwise create a separate
|
1
by brian
clean slate |
1247 |
handler object
|
1248 |
||
1249 |
NOTES
|
|
1250 |
This function creates and prepares for subsequent use a separate handler
|
|
1251 |
object if it can't reuse head->file. The reason for this is that during
|
|
1252 |
ROR-merge several key scans are performed simultaneously, and a single
|
|
1253 |
handler is only capable of preserving context of a single key scan.
|
|
1254 |
||
1255 |
In ROR-merge the quick select doing merge does full records retrieval,
|
|
1256 |
merged quick selects read only keys.
|
|
1257 |
||
1258 |
RETURN
|
|
1259 |
0 ROR child scan initialized, ok to use.
|
|
1260 |
1 error
|
|
1261 |
*/
|
|
1262 |
||
1263 |
int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) |
|
1264 |
{
|
|
1265 |
handler *save_file= file, *org_file; |
|
1266 |
THD *thd; |
|
1267 |
||
1268 |
in_ror_merged_scan= 1; |
|
1269 |
if (reuse_handler) |
|
1270 |
{
|
|
1271 |
if (init() || reset()) |
|
1272 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1273 |
return(1); |
1
by brian
clean slate |
1274 |
}
|
1275 |
head->column_bitmaps_set(&column_bitmap, &column_bitmap); |
|
1276 |
goto end; |
|
1277 |
}
|
|
1278 |
||
1279 |
/* Create a separate handler object for this quick select */
|
|
1280 |
if (free_file) |
|
1281 |
{
|
|
1282 |
/* already have own 'handler' object. */
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1283 |
return(0); |
1
by brian
clean slate |
1284 |
}
|
1285 |
||
1286 |
thd= head->in_use; |
|
1287 |
if (!(file= head->file->clone(thd->mem_root))) |
|
1288 |
{
|
|
1289 |
/*
|
|
1290 |
Manually set the error flag. Note: there seems to be quite a few
|
|
1291 |
places where a failure could cause the server to "hang" the client by
|
|
1292 |
sending no response to a query. ATM those are not real errors because
|
|
1293 |
the storage engine calls in question happen to never fail with the
|
|
1294 |
existing storage engines.
|
|
1295 |
*/
|
|
1296 |
my_error(ER_OUT_OF_RESOURCES, MYF(0)); /* purecov: inspected */ |
|
1297 |
/* Caller will free the memory */
|
|
1298 |
goto failure; /* purecov: inspected */ |
|
1299 |
}
|
|
1300 |
||
1301 |
head->column_bitmaps_set(&column_bitmap, &column_bitmap); |
|
1302 |
||
1303 |
if (file->ha_external_lock(thd, F_RDLCK)) |
|
1304 |
goto failure; |
|
1305 |
||
1306 |
if (init() || reset()) |
|
1307 |
{
|
|
1308 |
file->ha_external_lock(thd, F_UNLCK); |
|
1309 |
file->close(); |
|
1310 |
goto failure; |
|
1311 |
}
|
|
55
by brian
Update for using real bool types. |
1312 |
free_file= true; |
1
by brian
clean slate |
1313 |
last_rowid= file->ref; |
1314 |
||
1315 |
end: |
|
1316 |
/*
|
|
1317 |
We are only going to read key fields and call position() on 'file'
|
|
1318 |
The following sets head->tmp_set to only use this key and then updates
|
|
1319 |
head->read_set and head->write_set to use this bitmap.
|
|
1320 |
The now bitmap is stored in 'column_bitmap' which is used in ::get_next()
|
|
1321 |
*/
|
|
1322 |
org_file= head->file; |
|
1323 |
head->file= file; |
|
1324 |
/* We don't have to set 'head->keyread' here as the 'file' is unique */
|
|
1325 |
if (!head->no_keyread) |
|
1326 |
{
|
|
1327 |
head->key_read= 1; |
|
1328 |
head->mark_columns_used_by_index(index); |
|
1329 |
}
|
|
1330 |
head->prepare_for_position(); |
|
1331 |
head->file= org_file; |
|
1332 |
bitmap_copy(&column_bitmap, head->read_set); |
|
1333 |
head->column_bitmaps_set(&column_bitmap, &column_bitmap); |
|
1334 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1335 |
return(0); |
1
by brian
clean slate |
1336 |
|
1337 |
failure: |
|
1338 |
head->column_bitmaps_set(save_read_set, save_write_set); |
|
1339 |
delete file; |
|
1340 |
file= save_file; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1341 |
return(1); |
1
by brian
clean slate |
1342 |
}
|
1343 |
||
1344 |
||
1345 |
/*
|
|
1346 |
Initialize this quick select to be a part of a ROR-merged scan.
|
|
1347 |
SYNOPSIS
|
|
1348 |
QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan()
|
|
55
by brian
Update for using real bool types. |
1349 |
reuse_handler If true, use head->file, otherwise create separate
|
1
by brian
clean slate |
1350 |
handler object.
|
1351 |
RETURN
|
|
1352 |
0 OK
|
|
1353 |
other error code
|
|
1354 |
*/
|
|
1355 |
int QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan(bool reuse_handler) |
|
1356 |
{
|
|
1357 |
List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects); |
|
1358 |
QUICK_RANGE_SELECT* quick; |
|
1359 |
||
1360 |
/* Initialize all merged "children" quick selects */
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1361 |
assert(!need_to_fetch_row || reuse_handler); |
1
by brian
clean slate |
1362 |
if (!need_to_fetch_row && reuse_handler) |
1363 |
{
|
|
1364 |
quick= quick_it++; |
|
1365 |
/*
|
|
1366 |
There is no use of this->file. Use it for the first of merged range
|
|
1367 |
selects.
|
|
1368 |
*/
|
|
55
by brian
Update for using real bool types. |
1369 |
if (quick->init_ror_merged_scan(true)) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1370 |
return(1); |
1
by brian
clean slate |
1371 |
quick->file->extra(HA_EXTRA_KEYREAD_PRESERVE_FIELDS); |
1372 |
}
|
|
1373 |
while ((quick= quick_it++)) |
|
1374 |
{
|
|
55
by brian
Update for using real bool types. |
1375 |
if (quick->init_ror_merged_scan(false)) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1376 |
return(1); |
1
by brian
clean slate |
1377 |
quick->file->extra(HA_EXTRA_KEYREAD_PRESERVE_FIELDS); |
1378 |
/* All merged scans share the same record buffer in intersection. */
|
|
1379 |
quick->record= head->record[0]; |
|
1380 |
}
|
|
1381 |
||
1382 |
if (need_to_fetch_row && head->file->ha_rnd_init(1)) |
|
1383 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1384 |
return(1); |
1
by brian
clean slate |
1385 |
}
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1386 |
return(0); |
1
by brian
clean slate |
1387 |
}
|
1388 |
||
1389 |
||
1390 |
/*
|
|
1391 |
Initialize quick select for row retrieval.
|
|
1392 |
SYNOPSIS
|
|
1393 |
reset()
|
|
1394 |
RETURN
|
|
1395 |
0 OK
|
|
1396 |
other Error code
|
|
1397 |
*/
|
|
1398 |
||
1399 |
int QUICK_ROR_INTERSECT_SELECT::reset() |
|
1400 |
{
|
|
55
by brian
Update for using real bool types. |
1401 |
if (!scans_inited && init_ror_merged_scan(true)) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1402 |
return(1); |
55
by brian
Update for using real bool types. |
1403 |
scans_inited= true; |
1
by brian
clean slate |
1404 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
1405 |
QUICK_RANGE_SELECT *quick; |
|
1406 |
while ((quick= it++)) |
|
1407 |
quick->reset(); |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1408 |
return(0); |
1
by brian
clean slate |
1409 |
}
|
1410 |
||
1411 |
||
1412 |
/*
|
|
1413 |
Add a merged quick select to this ROR-intersection quick select.
|
|
1414 |
||
1415 |
SYNOPSIS
|
|
1416 |
QUICK_ROR_INTERSECT_SELECT::push_quick_back()
|
|
1417 |
quick Quick select to be added. The quick select must return
|
|
1418 |
rows in rowid order.
|
|
1419 |
NOTES
|
|
1420 |
This call can only be made before init() is called.
|
|
1421 |
||
1422 |
RETURN
|
|
55
by brian
Update for using real bool types. |
1423 |
false OK
|
1424 |
true Out of memory.
|
|
1
by brian
clean slate |
1425 |
*/
|
1426 |
||
1427 |
bool
|
|
1428 |
QUICK_ROR_INTERSECT_SELECT::push_quick_back(QUICK_RANGE_SELECT *quick) |
|
1429 |
{
|
|
1430 |
return quick_selects.push_back(quick); |
|
1431 |
}
|
|
1432 |
||
1433 |
QUICK_ROR_INTERSECT_SELECT::~QUICK_ROR_INTERSECT_SELECT() |
|
1434 |
{
|
|
1435 |
quick_selects.delete_elements(); |
|
1436 |
delete cpk_quick; |
|
1437 |
free_root(&alloc,MYF(0)); |
|
1438 |
if (need_to_fetch_row && head->file->inited != handler::NONE) |
|
1439 |
head->file->ha_rnd_end(); |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1440 |
return; |
1
by brian
clean slate |
1441 |
}
|
1442 |
||
1443 |
||
1444 |
QUICK_ROR_UNION_SELECT::QUICK_ROR_UNION_SELECT(THD *thd_param, |
|
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
1445 |
Table *table) |
55
by brian
Update for using real bool types. |
1446 |
: thd(thd_param), scans_inited(false) |
1
by brian
clean slate |
1447 |
{
|
1448 |
index= MAX_KEY; |
|
1449 |
head= table; |
|
1450 |
rowid_length= table->file->ref_length; |
|
1451 |
record= head->record[0]; |
|
1452 |
init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0); |
|
1453 |
thd_param->mem_root= &alloc; |
|
1454 |
}
|
|
1455 |
||
1456 |
||
1457 |
/*
|
|
1458 |
Do post-constructor initialization.
|
|
1459 |
SYNOPSIS
|
|
1460 |
QUICK_ROR_UNION_SELECT::init()
|
|
1461 |
||
1462 |
RETURN
|
|
1463 |
0 OK
|
|
1464 |
other Error code
|
|
1465 |
*/
|
|
1466 |
||
1467 |
int QUICK_ROR_UNION_SELECT::init() |
|
1468 |
{
|
|
1469 |
if (init_queue(&queue, quick_selects.elements, 0, |
|
55
by brian
Update for using real bool types. |
1470 |
false , QUICK_ROR_UNION_SELECT::queue_cmp, |
1
by brian
clean slate |
1471 |
(void*) this)) |
1472 |
{
|
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
1473 |
memset(&queue, 0, sizeof(QUEUE)); |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1474 |
return(1); |
1
by brian
clean slate |
1475 |
}
|
1476 |
||
1477 |
if (!(cur_rowid= (uchar*) alloc_root(&alloc, 2*head->file->ref_length))) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1478 |
return(1); |
1
by brian
clean slate |
1479 |
prev_rowid= cur_rowid + head->file->ref_length; |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1480 |
return(0); |
1
by brian
clean slate |
1481 |
}
|
1482 |
||
1483 |
||
1484 |
/*
|
|
1485 |
Comparison function to be used QUICK_ROR_UNION_SELECT::queue priority
|
|
1486 |
queue.
|
|
1487 |
||
1488 |
SYNPOSIS
|
|
1489 |
QUICK_ROR_UNION_SELECT::queue_cmp()
|
|
1490 |
arg Pointer to QUICK_ROR_UNION_SELECT
|
|
1491 |
val1 First merged select
|
|
1492 |
val2 Second merged select
|
|
1493 |
*/
|
|
1494 |
||
1495 |
int QUICK_ROR_UNION_SELECT::queue_cmp(void *arg, uchar *val1, uchar *val2) |
|
1496 |
{
|
|
1497 |
QUICK_ROR_UNION_SELECT *self= (QUICK_ROR_UNION_SELECT*)arg; |
|
1498 |
return self->head->file->cmp_ref(((QUICK_SELECT_I*)val1)->last_rowid, |
|
1499 |
((QUICK_SELECT_I*)val2)->last_rowid); |
|
1500 |
}
|
|
1501 |
||
1502 |
||
1503 |
/*
|
|
1504 |
Initialize quick select for row retrieval.
|
|
1505 |
SYNOPSIS
|
|
1506 |
reset()
|
|
1507 |
||
1508 |
RETURN
|
|
1509 |
0 OK
|
|
1510 |
other Error code
|
|
1511 |
*/
|
|
1512 |
||
1513 |
int QUICK_ROR_UNION_SELECT::reset() |
|
1514 |
{
|
|
1515 |
QUICK_SELECT_I *quick; |
|
1516 |
int error; |
|
55
by brian
Update for using real bool types. |
1517 |
have_prev_rowid= false; |
1
by brian
clean slate |
1518 |
if (!scans_inited) |
1519 |
{
|
|
1520 |
List_iterator_fast<QUICK_SELECT_I> it(quick_selects); |
|
1521 |
while ((quick= it++)) |
|
1522 |
{
|
|
55
by brian
Update for using real bool types. |
1523 |
if (quick->init_ror_merged_scan(false)) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1524 |
return(1); |
1
by brian
clean slate |
1525 |
}
|
55
by brian
Update for using real bool types. |
1526 |
scans_inited= true; |
1
by brian
clean slate |
1527 |
}
|
1528 |
queue_remove_all(&queue); |
|
1529 |
/*
|
|
1530 |
Initialize scans for merged quick selects and put all merged quick
|
|
1531 |
selects into the queue.
|
|
1532 |
*/
|
|
1533 |
List_iterator_fast<QUICK_SELECT_I> it(quick_selects); |
|
1534 |
while ((quick= it++)) |
|
1535 |
{
|
|
1536 |
if (quick->reset()) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1537 |
return(1); |
1
by brian
clean slate |
1538 |
if ((error= quick->get_next())) |
1539 |
{
|
|
1540 |
if (error == HA_ERR_END_OF_FILE) |
|
1541 |
continue; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1542 |
return(error); |
1
by brian
clean slate |
1543 |
}
|
1544 |
quick->save_last_pos(); |
|
1545 |
queue_insert(&queue, (uchar*)quick); |
|
1546 |
}
|
|
1547 |
||
1548 |
if (head->file->ha_rnd_init(1)) |
|
1549 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1550 |
return(1); |
1
by brian
clean slate |
1551 |
}
|
1552 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1553 |
return(0); |
1
by brian
clean slate |
1554 |
}
|
1555 |
||
1556 |
||
1557 |
bool
|
|
1558 |
QUICK_ROR_UNION_SELECT::push_quick_back(QUICK_SELECT_I *quick_sel_range) |
|
1559 |
{
|
|
1560 |
return quick_selects.push_back(quick_sel_range); |
|
1561 |
}
|
|
1562 |
||
1563 |
QUICK_ROR_UNION_SELECT::~QUICK_ROR_UNION_SELECT() |
|
1564 |
{
|
|
1565 |
delete_queue(&queue); |
|
1566 |
quick_selects.delete_elements(); |
|
1567 |
if (head->file->inited != handler::NONE) |
|
1568 |
head->file->ha_rnd_end(); |
|
1569 |
free_root(&alloc,MYF(0)); |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1570 |
return; |
1
by brian
clean slate |
1571 |
}
|
1572 |
||
1573 |
||
1574 |
QUICK_RANGE::QUICK_RANGE() |
|
1575 |
:min_key(0),max_key(0),min_length(0),max_length(0), |
|
1576 |
flag(NO_MIN_RANGE | NO_MAX_RANGE), |
|
1577 |
min_keypart_map(0), max_keypart_map(0) |
|
1578 |
{}
|
|
1579 |
||
1580 |
SEL_ARG::SEL_ARG(SEL_ARG &arg) :Sql_alloc() |
|
1581 |
{
|
|
1582 |
type=arg.type; |
|
1583 |
min_flag=arg.min_flag; |
|
1584 |
max_flag=arg.max_flag; |
|
1585 |
maybe_flag=arg.maybe_flag; |
|
1586 |
maybe_null=arg.maybe_null; |
|
1587 |
part=arg.part; |
|
1588 |
field=arg.field; |
|
1589 |
min_value=arg.min_value; |
|
1590 |
max_value=arg.max_value; |
|
1591 |
next_key_part=arg.next_key_part; |
|
1592 |
use_count=1; elements=1; |
|
1593 |
}
|
|
1594 |
||
1595 |
||
1596 |
inline void SEL_ARG::make_root() |
|
1597 |
{
|
|
1598 |
left=right= &null_element; |
|
1599 |
color=BLACK; |
|
1600 |
next=prev=0; |
|
1601 |
use_count=0; elements=1; |
|
1602 |
}
|
|
1603 |
||
1604 |
SEL_ARG::SEL_ARG(Field *f,const uchar *min_value_arg, |
|
1605 |
const uchar *max_value_arg) |
|
1606 |
:min_flag(0), max_flag(0), maybe_flag(0), maybe_null(f->real_maybe_null()), |
|
1607 |
elements(1), use_count(1), field(f), min_value((uchar*) min_value_arg), |
|
1608 |
max_value((uchar*) max_value_arg), next(0),prev(0), |
|
1609 |
next_key_part(0),color(BLACK),type(KEY_RANGE) |
|
1610 |
{
|
|
1611 |
left=right= &null_element; |
|
1612 |
}
|
|
1613 |
||
206
by Brian Aker
Removed final uint dead types. |
1614 |
SEL_ARG::SEL_ARG(Field *field_,uint8_t part_, |
1
by brian
clean slate |
1615 |
uchar *min_value_, uchar *max_value_, |
206
by Brian Aker
Removed final uint dead types. |
1616 |
uint8_t min_flag_,uint8_t max_flag_,uint8_t maybe_flag_) |
1
by brian
clean slate |
1617 |
:min_flag(min_flag_),max_flag(max_flag_),maybe_flag(maybe_flag_), |
1618 |
part(part_),maybe_null(field_->real_maybe_null()), elements(1),use_count(1), |
|
1619 |
field(field_), min_value(min_value_), max_value(max_value_), |
|
1620 |
next(0),prev(0),next_key_part(0),color(BLACK),type(KEY_RANGE) |
|
1621 |
{
|
|
1622 |
left=right= &null_element; |
|
1623 |
}
|
|
1624 |
||
1625 |
SEL_ARG *SEL_ARG::clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent, |
|
1626 |
SEL_ARG **next_arg) |
|
1627 |
{
|
|
1628 |
SEL_ARG *tmp; |
|
1629 |
||
1630 |
/* Bail out if we have already generated too many SEL_ARGs */
|
|
1631 |
if (++param->alloced_sel_args > MAX_SEL_ARGS) |
|
1632 |
return 0; |
|
1633 |
||
1634 |
if (type != KEY_RANGE) |
|
1635 |
{
|
|
1636 |
if (!(tmp= new (param->mem_root) SEL_ARG(type))) |
|
1637 |
return 0; // out of memory |
|
1638 |
tmp->prev= *next_arg; // Link into next/prev chain |
|
1639 |
(*next_arg)->next=tmp; |
|
1640 |
(*next_arg)= tmp; |
|
1641 |
}
|
|
1642 |
else
|
|
1643 |
{
|
|
1644 |
if (!(tmp= new (param->mem_root) SEL_ARG(field,part, min_value,max_value, |
|
1645 |
min_flag, max_flag, maybe_flag))) |
|
1646 |
return 0; // OOM |
|
1647 |
tmp->parent=new_parent; |
|
1648 |
tmp->next_key_part=next_key_part; |
|
1649 |
if (left != &null_element) |
|
1650 |
if (!(tmp->left=left->clone(param, tmp, next_arg))) |
|
1651 |
return 0; // OOM |
|
1652 |
||
1653 |
tmp->prev= *next_arg; // Link into next/prev chain |
|
1654 |
(*next_arg)->next=tmp; |
|
1655 |
(*next_arg)= tmp; |
|
1656 |
||
1657 |
if (right != &null_element) |
|
1658 |
if (!(tmp->right= right->clone(param, tmp, next_arg))) |
|
1659 |
return 0; // OOM |
|
1660 |
}
|
|
1661 |
increment_use_count(1); |
|
1662 |
tmp->color= color; |
|
1663 |
tmp->elements= this->elements; |
|
1664 |
return tmp; |
|
1665 |
}
|
|
1666 |
||
1667 |
SEL_ARG *SEL_ARG::first() |
|
1668 |
{
|
|
1669 |
SEL_ARG *next_arg=this; |
|
1670 |
if (!next_arg->left) |
|
1671 |
return 0; // MAYBE_KEY |
|
1672 |
while (next_arg->left != &null_element) |
|
1673 |
next_arg=next_arg->left; |
|
1674 |
return next_arg; |
|
1675 |
}
|
|
1676 |
||
1677 |
SEL_ARG *SEL_ARG::last() |
|
1678 |
{
|
|
1679 |
SEL_ARG *next_arg=this; |
|
1680 |
if (!next_arg->right) |
|
1681 |
return 0; // MAYBE_KEY |
|
1682 |
while (next_arg->right != &null_element) |
|
1683 |
next_arg=next_arg->right; |
|
1684 |
return next_arg; |
|
1685 |
}
|
|
1686 |
||
1687 |
||
1688 |
/*
|
|
1689 |
Check if a compare is ok, when one takes ranges in account
|
|
1690 |
Returns -2 or 2 if the ranges where 'joined' like < 2 and >= 2
|
|
1691 |
*/
|
|
1692 |
||
206
by Brian Aker
Removed final uint dead types. |
1693 |
static int sel_cmp(Field *field, uchar *a, uchar *b, uint8_t a_flag, |
1694 |
uint8_t b_flag) |
|
1
by brian
clean slate |
1695 |
{
|
1696 |
int cmp; |
|
1697 |
/* First check if there was a compare to a min or max element */
|
|
1698 |
if (a_flag & (NO_MIN_RANGE | NO_MAX_RANGE)) |
|
1699 |
{
|
|
1700 |
if ((a_flag & (NO_MIN_RANGE | NO_MAX_RANGE)) == |
|
1701 |
(b_flag & (NO_MIN_RANGE | NO_MAX_RANGE))) |
|
1702 |
return 0; |
|
1703 |
return (a_flag & NO_MIN_RANGE) ? -1 : 1; |
|
1704 |
}
|
|
1705 |
if (b_flag & (NO_MIN_RANGE | NO_MAX_RANGE)) |
|
1706 |
return (b_flag & NO_MIN_RANGE) ? 1 : -1; |
|
1707 |
||
1708 |
if (field->real_maybe_null()) // If null is part of key |
|
1709 |
{
|
|
1710 |
if (*a != *b) |
|
1711 |
{
|
|
1712 |
return *a ? -1 : 1; |
|
1713 |
}
|
|
1714 |
if (*a) |
|
1715 |
goto end; // NULL where equal |
|
1716 |
a++; b++; // Skip NULL marker |
|
1717 |
}
|
|
1718 |
cmp=field->key_cmp(a , b); |
|
1719 |
if (cmp) return cmp < 0 ? -1 : 1; // The values differed |
|
1720 |
||
1721 |
// Check if the compared equal arguments was defined with open/closed range
|
|
1722 |
end: |
|
1723 |
if (a_flag & (NEAR_MIN | NEAR_MAX)) |
|
1724 |
{
|
|
1725 |
if ((a_flag & (NEAR_MIN | NEAR_MAX)) == (b_flag & (NEAR_MIN | NEAR_MAX))) |
|
1726 |
return 0; |
|
1727 |
if (!(b_flag & (NEAR_MIN | NEAR_MAX))) |
|
1728 |
return (a_flag & NEAR_MIN) ? 2 : -2; |
|
1729 |
return (a_flag & NEAR_MIN) ? 1 : -1; |
|
1730 |
}
|
|
1731 |
if (b_flag & (NEAR_MIN | NEAR_MAX)) |
|
1732 |
return (b_flag & NEAR_MIN) ? -2 : 2; |
|
1733 |
return 0; // The elements where equal |
|
1734 |
}
|
|
1735 |
||
1736 |
||
1737 |
SEL_ARG *SEL_ARG::clone_tree(RANGE_OPT_PARAM *param) |
|
1738 |
{
|
|
1739 |
SEL_ARG tmp_link,*next_arg,*root; |
|
1740 |
next_arg= &tmp_link; |
|
1741 |
if (!(root= clone(param, (SEL_ARG *) 0, &next_arg))) |
|
1742 |
return 0; |
|
1743 |
next_arg->next=0; // Fix last link |
|
1744 |
tmp_link.next->prev=0; // Fix first link |
|
1745 |
if (root) // If not OOM |
|
1746 |
root->use_count= 0; |
|
1747 |
return root; |
|
1748 |
}
|
|
1749 |
||
1750 |
||
1751 |
/*
|
|
1752 |
Find the best index to retrieve first N records in given order
|
|
1753 |
||
1754 |
SYNOPSIS
|
|
1755 |
get_index_for_order()
|
|
1756 |
table Table to be accessed
|
|
1757 |
order Required ordering
|
|
1758 |
limit Number of records that will be retrieved
|
|
1759 |
||
1760 |
DESCRIPTION
|
|
1761 |
Find the best index that allows to retrieve first #limit records in the
|
|
1762 |
given order cheaper then one would retrieve them using full table scan.
|
|
1763 |
||
1764 |
IMPLEMENTATION
|
|
1765 |
Run through all table indexes and find the shortest index that allows
|
|
1766 |
records to be retrieved in given order. We look for the shortest index
|
|
1767 |
as we will have fewer index pages to read with it.
|
|
1768 |
||
1769 |
This function is used only by UPDATE/DELETE, so we take into account how
|
|
1770 |
the UPDATE/DELETE code will work:
|
|
1771 |
* index can only be scanned in forward direction
|
|
1772 |
* HA_EXTRA_KEYREAD will not be used
|
|
1773 |
Perhaps these assumptions could be relaxed.
|
|
1774 |
||
1775 |
RETURN
|
|
1776 |
Number of the index that produces the required ordering in the cheapest way
|
|
1777 |
MAX_KEY if no such index was found.
|
|
1778 |
*/
|
|
1779 |
||
327.2.3
by Brian Aker
Refactoring of class Table |
1780 |
uint get_index_for_order(Table *table, order_st *order, ha_rows limit) |
1
by brian
clean slate |
1781 |
{
|
1782 |
uint idx; |
|
1783 |
uint match_key= MAX_KEY, match_key_len= MAX_KEY_LENGTH + 1; |
|
327.2.3
by Brian Aker
Refactoring of class Table |
1784 |
order_st *ord; |
1
by brian
clean slate |
1785 |
|
1786 |
for (ord= order; ord; ord= ord->next) |
|
1787 |
if (!ord->asc) |
|
1788 |
return MAX_KEY; |
|
1789 |
||
1790 |
for (idx= 0; idx < table->s->keys; idx++) |
|
1791 |
{
|
|
1792 |
if (!(table->keys_in_use_for_query.is_set(idx))) |
|
1793 |
continue; |
|
1794 |
KEY_PART_INFO *keyinfo= table->key_info[idx].key_part; |
|
1795 |
uint n_parts= table->key_info[idx].key_parts; |
|
1796 |
uint partno= 0; |
|
1797 |
||
1798 |
/*
|
|
1799 |
The below check is sufficient considering we now have either BTREE
|
|
1800 |
indexes (records are returned in order for any index prefix) or HASH
|
|
1801 |
indexes (records are not returned in order for any index prefix).
|
|
1802 |
*/
|
|
1803 |
if (!(table->file->index_flags(idx, 0, 1) & HA_READ_ORDER)) |
|
1804 |
continue; |
|
1805 |
for (ord= order; ord && partno < n_parts; ord= ord->next, partno++) |
|
1806 |
{
|
|
1807 |
Item *item= order->item[0]; |
|
1808 |
if (!(item->type() == Item::FIELD_ITEM && |
|
1809 |
((Item_field*)item)->field->eq(keyinfo[partno].field))) |
|
1810 |
break; |
|
1811 |
}
|
|
1812 |
||
1813 |
if (!ord && table->key_info[idx].key_length < match_key_len) |
|
1814 |
{
|
|
1815 |
/*
|
|
1816 |
Ok, the ordering is compatible and this key is shorter then
|
|
1817 |
previous match (we want shorter keys as we'll have to read fewer
|
|
1818 |
index pages for the same number of records)
|
|
1819 |
*/
|
|
1820 |
match_key= idx; |
|
1821 |
match_key_len= table->key_info[idx].key_length; |
|
1822 |
}
|
|
1823 |
}
|
|
1824 |
||
1825 |
if (match_key != MAX_KEY) |
|
1826 |
{
|
|
1827 |
/*
|
|
1828 |
Found an index that allows records to be retrieved in the requested
|
|
1829 |
order. Now we'll check if using the index is cheaper then doing a table
|
|
1830 |
scan.
|
|
1831 |
*/
|
|
1832 |
double full_scan_time= table->file->scan_time(); |
|
1833 |
double index_scan_time= table->file->read_time(match_key, 1, limit); |
|
1834 |
if (index_scan_time > full_scan_time) |
|
1835 |
match_key= MAX_KEY; |
|
1836 |
}
|
|
1837 |
return match_key; |
|
1838 |
}
|
|
1839 |
||
1840 |
||
1841 |
/*
|
|
1842 |
Table rows retrieval plan. Range optimizer creates QUICK_SELECT_I-derived
|
|
1843 |
objects from table read plans.
|
|
1844 |
*/
|
|
1845 |
class TABLE_READ_PLAN |
|
1846 |
{
|
|
1847 |
public: |
|
1848 |
/*
|
|
1849 |
Plan read cost, with or without cost of full row retrieval, depending
|
|
1850 |
on plan creation parameters.
|
|
1851 |
*/
|
|
1852 |
double read_cost; |
|
1853 |
ha_rows records; /* estimate of #rows to be examined */ |
|
1854 |
||
1855 |
/*
|
|
55
by brian
Update for using real bool types. |
1856 |
If true, the scan returns rows in rowid order. This is used only for
|
1
by brian
clean slate |
1857 |
scans that can be both ROR and non-ROR.
|
1858 |
*/
|
|
1859 |
bool is_ror; |
|
1860 |
||
1861 |
/*
|
|
1862 |
Create quick select for this plan.
|
|
1863 |
SYNOPSIS
|
|
1864 |
make_quick()
|
|
1865 |
param Parameter from test_quick_select
|
|
55
by brian
Update for using real bool types. |
1866 |
retrieve_full_rows If true, created quick select will do full record
|
1
by brian
clean slate |
1867 |
retrieval.
|
1868 |
parent_alloc Memory pool to use, if any.
|
|
1869 |
||
1870 |
NOTES
|
|
1871 |
retrieve_full_rows is ignored by some implementations.
|
|
1872 |
||
1873 |
RETURN
|
|
1874 |
created quick select
|
|
1875 |
NULL on any error.
|
|
1876 |
*/
|
|
1877 |
virtual QUICK_SELECT_I *make_quick(PARAM *param, |
|
1878 |
bool retrieve_full_rows, |
|
1879 |
MEM_ROOT *parent_alloc=NULL) = 0; |
|
1880 |
||
1881 |
/* Table read plans are allocated on MEM_ROOT and are never deleted */
|
|
1882 |
static void *operator new(size_t size, MEM_ROOT *mem_root) |
|
1883 |
{ return (void*) alloc_root(mem_root, (uint) size); } |
|
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
1884 |
static void operator delete(void *ptr __attribute__((unused)), |
1885 |
size_t size __attribute__((unused))) |
|
77.1.46
by Monty Taylor
Finished the warnings work! |
1886 |
{ TRASH(ptr, size); } |
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
1887 |
static void operator delete(void *ptr __attribute__((unused)), |
1888 |
MEM_ROOT *mem_root __attribute__((unused))) |
|
77.1.46
by Monty Taylor
Finished the warnings work! |
1889 |
{ /* Never called */ } |
1
by brian
clean slate |
1890 |
virtual ~TABLE_READ_PLAN() {} /* Remove gcc warning */ |
1891 |
||
1892 |
};
|
|
1893 |
||
1894 |
class TRP_ROR_INTERSECT; |
|
1895 |
class TRP_ROR_UNION; |
|
1896 |
class TRP_INDEX_MERGE; |
|
1897 |
||
1898 |
||
1899 |
/*
|
|
1900 |
Plan for a QUICK_RANGE_SELECT scan.
|
|
1901 |
TRP_RANGE::make_quick ignores retrieve_full_rows parameter because
|
|
1902 |
QUICK_RANGE_SELECT doesn't distinguish between 'index only' scans and full
|
|
1903 |
record retrieval scans.
|
|
1904 |
*/
|
|
1905 |
||
1906 |
class TRP_RANGE : public TABLE_READ_PLAN |
|
1907 |
{
|
|
1908 |
public: |
|
1909 |
SEL_ARG *key; /* set of intervals to be used in "range" method retrieval */ |
|
1910 |
uint key_idx; /* key number in PARAM::key */ |
|
1911 |
uint mrr_flags; |
|
1912 |
uint mrr_buf_size; |
|
1913 |
||
1914 |
TRP_RANGE(SEL_ARG *key_arg, uint idx_arg, uint mrr_flags_arg) |
|
1915 |
: key(key_arg), key_idx(idx_arg), mrr_flags(mrr_flags_arg) |
|
1916 |
{}
|
|
1917 |
virtual ~TRP_RANGE() {} /* Remove gcc warning */ |
|
1918 |
||
77.1.46
by Monty Taylor
Finished the warnings work! |
1919 |
QUICK_SELECT_I *make_quick(PARAM *param, |
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
1920 |
bool retrieve_full_rows __attribute__((unused)), |
1
by brian
clean slate |
1921 |
MEM_ROOT *parent_alloc) |
1922 |
{
|
|
1923 |
QUICK_RANGE_SELECT *quick; |
|
1924 |
if ((quick= get_quick_select(param, key_idx, key, mrr_flags, mrr_buf_size, |
|
1925 |
parent_alloc))) |
|
1926 |
{
|
|
1927 |
quick->records= records; |
|
1928 |
quick->read_time= read_cost; |
|
1929 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1930 |
return(quick); |
1
by brian
clean slate |
1931 |
}
|
1932 |
};
|
|
1933 |
||
1934 |
||
1935 |
/* Plan for QUICK_ROR_INTERSECT_SELECT scan. */
|
|
1936 |
||
1937 |
class TRP_ROR_INTERSECT : public TABLE_READ_PLAN |
|
1938 |
{
|
|
1939 |
public: |
|
1940 |
TRP_ROR_INTERSECT() {} /* Remove gcc warning */ |
|
1941 |
virtual ~TRP_ROR_INTERSECT() {} /* Remove gcc warning */ |
|
1942 |
QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows, |
|
1943 |
MEM_ROOT *parent_alloc); |
|
1944 |
||
1945 |
/* Array of pointers to ROR range scans used in this intersection */
|
|
1946 |
struct st_ror_scan_info **first_scan; |
|
1947 |
struct st_ror_scan_info **last_scan; /* End of the above array */ |
|
1948 |
struct st_ror_scan_info *cpk_scan; /* Clustered PK scan, if there is one */ |
|
55
by brian
Update for using real bool types. |
1949 |
bool is_covering; /* true if no row retrieval phase is necessary */ |
1
by brian
clean slate |
1950 |
double index_scan_costs; /* SUM(cost(index_scan)) */ |
1951 |
};
|
|
1952 |
||
1953 |
||
1954 |
/*
|
|
1955 |
Plan for QUICK_ROR_UNION_SELECT scan.
|
|
1956 |
QUICK_ROR_UNION_SELECT always retrieves full rows, so retrieve_full_rows
|
|
1957 |
is ignored by make_quick.
|
|
1958 |
*/
|
|
1959 |
||
1960 |
class TRP_ROR_UNION : public TABLE_READ_PLAN |
|
1961 |
{
|
|
1962 |
public: |
|
1963 |
TRP_ROR_UNION() {} /* Remove gcc warning */ |
|
1964 |
virtual ~TRP_ROR_UNION() {} /* Remove gcc warning */ |
|
1965 |
QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows, |
|
1966 |
MEM_ROOT *parent_alloc); |
|
1967 |
TABLE_READ_PLAN **first_ror; /* array of ptrs to plans for merged scans */ |
|
1968 |
TABLE_READ_PLAN **last_ror; /* end of the above array */ |
|
1969 |
};
|
|
1970 |
||
1971 |
||
1972 |
/*
|
|
1973 |
Plan for QUICK_INDEX_MERGE_SELECT scan.
|
|
1974 |
QUICK_ROR_INTERSECT_SELECT always retrieves full rows, so retrieve_full_rows
|
|
1975 |
is ignored by make_quick.
|
|
1976 |
*/
|
|
1977 |
||
1978 |
class TRP_INDEX_MERGE : public TABLE_READ_PLAN |
|
1979 |
{
|
|
1980 |
public: |
|
1981 |
TRP_INDEX_MERGE() {} /* Remove gcc warning */ |
|
1982 |
virtual ~TRP_INDEX_MERGE() {} /* Remove gcc warning */ |
|
1983 |
QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows, |
|
1984 |
MEM_ROOT *parent_alloc); |
|
1985 |
TRP_RANGE **range_scans; /* array of ptrs to plans of merged scans */ |
|
1986 |
TRP_RANGE **range_scans_end; /* end of the array */ |
|
1987 |
};
|
|
1988 |
||
1989 |
||
1990 |
/*
|
|
1991 |
Plan for a QUICK_GROUP_MIN_MAX_SELECT scan.
|
|
1992 |
*/
|
|
1993 |
||
1994 |
class TRP_GROUP_MIN_MAX : public TABLE_READ_PLAN |
|
1995 |
{
|
|
1996 |
private: |
|
1997 |
bool have_min, have_max; |
|
1998 |
KEY_PART_INFO *min_max_arg_part; |
|
1999 |
uint group_prefix_len; |
|
2000 |
uint used_key_parts; |
|
2001 |
uint group_key_parts; |
|
2002 |
KEY *index_info; |
|
2003 |
uint index; |
|
2004 |
uint key_infix_len; |
|
2005 |
uchar key_infix[MAX_KEY_LENGTH]; |
|
2006 |
SEL_TREE *range_tree; /* Represents all range predicates in the query. */ |
|
2007 |
SEL_ARG *index_tree; /* The SEL_ARG sub-tree corresponding to index_info. */ |
|
2008 |
uint param_idx; /* Index of used key in param->key. */ |
|
2009 |
/* Number of records selected by the ranges in index_tree. */
|
|
2010 |
public: |
|
2011 |
ha_rows quick_prefix_records; |
|
2012 |
public: |
|
2013 |
TRP_GROUP_MIN_MAX(bool have_min_arg, bool have_max_arg, |
|
2014 |
KEY_PART_INFO *min_max_arg_part_arg, |
|
2015 |
uint group_prefix_len_arg, uint used_key_parts_arg, |
|
2016 |
uint group_key_parts_arg, KEY *index_info_arg, |
|
2017 |
uint index_arg, uint key_infix_len_arg, |
|
2018 |
uchar *key_infix_arg, |
|
2019 |
SEL_TREE *tree_arg, SEL_ARG *index_tree_arg, |
|
2020 |
uint param_idx_arg, ha_rows quick_prefix_records_arg) |
|
2021 |
: have_min(have_min_arg), have_max(have_max_arg), |
|
2022 |
min_max_arg_part(min_max_arg_part_arg), |
|
2023 |
group_prefix_len(group_prefix_len_arg), used_key_parts(used_key_parts_arg), |
|
2024 |
group_key_parts(group_key_parts_arg), index_info(index_info_arg), |
|
2025 |
index(index_arg), key_infix_len(key_infix_len_arg), range_tree(tree_arg), |
|
2026 |
index_tree(index_tree_arg), param_idx(param_idx_arg), |
|
2027 |
quick_prefix_records(quick_prefix_records_arg) |
|
2028 |
{
|
|
2029 |
if (key_infix_len) |
|
2030 |
memcpy(this->key_infix, key_infix_arg, key_infix_len); |
|
2031 |
}
|
|
2032 |
virtual ~TRP_GROUP_MIN_MAX() {} /* Remove gcc warning */ |
|
2033 |
||
2034 |
QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows, |
|
2035 |
MEM_ROOT *parent_alloc); |
|
2036 |
};
|
|
2037 |
||
2038 |
||
2039 |
/*
|
|
2040 |
Fill param->needed_fields with bitmap of fields used in the query.
|
|
2041 |
SYNOPSIS
|
|
2042 |
fill_used_fields_bitmap()
|
|
2043 |
param Parameter from test_quick_select function.
|
|
2044 |
||
2045 |
NOTES
|
|
2046 |
Clustered PK members are not put into the bitmap as they are implicitly
|
|
2047 |
present in all keys (and it is impossible to avoid reading them).
|
|
2048 |
RETURN
|
|
2049 |
0 Ok
|
|
2050 |
1 Out of memory.
|
|
2051 |
*/
|
|
2052 |
||
2053 |
static int fill_used_fields_bitmap(PARAM *param) |
|
2054 |
{
|
|
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
2055 |
Table *table= param->table; |
1
by brian
clean slate |
2056 |
my_bitmap_map *tmp; |
2057 |
uint pk; |
|
2058 |
param->tmp_covered_fields.bitmap= 0; |
|
2059 |
param->fields_bitmap_size= table->s->column_bitmap_size; |
|
2060 |
if (!(tmp= (my_bitmap_map*) alloc_root(param->mem_root, |
|
2061 |
param->fields_bitmap_size)) || |
|
55
by brian
Update for using real bool types. |
2062 |
bitmap_init(¶m->needed_fields, tmp, table->s->fields, false)) |
1
by brian
clean slate |
2063 |
return 1; |
2064 |
||
2065 |
bitmap_copy(¶m->needed_fields, table->read_set); |
|
2066 |
bitmap_union(¶m->needed_fields, table->write_set); |
|
2067 |
||
2068 |
pk= param->table->s->primary_key; |
|
2069 |
if (pk != MAX_KEY && param->table->file->primary_key_is_clustered()) |
|
2070 |
{
|
|
2071 |
/* The table uses clustered PK and it is not internally generated */
|
|
2072 |
KEY_PART_INFO *key_part= param->table->key_info[pk].key_part; |
|
2073 |
KEY_PART_INFO *key_part_end= key_part + |
|
2074 |
param->table->key_info[pk].key_parts; |
|
2075 |
for (;key_part != key_part_end; ++key_part) |
|
2076 |
bitmap_clear_bit(¶m->needed_fields, key_part->fieldnr-1); |
|
2077 |
}
|
|
2078 |
return 0; |
|
2079 |
}
|
|
2080 |
||
2081 |
||
2082 |
/*
|
|
2083 |
Test if a key can be used in different ranges
|
|
2084 |
||
2085 |
SYNOPSIS
|
|
2086 |
SQL_SELECT::test_quick_select()
|
|
2087 |
thd Current thread
|
|
2088 |
keys_to_use Keys to use for range retrieval
|
|
2089 |
prev_tables Tables assumed to be already read when the scan is
|
|
2090 |
performed (but not read at the moment of this call)
|
|
2091 |
limit Query limit
|
|
2092 |
force_quick_range Prefer to use range (instead of full table scan) even
|
|
2093 |
if it is more expensive.
|
|
2094 |
||
2095 |
NOTES
|
|
2096 |
Updates the following in the select parameter:
|
|
2097 |
needed_reg - Bits for keys with may be used if all prev regs are read
|
|
2098 |
quick - Parameter to use when reading records.
|
|
2099 |
||
2100 |
In the table struct the following information is updated:
|
|
2101 |
quick_keys - Which keys can be used
|
|
2102 |
quick_rows - How many rows the key matches
|
|
2103 |
quick_condition_rows - E(# rows that will satisfy the table condition)
|
|
2104 |
||
2105 |
IMPLEMENTATION
|
|
2106 |
quick_condition_rows value is obtained as follows:
|
|
2107 |
|
|
2108 |
It is a minimum of E(#output rows) for all considered table access
|
|
2109 |
methods (range and index_merge accesses over various indexes).
|
|
2110 |
|
|
2111 |
The obtained value is not a true E(#rows that satisfy table condition)
|
|
2112 |
but rather a pessimistic estimate. To obtain a true E(#...) one would
|
|
2113 |
need to combine estimates of various access methods, taking into account
|
|
2114 |
correlations between sets of rows they will return.
|
|
2115 |
|
|
2116 |
For example, if values of tbl.key1 and tbl.key2 are independent (a right
|
|
2117 |
assumption if we have no information about their correlation) then the
|
|
2118 |
correct estimate will be:
|
|
2119 |
|
|
2120 |
E(#rows("tbl.key1 < c1 AND tbl.key2 < c2")) =
|
|
2121 |
= E(#rows(tbl.key1 < c1)) / total_rows(tbl) * E(#rows(tbl.key2 < c2)
|
|
2122 |
||
2123 |
which is smaller than
|
|
2124 |
|
|
2125 |
MIN(E(#rows(tbl.key1 < c1), E(#rows(tbl.key2 < c2)))
|
|
2126 |
||
2127 |
which is currently produced.
|
|
2128 |
||
2129 |
TODO
|
|
2130 |
* Change the value returned in quick_condition_rows from a pessimistic
|
|
2131 |
estimate to true E(#rows that satisfy table condition).
|
|
2132 |
(we can re-use some of E(#rows) calcuation code from index_merge/intersection
|
|
2133 |
for this)
|
|
2134 |
|
|
2135 |
* Check if this function really needs to modify keys_to_use, and change the
|
|
2136 |
code to pass it by reference if it doesn't.
|
|
2137 |
||
2138 |
* In addition to force_quick_range other means can be (an usually are) used
|
|
2139 |
to make this function prefer range over full table scan. Figure out if
|
|
2140 |
force_quick_range is really needed.
|
|
2141 |
||
2142 |
RETURN
|
|
2143 |
-1 if impossible select (i.e. certainly no rows will be selected)
|
|
2144 |
0 if can't use quick_select
|
|
2145 |
1 if found usable ranges and quick select has been successfully created.
|
|
2146 |
*/
|
|
2147 |
||
2148 |
int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, |
|
2149 |
table_map prev_tables, |
|
2150 |
ha_rows limit, bool force_quick_range, |
|
2151 |
bool ordered_output) |
|
2152 |
{
|
|
2153 |
uint idx; |
|
2154 |
double scan_time; |
|
2155 |
delete quick; |
|
2156 |
quick=0; |
|
2157 |
needed_reg.clear_all(); |
|
2158 |
quick_keys.clear_all(); |
|
2159 |
if (keys_to_use.is_clear_all()) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2160 |
return(0); |
1
by brian
clean slate |
2161 |
records= head->file->stats.records; |
2162 |
if (!records) |
|
2163 |
records++; /* purecov: inspected */ |
|
2164 |
scan_time= (double) records / TIME_FOR_COMPARE + 1; |
|
2165 |
read_time= (double) head->file->scan_time() + scan_time + 1.1; |
|
2166 |
if (head->force_index) |
|
2167 |
scan_time= read_time= DBL_MAX; |
|
2168 |
if (limit < records) |
|
2169 |
read_time= (double) records + scan_time + 1; // Force to use index |
|
2170 |
else if (read_time <= 2.0 && !force_quick_range) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2171 |
return(0); /* No need for quick select */ |
1
by brian
clean slate |
2172 |
|
2173 |
keys_to_use.intersect(head->keys_in_use_for_query); |
|
2174 |
if (!keys_to_use.is_clear_all()) |
|
2175 |
{
|
|
2176 |
MEM_ROOT alloc; |
|
2177 |
SEL_TREE *tree= NULL; |
|
2178 |
KEY_PART *key_parts; |
|
2179 |
KEY *key_info; |
|
2180 |
PARAM param; |
|
2181 |
||
2182 |
if (check_stack_overrun(thd, 2*STACK_MIN_SIZE, NULL)) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2183 |
return(0); // Fatal error flag is set |
1
by brian
clean slate |
2184 |
|
2185 |
/* set up parameter that is passed to all functions */
|
|
2186 |
param.thd= thd; |
|
2187 |
param.baseflag= head->file->ha_table_flags(); |
|
2188 |
param.prev_tables=prev_tables | const_tables; |
|
2189 |
param.read_tables=read_tables; |
|
2190 |
param.current_table= head->map; |
|
2191 |
param.table=head; |
|
2192 |
param.keys=0; |
|
2193 |
param.mem_root= &alloc; |
|
2194 |
param.old_root= thd->mem_root; |
|
2195 |
param.needed_reg= &needed_reg; |
|
2196 |
param.imerge_cost_buff_size= 0; |
|
55
by brian
Update for using real bool types. |
2197 |
param.using_real_indexes= true; |
2198 |
param.remove_jump_scans= true; |
|
1
by brian
clean slate |
2199 |
param.force_default_mrr= ordered_output; |
2200 |
||
2201 |
thd->no_errors=1; // Don't warn about NULL |
|
2202 |
init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0); |
|
2203 |
if (!(param.key_parts= (KEY_PART*) alloc_root(&alloc, |
|
2204 |
sizeof(KEY_PART)* |
|
2205 |
head->s->key_parts)) || |
|
2206 |
fill_used_fields_bitmap(¶m)) |
|
2207 |
{
|
|
2208 |
thd->no_errors=0; |
|
2209 |
free_root(&alloc,MYF(0)); // Return memory & allocator |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2210 |
return(0); // Can't use range |
1
by brian
clean slate |
2211 |
}
|
2212 |
key_parts= param.key_parts; |
|
2213 |
thd->mem_root= &alloc; |
|
2214 |
||
2215 |
/*
|
|
2216 |
Make an array with description of all key parts of all table keys.
|
|
2217 |
This is used in get_mm_parts function.
|
|
2218 |
*/
|
|
2219 |
key_info= head->key_info; |
|
2220 |
for (idx=0 ; idx < head->s->keys ; idx++, key_info++) |
|
2221 |
{
|
|
2222 |
KEY_PART_INFO *key_part_info; |
|
2223 |
if (!keys_to_use.is_set(idx)) |
|
2224 |
continue; |
|
2225 |
||
2226 |
param.key[param.keys]=key_parts; |
|
2227 |
key_part_info= key_info->key_part; |
|
2228 |
for (uint part=0 ; part < key_info->key_parts ; |
|
2229 |
part++, key_parts++, key_part_info++) |
|
2230 |
{
|
|
2231 |
key_parts->key= param.keys; |
|
2232 |
key_parts->part= part; |
|
2233 |
key_parts->length= key_part_info->length; |
|
2234 |
key_parts->store_length= key_part_info->store_length; |
|
2235 |
key_parts->field= key_part_info->field; |
|
2236 |
key_parts->null_bit= key_part_info->null_bit; |
|
2237 |
key_parts->image_type = Field::itRAW; |
|
2238 |
/* Only HA_PART_KEY_SEG is used */
|
|
206
by Brian Aker
Removed final uint dead types. |
2239 |
key_parts->flag= (uint8_t) key_part_info->key_part_flag; |
1
by brian
clean slate |
2240 |
}
|
2241 |
param.real_keynr[param.keys++]=idx; |
|
2242 |
}
|
|
2243 |
param.key_parts_end=key_parts; |
|
2244 |
param.alloced_sel_args= 0; |
|
2245 |
||
2246 |
/* Calculate cost of full index read for the shortest covering index */
|
|
2247 |
if (!head->covering_keys.is_clear_all()) |
|
2248 |
{
|
|
355
by Brian Aker
More Table cleanup |
2249 |
int key_for_use= head->find_shortest_key(&head->covering_keys); |
1
by brian
clean slate |
2250 |
double key_read_time= |
2251 |
param.table->file->index_only_read_time(key_for_use, |
|
2252 |
rows2double(records)) + |
|
2253 |
(double) records / TIME_FOR_COMPARE; |
|
2254 |
if (key_read_time < read_time) |
|
2255 |
read_time= key_read_time; |
|
2256 |
}
|
|
2257 |
||
2258 |
TABLE_READ_PLAN *best_trp= NULL; |
|
2259 |
TRP_GROUP_MIN_MAX *group_trp; |
|
2260 |
double best_read_time= read_time; |
|
2261 |
||
2262 |
if (cond) |
|
2263 |
{
|
|
2264 |
if ((tree= get_mm_tree(¶m,cond))) |
|
2265 |
{
|
|
2266 |
if (tree->type == SEL_TREE::IMPOSSIBLE) |
|
2267 |
{
|
|
2268 |
records=0L; /* Return -1 from this function. */ |
|
2269 |
read_time= (double) HA_POS_ERROR; |
|
2270 |
goto free_mem; |
|
2271 |
}
|
|
2272 |
/*
|
|
2273 |
If the tree can't be used for range scans, proceed anyway, as we
|
|
2274 |
can construct a group-min-max quick select
|
|
2275 |
*/
|
|
2276 |
if (tree->type != SEL_TREE::KEY && tree->type != SEL_TREE::KEY_SMALLER) |
|
2277 |
tree= NULL; |
|
2278 |
}
|
|
2279 |
}
|
|
2280 |
||
2281 |
/*
|
|
2282 |
Try to construct a QUICK_GROUP_MIN_MAX_SELECT.
|
|
2283 |
Notice that it can be constructed no matter if there is a range tree.
|
|
2284 |
*/
|
|
2285 |
group_trp= get_best_group_min_max(¶m, tree); |
|
2286 |
if (group_trp) |
|
2287 |
{
|
|
2288 |
param.table->quick_condition_rows= min(group_trp->records, |
|
2289 |
head->file->stats.records); |
|
2290 |
if (group_trp->read_cost < best_read_time) |
|
2291 |
{
|
|
2292 |
best_trp= group_trp; |
|
2293 |
best_read_time= best_trp->read_cost; |
|
2294 |
}
|
|
2295 |
}
|
|
2296 |
||
2297 |
if (tree) |
|
2298 |
{
|
|
2299 |
/*
|
|
2300 |
It is possible to use a range-based quick select (but it might be
|
|
2301 |
slower than 'all' table scan).
|
|
2302 |
*/
|
|
2303 |
if (tree->merges.is_empty()) |
|
2304 |
{
|
|
2305 |
TRP_RANGE *range_trp; |
|
2306 |
TRP_ROR_INTERSECT *rori_trp; |
|
55
by brian
Update for using real bool types. |
2307 |
bool can_build_covering= false; |
1
by brian
clean slate |
2308 |
|
2309 |
/* Get best 'range' plan and prepare data for making other plans */
|
|
55
by brian
Update for using real bool types. |
2310 |
if ((range_trp= get_key_scans_params(¶m, tree, false, true, |
1
by brian
clean slate |
2311 |
best_read_time))) |
2312 |
{
|
|
2313 |
best_trp= range_trp; |
|
2314 |
best_read_time= best_trp->read_cost; |
|
2315 |
}
|
|
2316 |
||
2317 |
/*
|
|
2318 |
Simultaneous key scans and row deletes on several handler
|
|
2319 |
objects are not allowed so don't use ROR-intersection for
|
|
2320 |
table deletes.
|
|
2321 |
*/
|
|
2322 |
if ((thd->lex->sql_command != SQLCOM_DELETE)) |
|
2323 |
{
|
|
2324 |
/*
|
|
2325 |
Get best non-covering ROR-intersection plan and prepare data for
|
|
2326 |
building covering ROR-intersection.
|
|
2327 |
*/
|
|
2328 |
if ((rori_trp= get_best_ror_intersect(¶m, tree, best_read_time, |
|
2329 |
&can_build_covering))) |
|
2330 |
{
|
|
2331 |
best_trp= rori_trp; |
|
2332 |
best_read_time= best_trp->read_cost; |
|
2333 |
/*
|
|
2334 |
Try constructing covering ROR-intersect only if it looks possible
|
|
2335 |
and worth doing.
|
|
2336 |
*/
|
|
2337 |
if (!rori_trp->is_covering && can_build_covering && |
|
2338 |
(rori_trp= get_best_covering_ror_intersect(¶m, tree, |
|
2339 |
best_read_time))) |
|
2340 |
best_trp= rori_trp; |
|
2341 |
}
|
|
2342 |
}
|
|
2343 |
}
|
|
2344 |
else
|
|
2345 |
{
|
|
2346 |
/* Try creating index_merge/ROR-union scan. */
|
|
2347 |
SEL_IMERGE *imerge; |
|
2348 |
TABLE_READ_PLAN *best_conj_trp= NULL, *new_conj_trp; |
|
2349 |
List_iterator_fast<SEL_IMERGE> it(tree->merges); |
|
2350 |
while ((imerge= it++)) |
|
2351 |
{
|
|
2352 |
new_conj_trp= get_best_disjunct_quick(¶m, imerge, best_read_time); |
|
2353 |
if (new_conj_trp) |
|
2354 |
set_if_smaller(param.table->quick_condition_rows, |
|
2355 |
new_conj_trp->records); |
|
2356 |
if (!best_conj_trp || (new_conj_trp && new_conj_trp->read_cost < |
|
2357 |
best_conj_trp->read_cost)) |
|
2358 |
best_conj_trp= new_conj_trp; |
|
2359 |
}
|
|
2360 |
if (best_conj_trp) |
|
2361 |
best_trp= best_conj_trp; |
|
2362 |
}
|
|
2363 |
}
|
|
2364 |
||
2365 |
thd->mem_root= param.old_root; |
|
2366 |
||
2367 |
/* If we got a read plan, create a quick select from it. */
|
|
2368 |
if (best_trp) |
|
2369 |
{
|
|
2370 |
records= best_trp->records; |
|
55
by brian
Update for using real bool types. |
2371 |
if (!(quick= best_trp->make_quick(¶m, true)) || quick->init()) |
1
by brian
clean slate |
2372 |
{
|
2373 |
delete quick; |
|
2374 |
quick= NULL; |
|
2375 |
}
|
|
2376 |
}
|
|
2377 |
||
2378 |
free_mem: |
|
2379 |
free_root(&alloc,MYF(0)); // Return memory & allocator |
|
2380 |
thd->mem_root= param.old_root; |
|
2381 |
thd->no_errors=0; |
|
2382 |
}
|
|
2383 |
||
2384 |
/*
|
|
2385 |
Assume that if the user is using 'limit' we will only need to scan
|
|
2386 |
limit rows if we are using a key
|
|
2387 |
*/
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2388 |
return(records ? test(quick) : -1); |
1
by brian
clean slate |
2389 |
}
|
2390 |
||
2391 |
/*
|
|
2392 |
Get best plan for a SEL_IMERGE disjunctive expression.
|
|
2393 |
SYNOPSIS
|
|
2394 |
get_best_disjunct_quick()
|
|
2395 |
param Parameter from check_quick_select function
|
|
2396 |
imerge Expression to use
|
|
2397 |
read_time Don't create scans with cost > read_time
|
|
2398 |
||
2399 |
NOTES
|
|
2400 |
index_merge cost is calculated as follows:
|
|
2401 |
index_merge_cost =
|
|
2402 |
cost(index_reads) + (see #1)
|
|
2403 |
cost(rowid_to_row_scan) + (see #2)
|
|
2404 |
cost(unique_use) (see #3)
|
|
2405 |
||
2406 |
1. cost(index_reads) =SUM_i(cost(index_read_i))
|
|
2407 |
For non-CPK scans,
|
|
2408 |
cost(index_read_i) = {cost of ordinary 'index only' scan}
|
|
2409 |
For CPK scan,
|
|
2410 |
cost(index_read_i) = {cost of non-'index only' scan}
|
|
2411 |
||
2412 |
2. cost(rowid_to_row_scan)
|
|
2413 |
If table PK is clustered then
|
|
2414 |
cost(rowid_to_row_scan) =
|
|
2415 |
{cost of ordinary clustered PK scan with n_ranges=n_rows}
|
|
2416 |
||
2417 |
Otherwise, we use the following model to calculate costs:
|
|
2418 |
We need to retrieve n_rows rows from file that occupies n_blocks blocks.
|
|
2419 |
We assume that offsets of rows we need are independent variates with
|
|
2420 |
uniform distribution in [0..max_file_offset] range.
|
|
2421 |
||
2422 |
We'll denote block as "busy" if it contains row(s) we need to retrieve
|
|
2423 |
and "empty" if doesn't contain rows we need.
|
|
2424 |
||
2425 |
Probability that a block is empty is (1 - 1/n_blocks)^n_rows (this
|
|
2426 |
applies to any block in file). Let x_i be a variate taking value 1 if
|
|
2427 |
block #i is empty and 0 otherwise.
|
|
2428 |
||
2429 |
Then E(x_i) = (1 - 1/n_blocks)^n_rows;
|
|
2430 |
||
2431 |
E(n_empty_blocks) = E(sum(x_i)) = sum(E(x_i)) =
|
|
2432 |
= n_blocks * ((1 - 1/n_blocks)^n_rows) =
|
|
2433 |
~= n_blocks * exp(-n_rows/n_blocks).
|
|
2434 |
||
2435 |
E(n_busy_blocks) = n_blocks*(1 - (1 - 1/n_blocks)^n_rows) =
|
|
2436 |
~= n_blocks * (1 - exp(-n_rows/n_blocks)).
|
|
2437 |
||
2438 |
Average size of "hole" between neighbor non-empty blocks is
|
|
2439 |
E(hole_size) = n_blocks/E(n_busy_blocks).
|
|
2440 |
||
2441 |
The total cost of reading all needed blocks in one "sweep" is:
|
|
2442 |
||
2443 |
E(n_busy_blocks)*
|
|
2444 |
(DISK_SEEK_BASE_COST + DISK_SEEK_PROP_COST*n_blocks/E(n_busy_blocks)).
|
|
2445 |
||
2446 |
3. Cost of Unique use is calculated in Unique::get_use_cost function.
|
|
2447 |
||
2448 |
ROR-union cost is calculated in the same way index_merge, but instead of
|
|
2449 |
Unique a priority queue is used.
|
|
2450 |
||
2451 |
RETURN
|
|
2452 |
Created read plan
|
|
2453 |
NULL - Out of memory or no read scan could be built.
|
|
2454 |
*/
|
|
2455 |
||
2456 |
static
|
|
2457 |
TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, |
|
2458 |
double read_time) |
|
2459 |
{
|
|
2460 |
SEL_TREE **ptree; |
|
2461 |
TRP_INDEX_MERGE *imerge_trp= NULL; |
|
2462 |
uint n_child_scans= imerge->trees_next - imerge->trees; |
|
2463 |
TRP_RANGE **range_scans; |
|
2464 |
TRP_RANGE **cur_child; |
|
2465 |
TRP_RANGE **cpk_scan= NULL; |
|
55
by brian
Update for using real bool types. |
2466 |
bool imerge_too_expensive= false; |
1
by brian
clean slate |
2467 |
double imerge_cost= 0.0; |
2468 |
ha_rows cpk_scan_records= 0; |
|
2469 |
ha_rows non_cpk_scan_records= 0; |
|
2470 |
bool pk_is_clustered= param->table->file->primary_key_is_clustered(); |
|
55
by brian
Update for using real bool types. |
2471 |
bool all_scans_ror_able= true; |
2472 |
bool all_scans_rors= true; |
|
1
by brian
clean slate |
2473 |
uint unique_calc_buff_size; |
2474 |
TABLE_READ_PLAN **roru_read_plans; |
|
2475 |
TABLE_READ_PLAN **cur_roru_plan; |
|
2476 |
double roru_index_costs; |
|
2477 |
ha_rows roru_total_records; |
|
2478 |
double roru_intersect_part= 1.0; |
|
2479 |
||
2480 |
if (!(range_scans= (TRP_RANGE**)alloc_root(param->mem_root, |
|
2481 |
sizeof(TRP_RANGE*)* |
|
2482 |
n_child_scans))) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2483 |
return(NULL); |
1
by brian
clean slate |
2484 |
/*
|
2485 |
Collect best 'range' scan for each of disjuncts, and, while doing so,
|
|
2486 |
analyze possibility of ROR scans. Also calculate some values needed by
|
|
2487 |
other parts of the code.
|
|
2488 |
*/
|
|
2489 |
for (ptree= imerge->trees, cur_child= range_scans; |
|
2490 |
ptree != imerge->trees_next; |
|
2491 |
ptree++, cur_child++) |
|
2492 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2493 |
print_sel_tree(param, *ptree, &(*ptree)->keys_map, "tree in SEL_IMERGE"); |
55
by brian
Update for using real bool types. |
2494 |
if (!(*cur_child= get_key_scans_params(param, *ptree, true, false, read_time))) |
1
by brian
clean slate |
2495 |
{
|
2496 |
/*
|
|
2497 |
One of index scans in this index_merge is more expensive than entire
|
|
2498 |
table read for another available option. The entire index_merge (and
|
|
2499 |
any possible ROR-union) will be more expensive then, too. We continue
|
|
2500 |
here only to update SQL_SELECT members.
|
|
2501 |
*/
|
|
55
by brian
Update for using real bool types. |
2502 |
imerge_too_expensive= true; |
1
by brian
clean slate |
2503 |
}
|
2504 |
if (imerge_too_expensive) |
|
2505 |
continue; |
|
2506 |
||
2507 |
imerge_cost += (*cur_child)->read_cost; |
|
2508 |
all_scans_ror_able &= ((*ptree)->n_ror_scans > 0); |
|
2509 |
all_scans_rors &= (*cur_child)->is_ror; |
|
2510 |
if (pk_is_clustered && |
|
2511 |
param->real_keynr[(*cur_child)->key_idx] == |
|
2512 |
param->table->s->primary_key) |
|
2513 |
{
|
|
2514 |
cpk_scan= cur_child; |
|
2515 |
cpk_scan_records= (*cur_child)->records; |
|
2516 |
}
|
|
2517 |
else
|
|
2518 |
non_cpk_scan_records += (*cur_child)->records; |
|
2519 |
}
|
|
2520 |
||
2521 |
if (imerge_too_expensive || (imerge_cost > read_time) || |
|
2522 |
((non_cpk_scan_records+cpk_scan_records >= param->table->file->stats.records) && read_time != DBL_MAX)) |
|
2523 |
{
|
|
2524 |
/*
|
|
2525 |
Bail out if it is obvious that both index_merge and ROR-union will be
|
|
2526 |
more expensive
|
|
2527 |
*/
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2528 |
return(NULL); |
1
by brian
clean slate |
2529 |
}
|
2530 |
if (all_scans_rors) |
|
2531 |
{
|
|
2532 |
roru_read_plans= (TABLE_READ_PLAN**)range_scans; |
|
2533 |
goto skip_to_ror_scan; |
|
2534 |
}
|
|
2535 |
if (cpk_scan) |
|
2536 |
{
|
|
2537 |
/*
|
|
2538 |
Add one ROWID comparison for each row retrieved on non-CPK scan. (it
|
|
2539 |
is done in QUICK_RANGE_SELECT::row_in_ranges)
|
|
2540 |
*/
|
|
2541 |
imerge_cost += non_cpk_scan_records / TIME_FOR_COMPARE_ROWID; |
|
2542 |
}
|
|
2543 |
||
2544 |
/* Calculate cost(rowid_to_row_scan) */
|
|
2545 |
{
|
|
2546 |
COST_VECT sweep_cost; |
|
2547 |
JOIN *join= param->thd->lex->select_lex.join; |
|
2548 |
bool is_interrupted= test(join && join->tables == 1); |
|
2549 |
get_sweep_read_cost(param->table, non_cpk_scan_records, is_interrupted, |
|
2550 |
&sweep_cost); |
|
2551 |
imerge_cost += sweep_cost.total_cost(); |
|
2552 |
}
|
|
2553 |
if (imerge_cost > read_time) |
|
2554 |
goto build_ror_index_merge; |
|
2555 |
||
2556 |
/* Add Unique operations cost */
|
|
2557 |
unique_calc_buff_size= |
|
2558 |
Unique::get_cost_calc_buff_size((ulong)non_cpk_scan_records, |
|
2559 |
param->table->file->ref_length, |
|
2560 |
param->thd->variables.sortbuff_size); |
|
2561 |
if (param->imerge_cost_buff_size < unique_calc_buff_size) |
|
2562 |
{
|
|
2563 |
if (!(param->imerge_cost_buff= (uint*)alloc_root(param->mem_root, |
|
2564 |
unique_calc_buff_size))) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2565 |
return(NULL); |
1
by brian
clean slate |
2566 |
param->imerge_cost_buff_size= unique_calc_buff_size; |
2567 |
}
|
|
2568 |
||
2569 |
imerge_cost += |
|
2570 |
Unique::get_use_cost(param->imerge_cost_buff, (uint)non_cpk_scan_records, |
|
2571 |
param->table->file->ref_length, |
|
2572 |
param->thd->variables.sortbuff_size); |
|
2573 |
if (imerge_cost < read_time) |
|
2574 |
{
|
|
2575 |
if ((imerge_trp= new (param->mem_root)TRP_INDEX_MERGE)) |
|
2576 |
{
|
|
2577 |
imerge_trp->read_cost= imerge_cost; |
|
2578 |
imerge_trp->records= non_cpk_scan_records + cpk_scan_records; |
|
2579 |
imerge_trp->records= min(imerge_trp->records, |
|
2580 |
param->table->file->stats.records); |
|
2581 |
imerge_trp->range_scans= range_scans; |
|
2582 |
imerge_trp->range_scans_end= range_scans + n_child_scans; |
|
2583 |
read_time= imerge_cost; |
|
2584 |
}
|
|
2585 |
}
|
|
2586 |
||
2587 |
build_ror_index_merge: |
|
2588 |
if (!all_scans_ror_able || param->thd->lex->sql_command == SQLCOM_DELETE) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2589 |
return(imerge_trp); |
1
by brian
clean slate |
2590 |
|
2591 |
/* Ok, it is possible to build a ROR-union, try it. */
|
|
2592 |
bool dummy; |
|
2593 |
if (!(roru_read_plans= |
|
2594 |
(TABLE_READ_PLAN**)alloc_root(param->mem_root, |
|
2595 |
sizeof(TABLE_READ_PLAN*)* |
|
2596 |
n_child_scans))) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2597 |
return(imerge_trp); |
1
by brian
clean slate |
2598 |
skip_to_ror_scan: |
2599 |
roru_index_costs= 0.0; |
|
2600 |
roru_total_records= 0; |
|
2601 |
cur_roru_plan= roru_read_plans; |
|
2602 |
||
2603 |
/* Find 'best' ROR scan for each of trees in disjunction */
|
|
2604 |
for (ptree= imerge->trees, cur_child= range_scans; |
|
2605 |
ptree != imerge->trees_next; |
|
2606 |
ptree++, cur_child++, cur_roru_plan++) |
|
2607 |
{
|
|
2608 |
/*
|
|
2609 |
Assume the best ROR scan is the one that has cheapest full-row-retrieval
|
|
2610 |
scan cost.
|
|
2611 |
Also accumulate index_only scan costs as we'll need them to calculate
|
|
2612 |
overall index_intersection cost.
|
|
2613 |
*/
|
|
2614 |
double cost; |
|
2615 |
if ((*cur_child)->is_ror) |
|
2616 |
{
|
|
2617 |
/* Ok, we have index_only cost, now get full rows scan cost */
|
|
2618 |
cost= param->table->file-> |
|
2619 |
read_time(param->real_keynr[(*cur_child)->key_idx], 1, |
|
2620 |
(*cur_child)->records) + |
|
2621 |
rows2double((*cur_child)->records) / TIME_FOR_COMPARE; |
|
2622 |
}
|
|
2623 |
else
|
|
2624 |
cost= read_time; |
|
2625 |
||
2626 |
TABLE_READ_PLAN *prev_plan= *cur_child; |
|
2627 |
if (!(*cur_roru_plan= get_best_ror_intersect(param, *ptree, cost, |
|
2628 |
&dummy))) |
|
2629 |
{
|
|
2630 |
if (prev_plan->is_ror) |
|
2631 |
*cur_roru_plan= prev_plan; |
|
2632 |
else
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2633 |
return(imerge_trp); |
1
by brian
clean slate |
2634 |
roru_index_costs += (*cur_roru_plan)->read_cost; |
2635 |
}
|
|
2636 |
else
|
|
2637 |
roru_index_costs += |
|
2638 |
((TRP_ROR_INTERSECT*)(*cur_roru_plan))->index_scan_costs; |
|
2639 |
roru_total_records += (*cur_roru_plan)->records; |
|
2640 |
roru_intersect_part *= (*cur_roru_plan)->records / |
|
2641 |
param->table->file->stats.records; |
|
2642 |
}
|
|
2643 |
||
2644 |
/*
|
|
2645 |
rows to retrieve=
|
|
2646 |
SUM(rows_in_scan_i) - table_rows * PROD(rows_in_scan_i / table_rows).
|
|
2647 |
This is valid because index_merge construction guarantees that conditions
|
|
2648 |
in disjunction do not share key parts.
|
|
2649 |
*/
|
|
2650 |
roru_total_records -= (ha_rows)(roru_intersect_part* |
|
2651 |
param->table->file->stats.records); |
|
2652 |
/* ok, got a ROR read plan for each of the disjuncts
|
|
2653 |
Calculate cost:
|
|
2654 |
cost(index_union_scan(scan_1, ... scan_n)) =
|
|
2655 |
SUM_i(cost_of_index_only_scan(scan_i)) +
|
|
2656 |
queue_use_cost(rowid_len, n) +
|
|
2657 |
cost_of_row_retrieval
|
|
2658 |
See get_merge_buffers_cost function for queue_use_cost formula derivation.
|
|
2659 |
*/
|
|
2660 |
double roru_total_cost; |
|
2661 |
{
|
|
2662 |
COST_VECT sweep_cost; |
|
2663 |
JOIN *join= param->thd->lex->select_lex.join; |
|
2664 |
bool is_interrupted= test(join && join->tables == 1); |
|
2665 |
get_sweep_read_cost(param->table, roru_total_records, is_interrupted, |
|
2666 |
&sweep_cost); |
|
2667 |
roru_total_cost= roru_index_costs + |
|
2668 |
rows2double(roru_total_records)*log((double)n_child_scans) / |
|
2669 |
(TIME_FOR_COMPARE_ROWID * M_LN2) + |
|
2670 |
sweep_cost.total_cost(); |
|
2671 |
}
|
|
2672 |
||
2673 |
TRP_ROR_UNION* roru; |
|
2674 |
if (roru_total_cost < read_time) |
|
2675 |
{
|
|
2676 |
if ((roru= new (param->mem_root) TRP_ROR_UNION)) |
|
2677 |
{
|
|
2678 |
roru->first_ror= roru_read_plans; |
|
2679 |
roru->last_ror= roru_read_plans + n_child_scans; |
|
2680 |
roru->read_cost= roru_total_cost; |
|
2681 |
roru->records= roru_total_records; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2682 |
return(roru); |
1
by brian
clean slate |
2683 |
}
|
2684 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2685 |
return(imerge_trp); |
1
by brian
clean slate |
2686 |
}
|
2687 |
||
2688 |
||
2689 |
typedef struct st_ror_scan_info |
|
2690 |
{
|
|
2691 |
uint idx; /* # of used key in param->keys */ |
|
2692 |
uint keynr; /* # of used key in table */ |
|
2693 |
ha_rows records; /* estimate of # records this scan will return */ |
|
2694 |
||
2695 |
/* Set of intervals over key fields that will be used for row retrieval. */
|
|
2696 |
SEL_ARG *sel_arg; |
|
2697 |
||
2698 |
/* Fields used in the query and covered by this ROR scan. */
|
|
2699 |
MY_BITMAP covered_fields; |
|
2700 |
uint used_fields_covered; /* # of set bits in covered_fields */ |
|
2701 |
int key_rec_length; /* length of key record (including rowid) */ |
|
2702 |
||
2703 |
/*
|
|
2704 |
Cost of reading all index records with values in sel_arg intervals set
|
|
2705 |
(assuming there is no need to access full table records)
|
|
2706 |
*/
|
|
2707 |
double index_read_cost; |
|
2708 |
uint first_uncovered_field; /* first unused bit in covered_fields */ |
|
2709 |
uint key_components; /* # of parts in the key */ |
|
2710 |
} ROR_SCAN_INFO; |
|
2711 |
||
2712 |
||
2713 |
/*
|
|
2714 |
Create ROR_SCAN_INFO* structure with a single ROR scan on index idx using
|
|
2715 |
sel_arg set of intervals.
|
|
2716 |
||
2717 |
SYNOPSIS
|
|
2718 |
make_ror_scan()
|
|
2719 |
param Parameter from test_quick_select function
|
|
2720 |
idx Index of key in param->keys
|
|
2721 |
sel_arg Set of intervals for a given key
|
|
2722 |
||
2723 |
RETURN
|
|
2724 |
NULL - out of memory
|
|
2725 |
ROR scan structure containing a scan for {idx, sel_arg}
|
|
2726 |
*/
|
|
2727 |
||
2728 |
static
|
|
2729 |
ROR_SCAN_INFO *make_ror_scan(const PARAM *param, int idx, SEL_ARG *sel_arg) |
|
2730 |
{
|
|
2731 |
ROR_SCAN_INFO *ror_scan; |
|
2732 |
my_bitmap_map *bitmap_buf; |
|
2733 |
uint keynr; |
|
2734 |
||
2735 |
if (!(ror_scan= (ROR_SCAN_INFO*)alloc_root(param->mem_root, |
|
2736 |
sizeof(ROR_SCAN_INFO)))) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2737 |
return(NULL); |
1
by brian
clean slate |
2738 |
|
2739 |
ror_scan->idx= idx; |
|
2740 |
ror_scan->keynr= keynr= param->real_keynr[idx]; |
|
2741 |
ror_scan->key_rec_length= (param->table->key_info[keynr].key_length + |
|
2742 |
param->table->file->ref_length); |
|
2743 |
ror_scan->sel_arg= sel_arg; |
|
2744 |
ror_scan->records= param->table->quick_rows[keynr]; |
|
2745 |
||
2746 |
if (!(bitmap_buf= (my_bitmap_map*) alloc_root(param->mem_root, |
|
2747 |
param->fields_bitmap_size))) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2748 |
return(NULL); |
1
by brian
clean slate |
2749 |
|
2750 |
if (bitmap_init(&ror_scan->covered_fields, bitmap_buf, |
|
55
by brian
Update for using real bool types. |
2751 |
param->table->s->fields, false)) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2752 |
return(NULL); |
1
by brian
clean slate |
2753 |
bitmap_clear_all(&ror_scan->covered_fields); |
2754 |
||
2755 |
KEY_PART_INFO *key_part= param->table->key_info[keynr].key_part; |
|
2756 |
KEY_PART_INFO *key_part_end= key_part + |
|
2757 |
param->table->key_info[keynr].key_parts; |
|
2758 |
for (;key_part != key_part_end; ++key_part) |
|
2759 |
{
|
|
2760 |
if (bitmap_is_set(¶m->needed_fields, key_part->fieldnr-1)) |
|
2761 |
bitmap_set_bit(&ror_scan->covered_fields, key_part->fieldnr-1); |
|
2762 |
}
|
|
2763 |
double rows= rows2double(param->table->quick_rows[ror_scan->keynr]); |
|
2764 |
ror_scan->index_read_cost= |
|
2765 |
param->table->file->index_only_read_time(ror_scan->keynr, rows); |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2766 |
return(ror_scan); |
1
by brian
clean slate |
2767 |
}
|
2768 |
||
2769 |
||
2770 |
/*
|
|
2771 |
Compare two ROR_SCAN_INFO** by E(#records_matched) * key_record_length.
|
|
2772 |
SYNOPSIS
|
|
2773 |
cmp_ror_scan_info()
|
|
2774 |
a ptr to first compared value
|
|
2775 |
b ptr to second compared value
|
|
2776 |
||
2777 |
RETURN
|
|
2778 |
-1 a < b
|
|
2779 |
0 a = b
|
|
2780 |
1 a > b
|
|
2781 |
*/
|
|
2782 |
||
2783 |
static int cmp_ror_scan_info(ROR_SCAN_INFO** a, ROR_SCAN_INFO** b) |
|
2784 |
{
|
|
2785 |
double val1= rows2double((*a)->records) * (*a)->key_rec_length; |
|
2786 |
double val2= rows2double((*b)->records) * (*b)->key_rec_length; |
|
2787 |
return (val1 < val2)? -1: (val1 == val2)? 0 : 1; |
|
2788 |
}
|
|
2789 |
||
2790 |
/*
|
|
2791 |
Compare two ROR_SCAN_INFO** by
|
|
2792 |
(#covered fields in F desc,
|
|
2793 |
#components asc,
|
|
2794 |
number of first not covered component asc)
|
|
2795 |
||
2796 |
SYNOPSIS
|
|
2797 |
cmp_ror_scan_info_covering()
|
|
2798 |
a ptr to first compared value
|
|
2799 |
b ptr to second compared value
|
|
2800 |
||
2801 |
RETURN
|
|
2802 |
-1 a < b
|
|
2803 |
0 a = b
|
|
2804 |
1 a > b
|
|
2805 |
*/
|
|
2806 |
||
2807 |
static int cmp_ror_scan_info_covering(ROR_SCAN_INFO** a, ROR_SCAN_INFO** b) |
|
2808 |
{
|
|
2809 |
if ((*a)->used_fields_covered > (*b)->used_fields_covered) |
|
2810 |
return -1; |
|
2811 |
if ((*a)->used_fields_covered < (*b)->used_fields_covered) |
|
2812 |
return 1; |
|
2813 |
if ((*a)->key_components < (*b)->key_components) |
|
2814 |
return -1; |
|
2815 |
if ((*a)->key_components > (*b)->key_components) |
|
2816 |
return 1; |
|
2817 |
if ((*a)->first_uncovered_field < (*b)->first_uncovered_field) |
|
2818 |
return -1; |
|
2819 |
if ((*a)->first_uncovered_field > (*b)->first_uncovered_field) |
|
2820 |
return 1; |
|
2821 |
return 0; |
|
2822 |
}
|
|
2823 |
||
2824 |
||
2825 |
/* Auxiliary structure for incremental ROR-intersection creation */
|
|
2826 |
typedef struct |
|
2827 |
{
|
|
2828 |
const PARAM *param; |
|
2829 |
MY_BITMAP covered_fields; /* union of fields covered by all scans */ |
|
2830 |
/*
|
|
2831 |
Fraction of table records that satisfies conditions of all scans.
|
|
2832 |
This is the number of full records that will be retrieved if a
|
|
2833 |
non-index_only index intersection will be employed.
|
|
2834 |
*/
|
|
2835 |
double out_rows; |
|
55
by brian
Update for using real bool types. |
2836 |
/* true if covered_fields is a superset of needed_fields */
|
1
by brian
clean slate |
2837 |
bool is_covering; |
2838 |
||
2839 |
ha_rows index_records; /* sum(#records to look in indexes) */ |
|
2840 |
double index_scan_costs; /* SUM(cost of 'index-only' scans) */ |
|
2841 |
double total_cost; |
|
2842 |
} ROR_INTERSECT_INFO; |
|
2843 |
||
2844 |
||
2845 |
/*
|
|
2846 |
Allocate a ROR_INTERSECT_INFO and initialize it to contain zero scans.
|
|
2847 |
||
2848 |
SYNOPSIS
|
|
2849 |
ror_intersect_init()
|
|
2850 |
param Parameter from test_quick_select
|
|
2851 |
||
2852 |
RETURN
|
|
2853 |
allocated structure
|
|
2854 |
NULL on error
|
|
2855 |
*/
|
|
2856 |
||
2857 |
static
|
|
2858 |
ROR_INTERSECT_INFO* ror_intersect_init(const PARAM *param) |
|
2859 |
{
|
|
2860 |
ROR_INTERSECT_INFO *info; |
|
2861 |
my_bitmap_map* buf; |
|
2862 |
if (!(info= (ROR_INTERSECT_INFO*)alloc_root(param->mem_root, |
|
2863 |
sizeof(ROR_INTERSECT_INFO)))) |
|
2864 |
return NULL; |
|
2865 |
info->param= param; |
|
2866 |
if (!(buf= (my_bitmap_map*) alloc_root(param->mem_root, |
|
2867 |
param->fields_bitmap_size))) |
|
2868 |
return NULL; |
|
2869 |
if (bitmap_init(&info->covered_fields, buf, param->table->s->fields, |
|
55
by brian
Update for using real bool types. |
2870 |
false)) |
1
by brian
clean slate |
2871 |
return NULL; |
55
by brian
Update for using real bool types. |
2872 |
info->is_covering= false; |
1
by brian
clean slate |
2873 |
info->index_scan_costs= 0.0; |
2874 |
info->index_records= 0; |
|
2875 |
info->out_rows= (double) param->table->file->stats.records; |
|
2876 |
bitmap_clear_all(&info->covered_fields); |
|
2877 |
return info; |
|
2878 |
}
|
|
2879 |
||
2880 |
void ror_intersect_cpy(ROR_INTERSECT_INFO *dst, const ROR_INTERSECT_INFO *src) |
|
2881 |
{
|
|
2882 |
dst->param= src->param; |
|
2883 |
memcpy(dst->covered_fields.bitmap, src->covered_fields.bitmap, |
|
2884 |
no_bytes_in_map(&src->covered_fields)); |
|
2885 |
dst->out_rows= src->out_rows; |
|
2886 |
dst->is_covering= src->is_covering; |
|
2887 |
dst->index_records= src->index_records; |
|
2888 |
dst->index_scan_costs= src->index_scan_costs; |
|
2889 |
dst->total_cost= src->total_cost; |
|
2890 |
}
|
|
2891 |
||
2892 |
||
2893 |
/*
|
|
2894 |
Get selectivity of a ROR scan wrt ROR-intersection.
|
|
2895 |
||
2896 |
SYNOPSIS
|
|
2897 |
ror_scan_selectivity()
|
|
2898 |
info ROR-interection
|
|
2899 |
scan ROR scan
|
|
2900 |
|
|
2901 |
NOTES
|
|
2902 |
Suppose we have a condition on several keys
|
|
2903 |
cond=k_11=c_11 AND k_12=c_12 AND ... // parts of first key
|
|
2904 |
k_21=c_21 AND k_22=c_22 AND ... // parts of second key
|
|
2905 |
...
|
|
2906 |
k_n1=c_n1 AND k_n3=c_n3 AND ... (1) //parts of the key used by *scan
|
|
2907 |
||
2908 |
where k_ij may be the same as any k_pq (i.e. keys may have common parts).
|
|
2909 |
||
2910 |
A full row is retrieved if entire condition holds.
|
|
2911 |
||
2912 |
The recursive procedure for finding P(cond) is as follows:
|
|
2913 |
||
2914 |
First step:
|
|
2915 |
Pick 1st part of 1st key and break conjunction (1) into two parts:
|
|
2916 |
cond= (k_11=c_11 AND R)
|
|
2917 |
||
2918 |
Here R may still contain condition(s) equivalent to k_11=c_11.
|
|
2919 |
Nevertheless, the following holds:
|
|
2920 |
||
2921 |
P(k_11=c_11 AND R) = P(k_11=c_11) * P(R | k_11=c_11).
|
|
2922 |
||
2923 |
Mark k_11 as fixed field (and satisfied condition) F, save P(F),
|
|
2924 |
save R to be cond and proceed to recursion step.
|
|
2925 |
||
2926 |
Recursion step:
|
|
2927 |
We have a set of fixed fields/satisfied conditions) F, probability P(F),
|
|
2928 |
and remaining conjunction R
|
|
2929 |
Pick next key part on current key and its condition "k_ij=c_ij".
|
|
2930 |
We will add "k_ij=c_ij" into F and update P(F).
|
|
2931 |
Lets denote k_ij as t, R = t AND R1, where R1 may still contain t. Then
|
|
2932 |
||
2933 |
P((t AND R1)|F) = P(t|F) * P(R1|t|F) = P(t|F) * P(R1|(t AND F)) (2)
|
|
2934 |
||
2935 |
(where '|' mean conditional probability, not "or")
|
|
2936 |
||
2937 |
Consider the first multiplier in (2). One of the following holds:
|
|
2938 |
a) F contains condition on field used in t (i.e. t AND F = F).
|
|
2939 |
Then P(t|F) = 1
|
|
2940 |
||
2941 |
b) F doesn't contain condition on field used in t. Then F and t are
|
|
2942 |
considered independent.
|
|
2943 |
||
2944 |
P(t|F) = P(t|(fields_before_t_in_key AND other_fields)) =
|
|
2945 |
= P(t|fields_before_t_in_key).
|
|
2946 |
||
2947 |
P(t|fields_before_t_in_key) = #records(fields_before_t_in_key) /
|
|
2948 |
#records(fields_before_t_in_key, t)
|
|
2949 |
||
2950 |
The second multiplier is calculated by applying this step recursively.
|
|
2951 |
||
2952 |
IMPLEMENTATION
|
|
2953 |
This function calculates the result of application of the "recursion step"
|
|
2954 |
described above for all fixed key members of a single key, accumulating set
|
|
2955 |
of covered fields, selectivity, etc.
|
|
2956 |
||
2957 |
The calculation is conducted as follows:
|
|
2958 |
Lets denote #records(keypart1, ... keypartK) as n_k. We need to calculate
|
|
2959 |
||
2960 |
n_{k1} n_{k2}
|
|
2961 |
--------- * --------- * .... (3)
|
|
2962 |
n_{k1-1} n_{k2-1}
|
|
2963 |
||
2964 |
where k1,k2,... are key parts which fields were not yet marked as fixed
|
|
2965 |
( this is result of application of option b) of the recursion step for
|
|
2966 |
parts of a single key).
|
|
2967 |
Since it is reasonable to expect that most of the fields are not marked
|
|
2968 |
as fixed, we calculate (3) as
|
|
2969 |
||
2970 |
n_{i1} n_{i2}
|
|
2971 |
(3) = n_{max_key_part} / ( --------- * --------- * .... )
|
|
2972 |
n_{i1-1} n_{i2-1}
|
|
2973 |
||
2974 |
where i1,i2, .. are key parts that were already marked as fixed.
|
|
2975 |
||
2976 |
In order to minimize number of expensive records_in_range calls we group
|
|
2977 |
and reduce adjacent fractions.
|
|
2978 |
||
2979 |
RETURN
|
|
2980 |
Selectivity of given ROR scan.
|
|
2981 |
*/
|
|
2982 |
||
2983 |
static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info, |
|
2984 |
const ROR_SCAN_INFO *scan) |
|
2985 |
{
|
|
2986 |
double selectivity_mult= 1.0; |
|
2987 |
KEY_PART_INFO *key_part= info->param->table->key_info[scan->keynr].key_part; |
|
2988 |
uchar key_val[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; /* key values tuple */ |
|
2989 |
uchar *key_ptr= key_val; |
|
2990 |
SEL_ARG *sel_arg, *tuple_arg= NULL; |
|
2991 |
key_part_map keypart_map= 0; |
|
2992 |
bool cur_covered; |
|
2993 |
bool prev_covered= test(bitmap_is_set(&info->covered_fields, |
|
2994 |
key_part->fieldnr-1)); |
|
2995 |
key_range min_range; |
|
2996 |
key_range max_range; |
|
2997 |
min_range.key= key_val; |
|
2998 |
min_range.flag= HA_READ_KEY_EXACT; |
|
2999 |
max_range.key= key_val; |
|
3000 |
max_range.flag= HA_READ_AFTER_KEY; |
|
3001 |
ha_rows prev_records= info->param->table->file->stats.records; |
|
3002 |
||
3003 |
for (sel_arg= scan->sel_arg; sel_arg; |
|
3004 |
sel_arg= sel_arg->next_key_part) |
|
3005 |
{
|
|
3006 |
cur_covered= test(bitmap_is_set(&info->covered_fields, |
|
3007 |
key_part[sel_arg->part].fieldnr-1)); |
|
3008 |
if (cur_covered != prev_covered) |
|
3009 |
{
|
|
3010 |
/* create (part1val, ..., part{n-1}val) tuple. */
|
|
3011 |
ha_rows records; |
|
3012 |
if (!tuple_arg) |
|
3013 |
{
|
|
3014 |
tuple_arg= scan->sel_arg; |
|
3015 |
/* Here we use the length of the first key part */
|
|
3016 |
tuple_arg->store_min(key_part->store_length, &key_ptr, 0); |
|
3017 |
keypart_map= 1; |
|
3018 |
}
|
|
3019 |
while (tuple_arg->next_key_part != sel_arg) |
|
3020 |
{
|
|
3021 |
tuple_arg= tuple_arg->next_key_part; |
|
3022 |
tuple_arg->store_min(key_part[tuple_arg->part].store_length, |
|
3023 |
&key_ptr, 0); |
|
3024 |
keypart_map= (keypart_map << 1) | 1; |
|
3025 |
}
|
|
3026 |
min_range.length= max_range.length= (size_t) (key_ptr - key_val); |
|
3027 |
min_range.keypart_map= max_range.keypart_map= keypart_map; |
|
3028 |
records= (info->param->table->file-> |
|
3029 |
records_in_range(scan->keynr, &min_range, &max_range)); |
|
3030 |
if (cur_covered) |
|
3031 |
{
|
|
3032 |
/* uncovered -> covered */
|
|
3033 |
double tmp= rows2double(records)/rows2double(prev_records); |
|
3034 |
selectivity_mult *= tmp; |
|
3035 |
prev_records= HA_POS_ERROR; |
|
3036 |
}
|
|
3037 |
else
|
|
3038 |
{
|
|
3039 |
/* covered -> uncovered */
|
|
3040 |
prev_records= records; |
|
3041 |
}
|
|
3042 |
}
|
|
3043 |
prev_covered= cur_covered; |
|
3044 |
}
|
|
3045 |
if (!prev_covered) |
|
3046 |
{
|
|
3047 |
double tmp= rows2double(info->param->table->quick_rows[scan->keynr]) / |
|
3048 |
rows2double(prev_records); |
|
3049 |
selectivity_mult *= tmp; |
|
3050 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3051 |
return(selectivity_mult); |
1
by brian
clean slate |
3052 |
}
|
3053 |
||
3054 |
||
3055 |
/*
|
|
3056 |
Check if adding a ROR scan to a ROR-intersection reduces its cost of
|
|
3057 |
ROR-intersection and if yes, update parameters of ROR-intersection,
|
|
3058 |
including its cost.
|
|
3059 |
||
3060 |
SYNOPSIS
|
|
3061 |
ror_intersect_add()
|
|
3062 |
param Parameter from test_quick_select
|
|
3063 |
info ROR-intersection structure to add the scan to.
|
|
3064 |
ror_scan ROR scan info to add.
|
|
55
by brian
Update for using real bool types. |
3065 |
is_cpk_scan If true, add the scan as CPK scan (this can be inferred
|
1
by brian
clean slate |
3066 |
from other parameters and is passed separately only to
|
3067 |
avoid duplicating the inference code)
|
|
3068 |
||
3069 |
NOTES
|
|
3070 |
Adding a ROR scan to ROR-intersect "makes sense" iff the cost of ROR-
|
|
3071 |
intersection decreases. The cost of ROR-intersection is calculated as
|
|
3072 |
follows:
|
|
3073 |
||
3074 |
cost= SUM_i(key_scan_cost_i) + cost_of_full_rows_retrieval
|
|
3075 |
||
3076 |
When we add a scan the first increases and the second decreases.
|
|
3077 |
||
3078 |
cost_of_full_rows_retrieval=
|
|
3079 |
(union of indexes used covers all needed fields) ?
|
|
3080 |
cost_of_sweep_read(E(rows_to_retrieve), rows_in_table) :
|
|
3081 |
0
|
|
3082 |
||
3083 |
E(rows_to_retrieve) = #rows_in_table * ror_scan_selectivity(null, scan1) *
|
|
3084 |
ror_scan_selectivity({scan1}, scan2) * ... *
|
|
3085 |
ror_scan_selectivity({scan1,...}, scanN).
|
|
3086 |
RETURN
|
|
55
by brian
Update for using real bool types. |
3087 |
true ROR scan added to ROR-intersection, cost updated.
|
3088 |
false It doesn't make sense to add this ROR scan to this ROR-intersection.
|
|
1
by brian
clean slate |
3089 |
*/
|
3090 |
||
3091 |
static bool ror_intersect_add(ROR_INTERSECT_INFO *info, |
|
3092 |
ROR_SCAN_INFO* ror_scan, bool is_cpk_scan) |
|
3093 |
{
|
|
3094 |
double selectivity_mult= 1.0; |
|
3095 |
||
3096 |
selectivity_mult = ror_scan_selectivity(info, ror_scan); |
|
3097 |
if (selectivity_mult == 1.0) |
|
3098 |
{
|
|
3099 |
/* Don't add this scan if it doesn't improve selectivity. */
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3100 |
return(false); |
1
by brian
clean slate |
3101 |
}
|
3102 |
||
3103 |
info->out_rows *= selectivity_mult; |
|
3104 |
||
3105 |
if (is_cpk_scan) |
|
3106 |
{
|
|
3107 |
/*
|
|
3108 |
CPK scan is used to filter out rows. We apply filtering for
|
|
3109 |
each record of every scan. Assuming 1/TIME_FOR_COMPARE_ROWID
|
|
3110 |
per check this gives us:
|
|
3111 |
*/
|
|
3112 |
info->index_scan_costs += rows2double(info->index_records) / |
|
3113 |
TIME_FOR_COMPARE_ROWID; |
|
3114 |
}
|
|
3115 |
else
|
|
3116 |
{
|
|
3117 |
info->index_records += info->param->table->quick_rows[ror_scan->keynr]; |
|
3118 |
info->index_scan_costs += ror_scan->index_read_cost; |
|
3119 |
bitmap_union(&info->covered_fields, &ror_scan->covered_fields); |
|
3120 |
if (!info->is_covering && bitmap_is_subset(&info->param->needed_fields, |
|
3121 |
&info->covered_fields)) |
|
3122 |
{
|
|
55
by brian
Update for using real bool types. |
3123 |
info->is_covering= true; |
1
by brian
clean slate |
3124 |
}
|
3125 |
}
|
|
3126 |
||
3127 |
info->total_cost= info->index_scan_costs; |
|
3128 |
if (!info->is_covering) |
|
3129 |
{
|
|
3130 |
COST_VECT sweep_cost; |
|
3131 |
JOIN *join= info->param->thd->lex->select_lex.join; |
|
3132 |
bool is_interrupted= test(join && join->tables == 1); |
|
3133 |
get_sweep_read_cost(info->param->table, double2rows(info->out_rows), |
|
3134 |
is_interrupted, &sweep_cost); |
|
3135 |
info->total_cost += sweep_cost.total_cost(); |
|
3136 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3137 |
return(true); |
1
by brian
clean slate |
3138 |
}
|
3139 |
||
3140 |
||
3141 |
/*
|
|
3142 |
Get best ROR-intersection plan using non-covering ROR-intersection search
|
|
3143 |
algorithm. The returned plan may be covering.
|
|
3144 |
||
3145 |
SYNOPSIS
|
|
3146 |
get_best_ror_intersect()
|
|
3147 |
param Parameter from test_quick_select function.
|
|
3148 |
tree Transformed restriction condition to be used to look
|
|
3149 |
for ROR scans.
|
|
3150 |
read_time Do not return read plans with cost > read_time.
|
|
55
by brian
Update for using real bool types. |
3151 |
are_all_covering [out] set to true if union of all scans covers all
|
1
by brian
clean slate |
3152 |
fields needed by the query (and it is possible to build
|
3153 |
a covering ROR-intersection)
|
|
3154 |
||
3155 |
NOTES
|
|
3156 |
get_key_scans_params must be called before this function can be called.
|
|
3157 |
|
|
3158 |
When this function is called by ROR-union construction algorithm it
|
|
3159 |
assumes it is building an uncovered ROR-intersection (and thus # of full
|
|
3160 |
records to be retrieved is wrong here). This is a hack.
|
|
3161 |
||
3162 |
IMPLEMENTATION
|
|
3163 |
The approximate best non-covering plan search algorithm is as follows:
|
|
3164 |
||
3165 |
find_min_ror_intersection_scan()
|
|
3166 |
{
|
|
3167 |
R= select all ROR scans;
|
|
3168 |
order R by (E(#records_matched) * key_record_length).
|
|
3169 |
||
3170 |
S= first(R); -- set of scans that will be used for ROR-intersection
|
|
3171 |
R= R-first(S);
|
|
3172 |
min_cost= cost(S);
|
|
3173 |
min_scan= make_scan(S);
|
|
3174 |
while (R is not empty)
|
|
3175 |
{
|
|
3176 |
firstR= R - first(R);
|
|
3177 |
if (!selectivity(S + firstR < selectivity(S)))
|
|
3178 |
continue;
|
|
3179 |
|
|
3180 |
S= S + first(R);
|
|
3181 |
if (cost(S) < min_cost)
|
|
3182 |
{
|
|
3183 |
min_cost= cost(S);
|
|
3184 |
min_scan= make_scan(S);
|
|
3185 |
}
|
|
3186 |
}
|
|
3187 |
return min_scan;
|
|
3188 |
}
|
|
3189 |
||
3190 |
See ror_intersect_add function for ROR intersection costs.
|
|
3191 |
||
3192 |
Special handling for Clustered PK scans
|
|
3193 |
Clustered PK contains all table fields, so using it as a regular scan in
|
|
3194 |
index intersection doesn't make sense: a range scan on CPK will be less
|
|
3195 |
expensive in this case.
|
|
3196 |
Clustered PK scan has special handling in ROR-intersection: it is not used
|
|
3197 |
to retrieve rows, instead its condition is used to filter row references
|
|
3198 |
we get from scans on other keys.
|
|
3199 |
||
3200 |
RETURN
|
|
3201 |
ROR-intersection table read plan
|
|
3202 |
NULL if out of memory or no suitable plan found.
|
|
3203 |
*/
|
|
3204 |
||
3205 |
static
|
|
3206 |
TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree, |
|
3207 |
double read_time, |
|
3208 |
bool *are_all_covering) |
|
3209 |
{
|
|
3210 |
uint idx; |
|
3211 |
double min_cost= DBL_MAX; |
|
3212 |
||
3213 |
if ((tree->n_ror_scans < 2) || !param->table->file->stats.records) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3214 |
return(NULL); |
1
by brian
clean slate |
3215 |
|
3216 |
/*
|
|
3217 |
Step1: Collect ROR-able SEL_ARGs and create ROR_SCAN_INFO for each of
|
|
3218 |
them. Also find and save clustered PK scan if there is one.
|
|
3219 |
*/
|
|
3220 |
ROR_SCAN_INFO **cur_ror_scan; |
|
3221 |
ROR_SCAN_INFO *cpk_scan= NULL; |
|
3222 |
uint cpk_no; |
|
55
by brian
Update for using real bool types. |
3223 |
bool cpk_scan_used= false; |
1
by brian
clean slate |
3224 |
|
3225 |
if (!(tree->ror_scans= (ROR_SCAN_INFO**)alloc_root(param->mem_root, |
|
3226 |
sizeof(ROR_SCAN_INFO*)* |
|
3227 |
param->keys))) |
|
3228 |
return NULL; |
|
3229 |
cpk_no= ((param->table->file->primary_key_is_clustered()) ? |
|
3230 |
param->table->s->primary_key : MAX_KEY); |
|
3231 |
||
3232 |
for (idx= 0, cur_ror_scan= tree->ror_scans; idx < param->keys; idx++) |
|
3233 |
{
|
|
3234 |
ROR_SCAN_INFO *scan; |
|
3235 |
if (!tree->ror_scans_map.is_set(idx)) |
|
3236 |
continue; |
|
3237 |
if (!(scan= make_ror_scan(param, idx, tree->keys[idx]))) |
|
3238 |
return NULL; |
|
3239 |
if (param->real_keynr[idx] == cpk_no) |
|
3240 |
{
|
|
3241 |
cpk_scan= scan; |
|
3242 |
tree->n_ror_scans--; |
|
3243 |
}
|
|
3244 |
else
|
|
3245 |
*(cur_ror_scan++)= scan; |
|
3246 |
}
|
|
3247 |
||
3248 |
tree->ror_scans_end= cur_ror_scan; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3249 |
print_ror_scans_arr(param->table, "original", |
1
by brian
clean slate |
3250 |
tree->ror_scans, |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3251 |
tree->ror_scans_end); |
1
by brian
clean slate |
3252 |
/*
|
3253 |
Ok, [ror_scans, ror_scans_end) is array of ptrs to initialized
|
|
3254 |
ROR_SCAN_INFO's.
|
|
3255 |
Step 2: Get best ROR-intersection using an approximate algorithm.
|
|
3256 |
*/
|
|
3257 |
my_qsort(tree->ror_scans, tree->n_ror_scans, sizeof(ROR_SCAN_INFO*), |
|
3258 |
(qsort_cmp)cmp_ror_scan_info); |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3259 |
print_ror_scans_arr(param->table, "ordered", |
1
by brian
clean slate |
3260 |
tree->ror_scans, |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3261 |
tree->ror_scans_end); |
1
by brian
clean slate |
3262 |
|
3263 |
ROR_SCAN_INFO **intersect_scans; /* ROR scans used in index intersection */ |
|
3264 |
ROR_SCAN_INFO **intersect_scans_end; |
|
3265 |
if (!(intersect_scans= (ROR_SCAN_INFO**)alloc_root(param->mem_root, |
|
3266 |
sizeof(ROR_SCAN_INFO*)* |
|
3267 |
tree->n_ror_scans))) |
|
3268 |
return NULL; |
|
3269 |
intersect_scans_end= intersect_scans; |
|
3270 |
||
3271 |
/* Create and incrementally update ROR intersection. */
|
|
3272 |
ROR_INTERSECT_INFO *intersect, *intersect_best; |
|
3273 |
if (!(intersect= ror_intersect_init(param)) || |
|
3274 |
!(intersect_best= ror_intersect_init(param))) |
|
3275 |
return NULL; |
|
3276 |
||
3277 |
/* [intersect_scans,intersect_scans_best) will hold the best intersection */
|
|
3278 |
ROR_SCAN_INFO **intersect_scans_best; |
|
3279 |
cur_ror_scan= tree->ror_scans; |
|
3280 |
intersect_scans_best= intersect_scans; |
|
3281 |
while (cur_ror_scan != tree->ror_scans_end && !intersect->is_covering) |
|
3282 |
{
|
|
3283 |
/* S= S + first(R); R= R - first(R); */
|
|
55
by brian
Update for using real bool types. |
3284 |
if (!ror_intersect_add(intersect, *cur_ror_scan, false)) |
1
by brian
clean slate |
3285 |
{
|
3286 |
cur_ror_scan++; |
|
3287 |
continue; |
|
3288 |
}
|
|
3289 |
||
3290 |
*(intersect_scans_end++)= *(cur_ror_scan++); |
|
3291 |
||
3292 |
if (intersect->total_cost < min_cost) |
|
3293 |
{
|
|
3294 |
/* Local minimum found, save it */
|
|
3295 |
ror_intersect_cpy(intersect_best, intersect); |
|
3296 |
intersect_scans_best= intersect_scans_end; |
|
3297 |
min_cost = intersect->total_cost; |
|
3298 |
}
|
|
3299 |
}
|
|
3300 |
||
3301 |
if (intersect_scans_best == intersect_scans) |
|
3302 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3303 |
return(NULL); |
1
by brian
clean slate |
3304 |
}
|
3305 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3306 |
print_ror_scans_arr(param->table, |
1
by brian
clean slate |
3307 |
"best ROR-intersection", |
3308 |
intersect_scans, |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3309 |
intersect_scans_best); |
1
by brian
clean slate |
3310 |
|
3311 |
*are_all_covering= intersect->is_covering; |
|
3312 |
uint best_num= intersect_scans_best - intersect_scans; |
|
3313 |
ror_intersect_cpy(intersect, intersect_best); |
|
3314 |
||
3315 |
/*
|
|
3316 |
Ok, found the best ROR-intersection of non-CPK key scans.
|
|
3317 |
Check if we should add a CPK scan. If the obtained ROR-intersection is
|
|
3318 |
covering, it doesn't make sense to add CPK scan.
|
|
3319 |
*/
|
|
3320 |
if (cpk_scan && !intersect->is_covering) |
|
3321 |
{
|
|
55
by brian
Update for using real bool types. |
3322 |
if (ror_intersect_add(intersect, cpk_scan, true) && |
1
by brian
clean slate |
3323 |
(intersect->total_cost < min_cost)) |
3324 |
{
|
|
55
by brian
Update for using real bool types. |
3325 |
cpk_scan_used= true; |
1
by brian
clean slate |
3326 |
intersect_best= intersect; //just set pointer here |
3327 |
}
|
|
3328 |
}
|
|
3329 |
||
3330 |
/* Ok, return ROR-intersect plan if we have found one */
|
|
3331 |
TRP_ROR_INTERSECT *trp= NULL; |
|
3332 |
if (min_cost < read_time && (cpk_scan_used || best_num > 1)) |
|
3333 |
{
|
|
3334 |
if (!(trp= new (param->mem_root) TRP_ROR_INTERSECT)) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3335 |
return(trp); |
1
by brian
clean slate |
3336 |
if (!(trp->first_scan= |
3337 |
(ROR_SCAN_INFO**)alloc_root(param->mem_root, |
|
3338 |
sizeof(ROR_SCAN_INFO*)*best_num))) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3339 |
return(NULL); |
1
by brian
clean slate |
3340 |
memcpy(trp->first_scan, intersect_scans, best_num*sizeof(ROR_SCAN_INFO*)); |
3341 |
trp->last_scan= trp->first_scan + best_num; |
|
3342 |
trp->is_covering= intersect_best->is_covering; |
|
3343 |
trp->read_cost= intersect_best->total_cost; |
|
3344 |
/* Prevent divisons by zero */
|
|
3345 |
ha_rows best_rows = double2rows(intersect_best->out_rows); |
|
3346 |
if (!best_rows) |
|
3347 |
best_rows= 1; |
|
3348 |
set_if_smaller(param->table->quick_condition_rows, best_rows); |
|
3349 |
trp->records= best_rows; |
|
3350 |
trp->index_scan_costs= intersect_best->index_scan_costs; |
|
3351 |
trp->cpk_scan= cpk_scan_used? cpk_scan: NULL; |
|
3352 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3353 |
return(trp); |
1
by brian
clean slate |
3354 |
}
|
3355 |
||
3356 |
||
3357 |
/*
|
|
3358 |
Get best covering ROR-intersection.
|
|
3359 |
SYNOPSIS
|
|
3360 |
get_best_covering_ror_intersect()
|
|
3361 |
param Parameter from test_quick_select function.
|
|
3362 |
tree SEL_TREE with sets of intervals for different keys.
|
|
3363 |
read_time Don't return table read plans with cost > read_time.
|
|
3364 |
||
3365 |
RETURN
|
|
3366 |
Best covering ROR-intersection plan
|
|
3367 |
NULL if no plan found.
|
|
3368 |
||
3369 |
NOTES
|
|
3370 |
get_best_ror_intersect must be called for a tree before calling this
|
|
3371 |
function for it.
|
|
3372 |
This function invalidates tree->ror_scans member values.
|
|
3373 |
||
3374 |
The following approximate algorithm is used:
|
|
3375 |
I=set of all covering indexes
|
|
3376 |
F=set of all fields to cover
|
|
3377 |
S={}
|
|
3378 |
||
3379 |
do
|
|
3380 |
{
|
|
3381 |
Order I by (#covered fields in F desc,
|
|
3382 |
#components asc,
|
|
3383 |
number of first not covered component asc);
|
|
3384 |
F=F-covered by first(I);
|
|
3385 |
S=S+first(I);
|
|
3386 |
I=I-first(I);
|
|
3387 |
} while F is not empty.
|
|
3388 |
*/
|
|
3389 |
||
3390 |
static
|
|
3391 |
TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param, |
|
3392 |
SEL_TREE *tree, |
|
3393 |
double read_time) |
|
3394 |
{
|
|
3395 |
ROR_SCAN_INFO **ror_scan_mark; |
|
3396 |
ROR_SCAN_INFO **ror_scans_end= tree->ror_scans_end; |
|
3397 |
||
3398 |
for (ROR_SCAN_INFO **scan= tree->ror_scans; scan != ror_scans_end; ++scan) |
|
3399 |
(*scan)->key_components= |
|
3400 |
param->table->key_info[(*scan)->keynr].key_parts; |
|
3401 |
||
3402 |
/*
|
|
3403 |
Run covering-ROR-search algorithm.
|
|
3404 |
Assume set I is [ror_scan .. ror_scans_end)
|
|
3405 |
*/
|
|
3406 |
||
3407 |
/*I=set of all covering indexes */
|
|
3408 |
ror_scan_mark= tree->ror_scans; |
|
3409 |
||
3410 |
MY_BITMAP *covered_fields= ¶m->tmp_covered_fields; |
|
3411 |
if (!covered_fields->bitmap) |
|
3412 |
covered_fields->bitmap= (my_bitmap_map*)alloc_root(param->mem_root, |
|
3413 |
param->fields_bitmap_size); |
|
3414 |
if (!covered_fields->bitmap || |
|
3415 |
bitmap_init(covered_fields, covered_fields->bitmap, |
|
55
by brian
Update for using real bool types. |
3416 |
param->table->s->fields, false)) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3417 |
return(0); |
1
by brian
clean slate |
3418 |
bitmap_clear_all(covered_fields); |
3419 |
||
3420 |
double total_cost= 0.0f; |
|
3421 |
ha_rows records=0; |
|
3422 |
bool all_covered; |
|
3423 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3424 |
print_ror_scans_arr(param->table, |
1
by brian
clean slate |
3425 |
"building covering ROR-I", |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3426 |
ror_scan_mark, ror_scans_end); |
1
by brian
clean slate |
3427 |
do
|
3428 |
{
|
|
3429 |
/*
|
|
3430 |
Update changed sorting info:
|
|
3431 |
#covered fields,
|
|
3432 |
number of first not covered component
|
|
3433 |
Calculate and save these values for each of remaining scans.
|
|
3434 |
*/
|
|
3435 |
for (ROR_SCAN_INFO **scan= ror_scan_mark; scan != ror_scans_end; ++scan) |
|
3436 |
{
|
|
3437 |
bitmap_subtract(&(*scan)->covered_fields, covered_fields); |
|
3438 |
(*scan)->used_fields_covered= |
|
3439 |
bitmap_bits_set(&(*scan)->covered_fields); |
|
3440 |
(*scan)->first_uncovered_field= |
|
3441 |
bitmap_get_first(&(*scan)->covered_fields); |
|
3442 |
}
|
|
3443 |
||
3444 |
my_qsort(ror_scan_mark, ror_scans_end-ror_scan_mark, sizeof(ROR_SCAN_INFO*), |
|
3445 |
(qsort_cmp)cmp_ror_scan_info_covering); |
|
3446 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3447 |
print_ror_scans_arr(param->table, |
1
by brian
clean slate |
3448 |
"remaining scans", |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3449 |
ror_scan_mark, ror_scans_end); |
1
by brian
clean slate |
3450 |
|
3451 |
/* I=I-first(I) */
|
|
3452 |
total_cost += (*ror_scan_mark)->index_read_cost; |
|
3453 |
records += (*ror_scan_mark)->records; |
|
3454 |
if (total_cost > read_time) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3455 |
return(NULL); |
1
by brian
clean slate |
3456 |
/* F=F-covered by first(I) */
|
3457 |
bitmap_union(covered_fields, &(*ror_scan_mark)->covered_fields); |
|
3458 |
all_covered= bitmap_is_subset(¶m->needed_fields, covered_fields); |
|
3459 |
} while ((++ror_scan_mark < ror_scans_end) && !all_covered); |
|
3460 |
||
3461 |
if (!all_covered || (ror_scan_mark - tree->ror_scans) == 1) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3462 |
return(NULL); |
1
by brian
clean slate |
3463 |
|
3464 |
/*
|
|
3465 |
Ok, [tree->ror_scans .. ror_scan) holds covering index_intersection with
|
|
3466 |
cost total_cost.
|
|
3467 |
*/
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3468 |
print_ror_scans_arr(param->table, |
1
by brian
clean slate |
3469 |
"creating covering ROR-intersect", |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3470 |
tree->ror_scans, ror_scan_mark); |
1
by brian
clean slate |
3471 |
|
3472 |
/* Add priority queue use cost. */
|
|
3473 |
total_cost += rows2double(records)* |
|
3474 |
log((double)(ror_scan_mark - tree->ror_scans)) / |
|
3475 |
(TIME_FOR_COMPARE_ROWID * M_LN2); |
|
3476 |
||
3477 |
if (total_cost > read_time) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3478 |
return(NULL); |
1
by brian
clean slate |
3479 |
|
3480 |
TRP_ROR_INTERSECT *trp; |
|
3481 |
if (!(trp= new (param->mem_root) TRP_ROR_INTERSECT)) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3482 |
return(trp); |
1
by brian
clean slate |
3483 |
uint best_num= (ror_scan_mark - tree->ror_scans); |
3484 |
if (!(trp->first_scan= (ROR_SCAN_INFO**)alloc_root(param->mem_root, |
|
3485 |
sizeof(ROR_SCAN_INFO*)* |
|
3486 |
best_num))) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3487 |
return(NULL); |
1
by brian
clean slate |
3488 |
memcpy(trp->first_scan, tree->ror_scans, best_num*sizeof(ROR_SCAN_INFO*)); |
3489 |
trp->last_scan= trp->first_scan + best_num; |
|
55
by brian
Update for using real bool types. |
3490 |
trp->is_covering= true; |
1
by brian
clean slate |
3491 |
trp->read_cost= total_cost; |
3492 |
trp->records= records; |
|
3493 |
trp->cpk_scan= NULL; |
|
3494 |
set_if_smaller(param->table->quick_condition_rows, records); |
|
3495 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3496 |
return(trp); |
1
by brian
clean slate |
3497 |
}
|
3498 |
||
3499 |
||
3500 |
/*
|
|
3501 |
Get best "range" table read plan for given SEL_TREE, also update some info
|
|
3502 |
||
3503 |
SYNOPSIS
|
|
3504 |
get_key_scans_params()
|
|
3505 |
param Parameters from test_quick_select
|
|
3506 |
tree Make range select for this SEL_TREE
|
|
55
by brian
Update for using real bool types. |
3507 |
index_read_must_be_used true <=> assume 'index only' option will be set
|
1
by brian
clean slate |
3508 |
(except for clustered PK indexes)
|
55
by brian
Update for using real bool types. |
3509 |
update_tbl_stats true <=> update table->quick_* with information
|
1
by brian
clean slate |
3510 |
about range scans we've evaluated.
|
3511 |
read_time Maximum cost. i.e. don't create read plans with
|
|
3512 |
cost > read_time.
|
|
3513 |
||
3514 |
DESCRIPTION
|
|
3515 |
Find the best "range" table read plan for given SEL_TREE.
|
|
3516 |
The side effects are
|
|
3517 |
- tree->ror_scans is updated to indicate which scans are ROR scans.
|
|
55
by brian
Update for using real bool types. |
3518 |
- if update_tbl_stats=true then table->quick_* is updated with info
|
1
by brian
clean slate |
3519 |
about every possible range scan.
|
3520 |
||
3521 |
RETURN
|
|
3522 |
Best range read plan
|
|
3523 |
NULL if no plan found or error occurred
|
|
3524 |
*/
|
|
3525 |
||
3526 |
static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, |
|
3527 |
bool index_read_must_be_used, |
|
3528 |
bool update_tbl_stats, |
|
3529 |
double read_time) |
|
3530 |
{
|
|
3531 |
uint idx; |
|
3532 |
SEL_ARG **key,**end, **key_to_read= NULL; |
|
3533 |
ha_rows best_records= 0; |
|
3534 |
uint best_mrr_flags= 0, best_buf_size= 0; |
|
3535 |
TRP_RANGE* read_plan= NULL; |
|
3536 |
/*
|
|
3537 |
Note that there may be trees that have type SEL_TREE::KEY but contain no
|
|
3538 |
key reads at all, e.g. tree for expression "key1 is not null" where key1
|
|
3539 |
is defined as "not null".
|
|
3540 |
*/
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3541 |
print_sel_tree(param, tree, &tree->keys_map, "tree scans"); |
1
by brian
clean slate |
3542 |
tree->ror_scans_map.clear_all(); |
3543 |
tree->n_ror_scans= 0; |
|
3544 |
for (idx= 0,key=tree->keys, end=key+param->keys; key != end; key++,idx++) |
|
3545 |
{
|
|
3546 |
if (*key) |
|
3547 |
{
|
|
3548 |
ha_rows found_records; |
|
3549 |
COST_VECT cost; |
|
3550 |
double found_read_time; |
|
3551 |
uint mrr_flags, buf_size; |
|
3552 |
uint keynr= param->real_keynr[idx]; |
|
3553 |
if ((*key)->type == SEL_ARG::MAYBE_KEY || |
|
3554 |
(*key)->maybe_flag) |
|
3555 |
param->needed_reg->set_bit(keynr); |
|
3556 |
||
3557 |
bool read_index_only= index_read_must_be_used || |
|
3558 |
param->table->covering_keys.is_set(keynr); |
|
3559 |
||
3560 |
found_records= check_quick_select(param, idx, read_index_only, *key, |
|
3561 |
update_tbl_stats, &mrr_flags, |
|
3562 |
&buf_size, &cost); |
|
3563 |
found_read_time= cost.total_cost(); |
|
3564 |
if ((found_records != HA_POS_ERROR) && param->is_ror_scan) |
|
3565 |
{
|
|
3566 |
tree->n_ror_scans++; |
|
3567 |
tree->ror_scans_map.set_bit(idx); |
|
3568 |
}
|
|
3569 |
if (read_time > found_read_time && found_records != HA_POS_ERROR) |
|
3570 |
{
|
|
3571 |
read_time= found_read_time; |
|
3572 |
best_records= found_records; |
|
3573 |
key_to_read= key; |
|
3574 |
best_mrr_flags= mrr_flags; |
|
3575 |
best_buf_size= buf_size; |
|
3576 |
}
|
|
3577 |
}
|
|
3578 |
}
|
|
3579 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3580 |
print_sel_tree(param, tree, &tree->ror_scans_map, "ROR scans"); |
1
by brian
clean slate |
3581 |
if (key_to_read) |
3582 |
{
|
|
3583 |
idx= key_to_read - tree->keys; |
|
3584 |
if ((read_plan= new (param->mem_root) TRP_RANGE(*key_to_read, idx, |
|
3585 |
best_mrr_flags))) |
|
3586 |
{
|
|
3587 |
read_plan->records= best_records; |
|
3588 |
read_plan->is_ror= tree->ror_scans_map.is_set(idx); |
|
3589 |
read_plan->read_cost= read_time; |
|
3590 |
read_plan->mrr_buf_size= best_buf_size; |
|
3591 |
}
|
|
3592 |
}
|
|
3593 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3594 |
return(read_plan); |
1
by brian
clean slate |
3595 |
}
|
3596 |
||
3597 |
||
3598 |
QUICK_SELECT_I *TRP_INDEX_MERGE::make_quick(PARAM *param, |
|
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
3599 |
bool retrieve_full_rows __attribute__((unused)), |
3600 |
MEM_ROOT *parent_alloc __attribute__((unused))) |
|
1
by brian
clean slate |
3601 |
{
|
3602 |
QUICK_INDEX_MERGE_SELECT *quick_imerge; |
|
3603 |
QUICK_RANGE_SELECT *quick; |
|
3604 |
/* index_merge always retrieves full rows, ignore retrieve_full_rows */
|
|
3605 |
if (!(quick_imerge= new QUICK_INDEX_MERGE_SELECT(param->thd, param->table))) |
|
3606 |
return NULL; |
|
3607 |
||
3608 |
quick_imerge->records= records; |
|
3609 |
quick_imerge->read_time= read_cost; |
|
3610 |
for (TRP_RANGE **range_scan= range_scans; range_scan != range_scans_end; |
|
3611 |
range_scan++) |
|
3612 |
{
|
|
3613 |
if (!(quick= (QUICK_RANGE_SELECT*) |
|
55
by brian
Update for using real bool types. |
3614 |
((*range_scan)->make_quick(param, false, &quick_imerge->alloc)))|| |
1
by brian
clean slate |
3615 |
quick_imerge->push_quick_back(quick)) |
3616 |
{
|
|
3617 |
delete quick; |
|
3618 |
delete quick_imerge; |
|
3619 |
return NULL; |
|
3620 |
}
|
|
3621 |
}
|
|
3622 |
return quick_imerge; |
|
3623 |
}
|
|
3624 |
||
3625 |
QUICK_SELECT_I *TRP_ROR_INTERSECT::make_quick(PARAM *param, |
|
3626 |
bool retrieve_full_rows, |
|
3627 |
MEM_ROOT *parent_alloc) |
|
3628 |
{
|
|
3629 |
QUICK_ROR_INTERSECT_SELECT *quick_intrsect; |
|
3630 |
QUICK_RANGE_SELECT *quick; |
|
3631 |
MEM_ROOT *alloc; |
|
3632 |
||
3633 |
if ((quick_intrsect= |
|
3634 |
new QUICK_ROR_INTERSECT_SELECT(param->thd, param->table, |
|
3635 |
(retrieve_full_rows? (!is_covering) : |
|
55
by brian
Update for using real bool types. |
3636 |
false), |
1
by brian
clean slate |
3637 |
parent_alloc))) |
3638 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3639 |
print_ror_scans_arr(param->table, |
1
by brian
clean slate |
3640 |
"creating ROR-intersect", |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3641 |
first_scan, last_scan); |
1
by brian
clean slate |
3642 |
alloc= parent_alloc? parent_alloc: &quick_intrsect->alloc; |
3643 |
for (; first_scan != last_scan;++first_scan) |
|
3644 |
{
|
|
3645 |
if (!(quick= get_quick_select(param, (*first_scan)->idx, |
|
3646 |
(*first_scan)->sel_arg, |
|
3647 |
HA_MRR_USE_DEFAULT_IMPL | HA_MRR_SORTED, |
|
3648 |
0, alloc)) || |
|
3649 |
quick_intrsect->push_quick_back(quick)) |
|
3650 |
{
|
|
3651 |
delete quick_intrsect; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3652 |
return(NULL); |
1
by brian
clean slate |
3653 |
}
|
3654 |
}
|
|
3655 |
if (cpk_scan) |
|
3656 |
{
|
|
3657 |
if (!(quick= get_quick_select(param, cpk_scan->idx, |
|
3658 |
cpk_scan->sel_arg, |
|
3659 |
HA_MRR_USE_DEFAULT_IMPL | HA_MRR_SORTED, |
|
3660 |
0, alloc))) |
|
3661 |
{
|
|
3662 |
delete quick_intrsect; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3663 |
return(NULL); |
1
by brian
clean slate |
3664 |
}
|
3665 |
quick->file= NULL; |
|
3666 |
quick_intrsect->cpk_quick= quick; |
|
3667 |
}
|
|
3668 |
quick_intrsect->records= records; |
|
3669 |
quick_intrsect->read_time= read_cost; |
|
3670 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3671 |
return(quick_intrsect); |
1
by brian
clean slate |
3672 |
}
|
3673 |
||
3674 |
||
3675 |
QUICK_SELECT_I *TRP_ROR_UNION::make_quick(PARAM *param, |
|
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
3676 |
bool retrieve_full_rows __attribute__((unused)), |
3677 |
MEM_ROOT *parent_alloc __attribute__((unused))) |
|
1
by brian
clean slate |
3678 |
{
|
3679 |
QUICK_ROR_UNION_SELECT *quick_roru; |
|
3680 |
TABLE_READ_PLAN **scan; |
|
3681 |
QUICK_SELECT_I *quick; |
|
3682 |
/*
|
|
3683 |
It is impossible to construct a ROR-union that will not retrieve full
|
|
3684 |
rows, ignore retrieve_full_rows parameter.
|
|
3685 |
*/
|
|
3686 |
if ((quick_roru= new QUICK_ROR_UNION_SELECT(param->thd, param->table))) |
|
3687 |
{
|
|
3688 |
for (scan= first_ror; scan != last_ror; scan++) |
|
3689 |
{
|
|
55
by brian
Update for using real bool types. |
3690 |
if (!(quick= (*scan)->make_quick(param, false, &quick_roru->alloc)) || |
1
by brian
clean slate |
3691 |
quick_roru->push_quick_back(quick)) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3692 |
return(NULL); |
1
by brian
clean slate |
3693 |
}
|
3694 |
quick_roru->records= records; |
|
3695 |
quick_roru->read_time= read_cost; |
|
3696 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3697 |
return(quick_roru); |
1
by brian
clean slate |
3698 |
}
|
3699 |
||
3700 |
||
3701 |
/*
|
|
3702 |
Build a SEL_TREE for <> or NOT BETWEEN predicate
|
|
3703 |
|
|
3704 |
SYNOPSIS
|
|
3705 |
get_ne_mm_tree()
|
|
3706 |
param PARAM from SQL_SELECT::test_quick_select
|
|
3707 |
cond_func item for the predicate
|
|
3708 |
field field in the predicate
|
|
3709 |
lt_value constant that field should be smaller
|
|
3710 |
gt_value constant that field should be greaterr
|
|
3711 |
cmp_type compare type for the field
|
|
3712 |
||
3713 |
RETURN
|
|
3714 |
# Pointer to tree built tree
|
|
3715 |
0 on error
|
|
3716 |
*/
|
|
3717 |
||
3718 |
static SEL_TREE *get_ne_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func, |
|
3719 |
Field *field, |
|
3720 |
Item *lt_value, Item *gt_value, |
|
3721 |
Item_result cmp_type) |
|
3722 |
{
|
|
3723 |
SEL_TREE *tree; |
|
3724 |
tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC, |
|
3725 |
lt_value, cmp_type); |
|
3726 |
if (tree) |
|
3727 |
{
|
|
3728 |
tree= tree_or(param, tree, get_mm_parts(param, cond_func, field, |
|
3729 |
Item_func::GT_FUNC, |
|
3730 |
gt_value, cmp_type)); |
|
3731 |
}
|
|
3732 |
return tree; |
|
3733 |
}
|
|
3734 |
||
3735 |
||
3736 |
/*
|
|
3737 |
Build a SEL_TREE for a simple predicate
|
|
3738 |
|
|
3739 |
SYNOPSIS
|
|
3740 |
get_func_mm_tree()
|
|
3741 |
param PARAM from SQL_SELECT::test_quick_select
|
|
3742 |
cond_func item for the predicate
|
|
3743 |
field field in the predicate
|
|
3744 |
value constant in the predicate
|
|
3745 |
cmp_type compare type for the field
|
|
55
by brian
Update for using real bool types. |
3746 |
inv true <> NOT cond_func is considered
|
1
by brian
clean slate |
3747 |
(makes sense only when cond_func is BETWEEN or IN)
|
3748 |
||
3749 |
RETURN
|
|
3750 |
Pointer to the tree built tree
|
|
3751 |
*/
|
|
3752 |
||
3753 |
static SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func, |
|
3754 |
Field *field, Item *value, |
|
3755 |
Item_result cmp_type, bool inv) |
|
3756 |
{
|
|
3757 |
SEL_TREE *tree= 0; |
|
3758 |
||
3759 |
switch (cond_func->functype()) { |
|
3760 |
||
3761 |
case Item_func::NE_FUNC: |
|
3762 |
tree= get_ne_mm_tree(param, cond_func, field, value, value, cmp_type); |
|
3763 |
break; |
|
3764 |
||
3765 |
case Item_func::BETWEEN: |
|
3766 |
{
|
|
3767 |
if (!value) |
|
3768 |
{
|
|
3769 |
if (inv) |
|
3770 |
{
|
|
3771 |
tree= get_ne_mm_tree(param, cond_func, field, cond_func->arguments()[1], |
|
3772 |
cond_func->arguments()[2], cmp_type); |
|
3773 |
}
|
|
3774 |
else
|
|
3775 |
{
|
|
3776 |
tree= get_mm_parts(param, cond_func, field, Item_func::GE_FUNC, |
|
3777 |
cond_func->arguments()[1],cmp_type); |
|
3778 |
if (tree) |
|
3779 |
{
|
|
3780 |
tree= tree_and(param, tree, get_mm_parts(param, cond_func, field, |
|
3781 |
Item_func::LE_FUNC, |
|
3782 |
cond_func->arguments()[2], |
|
3783 |
cmp_type)); |
|
3784 |
}
|
|
3785 |
}
|
|
3786 |
}
|
|
3787 |
else
|
|
3788 |
tree= get_mm_parts(param, cond_func, field, |
|
3789 |
(inv ? |
|
3790 |
(value == (Item*)1 ? Item_func::GT_FUNC : |
|
3791 |
Item_func::LT_FUNC): |
|
3792 |
(value == (Item*)1 ? Item_func::LE_FUNC : |
|
3793 |
Item_func::GE_FUNC)), |
|
3794 |
cond_func->arguments()[0], cmp_type); |
|
3795 |
break; |
|
3796 |
}
|
|
3797 |
case Item_func::IN_FUNC: |
|
3798 |
{
|
|
3799 |
Item_func_in *func=(Item_func_in*) cond_func; |
|
3800 |
||
3801 |
/*
|
|
3802 |
Array for IN() is constructed when all values have the same result
|
|
3803 |
type. Tree won't be built for values with different result types,
|
|
3804 |
so we check it here to avoid unnecessary work.
|
|
3805 |
*/
|
|
3806 |
if (!func->arg_types_compatible) |
|
3807 |
break; |
|
3808 |
||
3809 |
if (inv) |
|
3810 |
{
|
|
3811 |
if (func->array && func->array->result_type() != ROW_RESULT) |
|
3812 |
{
|
|
3813 |
/*
|
|
3814 |
We get here for conditions in form "t.key NOT IN (c1, c2, ...)",
|
|
3815 |
where c{i} are constants. Our goal is to produce a SEL_TREE that
|
|
3816 |
represents intervals:
|
|
3817 |
|
|
3818 |
($MIN<t.key<c1) OR (c1<t.key<c2) OR (c2<t.key<c3) OR ... (*)
|
|
3819 |
|
|
3820 |
where $MIN is either "-inf" or NULL.
|
|
3821 |
|
|
3822 |
The most straightforward way to produce it is to convert NOT IN
|
|
3823 |
into "(t.key != c1) AND (t.key != c2) AND ... " and let the range
|
|
3824 |
analyzer to build SEL_TREE from that. The problem is that the
|
|
3825 |
range analyzer will use O(N^2) memory (which is probably a bug),
|
|
3826 |
and people do use big NOT IN lists (e.g. see BUG#15872, BUG#21282),
|
|
3827 |
will run out of memory.
|
|
3828 |
||
3829 |
Another problem with big lists like (*) is that a big list is
|
|
3830 |
unlikely to produce a good "range" access, while considering that
|
|
3831 |
range access will require expensive CPU calculations (and for
|
|
3832 |
MyISAM even index accesses). In short, big NOT IN lists are rarely
|
|
3833 |
worth analyzing.
|
|
3834 |
||
3835 |
Considering the above, we'll handle NOT IN as follows:
|
|
3836 |
* if the number of entries in the NOT IN list is less than
|
|
3837 |
NOT_IN_IGNORE_THRESHOLD, construct the SEL_TREE (*) manually.
|
|
3838 |
* Otherwise, don't produce a SEL_TREE.
|
|
3839 |
*/
|
|
3840 |
#define NOT_IN_IGNORE_THRESHOLD 1000
|
|
3841 |
MEM_ROOT *tmp_root= param->mem_root; |
|
3842 |
param->thd->mem_root= param->old_root; |
|
3843 |
/*
|
|
3844 |
Create one Item_type constant object. We'll need it as
|
|
3845 |
get_mm_parts only accepts constant values wrapped in Item_Type
|
|
3846 |
objects.
|
|
3847 |
We create the Item on param->mem_root which points to
|
|
3848 |
per-statement mem_root (while thd->mem_root is currently pointing
|
|
3849 |
to mem_root local to range optimizer).
|
|
3850 |
*/
|
|
3851 |
Item *value_item= func->array->create_item(); |
|
3852 |
param->thd->mem_root= tmp_root; |
|
3853 |
||
3854 |
if (func->array->count > NOT_IN_IGNORE_THRESHOLD || !value_item) |
|
3855 |
break; |
|
3856 |
||
3857 |
/* Get a SEL_TREE for "(-inf|NULL) < X < c_0" interval. */
|
|
3858 |
uint i=0; |
|
3859 |
do
|
|
3860 |
{
|
|
3861 |
func->array->value_to_item(i, value_item); |
|
3862 |
tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC, |
|
3863 |
value_item, cmp_type); |
|
3864 |
if (!tree) |
|
3865 |
break; |
|
3866 |
i++; |
|
3867 |
} while (i < func->array->count && tree->type == SEL_TREE::IMPOSSIBLE); |
|
3868 |
||
3869 |
if (!tree || tree->type == SEL_TREE::IMPOSSIBLE) |
|
3870 |
{
|
|
3871 |
/* We get here in cases like "t.unsigned NOT IN (-1,-2,-3) */
|
|
3872 |
tree= NULL; |
|
3873 |
break; |
|
3874 |
}
|
|
3875 |
SEL_TREE *tree2; |
|
3876 |
for (; i < func->array->count; i++) |
|
3877 |
{
|
|
3878 |
if (func->array->compare_elems(i, i-1)) |
|
3879 |
{
|
|
3880 |
/* Get a SEL_TREE for "-inf < X < c_i" interval */
|
|
3881 |
func->array->value_to_item(i, value_item); |
|
3882 |
tree2= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC, |
|
3883 |
value_item, cmp_type); |
|
3884 |
if (!tree2) |
|
3885 |
{
|
|
3886 |
tree= NULL; |
|
3887 |
break; |
|
3888 |
}
|
|
3889 |
||
3890 |
/* Change all intervals to be "c_{i-1} < X < c_i" */
|
|
3891 |
for (uint idx= 0; idx < param->keys; idx++) |
|
3892 |
{
|
|
3893 |
SEL_ARG *new_interval, *last_val; |
|
3894 |
if (((new_interval= tree2->keys[idx])) && |
|
3895 |
(tree->keys[idx]) && |
|
3896 |
((last_val= tree->keys[idx]->last()))) |
|
3897 |
{
|
|
3898 |
new_interval->min_value= last_val->max_value; |
|
3899 |
new_interval->min_flag= NEAR_MIN; |
|
3900 |
}
|
|
3901 |
}
|
|
3902 |
/*
|
|
3903 |
The following doesn't try to allocate memory so no need to
|
|
3904 |
check for NULL.
|
|
3905 |
*/
|
|
3906 |
tree= tree_or(param, tree, tree2); |
|
3907 |
}
|
|
3908 |
}
|
|
3909 |
||
3910 |
if (tree && tree->type != SEL_TREE::IMPOSSIBLE) |
|
3911 |
{
|
|
3912 |
/*
|
|
3913 |
Get the SEL_TREE for the last "c_last < X < +inf" interval
|
|
3914 |
(value_item cotains c_last already)
|
|
3915 |
*/
|
|
3916 |
tree2= get_mm_parts(param, cond_func, field, Item_func::GT_FUNC, |
|
3917 |
value_item, cmp_type); |
|
3918 |
tree= tree_or(param, tree, tree2); |
|
3919 |
}
|
|
3920 |
}
|
|
3921 |
else
|
|
3922 |
{
|
|
3923 |
tree= get_ne_mm_tree(param, cond_func, field, |
|
3924 |
func->arguments()[1], func->arguments()[1], |
|
3925 |
cmp_type); |
|
3926 |
if (tree) |
|
3927 |
{
|
|
3928 |
Item **arg, **end; |
|
3929 |
for (arg= func->arguments()+2, end= arg+func->argument_count()-2; |
|
3930 |
arg < end ; arg++) |
|
3931 |
{
|
|
3932 |
tree= tree_and(param, tree, get_ne_mm_tree(param, cond_func, field, |
|
3933 |
*arg, *arg, cmp_type)); |
|
3934 |
}
|
|
3935 |
}
|
|
3936 |
}
|
|
3937 |
}
|
|
3938 |
else
|
|
3939 |
{
|
|
3940 |
tree= get_mm_parts(param, cond_func, field, Item_func::EQ_FUNC, |
|
3941 |
func->arguments()[1], cmp_type); |
|
3942 |
if (tree) |
|
3943 |
{
|
|
3944 |
Item **arg, **end; |
|
3945 |
for (arg= func->arguments()+2, end= arg+func->argument_count()-2; |
|
3946 |
arg < end ; arg++) |
|
3947 |
{
|
|
3948 |
tree= tree_or(param, tree, get_mm_parts(param, cond_func, field, |
|
3949 |
Item_func::EQ_FUNC, |
|
3950 |
*arg, cmp_type)); |
|
3951 |
}
|
|
3952 |
}
|
|
3953 |
}
|
|
3954 |
break; |
|
3955 |
}
|
|
3956 |
default: |
|
3957 |
{
|
|
3958 |
/*
|
|
3959 |
Here the function for the following predicates are processed:
|
|
3960 |
<, <=, =, >=, >, LIKE, IS NULL, IS NOT NULL.
|
|
3961 |
If the predicate is of the form (value op field) it is handled
|
|
3962 |
as the equivalent predicate (field rev_op value), e.g.
|
|
3963 |
2 <= a is handled as a >= 2.
|
|
3964 |
*/
|
|
3965 |
Item_func::Functype func_type= |
|
3966 |
(value != cond_func->arguments()[0]) ? cond_func->functype() : |
|
3967 |
((Item_bool_func2*) cond_func)->rev_functype(); |
|
3968 |
tree= get_mm_parts(param, cond_func, field, func_type, value, cmp_type); |
|
3969 |
}
|
|
3970 |
}
|
|
3971 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3972 |
return(tree); |
1
by brian
clean slate |
3973 |
}
|
3974 |
||
3975 |
||
3976 |
/*
|
|
3977 |
Build conjunction of all SEL_TREEs for a simple predicate applying equalities
|
|
3978 |
|
|
3979 |
SYNOPSIS
|
|
3980 |
get_full_func_mm_tree()
|
|
3981 |
param PARAM from SQL_SELECT::test_quick_select
|
|
3982 |
cond_func item for the predicate
|
|
3983 |
field_item field in the predicate
|
|
3984 |
value constant in the predicate
|
|
3985 |
(for BETWEEN it contains the number of the field argument,
|
|
3986 |
for IN it's always 0)
|
|
55
by brian
Update for using real bool types. |
3987 |
inv true <> NOT cond_func is considered
|
1
by brian
clean slate |
3988 |
(makes sense only when cond_func is BETWEEN or IN)
|
3989 |
||
3990 |
DESCRIPTION
|
|
3991 |
For a simple SARGable predicate of the form (f op c), where f is a field and
|
|
3992 |
c is a constant, the function builds a conjunction of all SEL_TREES that can
|
|
3993 |
be obtained by the substitution of f for all different fields equal to f.
|
|
3994 |
||
3995 |
NOTES
|
|
3996 |
If the WHERE condition contains a predicate (fi op c),
|
|
3997 |
then not only SELL_TREE for this predicate is built, but
|
|
3998 |
the trees for the results of substitution of fi for
|
|
3999 |
each fj belonging to the same multiple equality as fi
|
|
4000 |
are built as well.
|
|
4001 |
E.g. for WHERE t1.a=t2.a AND t2.a > 10
|
|
4002 |
a SEL_TREE for t2.a > 10 will be built for quick select from t2
|
|
4003 |
and
|
|
4004 |
a SEL_TREE for t1.a > 10 will be built for quick select from t1.
|
|
4005 |
||
4006 |
A BETWEEN predicate of the form (fi [NOT] BETWEEN c1 AND c2) is treated
|
|
4007 |
in a similar way: we build a conjuction of trees for the results
|
|
4008 |
of all substitutions of fi for equal fj.
|
|
4009 |
Yet a predicate of the form (c BETWEEN f1i AND f2i) is processed
|
|
4010 |
differently. It is considered as a conjuction of two SARGable
|
|
4011 |
predicates (f1i <= c) and (f2i <=c) and the function get_full_func_mm_tree
|
|
4012 |
is called for each of them separately producing trees for
|
|
4013 |
AND j (f1j <=c ) and AND j (f2j <= c)
|
|
4014 |
After this these two trees are united in one conjunctive tree.
|
|
4015 |
It's easy to see that the same tree is obtained for
|
|
4016 |
AND j,k (f1j <=c AND f2k<=c)
|
|
4017 |
which is equivalent to
|
|
4018 |
AND j,k (c BETWEEN f1j AND f2k).
|
|
4019 |
The validity of the processing of the predicate (c NOT BETWEEN f1i AND f2i)
|
|
4020 |
which equivalent to (f1i > c OR f2i < c) is not so obvious. Here the
|
|
4021 |
function get_full_func_mm_tree is called for (f1i > c) and (f2i < c)
|
|
4022 |
producing trees for AND j (f1j > c) and AND j (f2j < c). Then this two
|
|
4023 |
trees are united in one OR-tree. The expression
|
|
4024 |
(AND j (f1j > c) OR AND j (f2j < c)
|
|
4025 |
is equivalent to the expression
|
|
4026 |
AND j,k (f1j > c OR f2k < c)
|
|
4027 |
which is just a translation of
|
|
4028 |
AND j,k (c NOT BETWEEN f1j AND f2k)
|
|
4029 |
||
4030 |
In the cases when one of the items f1, f2 is a constant c1 we do not create
|
|
4031 |
a tree for it at all. It works for BETWEEN predicates but does not
|
|
4032 |
work for NOT BETWEEN predicates as we have to evaluate the expression
|
|
55
by brian
Update for using real bool types. |
4033 |
with it. If it is true then the other tree can be completely ignored.
|
1
by brian
clean slate |
4034 |
We do not do it now and no trees are built in these cases for
|
4035 |
NOT BETWEEN predicates.
|
|
4036 |
||
4037 |
As to IN predicates only ones of the form (f IN (c1,...,cn)),
|
|
4038 |
where f1 is a field and c1,...,cn are constant, are considered as
|
|
4039 |
SARGable. We never try to narrow the index scan using predicates of
|
|
4040 |
the form (c IN (c1,...,f,...,cn)).
|
|
4041 |
|
|
4042 |
RETURN
|
|
4043 |
Pointer to the tree representing the built conjunction of SEL_TREEs
|
|
4044 |
*/
|
|
4045 |
||
4046 |
static SEL_TREE *get_full_func_mm_tree(RANGE_OPT_PARAM *param, |
|
4047 |
Item_func *cond_func, |
|
4048 |
Item_field *field_item, Item *value, |
|
4049 |
bool inv) |
|
4050 |
{
|
|
4051 |
SEL_TREE *tree= 0; |
|
4052 |
SEL_TREE *ftree= 0; |
|
4053 |
table_map ref_tables= 0; |
|
4054 |
table_map param_comp= ~(param->prev_tables | param->read_tables | |
|
4055 |
param->current_table); |
|
4056 |
||
4057 |
for (uint i= 0; i < cond_func->arg_count; i++) |
|
4058 |
{
|
|
4059 |
Item *arg= cond_func->arguments()[i]->real_item(); |
|
4060 |
if (arg != field_item) |
|
4061 |
ref_tables|= arg->used_tables(); |
|
4062 |
}
|
|
4063 |
Field *field= field_item->field; |
|
4064 |
Item_result cmp_type= field->cmp_type(); |
|
4065 |
if (!((ref_tables | field->table->map) & param_comp)) |
|
4066 |
ftree= get_func_mm_tree(param, cond_func, field, value, cmp_type, inv); |
|
4067 |
Item_equal *item_equal= field_item->item_equal; |
|
4068 |
if (item_equal) |
|
4069 |
{
|
|
4070 |
Item_equal_iterator it(*item_equal); |
|
4071 |
Item_field *item; |
|
4072 |
while ((item= it++)) |
|
4073 |
{
|
|
4074 |
Field *f= item->field; |
|
4075 |
if (field->eq(f)) |
|
4076 |
continue; |
|
4077 |
if (!((ref_tables | f->table->map) & param_comp)) |
|
4078 |
{
|
|
4079 |
tree= get_func_mm_tree(param, cond_func, f, value, cmp_type, inv); |
|
4080 |
ftree= !ftree ? tree : tree_and(param, ftree, tree); |
|
4081 |
}
|
|
4082 |
}
|
|
4083 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4084 |
return(ftree); |
1
by brian
clean slate |
4085 |
}
|
4086 |
||
4087 |
/* make a select tree of all keys in condition */
|
|
4088 |
||
4089 |
static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond) |
|
4090 |
{
|
|
4091 |
SEL_TREE *tree=0; |
|
4092 |
SEL_TREE *ftree= 0; |
|
4093 |
Item_field *field_item= 0; |
|
55
by brian
Update for using real bool types. |
4094 |
bool inv= false; |
1
by brian
clean slate |
4095 |
Item *value= 0; |
4096 |
||
4097 |
if (cond->type() == Item::COND_ITEM) |
|
4098 |
{
|
|
4099 |
List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); |
|
4100 |
||
4101 |
if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) |
|
4102 |
{
|
|
4103 |
tree=0; |
|
4104 |
Item *item; |
|
4105 |
while ((item=li++)) |
|
4106 |
{
|
|
4107 |
SEL_TREE *new_tree=get_mm_tree(param,item); |
|
4108 |
if (param->thd->is_fatal_error || |
|
4109 |
param->alloced_sel_args > SEL_ARG::MAX_SEL_ARGS) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4110 |
return(0); // out of memory |
1
by brian
clean slate |
4111 |
tree=tree_and(param,tree,new_tree); |
4112 |
if (tree && tree->type == SEL_TREE::IMPOSSIBLE) |
|
4113 |
break; |
|
4114 |
}
|
|
4115 |
}
|
|
4116 |
else
|
|
4117 |
{ // COND OR |
|
4118 |
tree=get_mm_tree(param,li++); |
|
4119 |
if (tree) |
|
4120 |
{
|
|
4121 |
Item *item; |
|
4122 |
while ((item=li++)) |
|
4123 |
{
|
|
4124 |
SEL_TREE *new_tree=get_mm_tree(param,item); |
|
4125 |
if (!new_tree) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4126 |
return(0); // out of memory |
1
by brian
clean slate |
4127 |
tree=tree_or(param,tree,new_tree); |
4128 |
if (!tree || tree->type == SEL_TREE::ALWAYS) |
|
4129 |
break; |
|
4130 |
}
|
|
4131 |
}
|
|
4132 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4133 |
return(tree); |
1
by brian
clean slate |
4134 |
}
|
4135 |
/* Here when simple cond */
|
|
4136 |
if (cond->const_item()) |
|
4137 |
{
|
|
4138 |
/*
|
|
4139 |
During the cond->val_int() evaluation we can come across a subselect
|
|
4140 |
item which may allocate memory on the thd->mem_root and assumes
|
|
4141 |
all the memory allocated has the same life span as the subselect
|
|
4142 |
item itself. So we have to restore the thread's mem_root here.
|
|
4143 |
*/
|
|
4144 |
MEM_ROOT *tmp_root= param->mem_root; |
|
4145 |
param->thd->mem_root= param->old_root; |
|
4146 |
tree= cond->val_int() ? new(tmp_root) SEL_TREE(SEL_TREE::ALWAYS) : |
|
4147 |
new(tmp_root) SEL_TREE(SEL_TREE::IMPOSSIBLE); |
|
4148 |
param->thd->mem_root= tmp_root; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4149 |
return(tree); |
1
by brian
clean slate |
4150 |
}
|
4151 |
||
4152 |
table_map ref_tables= 0; |
|
4153 |
table_map param_comp= ~(param->prev_tables | param->read_tables | |
|
4154 |
param->current_table); |
|
4155 |
if (cond->type() != Item::FUNC_ITEM) |
|
4156 |
{ // Should be a field |
|
4157 |
ref_tables= cond->used_tables(); |
|
4158 |
if ((ref_tables & param->current_table) || |
|
4159 |
(ref_tables & ~(param->prev_tables | param->read_tables))) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4160 |
return(0); |
4161 |
return(new SEL_TREE(SEL_TREE::MAYBE)); |
|
1
by brian
clean slate |
4162 |
}
|
4163 |
||
4164 |
Item_func *cond_func= (Item_func*) cond; |
|
4165 |
if (cond_func->functype() == Item_func::BETWEEN || |
|
4166 |
cond_func->functype() == Item_func::IN_FUNC) |
|
4167 |
inv= ((Item_func_opt_neg *) cond_func)->negated; |
|
4168 |
else if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4169 |
return(0); |
1
by brian
clean slate |
4170 |
|
4171 |
param->cond= cond; |
|
4172 |
||
4173 |
switch (cond_func->functype()) { |
|
4174 |
case Item_func::BETWEEN: |
|
4175 |
if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM) |
|
4176 |
{
|
|
4177 |
field_item= (Item_field*) (cond_func->arguments()[0]->real_item()); |
|
4178 |
ftree= get_full_func_mm_tree(param, cond_func, field_item, NULL, inv); |
|
4179 |
}
|
|
4180 |
||
4181 |
/*
|
|
4182 |
Concerning the code below see the NOTES section in
|
|
4183 |
the comments for the function get_full_func_mm_tree()
|
|
4184 |
*/
|
|
4185 |
for (uint i= 1 ; i < cond_func->arg_count ; i++) |
|
4186 |
{
|
|
4187 |
if (cond_func->arguments()[i]->real_item()->type() == Item::FIELD_ITEM) |
|
4188 |
{
|
|
4189 |
field_item= (Item_field*) (cond_func->arguments()[i]->real_item()); |
|
4190 |
SEL_TREE *tmp= get_full_func_mm_tree(param, cond_func, |
|
157
by Brian Aker
Second pass cleanup on removal of my_uint types |
4191 |
field_item, (Item*)(intptr_t)i, inv); |
1
by brian
clean slate |
4192 |
if (inv) |
4193 |
tree= !tree ? tmp : tree_or(param, tree, tmp); |
|
4194 |
else
|
|
4195 |
tree= tree_and(param, tree, tmp); |
|
4196 |
}
|
|
4197 |
else if (inv) |
|
4198 |
{
|
|
4199 |
tree= 0; |
|
4200 |
break; |
|
4201 |
}
|
|
4202 |
}
|
|
4203 |
||
4204 |
ftree = tree_and(param, ftree, tree); |
|
4205 |
break; |
|
4206 |
case Item_func::IN_FUNC: |
|
4207 |
{
|
|
4208 |
Item_func_in *func=(Item_func_in*) cond_func; |
|
4209 |
if (func->key_item()->real_item()->type() != Item::FIELD_ITEM) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4210 |
return(0); |
1
by brian
clean slate |
4211 |
field_item= (Item_field*) (func->key_item()->real_item()); |
4212 |
ftree= get_full_func_mm_tree(param, cond_func, field_item, NULL, inv); |
|
4213 |
break; |
|
4214 |
}
|
|
4215 |
case Item_func::MULT_EQUAL_FUNC: |
|
4216 |
{
|
|
4217 |
Item_equal *item_equal= (Item_equal *) cond; |
|
4218 |
if (!(value= item_equal->get_const())) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4219 |
return(0); |
1
by brian
clean slate |
4220 |
Item_equal_iterator it(*item_equal); |
4221 |
ref_tables= value->used_tables(); |
|
4222 |
while ((field_item= it++)) |
|
4223 |
{
|
|
4224 |
Field *field= field_item->field; |
|
4225 |
Item_result cmp_type= field->cmp_type(); |
|
4226 |
if (!((ref_tables | field->table->map) & param_comp)) |
|
4227 |
{
|
|
4228 |
tree= get_mm_parts(param, cond, field, Item_func::EQ_FUNC, |
|
4229 |
value,cmp_type); |
|
4230 |
ftree= !ftree ? tree : tree_and(param, ftree, tree); |
|
4231 |
}
|
|
4232 |
}
|
|
4233 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4234 |
return(ftree); |
1
by brian
clean slate |
4235 |
}
|
4236 |
default: |
|
4237 |
if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM) |
|
4238 |
{
|
|
4239 |
field_item= (Item_field*) (cond_func->arguments()[0]->real_item()); |
|
4240 |
value= cond_func->arg_count > 1 ? cond_func->arguments()[1] : 0; |
|
4241 |
}
|
|
4242 |
else if (cond_func->have_rev_func() && |
|
4243 |
cond_func->arguments()[1]->real_item()->type() == |
|
4244 |
Item::FIELD_ITEM) |
|
4245 |
{
|
|
4246 |
field_item= (Item_field*) (cond_func->arguments()[1]->real_item()); |
|
4247 |
value= cond_func->arguments()[0]; |
|
4248 |
}
|
|
4249 |
else
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4250 |
return(0); |
1
by brian
clean slate |
4251 |
ftree= get_full_func_mm_tree(param, cond_func, field_item, value, inv); |
4252 |
}
|
|
4253 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4254 |
return(ftree); |
1
by brian
clean slate |
4255 |
}
|
4256 |
||
4257 |
||
4258 |
static SEL_TREE * |
|
4259 |
get_mm_parts(RANGE_OPT_PARAM *param, COND *cond_func, Field *field, |
|
4260 |
Item_func::Functype type, |
|
77.1.46
by Monty Taylor
Finished the warnings work! |
4261 |
Item *value, |
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
4262 |
Item_result cmp_type __attribute__((unused))) |
1
by brian
clean slate |
4263 |
{
|
4264 |
if (field->table != param->table) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4265 |
return(0); |
1
by brian
clean slate |
4266 |
|
4267 |
KEY_PART *key_part = param->key_parts; |
|
4268 |
KEY_PART *end = param->key_parts_end; |
|
4269 |
SEL_TREE *tree=0; |
|
4270 |
if (value && |
|
4271 |
value->used_tables() & ~(param->prev_tables | param->read_tables)) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4272 |
return(0); |
1
by brian
clean slate |
4273 |
for (; key_part != end ; key_part++) |
4274 |
{
|
|
4275 |
if (field->eq(key_part->field)) |
|
4276 |
{
|
|
4277 |
SEL_ARG *sel_arg=0; |
|
4278 |
if (!tree && !(tree=new SEL_TREE())) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4279 |
return(0); // OOM |
1
by brian
clean slate |
4280 |
if (!value || !(value->used_tables() & ~param->read_tables)) |
4281 |
{
|
|
4282 |
sel_arg=get_mm_leaf(param,cond_func, |
|
4283 |
key_part->field,key_part,type,value); |
|
4284 |
if (!sel_arg) |
|
4285 |
continue; |
|
4286 |
if (sel_arg->type == SEL_ARG::IMPOSSIBLE) |
|
4287 |
{
|
|
4288 |
tree->type=SEL_TREE::IMPOSSIBLE; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4289 |
return(tree); |
1
by brian
clean slate |
4290 |
}
|
4291 |
}
|
|
4292 |
else
|
|
4293 |
{
|
|
4294 |
// This key may be used later
|
|
4295 |
if (!(sel_arg= new SEL_ARG(SEL_ARG::MAYBE_KEY))) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4296 |
return(0); // OOM |
1
by brian
clean slate |
4297 |
}
|
4298 |
sel_arg->part=(uchar) key_part->part; |
|
4299 |
tree->keys[key_part->key]=sel_add(tree->keys[key_part->key],sel_arg); |
|
4300 |
tree->keys_map.set_bit(key_part->key); |
|
4301 |
}
|
|
4302 |
}
|
|
4303 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4304 |
return(tree); |
1
by brian
clean slate |
4305 |
}
|
4306 |
||
4307 |
||
4308 |
static SEL_ARG * |
|
4309 |
get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, |
|
4310 |
KEY_PART *key_part, Item_func::Functype type,Item *value) |
|
4311 |
{
|
|
4312 |
uint maybe_null=(uint) field->real_maybe_null(); |
|
4313 |
bool optimize_range; |
|
4314 |
SEL_ARG *tree= 0; |
|
4315 |
MEM_ROOT *alloc= param->mem_root; |
|
4316 |
uchar *str; |
|
4317 |
ulong orig_sql_mode; |
|
4318 |
int err; |
|
4319 |
||
4320 |
/*
|
|
4321 |
We need to restore the runtime mem_root of the thread in this
|
|
4322 |
function because it evaluates the value of its argument, while
|
|
4323 |
the argument can be any, e.g. a subselect. The subselect
|
|
4324 |
items, in turn, assume that all the memory allocated during
|
|
4325 |
the evaluation has the same life span as the item itself.
|
|
4326 |
TODO: opt_range.cc should not reset thd->mem_root at all.
|
|
4327 |
*/
|
|
4328 |
param->thd->mem_root= param->old_root; |
|
4329 |
if (!value) // IS NULL or IS NOT NULL |
|
4330 |
{
|
|
4331 |
if (field->table->maybe_null) // Can't use a key on this |
|
4332 |
goto end; |
|
4333 |
if (!maybe_null) // Not null field |
|
4334 |
{
|
|
4335 |
if (type == Item_func::ISNULL_FUNC) |
|
4336 |
tree= &null_element; |
|
4337 |
goto end; |
|
4338 |
}
|
|
4339 |
if (!(tree= new (alloc) SEL_ARG(field,is_null_string,is_null_string))) |
|
4340 |
goto end; // out of memory |
|
4341 |
if (type == Item_func::ISNOTNULL_FUNC) |
|
4342 |
{
|
|
4343 |
tree->min_flag=NEAR_MIN; /* IS NOT NULL -> X > NULL */ |
|
4344 |
tree->max_flag=NO_MAX_RANGE; |
|
4345 |
}
|
|
4346 |
goto end; |
|
4347 |
}
|
|
4348 |
||
4349 |
/*
|
|
4350 |
1. Usually we can't use an index if the column collation
|
|
4351 |
differ from the operation collation.
|
|
4352 |
||
4353 |
2. However, we can reuse a case insensitive index for
|
|
4354 |
the binary searches:
|
|
4355 |
||
4356 |
WHERE latin1_swedish_ci_column = 'a' COLLATE lati1_bin;
|
|
4357 |
||
4358 |
WHERE latin1_swedish_ci_colimn = BINARY 'a '
|
|
4359 |
||
4360 |
*/
|
|
4361 |
if (field->result_type() == STRING_RESULT && |
|
4362 |
value->result_type() == STRING_RESULT && |
|
4363 |
key_part->image_type == Field::itRAW && |
|
4364 |
((Field_str*)field)->charset() != conf_func->compare_collation() && |
|
4365 |
!(conf_func->compare_collation()->state & MY_CS_BINSORT)) |
|
4366 |
goto end; |
|
4367 |
||
4368 |
if (param->using_real_indexes) |
|
4369 |
optimize_range= field->optimize_range(param->real_keynr[key_part->key], |
|
4370 |
key_part->part); |
|
4371 |
else
|
|
55
by brian
Update for using real bool types. |
4372 |
optimize_range= true; |
1
by brian
clean slate |
4373 |
|
4374 |
if (type == Item_func::LIKE_FUNC) |
|
4375 |
{
|
|
4376 |
bool like_error; |
|
4377 |
char buff1[MAX_FIELD_WIDTH]; |
|
4378 |
uchar *min_str,*max_str; |
|
4379 |
String tmp(buff1,sizeof(buff1),value->collation.collation),*res; |
|
4380 |
size_t length, offset, min_length, max_length; |
|
4381 |
uint field_length= field->pack_length()+maybe_null; |
|
4382 |
||
4383 |
if (!optimize_range) |
|
4384 |
goto end; |
|
4385 |
if (!(res= value->val_str(&tmp))) |
|
4386 |
{
|
|
4387 |
tree= &null_element; |
|
4388 |
goto end; |
|
4389 |
}
|
|
4390 |
||
4391 |
/*
|
|
4392 |
TODO:
|
|
4393 |
Check if this was a function. This should have be optimized away
|
|
4394 |
in the sql_select.cc
|
|
4395 |
*/
|
|
4396 |
if (res != &tmp) |
|
4397 |
{
|
|
4398 |
tmp.copy(*res); // Get own copy |
|
4399 |
res= &tmp; |
|
4400 |
}
|
|
4401 |
if (field->cmp_type() != STRING_RESULT) |
|
4402 |
goto end; // Can only optimize strings |
|
4403 |
||
4404 |
offset=maybe_null; |
|
4405 |
length=key_part->store_length; |
|
4406 |
||
4407 |
if (length != key_part->length + maybe_null) |
|
4408 |
{
|
|
4409 |
/* key packed with length prefix */
|
|
4410 |
offset+= HA_KEY_BLOB_LENGTH; |
|
4411 |
field_length= length - HA_KEY_BLOB_LENGTH; |
|
4412 |
}
|
|
4413 |
else
|
|
4414 |
{
|
|
4415 |
if (unlikely(length < field_length)) |
|
4416 |
{
|
|
4417 |
/*
|
|
4418 |
This can only happen in a table created with UNIREG where one key
|
|
4419 |
overlaps many fields
|
|
4420 |
*/
|
|
4421 |
length= field_length; |
|
4422 |
}
|
|
4423 |
else
|
|
4424 |
field_length= length; |
|
4425 |
}
|
|
4426 |
length+=offset; |
|
4427 |
if (!(min_str= (uchar*) alloc_root(alloc, length*2))) |
|
4428 |
goto end; |
|
4429 |
||
4430 |
max_str=min_str+length; |
|
4431 |
if (maybe_null) |
|
4432 |
max_str[0]= min_str[0]=0; |
|
4433 |
||
4434 |
field_length-= maybe_null; |
|
4435 |
like_error= my_like_range(field->charset(), |
|
4436 |
res->ptr(), res->length(), |
|
4437 |
((Item_func_like*)(param->cond))->escape, |
|
4438 |
wild_one, wild_many, |
|
4439 |
field_length, |
|
4440 |
(char*) min_str+offset, (char*) max_str+offset, |
|
4441 |
&min_length, &max_length); |
|
4442 |
if (like_error) // Can't optimize with LIKE |
|
4443 |
goto end; |
|
4444 |
||
4445 |
if (offset != maybe_null) // BLOB or VARCHAR |
|
4446 |
{
|
|
4447 |
int2store(min_str+maybe_null,min_length); |
|
4448 |
int2store(max_str+maybe_null,max_length); |
|
4449 |
}
|
|
4450 |
tree= new (alloc) SEL_ARG(field, min_str, max_str); |
|
4451 |
goto end; |
|
4452 |
}
|
|
4453 |
||
4454 |
if (!optimize_range && |
|
4455 |
type != Item_func::EQ_FUNC && |
|
4456 |
type != Item_func::EQUAL_FUNC) |
|
4457 |
goto end; // Can't optimize this |
|
4458 |
||
4459 |
/*
|
|
4460 |
We can't always use indexes when comparing a string index to a number
|
|
4461 |
cmp_type() is checked to allow compare of dates to numbers
|
|
4462 |
*/
|
|
4463 |
if (field->result_type() == STRING_RESULT && |
|
4464 |
value->result_type() != STRING_RESULT && |
|
4465 |
field->cmp_type() != value->result_type()) |
|
4466 |
goto end; |
|
4467 |
/* For comparison purposes allow invalid dates like 2000-01-32 */
|
|
4468 |
orig_sql_mode= field->table->in_use->variables.sql_mode; |
|
4469 |
if (value->real_item()->type() == Item::STRING_ITEM && |
|
212.2.2
by Patrick Galbraith
Renamed FIELD_TYPE to DRIZZLE_TYPE |
4470 |
(field->type() == DRIZZLE_TYPE_NEWDATE || |
4471 |
field->type() == DRIZZLE_TYPE_DATETIME)) |
|
1
by brian
clean slate |
4472 |
field->table->in_use->variables.sql_mode|= MODE_INVALID_DATES; |
4473 |
err= value->save_in_field_no_warnings(field, 1); |
|
4474 |
if (err > 0) |
|
4475 |
{
|
|
4476 |
if (field->cmp_type() != value->result_type()) |
|
4477 |
{
|
|
4478 |
if ((type == Item_func::EQ_FUNC || type == Item_func::EQUAL_FUNC) && |
|
4479 |
value->result_type() == item_cmp_type(field->result_type(), |
|
4480 |
value->result_type())) |
|
4481 |
{
|
|
4482 |
tree= new (alloc) SEL_ARG(field, 0, 0); |
|
4483 |
tree->type= SEL_ARG::IMPOSSIBLE; |
|
4484 |
goto end; |
|
4485 |
}
|
|
4486 |
else
|
|
4487 |
{
|
|
4488 |
/*
|
|
4489 |
TODO: We should return trees of the type SEL_ARG::IMPOSSIBLE
|
|
4490 |
for the cases like int_field > 999999999999999999999999 as well.
|
|
4491 |
*/
|
|
4492 |
tree= 0; |
|
212.2.2
by Patrick Galbraith
Renamed FIELD_TYPE to DRIZZLE_TYPE |
4493 |
if (err == 3 && field->type() == DRIZZLE_TYPE_NEWDATE && |
1
by brian
clean slate |
4494 |
(type == Item_func::GT_FUNC || type == Item_func::GE_FUNC || |
4495 |
type == Item_func::LT_FUNC || type == Item_func::LE_FUNC) ) |
|
4496 |
{
|
|
4497 |
/*
|
|
4498 |
We were saving DATETIME into a DATE column, the conversion went ok
|
|
4499 |
but a non-zero time part was cut off.
|
|
4500 |
||
4501 |
In MySQL's SQL dialect, DATE and DATETIME are compared as datetime
|
|
4502 |
values. Index over a DATE column uses DATE comparison. Changing
|
|
4503 |
from one comparison to the other is possible:
|
|
4504 |
||
4505 |
datetime(date_col)< '2007-12-10 12:34:55' -> date_col<='2007-12-10'
|
|
4506 |
datetime(date_col)<='2007-12-10 12:34:55' -> date_col<='2007-12-10'
|
|
4507 |
||
4508 |
datetime(date_col)> '2007-12-10 12:34:55' -> date_col>='2007-12-10'
|
|
4509 |
datetime(date_col)>='2007-12-10 12:34:55' -> date_col>='2007-12-10'
|
|
4510 |
||
4511 |
but we'll need to convert '>' to '>=' and '<' to '<='. This will
|
|
4512 |
be done together with other types at the end of this function
|
|
4513 |
(grep for field_is_equal_to_item)
|
|
4514 |
*/
|
|
4515 |
}
|
|
4516 |
else
|
|
4517 |
goto end; |
|
4518 |
}
|
|
4519 |
}
|
|
4520 |
||
4521 |
/*
|
|
4522 |
guaranteed at this point: err > 0; field and const of same type
|
|
4523 |
If an integer got bounded (e.g. to within 0..255 / -128..127)
|
|
4524 |
for < or >, set flags as for <= or >= (no NEAR_MAX / NEAR_MIN)
|
|
4525 |
*/
|
|
4526 |
else if (err == 1 && field->result_type() == INT_RESULT) |
|
4527 |
{
|
|
4528 |
if (type == Item_func::LT_FUNC && (value->val_int() > 0)) |
|
4529 |
type = Item_func::LE_FUNC; |
|
4530 |
else if (type == Item_func::GT_FUNC && |
|
4531 |
!((Field_num*)field)->unsigned_flag && |
|
4532 |
!((Item_int*)value)->unsigned_flag && |
|
4533 |
(value->val_int() < 0)) |
|
4534 |
type = Item_func::GE_FUNC; |
|
4535 |
}
|
|
4536 |
}
|
|
4537 |
else if (err < 0) |
|
4538 |
{
|
|
4539 |
field->table->in_use->variables.sql_mode= orig_sql_mode; |
|
4540 |
/* This happens when we try to insert a NULL field in a not null column */
|
|
55
by brian
Update for using real bool types. |
4541 |
tree= &null_element; // cmp with NULL is never true |
1
by brian
clean slate |
4542 |
goto end; |
4543 |
}
|
|
4544 |
field->table->in_use->variables.sql_mode= orig_sql_mode; |
|
4545 |
str= (uchar*) alloc_root(alloc, key_part->store_length+1); |
|
4546 |
if (!str) |
|
4547 |
goto end; |
|
4548 |
if (maybe_null) |
|
4549 |
*str= (uchar) field->is_real_null(); // Set to 1 if null |
|
4550 |
field->get_key_image(str+maybe_null, key_part->length, |
|
4551 |
key_part->image_type); |
|
4552 |
if (!(tree= new (alloc) SEL_ARG(field, str, str))) |
|
4553 |
goto end; // out of memory |
|
4554 |
||
4555 |
/*
|
|
4556 |
Check if we are comparing an UNSIGNED integer with a negative constant.
|
|
4557 |
In this case we know that:
|
|
55
by brian
Update for using real bool types. |
4558 |
(a) (unsigned_int [< | <=] negative_constant) == false
|
4559 |
(b) (unsigned_int [> | >=] negative_constant) == true
|
|
1
by brian
clean slate |
4560 |
In case (a) the condition is false for all values, and in case (b) it
|
4561 |
is true for all values, so we can avoid unnecessary retrieval and condition
|
|
4562 |
testing, and we also get correct comparison of unsinged integers with
|
|
4563 |
negative integers (which otherwise fails because at query execution time
|
|
4564 |
negative integers are cast to unsigned if compared with unsigned).
|
|
4565 |
*/
|
|
4566 |
if (field->result_type() == INT_RESULT && |
|
4567 |
value->result_type() == INT_RESULT && |
|
4568 |
((Field_num*)field)->unsigned_flag && !((Item_int*)value)->unsigned_flag) |
|
4569 |
{
|
|
152
by Brian Aker
longlong replacement |
4570 |
int64_t item_val= value->val_int(); |
1
by brian
clean slate |
4571 |
if (item_val < 0) |
4572 |
{
|
|
4573 |
if (type == Item_func::LT_FUNC || type == Item_func::LE_FUNC) |
|
4574 |
{
|
|
4575 |
tree->type= SEL_ARG::IMPOSSIBLE; |
|
4576 |
goto end; |
|
4577 |
}
|
|
4578 |
if (type == Item_func::GT_FUNC || type == Item_func::GE_FUNC) |
|
4579 |
{
|
|
4580 |
tree= 0; |
|
4581 |
goto end; |
|
4582 |
}
|
|
4583 |
}
|
|
4584 |
}
|
|
4585 |
||
4586 |
switch (type) { |
|
4587 |
case Item_func::LT_FUNC: |
|
4588 |
if (field_is_equal_to_item(field,value)) |
|
4589 |
tree->max_flag=NEAR_MAX; |
|
4590 |
/* fall through */
|
|
4591 |
case Item_func::LE_FUNC: |
|
4592 |
if (!maybe_null) |
|
4593 |
tree->min_flag=NO_MIN_RANGE; /* From start */ |
|
4594 |
else
|
|
4595 |
{ // > NULL |
|
4596 |
tree->min_value=is_null_string; |
|
4597 |
tree->min_flag=NEAR_MIN; |
|
4598 |
}
|
|
4599 |
break; |
|
4600 |
case Item_func::GT_FUNC: |
|
4601 |
/* Don't use open ranges for partial key_segments */
|
|
4602 |
if (field_is_equal_to_item(field,value) && |
|
4603 |
!(key_part->flag & HA_PART_KEY_SEG)) |
|
4604 |
tree->min_flag=NEAR_MIN; |
|
4605 |
/* fall through */
|
|
4606 |
case Item_func::GE_FUNC: |
|
4607 |
tree->max_flag=NO_MAX_RANGE; |
|
4608 |
break; |
|
4609 |
default: |
|
4610 |
break; |
|
4611 |
}
|
|
4612 |
||
4613 |
end: |
|
4614 |
param->thd->mem_root= alloc; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4615 |
return(tree); |
1
by brian
clean slate |
4616 |
}
|
4617 |
||
4618 |
||
4619 |
/******************************************************************************
|
|
4620 |
** Tree manipulation functions
|
|
4621 |
** If tree is 0 it means that the condition can't be tested. It refers
|
|
4622 |
** to a non existent table or to a field in current table with isn't a key.
|
|
4623 |
** The different tree flags:
|
|
55
by brian
Update for using real bool types. |
4624 |
** IMPOSSIBLE: Condition is never true
|
4625 |
** ALWAYS: Condition is always true
|
|
1
by brian
clean slate |
4626 |
** MAYBE: Condition may exists when tables are read
|
4627 |
** MAYBE_KEY: Condition refers to a key that may be used in join loop
|
|
4628 |
** KEY_RANGE: Condition uses a key
|
|
4629 |
******************************************************************************/
|
|
4630 |
||
4631 |
/*
|
|
4632 |
Add a new key test to a key when scanning through all keys
|
|
4633 |
This will never be called for same key parts.
|
|
4634 |
*/
|
|
4635 |
||
4636 |
static SEL_ARG * |
|
4637 |
sel_add(SEL_ARG *key1,SEL_ARG *key2) |
|
4638 |
{
|
|
4639 |
SEL_ARG *root,**key_link; |
|
4640 |
||
4641 |
if (!key1) |
|
4642 |
return key2; |
|
4643 |
if (!key2) |
|
4644 |
return key1; |
|
4645 |
||
4646 |
key_link= &root; |
|
4647 |
while (key1 && key2) |
|
4648 |
{
|
|
4649 |
if (key1->part < key2->part) |
|
4650 |
{
|
|
4651 |
*key_link= key1; |
|
4652 |
key_link= &key1->next_key_part; |
|
4653 |
key1=key1->next_key_part; |
|
4654 |
}
|
|
4655 |
else
|
|
4656 |
{
|
|
4657 |
*key_link= key2; |
|
4658 |
key_link= &key2->next_key_part; |
|
4659 |
key2=key2->next_key_part; |
|
4660 |
}
|
|
4661 |
}
|
|
4662 |
*key_link=key1 ? key1 : key2; |
|
4663 |
return root; |
|
4664 |
}
|
|
4665 |
||
4666 |
#define CLONE_KEY1_MAYBE 1
|
|
4667 |
#define CLONE_KEY2_MAYBE 2
|
|
4668 |
#define swap_clone_flag(A) ((A & 1) << 1) | ((A & 2) >> 1)
|
|
4669 |
||
4670 |
||
4671 |
static SEL_TREE * |
|
4672 |
tree_and(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) |
|
4673 |
{
|
|
4674 |
if (!tree1) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4675 |
return(tree2); |
1
by brian
clean slate |
4676 |
if (!tree2) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4677 |
return(tree1); |
1
by brian
clean slate |
4678 |
if (tree1->type == SEL_TREE::IMPOSSIBLE || tree2->type == SEL_TREE::ALWAYS) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4679 |
return(tree1); |
1
by brian
clean slate |
4680 |
if (tree2->type == SEL_TREE::IMPOSSIBLE || tree1->type == SEL_TREE::ALWAYS) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4681 |
return(tree2); |
1
by brian
clean slate |
4682 |
if (tree1->type == SEL_TREE::MAYBE) |
4683 |
{
|
|
4684 |
if (tree2->type == SEL_TREE::KEY) |
|
4685 |
tree2->type=SEL_TREE::KEY_SMALLER; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4686 |
return(tree2); |
1
by brian
clean slate |
4687 |
}
|
4688 |
if (tree2->type == SEL_TREE::MAYBE) |
|
4689 |
{
|
|
4690 |
tree1->type=SEL_TREE::KEY_SMALLER; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4691 |
return(tree1); |
1
by brian
clean slate |
4692 |
}
|
4693 |
key_map result_keys; |
|
4694 |
result_keys.clear_all(); |
|
4695 |
||
4696 |
/* Join the trees key per key */
|
|
4697 |
SEL_ARG **key1,**key2,**end; |
|
4698 |
for (key1= tree1->keys,key2= tree2->keys,end=key1+param->keys ; |
|
4699 |
key1 != end ; key1++,key2++) |
|
4700 |
{
|
|
4701 |
uint flag=0; |
|
4702 |
if (*key1 || *key2) |
|
4703 |
{
|
|
4704 |
if (*key1 && !(*key1)->simple_key()) |
|
4705 |
flag|=CLONE_KEY1_MAYBE; |
|
4706 |
if (*key2 && !(*key2)->simple_key()) |
|
4707 |
flag|=CLONE_KEY2_MAYBE; |
|
4708 |
*key1=key_and(param, *key1, *key2, flag); |
|
4709 |
if (*key1 && (*key1)->type == SEL_ARG::IMPOSSIBLE) |
|
4710 |
{
|
|
4711 |
tree1->type= SEL_TREE::IMPOSSIBLE; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4712 |
return(tree1); |
1
by brian
clean slate |
4713 |
}
|
4714 |
result_keys.set_bit(key1 - tree1->keys); |
|
4715 |
#ifdef EXTRA_DEBUG
|
|
4716 |
if (*key1 && param->alloced_sel_args < SEL_ARG::MAX_SEL_ARGS) |
|
4717 |
(*key1)->test_use_count(*key1); |
|
4718 |
#endif
|
|
4719 |
}
|
|
4720 |
}
|
|
4721 |
tree1->keys_map= result_keys; |
|
4722 |
/* dispose index_merge if there is a "range" option */
|
|
4723 |
if (!result_keys.is_clear_all()) |
|
4724 |
{
|
|
4725 |
tree1->merges.empty(); |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4726 |
return(tree1); |
1
by brian
clean slate |
4727 |
}
|
4728 |
||
4729 |
/* ok, both trees are index_merge trees */
|
|
4730 |
imerge_list_and_list(&tree1->merges, &tree2->merges); |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4731 |
return(tree1); |
1
by brian
clean slate |
4732 |
}
|
4733 |
||
4734 |
||
4735 |
/*
|
|
4736 |
Check if two SEL_TREES can be combined into one (i.e. a single key range
|
|
4737 |
read can be constructed for "cond_of_tree1 OR cond_of_tree2" ) without
|
|
4738 |
using index_merge.
|
|
4739 |
*/
|
|
4740 |
||
4741 |
bool sel_trees_can_be_ored(SEL_TREE *tree1, SEL_TREE *tree2, |
|
4742 |
RANGE_OPT_PARAM* param) |
|
4743 |
{
|
|
4744 |
key_map common_keys= tree1->keys_map; |
|
4745 |
common_keys.intersect(tree2->keys_map); |
|
4746 |
||
4747 |
if (common_keys.is_clear_all()) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4748 |
return(false); |
1
by brian
clean slate |
4749 |
|
4750 |
/* trees have a common key, check if they refer to same key part */
|
|
4751 |
SEL_ARG **key1,**key2; |
|
4752 |
for (uint key_no=0; key_no < param->keys; key_no++) |
|
4753 |
{
|
|
4754 |
if (common_keys.is_set(key_no)) |
|
4755 |
{
|
|
4756 |
key1= tree1->keys + key_no; |
|
4757 |
key2= tree2->keys + key_no; |
|
4758 |
if ((*key1)->part == (*key2)->part) |
|
4759 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4760 |
return(true); |
1
by brian
clean slate |
4761 |
}
|
4762 |
}
|
|
4763 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4764 |
return(false); |
1
by brian
clean slate |
4765 |
}
|
4766 |
||
4767 |
||
4768 |
/*
|
|
4769 |
Remove the trees that are not suitable for record retrieval.
|
|
4770 |
SYNOPSIS
|
|
4771 |
param Range analysis parameter
|
|
4772 |
tree Tree to be processed, tree->type is KEY or KEY_SMALLER
|
|
4773 |
|
|
4774 |
DESCRIPTION
|
|
4775 |
This function walks through tree->keys[] and removes the SEL_ARG* trees
|
|
4776 |
that are not "maybe" trees (*) and cannot be used to construct quick range
|
|
4777 |
selects.
|
|
4778 |
(*) - have type MAYBE or MAYBE_KEY. Perhaps we should remove trees of
|
|
4779 |
these types here as well.
|
|
4780 |
||
4781 |
A SEL_ARG* tree cannot be used to construct quick select if it has
|
|
4782 |
tree->part != 0. (e.g. it could represent "keypart2 < const").
|
|
4783 |
||
4784 |
WHY THIS FUNCTION IS NEEDED
|
|
4785 |
|
|
4786 |
Normally we allow construction of SEL_TREE objects that have SEL_ARG
|
|
4787 |
trees that do not allow quick range select construction. For example for
|
|
4788 |
" keypart1=1 AND keypart2=2 " the execution will proceed as follows:
|
|
4789 |
tree1= SEL_TREE { SEL_ARG{keypart1=1} }
|
|
4790 |
tree2= SEL_TREE { SEL_ARG{keypart2=2} } -- can't make quick range select
|
|
4791 |
from this
|
|
4792 |
call tree_and(tree1, tree2) -- this joins SEL_ARGs into a usable SEL_ARG
|
|
4793 |
tree.
|
|
4794 |
|
|
4795 |
There is an exception though: when we construct index_merge SEL_TREE,
|
|
4796 |
any SEL_ARG* tree that cannot be used to construct quick range select can
|
|
4797 |
be removed, because current range analysis code doesn't provide any way
|
|
4798 |
that tree could be later combined with another tree.
|
|
4799 |
Consider an example: we should not construct
|
|
4800 |
st1 = SEL_TREE {
|
|
4801 |
merges = SEL_IMERGE {
|
|
4802 |
SEL_TREE(t.key1part1 = 1),
|
|
4803 |
SEL_TREE(t.key2part2 = 2) -- (*)
|
|
4804 |
}
|
|
4805 |
};
|
|
4806 |
because
|
|
4807 |
- (*) cannot be used to construct quick range select,
|
|
4808 |
- There is no execution path that would cause (*) to be converted to
|
|
4809 |
a tree that could be used.
|
|
4810 |
||
4811 |
The latter is easy to verify: first, notice that the only way to convert
|
|
4812 |
(*) into a usable tree is to call tree_and(something, (*)).
|
|
4813 |
||
4814 |
Second look at what tree_and/tree_or function would do when passed a
|
|
4815 |
SEL_TREE that has the structure like st1 tree has, and conlcude that
|
|
4816 |
tree_and(something, (*)) will not be called.
|
|
4817 |
||
4818 |
RETURN
|
|
4819 |
0 Ok, some suitable trees left
|
|
4820 |
1 No tree->keys[] left.
|
|
4821 |
*/
|
|
4822 |
||
4823 |
static bool remove_nonrange_trees(RANGE_OPT_PARAM *param, SEL_TREE *tree) |
|
4824 |
{
|
|
55
by brian
Update for using real bool types. |
4825 |
bool res= false; |
1
by brian
clean slate |
4826 |
for (uint i=0; i < param->keys; i++) |
4827 |
{
|
|
4828 |
if (tree->keys[i]) |
|
4829 |
{
|
|
4830 |
if (tree->keys[i]->part) |
|
4831 |
{
|
|
4832 |
tree->keys[i]= NULL; |
|
4833 |
tree->keys_map.clear_bit(i); |
|
4834 |
}
|
|
4835 |
else
|
|
55
by brian
Update for using real bool types. |
4836 |
res= true; |
1
by brian
clean slate |
4837 |
}
|
4838 |
}
|
|
4839 |
return !res; |
|
4840 |
}
|
|
4841 |
||
4842 |
||
4843 |
static SEL_TREE * |
|
4844 |
tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) |
|
4845 |
{
|
|
4846 |
if (!tree1 || !tree2) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4847 |
return(0); |
1
by brian
clean slate |
4848 |
if (tree1->type == SEL_TREE::IMPOSSIBLE || tree2->type == SEL_TREE::ALWAYS) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4849 |
return(tree2); |
1
by brian
clean slate |
4850 |
if (tree2->type == SEL_TREE::IMPOSSIBLE || tree1->type == SEL_TREE::ALWAYS) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4851 |
return(tree1); |
1
by brian
clean slate |
4852 |
if (tree1->type == SEL_TREE::MAYBE) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4853 |
return(tree1); // Can't use this |
1
by brian
clean slate |
4854 |
if (tree2->type == SEL_TREE::MAYBE) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4855 |
return(tree2); |
1
by brian
clean slate |
4856 |
|
4857 |
SEL_TREE *result= 0; |
|
4858 |
key_map result_keys; |
|
4859 |
result_keys.clear_all(); |
|
4860 |
if (sel_trees_can_be_ored(tree1, tree2, param)) |
|
4861 |
{
|
|
4862 |
/* Join the trees key per key */
|
|
4863 |
SEL_ARG **key1,**key2,**end; |
|
4864 |
for (key1= tree1->keys,key2= tree2->keys,end= key1+param->keys ; |
|
4865 |
key1 != end ; key1++,key2++) |
|
4866 |
{
|
|
4867 |
*key1=key_or(param, *key1, *key2); |
|
4868 |
if (*key1) |
|
4869 |
{
|
|
4870 |
result=tree1; // Added to tree1 |
|
4871 |
result_keys.set_bit(key1 - tree1->keys); |
|
4872 |
#ifdef EXTRA_DEBUG
|
|
4873 |
if (param->alloced_sel_args < SEL_ARG::MAX_SEL_ARGS) |
|
4874 |
(*key1)->test_use_count(*key1); |
|
4875 |
#endif
|
|
4876 |
}
|
|
4877 |
}
|
|
4878 |
if (result) |
|
4879 |
result->keys_map= result_keys; |
|
4880 |
}
|
|
4881 |
else
|
|
4882 |
{
|
|
4883 |
/* ok, two trees have KEY type but cannot be used without index merge */
|
|
4884 |
if (tree1->merges.is_empty() && tree2->merges.is_empty()) |
|
4885 |
{
|
|
4886 |
if (param->remove_jump_scans) |
|
4887 |
{
|
|
4888 |
bool no_trees= remove_nonrange_trees(param, tree1); |
|
4889 |
no_trees= no_trees || remove_nonrange_trees(param, tree2); |
|
4890 |
if (no_trees) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4891 |
return(new SEL_TREE(SEL_TREE::ALWAYS)); |
1
by brian
clean slate |
4892 |
}
|
4893 |
SEL_IMERGE *merge; |
|
4894 |
/* both trees are "range" trees, produce new index merge structure */
|
|
4895 |
if (!(result= new SEL_TREE()) || !(merge= new SEL_IMERGE()) || |
|
4896 |
(result->merges.push_back(merge)) || |
|
4897 |
(merge->or_sel_tree(param, tree1)) || |
|
4898 |
(merge->or_sel_tree(param, tree2))) |
|
4899 |
result= NULL; |
|
4900 |
else
|
|
4901 |
result->type= tree1->type; |
|
4902 |
}
|
|
4903 |
else if (!tree1->merges.is_empty() && !tree2->merges.is_empty()) |
|
4904 |
{
|
|
4905 |
if (imerge_list_or_list(param, &tree1->merges, &tree2->merges)) |
|
4906 |
result= new SEL_TREE(SEL_TREE::ALWAYS); |
|
4907 |
else
|
|
4908 |
result= tree1; |
|
4909 |
}
|
|
4910 |
else
|
|
4911 |
{
|
|
4912 |
/* one tree is index merge tree and another is range tree */
|
|
4913 |
if (tree1->merges.is_empty()) |
|
4914 |
swap_variables(SEL_TREE*, tree1, tree2); |
|
4915 |
||
4916 |
if (param->remove_jump_scans && remove_nonrange_trees(param, tree2)) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4917 |
return(new SEL_TREE(SEL_TREE::ALWAYS)); |
1
by brian
clean slate |
4918 |
/* add tree2 to tree1->merges, checking if it collapses to ALWAYS */
|
4919 |
if (imerge_list_or_tree(param, &tree1->merges, tree2)) |
|
4920 |
result= new SEL_TREE(SEL_TREE::ALWAYS); |
|
4921 |
else
|
|
4922 |
result= tree1; |
|
4923 |
}
|
|
4924 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4925 |
return(result); |
1
by brian
clean slate |
4926 |
}
|
4927 |
||
4928 |
||
4929 |
/* And key trees where key1->part < key2 -> part */
|
|
4930 |
||
4931 |
static SEL_ARG * |
|
4932 |
and_all_keys(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, |
|
4933 |
uint clone_flag) |
|
4934 |
{
|
|
4935 |
SEL_ARG *next; |
|
4936 |
ulong use_count=key1->use_count; |
|
4937 |
||
4938 |
if (key1->elements != 1) |
|
4939 |
{
|
|
4940 |
key2->use_count+=key1->elements-1; //psergey: why we don't count that key1 has n-k-p? |
|
4941 |
key2->increment_use_count((int) key1->elements-1); |
|
4942 |
}
|
|
4943 |
if (key1->type == SEL_ARG::MAYBE_KEY) |
|
4944 |
{
|
|
4945 |
key1->right= key1->left= &null_element; |
|
4946 |
key1->next= key1->prev= 0; |
|
4947 |
}
|
|
4948 |
for (next=key1->first(); next ; next=next->next) |
|
4949 |
{
|
|
4950 |
if (next->next_key_part) |
|
4951 |
{
|
|
4952 |
SEL_ARG *tmp= key_and(param, next->next_key_part, key2, clone_flag); |
|
4953 |
if (tmp && tmp->type == SEL_ARG::IMPOSSIBLE) |
|
4954 |
{
|
|
4955 |
key1=key1->tree_delete(next); |
|
4956 |
continue; |
|
4957 |
}
|
|
4958 |
next->next_key_part=tmp; |
|
4959 |
if (use_count) |
|
4960 |
next->increment_use_count(use_count); |
|
4961 |
if (param->alloced_sel_args > SEL_ARG::MAX_SEL_ARGS) |
|
4962 |
break; |
|
4963 |
}
|
|
4964 |
else
|
|
4965 |
next->next_key_part=key2; |
|
4966 |
}
|
|
4967 |
if (!key1) |
|
4968 |
return &null_element; // Impossible ranges |
|
4969 |
key1->use_count++; |
|
4970 |
return key1; |
|
4971 |
}
|
|
4972 |
||
4973 |
||
4974 |
/*
|
|
4975 |
Produce a SEL_ARG graph that represents "key1 AND key2"
|
|
4976 |
||
4977 |
SYNOPSIS
|
|
4978 |
key_and()
|
|
4979 |
param Range analysis context (needed to track if we have allocated
|
|
4980 |
too many SEL_ARGs)
|
|
4981 |
key1 First argument, root of its RB-tree
|
|
4982 |
key2 Second argument, root of its RB-tree
|
|
4983 |
||
4984 |
RETURN
|
|
4985 |
RB-tree root of the resulting SEL_ARG graph.
|
|
4986 |
NULL if the result of AND operation is an empty interval {0}.
|
|
4987 |
*/
|
|
4988 |
||
4989 |
static SEL_ARG * |
|
4990 |
key_and(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, uint clone_flag) |
|
4991 |
{
|
|
4992 |
if (!key1) |
|
4993 |
return key2; |
|
4994 |
if (!key2) |
|
4995 |
return key1; |
|
4996 |
if (key1->part != key2->part) |
|
4997 |
{
|
|
4998 |
if (key1->part > key2->part) |
|
4999 |
{
|
|
5000 |
swap_variables(SEL_ARG *, key1, key2); |
|
5001 |
clone_flag=swap_clone_flag(clone_flag); |
|
5002 |
}
|
|
5003 |
// key1->part < key2->part
|
|
5004 |
key1->use_count--; |
|
5005 |
if (key1->use_count > 0) |
|
5006 |
if (!(key1= key1->clone_tree(param))) |
|
5007 |
return 0; // OOM |
|
5008 |
return and_all_keys(param, key1, key2, clone_flag); |
|
5009 |
}
|
|
5010 |
||
5011 |
if (((clone_flag & CLONE_KEY2_MAYBE) && |
|
5012 |
!(clone_flag & CLONE_KEY1_MAYBE) && |
|
5013 |
key2->type != SEL_ARG::MAYBE_KEY) || |
|
5014 |
key1->type == SEL_ARG::MAYBE_KEY) |
|
5015 |
{ // Put simple key in key2 |
|
5016 |
swap_variables(SEL_ARG *, key1, key2); |
|
5017 |
clone_flag=swap_clone_flag(clone_flag); |
|
5018 |
}
|
|
5019 |
||
5020 |
/* If one of the key is MAYBE_KEY then the found region may be smaller */
|
|
5021 |
if (key2->type == SEL_ARG::MAYBE_KEY) |
|
5022 |
{
|
|
5023 |
if (key1->use_count > 1) |
|
5024 |
{
|
|
5025 |
key1->use_count--; |
|
5026 |
if (!(key1=key1->clone_tree(param))) |
|
5027 |
return 0; // OOM |
|
5028 |
key1->use_count++; |
|
5029 |
}
|
|
5030 |
if (key1->type == SEL_ARG::MAYBE_KEY) |
|
5031 |
{ // Both are maybe key |
|
5032 |
key1->next_key_part=key_and(param, key1->next_key_part, |
|
5033 |
key2->next_key_part, clone_flag); |
|
5034 |
if (key1->next_key_part && |
|
5035 |
key1->next_key_part->type == SEL_ARG::IMPOSSIBLE) |
|
5036 |
return key1; |
|
5037 |
}
|
|
5038 |
else
|
|
5039 |
{
|
|
5040 |
key1->maybe_smaller(); |
|
5041 |
if (key2->next_key_part) |
|
5042 |
{
|
|
5043 |
key1->use_count--; // Incremented in and_all_keys |
|
5044 |
return and_all_keys(param, key1, key2, clone_flag); |
|
5045 |
}
|
|
5046 |
key2->use_count--; // Key2 doesn't have a tree |
|
5047 |
}
|
|
5048 |
return key1; |
|
5049 |
}
|
|
5050 |
||
5051 |
key1->use_count--; |
|
5052 |
key2->use_count--; |
|
5053 |
SEL_ARG *e1=key1->first(), *e2=key2->first(), *new_tree=0; |
|
5054 |
||
5055 |
while (e1 && e2) |
|
5056 |
{
|
|
5057 |
int cmp=e1->cmp_min_to_min(e2); |
|
5058 |
if (cmp < 0) |
|
5059 |
{
|
|
5060 |
if (get_range(&e1,&e2,key1)) |
|
5061 |
continue; |
|
5062 |
}
|
|
5063 |
else if (get_range(&e2,&e1,key2)) |
|
5064 |
continue; |
|
5065 |
SEL_ARG *next=key_and(param, e1->next_key_part, e2->next_key_part, |
|
5066 |
clone_flag); |
|
5067 |
e1->increment_use_count(1); |
|
5068 |
e2->increment_use_count(1); |
|
5069 |
if (!next || next->type != SEL_ARG::IMPOSSIBLE) |
|
5070 |
{
|
|
5071 |
SEL_ARG *new_arg= e1->clone_and(e2); |
|
5072 |
if (!new_arg) |
|
5073 |
return &null_element; // End of memory |
|
5074 |
new_arg->next_key_part=next; |
|
5075 |
if (!new_tree) |
|
5076 |
{
|
|
5077 |
new_tree=new_arg; |
|
5078 |
}
|
|
5079 |
else
|
|
5080 |
new_tree=new_tree->insert(new_arg); |
|
5081 |
}
|
|
5082 |
if (e1->cmp_max_to_max(e2) < 0) |
|
5083 |
e1=e1->next; // e1 can't overlapp next e2 |
|
5084 |
else
|
|
5085 |
e2=e2->next; |
|
5086 |
}
|
|
5087 |
key1->free_tree(); |
|
5088 |
key2->free_tree(); |
|
5089 |
if (!new_tree) |
|
5090 |
return &null_element; // Impossible range |
|
5091 |
return new_tree; |
|
5092 |
}
|
|
5093 |
||
5094 |
||
5095 |
static bool |
|
5096 |
get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1) |
|
5097 |
{
|
|
5098 |
(*e1)=root1->find_range(*e2); // first e1->min < e2->min |
|
5099 |
if ((*e1)->cmp_max_to_min(*e2) < 0) |
|
5100 |
{
|
|
5101 |
if (!((*e1)=(*e1)->next)) |
|
5102 |
return 1; |
|
5103 |
if ((*e1)->cmp_min_to_max(*e2) > 0) |
|
5104 |
{
|
|
5105 |
(*e2)=(*e2)->next; |
|
5106 |
return 1; |
|
5107 |
}
|
|
5108 |
}
|
|
5109 |
return 0; |
|
5110 |
}
|
|
5111 |
||
5112 |
||
5113 |
static SEL_ARG * |
|
5114 |
key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) |
|
5115 |
{
|
|
5116 |
if (!key1) |
|
5117 |
{
|
|
5118 |
if (key2) |
|
5119 |
{
|
|
5120 |
key2->use_count--; |
|
5121 |
key2->free_tree(); |
|
5122 |
}
|
|
5123 |
return 0; |
|
5124 |
}
|
|
5125 |
if (!key2) |
|
5126 |
{
|
|
5127 |
key1->use_count--; |
|
5128 |
key1->free_tree(); |
|
5129 |
return 0; |
|
5130 |
}
|
|
5131 |
key1->use_count--; |
|
5132 |
key2->use_count--; |
|
5133 |
||
5134 |
if (key1->part != key2->part) |
|
5135 |
{
|
|
5136 |
key1->free_tree(); |
|
5137 |
key2->free_tree(); |
|
5138 |
return 0; // Can't optimize this |
|
5139 |
}
|
|
5140 |
||
5141 |
// If one of the key is MAYBE_KEY then the found region may be bigger
|
|
5142 |
if (key1->type == SEL_ARG::MAYBE_KEY) |
|
5143 |
{
|
|
5144 |
key2->free_tree(); |
|
5145 |
key1->use_count++; |
|
5146 |
return key1; |
|
5147 |
}
|
|
5148 |
if (key2->type == SEL_ARG::MAYBE_KEY) |
|
5149 |
{
|
|
5150 |
key1->free_tree(); |
|
5151 |
key2->use_count++; |
|
5152 |
return key2; |
|
5153 |
}
|
|
5154 |
||
5155 |
if (key1->use_count > 0) |
|
5156 |
{
|
|
5157 |
if (key2->use_count == 0 || key1->elements > key2->elements) |
|
5158 |
{
|
|
5159 |
swap_variables(SEL_ARG *,key1,key2); |
|
5160 |
}
|
|
5161 |
if (key1->use_count > 0 || !(key1=key1->clone_tree(param))) |
|
5162 |
return 0; // OOM |
|
5163 |
}
|
|
5164 |
||
5165 |
// Add tree at key2 to tree at key1
|
|
5166 |
bool key2_shared=key2->use_count != 0; |
|
5167 |
key1->maybe_flag|=key2->maybe_flag; |
|
5168 |
||
5169 |
for (key2=key2->first(); key2; ) |
|
5170 |
{
|
|
5171 |
SEL_ARG *tmp=key1->find_range(key2); // Find key1.min <= key2.min |
|
5172 |
int cmp; |
|
5173 |
||
5174 |
if (!tmp) |
|
5175 |
{
|
|
5176 |
tmp=key1->first(); // tmp.min > key2.min |
|
5177 |
cmp= -1; |
|
5178 |
}
|
|
5179 |
else if ((cmp=tmp->cmp_max_to_min(key2)) < 0) |
|
5180 |
{ // Found tmp.max < key2.min |
|
5181 |
SEL_ARG *next=tmp->next; |
|
5182 |
if (cmp == -2 && eq_tree(tmp->next_key_part,key2->next_key_part)) |
|
5183 |
{
|
|
5184 |
// Join near ranges like tmp.max < 0 and key2.min >= 0
|
|
5185 |
SEL_ARG *key2_next=key2->next; |
|
5186 |
if (key2_shared) |
|
5187 |
{
|
|
5188 |
if (!(key2=new SEL_ARG(*key2))) |
|
5189 |
return 0; // out of memory |
|
5190 |
key2->increment_use_count(key1->use_count+1); |
|
5191 |
key2->next=key2_next; // New copy of key2 |
|
5192 |
}
|
|
5193 |
key2->copy_min(tmp); |
|
5194 |
if (!(key1=key1->tree_delete(tmp))) |
|
5195 |
{ // Only one key in tree |
|
5196 |
key1=key2; |
|
5197 |
key1->make_root(); |
|
5198 |
key2=key2_next; |
|
5199 |
break; |
|
5200 |
}
|
|
5201 |
}
|
|
5202 |
if (!(tmp=next)) // tmp.min > key2.min |
|
5203 |
break; // Copy rest of key2 |
|
5204 |
}
|
|
5205 |
if (cmp < 0) |
|
5206 |
{ // tmp.min > key2.min |
|
5207 |
int tmp_cmp; |
|
5208 |
if ((tmp_cmp=tmp->cmp_min_to_max(key2)) > 0) // if tmp.min > key2.max |
|
5209 |
{
|
|
5210 |
if (tmp_cmp == 2 && eq_tree(tmp->next_key_part,key2->next_key_part)) |
|
5211 |
{ // ranges are connected |
|
5212 |
tmp->copy_min_to_min(key2); |
|
5213 |
key1->merge_flags(key2); |
|
5214 |
if (tmp->min_flag & NO_MIN_RANGE && |
|
5215 |
tmp->max_flag & NO_MAX_RANGE) |
|
5216 |
{
|
|
5217 |
if (key1->maybe_flag) |
|
5218 |
return new SEL_ARG(SEL_ARG::MAYBE_KEY); |
|
5219 |
return 0; |
|
5220 |
}
|
|
5221 |
key2->increment_use_count(-1); // Free not used tree |
|
5222 |
key2=key2->next; |
|
5223 |
continue; |
|
5224 |
}
|
|
5225 |
else
|
|
5226 |
{
|
|
5227 |
SEL_ARG *next=key2->next; // Keys are not overlapping |
|
5228 |
if (key2_shared) |
|
5229 |
{
|
|
5230 |
SEL_ARG *cpy= new SEL_ARG(*key2); // Must make copy |
|
5231 |
if (!cpy) |
|
5232 |
return 0; // OOM |
|
5233 |
key1=key1->insert(cpy); |
|
5234 |
key2->increment_use_count(key1->use_count+1); |
|
5235 |
}
|
|
5236 |
else
|
|
5237 |
key1=key1->insert(key2); // Will destroy key2_root |
|
5238 |
key2=next; |
|
5239 |
continue; |
|
5240 |
}
|
|
5241 |
}
|
|
5242 |
}
|
|
5243 |
||
5244 |
// tmp.max >= key2.min && tmp.min <= key.max (overlapping ranges)
|
|
5245 |
if (eq_tree(tmp->next_key_part,key2->next_key_part)) |
|
5246 |
{
|
|
5247 |
if (tmp->is_same(key2)) |
|
5248 |
{
|
|
5249 |
tmp->merge_flags(key2); // Copy maybe flags |
|
5250 |
key2->increment_use_count(-1); // Free not used tree |
|
5251 |
}
|
|
5252 |
else
|
|
5253 |
{
|
|
5254 |
SEL_ARG *last=tmp; |
|
5255 |
while (last->next && last->next->cmp_min_to_max(key2) <= 0 && |
|
5256 |
eq_tree(last->next->next_key_part,key2->next_key_part)) |
|
5257 |
{
|
|
5258 |
SEL_ARG *save=last; |
|
5259 |
last=last->next; |
|
5260 |
key1=key1->tree_delete(save); |
|
5261 |
}
|
|
5262 |
last->copy_min(tmp); |
|
5263 |
if (last->copy_min(key2) || last->copy_max(key2)) |
|
5264 |
{ // Full range |
|
5265 |
key1->free_tree(); |
|
5266 |
for (; key2 ; key2=key2->next) |
|
5267 |
key2->increment_use_count(-1); // Free not used tree |
|
5268 |
if (key1->maybe_flag) |
|
5269 |
return new SEL_ARG(SEL_ARG::MAYBE_KEY); |
|
5270 |
return 0; |
|
5271 |
}
|
|
5272 |
}
|
|
5273 |
key2=key2->next; |
|
5274 |
continue; |
|
5275 |
}
|
|
5276 |
||
5277 |
if (cmp >= 0 && tmp->cmp_min_to_min(key2) < 0) |
|
5278 |
{ // tmp.min <= x < key2.min |
|
5279 |
SEL_ARG *new_arg=tmp->clone_first(key2); |
|
5280 |
if (!new_arg) |
|
5281 |
return 0; // OOM |
|
5282 |
if ((new_arg->next_key_part= key1->next_key_part)) |
|
5283 |
new_arg->increment_use_count(key1->use_count+1); |
|
5284 |
tmp->copy_min_to_min(key2); |
|
5285 |
key1=key1->insert(new_arg); |
|
5286 |
}
|
|
5287 |
||
5288 |
// tmp.min >= key2.min && tmp.min <= key2.max
|
|
5289 |
SEL_ARG key(*key2); // Get copy we can modify |
|
5290 |
for (;;) |
|
5291 |
{
|
|
5292 |
if (tmp->cmp_min_to_min(&key) > 0) |
|
5293 |
{ // key.min <= x < tmp.min |
|
5294 |
SEL_ARG *new_arg=key.clone_first(tmp); |
|
5295 |
if (!new_arg) |
|
5296 |
return 0; // OOM |
|
5297 |
if ((new_arg->next_key_part=key.next_key_part)) |
|
5298 |
new_arg->increment_use_count(key1->use_count+1); |
|
5299 |
key1=key1->insert(new_arg); |
|
5300 |
}
|
|
5301 |
if ((cmp=tmp->cmp_max_to_max(&key)) <= 0) |
|
5302 |
{ // tmp.min. <= x <= tmp.max |
|
5303 |
tmp->maybe_flag|= key.maybe_flag; |
|
5304 |
key.increment_use_count(key1->use_count+1); |
|
5305 |
tmp->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part); |
|
5306 |
if (!cmp) // Key2 is ready |
|
5307 |
break; |
|
5308 |
key.copy_max_to_min(tmp); |
|
5309 |
if (!(tmp=tmp->next)) |
|
5310 |
{
|
|
5311 |
SEL_ARG *tmp2= new SEL_ARG(key); |
|
5312 |
if (!tmp2) |
|
5313 |
return 0; // OOM |
|
5314 |
key1=key1->insert(tmp2); |
|
5315 |
key2=key2->next; |
|
5316 |
goto end; |
|
5317 |
}
|
|
5318 |
if (tmp->cmp_min_to_max(&key) > 0) |
|
5319 |
{
|
|
5320 |
SEL_ARG *tmp2= new SEL_ARG(key); |
|
5321 |
if (!tmp2) |
|
5322 |
return 0; // OOM |
|
5323 |
key1=key1->insert(tmp2); |
|
5324 |
break; |
|
5325 |
}
|
|
5326 |
}
|
|
5327 |
else
|
|
5328 |
{
|
|
5329 |
SEL_ARG *new_arg=tmp->clone_last(&key); // tmp.min <= x <= key.max |
|
5330 |
if (!new_arg) |
|
5331 |
return 0; // OOM |
|
5332 |
tmp->copy_max_to_min(&key); |
|
5333 |
tmp->increment_use_count(key1->use_count+1); |
|
5334 |
/* Increment key count as it may be used for next loop */
|
|
5335 |
key.increment_use_count(1); |
|
5336 |
new_arg->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part); |
|
5337 |
key1=key1->insert(new_arg); |
|
5338 |
break; |
|
5339 |
}
|
|
5340 |
}
|
|
5341 |
key2=key2->next; |
|
5342 |
}
|
|
5343 |
||
5344 |
end: |
|
5345 |
while (key2) |
|
5346 |
{
|
|
5347 |
SEL_ARG *next=key2->next; |
|
5348 |
if (key2_shared) |
|
5349 |
{
|
|
5350 |
SEL_ARG *tmp=new SEL_ARG(*key2); // Must make copy |
|
5351 |
if (!tmp) |
|
5352 |
return 0; |
|
5353 |
key2->increment_use_count(key1->use_count+1); |
|
5354 |
key1=key1->insert(tmp); |
|
5355 |
}
|
|
5356 |
else
|
|
5357 |
key1=key1->insert(key2); // Will destroy key2_root |
|
5358 |
key2=next; |
|
5359 |
}
|
|
5360 |
key1->use_count++; |
|
5361 |
return key1; |
|
5362 |
}
|
|
5363 |
||
5364 |
||
5365 |
/* Compare if two trees are equal */
|
|
5366 |
||
5367 |
static bool eq_tree(SEL_ARG* a,SEL_ARG *b) |
|
5368 |
{
|
|
5369 |
if (a == b) |
|
5370 |
return 1; |
|
5371 |
if (!a || !b || !a->is_same(b)) |
|
5372 |
return 0; |
|
5373 |
if (a->left != &null_element && b->left != &null_element) |
|
5374 |
{
|
|
5375 |
if (!eq_tree(a->left,b->left)) |
|
5376 |
return 0; |
|
5377 |
}
|
|
5378 |
else if (a->left != &null_element || b->left != &null_element) |
|
5379 |
return 0; |
|
5380 |
if (a->right != &null_element && b->right != &null_element) |
|
5381 |
{
|
|
5382 |
if (!eq_tree(a->right,b->right)) |
|
5383 |
return 0; |
|
5384 |
}
|
|
5385 |
else if (a->right != &null_element || b->right != &null_element) |
|
5386 |
return 0; |
|
5387 |
if (a->next_key_part != b->next_key_part) |
|
5388 |
{ // Sub range |
|
5389 |
if (!a->next_key_part != !b->next_key_part || |
|
5390 |
!eq_tree(a->next_key_part, b->next_key_part)) |
|
5391 |
return 0; |
|
5392 |
}
|
|
5393 |
return 1; |
|
5394 |
}
|
|
5395 |
||
5396 |
||
5397 |
SEL_ARG * |
|
5398 |
SEL_ARG::insert(SEL_ARG *key) |
|
5399 |
{
|
|
5400 |
SEL_ARG *element, **par= NULL, *last_element= NULL; |
|
5401 |
||
5402 |
for (element= this; element != &null_element ; ) |
|
5403 |
{
|
|
5404 |
last_element=element; |
|
5405 |
if (key->cmp_min_to_min(element) > 0) |
|
5406 |
{
|
|
5407 |
par= &element->right; element= element->right; |
|
5408 |
}
|
|
5409 |
else
|
|
5410 |
{
|
|
5411 |
par = &element->left; element= element->left; |
|
5412 |
}
|
|
5413 |
}
|
|
5414 |
*par=key; |
|
5415 |
key->parent=last_element; |
|
5416 |
/* Link in list */
|
|
5417 |
if (par == &last_element->left) |
|
5418 |
{
|
|
5419 |
key->next=last_element; |
|
5420 |
if ((key->prev=last_element->prev)) |
|
5421 |
key->prev->next=key; |
|
5422 |
last_element->prev=key; |
|
5423 |
}
|
|
5424 |
else
|
|
5425 |
{
|
|
5426 |
if ((key->next=last_element->next)) |
|
5427 |
key->next->prev=key; |
|
5428 |
key->prev=last_element; |
|
5429 |
last_element->next=key; |
|
5430 |
}
|
|
5431 |
key->left=key->right= &null_element; |
|
5432 |
SEL_ARG *root=rb_insert(key); // rebalance tree |
|
5433 |
root->use_count=this->use_count; // copy root info |
|
5434 |
root->elements= this->elements+1; |
|
5435 |
root->maybe_flag=this->maybe_flag; |
|
5436 |
return root; |
|
5437 |
}
|
|
5438 |
||
5439 |
||
5440 |
/*
|
|
5441 |
** Find best key with min <= given key
|
|
5442 |
** Because the call context this should never return 0 to get_range
|
|
5443 |
*/
|
|
5444 |
||
5445 |
SEL_ARG * |
|
5446 |
SEL_ARG::find_range(SEL_ARG *key) |
|
5447 |
{
|
|
5448 |
SEL_ARG *element=this,*found=0; |
|
5449 |
||
5450 |
for (;;) |
|
5451 |
{
|
|
5452 |
if (element == &null_element) |
|
5453 |
return found; |
|
5454 |
int cmp=element->cmp_min_to_min(key); |
|
5455 |
if (cmp == 0) |
|
5456 |
return element; |
|
5457 |
if (cmp < 0) |
|
5458 |
{
|
|
5459 |
found=element; |
|
5460 |
element=element->right; |
|
5461 |
}
|
|
5462 |
else
|
|
5463 |
element=element->left; |
|
5464 |
}
|
|
5465 |
}
|
|
5466 |
||
5467 |
||
5468 |
/*
|
|
5469 |
Remove a element from the tree
|
|
5470 |
||
5471 |
SYNOPSIS
|
|
5472 |
tree_delete()
|
|
5473 |
key Key that is to be deleted from tree (this)
|
|
5474 |
||
5475 |
NOTE
|
|
5476 |
This also frees all sub trees that is used by the element
|
|
5477 |
||
5478 |
RETURN
|
|
5479 |
root of new tree (with key deleted)
|
|
5480 |
*/
|
|
5481 |
||
5482 |
SEL_ARG * |
|
5483 |
SEL_ARG::tree_delete(SEL_ARG *key) |
|
5484 |
{
|
|
5485 |
enum leaf_color remove_color; |
|
5486 |
SEL_ARG *root,*nod,**par,*fix_par; |
|
5487 |
||
5488 |
root=this; |
|
5489 |
this->parent= 0; |
|
5490 |
||
5491 |
/* Unlink from list */
|
|
5492 |
if (key->prev) |
|
5493 |
key->prev->next=key->next; |
|
5494 |
if (key->next) |
|
5495 |
key->next->prev=key->prev; |
|
5496 |
key->increment_use_count(-1); |
|
5497 |
if (!key->parent) |
|
5498 |
par= &root; |
|
5499 |
else
|
|
5500 |
par=key->parent_ptr(); |
|
5501 |
||
5502 |
if (key->left == &null_element) |
|
5503 |
{
|
|
5504 |
*par=nod=key->right; |
|
5505 |
fix_par=key->parent; |
|
5506 |
if (nod != &null_element) |
|
5507 |
nod->parent=fix_par; |
|
5508 |
remove_color= key->color; |
|
5509 |
}
|
|
5510 |
else if (key->right == &null_element) |
|
5511 |
{
|
|
5512 |
*par= nod=key->left; |
|
5513 |
nod->parent=fix_par=key->parent; |
|
5514 |
remove_color= key->color; |
|
5515 |
}
|
|
5516 |
else
|
|
5517 |
{
|
|
5518 |
SEL_ARG *tmp=key->next; // next bigger key (exist!) |
|
5519 |
nod= *tmp->parent_ptr()= tmp->right; // unlink tmp from tree |
|
5520 |
fix_par=tmp->parent; |
|
5521 |
if (nod != &null_element) |
|
5522 |
nod->parent=fix_par; |
|
5523 |
remove_color= tmp->color; |
|
5524 |
||
5525 |
tmp->parent=key->parent; // Move node in place of key |
|
5526 |
(tmp->left=key->left)->parent=tmp; |
|
5527 |
if ((tmp->right=key->right) != &null_element) |
|
5528 |
tmp->right->parent=tmp; |
|
5529 |
tmp->color=key->color; |
|
5530 |
*par=tmp; |
|
5531 |
if (fix_par == key) // key->right == key->next |
|
5532 |
fix_par=tmp; // new parent of nod |
|
5533 |
}
|
|
5534 |
||
5535 |
if (root == &null_element) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
5536 |
return(0); // Maybe root later |
1
by brian
clean slate |
5537 |
if (remove_color == BLACK) |
5538 |
root=rb_delete_fixup(root,nod,fix_par); |
|
5539 |
test_rb_tree(root,root->parent); |
|
5540 |
||
5541 |
root->use_count=this->use_count; // Fix root counters |
|
5542 |
root->elements=this->elements-1; |
|
5543 |
root->maybe_flag=this->maybe_flag; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
5544 |
return(root); |
1
by brian
clean slate |
5545 |
}
|
5546 |
||
5547 |
||
5548 |
/* Functions to fix up the tree after insert and delete */
|
|
5549 |
||
5550 |
static void left_rotate(SEL_ARG **root,SEL_ARG *leaf) |
|
5551 |
{
|
|
5552 |
SEL_ARG *y=leaf->right; |
|
5553 |
leaf->right=y->left; |
|
5554 |
if (y->left != &null_element) |
|
5555 |
y->left->parent=leaf; |
|
5556 |
if (!(y->parent=leaf->parent)) |
|
5557 |
*root=y; |
|
5558 |
else
|
|
5559 |
*leaf->parent_ptr()=y; |
|
5560 |
y->left=leaf; |
|
5561 |
leaf->parent=y; |
|
5562 |
}
|
|
5563 |
||
5564 |
static void right_rotate(SEL_ARG **root,SEL_ARG *leaf) |
|
5565 |
{
|
|
5566 |
SEL_ARG *y=leaf->left; |
|
5567 |
leaf->left=y->right; |
|
5568 |
if (y->right != &null_element) |
|
5569 |
y->right->parent=leaf; |
|
5570 |
if (!(y->parent=leaf->parent)) |
|
5571 |
*root=y; |
|
5572 |
else
|
|
5573 |
*leaf->parent_ptr()=y; |
|
5574 |
y->right=leaf; |
|
5575 |
leaf->parent=y; |
|
5576 |
}
|
|
5577 |
||
5578 |
||
5579 |
SEL_ARG * |
|
5580 |
SEL_ARG::rb_insert(SEL_ARG *leaf) |
|
5581 |
{
|
|
5582 |
SEL_ARG *y,*par,*par2,*root; |
|
5583 |
root= this; root->parent= 0; |
|
5584 |
||
5585 |
leaf->color=RED; |
|
5586 |
while (leaf != root && (par= leaf->parent)->color == RED) |
|
5587 |
{ // This can't be root or 1 level under |
|
5588 |
if (par == (par2= leaf->parent->parent)->left) |
|
5589 |
{
|
|
5590 |
y= par2->right; |
|
5591 |
if (y->color == RED) |
|
5592 |
{
|
|
5593 |
par->color=BLACK; |
|
5594 |
y->color=BLACK; |
|
5595 |
leaf=par2; |
|
5596 |
leaf->color=RED; /* And the loop continues */ |
|
5597 |
}
|
|
5598 |
else
|
|
5599 |
{
|
|
5600 |
if (leaf == par->right) |
|
5601 |
{
|
|
5602 |
left_rotate(&root,leaf->parent); |
|
5603 |
par=leaf; /* leaf is now parent to old leaf */ |
|
5604 |
}
|
|
5605 |
par->color=BLACK; |
|
5606 |
par2->color=RED; |
|
5607 |
right_rotate(&root,par2); |
|
5608 |
break; |
|
5609 |
}
|
|
5610 |
}
|
|
5611 |
else
|
|
5612 |
{
|
|
5613 |
y= par2->left; |
|
5614 |
if (y->color == RED) |
|
5615 |
{
|
|
5616 |
par->color=BLACK; |
|
5617 |
y->color=BLACK; |
|
5618 |
leaf=par2; |
|
5619 |
leaf->color=RED; /* And the loop continues */ |
|
5620 |
}
|
|
5621 |
else
|
|
5622 |
{
|
|
5623 |
if (leaf == par->left) |
|
5624 |
{
|
|
5625 |
right_rotate(&root,par); |
|
5626 |
par=leaf; |
|
5627 |
}
|
|
5628 |
par->color=BLACK; |
|
5629 |
par2->color=RED; |
|
5630 |
left_rotate(&root,par2); |
|
5631 |
break; |
|
5632 |
}
|
|
5633 |
}
|
|
5634 |
}
|
|
5635 |
root->color=BLACK; |
|
5636 |
test_rb_tree(root,root->parent); |
|
5637 |
return root; |
|
5638 |
}
|
|
5639 |
||
5640 |
||
5641 |
SEL_ARG *rb_delete_fixup(SEL_ARG *root,SEL_ARG *key,SEL_ARG *par) |
|
5642 |
{
|
|
5643 |
SEL_ARG *x,*w; |
|
5644 |
root->parent=0; |
|
5645 |
||
5646 |
x= key; |
|
5647 |
while (x != root && x->color == SEL_ARG::BLACK) |
|
5648 |
{
|
|
5649 |
if (x == par->left) |
|
5650 |
{
|
|
5651 |
w=par->right; |
|
5652 |
if (w->color == SEL_ARG::RED) |
|
5653 |
{
|
|
5654 |
w->color=SEL_ARG::BLACK; |
|
5655 |
par->color=SEL_ARG::RED; |
|
5656 |
left_rotate(&root,par); |
|
5657 |
w=par->right; |
|
5658 |
}
|
|
5659 |
if (w->left->color == SEL_ARG::BLACK && w->right->color == SEL_ARG::BLACK) |
|
5660 |
{
|
|
5661 |
w->color=SEL_ARG::RED; |
|
5662 |
x=par; |
|
5663 |
}
|
|
5664 |
else
|
|
5665 |
{
|
|
5666 |
if (w->right->color == SEL_ARG::BLACK) |
|
5667 |
{
|
|
5668 |
w->left->color=SEL_ARG::BLACK; |
|
5669 |
w->color=SEL_ARG::RED; |
|
5670 |
right_rotate(&root,w); |
|
5671 |
w=par->right; |
|
5672 |
}
|
|
5673 |
w->color=par->color; |
|
5674 |
par->color=SEL_ARG::BLACK; |
|
5675 |
w->right->color=SEL_ARG::BLACK; |
|
5676 |
left_rotate(&root,par); |
|
5677 |
x=root; |
|
5678 |
break; |
|
5679 |
}
|
|
5680 |
}
|
|
5681 |
else
|
|
5682 |
{
|
|
5683 |
w=par->left; |
|
5684 |
if (w->color == SEL_ARG::RED) |
|
5685 |
{
|
|
5686 |
w->color=SEL_ARG::BLACK; |
|
5687 |
par->color=SEL_ARG::RED; |
|
5688 |
right_rotate(&root,par); |
|
5689 |
w=par->left; |
|
5690 |
}
|
|
5691 |
if (w->right->color == SEL_ARG::BLACK && w->left->color == SEL_ARG::BLACK) |
|
5692 |
{
|
|
5693 |
w->color=SEL_ARG::RED; |
|
5694 |
x=par; |
|
5695 |
}
|
|
5696 |
else
|
|
5697 |
{
|
|
5698 |
if (w->left->color == SEL_ARG::BLACK) |
|
5699 |
{
|
|
5700 |
w->right->color=SEL_ARG::BLACK; |
|
5701 |
w->color=SEL_ARG::RED; |
|
5702 |
left_rotate(&root,w); |
|
5703 |
w=par->left; |
|
5704 |
}
|
|
5705 |
w->color=par->color; |
|
5706 |
par->color=SEL_ARG::BLACK; |
|
5707 |
w->left->color=SEL_ARG::BLACK; |
|
5708 |
right_rotate(&root,par); |
|
5709 |
x=root; |
|
5710 |
break; |
|
5711 |
}
|
|
5712 |
}
|
|
5713 |
par=x->parent; |
|
5714 |
}
|
|
5715 |
x->color=SEL_ARG::BLACK; |
|
5716 |
return root; |
|
5717 |
}
|
|
5718 |
||
5719 |
||
5720 |
/* Test that the properties for a red-black tree hold */
|
|
5721 |
||
5722 |
#ifdef EXTRA_DEBUG
|
|
5723 |
int test_rb_tree(SEL_ARG *element,SEL_ARG *parent) |
|
5724 |
{
|
|
5725 |
int count_l,count_r; |
|
5726 |
||
5727 |
if (element == &null_element) |
|
5728 |
return 0; // Found end of tree |
|
5729 |
if (element->parent != parent) |
|
5730 |
{
|
|
5731 |
sql_print_error("Wrong tree: Parent doesn't point at parent"); |
|
5732 |
return -1; |
|
5733 |
}
|
|
5734 |
if (element->color == SEL_ARG::RED && |
|
5735 |
(element->left->color == SEL_ARG::RED || |
|
5736 |
element->right->color == SEL_ARG::RED)) |
|
5737 |
{
|
|
5738 |
sql_print_error("Wrong tree: Found two red in a row"); |
|
5739 |
return -1; |
|
5740 |
}
|
|
5741 |
if (element->left == element->right && element->left != &null_element) |
|
5742 |
{ // Dummy test |
|
5743 |
sql_print_error("Wrong tree: Found right == left"); |
|
5744 |
return -1; |
|
5745 |
}
|
|
5746 |
count_l=test_rb_tree(element->left,element); |
|
5747 |
count_r=test_rb_tree(element->right,element); |
|
5748 |
if (count_l >= 0 && count_r >= 0) |
|
5749 |
{
|
|
5750 |
if (count_l == count_r) |
|
5751 |
return count_l+(element->color == SEL_ARG::BLACK); |
|
5752 |
sql_print_error("Wrong tree: Incorrect black-count: %d - %d", |
|
5753 |
count_l,count_r); |
|
5754 |
}
|
|
5755 |
return -1; // Error, no more warnings |
|
5756 |
}
|
|
5757 |
||
5758 |
||
5759 |
/*
|
|
5760 |
Count how many times SEL_ARG graph "root" refers to its part "key"
|
|
5761 |
|
|
5762 |
SYNOPSIS
|
|
5763 |
count_key_part_usage()
|
|
5764 |
root An RB-Root node in a SEL_ARG graph.
|
|
5765 |
key Another RB-Root node in that SEL_ARG graph.
|
|
5766 |
||
5767 |
DESCRIPTION
|
|
5768 |
The passed "root" node may refer to "key" node via root->next_key_part,
|
|
5769 |
root->next->n
|
|
5770 |
||
5771 |
This function counts how many times the node "key" is referred (via
|
|
5772 |
SEL_ARG::next_key_part) by
|
|
5773 |
- intervals of RB-tree pointed by "root",
|
|
5774 |
- intervals of RB-trees that are pointed by SEL_ARG::next_key_part from
|
|
5775 |
intervals of RB-tree pointed by "root",
|
|
5776 |
- and so on.
|
|
5777 |
|
|
5778 |
Here is an example (horizontal links represent next_key_part pointers,
|
|
5779 |
vertical links - next/prev prev pointers):
|
|
5780 |
|
|
5781 |
+----+ $
|
|
5782 |
|root|-----------------+
|
|
5783 |
+----+ $ |
|
|
5784 |
| $ |
|
|
5785 |
| $ |
|
|
5786 |
+----+ +---+ $ | +---+ Here the return value
|
|
5787 |
| |- ... -| |---$-+--+->|key| will be 4.
|
|
5788 |
+----+ +---+ $ | | +---+
|
|
5789 |
| $ | |
|
|
5790 |
... $ | |
|
|
5791 |
| $ | |
|
|
5792 |
+----+ +---+ $ | |
|
|
5793 |
| |---| |---------+ |
|
|
5794 |
+----+ +---+ $ |
|
|
5795 |
| | $ |
|
|
5796 |
... +---+ $ |
|
|
5797 |
| |------------+
|
|
5798 |
+---+ $
|
|
5799 |
RETURN
|
|
5800 |
Number of links to "key" from nodes reachable from "root".
|
|
5801 |
*/
|
|
5802 |
||
5803 |
static ulong count_key_part_usage(SEL_ARG *root, SEL_ARG *key) |
|
5804 |
{
|
|
5805 |
ulong count= 0; |
|
5806 |
for (root=root->first(); root ; root=root->next) |
|
5807 |
{
|
|
5808 |
if (root->next_key_part) |
|
5809 |
{
|
|
5810 |
if (root->next_key_part == key) |
|
5811 |
count++; |
|
5812 |
if (root->next_key_part->part < key->part) |
|
5813 |
count+=count_key_part_usage(root->next_key_part,key); |
|
5814 |
}
|
|
5815 |
}
|
|
5816 |
return count; |
|
5817 |
}
|
|
5818 |
||
5819 |
||
5820 |
/*
|
|
5821 |
Check if SEL_ARG::use_count value is correct
|
|
5822 |
||
5823 |
SYNOPSIS
|
|
5824 |
SEL_ARG::test_use_count()
|
|
5825 |
root The root node of the SEL_ARG graph (an RB-tree root node that
|
|
5826 |
has the least value of sel_arg->part in the entire graph, and
|
|
5827 |
thus is the "origin" of the graph)
|
|
5828 |
||
5829 |
DESCRIPTION
|
|
5830 |
Check if SEL_ARG::use_count value is correct. See the definition of
|
|
5831 |
use_count for what is "correct".
|
|
5832 |
*/
|
|
5833 |
||
5834 |
void SEL_ARG::test_use_count(SEL_ARG *root) |
|
5835 |
{
|
|
5836 |
uint e_count=0; |
|
5837 |
if (this == root && use_count != 1) |
|
5838 |
{
|
|
5839 |
sql_print_information("Use_count: Wrong count %lu for root",use_count); |
|
5840 |
return; |
|
5841 |
}
|
|
5842 |
if (this->type != SEL_ARG::KEY_RANGE) |
|
5843 |
return; |
|
5844 |
for (SEL_ARG *pos=first(); pos ; pos=pos->next) |
|
5845 |
{
|
|
5846 |
e_count++; |
|
5847 |
if (pos->next_key_part) |
|
5848 |
{
|
|
5849 |
ulong count=count_key_part_usage(root,pos->next_key_part); |
|
5850 |
if (count > pos->next_key_part->use_count) |
|
5851 |
{
|
|
5852 |
sql_print_information("Use_count: Wrong count for key at 0x%lx, %lu " |
|
5853 |
"should be %lu", (long unsigned int)pos, |
|
5854 |
pos->next_key_part->use_count, count); |
|
5855 |
return; |
|
5856 |
}
|
|
5857 |
pos->next_key_part->test_use_count(root); |
|
5858 |
}
|
|
5859 |
}
|
|
5860 |
if (e_count != elements) |
|
5861 |
sql_print_warning("Wrong use count: %u (should be %u) for tree at 0x%lx", |
|
5862 |
e_count, elements, (long unsigned int) this); |
|
5863 |
}
|
|
5864 |
||
5865 |
#endif
|
|
5866 |
||
5867 |
/****************************************************************************
|
|
5868 |
MRR Range Sequence Interface implementation that walks a SEL_ARG* tree.
|
|
5869 |
****************************************************************************/
|
|
5870 |
||
5871 |
/* MRR range sequence, SEL_ARG* implementation: stack entry */
|
|
5872 |
typedef struct st_range_seq_entry |
|
5873 |
{
|
|
5874 |
/*
|
|
5875 |
Pointers in min and max keys. They point to right-after-end of key
|
|
5876 |
images. The 0-th entry has these pointing to key tuple start.
|
|
5877 |
*/
|
|
5878 |
uchar *min_key, *max_key; |
|
5879 |
||
5880 |
/*
|
|
5881 |
Flags, for {keypart0, keypart1, ... this_keypart} subtuple.
|
|
5882 |
min_key_flag may have NULL_RANGE set.
|
|
5883 |
*/
|
|
5884 |
uint min_key_flag, max_key_flag; |
|
5885 |
||
5886 |
/* Number of key parts */
|
|
5887 |
uint min_key_parts, max_key_parts; |
|
5888 |
SEL_ARG *key_tree; |
|
5889 |
} RANGE_SEQ_ENTRY; |
|
5890 |
||
5891 |
||
5892 |
/*
|
|
5893 |
MRR range sequence, SEL_ARG* implementation: SEL_ARG graph traversal context
|
|
5894 |
*/
|
|
5895 |
typedef struct st_sel_arg_range_seq |
|
5896 |
{
|
|
5897 |
uint keyno; /* index of used tree in SEL_TREE structure */ |
|
5898 |
uint real_keyno; /* Number of the index in tables */ |
|
5899 |
PARAM *param; |
|
5900 |
SEL_ARG *start; /* Root node of the traversed SEL_ARG* graph */ |
|
5901 |
||
5902 |
RANGE_SEQ_ENTRY stack[MAX_REF_PARTS]; |
|
5903 |
int i; /* Index of last used element in the above array */ |
|
5904 |
||
55
by brian
Update for using real bool types. |
5905 |
bool at_start; /* true <=> The traversal has just started */ |
1
by brian
clean slate |
5906 |
} SEL_ARG_RANGE_SEQ; |
5907 |
||
5908 |
||
5909 |
/*
|
|
5910 |
Range sequence interface, SEL_ARG* implementation: Initialize the traversal
|
|
5911 |
||
5912 |
SYNOPSIS
|
|
5913 |
init()
|
|
5914 |
init_params SEL_ARG tree traversal context
|
|
5915 |
n_ranges [ignored] The number of ranges obtained
|
|
5916 |
flags [ignored] HA_MRR_SINGLE_POINT, HA_MRR_FIXED_KEY
|
|
5917 |
||
5918 |
RETURN
|
|
5919 |
Value of init_param
|
|
5920 |
*/
|
|
5921 |
||
77.1.46
by Monty Taylor
Finished the warnings work! |
5922 |
range_seq_t sel_arg_range_seq_init(void *init_param, |
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
5923 |
uint n_ranges __attribute__((unused)), |
5924 |
uint flags __attribute__((unused))) |
|
1
by brian
clean slate |
5925 |
{
|
5926 |
SEL_ARG_RANGE_SEQ *seq= (SEL_ARG_RANGE_SEQ*)init_param; |
|
55
by brian
Update for using real bool types. |
5927 |
seq->at_start= true; |
1
by brian
clean slate |
5928 |
seq->stack[0].key_tree= NULL; |
5929 |
seq->stack[0].min_key= seq->param->min_key; |
|
5930 |
seq->stack[0].min_key_flag= 0; |
|
5931 |
seq->stack[0].min_key_parts= 0; |
|
5932 |
||
5933 |
seq->stack[0].max_key= seq->param->max_key; |
|
5934 |
seq->stack[0].max_key_flag= 0; |
|
5935 |
seq->stack[0].max_key_parts= 0; |
|
5936 |
seq->i= 0; |
|
5937 |
return init_param; |
|
5938 |
}
|
|
5939 |
||
5940 |
||
5941 |
static void step_down_to(SEL_ARG_RANGE_SEQ *arg, SEL_ARG *key_tree) |
|
5942 |
{
|
|
5943 |
RANGE_SEQ_ENTRY *cur= &arg->stack[arg->i+1]; |
|
5944 |
RANGE_SEQ_ENTRY *prev= &arg->stack[arg->i]; |
|
5945 |
||
5946 |
cur->key_tree= key_tree; |
|
5947 |
cur->min_key= prev->min_key; |
|
5948 |
cur->max_key= prev->max_key; |
|
5949 |
cur->min_key_parts= prev->min_key_parts; |
|
5950 |
cur->max_key_parts= prev->max_key_parts; |
|
5951 |
||
206
by Brian Aker
Removed final uint dead types. |
5952 |
uint16_t stor_length= arg->param->key[arg->keyno][key_tree->part].store_length; |
1
by brian
clean slate |
5953 |
cur->min_key_parts += key_tree->store_min(stor_length, &cur->min_key, |
5954 |
prev->min_key_flag); |
|
5955 |
cur->max_key_parts += key_tree->store_max(stor_length, &cur->max_key, |
|
5956 |
prev->max_key_flag); |
|
5957 |
||
5958 |
cur->min_key_flag= prev->min_key_flag | key_tree->min_flag; |
|
5959 |
cur->max_key_flag= prev->max_key_flag | key_tree->max_flag; |
|
5960 |
||
5961 |
if (key_tree->is_null_interval()) |
|
5962 |
cur->min_key_flag |= NULL_RANGE; |
|
5963 |
(arg->i)++; |
|
5964 |
}
|
|
5965 |
||
5966 |
||
5967 |
/*
|
|
5968 |
Range sequence interface, SEL_ARG* implementation: get the next interval
|
|
5969 |
|
|
5970 |
SYNOPSIS
|
|
5971 |
sel_arg_range_seq_next()
|
|
5972 |
rseq Value returned from sel_arg_range_seq_init
|
|
5973 |
range OUT Store information about the range here
|
|
5974 |
||
5975 |
DESCRIPTION
|
|
5976 |
This is "get_next" function for Range sequence interface implementation
|
|
5977 |
for SEL_ARG* tree.
|
|
5978 |
||
5979 |
IMPLEMENTATION
|
|
5980 |
The traversal also updates those param members:
|
|
5981 |
- is_ror_scan
|
|
5982 |
- range_count
|
|
5983 |
- max_key_part
|
|
5984 |
||
5985 |
RETURN
|
|
5986 |
0 Ok
|
|
5987 |
1 No more ranges in the sequence
|
|
5988 |
*/
|
|
5989 |
||
5990 |
//psergey-merge-todo: support check_quick_keys:max_keypart
|
|
5991 |
uint sel_arg_range_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range) |
|
5992 |
{
|
|
5993 |
SEL_ARG *key_tree; |
|
5994 |
SEL_ARG_RANGE_SEQ *seq= (SEL_ARG_RANGE_SEQ*)rseq; |
|
5995 |
if (seq->at_start) |
|
5996 |
{
|
|
5997 |
key_tree= seq->start; |
|
55
by brian
Update for using real bool types. |
5998 |
seq->at_start= false; |
1
by brian
clean slate |
5999 |
goto walk_up_n_right; |
6000 |
}
|
|
6001 |
||
6002 |
key_tree= seq->stack[seq->i].key_tree; |
|
6003 |
/* Ok, we're at some "full tuple" position in the tree */
|
|
6004 |
||
6005 |
/* Step down if we can */
|
|
6006 |
if (key_tree->next && key_tree->next != &null_element) |
|
6007 |
{
|
|
6008 |
//step down; (update the tuple, we'll step right and stay there)
|
|
6009 |
seq->i--; |
|
6010 |
step_down_to(seq, key_tree->next); |
|
6011 |
key_tree= key_tree->next; |
|
55
by brian
Update for using real bool types. |
6012 |
seq->param->is_ror_scan= false; |
1
by brian
clean slate |
6013 |
goto walk_right_n_up; |
6014 |
}
|
|
6015 |
||
6016 |
/* Ok, can't step down, walk left until we can step down */
|
|
6017 |
while (1) |
|
6018 |
{
|
|
6019 |
if (seq->i == 1) // can't step left |
|
6020 |
return 1; |
|
6021 |
/* Step left */
|
|
6022 |
seq->i--; |
|
6023 |
key_tree= seq->stack[seq->i].key_tree; |
|
6024 |
||
6025 |
/* Step down if we can */
|
|
6026 |
if (key_tree->next && key_tree->next != &null_element) |
|
6027 |
{
|
|
6028 |
// Step down; update the tuple
|
|
6029 |
seq->i--; |
|
6030 |
step_down_to(seq, key_tree->next); |
|
6031 |
key_tree= key_tree->next; |
|
6032 |
break; |
|
6033 |
}
|
|
6034 |
}
|
|
6035 |
||
6036 |
/*
|
|
6037 |
Ok, we've stepped down from the path to previous tuple.
|
|
6038 |
Walk right-up while we can
|
|
6039 |
*/
|
|
6040 |
walk_right_n_up: |
|
6041 |
while (key_tree->next_key_part && key_tree->next_key_part != &null_element && |
|
6042 |
key_tree->next_key_part->part == key_tree->part + 1 && |
|
6043 |
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) |
|
6044 |
{
|
|
6045 |
{
|
|
6046 |
RANGE_SEQ_ENTRY *cur= &seq->stack[seq->i]; |
|
6047 |
uint min_key_length= cur->min_key - seq->param->min_key; |
|
6048 |
uint max_key_length= cur->max_key - seq->param->max_key; |
|
6049 |
uint len= cur->min_key - cur[-1].min_key; |
|
6050 |
if (!(min_key_length == max_key_length && |
|
6051 |
!memcmp(cur[-1].min_key, cur[-1].max_key, len) && |
|
6052 |
!key_tree->min_flag && !key_tree->max_flag)) |
|
6053 |
{
|
|
55
by brian
Update for using real bool types. |
6054 |
seq->param->is_ror_scan= false; |
1
by brian
clean slate |
6055 |
if (!key_tree->min_flag) |
6056 |
cur->min_key_parts += |
|
6057 |
key_tree->next_key_part->store_min_key(seq->param->key[seq->keyno], |
|
6058 |
&cur->min_key, |
|
6059 |
&cur->min_key_flag); |
|
6060 |
if (!key_tree->max_flag) |
|
6061 |
cur->max_key_parts += |
|
6062 |
key_tree->next_key_part->store_max_key(seq->param->key[seq->keyno], |
|
6063 |
&cur->max_key, |
|
6064 |
&cur->max_key_flag); |
|
6065 |
break; |
|
6066 |
}
|
|
6067 |
}
|
|
6068 |
||
6069 |
/*
|
|
6070 |
Ok, current atomic interval is in form "t.field=const" and there is
|
|
6071 |
next_key_part interval. Step right, and walk up from there.
|
|
6072 |
*/
|
|
6073 |
key_tree= key_tree->next_key_part; |
|
6074 |
||
6075 |
walk_up_n_right: |
|
6076 |
while (key_tree->prev && key_tree->prev != &null_element) |
|
6077 |
{
|
|
6078 |
/* Step up */
|
|
6079 |
key_tree= key_tree->prev; |
|
6080 |
}
|
|
6081 |
step_down_to(seq, key_tree); |
|
6082 |
}
|
|
6083 |
||
6084 |
/* Ok got a tuple */
|
|
6085 |
RANGE_SEQ_ENTRY *cur= &seq->stack[seq->i]; |
|
6086 |
||
6087 |
range->ptr= (char*)(int)(key_tree->part); |
|
6088 |
{
|
|
6089 |
range->range_flag= cur->min_key_flag | cur->max_key_flag; |
|
6090 |
||
6091 |
range->start_key.key= seq->param->min_key; |
|
6092 |
range->start_key.length= cur->min_key - seq->param->min_key; |
|
6093 |
range->start_key.keypart_map= make_prev_keypart_map(cur->min_key_parts); |
|
6094 |
range->start_key.flag= (cur->min_key_flag & NEAR_MIN ? HA_READ_AFTER_KEY : |
|
6095 |
HA_READ_KEY_EXACT); |
|
6096 |
||
6097 |
range->end_key.key= seq->param->max_key; |
|
6098 |
range->end_key.length= cur->max_key - seq->param->max_key; |
|
6099 |
range->end_key.flag= (cur->max_key_flag & NEAR_MAX ? HA_READ_BEFORE_KEY : |
|
6100 |
HA_READ_AFTER_KEY); |
|
6101 |
range->end_key.keypart_map= make_prev_keypart_map(cur->max_key_parts); |
|
6102 |
||
6103 |
if (!(cur->min_key_flag & ~NULL_RANGE) && !cur->max_key_flag && |
|
6104 |
(uint)key_tree->part+1 == seq->param->table->key_info[seq->real_keyno].key_parts && |
|
53.2.14
by Monty Taylor
Removed HA_END_SPACE_KEY and references to it. It was _supposed_ to be gone anyway, but the ifdef around it was broken (MYSQL_VERSION_ID was actually undefined.) |
6105 |
(seq->param->table->key_info[seq->real_keyno].flags & (HA_NOSAME)) == |
1
by brian
clean slate |
6106 |
HA_NOSAME && |
6107 |
range->start_key.length == range->end_key.length && |
|
6108 |
!memcmp(seq->param->min_key,seq->param->max_key,range->start_key.length)) |
|
6109 |
range->range_flag= UNIQUE_RANGE | (cur->min_key_flag & NULL_RANGE); |
|
6110 |
||
6111 |
if (seq->param->is_ror_scan) |
|
6112 |
{
|
|
6113 |
/*
|
|
6114 |
If we get here, the condition on the key was converted to form
|
|
6115 |
"(keyXpart1 = c1) AND ... AND (keyXpart{key_tree->part - 1} = cN) AND
|
|
6116 |
somecond(keyXpart{key_tree->part})"
|
|
6117 |
Check if
|
|
6118 |
somecond is "keyXpart{key_tree->part} = const" and
|
|
6119 |
uncovered "tail" of KeyX parts is either empty or is identical to
|
|
6120 |
first members of clustered primary key.
|
|
6121 |
*/
|
|
6122 |
if (!(!(cur->min_key_flag & ~NULL_RANGE) && !cur->max_key_flag && |
|
6123 |
(range->start_key.length == range->end_key.length) && |
|
6124 |
!memcmp(range->start_key.key, range->end_key.key, range->start_key.length) && |
|
6125 |
is_key_scan_ror(seq->param, seq->real_keyno, key_tree->part + 1))) |
|
55
by brian
Update for using real bool types. |
6126 |
seq->param->is_ror_scan= false; |
1
by brian
clean slate |
6127 |
}
|
6128 |
}
|
|
6129 |
seq->param->range_count++; |
|
287.3.8
by Monty Taylor
Oy. Replaced max and min macros with std::max and std::min so that we get |
6130 |
seq->param->max_key_part=max(seq->param->max_key_part,(uint)key_tree->part); |
1
by brian
clean slate |
6131 |
return 0; |
6132 |
}
|
|
6133 |
||
6134 |
||
6135 |
/*
|
|
6136 |
Calculate cost and E(#rows) for a given index and intervals tree
|
|
6137 |
||
6138 |
SYNOPSIS
|
|
6139 |
check_quick_select()
|
|
6140 |
param Parameter from test_quick_select
|
|
6141 |
idx Number of index to use in PARAM::key SEL_TREE::key
|
|
55
by brian
Update for using real bool types. |
6142 |
index_only true - assume only index tuples will be accessed
|
6143 |
false - assume full table rows will be read
|
|
1
by brian
clean slate |
6144 |
tree Transformed selection condition, tree->key[idx] holds
|
6145 |
the intervals for the given index.
|
|
55
by brian
Update for using real bool types. |
6146 |
update_tbl_stats true <=> update table->quick_* with information
|
1
by brian
clean slate |
6147 |
about range scan we've evaluated.
|
6148 |
mrr_flags INOUT MRR access flags
|
|
6149 |
cost OUT Scan cost
|
|
6150 |
||
6151 |
NOTES
|
|
6152 |
param->is_ror_scan is set to reflect if the key scan is a ROR (see
|
|
6153 |
is_key_scan_ror function for more info)
|
|
6154 |
param->table->quick_*, param->range_count (and maybe others) are
|
|
6155 |
updated with data of given key scan, see quick_range_seq_next for details.
|
|
6156 |
||
6157 |
RETURN
|
|
6158 |
Estimate # of records to be retrieved.
|
|
6159 |
HA_POS_ERROR if estimate calculation failed due to table handler problems.
|
|
6160 |
*/
|
|
6161 |
||
6162 |
static
|
|
6163 |
ha_rows check_quick_select(PARAM *param, uint idx, bool index_only, |
|
6164 |
SEL_ARG *tree, bool update_tbl_stats, |
|
6165 |
uint *mrr_flags, uint *bufsize, COST_VECT *cost) |
|
6166 |
{
|
|
6167 |
SEL_ARG_RANGE_SEQ seq; |
|
6168 |
RANGE_SEQ_IF seq_if = {sel_arg_range_seq_init, sel_arg_range_seq_next}; |
|
6169 |
handler *file= param->table->file; |
|
6170 |
ha_rows rows; |
|
6171 |
uint keynr= param->real_keynr[idx]; |
|
6172 |
||
6173 |
/* Handle cases when we don't have a valid non-empty list of range */
|
|
6174 |
if (!tree) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6175 |
return(HA_POS_ERROR); |
1
by brian
clean slate |
6176 |
if (tree->type == SEL_ARG::IMPOSSIBLE) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6177 |
return(0L); |
1
by brian
clean slate |
6178 |
if (tree->type != SEL_ARG::KEY_RANGE || tree->part != 0) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6179 |
return(HA_POS_ERROR); |
1
by brian
clean slate |
6180 |
|
6181 |
seq.keyno= idx; |
|
6182 |
seq.real_keyno= keynr; |
|
6183 |
seq.param= param; |
|
6184 |
seq.start= tree; |
|
6185 |
||
6186 |
param->range_count=0; |
|
6187 |
param->max_key_part=0; |
|
6188 |
||
55
by brian
Update for using real bool types. |
6189 |
param->is_ror_scan= true; |
6190 |
if (file->index_flags(keynr, 0, true) & HA_KEY_SCAN_NOT_ROR) |
|
6191 |
param->is_ror_scan= false; |
|
1
by brian
clean slate |
6192 |
|
6193 |
*mrr_flags= param->force_default_mrr? HA_MRR_USE_DEFAULT_IMPL: 0; |
|
6194 |
*mrr_flags|= HA_MRR_NO_ASSOCIATION; |
|
6195 |
||
6196 |
bool pk_is_clustered= file->primary_key_is_clustered(); |
|
6197 |
if (index_only && |
|
6198 |
(file->index_flags(keynr, param->max_key_part, 1) & HA_KEYREAD_ONLY) && |
|
6199 |
!(pk_is_clustered && keynr == param->table->s->primary_key)) |
|
6200 |
*mrr_flags |= HA_MRR_INDEX_ONLY; |
|
6201 |
||
6202 |
if (current_thd->lex->sql_command != SQLCOM_SELECT) |
|
6203 |
*mrr_flags |= HA_MRR_USE_DEFAULT_IMPL; |
|
6204 |
||
6205 |
*bufsize= param->thd->variables.read_rnd_buff_size; |
|
6206 |
rows= file->multi_range_read_info_const(keynr, &seq_if, (void*)&seq, 0, |
|
6207 |
bufsize, mrr_flags, cost); |
|
6208 |
if (rows != HA_POS_ERROR) |
|
6209 |
{
|
|
6210 |
param->table->quick_rows[keynr]=rows; |
|
6211 |
if (update_tbl_stats) |
|
6212 |
{
|
|
6213 |
param->table->quick_keys.set_bit(keynr); |
|
6214 |
param->table->quick_key_parts[keynr]=param->max_key_part+1; |
|
6215 |
param->table->quick_n_ranges[keynr]= param->range_count; |
|
6216 |
param->table->quick_condition_rows= |
|
6217 |
min(param->table->quick_condition_rows, rows); |
|
6218 |
}
|
|
6219 |
}
|
|
6220 |
/* Figure out if the key scan is ROR (returns rows in ROWID order) or not */
|
|
6221 |
enum ha_key_alg key_alg= param->table->key_info[seq.real_keyno].algorithm; |
|
6222 |
if ((key_alg != HA_KEY_ALG_BTREE) && (key_alg!= HA_KEY_ALG_UNDEF)) |
|
6223 |
{
|
|
6224 |
/*
|
|
6225 |
All scans are non-ROR scans for those index types.
|
|
6226 |
TODO: Don't have this logic here, make table engines return
|
|
6227 |
appropriate flags instead.
|
|
6228 |
*/
|
|
55
by brian
Update for using real bool types. |
6229 |
param->is_ror_scan= false; |
1
by brian
clean slate |
6230 |
}
|
6231 |
else
|
|
6232 |
{
|
|
6233 |
/* Clustered PK scan is always a ROR scan (TODO: same as above) */
|
|
6234 |
if (param->table->s->primary_key == keynr && pk_is_clustered) |
|
55
by brian
Update for using real bool types. |
6235 |
param->is_ror_scan= true; |
1
by brian
clean slate |
6236 |
}
|
6237 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6238 |
return(rows); //psergey-merge:todo: maintain first_null_comp. |
1
by brian
clean slate |
6239 |
}
|
6240 |
||
6241 |
||
6242 |
/*
|
|
6243 |
Check if key scan on given index with equality conditions on first n key
|
|
6244 |
parts is a ROR scan.
|
|
6245 |
||
6246 |
SYNOPSIS
|
|
6247 |
is_key_scan_ror()
|
|
6248 |
param Parameter from test_quick_select
|
|
6249 |
keynr Number of key in the table. The key must not be a clustered
|
|
6250 |
primary key.
|
|
6251 |
nparts Number of first key parts for which equality conditions
|
|
6252 |
are present.
|
|
6253 |
||
6254 |
NOTES
|
|
6255 |
ROR (Rowid Ordered Retrieval) key scan is a key scan that produces
|
|
6256 |
ordered sequence of rowids (ha_xxx::cmp_ref is the comparison function)
|
|
6257 |
||
6258 |
This function is needed to handle a practically-important special case:
|
|
6259 |
an index scan is a ROR scan if it is done using a condition in form
|
|
6260 |
||
6261 |
"key1_1=c_1 AND ... AND key1_n=c_n"
|
|
6262 |
||
6263 |
where the index is defined on (key1_1, ..., key1_N [,a_1, ..., a_n])
|
|
6264 |
||
6265 |
and the table has a clustered Primary Key defined as
|
|
6266 |
PRIMARY KEY(a_1, ..., a_n, b1, ..., b_k)
|
|
6267 |
|
|
6268 |
i.e. the first key parts of it are identical to uncovered parts ot the
|
|
6269 |
key being scanned. This function assumes that the index flags do not
|
|
6270 |
include HA_KEY_SCAN_NOT_ROR flag (that is checked elsewhere).
|
|
6271 |
||
6272 |
Check (1) is made in quick_range_seq_next()
|
|
6273 |
||
6274 |
RETURN
|
|
55
by brian
Update for using real bool types. |
6275 |
true The scan is ROR-scan
|
6276 |
false Otherwise
|
|
1
by brian
clean slate |
6277 |
*/
|
6278 |
||
206
by Brian Aker
Removed final uint dead types. |
6279 |
static bool is_key_scan_ror(PARAM *param, uint keynr, uint8_t nparts) |
1
by brian
clean slate |
6280 |
{
|
6281 |
KEY *table_key= param->table->key_info + keynr; |
|
6282 |
KEY_PART_INFO *key_part= table_key->key_part + nparts; |
|
6283 |
KEY_PART_INFO *key_part_end= (table_key->key_part + |
|
6284 |
table_key->key_parts); |
|
6285 |
uint pk_number; |
|
6286 |
||
6287 |
for (KEY_PART_INFO *kp= table_key->key_part; kp < key_part; kp++) |
|
6288 |
{
|
|
206
by Brian Aker
Removed final uint dead types. |
6289 |
uint16_t fieldnr= param->table->key_info[keynr]. |
1
by brian
clean slate |
6290 |
key_part[kp - table_key->key_part].fieldnr - 1; |
6291 |
if (param->table->field[fieldnr]->key_length() != kp->length) |
|
55
by brian
Update for using real bool types. |
6292 |
return false; |
1
by brian
clean slate |
6293 |
}
|
6294 |
||
6295 |
if (key_part == key_part_end) |
|
55
by brian
Update for using real bool types. |
6296 |
return true; |
1
by brian
clean slate |
6297 |
|
6298 |
key_part= table_key->key_part + nparts; |
|
6299 |
pk_number= param->table->s->primary_key; |
|
6300 |
if (!param->table->file->primary_key_is_clustered() || pk_number == MAX_KEY) |
|
55
by brian
Update for using real bool types. |
6301 |
return false; |
1
by brian
clean slate |
6302 |
|
6303 |
KEY_PART_INFO *pk_part= param->table->key_info[pk_number].key_part; |
|
6304 |
KEY_PART_INFO *pk_part_end= pk_part + |
|
6305 |
param->table->key_info[pk_number].key_parts; |
|
6306 |
for (;(key_part!=key_part_end) && (pk_part != pk_part_end); |
|
6307 |
++key_part, ++pk_part) |
|
6308 |
{
|
|
6309 |
if ((key_part->field != pk_part->field) || |
|
6310 |
(key_part->length != pk_part->length)) |
|
55
by brian
Update for using real bool types. |
6311 |
return false; |
1
by brian
clean slate |
6312 |
}
|
6313 |
return (key_part == key_part_end); |
|
6314 |
}
|
|
6315 |
||
6316 |
||
6317 |
/*
|
|
6318 |
Create a QUICK_RANGE_SELECT from given key and SEL_ARG tree for that key.
|
|
6319 |
||
6320 |
SYNOPSIS
|
|
6321 |
get_quick_select()
|
|
6322 |
param
|
|
6323 |
idx Index of used key in param->key.
|
|
6324 |
key_tree SEL_ARG tree for the used key
|
|
6325 |
mrr_flags MRR parameter for quick select
|
|
6326 |
mrr_buf_size MRR parameter for quick select
|
|
6327 |
parent_alloc If not NULL, use it to allocate memory for
|
|
6328 |
quick select data. Otherwise use quick->alloc.
|
|
6329 |
NOTES
|
|
6330 |
The caller must call QUICK_SELECT::init for returned quick select.
|
|
6331 |
||
6332 |
CAUTION! This function may change thd->mem_root to a MEM_ROOT which will be
|
|
6333 |
deallocated when the returned quick select is deleted.
|
|
6334 |
||
6335 |
RETURN
|
|
6336 |
NULL on error
|
|
6337 |
otherwise created quick select
|
|
6338 |
*/
|
|
6339 |
||
6340 |
QUICK_RANGE_SELECT * |
|
6341 |
get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree, uint mrr_flags, |
|
6342 |
uint mrr_buf_size, MEM_ROOT *parent_alloc) |
|
6343 |
{
|
|
6344 |
QUICK_RANGE_SELECT *quick; |
|
55
by brian
Update for using real bool types. |
6345 |
bool create_err= false; |
1
by brian
clean slate |
6346 |
|
6347 |
quick=new QUICK_RANGE_SELECT(param->thd, param->table, |
|
6348 |
param->real_keynr[idx], |
|
6349 |
test(parent_alloc), NULL, &create_err); |
|
6350 |
||
6351 |
if (quick) |
|
6352 |
{
|
|
6353 |
if (create_err || |
|
6354 |
get_quick_keys(param,quick,param->key[idx],key_tree,param->min_key,0, |
|
6355 |
param->max_key,0)) |
|
6356 |
{
|
|
6357 |
delete quick; |
|
6358 |
quick=0; |
|
6359 |
}
|
|
6360 |
else
|
|
6361 |
{
|
|
6362 |
quick->mrr_flags= mrr_flags; |
|
6363 |
quick->mrr_buf_size= mrr_buf_size; |
|
6364 |
quick->key_parts=(KEY_PART*) |
|
6365 |
memdup_root(parent_alloc? parent_alloc : &quick->alloc, |
|
6366 |
(char*) param->key[idx], |
|
6367 |
sizeof(KEY_PART)* |
|
6368 |
param->table->key_info[param->real_keynr[idx]].key_parts); |
|
6369 |
}
|
|
6370 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6371 |
return(quick); |
1
by brian
clean slate |
6372 |
}
|
6373 |
||
6374 |
||
6375 |
/*
|
|
6376 |
** Fix this to get all possible sub_ranges
|
|
6377 |
*/
|
|
6378 |
bool
|
|
6379 |
get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, |
|
6380 |
SEL_ARG *key_tree, uchar *min_key,uint min_key_flag, |
|
6381 |
uchar *max_key, uint max_key_flag) |
|
6382 |
{
|
|
6383 |
QUICK_RANGE *range; |
|
6384 |
uint flag; |
|
6385 |
int min_part= key_tree->part-1, // # of keypart values in min_key buffer |
|
6386 |
max_part= key_tree->part-1; // # of keypart values in max_key buffer |
|
6387 |
||
6388 |
if (key_tree->left != &null_element) |
|
6389 |
{
|
|
6390 |
if (get_quick_keys(param,quick,key,key_tree->left, |
|
6391 |
min_key,min_key_flag, max_key, max_key_flag)) |
|
6392 |
return 1; |
|
6393 |
}
|
|
6394 |
uchar *tmp_min_key=min_key,*tmp_max_key=max_key; |
|
6395 |
min_part+= key_tree->store_min(key[key_tree->part].store_length, |
|
6396 |
&tmp_min_key,min_key_flag); |
|
6397 |
max_part+= key_tree->store_max(key[key_tree->part].store_length, |
|
6398 |
&tmp_max_key,max_key_flag); |
|
6399 |
||
6400 |
if (key_tree->next_key_part && |
|
6401 |
key_tree->next_key_part->part == key_tree->part+1 && |
|
6402 |
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) |
|
6403 |
{ // const key as prefix |
|
6404 |
if ((tmp_min_key - min_key) == (tmp_max_key - max_key) && |
|
6405 |
memcmp(min_key, max_key, (uint)(tmp_max_key - max_key))==0 && |
|
6406 |
key_tree->min_flag==0 && key_tree->max_flag==0) |
|
6407 |
{
|
|
6408 |
if (get_quick_keys(param,quick,key,key_tree->next_key_part, |
|
6409 |
tmp_min_key, min_key_flag | key_tree->min_flag, |
|
6410 |
tmp_max_key, max_key_flag | key_tree->max_flag)) |
|
6411 |
return 1; |
|
6412 |
goto end; // Ugly, but efficient |
|
6413 |
}
|
|
6414 |
{
|
|
6415 |
uint tmp_min_flag=key_tree->min_flag,tmp_max_flag=key_tree->max_flag; |
|
6416 |
if (!tmp_min_flag) |
|
6417 |
min_part+= key_tree->next_key_part->store_min_key(key, &tmp_min_key, |
|
6418 |
&tmp_min_flag); |
|
6419 |
if (!tmp_max_flag) |
|
6420 |
max_part+= key_tree->next_key_part->store_max_key(key, &tmp_max_key, |
|
6421 |
&tmp_max_flag); |
|
6422 |
flag=tmp_min_flag | tmp_max_flag; |
|
6423 |
}
|
|
6424 |
}
|
|
6425 |
else
|
|
6426 |
{
|
|
6427 |
flag= key_tree->min_flag | key_tree->max_flag; |
|
6428 |
}
|
|
6429 |
||
6430 |
/*
|
|
6431 |
Ensure that some part of min_key and max_key are used. If not,
|
|
6432 |
regard this as no lower/upper range
|
|
6433 |
*/
|
|
6434 |
{
|
|
6435 |
if (tmp_min_key != param->min_key) |
|
6436 |
flag&= ~NO_MIN_RANGE; |
|
6437 |
else
|
|
6438 |
flag|= NO_MIN_RANGE; |
|
6439 |
if (tmp_max_key != param->max_key) |
|
6440 |
flag&= ~NO_MAX_RANGE; |
|
6441 |
else
|
|
6442 |
flag|= NO_MAX_RANGE; |
|
6443 |
}
|
|
6444 |
if (flag == 0) |
|
6445 |
{
|
|
6446 |
uint length= (uint) (tmp_min_key - param->min_key); |
|
6447 |
if (length == (uint) (tmp_max_key - param->max_key) && |
|
6448 |
!memcmp(param->min_key,param->max_key,length)) |
|
6449 |
{
|
|
6450 |
KEY *table_key=quick->head->key_info+quick->index; |
|
6451 |
flag=EQ_RANGE; |
|
53.2.14
by Monty Taylor
Removed HA_END_SPACE_KEY and references to it. It was _supposed_ to be gone anyway, but the ifdef around it was broken (MYSQL_VERSION_ID was actually undefined.) |
6452 |
if ((table_key->flags & (HA_NOSAME)) == HA_NOSAME && |
1
by brian
clean slate |
6453 |
key->part == table_key->key_parts-1) |
6454 |
{
|
|
6455 |
if (!(table_key->flags & HA_NULL_PART_KEY) || |
|
6456 |
!null_part_in_key(key, |
|
6457 |
param->min_key, |
|
6458 |
(uint) (tmp_min_key - param->min_key))) |
|
6459 |
flag|= UNIQUE_RANGE; |
|
6460 |
else
|
|
6461 |
flag|= NULL_RANGE; |
|
6462 |
}
|
|
6463 |
}
|
|
6464 |
}
|
|
6465 |
||
6466 |
/* Get range for retrieving rows in QUICK_SELECT::get_next */
|
|
6467 |
if (!(range= new QUICK_RANGE(param->min_key, |
|
6468 |
(uint) (tmp_min_key - param->min_key), |
|
6469 |
min_part >=0 ? make_keypart_map(min_part) : 0, |
|
6470 |
param->max_key, |
|
6471 |
(uint) (tmp_max_key - param->max_key), |
|
6472 |
max_part >=0 ? make_keypart_map(max_part) : 0, |
|
6473 |
flag))) |
|
6474 |
return 1; // out of memory |
|
6475 |
||
6476 |
set_if_bigger(quick->max_used_key_length, range->min_length); |
|
6477 |
set_if_bigger(quick->max_used_key_length, range->max_length); |
|
6478 |
set_if_bigger(quick->used_key_parts, (uint) key_tree->part+1); |
|
6479 |
if (insert_dynamic(&quick->ranges, (uchar*) &range)) |
|
6480 |
return 1; |
|
6481 |
||
6482 |
end: |
|
6483 |
if (key_tree->right != &null_element) |
|
6484 |
return get_quick_keys(param,quick,key,key_tree->right, |
|
6485 |
min_key,min_key_flag, |
|
6486 |
max_key,max_key_flag); |
|
6487 |
return 0; |
|
6488 |
}
|
|
6489 |
||
6490 |
/*
|
|
6491 |
Return 1 if there is only one range and this uses the whole primary key
|
|
6492 |
*/
|
|
6493 |
||
6494 |
bool QUICK_RANGE_SELECT::unique_key_range() |
|
6495 |
{
|
|
6496 |
if (ranges.elements == 1) |
|
6497 |
{
|
|
6498 |
QUICK_RANGE *tmp= *((QUICK_RANGE**)ranges.buffer); |
|
6499 |
if ((tmp->flag & (EQ_RANGE | NULL_RANGE)) == EQ_RANGE) |
|
6500 |
{
|
|
6501 |
KEY *key=head->key_info+index; |
|
53.2.14
by Monty Taylor
Removed HA_END_SPACE_KEY and references to it. It was _supposed_ to be gone anyway, but the ifdef around it was broken (MYSQL_VERSION_ID was actually undefined.) |
6502 |
return ((key->flags & (HA_NOSAME)) == HA_NOSAME && |
1
by brian
clean slate |
6503 |
key->key_length == tmp->min_length); |
6504 |
}
|
|
6505 |
}
|
|
6506 |
return 0; |
|
6507 |
}
|
|
6508 |
||
6509 |
||
6510 |
||
6511 |
/*
|
|
55
by brian
Update for using real bool types. |
6512 |
Return true if any part of the key is NULL
|
1
by brian
clean slate |
6513 |
|
6514 |
SYNOPSIS
|
|
6515 |
null_part_in_key()
|
|
6516 |
key_part Array of key parts (index description)
|
|
6517 |
key Key values tuple
|
|
6518 |
length Length of key values tuple in bytes.
|
|
6519 |
||
6520 |
RETURN
|
|
55
by brian
Update for using real bool types. |
6521 |
true The tuple has at least one "keypartX is NULL"
|
6522 |
false Otherwise
|
|
1
by brian
clean slate |
6523 |
*/
|
6524 |
||
6525 |
static bool null_part_in_key(KEY_PART *key_part, const uchar *key, uint length) |
|
6526 |
{
|
|
6527 |
for (const uchar *end=key+length ; |
|
6528 |
key < end; |
|
6529 |
key+= key_part++->store_length) |
|
6530 |
{
|
|
6531 |
if (key_part->null_bit && *key) |
|
6532 |
return 1; |
|
6533 |
}
|
|
6534 |
return 0; |
|
6535 |
}
|
|
6536 |
||
6537 |
||
6538 |
bool QUICK_SELECT_I::is_keys_used(const MY_BITMAP *fields) |
|
6539 |
{
|
|
6540 |
return is_key_used(head, index, fields); |
|
6541 |
}
|
|
6542 |
||
6543 |
bool QUICK_INDEX_MERGE_SELECT::is_keys_used(const MY_BITMAP *fields) |
|
6544 |
{
|
|
6545 |
QUICK_RANGE_SELECT *quick; |
|
6546 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
|
6547 |
while ((quick= it++)) |
|
6548 |
{
|
|
6549 |
if (is_key_used(head, quick->index, fields)) |
|
6550 |
return 1; |
|
6551 |
}
|
|
6552 |
return 0; |
|
6553 |
}
|
|
6554 |
||
6555 |
bool QUICK_ROR_INTERSECT_SELECT::is_keys_used(const MY_BITMAP *fields) |
|
6556 |
{
|
|
6557 |
QUICK_RANGE_SELECT *quick; |
|
6558 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
|
6559 |
while ((quick= it++)) |
|
6560 |
{
|
|
6561 |
if (is_key_used(head, quick->index, fields)) |
|
6562 |
return 1; |
|
6563 |
}
|
|
6564 |
return 0; |
|
6565 |
}
|
|
6566 |
||
6567 |
bool QUICK_ROR_UNION_SELECT::is_keys_used(const MY_BITMAP *fields) |
|
6568 |
{
|
|
6569 |
QUICK_SELECT_I *quick; |
|
6570 |
List_iterator_fast<QUICK_SELECT_I> it(quick_selects); |
|
6571 |
while ((quick= it++)) |
|
6572 |
{
|
|
6573 |
if (quick->is_keys_used(fields)) |
|
6574 |
return 1; |
|
6575 |
}
|
|
6576 |
return 0; |
|
6577 |
}
|
|
6578 |
||
6579 |
||
6580 |
/*
|
|
6581 |
Create quick select from ref/ref_or_null scan.
|
|
6582 |
||
6583 |
SYNOPSIS
|
|
6584 |
get_quick_select_for_ref()
|
|
6585 |
thd Thread handle
|
|
6586 |
table Table to access
|
|
6587 |
ref ref[_or_null] scan parameters
|
|
6588 |
records Estimate of number of records (needed only to construct
|
|
6589 |
quick select)
|
|
6590 |
NOTES
|
|
6591 |
This allocates things in a new memory root, as this may be called many
|
|
6592 |
times during a query.
|
|
6593 |
||
6594 |
RETURN
|
|
6595 |
Quick select that retrieves the same rows as passed ref scan
|
|
6596 |
NULL on error.
|
|
6597 |
*/
|
|
6598 |
||
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
6599 |
QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, Table *table, |
1
by brian
clean slate |
6600 |
TABLE_REF *ref, ha_rows records) |
6601 |
{
|
|
6602 |
MEM_ROOT *old_root, *alloc; |
|
6603 |
QUICK_RANGE_SELECT *quick; |
|
6604 |
KEY *key_info = &table->key_info[ref->key]; |
|
6605 |
KEY_PART *key_part; |
|
6606 |
QUICK_RANGE *range; |
|
6607 |
uint part; |
|
55
by brian
Update for using real bool types. |
6608 |
bool create_err= false; |
1
by brian
clean slate |
6609 |
COST_VECT cost; |
6610 |
||
6611 |
old_root= thd->mem_root; |
|
6612 |
/* The following call may change thd->mem_root */
|
|
6613 |
quick= new QUICK_RANGE_SELECT(thd, table, ref->key, 0, 0, &create_err); |
|
6614 |
/* save mem_root set by QUICK_RANGE_SELECT constructor */
|
|
6615 |
alloc= thd->mem_root; |
|
6616 |
/*
|
|
6617 |
return back default mem_root (thd->mem_root) changed by
|
|
6618 |
QUICK_RANGE_SELECT constructor
|
|
6619 |
*/
|
|
6620 |
thd->mem_root= old_root; |
|
6621 |
||
6622 |
if (!quick || create_err) |
|
6623 |
return 0; /* no ranges found */ |
|
6624 |
if (quick->init()) |
|
6625 |
goto err; |
|
6626 |
quick->records= records; |
|
6627 |
||
354
by Brian Aker
Refactor of Table methods. |
6628 |
if ((cp_buffer_from_ref(thd, ref) && thd->is_fatal_error) || |
1
by brian
clean slate |
6629 |
!(range= new(alloc) QUICK_RANGE())) |
6630 |
goto err; // out of memory |
|
6631 |
||
6632 |
range->min_key= range->max_key= ref->key_buff; |
|
6633 |
range->min_length= range->max_length= ref->key_length; |
|
6634 |
range->min_keypart_map= range->max_keypart_map= |
|
6635 |
make_prev_keypart_map(ref->key_parts); |
|
6636 |
range->flag= ((ref->key_length == key_info->key_length && |
|
53.2.14
by Monty Taylor
Removed HA_END_SPACE_KEY and references to it. It was _supposed_ to be gone anyway, but the ifdef around it was broken (MYSQL_VERSION_ID was actually undefined.) |
6637 |
key_info->flags == 0) ? EQ_RANGE : 0); |
1
by brian
clean slate |
6638 |
|
6639 |
if (!(quick->key_parts=key_part=(KEY_PART *) |
|
6640 |
alloc_root(&quick->alloc,sizeof(KEY_PART)*ref->key_parts))) |
|
6641 |
goto err; |
|
6642 |
||
6643 |
for (part=0 ; part < ref->key_parts ;part++,key_part++) |
|
6644 |
{
|
|
6645 |
key_part->part=part; |
|
6646 |
key_part->field= key_info->key_part[part].field; |
|
6647 |
key_part->length= key_info->key_part[part].length; |
|
6648 |
key_part->store_length= key_info->key_part[part].store_length; |
|
6649 |
key_part->null_bit= key_info->key_part[part].null_bit; |
|
206
by Brian Aker
Removed final uint dead types. |
6650 |
key_part->flag= (uint8_t) key_info->key_part[part].key_part_flag; |
1
by brian
clean slate |
6651 |
}
|
6652 |
if (insert_dynamic(&quick->ranges,(uchar*)&range)) |
|
6653 |
goto err; |
|
6654 |
||
6655 |
/*
|
|
6656 |
Add a NULL range if REF_OR_NULL optimization is used.
|
|
6657 |
For example:
|
|
6658 |
if we have "WHERE A=2 OR A IS NULL" we created the (A=2) range above
|
|
6659 |
and have ref->null_ref_key set. Will create a new NULL range here.
|
|
6660 |
*/
|
|
6661 |
if (ref->null_ref_key) |
|
6662 |
{
|
|
6663 |
QUICK_RANGE *null_range; |
|
6664 |
||
6665 |
*ref->null_ref_key= 1; // Set null byte then create a range |
|
6666 |
if (!(null_range= new (alloc) |
|
6667 |
QUICK_RANGE(ref->key_buff, ref->key_length, |
|
6668 |
make_prev_keypart_map(ref->key_parts), |
|
6669 |
ref->key_buff, ref->key_length, |
|
6670 |
make_prev_keypart_map(ref->key_parts), EQ_RANGE))) |
|
6671 |
goto err; |
|
6672 |
*ref->null_ref_key= 0; // Clear null byte |
|
6673 |
if (insert_dynamic(&quick->ranges,(uchar*)&null_range)) |
|
6674 |
goto err; |
|
6675 |
}
|
|
6676 |
||
6677 |
/* Call multi_range_read_info() to get the MRR flags and buffer size */
|
|
6678 |
quick->mrr_flags= HA_MRR_NO_ASSOCIATION | |
|
6679 |
(table->key_read ? HA_MRR_INDEX_ONLY : 0); |
|
6680 |
if (thd->lex->sql_command != SQLCOM_SELECT) |
|
6681 |
quick->mrr_flags |= HA_MRR_USE_DEFAULT_IMPL; |
|
6682 |
||
6683 |
quick->mrr_buf_size= thd->variables.read_rnd_buff_size; |
|
6684 |
if (table->file->multi_range_read_info(quick->index, 1, (uint)records, |
|
6685 |
&quick->mrr_buf_size, |
|
6686 |
&quick->mrr_flags, &cost)) |
|
6687 |
goto err; |
|
6688 |
||
6689 |
return quick; |
|
6690 |
err: |
|
6691 |
delete quick; |
|
6692 |
return 0; |
|
6693 |
}
|
|
6694 |
||
6695 |
||
6696 |
/*
|
|
6697 |
Perform key scans for all used indexes (except CPK), get rowids and merge
|
|
6698 |
them into an ordered non-recurrent sequence of rowids.
|
|
6699 |
|
|
6700 |
The merge/duplicate removal is performed using Unique class. We put all
|
|
6701 |
rowids into Unique, get the sorted sequence and destroy the Unique.
|
|
6702 |
|
|
55
by brian
Update for using real bool types. |
6703 |
If table has a clustered primary key that covers all rows (true for bdb
|
1
by brian
clean slate |
6704 |
and innodb currently) and one of the index_merge scans is a scan on PK,
|
6705 |
then rows that will be retrieved by PK scan are not put into Unique and
|
|
6706 |
primary key scan is not performed here, it is performed later separately.
|
|
6707 |
||
6708 |
RETURN
|
|
6709 |
0 OK
|
|
6710 |
other error
|
|
6711 |
*/
|
|
6712 |
||
6713 |
int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() |
|
6714 |
{
|
|
6715 |
List_iterator_fast<QUICK_RANGE_SELECT> cur_quick_it(quick_selects); |
|
6716 |
QUICK_RANGE_SELECT* cur_quick; |
|
6717 |
int result; |
|
6718 |
Unique *unique; |
|
6719 |
handler *file= head->file; |
|
6720 |
||
6721 |
file->extra(HA_EXTRA_KEYREAD); |
|
6722 |
head->prepare_for_position(); |
|
6723 |
||
6724 |
cur_quick_it.rewind(); |
|
6725 |
cur_quick= cur_quick_it++; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6726 |
assert(cur_quick != 0); |
1
by brian
clean slate |
6727 |
|
6728 |
/*
|
|
6729 |
We reuse the same instance of handler so we need to call both init and
|
|
6730 |
reset here.
|
|
6731 |
*/
|
|
6732 |
if (cur_quick->init() || cur_quick->reset()) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6733 |
return(1); |
1
by brian
clean slate |
6734 |
|
6735 |
unique= new Unique(refpos_order_cmp, (void *)file, |
|
6736 |
file->ref_length, |
|
6737 |
thd->variables.sortbuff_size); |
|
6738 |
if (!unique) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6739 |
return(1); |
1
by brian
clean slate |
6740 |
for (;;) |
6741 |
{
|
|
6742 |
while ((result= cur_quick->get_next()) == HA_ERR_END_OF_FILE) |
|
6743 |
{
|
|
6744 |
cur_quick->range_end(); |
|
6745 |
cur_quick= cur_quick_it++; |
|
6746 |
if (!cur_quick) |
|
6747 |
break; |
|
6748 |
||
6749 |
if (cur_quick->file->inited != handler::NONE) |
|
6750 |
cur_quick->file->ha_index_end(); |
|
6751 |
if (cur_quick->init() || cur_quick->reset()) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6752 |
return(1); |
1
by brian
clean slate |
6753 |
}
|
6754 |
||
6755 |
if (result) |
|
6756 |
{
|
|
6757 |
if (result != HA_ERR_END_OF_FILE) |
|
6758 |
{
|
|
6759 |
cur_quick->range_end(); |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6760 |
return(result); |
1
by brian
clean slate |
6761 |
}
|
6762 |
break; |
|
6763 |
}
|
|
6764 |
||
6765 |
if (thd->killed) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6766 |
return(1); |
1
by brian
clean slate |
6767 |
|
6768 |
/* skip row if it will be retrieved by clustered PK scan */
|
|
6769 |
if (pk_quick_select && pk_quick_select->row_in_ranges()) |
|
6770 |
continue; |
|
6771 |
||
6772 |
cur_quick->file->position(cur_quick->record); |
|
6773 |
result= unique->unique_add((char*)cur_quick->file->ref); |
|
6774 |
if (result) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6775 |
return(1); |
1
by brian
clean slate |
6776 |
|
6777 |
}
|
|
6778 |
||
6779 |
/* ok, all row ids are in Unique */
|
|
6780 |
result= unique->get(head); |
|
6781 |
delete unique; |
|
55
by brian
Update for using real bool types. |
6782 |
doing_pk_scan= false; |
1
by brian
clean slate |
6783 |
/* index_merge currently doesn't support "using index" at all */
|
6784 |
file->extra(HA_EXTRA_NO_KEYREAD); |
|
6785 |
/* start table scan */
|
|
6786 |
init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1, 1); |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6787 |
return(result); |
1
by brian
clean slate |
6788 |
}
|
6789 |
||
6790 |
||
6791 |
/*
|
|
6792 |
Get next row for index_merge.
|
|
6793 |
NOTES
|
|
6794 |
The rows are read from
|
|
6795 |
1. rowids stored in Unique.
|
|
6796 |
2. QUICK_RANGE_SELECT with clustered primary key (if any).
|
|
6797 |
The sets of rows retrieved in 1) and 2) are guaranteed to be disjoint.
|
|
6798 |
*/
|
|
6799 |
||
6800 |
int QUICK_INDEX_MERGE_SELECT::get_next() |
|
6801 |
{
|
|
6802 |
int result; |
|
6803 |
||
6804 |
if (doing_pk_scan) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6805 |
return(pk_quick_select->get_next()); |
1
by brian
clean slate |
6806 |
|
6807 |
if ((result= read_record.read_record(&read_record)) == -1) |
|
6808 |
{
|
|
6809 |
result= HA_ERR_END_OF_FILE; |
|
6810 |
end_read_record(&read_record); |
|
6811 |
/* All rows from Unique have been retrieved, do a clustered PK scan */
|
|
6812 |
if (pk_quick_select) |
|
6813 |
{
|
|
55
by brian
Update for using real bool types. |
6814 |
doing_pk_scan= true; |
1
by brian
clean slate |
6815 |
if ((result= pk_quick_select->init()) || |
6816 |
(result= pk_quick_select->reset())) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6817 |
return(result); |
6818 |
return(pk_quick_select->get_next()); |
|
1
by brian
clean slate |
6819 |
}
|
6820 |
}
|
|
6821 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6822 |
return(result); |
1
by brian
clean slate |
6823 |
}
|
6824 |
||
6825 |
||
6826 |
/*
|
|
6827 |
Retrieve next record.
|
|
6828 |
SYNOPSIS
|
|
6829 |
QUICK_ROR_INTERSECT_SELECT::get_next()
|
|
6830 |
||
6831 |
NOTES
|
|
6832 |
Invariant on enter/exit: all intersected selects have retrieved all index
|
|
6833 |
records with rowid <= some_rowid_val and no intersected select has
|
|
6834 |
retrieved any index records with rowid > some_rowid_val.
|
|
6835 |
We start fresh and loop until we have retrieved the same rowid in each of
|
|
6836 |
the key scans or we got an error.
|
|
6837 |
||
6838 |
If a Clustered PK scan is present, it is used only to check if row
|
|
6839 |
satisfies its condition (and never used for row retrieval).
|
|
6840 |
||
6841 |
RETURN
|
|
6842 |
0 - Ok
|
|
6843 |
other - Error code if any error occurred.
|
|
6844 |
*/
|
|
6845 |
||
6846 |
int QUICK_ROR_INTERSECT_SELECT::get_next() |
|
6847 |
{
|
|
6848 |
List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects); |
|
6849 |
QUICK_RANGE_SELECT* quick; |
|
6850 |
int error, cmp; |
|
6851 |
uint last_rowid_count=0; |
|
6852 |
||
6853 |
do
|
|
6854 |
{
|
|
6855 |
/* Get a rowid for first quick and save it as a 'candidate' */
|
|
6856 |
quick= quick_it++; |
|
6857 |
error= quick->get_next(); |
|
6858 |
if (cpk_quick) |
|
6859 |
{
|
|
6860 |
while (!error && !cpk_quick->row_in_ranges()) |
|
6861 |
error= quick->get_next(); |
|
6862 |
}
|
|
6863 |
if (error) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6864 |
return(error); |
1
by brian
clean slate |
6865 |
|
6866 |
quick->file->position(quick->record); |
|
6867 |
memcpy(last_rowid, quick->file->ref, head->file->ref_length); |
|
6868 |
last_rowid_count= 1; |
|
6869 |
||
6870 |
while (last_rowid_count < quick_selects.elements) |
|
6871 |
{
|
|
6872 |
if (!(quick= quick_it++)) |
|
6873 |
{
|
|
6874 |
quick_it.rewind(); |
|
6875 |
quick= quick_it++; |
|
6876 |
}
|
|
6877 |
||
6878 |
do
|
|
6879 |
{
|
|
6880 |
if ((error= quick->get_next())) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6881 |
return(error); |
1
by brian
clean slate |
6882 |
quick->file->position(quick->record); |
6883 |
cmp= head->file->cmp_ref(quick->file->ref, last_rowid); |
|
6884 |
} while (cmp < 0); |
|
6885 |
||
6886 |
/* Ok, current select 'caught up' and returned ref >= cur_ref */
|
|
6887 |
if (cmp > 0) |
|
6888 |
{
|
|
6889 |
/* Found a row with ref > cur_ref. Make it a new 'candidate' */
|
|
6890 |
if (cpk_quick) |
|
6891 |
{
|
|
6892 |
while (!cpk_quick->row_in_ranges()) |
|
6893 |
{
|
|
6894 |
if ((error= quick->get_next())) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6895 |
return(error); |
1
by brian
clean slate |
6896 |
}
|
6897 |
}
|
|
6898 |
memcpy(last_rowid, quick->file->ref, head->file->ref_length); |
|
6899 |
last_rowid_count= 1; |
|
6900 |
}
|
|
6901 |
else
|
|
6902 |
{
|
|
6903 |
/* current 'candidate' row confirmed by this select */
|
|
6904 |
last_rowid_count++; |
|
6905 |
}
|
|
6906 |
}
|
|
6907 |
||
6908 |
/* We get here if we got the same row ref in all scans. */
|
|
6909 |
if (need_to_fetch_row) |
|
6910 |
error= head->file->rnd_pos(head->record[0], last_rowid); |
|
6911 |
} while (error == HA_ERR_RECORD_DELETED); |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6912 |
return(error); |
1
by brian
clean slate |
6913 |
}
|
6914 |
||
6915 |
||
6916 |
/*
|
|
6917 |
Retrieve next record.
|
|
6918 |
SYNOPSIS
|
|
6919 |
QUICK_ROR_UNION_SELECT::get_next()
|
|
6920 |
||
6921 |
NOTES
|
|
6922 |
Enter/exit invariant:
|
|
6923 |
For each quick select in the queue a {key,rowid} tuple has been
|
|
6924 |
retrieved but the corresponding row hasn't been passed to output.
|
|
6925 |
||
6926 |
RETURN
|
|
6927 |
0 - Ok
|
|
6928 |
other - Error code if any error occurred.
|
|
6929 |
*/
|
|
6930 |
||
6931 |
int QUICK_ROR_UNION_SELECT::get_next() |
|
6932 |
{
|
|
6933 |
int error, dup_row; |
|
6934 |
QUICK_SELECT_I *quick; |
|
6935 |
uchar *tmp; |
|
6936 |
||
6937 |
do
|
|
6938 |
{
|
|
6939 |
do
|
|
6940 |
{
|
|
6941 |
if (!queue.elements) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6942 |
return(HA_ERR_END_OF_FILE); |
1
by brian
clean slate |
6943 |
/* Ok, we have a queue with >= 1 scans */
|
6944 |
||
6945 |
quick= (QUICK_SELECT_I*)queue_top(&queue); |
|
6946 |
memcpy(cur_rowid, quick->last_rowid, rowid_length); |
|
6947 |
||
6948 |
/* put into queue rowid from the same stream as top element */
|
|
6949 |
if ((error= quick->get_next())) |
|
6950 |
{
|
|
6951 |
if (error != HA_ERR_END_OF_FILE) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6952 |
return(error); |
1
by brian
clean slate |
6953 |
queue_remove(&queue, 0); |
6954 |
}
|
|
6955 |
else
|
|
6956 |
{
|
|
6957 |
quick->save_last_pos(); |
|
6958 |
queue_replaced(&queue); |
|
6959 |
}
|
|
6960 |
||
6961 |
if (!have_prev_rowid) |
|
6962 |
{
|
|
6963 |
/* No rows have been returned yet */
|
|
55
by brian
Update for using real bool types. |
6964 |
dup_row= false; |
6965 |
have_prev_rowid= true; |
|
1
by brian
clean slate |
6966 |
}
|
6967 |
else
|
|
6968 |
dup_row= !head->file->cmp_ref(cur_rowid, prev_rowid); |
|
6969 |
} while (dup_row); |
|
6970 |
||
6971 |
tmp= cur_rowid; |
|
6972 |
cur_rowid= prev_rowid; |
|
6973 |
prev_rowid= tmp; |
|
6974 |
||
6975 |
error= head->file->rnd_pos(quick->record, prev_rowid); |
|
6976 |
} while (error == HA_ERR_RECORD_DELETED); |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6977 |
return(error); |
1
by brian
clean slate |
6978 |
}
|
6979 |
||
6980 |
||
6981 |
int QUICK_RANGE_SELECT::reset() |
|
6982 |
{
|
|
6983 |
uint buf_size; |
|
6984 |
uchar *mrange_buff; |
|
6985 |
int error; |
|
6986 |
HANDLER_BUFFER empty_buf; |
|
6987 |
last_range= NULL; |
|
6988 |
cur_range= (QUICK_RANGE**) ranges.buffer; |
|
6989 |
||
6990 |
if (file->inited == handler::NONE && (error= file->ha_index_init(index,1))) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6991 |
return(error); |
1
by brian
clean slate |
6992 |
|
6993 |
/* Allocate buffer if we need one but haven't allocated it yet */
|
|
6994 |
if (mrr_buf_size && !mrr_buf_desc) |
|
6995 |
{
|
|
6996 |
buf_size= mrr_buf_size; |
|
6997 |
while (buf_size && !my_multi_malloc(MYF(MY_WME), |
|
6998 |
&mrr_buf_desc, sizeof(*mrr_buf_desc), |
|
6999 |
&mrange_buff, buf_size, |
|
7000 |
NullS)) |
|
7001 |
{
|
|
7002 |
/* Try to shrink the buffers until both are 0. */
|
|
7003 |
buf_size/= 2; |
|
7004 |
}
|
|
7005 |
if (!mrr_buf_desc) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7006 |
return(HA_ERR_OUT_OF_MEM); |
1
by brian
clean slate |
7007 |
|
7008 |
/* Initialize the handler buffer. */
|
|
7009 |
mrr_buf_desc->buffer= mrange_buff; |
|
7010 |
mrr_buf_desc->buffer_end= mrange_buff + buf_size; |
|
7011 |
mrr_buf_desc->end_of_used_area= mrange_buff; |
|
7012 |
}
|
|
7013 |
||
7014 |
if (!mrr_buf_desc) |
|
7015 |
empty_buf.buffer= empty_buf.buffer_end= empty_buf.end_of_used_area= NULL; |
|
7016 |
||
7017 |
if (sorted) |
|
7018 |
mrr_flags |= HA_MRR_SORTED; |
|
7019 |
RANGE_SEQ_IF seq_funcs= {quick_range_seq_init, quick_range_seq_next}; |
|
7020 |
error= file->multi_range_read_init(&seq_funcs, (void*)this, ranges.elements, |
|
7021 |
mrr_flags, mrr_buf_desc? mrr_buf_desc: |
|
7022 |
&empty_buf); |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7023 |
return(error); |
1
by brian
clean slate |
7024 |
}
|
7025 |
||
7026 |
||
7027 |
/*
|
|
7028 |
Range sequence interface implementation for array<QUICK_RANGE>: initialize
|
|
7029 |
|
|
7030 |
SYNOPSIS
|
|
7031 |
quick_range_seq_init()
|
|
7032 |
init_param Caller-opaque paramenter: QUICK_RANGE_SELECT* pointer
|
|
7033 |
n_ranges Number of ranges in the sequence (ignored)
|
|
7034 |
flags MRR flags (currently not used)
|
|
7035 |
||
7036 |
RETURN
|
|
7037 |
Opaque value to be passed to quick_range_seq_next
|
|
7038 |
*/
|
|
7039 |
||
77.1.46
by Monty Taylor
Finished the warnings work! |
7040 |
range_seq_t quick_range_seq_init(void *init_param, |
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
7041 |
uint n_ranges __attribute__((unused)), |
7042 |
uint flags __attribute__((unused))) |
|
1
by brian
clean slate |
7043 |
{
|
7044 |
QUICK_RANGE_SELECT *quick= (QUICK_RANGE_SELECT*)init_param; |
|
7045 |
quick->qr_traversal_ctx.first= (QUICK_RANGE**)quick->ranges.buffer; |
|
7046 |
quick->qr_traversal_ctx.cur= (QUICK_RANGE**)quick->ranges.buffer; |
|
77.1.46
by Monty Taylor
Finished the warnings work! |
7047 |
quick->qr_traversal_ctx.last= quick->qr_traversal_ctx.cur + |
1
by brian
clean slate |
7048 |
quick->ranges.elements; |
7049 |
return &quick->qr_traversal_ctx; |
|
7050 |
}
|
|
7051 |
||
7052 |
||
7053 |
/*
|
|
7054 |
Range sequence interface implementation for array<QUICK_RANGE>: get next
|
|
7055 |
|
|
7056 |
SYNOPSIS
|
|
7057 |
quick_range_seq_next()
|
|
7058 |
rseq Value returned from quick_range_seq_init
|
|
7059 |
range OUT Store information about the range here
|
|
7060 |
||
7061 |
RETURN
|
|
7062 |
0 Ok
|
|
7063 |
1 No more ranges in the sequence
|
|
7064 |
*/
|
|
7065 |
||
7066 |
uint quick_range_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range) |
|
7067 |
{
|
|
7068 |
QUICK_RANGE_SEQ_CTX *ctx= (QUICK_RANGE_SEQ_CTX*)rseq; |
|
7069 |
||
7070 |
if (ctx->cur == ctx->last) |
|
7071 |
return 1; /* no more ranges */ |
|
7072 |
||
7073 |
QUICK_RANGE *cur= *(ctx->cur); |
|
7074 |
key_range *start_key= &range->start_key; |
|
7075 |
key_range *end_key= &range->end_key; |
|
7076 |
||
7077 |
start_key->key= cur->min_key; |
|
7078 |
start_key->length= cur->min_length; |
|
7079 |
start_key->keypart_map= cur->min_keypart_map; |
|
7080 |
start_key->flag= ((cur->flag & NEAR_MIN) ? HA_READ_AFTER_KEY : |
|
7081 |
(cur->flag & EQ_RANGE) ? |
|
7082 |
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT); |
|
7083 |
end_key->key= cur->max_key; |
|
7084 |
end_key->length= cur->max_length; |
|
7085 |
end_key->keypart_map= cur->max_keypart_map; |
|
7086 |
/*
|
|
7087 |
We use HA_READ_AFTER_KEY here because if we are reading on a key
|
|
7088 |
prefix. We want to find all keys with this prefix.
|
|
7089 |
*/
|
|
7090 |
end_key->flag= (cur->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : |
|
7091 |
HA_READ_AFTER_KEY); |
|
7092 |
range->range_flag= cur->flag; |
|
7093 |
ctx->cur++; |
|
7094 |
return 0; |
|
7095 |
}
|
|
7096 |
||
7097 |
||
7098 |
/*
|
|
7099 |
MRR range sequence interface: array<QUICK_RANGE> impl: utility func for NDB
|
|
7100 |
||
7101 |
SYNOPSIS
|
|
7102 |
mrr_persistent_flag_storage()
|
|
7103 |
seq Range sequence being traversed
|
|
7104 |
idx Number of range
|
|
7105 |
||
7106 |
DESCRIPTION
|
|
7107 |
MRR/NDB implementation needs to store some bits for each range. This
|
|
7108 |
function returns a reference to the "range_flag" associated with the
|
|
7109 |
range number idx.
|
|
7110 |
||
7111 |
This function should be removed when we get a proper MRR/NDB
|
|
7112 |
implementation.
|
|
7113 |
||
7114 |
RETURN
|
|
7115 |
Reference to range_flag associated with range number #idx
|
|
7116 |
*/
|
|
7117 |
||
206
by Brian Aker
Removed final uint dead types. |
7118 |
uint16_t &mrr_persistent_flag_storage(range_seq_t seq, uint idx) |
1
by brian
clean slate |
7119 |
{
|
7120 |
QUICK_RANGE_SEQ_CTX *ctx= (QUICK_RANGE_SEQ_CTX*)seq; |
|
7121 |
return ctx->first[idx]->flag; |
|
7122 |
}
|
|
7123 |
||
7124 |
||
7125 |
/*
|
|
7126 |
MRR range sequence interface: array<QUICK_RANGE> impl: utility func for NDB
|
|
7127 |
||
7128 |
SYNOPSIS
|
|
7129 |
mrr_get_ptr_by_idx()
|
|
7130 |
seq Range sequence bening traversed
|
|
7131 |
idx Number of the range
|
|
7132 |
||
7133 |
DESCRIPTION
|
|
7134 |
An extension of MRR range sequence interface needed by NDB: return the
|
|
7135 |
data associated with the given range.
|
|
7136 |
||
7137 |
A proper MRR interface implementer is supposed to store and return
|
|
7138 |
range-associated data. NDB stores number of the range instead. So this
|
|
7139 |
is a helper function that translates range number to range associated
|
|
7140 |
data.
|
|
7141 |
||
7142 |
This function does nothing, as currrently there is only one user of the
|
|
7143 |
MRR interface - the quick range select code, and this user doesn't need
|
|
7144 |
to use range-associated data.
|
|
7145 |
||
7146 |
RETURN
|
|
7147 |
Reference to range-associated data
|
|
7148 |
*/
|
|
7149 |
||
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
7150 |
char* &mrr_get_ptr_by_idx(range_seq_t seq __attribute__((unused)), |
7151 |
uint idx __attribute__((unused))) |
|
1
by brian
clean slate |
7152 |
{
|
7153 |
static char *dummy; |
|
7154 |
return dummy; |
|
7155 |
}
|
|
7156 |
||
7157 |
||
7158 |
/*
|
|
7159 |
Get next possible record using quick-struct.
|
|
7160 |
||
7161 |
SYNOPSIS
|
|
7162 |
QUICK_RANGE_SELECT::get_next()
|
|
7163 |
||
7164 |
NOTES
|
|
7165 |
Record is read into table->record[0]
|
|
7166 |
||
7167 |
RETURN
|
|
7168 |
0 Found row
|
|
7169 |
HA_ERR_END_OF_FILE No (more) rows in range
|
|
7170 |
# Error code
|
|
7171 |
*/
|
|
7172 |
||
7173 |
int QUICK_RANGE_SELECT::get_next() |
|
7174 |
{
|
|
7175 |
char *dummy; |
|
7176 |
if (in_ror_merged_scan) |
|
7177 |
{
|
|
7178 |
/*
|
|
7179 |
We don't need to signal the bitmap change as the bitmap is always the
|
|
7180 |
same for this head->file
|
|
7181 |
*/
|
|
7182 |
head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap); |
|
7183 |
}
|
|
7184 |
||
7185 |
int result= file->multi_range_read_next(&dummy); |
|
7186 |
||
7187 |
if (in_ror_merged_scan) |
|
7188 |
{
|
|
7189 |
/* Restore bitmaps set on entry */
|
|
7190 |
head->column_bitmaps_set_no_signal(save_read_set, save_write_set); |
|
7191 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7192 |
return(result); |
1
by brian
clean slate |
7193 |
}
|
7194 |
||
7195 |
||
7196 |
/*
|
|
7197 |
Get the next record with a different prefix.
|
|
7198 |
||
7199 |
SYNOPSIS
|
|
7200 |
QUICK_RANGE_SELECT::get_next_prefix()
|
|
7201 |
prefix_length length of cur_prefix
|
|
7202 |
cur_prefix prefix of a key to be searched for
|
|
7203 |
||
7204 |
DESCRIPTION
|
|
7205 |
Each subsequent call to the method retrieves the first record that has a
|
|
7206 |
prefix with length prefix_length different from cur_prefix, such that the
|
|
7207 |
record with the new prefix is within the ranges described by
|
|
7208 |
this->ranges. The record found is stored into the buffer pointed by
|
|
7209 |
this->record.
|
|
7210 |
The method is useful for GROUP-BY queries with range conditions to
|
|
7211 |
discover the prefix of the next group that satisfies the range conditions.
|
|
7212 |
||
7213 |
TODO
|
|
7214 |
This method is a modified copy of QUICK_RANGE_SELECT::get_next(), so both
|
|
7215 |
methods should be unified into a more general one to reduce code
|
|
7216 |
duplication.
|
|
7217 |
||
7218 |
RETURN
|
|
7219 |
0 on success
|
|
7220 |
HA_ERR_END_OF_FILE if returned all keys
|
|
7221 |
other if some error occurred
|
|
7222 |
*/
|
|
7223 |
||
7224 |
int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, |
|
7225 |
key_part_map keypart_map, |
|
7226 |
uchar *cur_prefix) |
|
7227 |
{
|
|
7228 |
for (;;) |
|
7229 |
{
|
|
7230 |
int result; |
|
7231 |
key_range start_key, end_key; |
|
7232 |
if (last_range) |
|
7233 |
{
|
|
7234 |
/* Read the next record in the same range with prefix after cur_prefix. */
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7235 |
assert(cur_prefix != 0); |
1
by brian
clean slate |
7236 |
result= file->index_read_map(record, cur_prefix, keypart_map, |
7237 |
HA_READ_AFTER_KEY); |
|
7238 |
if (result || (file->compare_key(file->end_range) <= 0)) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7239 |
return(result); |
1
by brian
clean slate |
7240 |
}
|
7241 |
||
7242 |
uint count= ranges.elements - (cur_range - (QUICK_RANGE**) ranges.buffer); |
|
7243 |
if (count == 0) |
|
7244 |
{
|
|
7245 |
/* Ranges have already been used up before. None is left for read. */
|
|
7246 |
last_range= 0; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7247 |
return(HA_ERR_END_OF_FILE); |
1
by brian
clean slate |
7248 |
}
|
7249 |
last_range= *(cur_range++); |
|
7250 |
||
7251 |
start_key.key= (const uchar*) last_range->min_key; |
|
287.3.8
by Monty Taylor
Oy. Replaced max and min macros with std::max and std::min so that we get |
7252 |
start_key.length= min(last_range->min_length, (uint16_t)prefix_length); |
1
by brian
clean slate |
7253 |
start_key.keypart_map= last_range->min_keypart_map & keypart_map; |
7254 |
start_key.flag= ((last_range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY : |
|
7255 |
(last_range->flag & EQ_RANGE) ? |
|
7256 |
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT); |
|
7257 |
end_key.key= (const uchar*) last_range->max_key; |
|
287.3.8
by Monty Taylor
Oy. Replaced max and min macros with std::max and std::min so that we get |
7258 |
end_key.length= min(last_range->max_length, (uint16_t)prefix_length); |
1
by brian
clean slate |
7259 |
end_key.keypart_map= last_range->max_keypart_map & keypart_map; |
7260 |
/*
|
|
7261 |
We use READ_AFTER_KEY here because if we are reading on a key
|
|
7262 |
prefix we want to find all keys with this prefix
|
|
7263 |
*/
|
|
7264 |
end_key.flag= (last_range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : |
|
7265 |
HA_READ_AFTER_KEY); |
|
7266 |
||
7267 |
result= file->read_range_first(last_range->min_keypart_map ? &start_key : 0, |
|
7268 |
last_range->max_keypart_map ? &end_key : 0, |
|
7269 |
test(last_range->flag & EQ_RANGE), |
|
7270 |
sorted); |
|
7271 |
if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE)) |
|
7272 |
last_range= 0; // Stop searching |
|
7273 |
||
7274 |
if (result != HA_ERR_END_OF_FILE) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7275 |
return(result); |
1
by brian
clean slate |
7276 |
last_range= 0; // No matching rows; go to next range |
7277 |
}
|
|
7278 |
}
|
|
7279 |
||
7280 |
||
7281 |
/*
|
|
7282 |
Check if current row will be retrieved by this QUICK_RANGE_SELECT
|
|
7283 |
||
7284 |
NOTES
|
|
7285 |
It is assumed that currently a scan is being done on another index
|
|
7286 |
which reads all necessary parts of the index that is scanned by this
|
|
7287 |
quick select.
|
|
7288 |
The implementation does a binary search on sorted array of disjoint
|
|
7289 |
ranges, without taking size of range into account.
|
|
7290 |
||
7291 |
This function is used to filter out clustered PK scan rows in
|
|
7292 |
index_merge quick select.
|
|
7293 |
||
7294 |
RETURN
|
|
55
by brian
Update for using real bool types. |
7295 |
true if current row will be retrieved by this quick select
|
7296 |
false if not
|
|
1
by brian
clean slate |
7297 |
*/
|
7298 |
||
7299 |
bool QUICK_RANGE_SELECT::row_in_ranges() |
|
7300 |
{
|
|
7301 |
QUICK_RANGE *res; |
|
7302 |
uint min= 0; |
|
7303 |
uint max= ranges.elements - 1; |
|
7304 |
uint mid= (max + min)/2; |
|
7305 |
||
7306 |
while (min != max) |
|
7307 |
{
|
|
7308 |
if (cmp_next(*(QUICK_RANGE**)dynamic_array_ptr(&ranges, mid))) |
|
7309 |
{
|
|
7310 |
/* current row value > mid->max */
|
|
7311 |
min= mid + 1; |
|
7312 |
}
|
|
7313 |
else
|
|
7314 |
max= mid; |
|
7315 |
mid= (min + max) / 2; |
|
7316 |
}
|
|
7317 |
res= *(QUICK_RANGE**)dynamic_array_ptr(&ranges, mid); |
|
7318 |
return (!cmp_next(res) && !cmp_prev(res)); |
|
7319 |
}
|
|
7320 |
||
7321 |
/*
|
|
7322 |
This is a hack: we inherit from QUICK_SELECT so that we can use the
|
|
7323 |
get_next() interface, but we have to hold a pointer to the original
|
|
7324 |
QUICK_SELECT because its data are used all over the place. What
|
|
7325 |
should be done is to factor out the data that is needed into a base
|
|
7326 |
class (QUICK_SELECT), and then have two subclasses (_ASC and _DESC)
|
|
7327 |
which handle the ranges and implement the get_next() function. But
|
|
7328 |
for now, this seems to work right at least.
|
|
7329 |
*/
|
|
7330 |
||
7331 |
QUICK_SELECT_DESC::QUICK_SELECT_DESC(QUICK_RANGE_SELECT *q, |
|
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
7332 |
uint used_key_parts_arg __attribute__((unused)), |
7333 |
bool *create_err __attribute__((unused))) |
|
1
by brian
clean slate |
7334 |
:QUICK_RANGE_SELECT(*q), rev_it(rev_ranges) |
7335 |
{
|
|
7336 |
QUICK_RANGE *r; |
|
7337 |
||
7338 |
QUICK_RANGE **pr= (QUICK_RANGE**)ranges.buffer; |
|
7339 |
QUICK_RANGE **end_range= pr + ranges.elements; |
|
7340 |
for (; pr!=end_range; pr++) |
|
7341 |
rev_ranges.push_front(*pr); |
|
7342 |
||
7343 |
/* Remove EQ_RANGE flag for keys that are not using the full key */
|
|
7344 |
for (r = rev_it++; r; r = rev_it++) |
|
7345 |
{
|
|
7346 |
if ((r->flag & EQ_RANGE) && |
|
7347 |
head->key_info[index].key_length != r->max_length) |
|
7348 |
r->flag&= ~EQ_RANGE; |
|
7349 |
}
|
|
7350 |
rev_it.rewind(); |
|
7351 |
q->dont_free=1; // Don't free shared mem |
|
7352 |
delete q; |
|
7353 |
}
|
|
7354 |
||
7355 |
||
7356 |
int QUICK_SELECT_DESC::get_next() |
|
7357 |
{
|
|
7358 |
/* The max key is handled as follows:
|
|
7359 |
* - if there is NO_MAX_RANGE, start at the end and move backwards
|
|
7360 |
* - if it is an EQ_RANGE, which means that max key covers the entire
|
|
7361 |
* key, go directly to the key and read through it (sorting backwards is
|
|
7362 |
* same as sorting forwards)
|
|
7363 |
* - if it is NEAR_MAX, go to the key or next, step back once, and
|
|
7364 |
* move backwards
|
|
7365 |
* - otherwise (not NEAR_MAX == include the key), go after the key,
|
|
7366 |
* step back once, and move backwards
|
|
7367 |
*/
|
|
7368 |
||
7369 |
for (;;) |
|
7370 |
{
|
|
7371 |
int result; |
|
7372 |
if (last_range) |
|
7373 |
{ // Already read through key |
|
7374 |
result = ((last_range->flag & EQ_RANGE) |
|
7375 |
? file->index_next_same(record, last_range->min_key, |
|
7376 |
last_range->min_length) : |
|
7377 |
file->index_prev(record)); |
|
7378 |
if (!result) |
|
7379 |
{
|
|
7380 |
if (cmp_prev(*rev_it.ref()) == 0) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7381 |
return(0); |
1
by brian
clean slate |
7382 |
}
|
7383 |
else if (result != HA_ERR_END_OF_FILE) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7384 |
return(result); |
1
by brian
clean slate |
7385 |
}
|
7386 |
||
7387 |
if (!(last_range= rev_it++)) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7388 |
return(HA_ERR_END_OF_FILE); // All ranges used |
1
by brian
clean slate |
7389 |
|
7390 |
if (last_range->flag & NO_MAX_RANGE) // Read last record |
|
7391 |
{
|
|
7392 |
int local_error; |
|
7393 |
if ((local_error=file->index_last(record))) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7394 |
return(local_error); // Empty table |
1
by brian
clean slate |
7395 |
if (cmp_prev(last_range) == 0) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7396 |
return(0); |
1
by brian
clean slate |
7397 |
last_range= 0; // No match; go to next range |
7398 |
continue; |
|
7399 |
}
|
|
7400 |
||
7401 |
if (last_range->flag & EQ_RANGE) |
|
7402 |
{
|
|
7403 |
result = file->index_read_map(record, last_range->max_key, |
|
7404 |
last_range->max_keypart_map, |
|
7405 |
HA_READ_KEY_EXACT); |
|
7406 |
}
|
|
7407 |
else
|
|
7408 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7409 |
assert(last_range->flag & NEAR_MAX || |
1
by brian
clean slate |
7410 |
range_reads_after_key(last_range)); |
7411 |
result=file->index_read_map(record, last_range->max_key, |
|
7412 |
last_range->max_keypart_map, |
|
7413 |
((last_range->flag & NEAR_MAX) ? |
|
7414 |
HA_READ_BEFORE_KEY : |
|
7415 |
HA_READ_PREFIX_LAST_OR_PREV)); |
|
7416 |
}
|
|
7417 |
if (result) |
|
7418 |
{
|
|
7419 |
if (result != HA_ERR_KEY_NOT_FOUND && result != HA_ERR_END_OF_FILE) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7420 |
return(result); |
1
by brian
clean slate |
7421 |
last_range= 0; // Not found, to next range |
7422 |
continue; |
|
7423 |
}
|
|
7424 |
if (cmp_prev(last_range) == 0) |
|
7425 |
{
|
|
7426 |
if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE)) |
|
7427 |
last_range= 0; // Stop searching |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7428 |
return(0); // Found key is in range |
1
by brian
clean slate |
7429 |
}
|
7430 |
last_range= 0; // To next range |
|
7431 |
}
|
|
7432 |
}
|
|
7433 |
||
7434 |
||
7435 |
/*
|
|
7436 |
Compare if found key is over max-value
|
|
7437 |
Returns 0 if key <= range->max_key
|
|
7438 |
TODO: Figure out why can't this function be as simple as cmp_prev().
|
|
7439 |
*/
|
|
7440 |
||
7441 |
int QUICK_RANGE_SELECT::cmp_next(QUICK_RANGE *range_arg) |
|
7442 |
{
|
|
7443 |
if (range_arg->flag & NO_MAX_RANGE) |
|
7444 |
return 0; /* key can't be to large */ |
|
7445 |
||
7446 |
KEY_PART *key_part=key_parts; |
|
7447 |
uint store_length; |
|
7448 |
||
7449 |
for (uchar *key=range_arg->max_key, *end=key+range_arg->max_length; |
|
7450 |
key < end; |
|
7451 |
key+= store_length, key_part++) |
|
7452 |
{
|
|
7453 |
int cmp; |
|
7454 |
store_length= key_part->store_length; |
|
7455 |
if (key_part->null_bit) |
|
7456 |
{
|
|
7457 |
if (*key) |
|
7458 |
{
|
|
7459 |
if (!key_part->field->is_null()) |
|
7460 |
return 1; |
|
7461 |
continue; |
|
7462 |
}
|
|
7463 |
else if (key_part->field->is_null()) |
|
7464 |
return 0; |
|
7465 |
key++; // Skip null byte |
|
7466 |
store_length--; |
|
7467 |
}
|
|
7468 |
if ((cmp=key_part->field->key_cmp(key, key_part->length)) < 0) |
|
7469 |
return 0; |
|
7470 |
if (cmp > 0) |
|
7471 |
return 1; |
|
7472 |
}
|
|
7473 |
return (range_arg->flag & NEAR_MAX) ? 1 : 0; // Exact match |
|
7474 |
}
|
|
7475 |
||
7476 |
||
7477 |
/*
|
|
7478 |
Returns 0 if found key is inside range (found key >= range->min_key).
|
|
7479 |
*/
|
|
7480 |
||
7481 |
int QUICK_RANGE_SELECT::cmp_prev(QUICK_RANGE *range_arg) |
|
7482 |
{
|
|
7483 |
int cmp; |
|
7484 |
if (range_arg->flag & NO_MIN_RANGE) |
|
7485 |
return 0; /* key can't be to small */ |
|
7486 |
||
7487 |
cmp= key_cmp(key_part_info, range_arg->min_key, |
|
7488 |
range_arg->min_length); |
|
7489 |
if (cmp > 0 || (cmp == 0 && (range_arg->flag & NEAR_MIN) == false)) |
|
7490 |
return 0; |
|
7491 |
return 1; // outside of range |
|
7492 |
}
|
|
7493 |
||
7494 |
||
7495 |
/*
|
|
55
by brian
Update for using real bool types. |
7496 |
* true if this range will require using HA_READ_AFTER_KEY
|
1
by brian
clean slate |
7497 |
See comment in get_next() about this
|
7498 |
*/
|
|
7499 |
||
7500 |
bool QUICK_SELECT_DESC::range_reads_after_key(QUICK_RANGE *range_arg) |
|
7501 |
{
|
|
7502 |
return ((range_arg->flag & (NO_MAX_RANGE | NEAR_MAX)) || |
|
7503 |
!(range_arg->flag & EQ_RANGE) || |
|
7504 |
head->key_info[index].key_length != range_arg->max_length) ? 1 : 0; |
|
7505 |
}
|
|
7506 |
||
7507 |
||
7508 |
void QUICK_RANGE_SELECT::add_info_string(String *str) |
|
7509 |
{
|
|
7510 |
KEY *key_info= head->key_info + index; |
|
7511 |
str->append(key_info->name); |
|
7512 |
}
|
|
7513 |
||
7514 |
void QUICK_INDEX_MERGE_SELECT::add_info_string(String *str) |
|
7515 |
{
|
|
7516 |
QUICK_RANGE_SELECT *quick; |
|
55
by brian
Update for using real bool types. |
7517 |
bool first= true; |
1
by brian
clean slate |
7518 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
7519 |
str->append(STRING_WITH_LEN("sort_union(")); |
|
7520 |
while ((quick= it++)) |
|
7521 |
{
|
|
7522 |
if (!first) |
|
7523 |
str->append(','); |
|
7524 |
else
|
|
55
by brian
Update for using real bool types. |
7525 |
first= false; |
1
by brian
clean slate |
7526 |
quick->add_info_string(str); |
7527 |
}
|
|
7528 |
if (pk_quick_select) |
|
7529 |
{
|
|
7530 |
str->append(','); |
|
7531 |
pk_quick_select->add_info_string(str); |
|
7532 |
}
|
|
7533 |
str->append(')'); |
|
7534 |
}
|
|
7535 |
||
7536 |
void QUICK_ROR_INTERSECT_SELECT::add_info_string(String *str) |
|
7537 |
{
|
|
55
by brian
Update for using real bool types. |
7538 |
bool first= true; |
1
by brian
clean slate |
7539 |
QUICK_RANGE_SELECT *quick; |
7540 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
|
7541 |
str->append(STRING_WITH_LEN("intersect(")); |
|
7542 |
while ((quick= it++)) |
|
7543 |
{
|
|
7544 |
KEY *key_info= head->key_info + quick->index; |
|
7545 |
if (!first) |
|
7546 |
str->append(','); |
|
7547 |
else
|
|
55
by brian
Update for using real bool types. |
7548 |
first= false; |
1
by brian
clean slate |
7549 |
str->append(key_info->name); |
7550 |
}
|
|
7551 |
if (cpk_quick) |
|
7552 |
{
|
|
7553 |
KEY *key_info= head->key_info + cpk_quick->index; |
|
7554 |
str->append(','); |
|
7555 |
str->append(key_info->name); |
|
7556 |
}
|
|
7557 |
str->append(')'); |
|
7558 |
}
|
|
7559 |
||
7560 |
void QUICK_ROR_UNION_SELECT::add_info_string(String *str) |
|
7561 |
{
|
|
55
by brian
Update for using real bool types. |
7562 |
bool first= true; |
1
by brian
clean slate |
7563 |
QUICK_SELECT_I *quick; |
7564 |
List_iterator_fast<QUICK_SELECT_I> it(quick_selects); |
|
7565 |
str->append(STRING_WITH_LEN("union(")); |
|
7566 |
while ((quick= it++)) |
|
7567 |
{
|
|
7568 |
if (!first) |
|
7569 |
str->append(','); |
|
7570 |
else
|
|
55
by brian
Update for using real bool types. |
7571 |
first= false; |
1
by brian
clean slate |
7572 |
quick->add_info_string(str); |
7573 |
}
|
|
7574 |
str->append(')'); |
|
7575 |
}
|
|
7576 |
||
7577 |
||
7578 |
void QUICK_RANGE_SELECT::add_keys_and_lengths(String *key_names, |
|
7579 |
String *used_lengths) |
|
7580 |
{
|
|
7581 |
char buf[64]; |
|
7582 |
uint length; |
|
7583 |
KEY *key_info= head->key_info + index; |
|
7584 |
key_names->append(key_info->name); |
|
152
by Brian Aker
longlong replacement |
7585 |
length= int64_t2str(max_used_key_length, buf, 10) - buf; |
1
by brian
clean slate |
7586 |
used_lengths->append(buf, length); |
7587 |
}
|
|
7588 |
||
7589 |
void QUICK_INDEX_MERGE_SELECT::add_keys_and_lengths(String *key_names, |
|
7590 |
String *used_lengths) |
|
7591 |
{
|
|
7592 |
char buf[64]; |
|
7593 |
uint length; |
|
55
by brian
Update for using real bool types. |
7594 |
bool first= true; |
1
by brian
clean slate |
7595 |
QUICK_RANGE_SELECT *quick; |
7596 |
||
7597 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
|
7598 |
while ((quick= it++)) |
|
7599 |
{
|
|
7600 |
if (first) |
|
55
by brian
Update for using real bool types. |
7601 |
first= false; |
1
by brian
clean slate |
7602 |
else
|
7603 |
{
|
|
7604 |
key_names->append(','); |
|
7605 |
used_lengths->append(','); |
|
7606 |
}
|
|
7607 |
||
7608 |
KEY *key_info= head->key_info + quick->index; |
|
7609 |
key_names->append(key_info->name); |
|
152
by Brian Aker
longlong replacement |
7610 |
length= int64_t2str(quick->max_used_key_length, buf, 10) - buf; |
1
by brian
clean slate |
7611 |
used_lengths->append(buf, length); |
7612 |
}
|
|
7613 |
if (pk_quick_select) |
|
7614 |
{
|
|
7615 |
KEY *key_info= head->key_info + pk_quick_select->index; |
|
7616 |
key_names->append(','); |
|
7617 |
key_names->append(key_info->name); |
|
152
by Brian Aker
longlong replacement |
7618 |
length= int64_t2str(pk_quick_select->max_used_key_length, buf, 10) - buf; |
1
by brian
clean slate |
7619 |
used_lengths->append(','); |
7620 |
used_lengths->append(buf, length); |
|
7621 |
}
|
|
7622 |
}
|
|
7623 |
||
7624 |
void QUICK_ROR_INTERSECT_SELECT::add_keys_and_lengths(String *key_names, |
|
7625 |
String *used_lengths) |
|
7626 |
{
|
|
7627 |
char buf[64]; |
|
7628 |
uint length; |
|
55
by brian
Update for using real bool types. |
7629 |
bool first= true; |
1
by brian
clean slate |
7630 |
QUICK_RANGE_SELECT *quick; |
7631 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
|
7632 |
while ((quick= it++)) |
|
7633 |
{
|
|
7634 |
KEY *key_info= head->key_info + quick->index; |
|
7635 |
if (first) |
|
55
by brian
Update for using real bool types. |
7636 |
first= false; |
1
by brian
clean slate |
7637 |
else
|
7638 |
{
|
|
7639 |
key_names->append(','); |
|
7640 |
used_lengths->append(','); |
|
7641 |
}
|
|
7642 |
key_names->append(key_info->name); |
|
152
by Brian Aker
longlong replacement |
7643 |
length= int64_t2str(quick->max_used_key_length, buf, 10) - buf; |
1
by brian
clean slate |
7644 |
used_lengths->append(buf, length); |
7645 |
}
|
|
7646 |
||
7647 |
if (cpk_quick) |
|
7648 |
{
|
|
7649 |
KEY *key_info= head->key_info + cpk_quick->index; |
|
7650 |
key_names->append(','); |
|
7651 |
key_names->append(key_info->name); |
|
152
by Brian Aker
longlong replacement |
7652 |
length= int64_t2str(cpk_quick->max_used_key_length, buf, 10) - buf; |
1
by brian
clean slate |
7653 |
used_lengths->append(','); |
7654 |
used_lengths->append(buf, length); |
|
7655 |
}
|
|
7656 |
}
|
|
7657 |
||
7658 |
void QUICK_ROR_UNION_SELECT::add_keys_and_lengths(String *key_names, |
|
7659 |
String *used_lengths) |
|
7660 |
{
|
|
55
by brian
Update for using real bool types. |
7661 |
bool first= true; |
1
by brian
clean slate |
7662 |
QUICK_SELECT_I *quick; |
7663 |
List_iterator_fast<QUICK_SELECT_I> it(quick_selects); |
|
7664 |
while ((quick= it++)) |
|
7665 |
{
|
|
7666 |
if (first) |
|
55
by brian
Update for using real bool types. |
7667 |
first= false; |
1
by brian
clean slate |
7668 |
else
|
7669 |
{
|
|
7670 |
used_lengths->append(','); |
|
7671 |
key_names->append(','); |
|
7672 |
}
|
|
7673 |
quick->add_keys_and_lengths(key_names, used_lengths); |
|
7674 |
}
|
|
7675 |
}
|
|
7676 |
||
7677 |
||
7678 |
/*******************************************************************************
|
|
7679 |
* Implementation of QUICK_GROUP_MIN_MAX_SELECT
|
|
7680 |
*******************************************************************************/
|
|
7681 |
||
7682 |
static inline uint get_field_keypart(KEY *index, Field *field); |
|
7683 |
static inline SEL_ARG * get_index_range_tree(uint index, SEL_TREE* range_tree, |
|
7684 |
PARAM *param, uint *param_idx); |
|
7685 |
static bool get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree, |
|
7686 |
KEY_PART_INFO *first_non_group_part, |
|
7687 |
KEY_PART_INFO *min_max_arg_part, |
|
7688 |
KEY_PART_INFO *last_part, THD *thd, |
|
7689 |
uchar *key_infix, uint *key_infix_len, |
|
7690 |
KEY_PART_INFO **first_non_infix_part); |
|
7691 |
static bool |
|
7692 |
check_group_min_max_predicates(COND *cond, Item_field *min_max_arg_item, |
|
7693 |
Field::imagetype image_type); |
|
7694 |
||
7695 |
static void |
|
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
7696 |
cost_group_min_max(Table* table, KEY *index_info, uint used_key_parts, |
1
by brian
clean slate |
7697 |
uint group_key_parts, SEL_TREE *range_tree, |
7698 |
SEL_ARG *index_tree, ha_rows quick_prefix_records, |
|
7699 |
bool have_min, bool have_max, |
|
7700 |
double *read_cost, ha_rows *records); |
|
7701 |
||
7702 |
||
7703 |
/*
|
|
7704 |
Test if this access method is applicable to a GROUP query with MIN/MAX
|
|
7705 |
functions, and if so, construct a new TRP object.
|
|
7706 |
||
7707 |
SYNOPSIS
|
|
7708 |
get_best_group_min_max()
|
|
7709 |
param Parameter from test_quick_select
|
|
7710 |
sel_tree Range tree generated by get_mm_tree
|
|
7711 |
||
7712 |
DESCRIPTION
|
|
7713 |
Test whether a query can be computed via a QUICK_GROUP_MIN_MAX_SELECT.
|
|
7714 |
Queries computable via a QUICK_GROUP_MIN_MAX_SELECT must satisfy the
|
|
7715 |
following conditions:
|
|
7716 |
A) Table T has at least one compound index I of the form:
|
|
7717 |
I = <A_1, ...,A_k, [B_1,..., B_m], C, [D_1,...,D_n]>
|
|
7718 |
B) Query conditions:
|
|
7719 |
B0. Q is over a single table T.
|
|
7720 |
B1. The attributes referenced by Q are a subset of the attributes of I.
|
|
7721 |
B2. All attributes QA in Q can be divided into 3 overlapping groups:
|
|
7722 |
- SA = {S_1, ..., S_l, [C]} - from the SELECT clause, where C is
|
|
7723 |
referenced by any number of MIN and/or MAX functions if present.
|
|
7724 |
- WA = {W_1, ..., W_p} - from the WHERE clause
|
|
7725 |
- GA = <G_1, ..., G_k> - from the GROUP BY clause (if any)
|
|
7726 |
= SA - if Q is a DISTINCT query (based on the
|
|
7727 |
equivalence of DISTINCT and GROUP queries.
|
|
7728 |
- NGA = QA - (GA union C) = {NG_1, ..., NG_m} - the ones not in
|
|
7729 |
GROUP BY and not referenced by MIN/MAX functions.
|
|
7730 |
with the following properties specified below.
|
|
7731 |
B3. If Q has a GROUP BY WITH ROLLUP clause the access method is not
|
|
7732 |
applicable.
|
|
7733 |
||
7734 |
SA1. There is at most one attribute in SA referenced by any number of
|
|
7735 |
MIN and/or MAX functions which, which if present, is denoted as C.
|
|
7736 |
SA2. The position of the C attribute in the index is after the last A_k.
|
|
7737 |
SA3. The attribute C can be referenced in the WHERE clause only in
|
|
7738 |
predicates of the forms:
|
|
7739 |
- (C {< | <= | > | >= | =} const)
|
|
7740 |
- (const {< | <= | > | >= | =} C)
|
|
7741 |
- (C between const_i and const_j)
|
|
7742 |
- C IS NULL
|
|
7743 |
- C IS NOT NULL
|
|
7744 |
- C != const
|
|
7745 |
SA4. If Q has a GROUP BY clause, there are no other aggregate functions
|
|
7746 |
except MIN and MAX. For queries with DISTINCT, aggregate functions
|
|
7747 |
are allowed.
|
|
7748 |
SA5. The select list in DISTINCT queries should not contain expressions.
|
|
7749 |
GA1. If Q has a GROUP BY clause, then GA is a prefix of I. That is, if
|
|
7750 |
G_i = A_j => i = j.
|
|
7751 |
GA2. If Q has a DISTINCT clause, then there is a permutation of SA that
|
|
7752 |
forms a prefix of I. This permutation is used as the GROUP clause
|
|
7753 |
when the DISTINCT query is converted to a GROUP query.
|
|
7754 |
GA3. The attributes in GA may participate in arbitrary predicates, divided
|
|
7755 |
into two groups:
|
|
7756 |
- RNG(G_1,...,G_q ; where q <= k) is a range condition over the
|
|
7757 |
attributes of a prefix of GA
|
|
7758 |
- PA(G_i1,...G_iq) is an arbitrary predicate over an arbitrary subset
|
|
7759 |
of GA. Since P is applied to only GROUP attributes it filters some
|
|
7760 |
groups, and thus can be applied after the grouping.
|
|
7761 |
GA4. There are no expressions among G_i, just direct column references.
|
|
7762 |
NGA1.If in the index I there is a gap between the last GROUP attribute G_k,
|
|
7763 |
and the MIN/MAX attribute C, then NGA must consist of exactly the
|
|
7764 |
index attributes that constitute the gap. As a result there is a
|
|
7765 |
permutation of NGA that coincides with the gap in the index
|
|
7766 |
<B_1, ..., B_m>.
|
|
7767 |
NGA2.If BA <> {}, then the WHERE clause must contain a conjunction EQ of
|
|
7768 |
equality conditions for all NG_i of the form (NG_i = const) or
|
|
7769 |
(const = NG_i), such that each NG_i is referenced in exactly one
|
|
7770 |
conjunct. Informally, the predicates provide constants to fill the
|
|
7771 |
gap in the index.
|
|
7772 |
WA1. There are no other attributes in the WHERE clause except the ones
|
|
7773 |
referenced in predicates RNG, PA, PC, EQ defined above. Therefore
|
|
7774 |
WA is subset of (GA union NGA union C) for GA,NGA,C that pass the
|
|
7775 |
above tests. By transitivity then it also follows that each WA_i
|
|
7776 |
participates in the index I (if this was already tested for GA, NGA
|
|
7777 |
and C).
|
|
7778 |
||
7779 |
C) Overall query form:
|
|
7780 |
SELECT EXPR([A_1,...,A_k], [B_1,...,B_m], [MIN(C)], [MAX(C)])
|
|
7781 |
FROM T
|
|
7782 |
WHERE [RNG(A_1,...,A_p ; where p <= k)]
|
|
7783 |
[AND EQ(B_1,...,B_m)]
|
|
7784 |
[AND PC(C)]
|
|
7785 |
[AND PA(A_i1,...,A_iq)]
|
|
7786 |
GROUP BY A_1,...,A_k
|
|
7787 |
[HAVING PH(A_1, ..., B_1,..., C)]
|
|
7788 |
where EXPR(...) is an arbitrary expression over some or all SELECT fields,
|
|
7789 |
or:
|
|
7790 |
SELECT DISTINCT A_i1,...,A_ik
|
|
7791 |
FROM T
|
|
7792 |
WHERE [RNG(A_1,...,A_p ; where p <= k)]
|
|
7793 |
[AND PA(A_i1,...,A_iq)];
|
|
7794 |
||
7795 |
NOTES
|
|
7796 |
If the current query satisfies the conditions above, and if
|
|
7797 |
(mem_root! = NULL), then the function constructs and returns a new TRP
|
|
7798 |
object, that is later used to construct a new QUICK_GROUP_MIN_MAX_SELECT.
|
|
7799 |
If (mem_root == NULL), then the function only tests whether the current
|
|
7800 |
query satisfies the conditions above, and, if so, sets
|
|
55
by brian
Update for using real bool types. |
7801 |
is_applicable = true.
|
1
by brian
clean slate |
7802 |
|
7803 |
Queries with DISTINCT for which index access can be used are transformed
|
|
7804 |
into equivalent group-by queries of the form:
|
|
7805 |
||
7806 |
SELECT A_1,...,A_k FROM T
|
|
7807 |
WHERE [RNG(A_1,...,A_p ; where p <= k)]
|
|
7808 |
[AND PA(A_i1,...,A_iq)]
|
|
7809 |
GROUP BY A_1,...,A_k;
|
|
7810 |
||
7811 |
The group-by list is a permutation of the select attributes, according
|
|
7812 |
to their order in the index.
|
|
7813 |
||
7814 |
TODO
|
|
7815 |
- What happens if the query groups by the MIN/MAX field, and there is no
|
|
7816 |
other field as in: "select min(a) from t1 group by a" ?
|
|
7817 |
- We assume that the general correctness of the GROUP-BY query was checked
|
|
7818 |
before this point. Is this correct, or do we have to check it completely?
|
|
7819 |
- Lift the limitation in condition (B3), that is, make this access method
|
|
7820 |
applicable to ROLLUP queries.
|
|
7821 |
||
7822 |
RETURN
|
|
7823 |
If mem_root != NULL
|
|
7824 |
- valid TRP_GROUP_MIN_MAX object if this QUICK class can be used for
|
|
7825 |
the query
|
|
7826 |
- NULL o/w.
|
|
7827 |
If mem_root == NULL
|
|
7828 |
- NULL
|
|
7829 |
*/
|
|
7830 |
||
7831 |
static TRP_GROUP_MIN_MAX * |
|
7832 |
get_best_group_min_max(PARAM *param, SEL_TREE *tree) |
|
7833 |
{
|
|
7834 |
THD *thd= param->thd; |
|
7835 |
JOIN *join= thd->lex->current_select->join; |
|
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
7836 |
Table *table= param->table; |
55
by brian
Update for using real bool types. |
7837 |
bool have_min= false; /* true if there is a MIN function. */ |
7838 |
bool have_max= false; /* true if there is a MAX function. */ |
|
1
by brian
clean slate |
7839 |
Item_field *min_max_arg_item= NULL; // The argument of all MIN/MAX functions |
7840 |
KEY_PART_INFO *min_max_arg_part= NULL; /* The corresponding keypart. */ |
|
7841 |
uint group_prefix_len= 0; /* Length (in bytes) of the key prefix. */ |
|
7842 |
KEY *index_info= NULL; /* The index chosen for data access. */ |
|
7843 |
uint index= 0; /* The id of the chosen index. */ |
|
7844 |
uint group_key_parts= 0; // Number of index key parts in the group prefix. |
|
7845 |
uint used_key_parts= 0; /* Number of index key parts used for access. */ |
|
7846 |
uchar key_infix[MAX_KEY_LENGTH]; /* Constants from equality predicates.*/ |
|
7847 |
uint key_infix_len= 0; /* Length of key_infix. */ |
|
7848 |
TRP_GROUP_MIN_MAX *read_plan= NULL; /* The eventually constructed TRP. */ |
|
7849 |
uint key_part_nr; |
|
327.2.3
by Brian Aker
Refactoring of class Table |
7850 |
order_st *tmp_group; |
1
by brian
clean slate |
7851 |
Item *item; |
7852 |
Item_field *item_field; |
|
7853 |
||
7854 |
/* Perform few 'cheap' tests whether this access method is applicable. */
|
|
7855 |
if (!join) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7856 |
return(NULL); /* This is not a select statement. */ |
1
by brian
clean slate |
7857 |
if ((join->tables != 1) || /* The query must reference one table. */ |
7858 |
((!join->group_list) && /* Neither GROUP BY nor a DISTINCT query. */ |
|
7859 |
(!join->select_distinct)) || |
|
7860 |
(join->select_lex->olap == ROLLUP_TYPE)) /* Check (B3) for ROLLUP */ |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7861 |
return(NULL); |
1
by brian
clean slate |
7862 |
if (table->s->keys == 0) /* There are no indexes to use. */ |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7863 |
return(NULL); |
1
by brian
clean slate |
7864 |
|
7865 |
/* Analyze the query in more detail. */
|
|
7866 |
List_iterator<Item> select_items_it(join->fields_list); |
|
7867 |
||
7868 |
/* Check (SA1,SA4) and store the only MIN/MAX argument - the C attribute.*/
|
|
7869 |
if (join->make_sum_func_list(join->all_fields, join->fields_list, 1)) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7870 |
return(NULL); |
1
by brian
clean slate |
7871 |
if (join->sum_funcs[0]) |
7872 |
{
|
|
7873 |
Item_sum *min_max_item; |
|
7874 |
Item_sum **func_ptr= join->sum_funcs; |
|
7875 |
while ((min_max_item= *(func_ptr++))) |
|
7876 |
{
|
|
7877 |
if (min_max_item->sum_func() == Item_sum::MIN_FUNC) |
|
55
by brian
Update for using real bool types. |
7878 |
have_min= true; |
1
by brian
clean slate |
7879 |
else if (min_max_item->sum_func() == Item_sum::MAX_FUNC) |
55
by brian
Update for using real bool types. |
7880 |
have_max= true; |
1
by brian
clean slate |
7881 |
else
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7882 |
return(NULL); |
1
by brian
clean slate |
7883 |
|
7884 |
/* The argument of MIN/MAX. */
|
|
7885 |
Item *expr= min_max_item->args[0]->real_item(); |
|
7886 |
if (expr->type() == Item::FIELD_ITEM) /* Is it an attribute? */ |
|
7887 |
{
|
|
7888 |
if (! min_max_arg_item) |
|
7889 |
min_max_arg_item= (Item_field*) expr; |
|
7890 |
else if (! min_max_arg_item->eq(expr, 1)) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7891 |
return(NULL); |
1
by brian
clean slate |
7892 |
}
|
7893 |
else
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7894 |
return(NULL); |
1
by brian
clean slate |
7895 |
}
|
7896 |
}
|
|
7897 |
||
7898 |
/* Check (SA5). */
|
|
7899 |
if (join->select_distinct) |
|
7900 |
{
|
|
7901 |
while ((item= select_items_it++)) |
|
7902 |
{
|
|
7903 |
if (item->type() != Item::FIELD_ITEM) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7904 |
return(NULL); |
1
by brian
clean slate |
7905 |
}
|
7906 |
}
|
|
7907 |
||
7908 |
/* Check (GA4) - that there are no expressions among the group attributes. */
|
|
7909 |
for (tmp_group= join->group_list; tmp_group; tmp_group= tmp_group->next) |
|
7910 |
{
|
|
7911 |
if ((*tmp_group->item)->type() != Item::FIELD_ITEM) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7912 |
return(NULL); |
1
by brian
clean slate |
7913 |
}
|
7914 |
||
7915 |
/*
|
|
7916 |
Check that table has at least one compound index such that the conditions
|
|
55
by brian
Update for using real bool types. |
7917 |
(GA1,GA2) are all true. If there is more than one such index, select the
|
1
by brian
clean slate |
7918 |
first one. Here we set the variables: group_prefix_len and index_info.
|
7919 |
*/
|
|
7920 |
KEY *cur_index_info= table->key_info; |
|
7921 |
KEY *cur_index_info_end= cur_index_info + table->s->keys; |
|
7922 |
KEY_PART_INFO *cur_part= NULL; |
|
7923 |
KEY_PART_INFO *end_part; /* Last part for loops. */ |
|
7924 |
/* Last index part. */
|
|
7925 |
KEY_PART_INFO *last_part= NULL; |
|
7926 |
KEY_PART_INFO *first_non_group_part= NULL; |
|
7927 |
KEY_PART_INFO *first_non_infix_part= NULL; |
|
7928 |
uint key_infix_parts= 0; |
|
7929 |
uint cur_group_key_parts= 0; |
|
7930 |
uint cur_group_prefix_len= 0; |
|
7931 |
/* Cost-related variables for the best index so far. */
|
|
7932 |
double best_read_cost= DBL_MAX; |
|
7933 |
ha_rows best_records= 0; |
|
7934 |
SEL_ARG *best_index_tree= NULL; |
|
7935 |
ha_rows best_quick_prefix_records= 0; |
|
7936 |
uint best_param_idx= 0; |
|
7937 |
double cur_read_cost= DBL_MAX; |
|
7938 |
ha_rows cur_records; |
|
7939 |
SEL_ARG *cur_index_tree= NULL; |
|
7940 |
ha_rows cur_quick_prefix_records= 0; |
|
7941 |
uint cur_param_idx=MAX_KEY; |
|
7942 |
key_map cur_used_key_parts; |
|
7943 |
uint pk= param->table->s->primary_key; |
|
7944 |
||
7945 |
for (uint cur_index= 0 ; cur_index_info != cur_index_info_end ; |
|
7946 |
cur_index_info++, cur_index++) |
|
7947 |
{
|
|
7948 |
/* Check (B1) - if current index is covering. */
|
|
7949 |
if (!table->covering_keys.is_set(cur_index)) |
|
7950 |
goto next_index; |
|
7951 |
||
7952 |
/*
|
|
7953 |
If the current storage manager is such that it appends the primary key to
|
|
7954 |
each index, then the above condition is insufficient to check if the
|
|
7955 |
index is covering. In such cases it may happen that some fields are
|
|
7956 |
covered by the PK index, but not by the current index. Since we can't
|
|
7957 |
use the concatenation of both indexes for index lookup, such an index
|
|
7958 |
does not qualify as covering in our case. If this is the case, below
|
|
7959 |
we check that all query fields are indeed covered by 'cur_index'.
|
|
7960 |
*/
|
|
7961 |
if (pk < MAX_KEY && cur_index != pk && |
|
7962 |
(table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX)) |
|
7963 |
{
|
|
7964 |
/* For each table field */
|
|
7965 |
for (uint i= 0; i < table->s->fields; i++) |
|
7966 |
{
|
|
7967 |
Field *cur_field= table->field[i]; |
|
7968 |
/*
|
|
7969 |
If the field is used in the current query ensure that it's
|
|
7970 |
part of 'cur_index'
|
|
7971 |
*/
|
|
7972 |
if (bitmap_is_set(table->read_set, cur_field->field_index) && |
|
7973 |
!cur_field->part_of_key_not_clustered.is_set(cur_index)) |
|
7974 |
goto next_index; // Field was not part of key |
|
7975 |
}
|
|
7976 |
}
|
|
7977 |
||
7978 |
/*
|
|
7979 |
Check (GA1) for GROUP BY queries.
|
|
7980 |
*/
|
|
7981 |
if (join->group_list) |
|
7982 |
{
|
|
7983 |
cur_part= cur_index_info->key_part; |
|
7984 |
end_part= cur_part + cur_index_info->key_parts; |
|
7985 |
/* Iterate in parallel over the GROUP list and the index parts. */
|
|
7986 |
for (tmp_group= join->group_list; tmp_group && (cur_part != end_part); |
|
7987 |
tmp_group= tmp_group->next, cur_part++) |
|
7988 |
{
|
|
7989 |
/*
|
|
7990 |
TODO:
|
|
7991 |
tmp_group::item is an array of Item, is it OK to consider only the
|
|
7992 |
first Item? If so, then why? What is the array for?
|
|
7993 |
*/
|
|
7994 |
/* Above we already checked that all group items are fields. */
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7995 |
assert((*tmp_group->item)->type() == Item::FIELD_ITEM); |
1
by brian
clean slate |
7996 |
Item_field *group_field= (Item_field *) (*tmp_group->item); |
7997 |
if (group_field->field->eq(cur_part->field)) |
|
7998 |
{
|
|
7999 |
cur_group_prefix_len+= cur_part->store_length; |
|
8000 |
++cur_group_key_parts; |
|
8001 |
}
|
|
8002 |
else
|
|
8003 |
goto next_index; |
|
8004 |
}
|
|
8005 |
}
|
|
8006 |
/*
|
|
8007 |
Check (GA2) if this is a DISTINCT query.
|
|
327.2.3
by Brian Aker
Refactoring of class Table |
8008 |
If GA2, then Store a new order_st object in group_fields_array at the
|
8009 |
position of the key part of item_field->field. Thus we get the order_st
|
|
1
by brian
clean slate |
8010 |
objects for each field ordered as the corresponding key parts.
|
327.2.3
by Brian Aker
Refactoring of class Table |
8011 |
Later group_fields_array of order_st objects is used to convert the query
|
1
by brian
clean slate |
8012 |
to a GROUP query.
|
8013 |
*/
|
|
8014 |
else if (join->select_distinct) |
|
8015 |
{
|
|
8016 |
select_items_it.rewind(); |
|
8017 |
cur_used_key_parts.clear_all(); |
|
8018 |
uint max_key_part= 0; |
|
8019 |
while ((item= select_items_it++)) |
|
8020 |
{
|
|
8021 |
item_field= (Item_field*) item; /* (SA5) already checked above. */ |
|
8022 |
/* Find the order of the key part in the index. */
|
|
8023 |
key_part_nr= get_field_keypart(cur_index_info, item_field->field); |
|
8024 |
/*
|
|
8025 |
Check if this attribute was already present in the select list.
|
|
8026 |
If it was present, then its corresponding key part was alredy used.
|
|
8027 |
*/
|
|
8028 |
if (cur_used_key_parts.is_set(key_part_nr)) |
|
8029 |
continue; |
|
8030 |
if (key_part_nr < 1 || key_part_nr > join->fields_list.elements) |
|
8031 |
goto next_index; |
|
8032 |
cur_part= cur_index_info->key_part + key_part_nr - 1; |
|
8033 |
cur_group_prefix_len+= cur_part->store_length; |
|
8034 |
cur_used_key_parts.set_bit(key_part_nr); |
|
8035 |
++cur_group_key_parts; |
|
8036 |
max_key_part= max(max_key_part,key_part_nr); |
|
8037 |
}
|
|
8038 |
/*
|
|
8039 |
Check that used key parts forms a prefix of the index.
|
|
8040 |
To check this we compare bits in all_parts and cur_parts.
|
|
8041 |
all_parts have all bits set from 0 to (max_key_part-1).
|
|
8042 |
cur_parts have bits set for only used keyparts.
|
|
8043 |
*/
|
|
151
by Brian Aker
Ulonglong to uint64_t |
8044 |
uint64_t all_parts, cur_parts; |
1
by brian
clean slate |
8045 |
all_parts= (1<<max_key_part) - 1; |
151
by Brian Aker
Ulonglong to uint64_t |
8046 |
cur_parts= cur_used_key_parts.to_uint64_t() >> 1; |
1
by brian
clean slate |
8047 |
if (all_parts != cur_parts) |
8048 |
goto next_index; |
|
8049 |
}
|
|
8050 |
else
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8051 |
assert(false); |
1
by brian
clean slate |
8052 |
|
8053 |
/* Check (SA2). */
|
|
8054 |
if (min_max_arg_item) |
|
8055 |
{
|
|
8056 |
key_part_nr= get_field_keypart(cur_index_info, min_max_arg_item->field); |
|
8057 |
if (key_part_nr <= cur_group_key_parts) |
|
8058 |
goto next_index; |
|
8059 |
min_max_arg_part= cur_index_info->key_part + key_part_nr - 1; |
|
8060 |
}
|
|
8061 |
||
8062 |
/*
|
|
8063 |
Check (NGA1, NGA2) and extract a sequence of constants to be used as part
|
|
8064 |
of all search keys.
|
|
8065 |
*/
|
|
8066 |
||
8067 |
/*
|
|
8068 |
If there is MIN/MAX, each keypart between the last group part and the
|
|
8069 |
MIN/MAX part must participate in one equality with constants, and all
|
|
8070 |
keyparts after the MIN/MAX part must not be referenced in the query.
|
|
8071 |
||
8072 |
If there is no MIN/MAX, the keyparts after the last group part can be
|
|
8073 |
referenced only in equalities with constants, and the referenced keyparts
|
|
8074 |
must form a sequence without any gaps that starts immediately after the
|
|
8075 |
last group keypart.
|
|
8076 |
*/
|
|
8077 |
last_part= cur_index_info->key_part + cur_index_info->key_parts; |
|
8078 |
first_non_group_part= (cur_group_key_parts < cur_index_info->key_parts) ? |
|
8079 |
cur_index_info->key_part + cur_group_key_parts : |
|
8080 |
NULL; |
|
8081 |
first_non_infix_part= min_max_arg_part ? |
|
8082 |
(min_max_arg_part < last_part) ? |
|
8083 |
min_max_arg_part : |
|
8084 |
NULL : |
|
8085 |
NULL; |
|
8086 |
if (first_non_group_part && |
|
8087 |
(!min_max_arg_part || (min_max_arg_part - first_non_group_part > 0))) |
|
8088 |
{
|
|
8089 |
if (tree) |
|
8090 |
{
|
|
8091 |
uint dummy; |
|
8092 |
SEL_ARG *index_range_tree= get_index_range_tree(cur_index, tree, param, |
|
8093 |
&dummy); |
|
8094 |
if (!get_constant_key_infix(cur_index_info, index_range_tree, |
|
8095 |
first_non_group_part, min_max_arg_part, |
|
8096 |
last_part, thd, key_infix, &key_infix_len, |
|
8097 |
&first_non_infix_part)) |
|
8098 |
goto next_index; |
|
8099 |
}
|
|
8100 |
else if (min_max_arg_part && |
|
8101 |
(min_max_arg_part - first_non_group_part > 0)) |
|
8102 |
{
|
|
8103 |
/*
|
|
8104 |
There is a gap but no range tree, thus no predicates at all for the
|
|
8105 |
non-group keyparts.
|
|
8106 |
*/
|
|
8107 |
goto next_index; |
|
8108 |
}
|
|
8109 |
else if (first_non_group_part && join->conds) |
|
8110 |
{
|
|
8111 |
/*
|
|
8112 |
If there is no MIN/MAX function in the query, but some index
|
|
8113 |
key part is referenced in the WHERE clause, then this index
|
|
8114 |
cannot be used because the WHERE condition over the keypart's
|
|
8115 |
field cannot be 'pushed' to the index (because there is no
|
|
8116 |
range 'tree'), and the WHERE clause must be evaluated before
|
|
8117 |
GROUP BY/DISTINCT.
|
|
8118 |
*/
|
|
8119 |
/*
|
|
8120 |
Store the first and last keyparts that need to be analyzed
|
|
8121 |
into one array that can be passed as parameter.
|
|
8122 |
*/
|
|
8123 |
KEY_PART_INFO *key_part_range[2]; |
|
8124 |
key_part_range[0]= first_non_group_part; |
|
8125 |
key_part_range[1]= last_part; |
|
8126 |
||
8127 |
/* Check if cur_part is referenced in the WHERE clause. */
|
|
8128 |
if (join->conds->walk(&Item::find_item_in_field_list_processor, 0, |
|
8129 |
(uchar*) key_part_range)) |
|
8130 |
goto next_index; |
|
8131 |
}
|
|
8132 |
}
|
|
8133 |
||
8134 |
/*
|
|
8135 |
Test (WA1) partially - that no other keypart after the last infix part is
|
|
8136 |
referenced in the query.
|
|
8137 |
*/
|
|
8138 |
if (first_non_infix_part) |
|
8139 |
{
|
|
8140 |
cur_part= first_non_infix_part + |
|
8141 |
(min_max_arg_part && (min_max_arg_part < last_part)); |
|
8142 |
for (; cur_part != last_part; cur_part++) |
|
8143 |
{
|
|
8144 |
if (bitmap_is_set(table->read_set, cur_part->field->field_index)) |
|
8145 |
goto next_index; |
|
8146 |
}
|
|
8147 |
}
|
|
8148 |
||
8149 |
/* If we got to this point, cur_index_info passes the test. */
|
|
8150 |
key_infix_parts= key_infix_len ? |
|
8151 |
(first_non_infix_part - first_non_group_part) : 0; |
|
8152 |
used_key_parts= cur_group_key_parts + key_infix_parts; |
|
8153 |
||
8154 |
/* Compute the cost of using this index. */
|
|
8155 |
if (tree) |
|
8156 |
{
|
|
8157 |
/* Find the SEL_ARG sub-tree that corresponds to the chosen index. */
|
|
8158 |
cur_index_tree= get_index_range_tree(cur_index, tree, param, |
|
8159 |
&cur_param_idx); |
|
8160 |
/* Check if this range tree can be used for prefix retrieval. */
|
|
8161 |
COST_VECT dummy_cost; |
|
8162 |
uint mrr_flags= HA_MRR_USE_DEFAULT_IMPL; |
|
8163 |
uint mrr_bufsize=0; |
|
8164 |
cur_quick_prefix_records= check_quick_select(param, cur_param_idx, |
|
55
by brian
Update for using real bool types. |
8165 |
false /*don't care*/, |
8166 |
cur_index_tree, true, |
|
1
by brian
clean slate |
8167 |
&mrr_flags, &mrr_bufsize, |
8168 |
&dummy_cost); |
|
8169 |
}
|
|
8170 |
cost_group_min_max(table, cur_index_info, used_key_parts, |
|
8171 |
cur_group_key_parts, tree, cur_index_tree, |
|
8172 |
cur_quick_prefix_records, have_min, have_max, |
|
8173 |
&cur_read_cost, &cur_records); |
|
8174 |
/*
|
|
8175 |
If cur_read_cost is lower than best_read_cost use cur_index.
|
|
8176 |
Do not compare doubles directly because they may have different
|
|
8177 |
representations (64 vs. 80 bits).
|
|
8178 |
*/
|
|
8179 |
if (cur_read_cost < best_read_cost - (DBL_EPSILON * cur_read_cost)) |
|
8180 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8181 |
assert(tree != 0 || cur_param_idx == MAX_KEY); |
1
by brian
clean slate |
8182 |
index_info= cur_index_info; |
8183 |
index= cur_index; |
|
8184 |
best_read_cost= cur_read_cost; |
|
8185 |
best_records= cur_records; |
|
8186 |
best_index_tree= cur_index_tree; |
|
8187 |
best_quick_prefix_records= cur_quick_prefix_records; |
|
8188 |
best_param_idx= cur_param_idx; |
|
8189 |
group_key_parts= cur_group_key_parts; |
|
8190 |
group_prefix_len= cur_group_prefix_len; |
|
8191 |
}
|
|
8192 |
||
8193 |
next_index: |
|
8194 |
cur_group_key_parts= 0; |
|
8195 |
cur_group_prefix_len= 0; |
|
8196 |
}
|
|
8197 |
if (!index_info) /* No usable index found. */ |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8198 |
return(NULL); |
1
by brian
clean slate |
8199 |
|
8200 |
/* Check (SA3) for the where clause. */
|
|
8201 |
if (join->conds && min_max_arg_item && |
|
248
by Brian Aker
Random cleanup in base.h |
8202 |
!check_group_min_max_predicates(join->conds, min_max_arg_item, Field::itRAW)) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8203 |
return(NULL); |
1
by brian
clean slate |
8204 |
|
8205 |
/* The query passes all tests, so construct a new TRP object. */
|
|
8206 |
read_plan= new (param->mem_root) |
|
8207 |
TRP_GROUP_MIN_MAX(have_min, have_max, min_max_arg_part, |
|
8208 |
group_prefix_len, used_key_parts, |
|
8209 |
group_key_parts, index_info, index, |
|
8210 |
key_infix_len, |
|
8211 |
(key_infix_len > 0) ? key_infix : NULL, |
|
8212 |
tree, best_index_tree, best_param_idx, |
|
8213 |
best_quick_prefix_records); |
|
8214 |
if (read_plan) |
|
8215 |
{
|
|
8216 |
if (tree && read_plan->quick_prefix_records == 0) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8217 |
return(NULL); |
1
by brian
clean slate |
8218 |
|
8219 |
read_plan->read_cost= best_read_cost; |
|
8220 |
read_plan->records= best_records; |
|
8221 |
}
|
|
8222 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8223 |
return(read_plan); |
1
by brian
clean slate |
8224 |
}
|
8225 |
||
8226 |
||
8227 |
/*
|
|
8228 |
Check that the MIN/MAX attribute participates only in range predicates
|
|
8229 |
with constants.
|
|
8230 |
||
8231 |
SYNOPSIS
|
|
8232 |
check_group_min_max_predicates()
|
|
8233 |
cond tree (or subtree) describing all or part of the WHERE
|
|
8234 |
clause being analyzed
|
|
8235 |
min_max_arg_item the field referenced by the MIN/MAX function(s)
|
|
8236 |
min_max_arg_part the keypart of the MIN/MAX argument if any
|
|
8237 |
||
8238 |
DESCRIPTION
|
|
8239 |
The function walks recursively over the cond tree representing a WHERE
|
|
8240 |
clause, and checks condition (SA3) - if a field is referenced by a MIN/MAX
|
|
8241 |
aggregate function, it is referenced only by one of the following
|
|
8242 |
predicates: {=, !=, <, <=, >, >=, between, is null, is not null}.
|
|
8243 |
||
8244 |
RETURN
|
|
55
by brian
Update for using real bool types. |
8245 |
true if cond passes the test
|
8246 |
false o/w
|
|
1
by brian
clean slate |
8247 |
*/
|
8248 |
||
8249 |
static bool |
|
8250 |
check_group_min_max_predicates(COND *cond, Item_field *min_max_arg_item, |
|
8251 |
Field::imagetype image_type) |
|
8252 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8253 |
assert(cond && min_max_arg_item); |
1
by brian
clean slate |
8254 |
|
8255 |
cond= cond->real_item(); |
|
8256 |
Item::Type cond_type= cond->type(); |
|
8257 |
if (cond_type == Item::COND_ITEM) /* 'AND' or 'OR' */ |
|
8258 |
{
|
|
8259 |
List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list()); |
|
8260 |
Item *and_or_arg; |
|
8261 |
while ((and_or_arg= li++)) |
|
8262 |
{
|
|
8263 |
if (!check_group_min_max_predicates(and_or_arg, min_max_arg_item, |
|
8264 |
image_type)) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8265 |
return(false); |
1
by brian
clean slate |
8266 |
}
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8267 |
return(true); |
1
by brian
clean slate |
8268 |
}
|
8269 |
||
8270 |
/*
|
|
8271 |
TODO:
|
|
8272 |
This is a very crude fix to handle sub-selects in the WHERE clause
|
|
8273 |
(Item_subselect objects). With the test below we rule out from the
|
|
8274 |
optimization all queries with subselects in the WHERE clause. What has to
|
|
8275 |
be done, is that here we should analyze whether the subselect references
|
|
8276 |
the MIN/MAX argument field, and disallow the optimization only if this is
|
|
8277 |
so.
|
|
8278 |
*/
|
|
8279 |
if (cond_type == Item::SUBSELECT_ITEM) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8280 |
return(false); |
1
by brian
clean slate |
8281 |
|
8282 |
/* We presume that at this point there are no other Items than functions. */
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8283 |
assert(cond_type == Item::FUNC_ITEM); |
1
by brian
clean slate |
8284 |
|
8285 |
/* Test if cond references only group-by or non-group fields. */
|
|
8286 |
Item_func *pred= (Item_func*) cond; |
|
8287 |
Item **arguments= pred->arguments(); |
|
8288 |
Item *cur_arg; |
|
8289 |
for (uint arg_idx= 0; arg_idx < pred->argument_count (); arg_idx++) |
|
8290 |
{
|
|
8291 |
cur_arg= arguments[arg_idx]->real_item(); |
|
8292 |
if (cur_arg->type() == Item::FIELD_ITEM) |
|
8293 |
{
|
|
8294 |
if (min_max_arg_item->eq(cur_arg, 1)) |
|
8295 |
{
|
|
8296 |
/*
|
|
8297 |
If pred references the MIN/MAX argument, check whether pred is a range
|
|
8298 |
condition that compares the MIN/MAX argument with a constant.
|
|
8299 |
*/
|
|
8300 |
Item_func::Functype pred_type= pred->functype(); |
|
8301 |
if (pred_type != Item_func::EQUAL_FUNC && |
|
8302 |
pred_type != Item_func::LT_FUNC && |
|
8303 |
pred_type != Item_func::LE_FUNC && |
|
8304 |
pred_type != Item_func::GT_FUNC && |
|
8305 |
pred_type != Item_func::GE_FUNC && |
|
8306 |
pred_type != Item_func::BETWEEN && |
|
8307 |
pred_type != Item_func::ISNULL_FUNC && |
|
8308 |
pred_type != Item_func::ISNOTNULL_FUNC && |
|
8309 |
pred_type != Item_func::EQ_FUNC && |
|
8310 |
pred_type != Item_func::NE_FUNC) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8311 |
return(false); |
1
by brian
clean slate |
8312 |
|
8313 |
/* Check that pred compares min_max_arg_item with a constant. */
|
|
8314 |
Item *args[3]; |
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
8315 |
memset(args, 0, 3 * sizeof(Item*)); |
1
by brian
clean slate |
8316 |
bool inv; |
8317 |
/* Test if this is a comparison of a field and a constant. */
|
|
8318 |
if (!simple_pred(pred, args, &inv)) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8319 |
return(false); |
1
by brian
clean slate |
8320 |
|
8321 |
/* Check for compatible string comparisons - similar to get_mm_leaf. */
|
|
8322 |
if (args[0] && args[1] && !args[2] && // this is a binary function |
|
8323 |
min_max_arg_item->result_type() == STRING_RESULT && |
|
8324 |
/*
|
|
8325 |
Don't use an index when comparing strings of different collations.
|
|
8326 |
*/
|
|
8327 |
((args[1]->result_type() == STRING_RESULT && |
|
8328 |
image_type == Field::itRAW && |
|
8329 |
((Field_str*) min_max_arg_item->field)->charset() != |
|
8330 |
pred->compare_collation()) |
|
8331 |
||
|
|
8332 |
/*
|
|
8333 |
We can't always use indexes when comparing a string index to a
|
|
8334 |
number.
|
|
8335 |
*/
|
|
8336 |
(args[1]->result_type() != STRING_RESULT && |
|
8337 |
min_max_arg_item->field->cmp_type() != args[1]->result_type()))) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8338 |
return(false); |
1
by brian
clean slate |
8339 |
}
|
8340 |
}
|
|
8341 |
else if (cur_arg->type() == Item::FUNC_ITEM) |
|
8342 |
{
|
|
8343 |
if (!check_group_min_max_predicates(cur_arg, min_max_arg_item, |
|
8344 |
image_type)) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8345 |
return(false); |
1
by brian
clean slate |
8346 |
}
|
8347 |
else if (cur_arg->const_item()) |
|
8348 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8349 |
return(true); |
1
by brian
clean slate |
8350 |
}
|
8351 |
else
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8352 |
return(false); |
1
by brian
clean slate |
8353 |
}
|
8354 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8355 |
return(true); |
1
by brian
clean slate |
8356 |
}
|
8357 |
||
8358 |
||
8359 |
/*
|
|
8360 |
Extract a sequence of constants from a conjunction of equality predicates.
|
|
8361 |
||
8362 |
SYNOPSIS
|
|
8363 |
get_constant_key_infix()
|
|
8364 |
index_info [in] Descriptor of the chosen index.
|
|
8365 |
index_range_tree [in] Range tree for the chosen index
|
|
8366 |
first_non_group_part [in] First index part after group attribute parts
|
|
8367 |
min_max_arg_part [in] The keypart of the MIN/MAX argument if any
|
|
8368 |
last_part [in] Last keypart of the index
|
|
8369 |
thd [in] Current thread
|
|
8370 |
key_infix [out] Infix of constants to be used for index lookup
|
|
8371 |
key_infix_len [out] Lenghth of the infix
|
|
8372 |
first_non_infix_part [out] The first keypart after the infix (if any)
|
|
8373 |
|
|
8374 |
DESCRIPTION
|
|
8375 |
Test conditions (NGA1, NGA2) from get_best_group_min_max(). Namely,
|
|
8376 |
for each keypart field NGF_i not in GROUP-BY, check that there is a
|
|
8377 |
constant equality predicate among conds with the form (NGF_i = const_ci) or
|
|
8378 |
(const_ci = NGF_i).
|
|
8379 |
Thus all the NGF_i attributes must fill the 'gap' between the last group-by
|
|
8380 |
attribute and the MIN/MAX attribute in the index (if present). If these
|
|
8381 |
conditions hold, copy each constant from its corresponding predicate into
|
|
8382 |
key_infix, in the order its NG_i attribute appears in the index, and update
|
|
8383 |
key_infix_len with the total length of the key parts in key_infix.
|
|
8384 |
||
8385 |
RETURN
|
|
55
by brian
Update for using real bool types. |
8386 |
true if the index passes the test
|
8387 |
false o/w
|
|
1
by brian
clean slate |
8388 |
*/
|
8389 |
||
8390 |
static bool |
|
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
8391 |
get_constant_key_infix(KEY *index_info __attribute__((unused)), |
77.1.46
by Monty Taylor
Finished the warnings work! |
8392 |
SEL_ARG *index_range_tree, |
1
by brian
clean slate |
8393 |
KEY_PART_INFO *first_non_group_part, |
8394 |
KEY_PART_INFO *min_max_arg_part, |
|
77.1.46
by Monty Taylor
Finished the warnings work! |
8395 |
KEY_PART_INFO *last_part, |
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
8396 |
THD *thd __attribute__((unused)), |
1
by brian
clean slate |
8397 |
uchar *key_infix, uint *key_infix_len, |
8398 |
KEY_PART_INFO **first_non_infix_part) |
|
8399 |
{
|
|
8400 |
SEL_ARG *cur_range; |
|
8401 |
KEY_PART_INFO *cur_part; |
|
8402 |
/* End part for the first loop below. */
|
|
8403 |
KEY_PART_INFO *end_part= min_max_arg_part ? min_max_arg_part : last_part; |
|
8404 |
||
8405 |
*key_infix_len= 0; |
|
8406 |
uchar *key_ptr= key_infix; |
|
8407 |
for (cur_part= first_non_group_part; cur_part != end_part; cur_part++) |
|
8408 |
{
|
|
8409 |
/*
|
|
8410 |
Find the range tree for the current keypart. We assume that
|
|
8411 |
index_range_tree points to the leftmost keypart in the index.
|
|
8412 |
*/
|
|
8413 |
for (cur_range= index_range_tree; cur_range; |
|
8414 |
cur_range= cur_range->next_key_part) |
|
8415 |
{
|
|
8416 |
if (cur_range->field->eq(cur_part->field)) |
|
8417 |
break; |
|
8418 |
}
|
|
8419 |
if (!cur_range) |
|
8420 |
{
|
|
8421 |
if (min_max_arg_part) |
|
55
by brian
Update for using real bool types. |
8422 |
return false; /* The current keypart has no range predicates at all. */ |
1
by brian
clean slate |
8423 |
else
|
8424 |
{
|
|
8425 |
*first_non_infix_part= cur_part; |
|
55
by brian
Update for using real bool types. |
8426 |
return true; |
1
by brian
clean slate |
8427 |
}
|
8428 |
}
|
|
8429 |
||
8430 |
/* Check that the current range tree is a single point interval. */
|
|
8431 |
if (cur_range->prev || cur_range->next) |
|
55
by brian
Update for using real bool types. |
8432 |
return false; /* This is not the only range predicate for the field. */ |
1
by brian
clean slate |
8433 |
if ((cur_range->min_flag & NO_MIN_RANGE) || |
8434 |
(cur_range->max_flag & NO_MAX_RANGE) || |
|
8435 |
(cur_range->min_flag & NEAR_MIN) || (cur_range->max_flag & NEAR_MAX)) |
|
55
by brian
Update for using real bool types. |
8436 |
return false; |
1
by brian
clean slate |
8437 |
|
8438 |
uint field_length= cur_part->store_length; |
|
8439 |
if ((cur_range->maybe_null && |
|
8440 |
cur_range->min_value[0] && cur_range->max_value[0]) || |
|
8441 |
!memcmp(cur_range->min_value, cur_range->max_value, field_length)) |
|
8442 |
{
|
|
8443 |
/* cur_range specifies 'IS NULL' or an equality condition. */
|
|
8444 |
memcpy(key_ptr, cur_range->min_value, field_length); |
|
8445 |
key_ptr+= field_length; |
|
8446 |
*key_infix_len+= field_length; |
|
8447 |
}
|
|
8448 |
else
|
|
55
by brian
Update for using real bool types. |
8449 |
return false; |
1
by brian
clean slate |
8450 |
}
|
8451 |
||
8452 |
if (!min_max_arg_part && (cur_part == last_part)) |
|
8453 |
*first_non_infix_part= last_part; |
|
8454 |
||
55
by brian
Update for using real bool types. |
8455 |
return true; |
1
by brian
clean slate |
8456 |
}
|
8457 |
||
8458 |
||
8459 |
/*
|
|
8460 |
Find the key part referenced by a field.
|
|
8461 |
||
8462 |
SYNOPSIS
|
|
8463 |
get_field_keypart()
|
|
8464 |
index descriptor of an index
|
|
8465 |
field field that possibly references some key part in index
|
|
8466 |
||
8467 |
NOTES
|
|
8468 |
The return value can be used to get a KEY_PART_INFO pointer by
|
|
8469 |
part= index->key_part + get_field_keypart(...) - 1;
|
|
8470 |
||
8471 |
RETURN
|
|
8472 |
Positive number which is the consecutive number of the key part, or
|
|
8473 |
0 if field does not reference any index field.
|
|
8474 |
*/
|
|
8475 |
||
8476 |
static inline uint |
|
8477 |
get_field_keypart(KEY *index, Field *field) |
|
8478 |
{
|
|
8479 |
KEY_PART_INFO *part, *end; |
|
8480 |
||
8481 |
for (part= index->key_part, end= part + index->key_parts; part < end; part++) |
|
8482 |
{
|
|
8483 |
if (field->eq(part->field)) |
|
8484 |
return part - index->key_part + 1; |
|
8485 |
}
|
|
8486 |
return 0; |
|
8487 |
}
|
|
8488 |
||
8489 |
||
8490 |
/*
|
|
8491 |
Find the SEL_ARG sub-tree that corresponds to the chosen index.
|
|
8492 |
||
8493 |
SYNOPSIS
|
|
8494 |
get_index_range_tree()
|
|
8495 |
index [in] The ID of the index being looked for
|
|
8496 |
range_tree[in] Tree of ranges being searched
|
|
8497 |
param [in] PARAM from SQL_SELECT::test_quick_select
|
|
8498 |
param_idx [out] Index in the array PARAM::key that corresponds to 'index'
|
|
8499 |
||
8500 |
DESCRIPTION
|
|
8501 |
||
8502 |
A SEL_TREE contains range trees for all usable indexes. This procedure
|
|
8503 |
finds the SEL_ARG sub-tree for 'index'. The members of a SEL_TREE are
|
|
8504 |
ordered in the same way as the members of PARAM::key, thus we first find
|
|
8505 |
the corresponding index in the array PARAM::key. This index is returned
|
|
8506 |
through the variable param_idx, to be used later as argument of
|
|
8507 |
check_quick_select().
|
|
8508 |
||
8509 |
RETURN
|
|
8510 |
Pointer to the SEL_ARG subtree that corresponds to index.
|
|
8511 |
*/
|
|
8512 |
||
8513 |
SEL_ARG * get_index_range_tree(uint index, SEL_TREE* range_tree, PARAM *param, |
|
8514 |
uint *param_idx) |
|
8515 |
{
|
|
8516 |
uint idx= 0; /* Index nr in param->key_parts */ |
|
8517 |
while (idx < param->keys) |
|
8518 |
{
|
|
8519 |
if (index == param->real_keynr[idx]) |
|
8520 |
break; |
|
8521 |
idx++; |
|
8522 |
}
|
|
8523 |
*param_idx= idx; |
|
8524 |
return(range_tree->keys[idx]); |
|
8525 |
}
|
|
8526 |
||
8527 |
||
8528 |
/*
|
|
8529 |
Compute the cost of a quick_group_min_max_select for a particular index.
|
|
8530 |
||
8531 |
SYNOPSIS
|
|
8532 |
cost_group_min_max()
|
|
8533 |
table [in] The table being accessed
|
|
8534 |
index_info [in] The index used to access the table
|
|
8535 |
used_key_parts [in] Number of key parts used to access the index
|
|
8536 |
group_key_parts [in] Number of index key parts in the group prefix
|
|
8537 |
range_tree [in] Tree of ranges for all indexes
|
|
8538 |
index_tree [in] The range tree for the current index
|
|
8539 |
quick_prefix_records [in] Number of records retrieved by the internally
|
|
8540 |
used quick range select if any
|
|
8541 |
have_min [in] True if there is a MIN function
|
|
8542 |
have_max [in] True if there is a MAX function
|
|
8543 |
read_cost [out] The cost to retrieve rows via this quick select
|
|
8544 |
records [out] The number of rows retrieved
|
|
8545 |
||
8546 |
DESCRIPTION
|
|
8547 |
This method computes the access cost of a TRP_GROUP_MIN_MAX instance and
|
|
8548 |
the number of rows returned. It updates this->read_cost and this->records.
|
|
8549 |
||
8550 |
NOTES
|
|
8551 |
The cost computation distinguishes several cases:
|
|
8552 |
1) No equality predicates over non-group attributes (thus no key_infix).
|
|
8553 |
If groups are bigger than blocks on the average, then we assume that it
|
|
8554 |
is very unlikely that block ends are aligned with group ends, thus even
|
|
8555 |
if we look for both MIN and MAX keys, all pairs of neighbor MIN/MAX
|
|
8556 |
keys, except for the first MIN and the last MAX keys, will be in the
|
|
8557 |
same block. If groups are smaller than blocks, then we are going to
|
|
8558 |
read all blocks.
|
|
8559 |
2) There are equality predicates over non-group attributes.
|
|
8560 |
In this case the group prefix is extended by additional constants, and
|
|
8561 |
as a result the min/max values are inside sub-groups of the original
|
|
8562 |
groups. The number of blocks that will be read depends on whether the
|
|
8563 |
ends of these sub-groups will be contained in the same or in different
|
|
8564 |
blocks. We compute the probability for the two ends of a subgroup to be
|
|
8565 |
in two different blocks as the ratio of:
|
|
8566 |
- the number of positions of the left-end of a subgroup inside a group,
|
|
8567 |
such that the right end of the subgroup is past the end of the buffer
|
|
8568 |
containing the left-end, and
|
|
8569 |
- the total number of possible positions for the left-end of the
|
|
8570 |
subgroup, which is the number of keys in the containing group.
|
|
8571 |
We assume it is very unlikely that two ends of subsequent subgroups are
|
|
8572 |
in the same block.
|
|
8573 |
3) The are range predicates over the group attributes.
|
|
8574 |
Then some groups may be filtered by the range predicates. We use the
|
|
8575 |
selectivity of the range predicates to decide how many groups will be
|
|
8576 |
filtered.
|
|
8577 |
||
8578 |
TODO
|
|
8579 |
- Take into account the optional range predicates over the MIN/MAX
|
|
8580 |
argument.
|
|
8581 |
- Check if we have a PK index and we use all cols - then each key is a
|
|
8582 |
group, and it will be better to use an index scan.
|
|
8583 |
||
8584 |
RETURN
|
|
8585 |
None
|
|
8586 |
*/
|
|
8587 |
||
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
8588 |
void cost_group_min_max(Table* table, KEY *index_info, uint used_key_parts, |
1
by brian
clean slate |
8589 |
uint group_key_parts, SEL_TREE *range_tree, |
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
8590 |
SEL_ARG *index_tree __attribute__((unused)), |
77.1.46
by Monty Taylor
Finished the warnings work! |
8591 |
ha_rows quick_prefix_records, |
1
by brian
clean slate |
8592 |
bool have_min, bool have_max, |
8593 |
double *read_cost, ha_rows *records) |
|
8594 |
{
|
|
8595 |
ha_rows table_records; |
|
8596 |
uint num_groups; |
|
8597 |
uint num_blocks; |
|
8598 |
uint keys_per_block; |
|
8599 |
uint keys_per_group; |
|
8600 |
uint keys_per_subgroup; /* Average number of keys in sub-groups */ |
|
8601 |
/* formed by a key infix. */
|
|
8602 |
double p_overlap; /* Probability that a sub-group overlaps two blocks. */ |
|
8603 |
double quick_prefix_selectivity; |
|
8604 |
double io_cost; |
|
8605 |
double cpu_cost= 0; /* TODO: CPU cost of index_read calls? */ |
|
8606 |
||
8607 |
table_records= table->file->stats.records; |
|
8608 |
keys_per_block= (table->file->stats.block_size / 2 / |
|
8609 |
(index_info->key_length + table->file->ref_length) |
|
8610 |
+ 1); |
|
8611 |
num_blocks= (uint)(table_records / keys_per_block) + 1; |
|
8612 |
||
8613 |
/* Compute the number of keys in a group. */
|
|
8614 |
keys_per_group= index_info->rec_per_key[group_key_parts - 1]; |
|
8615 |
if (keys_per_group == 0) /* If there is no statistics try to guess */ |
|
8616 |
/* each group contains 10% of all records */
|
|
8617 |
keys_per_group= (uint)(table_records / 10) + 1; |
|
8618 |
num_groups= (uint)(table_records / keys_per_group) + 1; |
|
8619 |
||
8620 |
/* Apply the selectivity of the quick select for group prefixes. */
|
|
8621 |
if (range_tree && (quick_prefix_records != HA_POS_ERROR)) |
|
8622 |
{
|
|
8623 |
quick_prefix_selectivity= (double) quick_prefix_records / |
|
8624 |
(double) table_records; |
|
8625 |
num_groups= (uint) rint(num_groups * quick_prefix_selectivity); |
|
8626 |
set_if_bigger(num_groups, 1); |
|
8627 |
}
|
|
8628 |
||
8629 |
if (used_key_parts > group_key_parts) |
|
8630 |
{ /* |
|
8631 |
Compute the probability that two ends of a subgroup are inside
|
|
8632 |
different blocks.
|
|
8633 |
*/
|
|
8634 |
keys_per_subgroup= index_info->rec_per_key[used_key_parts - 1]; |
|
8635 |
if (keys_per_subgroup >= keys_per_block) /* If a subgroup is bigger than */ |
|
8636 |
p_overlap= 1.0; /* a block, it will overlap at least two blocks. */ |
|
8637 |
else
|
|
8638 |
{
|
|
8639 |
double blocks_per_group= (double) num_blocks / (double) num_groups; |
|
8640 |
p_overlap= (blocks_per_group * (keys_per_subgroup - 1)) / keys_per_group; |
|
8641 |
p_overlap= min(p_overlap, 1.0); |
|
8642 |
}
|
|
287.3.8
by Monty Taylor
Oy. Replaced max and min macros with std::max and std::min so that we get |
8643 |
io_cost= (double) min(num_groups * (1 + p_overlap), (double)num_blocks); |
1
by brian
clean slate |
8644 |
}
|
8645 |
else
|
|
8646 |
io_cost= (keys_per_group > keys_per_block) ? |
|
8647 |
(have_min && have_max) ? (double) (num_groups + 1) : |
|
8648 |
(double) num_groups : |
|
8649 |
(double) num_blocks; |
|
8650 |
||
8651 |
/*
|
|
8652 |
TODO: If there is no WHERE clause and no other expressions, there should be
|
|
8653 |
no CPU cost. We leave it here to make this cost comparable to that of index
|
|
8654 |
scan as computed in SQL_SELECT::test_quick_select().
|
|
8655 |
*/
|
|
8656 |
cpu_cost= (double) num_groups / TIME_FOR_COMPARE; |
|
8657 |
||
8658 |
*read_cost= io_cost + cpu_cost; |
|
8659 |
*records= num_groups; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8660 |
return; |
1
by brian
clean slate |
8661 |
}
|
8662 |
||
8663 |
||
8664 |
/*
|
|
8665 |
Construct a new quick select object for queries with group by with min/max.
|
|
8666 |
||
8667 |
SYNOPSIS
|
|
8668 |
TRP_GROUP_MIN_MAX::make_quick()
|
|
8669 |
param Parameter from test_quick_select
|
|
8670 |
retrieve_full_rows ignored
|
|
8671 |
parent_alloc Memory pool to use, if any.
|
|
8672 |
||
8673 |
NOTES
|
|
8674 |
Make_quick ignores the retrieve_full_rows parameter because
|
|
8675 |
QUICK_GROUP_MIN_MAX_SELECT always performs 'index only' scans.
|
|
8676 |
The other parameter are ignored as well because all necessary
|
|
8677 |
data to create the QUICK object is computed at this TRP creation
|
|
8678 |
time.
|
|
8679 |
||
8680 |
RETURN
|
|
8681 |
New QUICK_GROUP_MIN_MAX_SELECT object if successfully created,
|
|
8682 |
NULL otherwise.
|
|
8683 |
*/
|
|
8684 |
||
8685 |
QUICK_SELECT_I * |
|
77.1.46
by Monty Taylor
Finished the warnings work! |
8686 |
TRP_GROUP_MIN_MAX::make_quick(PARAM *param, |
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
8687 |
bool retrieve_full_rows __attribute__((unused)), |
1
by brian
clean slate |
8688 |
MEM_ROOT *parent_alloc) |
8689 |
{
|
|
8690 |
QUICK_GROUP_MIN_MAX_SELECT *quick; |
|
8691 |
||
8692 |
quick= new QUICK_GROUP_MIN_MAX_SELECT(param->table, |
|
8693 |
param->thd->lex->current_select->join, |
|
8694 |
have_min, have_max, min_max_arg_part, |
|
8695 |
group_prefix_len, group_key_parts, |
|
8696 |
used_key_parts, index_info, index, |
|
8697 |
read_cost, records, key_infix_len, |
|
8698 |
key_infix, parent_alloc); |
|
8699 |
if (!quick) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8700 |
return(NULL); |
1
by brian
clean slate |
8701 |
|
8702 |
if (quick->init()) |
|
8703 |
{
|
|
8704 |
delete quick; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8705 |
return(NULL); |
1
by brian
clean slate |
8706 |
}
|
8707 |
||
8708 |
if (range_tree) |
|
8709 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8710 |
assert(quick_prefix_records > 0); |
1
by brian
clean slate |
8711 |
if (quick_prefix_records == HA_POS_ERROR) |
8712 |
quick->quick_prefix_select= NULL; /* Can't construct a quick select. */ |
|
8713 |
else
|
|
8714 |
/* Make a QUICK_RANGE_SELECT to be used for group prefix retrieval. */
|
|
8715 |
quick->quick_prefix_select= get_quick_select(param, param_idx, |
|
8716 |
index_tree, |
|
8717 |
HA_MRR_USE_DEFAULT_IMPL, 0, |
|
8718 |
&quick->alloc); |
|
8719 |
||
8720 |
/*
|
|
8721 |
Extract the SEL_ARG subtree that contains only ranges for the MIN/MAX
|
|
8722 |
attribute, and create an array of QUICK_RANGES to be used by the
|
|
8723 |
new quick select.
|
|
8724 |
*/
|
|
8725 |
if (min_max_arg_part) |
|
8726 |
{
|
|
8727 |
SEL_ARG *min_max_range= index_tree; |
|
8728 |
while (min_max_range) /* Find the tree for the MIN/MAX key part. */ |
|
8729 |
{
|
|
8730 |
if (min_max_range->field->eq(min_max_arg_part->field)) |
|
8731 |
break; |
|
8732 |
min_max_range= min_max_range->next_key_part; |
|
8733 |
}
|
|
8734 |
/* Scroll to the leftmost interval for the MIN/MAX argument. */
|
|
8735 |
while (min_max_range && min_max_range->prev) |
|
8736 |
min_max_range= min_max_range->prev; |
|
8737 |
/* Create an array of QUICK_RANGEs for the MIN/MAX argument. */
|
|
8738 |
while (min_max_range) |
|
8739 |
{
|
|
8740 |
if (quick->add_range(min_max_range)) |
|
8741 |
{
|
|
8742 |
delete quick; |
|
8743 |
quick= NULL; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8744 |
return(NULL); |
1
by brian
clean slate |
8745 |
}
|
8746 |
min_max_range= min_max_range->next; |
|
8747 |
}
|
|
8748 |
}
|
|
8749 |
}
|
|
8750 |
else
|
|
8751 |
quick->quick_prefix_select= NULL; |
|
8752 |
||
8753 |
quick->update_key_stat(); |
|
8754 |
quick->adjust_prefix_ranges(); |
|
8755 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8756 |
return(quick); |
1
by brian
clean slate |
8757 |
}
|
8758 |
||
8759 |
||
8760 |
/*
|
|
8761 |
Construct new quick select for group queries with min/max.
|
|
8762 |
||
8763 |
SYNOPSIS
|
|
8764 |
QUICK_GROUP_MIN_MAX_SELECT::QUICK_GROUP_MIN_MAX_SELECT()
|
|
8765 |
table The table being accessed
|
|
8766 |
join Descriptor of the current query
|
|
55
by brian
Update for using real bool types. |
8767 |
have_min true if the query selects a MIN function
|
8768 |
have_max true if the query selects a MAX function
|
|
1
by brian
clean slate |
8769 |
min_max_arg_part The only argument field of all MIN/MAX functions
|
8770 |
group_prefix_len Length of all key parts in the group prefix
|
|
8771 |
prefix_key_parts All key parts in the group prefix
|
|
8772 |
index_info The index chosen for data access
|
|
8773 |
use_index The id of index_info
|
|
8774 |
read_cost Cost of this access method
|
|
8775 |
records Number of records returned
|
|
8776 |
key_infix_len Length of the key infix appended to the group prefix
|
|
8777 |
key_infix Infix of constants from equality predicates
|
|
8778 |
parent_alloc Memory pool for this and quick_prefix_select data
|
|
8779 |
||
8780 |
RETURN
|
|
8781 |
None
|
|
8782 |
*/
|
|
8783 |
||
8784 |
QUICK_GROUP_MIN_MAX_SELECT:: |
|
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
8785 |
QUICK_GROUP_MIN_MAX_SELECT(Table *table, JOIN *join_arg, bool have_min_arg, |
1
by brian
clean slate |
8786 |
bool have_max_arg, |
8787 |
KEY_PART_INFO *min_max_arg_part_arg, |
|
8788 |
uint group_prefix_len_arg, uint group_key_parts_arg, |
|
8789 |
uint used_key_parts_arg, KEY *index_info_arg, |
|
8790 |
uint use_index, double read_cost_arg, |
|
8791 |
ha_rows records_arg, uint key_infix_len_arg, |
|
8792 |
uchar *key_infix_arg, MEM_ROOT *parent_alloc) |
|
8793 |
:join(join_arg), index_info(index_info_arg), |
|
8794 |
group_prefix_len(group_prefix_len_arg), |
|
8795 |
group_key_parts(group_key_parts_arg), have_min(have_min_arg), |
|
55
by brian
Update for using real bool types. |
8796 |
have_max(have_max_arg), seen_first_key(false), |
1
by brian
clean slate |
8797 |
min_max_arg_part(min_max_arg_part_arg), key_infix(key_infix_arg), |
8798 |
key_infix_len(key_infix_len_arg), min_functions_it(NULL), |
|
8799 |
max_functions_it(NULL) |
|
8800 |
{
|
|
8801 |
head= table; |
|
8802 |
file= head->file; |
|
8803 |
index= use_index; |
|
8804 |
record= head->record[0]; |
|
8805 |
tmp_record= head->record[1]; |
|
8806 |
read_time= read_cost_arg; |
|
8807 |
records= records_arg; |
|
8808 |
used_key_parts= used_key_parts_arg; |
|
8809 |
real_key_parts= used_key_parts_arg; |
|
8810 |
real_prefix_len= group_prefix_len + key_infix_len; |
|
8811 |
group_prefix= NULL; |
|
8812 |
min_max_arg_len= min_max_arg_part ? min_max_arg_part->store_length : 0; |
|
8813 |
||
8814 |
/*
|
|
8815 |
We can't have parent_alloc set as the init function can't handle this case
|
|
8816 |
yet.
|
|
8817 |
*/
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8818 |
assert(!parent_alloc); |
1
by brian
clean slate |
8819 |
if (!parent_alloc) |
8820 |
{
|
|
8821 |
init_sql_alloc(&alloc, join->thd->variables.range_alloc_block_size, 0); |
|
8822 |
join->thd->mem_root= &alloc; |
|
8823 |
}
|
|
8824 |
else
|
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
8825 |
memset(&alloc, 0, sizeof(MEM_ROOT)); // ensure that it's not used |
1
by brian
clean slate |
8826 |
}
|
8827 |
||
8828 |
||
8829 |
/*
|
|
8830 |
Do post-constructor initialization.
|
|
8831 |
||
8832 |
SYNOPSIS
|
|
8833 |
QUICK_GROUP_MIN_MAX_SELECT::init()
|
|
8834 |
|
|
8835 |
DESCRIPTION
|
|
8836 |
The method performs initialization that cannot be done in the constructor
|
|
8837 |
such as memory allocations that may fail. It allocates memory for the
|
|
8838 |
group prefix and inifix buffers, and for the lists of MIN/MAX item to be
|
|
8839 |
updated during execution.
|
|
8840 |
||
8841 |
RETURN
|
|
8842 |
0 OK
|
|
8843 |
other Error code
|
|
8844 |
*/
|
|
8845 |
||
8846 |
int QUICK_GROUP_MIN_MAX_SELECT::init() |
|
8847 |
{
|
|
8848 |
if (group_prefix) /* Already initialized. */ |
|
8849 |
return 0; |
|
8850 |
||
8851 |
if (!(last_prefix= (uchar*) alloc_root(&alloc, group_prefix_len))) |
|
8852 |
return 1; |
|
8853 |
/*
|
|
8854 |
We may use group_prefix to store keys with all select fields, so allocate
|
|
8855 |
enough space for it.
|
|
8856 |
*/
|
|
8857 |
if (!(group_prefix= (uchar*) alloc_root(&alloc, |
|
8858 |
real_prefix_len + min_max_arg_len))) |
|
8859 |
return 1; |
|
8860 |
||
8861 |
if (key_infix_len > 0) |
|
8862 |
{
|
|
8863 |
/*
|
|
8864 |
The memory location pointed to by key_infix will be deleted soon, so
|
|
8865 |
allocate a new buffer and copy the key_infix into it.
|
|
8866 |
*/
|
|
8867 |
uchar *tmp_key_infix= (uchar*) alloc_root(&alloc, key_infix_len); |
|
8868 |
if (!tmp_key_infix) |
|
8869 |
return 1; |
|
8870 |
memcpy(tmp_key_infix, this->key_infix, key_infix_len); |
|
8871 |
this->key_infix= tmp_key_infix; |
|
8872 |
}
|
|
8873 |
||
8874 |
if (min_max_arg_part) |
|
8875 |
{
|
|
8876 |
if (my_init_dynamic_array(&min_max_ranges, sizeof(QUICK_RANGE*), 16, 16)) |
|
8877 |
return 1; |
|
8878 |
||
8879 |
if (have_min) |
|
8880 |
{
|
|
8881 |
if (!(min_functions= new List<Item_sum>)) |
|
8882 |
return 1; |
|
8883 |
}
|
|
8884 |
else
|
|
8885 |
min_functions= NULL; |
|
8886 |
if (have_max) |
|
8887 |
{
|
|
8888 |
if (!(max_functions= new List<Item_sum>)) |
|
8889 |
return 1; |
|
8890 |
}
|
|
8891 |
else
|
|
8892 |
max_functions= NULL; |
|
8893 |
||
8894 |
Item_sum *min_max_item; |
|
8895 |
Item_sum **func_ptr= join->sum_funcs; |
|
8896 |
while ((min_max_item= *(func_ptr++))) |
|
8897 |
{
|
|
8898 |
if (have_min && (min_max_item->sum_func() == Item_sum::MIN_FUNC)) |
|
8899 |
min_functions->push_back(min_max_item); |
|
8900 |
else if (have_max && (min_max_item->sum_func() == Item_sum::MAX_FUNC)) |
|
8901 |
max_functions->push_back(min_max_item); |
|
8902 |
}
|
|
8903 |
||
8904 |
if (have_min) |
|
8905 |
{
|
|
8906 |
if (!(min_functions_it= new List_iterator<Item_sum>(*min_functions))) |
|
8907 |
return 1; |
|
8908 |
}
|
|
8909 |
||
8910 |
if (have_max) |
|
8911 |
{
|
|
8912 |
if (!(max_functions_it= new List_iterator<Item_sum>(*max_functions))) |
|
8913 |
return 1; |
|
8914 |
}
|
|
8915 |
}
|
|
8916 |
else
|
|
8917 |
min_max_ranges.elements= 0; |
|
8918 |
||
8919 |
return 0; |
|
8920 |
}
|
|
8921 |
||
8922 |
||
8923 |
QUICK_GROUP_MIN_MAX_SELECT::~QUICK_GROUP_MIN_MAX_SELECT() |
|
8924 |
{
|
|
8925 |
if (file->inited != handler::NONE) |
|
8926 |
file->ha_index_end(); |
|
8927 |
if (min_max_arg_part) |
|
8928 |
delete_dynamic(&min_max_ranges); |
|
8929 |
free_root(&alloc,MYF(0)); |
|
8930 |
delete min_functions_it; |
|
8931 |
delete max_functions_it; |
|
8932 |
delete quick_prefix_select; |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8933 |
return; |
1
by brian
clean slate |
8934 |
}
|
8935 |
||
8936 |
||
8937 |
/*
|
|
8938 |
Eventually create and add a new quick range object.
|
|
8939 |
||
8940 |
SYNOPSIS
|
|
8941 |
QUICK_GROUP_MIN_MAX_SELECT::add_range()
|
|
8942 |
sel_range Range object from which a
|
|
8943 |
||
8944 |
NOTES
|
|
8945 |
Construct a new QUICK_RANGE object from a SEL_ARG object, and
|
|
8946 |
add it to the array min_max_ranges. If sel_arg is an infinite
|
|
8947 |
range, e.g. (x < 5 or x > 4), then skip it and do not construct
|
|
8948 |
a quick range.
|
|
8949 |
||
8950 |
RETURN
|
|
55
by brian
Update for using real bool types. |
8951 |
false on success
|
8952 |
true otherwise
|
|
1
by brian
clean slate |
8953 |
*/
|
8954 |
||
8955 |
bool QUICK_GROUP_MIN_MAX_SELECT::add_range(SEL_ARG *sel_range) |
|
8956 |
{
|
|
8957 |
QUICK_RANGE *range; |
|
8958 |
uint range_flag= sel_range->min_flag | sel_range->max_flag; |
|
8959 |
||
8960 |
/* Skip (-inf,+inf) ranges, e.g. (x < 5 or x > 4). */
|
|
8961 |
if ((range_flag & NO_MIN_RANGE) && (range_flag & NO_MAX_RANGE)) |
|
55
by brian
Update for using real bool types. |
8962 |
return false; |
1
by brian
clean slate |
8963 |
|
8964 |
if (!(sel_range->min_flag & NO_MIN_RANGE) && |
|
8965 |
!(sel_range->max_flag & NO_MAX_RANGE)) |
|
8966 |
{
|
|
8967 |
if (sel_range->maybe_null && |
|
8968 |
sel_range->min_value[0] && sel_range->max_value[0]) |
|
8969 |
range_flag|= NULL_RANGE; /* IS NULL condition */ |
|
8970 |
else if (memcmp(sel_range->min_value, sel_range->max_value, |
|
8971 |
min_max_arg_len) == 0) |
|
8972 |
range_flag|= EQ_RANGE; /* equality condition */ |
|
8973 |
}
|
|
8974 |
range= new QUICK_RANGE(sel_range->min_value, min_max_arg_len, |
|
8975 |
make_keypart_map(sel_range->part), |
|
8976 |
sel_range->max_value, min_max_arg_len, |
|
8977 |
make_keypart_map(sel_range->part), |
|
8978 |
range_flag); |
|
8979 |
if (!range) |
|
55
by brian
Update for using real bool types. |
8980 |
return true; |
1
by brian
clean slate |
8981 |
if (insert_dynamic(&min_max_ranges, (uchar*)&range)) |
55
by brian
Update for using real bool types. |
8982 |
return true; |
8983 |
return false; |
|
1
by brian
clean slate |
8984 |
}
|
8985 |
||
8986 |
||
8987 |
/*
|
|
8988 |
Opens the ranges if there are more conditions in quick_prefix_select than
|
|
8989 |
the ones used for jumping through the prefixes.
|
|
8990 |
||
8991 |
SYNOPSIS
|
|
8992 |
QUICK_GROUP_MIN_MAX_SELECT::adjust_prefix_ranges()
|
|
8993 |
||
8994 |
NOTES
|
|
8995 |
quick_prefix_select is made over the conditions on the whole key.
|
|
8996 |
It defines a number of ranges of length x.
|
|
8997 |
However when jumping through the prefixes we use only the the first
|
|
8998 |
few most significant keyparts in the range key. However if there
|
|
8999 |
are more keyparts to follow the ones we are using we must make the
|
|
9000 |
condition on the key inclusive (because x < "ab" means
|
|
9001 |
x[0] < 'a' OR (x[0] == 'a' AND x[1] < 'b').
|
|
9002 |
To achive the above we must turn off the NEAR_MIN/NEAR_MAX
|
|
9003 |
*/
|
|
9004 |
void QUICK_GROUP_MIN_MAX_SELECT::adjust_prefix_ranges () |
|
9005 |
{
|
|
9006 |
if (quick_prefix_select && |
|
9007 |
group_prefix_len < quick_prefix_select->max_used_key_length) |
|
9008 |
{
|
|
9009 |
DYNAMIC_ARRAY *arr; |
|
9010 |
uint inx; |
|
9011 |
||
9012 |
for (inx= 0, arr= &quick_prefix_select->ranges; inx < arr->elements; inx++) |
|
9013 |
{
|
|
9014 |
QUICK_RANGE *range; |
|
9015 |
||
9016 |
get_dynamic(arr, (uchar*)&range, inx); |
|
9017 |
range->flag &= ~(NEAR_MIN | NEAR_MAX); |
|
9018 |
}
|
|
9019 |
}
|
|
9020 |
}
|
|
9021 |
||
9022 |
||
9023 |
/*
|
|
9024 |
Determine the total number and length of the keys that will be used for
|
|
9025 |
index lookup.
|
|
9026 |
||
9027 |
SYNOPSIS
|
|
9028 |
QUICK_GROUP_MIN_MAX_SELECT::update_key_stat()
|
|
9029 |
||
9030 |
DESCRIPTION
|
|
9031 |
The total length of the keys used for index lookup depends on whether
|
|
9032 |
there are any predicates referencing the min/max argument, and/or if
|
|
9033 |
the min/max argument field can be NULL.
|
|
9034 |
This function does an optimistic analysis whether the search key might
|
|
9035 |
be extended by a constant for the min/max keypart. It is 'optimistic'
|
|
9036 |
because during actual execution it may happen that a particular range
|
|
9037 |
is skipped, and then a shorter key will be used. However this is data
|
|
9038 |
dependent and can't be easily estimated here.
|
|
9039 |
||
9040 |
RETURN
|
|
9041 |
None
|
|
9042 |
*/
|
|
9043 |
||
9044 |
void QUICK_GROUP_MIN_MAX_SELECT::update_key_stat() |
|
9045 |
{
|
|
9046 |
max_used_key_length= real_prefix_len; |
|
9047 |
if (min_max_ranges.elements > 0) |
|
9048 |
{
|
|
9049 |
QUICK_RANGE *cur_range; |
|
9050 |
if (have_min) |
|
9051 |
{ /* Check if the right-most range has a lower boundary. */ |
|
9052 |
get_dynamic(&min_max_ranges, (uchar*)&cur_range, |
|
9053 |
min_max_ranges.elements - 1); |
|
9054 |
if (!(cur_range->flag & NO_MIN_RANGE)) |
|
9055 |
{
|
|
9056 |
max_used_key_length+= min_max_arg_len; |
|
9057 |
used_key_parts++; |
|
9058 |
return; |
|
9059 |
}
|
|
9060 |
}
|
|
9061 |
if (have_max) |
|
9062 |
{ /* Check if the left-most range has an upper boundary. */ |
|
9063 |
get_dynamic(&min_max_ranges, (uchar*)&cur_range, 0); |
|
9064 |
if (!(cur_range->flag & NO_MAX_RANGE)) |
|
9065 |
{
|
|
9066 |
max_used_key_length+= min_max_arg_len; |
|
9067 |
used_key_parts++; |
|
9068 |
return; |
|
9069 |
}
|
|
9070 |
}
|
|
9071 |
}
|
|
9072 |
else if (have_min && min_max_arg_part && |
|
9073 |
min_max_arg_part->field->real_maybe_null()) |
|
9074 |
{
|
|
9075 |
/*
|
|
9076 |
If a MIN/MAX argument value is NULL, we can quickly determine
|
|
9077 |
that we're in the beginning of the next group, because NULLs
|
|
9078 |
are always < any other value. This allows us to quickly
|
|
9079 |
determine the end of the current group and jump to the next
|
|
9080 |
group (see next_min()) and thus effectively increases the
|
|
9081 |
usable key length.
|
|
9082 |
*/
|
|
9083 |
max_used_key_length+= min_max_arg_len; |
|
9084 |
used_key_parts++; |
|
9085 |
}
|
|
9086 |
}
|
|
9087 |
||
9088 |
||
9089 |
/*
|
|
9090 |
Initialize a quick group min/max select for key retrieval.
|
|
9091 |
||
9092 |
SYNOPSIS
|
|
9093 |
QUICK_GROUP_MIN_MAX_SELECT::reset()
|
|
9094 |
||
9095 |
DESCRIPTION
|
|
9096 |
Initialize the index chosen for access and find and store the prefix
|
|
9097 |
of the last group. The method is expensive since it performs disk access.
|
|
9098 |
||
9099 |
RETURN
|
|
9100 |
0 OK
|
|
9101 |
other Error code
|
|
9102 |
*/
|
|
9103 |
||
9104 |
int QUICK_GROUP_MIN_MAX_SELECT::reset(void) |
|
9105 |
{
|
|
9106 |
int result; |
|
9107 |
||
9108 |
file->extra(HA_EXTRA_KEYREAD); /* We need only the key attributes */ |
|
9109 |
if ((result= file->ha_index_init(index,1))) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9110 |
return(result); |
1
by brian
clean slate |
9111 |
if (quick_prefix_select && quick_prefix_select->reset()) |
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9112 |
return(1); |
1
by brian
clean slate |
9113 |
result= file->index_last(record); |
9114 |
if (result == HA_ERR_END_OF_FILE) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9115 |
return(0); |
1
by brian
clean slate |
9116 |
/* Save the prefix of the last group. */
|
9117 |
key_copy(last_prefix, record, index_info, group_prefix_len); |
|
9118 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9119 |
return(0); |
1
by brian
clean slate |
9120 |
}
|
9121 |
||
9122 |
||
9123 |
||
9124 |
/*
|
|
9125 |
Get the next key containing the MIN and/or MAX key for the next group.
|
|
9126 |
||
9127 |
SYNOPSIS
|
|
9128 |
QUICK_GROUP_MIN_MAX_SELECT::get_next()
|
|
9129 |
||
9130 |
DESCRIPTION
|
|
9131 |
The method finds the next subsequent group of records that satisfies the
|
|
9132 |
query conditions and finds the keys that contain the MIN/MAX values for
|
|
9133 |
the key part referenced by the MIN/MAX function(s). Once a group and its
|
|
9134 |
MIN/MAX values are found, store these values in the Item_sum objects for
|
|
9135 |
the MIN/MAX functions. The rest of the values in the result row are stored
|
|
9136 |
in the Item_field::result_field of each select field. If the query does
|
|
9137 |
not contain MIN and/or MAX functions, then the function only finds the
|
|
9138 |
group prefix, which is a query answer itself.
|
|
9139 |
||
9140 |
NOTES
|
|
9141 |
If both MIN and MAX are computed, then we use the fact that if there is
|
|
9142 |
no MIN key, there can't be a MAX key as well, so we can skip looking
|
|
9143 |
for a MAX key in this case.
|
|
9144 |
||
9145 |
RETURN
|
|
9146 |
0 on success
|
|
9147 |
HA_ERR_END_OF_FILE if returned all keys
|
|
9148 |
other if some error occurred
|
|
9149 |
*/
|
|
9150 |
||
9151 |
int QUICK_GROUP_MIN_MAX_SELECT::get_next() |
|
9152 |
{
|
|
9153 |
int min_res= 0; |
|
9154 |
int max_res= 0; |
|
9155 |
int result; |
|
9156 |
int is_last_prefix= 0; |
|
9157 |
||
9158 |
/*
|
|
9159 |
Loop until a group is found that satisfies all query conditions or the last
|
|
9160 |
group is reached.
|
|
9161 |
*/
|
|
9162 |
do
|
|
9163 |
{
|
|
9164 |
result= next_prefix(); |
|
9165 |
/*
|
|
9166 |
Check if this is the last group prefix. Notice that at this point
|
|
9167 |
this->record contains the current prefix in record format.
|
|
9168 |
*/
|
|
9169 |
if (!result) |
|
9170 |
{
|
|
9171 |
is_last_prefix= key_cmp(index_info->key_part, last_prefix, |
|
9172 |
group_prefix_len); |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9173 |
assert(is_last_prefix <= 0); |
1
by brian
clean slate |
9174 |
}
|
9175 |
else
|
|
9176 |
{
|
|
9177 |
if (result == HA_ERR_KEY_NOT_FOUND) |
|
9178 |
continue; |
|
9179 |
break; |
|
9180 |
}
|
|
9181 |
||
9182 |
if (have_min) |
|
9183 |
{
|
|
9184 |
min_res= next_min(); |
|
9185 |
if (min_res == 0) |
|
9186 |
update_min_result(); |
|
9187 |
}
|
|
9188 |
/* If there is no MIN in the group, there is no MAX either. */
|
|
9189 |
if ((have_max && !have_min) || |
|
9190 |
(have_max && have_min && (min_res == 0))) |
|
9191 |
{
|
|
9192 |
max_res= next_max(); |
|
9193 |
if (max_res == 0) |
|
9194 |
update_max_result(); |
|
9195 |
/* If a MIN was found, a MAX must have been found as well. */
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9196 |
assert((have_max && !have_min) || |
1
by brian
clean slate |
9197 |
(have_max && have_min && (max_res == 0))); |
9198 |
}
|
|
9199 |
/*
|
|
9200 |
If this is just a GROUP BY or DISTINCT without MIN or MAX and there
|
|
9201 |
are equality predicates for the key parts after the group, find the
|
|
9202 |
first sub-group with the extended prefix.
|
|
9203 |
*/
|
|
9204 |
if (!have_min && !have_max && key_infix_len > 0) |
|
9205 |
result= file->index_read_map(record, group_prefix, |
|
9206 |
make_prev_keypart_map(real_key_parts), |
|
9207 |
HA_READ_KEY_EXACT); |
|
9208 |
||
9209 |
result= have_min ? min_res : have_max ? max_res : result; |
|
9210 |
} while ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) && |
|
9211 |
is_last_prefix != 0); |
|
9212 |
||
9213 |
if (result == 0) |
|
9214 |
{
|
|
9215 |
/*
|
|
9216 |
Partially mimic the behavior of end_select_send. Copy the
|
|
9217 |
field data from Item_field::field into Item_field::result_field
|
|
9218 |
of each non-aggregated field (the group fields, and optionally
|
|
9219 |
other fields in non-ANSI SQL mode).
|
|
9220 |
*/
|
|
9221 |
copy_fields(&join->tmp_table_param); |
|
9222 |
}
|
|
9223 |
else if (result == HA_ERR_KEY_NOT_FOUND) |
|
9224 |
result= HA_ERR_END_OF_FILE; |
|
9225 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9226 |
return(result); |
1
by brian
clean slate |
9227 |
}
|
9228 |
||
9229 |
||
9230 |
/*
|
|
9231 |
Retrieve the minimal key in the next group.
|
|
9232 |
||
9233 |
SYNOPSIS
|
|
9234 |
QUICK_GROUP_MIN_MAX_SELECT::next_min()
|
|
9235 |
||
9236 |
DESCRIPTION
|
|
9237 |
Find the minimal key within this group such that the key satisfies the query
|
|
9238 |
conditions and NULL semantics. The found key is loaded into this->record.
|
|
9239 |
||
9240 |
IMPLEMENTATION
|
|
9241 |
Depending on the values of min_max_ranges.elements, key_infix_len, and
|
|
9242 |
whether there is a NULL in the MIN field, this function may directly
|
|
9243 |
return without any data access. In this case we use the key loaded into
|
|
9244 |
this->record by the call to this->next_prefix() just before this call.
|
|
9245 |
||
9246 |
RETURN
|
|
9247 |
0 on success
|
|
9248 |
HA_ERR_KEY_NOT_FOUND if no MIN key was found that fulfills all conditions.
|
|
9249 |
HA_ERR_END_OF_FILE - "" -
|
|
9250 |
other if some error occurred
|
|
9251 |
*/
|
|
9252 |
||
9253 |
int QUICK_GROUP_MIN_MAX_SELECT::next_min() |
|
9254 |
{
|
|
9255 |
int result= 0; |
|
9256 |
||
9257 |
/* Find the MIN key using the eventually extended group prefix. */
|
|
9258 |
if (min_max_ranges.elements > 0) |
|
9259 |
{
|
|
9260 |
if ((result= next_min_in_range())) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9261 |
return(result); |
1
by brian
clean slate |
9262 |
}
|
9263 |
else
|
|
9264 |
{
|
|
9265 |
/* Apply the constant equality conditions to the non-group select fields */
|
|
9266 |
if (key_infix_len > 0) |
|
9267 |
{
|
|
9268 |
if ((result= file->index_read_map(record, group_prefix, |
|
9269 |
make_prev_keypart_map(real_key_parts), |
|
9270 |
HA_READ_KEY_EXACT))) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9271 |
return(result); |
1
by brian
clean slate |
9272 |
}
|
9273 |
||
9274 |
/*
|
|
9275 |
If the min/max argument field is NULL, skip subsequent rows in the same
|
|
9276 |
group with NULL in it. Notice that:
|
|
9277 |
- if the first row in a group doesn't have a NULL in the field, no row
|
|
9278 |
in the same group has (because NULL < any other value),
|
|
9279 |
- min_max_arg_part->field->ptr points to some place in 'record'.
|
|
9280 |
*/
|
|
9281 |
if (min_max_arg_part && min_max_arg_part->field->is_null()) |
|
9282 |
{
|
|
9283 |
/* Find the first subsequent record without NULL in the MIN/MAX field. */
|
|
9284 |
key_copy(tmp_record, record, index_info, 0); |
|
9285 |
result= file->index_read_map(record, tmp_record, |
|
9286 |
make_keypart_map(real_key_parts), |
|
9287 |
HA_READ_AFTER_KEY); |
|
9288 |
/*
|
|
9289 |
Check if the new record belongs to the current group by comparing its
|
|
9290 |
prefix with the group's prefix. If it is from the next group, then the
|
|
9291 |
whole group has NULLs in the MIN/MAX field, so use the first record in
|
|
9292 |
the group as a result.
|
|
9293 |
TODO:
|
|
9294 |
It is possible to reuse this new record as the result candidate for the
|
|
9295 |
next call to next_min(), and to save one lookup in the next call. For
|
|
9296 |
this add a new member 'this->next_group_prefix'.
|
|
9297 |
*/
|
|
9298 |
if (!result) |
|
9299 |
{
|
|
9300 |
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len)) |
|
9301 |
key_restore(record, tmp_record, index_info, 0); |
|
9302 |
}
|
|
9303 |
else if (result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) |
|
9304 |
result= 0; /* There is a result in any case. */ |
|
9305 |
}
|
|
9306 |
}
|
|
9307 |
||
9308 |
/*
|
|
9309 |
If the MIN attribute is non-nullable, this->record already contains the
|
|
9310 |
MIN key in the group, so just return.
|
|
9311 |
*/
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9312 |
return(result); |
1
by brian
clean slate |
9313 |
}
|
9314 |
||
9315 |
||
9316 |
/*
|
|
9317 |
Retrieve the maximal key in the next group.
|
|
9318 |
||
9319 |
SYNOPSIS
|
|
9320 |
QUICK_GROUP_MIN_MAX_SELECT::next_max()
|
|
9321 |
||
9322 |
DESCRIPTION
|
|
9323 |
Lookup the maximal key of the group, and store it into this->record.
|
|
9324 |
||
9325 |
RETURN
|
|
9326 |
0 on success
|
|
9327 |
HA_ERR_KEY_NOT_FOUND if no MAX key was found that fulfills all conditions.
|
|
9328 |
HA_ERR_END_OF_FILE - "" -
|
|
9329 |
other if some error occurred
|
|
9330 |
*/
|
|
9331 |
||
9332 |
int QUICK_GROUP_MIN_MAX_SELECT::next_max() |
|
9333 |
{
|
|
9334 |
int result; |
|
9335 |
||
9336 |
/* Get the last key in the (possibly extended) group. */
|
|
9337 |
if (min_max_ranges.elements > 0) |
|
9338 |
result= next_max_in_range(); |
|
9339 |
else
|
|
9340 |
result= file->index_read_map(record, group_prefix, |
|
9341 |
make_prev_keypart_map(real_key_parts), |
|
9342 |
HA_READ_PREFIX_LAST); |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9343 |
return(result); |
1
by brian
clean slate |
9344 |
}
|
9345 |
||
9346 |
||
9347 |
/*
|
|
9348 |
Determine the prefix of the next group.
|
|
9349 |
||
9350 |
SYNOPSIS
|
|
9351 |
QUICK_GROUP_MIN_MAX_SELECT::next_prefix()
|
|
9352 |
||
9353 |
DESCRIPTION
|
|
9354 |
Determine the prefix of the next group that satisfies the query conditions.
|
|
9355 |
If there is a range condition referencing the group attributes, use a
|
|
9356 |
QUICK_RANGE_SELECT object to retrieve the *first* key that satisfies the
|
|
9357 |
condition. If there is a key infix of constants, append this infix
|
|
9358 |
immediately after the group attributes. The possibly extended prefix is
|
|
9359 |
stored in this->group_prefix. The first key of the found group is stored in
|
|
9360 |
this->record, on which relies this->next_min().
|
|
9361 |
||
9362 |
RETURN
|
|
9363 |
0 on success
|
|
9364 |
HA_ERR_KEY_NOT_FOUND if there is no key with the formed prefix
|
|
9365 |
HA_ERR_END_OF_FILE if there are no more keys
|
|
9366 |
other if some error occurred
|
|
9367 |
*/
|
|
9368 |
int QUICK_GROUP_MIN_MAX_SELECT::next_prefix() |
|
9369 |
{
|
|
9370 |
int result; |
|
9371 |
||
9372 |
if (quick_prefix_select) |
|
9373 |
{
|
|
9374 |
uchar *cur_prefix= seen_first_key ? group_prefix : NULL; |
|
9375 |
if ((result= quick_prefix_select->get_next_prefix(group_prefix_len, |
|
9376 |
make_prev_keypart_map(group_key_parts), cur_prefix))) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9377 |
return(result); |
55
by brian
Update for using real bool types. |
9378 |
seen_first_key= true; |
1
by brian
clean slate |
9379 |
}
|
9380 |
else
|
|
9381 |
{
|
|
9382 |
if (!seen_first_key) |
|
9383 |
{
|
|
9384 |
result= file->index_first(record); |
|
9385 |
if (result) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9386 |
return(result); |
55
by brian
Update for using real bool types. |
9387 |
seen_first_key= true; |
1
by brian
clean slate |
9388 |
}
|
9389 |
else
|
|
9390 |
{
|
|
9391 |
/* Load the first key in this group into record. */
|
|
9392 |
result= file->index_read_map(record, group_prefix, |
|
9393 |
make_prev_keypart_map(group_key_parts), |
|
9394 |
HA_READ_AFTER_KEY); |
|
9395 |
if (result) |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9396 |
return(result); |
1
by brian
clean slate |
9397 |
}
|
9398 |
}
|
|
9399 |
||
9400 |
/* Save the prefix of this group for subsequent calls. */
|
|
9401 |
key_copy(group_prefix, record, index_info, group_prefix_len); |
|
9402 |
/* Append key_infix to group_prefix. */
|
|
9403 |
if (key_infix_len > 0) |
|
9404 |
memcpy(group_prefix + group_prefix_len, |
|
9405 |
key_infix, key_infix_len); |
|
9406 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9407 |
return(0); |
1
by brian
clean slate |
9408 |
}
|
9409 |
||
9410 |
||
9411 |
/*
|
|
9412 |
Find the minimal key in a group that satisfies some range conditions for the
|
|
9413 |
min/max argument field.
|
|
9414 |
||
9415 |
SYNOPSIS
|
|
9416 |
QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range()
|
|
9417 |
||
9418 |
DESCRIPTION
|
|
9419 |
Given the sequence of ranges min_max_ranges, find the minimal key that is
|
|
9420 |
in the left-most possible range. If there is no such key, then the current
|
|
9421 |
group does not have a MIN key that satisfies the WHERE clause. If a key is
|
|
9422 |
found, its value is stored in this->record.
|
|
9423 |
||
9424 |
RETURN
|
|
9425 |
0 on success
|
|
9426 |
HA_ERR_KEY_NOT_FOUND if there is no key with the given prefix in any of
|
|
9427 |
the ranges
|
|
9428 |
HA_ERR_END_OF_FILE - "" -
|
|
9429 |
other if some error
|
|
9430 |
*/
|
|
9431 |
||
9432 |
int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range() |
|
9433 |
{
|
|
9434 |
ha_rkey_function find_flag; |
|
9435 |
key_part_map keypart_map; |
|
9436 |
QUICK_RANGE *cur_range; |
|
55
by brian
Update for using real bool types. |
9437 |
bool found_null= false; |
1
by brian
clean slate |
9438 |
int result= HA_ERR_KEY_NOT_FOUND; |
9439 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9440 |
assert(min_max_ranges.elements > 0); |
1
by brian
clean slate |
9441 |
|
9442 |
for (uint range_idx= 0; range_idx < min_max_ranges.elements; range_idx++) |
|
9443 |
{ /* Search from the left-most range to the right. */ |
|
9444 |
get_dynamic(&min_max_ranges, (uchar*)&cur_range, range_idx); |
|
9445 |
||
9446 |
/*
|
|
9447 |
If the current value for the min/max argument is bigger than the right
|
|
9448 |
boundary of cur_range, there is no need to check this range.
|
|
9449 |
*/
|
|
9450 |
if (range_idx != 0 && !(cur_range->flag & NO_MAX_RANGE) && |
|
9451 |
(key_cmp(min_max_arg_part, (const uchar*) cur_range->max_key, |
|
9452 |
min_max_arg_len) == 1)) |
|
9453 |
continue; |
|
9454 |
||
9455 |
if (cur_range->flag & NO_MIN_RANGE) |
|
9456 |
{
|
|
9457 |
keypart_map= make_prev_keypart_map(real_key_parts); |
|
9458 |
find_flag= HA_READ_KEY_EXACT; |
|
9459 |
}
|
|
9460 |
else
|
|
9461 |
{
|
|
9462 |
/* Extend the search key with the lower boundary for this range. */
|
|
9463 |
memcpy(group_prefix + real_prefix_len, cur_range->min_key, |
|
9464 |
cur_range->min_length); |
|
9465 |
keypart_map= make_keypart_map(real_key_parts); |
|
9466 |
find_flag= (cur_range->flag & (EQ_RANGE | NULL_RANGE)) ? |
|
9467 |
HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MIN) ? |
|
9468 |
HA_READ_AFTER_KEY : HA_READ_KEY_OR_NEXT; |
|
9469 |
}
|
|
9470 |
||
9471 |
result= file->index_read_map(record, group_prefix, keypart_map, find_flag); |
|
9472 |
if (result) |
|
9473 |
{
|
|
9474 |
if ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) && |
|
9475 |
(cur_range->flag & (EQ_RANGE | NULL_RANGE))) |
|
9476 |
continue; /* Check the next range. */ |
|
9477 |
||
9478 |
/*
|
|
9479 |
In all other cases (HA_ERR_*, HA_READ_KEY_EXACT with NO_MIN_RANGE,
|
|
9480 |
HA_READ_AFTER_KEY, HA_READ_KEY_OR_NEXT) if the lookup failed for this
|
|
9481 |
range, it can't succeed for any other subsequent range.
|
|
9482 |
*/
|
|
9483 |
break; |
|
9484 |
}
|
|
9485 |
||
9486 |
/* A key was found. */
|
|
9487 |
if (cur_range->flag & EQ_RANGE) |
|
9488 |
break; /* No need to perform the checks below for equal keys. */ |
|
9489 |
||
9490 |
if (cur_range->flag & NULL_RANGE) |
|
9491 |
{
|
|
9492 |
/*
|
|
9493 |
Remember this key, and continue looking for a non-NULL key that
|
|
9494 |
satisfies some other condition.
|
|
9495 |
*/
|
|
9496 |
memcpy(tmp_record, record, head->s->rec_buff_length); |
|
55
by brian
Update for using real bool types. |
9497 |
found_null= true; |
1
by brian
clean slate |
9498 |
continue; |
9499 |
}
|
|
9500 |
||
9501 |
/* Check if record belongs to the current group. */
|
|
9502 |
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len)) |
|
9503 |
{
|
|
9504 |
result= HA_ERR_KEY_NOT_FOUND; |
|
9505 |
continue; |
|
9506 |
}
|
|
9507 |
||
9508 |
/* If there is an upper limit, check if the found key is in the range. */
|
|
9509 |
if ( !(cur_range->flag & NO_MAX_RANGE) ) |
|
9510 |
{
|
|
9511 |
/* Compose the MAX key for the range. */
|
|
9512 |
uchar *max_key= (uchar*) my_alloca(real_prefix_len + min_max_arg_len); |
|
9513 |
memcpy(max_key, group_prefix, real_prefix_len); |
|
9514 |
memcpy(max_key + real_prefix_len, cur_range->max_key, |
|
9515 |
cur_range->max_length); |
|
9516 |
/* Compare the found key with max_key. */
|
|
9517 |
int cmp_res= key_cmp(index_info->key_part, max_key, |
|
9518 |
real_prefix_len + min_max_arg_len); |
|
9519 |
if ((!((cur_range->flag & NEAR_MAX) && (cmp_res == -1)) || (cmp_res <= 0))) |
|
9520 |
{
|
|
9521 |
result= HA_ERR_KEY_NOT_FOUND; |
|
9522 |
continue; |
|
9523 |
}
|
|
9524 |
}
|
|
9525 |
/* If we got to this point, the current key qualifies as MIN. */
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9526 |
assert(result == 0); |
1
by brian
clean slate |
9527 |
break; |
9528 |
}
|
|
9529 |
/*
|
|
9530 |
If there was a key with NULL in the MIN/MAX field, and there was no other
|
|
9531 |
key without NULL from the same group that satisfies some other condition,
|
|
9532 |
then use the key with the NULL.
|
|
9533 |
*/
|
|
9534 |
if (found_null && result) |
|
9535 |
{
|
|
9536 |
memcpy(record, tmp_record, head->s->rec_buff_length); |
|
9537 |
result= 0; |
|
9538 |
}
|
|
9539 |
return result; |
|
9540 |
}
|
|
9541 |
||
9542 |
||
9543 |
/*
|
|
9544 |
Find the maximal key in a group that satisfies some range conditions for the
|
|
9545 |
min/max argument field.
|
|
9546 |
||
9547 |
SYNOPSIS
|
|
9548 |
QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range()
|
|
9549 |
||
9550 |
DESCRIPTION
|
|
9551 |
Given the sequence of ranges min_max_ranges, find the maximal key that is
|
|
9552 |
in the right-most possible range. If there is no such key, then the current
|
|
9553 |
group does not have a MAX key that satisfies the WHERE clause. If a key is
|
|
9554 |
found, its value is stored in this->record.
|
|
9555 |
||
9556 |
RETURN
|
|
9557 |
0 on success
|
|
9558 |
HA_ERR_KEY_NOT_FOUND if there is no key with the given prefix in any of
|
|
9559 |
the ranges
|
|
9560 |
HA_ERR_END_OF_FILE - "" -
|
|
9561 |
other if some error
|
|
9562 |
*/
|
|
9563 |
||
9564 |
int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range() |
|
9565 |
{
|
|
9566 |
ha_rkey_function find_flag; |
|
9567 |
key_part_map keypart_map; |
|
9568 |
QUICK_RANGE *cur_range; |
|
9569 |
int result; |
|
9570 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9571 |
assert(min_max_ranges.elements > 0); |
1
by brian
clean slate |
9572 |
|
9573 |
for (uint range_idx= min_max_ranges.elements; range_idx > 0; range_idx--) |
|
9574 |
{ /* Search from the right-most range to the left. */ |
|
9575 |
get_dynamic(&min_max_ranges, (uchar*)&cur_range, range_idx - 1); |
|
9576 |
||
9577 |
/*
|
|
9578 |
If the current value for the min/max argument is smaller than the left
|
|
9579 |
boundary of cur_range, there is no need to check this range.
|
|
9580 |
*/
|
|
9581 |
if (range_idx != min_max_ranges.elements && |
|
9582 |
!(cur_range->flag & NO_MIN_RANGE) && |
|
9583 |
(key_cmp(min_max_arg_part, (const uchar*) cur_range->min_key, |
|
9584 |
min_max_arg_len) == -1)) |
|
9585 |
continue; |
|
9586 |
||
9587 |
if (cur_range->flag & NO_MAX_RANGE) |
|
9588 |
{
|
|
9589 |
keypart_map= make_prev_keypart_map(real_key_parts); |
|
9590 |
find_flag= HA_READ_PREFIX_LAST; |
|
9591 |
}
|
|
9592 |
else
|
|
9593 |
{
|
|
9594 |
/* Extend the search key with the upper boundary for this range. */
|
|
9595 |
memcpy(group_prefix + real_prefix_len, cur_range->max_key, |
|
9596 |
cur_range->max_length); |
|
9597 |
keypart_map= make_keypart_map(real_key_parts); |
|
9598 |
find_flag= (cur_range->flag & EQ_RANGE) ? |
|
9599 |
HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MAX) ? |
|
9600 |
HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV; |
|
9601 |
}
|
|
9602 |
||
9603 |
result= file->index_read_map(record, group_prefix, keypart_map, find_flag); |
|
9604 |
||
9605 |
if (result) |
|
9606 |
{
|
|
9607 |
if ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) && |
|
9608 |
(cur_range->flag & EQ_RANGE)) |
|
9609 |
continue; /* Check the next range. */ |
|
9610 |
||
9611 |
/*
|
|
9612 |
In no key was found with this upper bound, there certainly are no keys
|
|
9613 |
in the ranges to the left.
|
|
9614 |
*/
|
|
9615 |
return result; |
|
9616 |
}
|
|
9617 |
/* A key was found. */
|
|
9618 |
if (cur_range->flag & EQ_RANGE) |
|
9619 |
return 0; /* No need to perform the checks below for equal keys. */ |
|
9620 |
||
9621 |
/* Check if record belongs to the current group. */
|
|
9622 |
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len)) |
|
9623 |
continue; // Row not found |
|
9624 |
||
9625 |
/* If there is a lower limit, check if the found key is in the range. */
|
|
9626 |
if ( !(cur_range->flag & NO_MIN_RANGE) ) |
|
9627 |
{
|
|
9628 |
/* Compose the MIN key for the range. */
|
|
9629 |
uchar *min_key= (uchar*) my_alloca(real_prefix_len + min_max_arg_len); |
|
9630 |
memcpy(min_key, group_prefix, real_prefix_len); |
|
9631 |
memcpy(min_key + real_prefix_len, cur_range->min_key, |
|
9632 |
cur_range->min_length); |
|
9633 |
/* Compare the found key with min_key. */
|
|
9634 |
int cmp_res= key_cmp(index_info->key_part, min_key, |
|
9635 |
real_prefix_len + min_max_arg_len); |
|
9636 |
if ((!((cur_range->flag & NEAR_MIN) && (cmp_res == 1)) || |
|
9637 |
(cmp_res >= 0))) |
|
9638 |
continue; |
|
9639 |
}
|
|
9640 |
/* If we got to this point, the current key qualifies as MAX. */
|
|
9641 |
return result; |
|
9642 |
}
|
|
9643 |
return HA_ERR_KEY_NOT_FOUND; |
|
9644 |
}
|
|
9645 |
||
9646 |
||
9647 |
/*
|
|
9648 |
Update all MIN function results with the newly found value.
|
|
9649 |
||
9650 |
SYNOPSIS
|
|
9651 |
QUICK_GROUP_MIN_MAX_SELECT::update_min_result()
|
|
9652 |
||
9653 |
DESCRIPTION
|
|
9654 |
The method iterates through all MIN functions and updates the result value
|
|
9655 |
of each function by calling Item_sum::reset(), which in turn picks the new
|
|
9656 |
result value from this->head->record[0], previously updated by
|
|
9657 |
next_min(). The updated value is stored in a member variable of each of the
|
|
9658 |
Item_sum objects, depending on the value type.
|
|
9659 |
||
9660 |
IMPLEMENTATION
|
|
9661 |
The update must be done separately for MIN and MAX, immediately after
|
|
9662 |
next_min() was called and before next_max() is called, because both MIN and
|
|
9663 |
MAX take their result value from the same buffer this->head->record[0]
|
|
9664 |
(i.e. this->record).
|
|
9665 |
||
9666 |
RETURN
|
|
9667 |
None
|
|
9668 |
*/
|
|
9669 |
||
9670 |
void QUICK_GROUP_MIN_MAX_SELECT::update_min_result() |
|
9671 |
{
|
|
9672 |
Item_sum *min_func; |
|
9673 |
||
9674 |
min_functions_it->rewind(); |
|
9675 |
while ((min_func= (*min_functions_it)++)) |
|
9676 |
min_func->reset(); |
|
9677 |
}
|
|
9678 |
||
9679 |
||
9680 |
/*
|
|
9681 |
Update all MAX function results with the newly found value.
|
|
9682 |
||
9683 |
SYNOPSIS
|
|
9684 |
QUICK_GROUP_MIN_MAX_SELECT::update_max_result()
|
|
9685 |
||
9686 |
DESCRIPTION
|
|
9687 |
The method iterates through all MAX functions and updates the result value
|
|
9688 |
of each function by calling Item_sum::reset(), which in turn picks the new
|
|
9689 |
result value from this->head->record[0], previously updated by
|
|
9690 |
next_max(). The updated value is stored in a member variable of each of the
|
|
9691 |
Item_sum objects, depending on the value type.
|
|
9692 |
||
9693 |
IMPLEMENTATION
|
|
9694 |
The update must be done separately for MIN and MAX, immediately after
|
|
9695 |
next_max() was called, because both MIN and MAX take their result value
|
|
9696 |
from the same buffer this->head->record[0] (i.e. this->record).
|
|
9697 |
||
9698 |
RETURN
|
|
9699 |
None
|
|
9700 |
*/
|
|
9701 |
||
9702 |
void QUICK_GROUP_MIN_MAX_SELECT::update_max_result() |
|
9703 |
{
|
|
9704 |
Item_sum *max_func; |
|
9705 |
||
9706 |
max_functions_it->rewind(); |
|
9707 |
while ((max_func= (*max_functions_it)++)) |
|
9708 |
max_func->reset(); |
|
9709 |
}
|
|
9710 |
||
9711 |
||
9712 |
/*
|
|
9713 |
Append comma-separated list of keys this quick select uses to key_names;
|
|
9714 |
append comma-separated list of corresponding used lengths to used_lengths.
|
|
9715 |
||
9716 |
SYNOPSIS
|
|
9717 |
QUICK_GROUP_MIN_MAX_SELECT::add_keys_and_lengths()
|
|
9718 |
key_names [out] Names of used indexes
|
|
9719 |
used_lengths [out] Corresponding lengths of the index names
|
|
9720 |
||
9721 |
DESCRIPTION
|
|
9722 |
This method is used by select_describe to extract the names of the
|
|
9723 |
indexes used by a quick select.
|
|
9724 |
||
9725 |
*/
|
|
9726 |
||
9727 |
void QUICK_GROUP_MIN_MAX_SELECT::add_keys_and_lengths(String *key_names, |
|
9728 |
String *used_lengths) |
|
9729 |
{
|
|
9730 |
char buf[64]; |
|
9731 |
uint length; |
|
9732 |
key_names->append(index_info->name); |
|
152
by Brian Aker
longlong replacement |
9733 |
length= int64_t2str(max_used_key_length, buf, 10) - buf; |
1
by brian
clean slate |
9734 |
used_lengths->append(buf, length); |
9735 |
}
|
|
9736 |
||
9737 |
static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map, |
|
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
9738 |
const char *msg __attribute__((unused))) |
1
by brian
clean slate |
9739 |
{
|
9740 |
SEL_ARG **key,**end; |
|
9741 |
int idx; |
|
9742 |
char buff[1024]; |
|
9743 |
||
9744 |
String tmp(buff,sizeof(buff),&my_charset_bin); |
|
9745 |
tmp.length(0); |
|
9746 |
for (idx= 0,key=tree->keys, end=key+param->keys ; |
|
9747 |
key != end ; |
|
9748 |
key++,idx++) |
|
9749 |
{
|
|
9750 |
if (tree_map->is_set(idx)) |
|
9751 |
{
|
|
9752 |
uint keynr= param->real_keynr[idx]; |
|
9753 |
if (tmp.length()) |
|
9754 |
tmp.append(','); |
|
9755 |
tmp.append(param->table->key_info[keynr].name); |
|
9756 |
}
|
|
9757 |
}
|
|
9758 |
if (!tmp.length()) |
|
9759 |
tmp.append(STRING_WITH_LEN("(empty)")); |
|
9760 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9761 |
return; |
1
by brian
clean slate |
9762 |
}
|
9763 |
||
9764 |
||
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
9765 |
static void print_ror_scans_arr(Table *table, |
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
9766 |
const char *msg __attribute__((unused)), |
1
by brian
clean slate |
9767 |
struct st_ror_scan_info **start, |
9768 |
struct st_ror_scan_info **end) |
|
9769 |
{
|
|
9770 |
char buff[1024]; |
|
9771 |
String tmp(buff,sizeof(buff),&my_charset_bin); |
|
9772 |
tmp.length(0); |
|
9773 |
for (;start != end; start++) |
|
9774 |
{
|
|
9775 |
if (tmp.length()) |
|
9776 |
tmp.append(','); |
|
9777 |
tmp.append(table->key_info[(*start)->keynr].name); |
|
9778 |
}
|
|
9779 |
if (!tmp.length()) |
|
9780 |
tmp.append(STRING_WITH_LEN("(empty)")); |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9781 |
return; |
1
by brian
clean slate |
9782 |
}
|
9783 |
||
9784 |
/*****************************************************************************
|
|
9785 |
** Instantiate templates
|
|
9786 |
*****************************************************************************/
|
|
9787 |
||
9788 |
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
|
|
9789 |
template class List<QUICK_RANGE>; |
|
9790 |
template class List_iterator<QUICK_RANGE>; |
|
9791 |
#endif
|