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 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
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
|
|
1
by brian
clean slate |
32 |
intervals.
|
33 |
The entry point for the range analysis module is get_mm_tree() function.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
34 |
|
1
by brian
clean slate |
35 |
The lists are returned in form of complicated structure of interlinked
|
36 |
SEL_TREE/SEL_IMERGE/SEL_ARG objects.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
37 |
See quick_range_seq_next, find_used_partitions for examples of how to walk
|
1
by brian
clean slate |
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 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
49 |
Range/index_merge/groupby-minmax optimizer module
|
50 |
A module that accepts a table, condition, and returns
|
|
1
by brian
clean slate |
51 |
- a QUICK_*_SELECT object that can be used to retrieve rows that match
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
52 |
the specified condition, or a "no records will match the condition"
|
1
by brian
clean slate |
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:
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
67 |
|
1
by brian
clean slate |
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)
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
70 |
|
1
by brian
clean slate |
71 |
KeyTuple: keypart1-data, keypart2-data, ...
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
72 |
|
1
by brian
clean slate |
73 |
The value of each keypart is stored in the following format:
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
74 |
|
1
by brian
clean slate |
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
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
78 |
be used to check this), then the first byte is a NULL indicator with the
|
1
by brian
clean slate |
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
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
89 |
stored. The default is that length is static and equal to
|
1
by brian
clean slate |
90 |
KEY_PART_INFO::length.
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
91 |
|
92 |
Key parts with (key_part_flag & HA_BLOB_PART) have length depending of the
|
|
1
by brian
clean slate |
93 |
value:
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
94 |
|
1
by brian
clean slate |
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 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
102 |
CAUTION: the above description is only sergefp's understanding of the
|
1
by brian
clean slate |
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> |
|
550
by Monty Taylor
Moved error.h into just the files that need it. |
108 |
#include <drizzled/error.h> |
575.1.3
by Monty Taylor
Moved some stuff out of handler.h. |
109 |
#include <drizzled/cost_vect.h> |
584.4.7
by Monty Taylor
Removed a big bank of includes from item.h. |
110 |
#include <drizzled/item/cmpfunc.h> |
584.5.1
by Monty Taylor
Removed field includes from field.h. |
111 |
#include <drizzled/field/num.h> |
670.2.4
by Monty Taylor
Removed more stuff from the headers. |
112 |
#include <drizzled/check_stack_overrun.h> |
575.1.3
by Monty Taylor
Moved some stuff out of handler.h. |
113 |
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
114 |
#include <string> |
572.1.4
by Monty Taylor
Removed a bunch of unusued tests and defines from autoconf. |
115 |
#include CMATH_H
|
116 |
||
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
117 |
using namespace std; |
572.1.4
by Monty Taylor
Removed a bunch of unusued tests and defines from autoconf. |
118 |
#if defined(CMATH_NAMESPACE)
|
119 |
using namespace CMATH_NAMESPACE; |
|
120 |
#endif
|
|
1
by brian
clean slate |
121 |
|
122 |
/*
|
|
123 |
Convert double value to #rows. Currently this does floor(), and we
|
|
124 |
might consider using round() instead.
|
|
125 |
*/
|
|
126 |
#define double2rows(x) ((ha_rows)(x))
|
|
127 |
||
481
by Brian Aker
Remove all of uchar. |
128 |
static int sel_cmp(Field *f,unsigned char *a,unsigned char *b,uint8_t a_flag,uint8_t b_flag); |
1
by brian
clean slate |
129 |
|
481
by Brian Aker
Remove all of uchar. |
130 |
static unsigned char is_null_string[2]= {1,0}; |
1
by brian
clean slate |
131 |
|
132 |
class RANGE_OPT_PARAM; |
|
133 |
/*
|
|
134 |
A construction block of the SEL_ARG-graph.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
135 |
|
136 |
The following description only covers graphs of SEL_ARG objects with
|
|
1
by brian
clean slate |
137 |
sel_arg->type==KEY_RANGE:
|
138 |
||
139 |
One SEL_ARG object represents an "elementary interval" in form
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
140 |
|
1
by brian
clean slate |
141 |
min_value <=? table.keypartX <=? max_value
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
142 |
|
1
by brian
clean slate |
143 |
The interval is a non-empty interval of any kind: with[out] minimum/maximum
|
144 |
bound, [half]open/closed, single-point interval, etc.
|
|
145 |
||
146 |
1. SEL_ARG GRAPH STRUCTURE
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
147 |
|
1
by brian
clean slate |
148 |
SEL_ARG objects are linked together in a graph. The meaning of the graph
|
149 |
is better demostrated by an example:
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
150 |
|
1
by brian
clean slate |
151 |
tree->keys[i]
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
152 |
|
|
1
by brian
clean slate |
153 |
| $ $
|
154 |
| part=1 $ part=2 $ part=3
|
|
155 |
| $ $
|
|
156 |
| +-------+ $ +-------+ $ +--------+
|
|
157 |
| | kp1<1 |--$-->| kp2=5 |--$-->| kp3=10 |
|
|
158 |
| +-------+ $ +-------+ $ +--------+
|
|
159 |
| | $ $ |
|
|
160 |
| | $ $ +--------+
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
161 |
| | $ $ | kp3=12 |
|
162 |
| | $ $ +--------+
|
|
163 |
| +-------+ $ $
|
|
164 |
\->| kp1=2 |--$--------------$-+
|
|
1
by brian
clean slate |
165 |
+-------+ $ $ | +--------+
|
166 |
| $ $ ==>| kp3=11 |
|
|
167 |
+-------+ $ $ | +--------+
|
|
168 |
| kp1=3 |--$--------------$-+ |
|
|
169 |
+-------+ $ $ +--------+
|
|
170 |
| $ $ | kp3=14 |
|
|
171 |
... $ $ +--------+
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
172 |
|
1
by brian
clean slate |
173 |
The entire graph is partitioned into "interval lists".
|
174 |
||
175 |
An interval list is a sequence of ordered disjoint intervals over the same
|
|
176 |
key part. SEL_ARG are linked via "next" and "prev" pointers. Additionally,
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
177 |
all intervals in the list form an RB-tree, linked via left/right/parent
|
1
by brian
clean slate |
178 |
pointers. The RB-tree root SEL_ARG object will be further called "root of the
|
179 |
interval list".
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
180 |
|
181 |
In the example pic, there are 4 interval lists:
|
|
1
by brian
clean slate |
182 |
"kp<1 OR kp1=2 OR kp1=3", "kp2=5", "kp3=10 OR kp3=12", "kp3=11 OR kp3=13".
|
183 |
The vertical lines represent SEL_ARG::next/prev pointers.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
184 |
|
1
by brian
clean slate |
185 |
In an interval list, each member X may have SEL_ARG::next_key_part pointer
|
186 |
pointing to the root of another interval list Y. The pointed interval list
|
|
187 |
must cover a key part with greater number (i.e. Y->part > X->part).
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
188 |
|
1
by brian
clean slate |
189 |
In the example pic, the next_key_part pointers are represented by
|
190 |
horisontal lines.
|
|
191 |
||
192 |
2. SEL_ARG GRAPH SEMANTICS
|
|
193 |
||
194 |
It represents a condition in a special form (we don't have a name for it ATM)
|
|
195 |
The SEL_ARG::next/prev is "OR", and next_key_part is "AND".
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
196 |
|
1
by brian
clean slate |
197 |
For example, the picture represents the condition in form:
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
198 |
(kp1 < 1 AND kp2=5 AND (kp3=10 OR kp3=12)) OR
|
199 |
(kp1=2 AND (kp3=11 OR kp3=14)) OR
|
|
1
by brian
clean slate |
200 |
(kp1=3 AND (kp3=11 OR kp3=14))
|
201 |
||
202 |
||
203 |
3. SEL_ARG GRAPH USE
|
|
204 |
||
205 |
Use get_mm_tree() to construct SEL_ARG graph from WHERE condition.
|
|
206 |
Then walk the SEL_ARG graph and get a list of dijsoint ordered key
|
|
207 |
intervals (i.e. intervals in form
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
208 |
|
1
by brian
clean slate |
209 |
(constA1, .., const1_K) < (keypart1,.., keypartK) < (constB1, .., constB_K)
|
210 |
||
211 |
Those intervals can be used to access the index. The uses are in:
|
|
212 |
- check_quick_select() - Walk the SEL_ARG graph and find an estimate of
|
|
213 |
how many table records are contained within all
|
|
214 |
intervals.
|
|
215 |
- get_quick_select() - Walk the SEL_ARG, materialize the key intervals,
|
|
216 |
and create QUICK_RANGE_SELECT object that will
|
|
217 |
read records within these intervals.
|
|
218 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
219 |
4. SPACE COMPLEXITY NOTES
|
1
by brian
clean slate |
220 |
|
221 |
SEL_ARG graph is a representation of an ordered disjoint sequence of
|
|
222 |
intervals over the ordered set of index tuple values.
|
|
223 |
||
224 |
For multi-part keys, one can construct a WHERE expression such that its
|
|
225 |
list of intervals will be of combinatorial size. Here is an example:
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
226 |
|
227 |
(keypart1 IN (1,2, ..., n1)) AND
|
|
228 |
(keypart2 IN (1,2, ..., n2)) AND
|
|
1
by brian
clean slate |
229 |
(keypart3 IN (1,2, ..., n3))
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
230 |
|
1
by brian
clean slate |
231 |
For this WHERE clause the list of intervals will have n1*n2*n3 intervals
|
232 |
of form
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
233 |
|
1
by brian
clean slate |
234 |
(keypart1, keypart2, keypart3) = (k1, k2, k3), where 1 <= k{i} <= n{i}
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
235 |
|
1
by brian
clean slate |
236 |
SEL_ARG graph structure aims to reduce the amount of required space by
|
237 |
"sharing" the elementary intervals when possible (the pic at the
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
238 |
beginning of this comment has examples of such sharing). The sharing may
|
1
by brian
clean slate |
239 |
prevent combinatorial blowup:
|
240 |
||
241 |
There are WHERE clauses that have combinatorial-size interval lists but
|
|
242 |
will be represented by a compact SEL_ARG graph.
|
|
243 |
Example:
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
244 |
(keypartN IN (1,2, ..., n1)) AND
|
1
by brian
clean slate |
245 |
...
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
246 |
(keypart2 IN (1,2, ..., n2)) AND
|
1
by brian
clean slate |
247 |
(keypart1 IN (1,2, ..., n3))
|
248 |
||
249 |
but not in all cases:
|
|
250 |
||
251 |
- There are WHERE clauses that do have a compact SEL_ARG-graph
|
|
252 |
representation but get_mm_tree() and its callees will construct a
|
|
253 |
graph of combinatorial size.
|
|
254 |
Example:
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
255 |
(keypart1 IN (1,2, ..., n1)) AND
|
256 |
(keypart2 IN (1,2, ..., n2)) AND
|
|
1
by brian
clean slate |
257 |
...
|
258 |
(keypartN IN (1,2, ..., n3))
|
|
259 |
||
260 |
- There are WHERE clauses for which the minimal possible SEL_ARG graph
|
|
261 |
representation will have combinatorial size.
|
|
262 |
Example:
|
|
263 |
By induction: Let's take any interval on some keypart in the middle:
|
|
264 |
||
265 |
kp15=c0
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
266 |
|
1
by brian
clean slate |
267 |
Then let's AND it with this interval 'structure' from preceding and
|
268 |
following keyparts:
|
|
269 |
||
270 |
(kp14=c1 AND kp16=c3) OR keypart14=c2) (*)
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
271 |
|
1
by brian
clean slate |
272 |
We will obtain this SEL_ARG graph:
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
273 |
|
1
by brian
clean slate |
274 |
kp14 $ kp15 $ kp16
|
275 |
$ $
|
|
276 |
+---------+ $ +---------+ $ +---------+
|
|
277 |
| kp14=c1 |--$-->| kp15=c0 |--$-->| kp16=c3 |
|
|
278 |
+---------+ $ +---------+ $ +---------+
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
279 |
| $ $
|
280 |
+---------+ $ +---------+ $
|
|
281 |
| kp14=c2 |--$-->| kp15=c0 | $
|
|
282 |
+---------+ $ +---------+ $
|
|
1
by brian
clean slate |
283 |
$ $
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
284 |
|
1
by brian
clean slate |
285 |
Note that we had to duplicate "kp15=c0" and there was no way to avoid
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
286 |
that.
|
1
by brian
clean slate |
287 |
The induction step: AND the obtained expression with another "wrapping"
|
288 |
expression like (*).
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
289 |
When the process ends because of the limit on max. number of keyparts
|
1
by brian
clean slate |
290 |
we'll have:
|
291 |
||
292 |
WHERE clause length is O(3*#max_keyparts)
|
|
293 |
SEL_ARG graph size is O(2^(#max_keyparts/2))
|
|
294 |
||
295 |
(it is also possible to construct a case where instead of 2 in 2^n we
|
|
296 |
have a bigger constant, e.g. 4, and get a graph with 4^(31/2)= 2^31
|
|
297 |
nodes)
|
|
298 |
||
299 |
We avoid consuming too much memory by setting a limit on the number of
|
|
300 |
SEL_ARG object we can construct during one range analysis invocation.
|
|
301 |
*/
|
|
302 |
||
303 |
class SEL_ARG :public Sql_alloc |
|
304 |
{
|
|
305 |
public: |
|
206
by Brian Aker
Removed final uint dead types. |
306 |
uint8_t min_flag,max_flag,maybe_flag; |
307 |
uint8_t part; // Which key part |
|
308 |
uint8_t maybe_null; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
309 |
/*
|
1
by brian
clean slate |
310 |
Number of children of this element in the RB-tree, plus 1 for this
|
311 |
element itself.
|
|
312 |
*/
|
|
206
by Brian Aker
Removed final uint dead types. |
313 |
uint16_t elements; |
1
by brian
clean slate |
314 |
/*
|
315 |
Valid only for elements which are RB-tree roots: Number of times this
|
|
316 |
RB-tree is referred to (it is referred by SEL_ARG::next_key_part or by
|
|
317 |
SEL_TREE::keys[i] or by a temporary SEL_ARG* variable)
|
|
318 |
*/
|
|
319 |
ulong use_count; |
|
320 |
||
321 |
Field *field; |
|
481
by Brian Aker
Remove all of uchar. |
322 |
unsigned char *min_value,*max_value; // Pointer to range |
1
by brian
clean slate |
323 |
|
324 |
/*
|
|
325 |
eq_tree() requires that left == right == 0 if the type is MAYBE_KEY.
|
|
326 |
*/
|
|
327 |
SEL_ARG *left,*right; /* R-B tree children */ |
|
328 |
SEL_ARG *next,*prev; /* Links for bi-directional interval list */ |
|
329 |
SEL_ARG *parent; /* R-B tree parent */ |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
330 |
SEL_ARG *next_key_part; |
1
by brian
clean slate |
331 |
enum leaf_color { BLACK,RED } color; |
332 |
enum Type { IMPOSSIBLE, MAYBE, MAYBE_KEY, KEY_RANGE } type; |
|
333 |
||
334 |
enum { MAX_SEL_ARGS = 16000 }; |
|
335 |
||
336 |
SEL_ARG() {} |
|
337 |
SEL_ARG(SEL_ARG &); |
|
481
by Brian Aker
Remove all of uchar. |
338 |
SEL_ARG(Field *,const unsigned char *, const unsigned char *); |
339 |
SEL_ARG(Field *field, uint8_t part, unsigned char *min_value, unsigned char *max_value, |
|
206
by Brian Aker
Removed final uint dead types. |
340 |
uint8_t min_flag, uint8_t max_flag, uint8_t maybe_flag); |
1
by brian
clean slate |
341 |
SEL_ARG(enum Type type_arg) |
342 |
:min_flag(0),elements(1),use_count(1),left(0),right(0),next_key_part(0), |
|
343 |
color(BLACK), type(type_arg) |
|
344 |
{}
|
|
345 |
inline bool is_same(SEL_ARG *arg) |
|
346 |
{
|
|
347 |
if (type != arg->type || part != arg->part) |
|
348 |
return 0; |
|
349 |
if (type != KEY_RANGE) |
|
350 |
return 1; |
|
351 |
return cmp_min_to_min(arg) == 0 && cmp_max_to_max(arg) == 0; |
|
352 |
}
|
|
353 |
inline void merge_flags(SEL_ARG *arg) { maybe_flag|=arg->maybe_flag; } |
|
354 |
inline void maybe_smaller() { maybe_flag=1; } |
|
355 |
/* Return true iff it's a single-point null interval */
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
356 |
inline bool is_null_interval() { return maybe_null && max_value[0] == 1; } |
1
by brian
clean slate |
357 |
inline int cmp_min_to_min(SEL_ARG* arg) |
358 |
{
|
|
359 |
return sel_cmp(field,min_value, arg->min_value, min_flag, arg->min_flag); |
|
360 |
}
|
|
361 |
inline int cmp_min_to_max(SEL_ARG* arg) |
|
362 |
{
|
|
363 |
return sel_cmp(field,min_value, arg->max_value, min_flag, arg->max_flag); |
|
364 |
}
|
|
365 |
inline int cmp_max_to_max(SEL_ARG* arg) |
|
366 |
{
|
|
367 |
return sel_cmp(field,max_value, arg->max_value, max_flag, arg->max_flag); |
|
368 |
}
|
|
369 |
inline int cmp_max_to_min(SEL_ARG* arg) |
|
370 |
{
|
|
371 |
return sel_cmp(field,max_value, arg->min_value, max_flag, arg->min_flag); |
|
372 |
}
|
|
373 |
SEL_ARG *clone_and(SEL_ARG* arg) |
|
374 |
{ // Get overlapping range |
|
481
by Brian Aker
Remove all of uchar. |
375 |
unsigned char *new_min,*new_max; |
206
by Brian Aker
Removed final uint dead types. |
376 |
uint8_t flag_min,flag_max; |
1
by brian
clean slate |
377 |
if (cmp_min_to_min(arg) >= 0) |
378 |
{
|
|
379 |
new_min=min_value; flag_min=min_flag; |
|
380 |
}
|
|
381 |
else
|
|
382 |
{
|
|
383 |
new_min=arg->min_value; flag_min=arg->min_flag; /* purecov: deadcode */ |
|
384 |
}
|
|
385 |
if (cmp_max_to_max(arg) <= 0) |
|
386 |
{
|
|
387 |
new_max=max_value; flag_max=max_flag; |
|
388 |
}
|
|
389 |
else
|
|
390 |
{
|
|
391 |
new_max=arg->max_value; flag_max=arg->max_flag; |
|
392 |
}
|
|
393 |
return new SEL_ARG(field, part, new_min, new_max, flag_min, flag_max, |
|
394 |
test(maybe_flag && arg->maybe_flag)); |
|
395 |
}
|
|
396 |
SEL_ARG *clone_first(SEL_ARG *arg) |
|
397 |
{ // min <= X < arg->min |
|
398 |
return new SEL_ARG(field,part, min_value, arg->min_value, |
|
399 |
min_flag, arg->min_flag & NEAR_MIN ? 0 : NEAR_MAX, |
|
400 |
maybe_flag | arg->maybe_flag); |
|
401 |
}
|
|
402 |
SEL_ARG *clone_last(SEL_ARG *arg) |
|
403 |
{ // min <= X <= key_max |
|
404 |
return new SEL_ARG(field, part, min_value, arg->max_value, |
|
405 |
min_flag, arg->max_flag, maybe_flag | arg->maybe_flag); |
|
406 |
}
|
|
407 |
SEL_ARG *clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent, SEL_ARG **next); |
|
408 |
||
409 |
bool copy_min(SEL_ARG* arg) |
|
410 |
{ // Get overlapping range |
|
411 |
if (cmp_min_to_min(arg) > 0) |
|
412 |
{
|
|
413 |
min_value=arg->min_value; min_flag=arg->min_flag; |
|
414 |
if ((max_flag & (NO_MAX_RANGE | NO_MIN_RANGE)) == |
|
415 |
(NO_MAX_RANGE | NO_MIN_RANGE)) |
|
416 |
return 1; // Full range |
|
417 |
}
|
|
418 |
maybe_flag|=arg->maybe_flag; |
|
419 |
return 0; |
|
420 |
}
|
|
421 |
bool copy_max(SEL_ARG* arg) |
|
422 |
{ // Get overlapping range |
|
423 |
if (cmp_max_to_max(arg) <= 0) |
|
424 |
{
|
|
425 |
max_value=arg->max_value; max_flag=arg->max_flag; |
|
426 |
if ((max_flag & (NO_MAX_RANGE | NO_MIN_RANGE)) == |
|
427 |
(NO_MAX_RANGE | NO_MIN_RANGE)) |
|
428 |
return 1; // Full range |
|
429 |
}
|
|
430 |
maybe_flag|=arg->maybe_flag; |
|
431 |
return 0; |
|
432 |
}
|
|
433 |
||
434 |
void copy_min_to_min(SEL_ARG *arg) |
|
435 |
{
|
|
436 |
min_value=arg->min_value; min_flag=arg->min_flag; |
|
437 |
}
|
|
438 |
void copy_min_to_max(SEL_ARG *arg) |
|
439 |
{
|
|
440 |
max_value=arg->min_value; |
|
441 |
max_flag=arg->min_flag & NEAR_MIN ? 0 : NEAR_MAX; |
|
442 |
}
|
|
443 |
void copy_max_to_min(SEL_ARG *arg) |
|
444 |
{
|
|
445 |
min_value=arg->max_value; |
|
446 |
min_flag=arg->max_flag & NEAR_MAX ? 0 : NEAR_MIN; |
|
447 |
}
|
|
448 |
/* returns a number of keypart values (0 or 1) appended to the key buffer */
|
|
482
by Brian Aker
Remove uint. |
449 |
int store_min(uint32_t length, unsigned char **min_key,uint32_t min_key_flag) |
1
by brian
clean slate |
450 |
{
|
451 |
/* "(kp1 > c1) AND (kp2 OP c2) AND ..." -> (kp1 > c1) */
|
|
452 |
if ((!(min_flag & NO_MIN_RANGE) && |
|
453 |
!(min_key_flag & (NO_MIN_RANGE | NEAR_MIN)))) |
|
454 |
{
|
|
455 |
if (maybe_null && *min_value) |
|
456 |
{
|
|
457 |
**min_key=1; |
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
458 |
memset(*min_key+1, 0, length-1); |
1
by brian
clean slate |
459 |
}
|
460 |
else
|
|
461 |
memcpy(*min_key,min_value,length); |
|
462 |
(*min_key)+= length; |
|
463 |
return 1; |
|
464 |
}
|
|
465 |
return 0; |
|
466 |
}
|
|
467 |
/* returns a number of keypart values (0 or 1) appended to the key buffer */
|
|
482
by Brian Aker
Remove uint. |
468 |
int store_max(uint32_t length, unsigned char **max_key, uint32_t max_key_flag) |
1
by brian
clean slate |
469 |
{
|
470 |
if (!(max_flag & NO_MAX_RANGE) && |
|
471 |
!(max_key_flag & (NO_MAX_RANGE | NEAR_MAX))) |
|
472 |
{
|
|
473 |
if (maybe_null && *max_value) |
|
474 |
{
|
|
475 |
**max_key=1; |
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
476 |
memset(*max_key+1, 0, length-1); |
1
by brian
clean slate |
477 |
}
|
478 |
else
|
|
479 |
memcpy(*max_key,max_value,length); |
|
480 |
(*max_key)+= length; |
|
481 |
return 1; |
|
482 |
}
|
|
483 |
return 0; |
|
484 |
}
|
|
485 |
||
486 |
/* returns a number of keypart values appended to the key buffer */
|
|
482
by Brian Aker
Remove uint. |
487 |
int store_min_key(KEY_PART *key, unsigned char **range_key, uint32_t *range_key_flag) |
1
by brian
clean slate |
488 |
{
|
489 |
SEL_ARG *key_tree= first(); |
|
482
by Brian Aker
Remove uint. |
490 |
uint32_t res= key_tree->store_min(key[key_tree->part].store_length, |
1
by brian
clean slate |
491 |
range_key, *range_key_flag); |
492 |
*range_key_flag|= key_tree->min_flag; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
493 |
|
1
by brian
clean slate |
494 |
if (key_tree->next_key_part && |
495 |
key_tree->next_key_part->part == key_tree->part+1 && |
|
496 |
!(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN)) && |
|
497 |
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) |
|
498 |
res+= key_tree->next_key_part->store_min_key(key, range_key, |
|
499 |
range_key_flag); |
|
500 |
return res; |
|
501 |
}
|
|
502 |
||
503 |
/* returns a number of keypart values appended to the key buffer */
|
|
482
by Brian Aker
Remove uint. |
504 |
int store_max_key(KEY_PART *key, unsigned char **range_key, uint32_t *range_key_flag) |
1
by brian
clean slate |
505 |
{
|
506 |
SEL_ARG *key_tree= last(); |
|
482
by Brian Aker
Remove uint. |
507 |
uint32_t res=key_tree->store_max(key[key_tree->part].store_length, |
1
by brian
clean slate |
508 |
range_key, *range_key_flag); |
509 |
(*range_key_flag)|= key_tree->max_flag; |
|
510 |
if (key_tree->next_key_part && |
|
511 |
key_tree->next_key_part->part == key_tree->part+1 && |
|
512 |
!(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX)) && |
|
513 |
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) |
|
514 |
res+= key_tree->next_key_part->store_max_key(key, range_key, |
|
515 |
range_key_flag); |
|
516 |
return res; |
|
517 |
}
|
|
518 |
||
519 |
SEL_ARG *insert(SEL_ARG *key); |
|
520 |
SEL_ARG *tree_delete(SEL_ARG *key); |
|
521 |
SEL_ARG *find_range(SEL_ARG *key); |
|
522 |
SEL_ARG *rb_insert(SEL_ARG *leaf); |
|
523 |
friend SEL_ARG *rb_delete_fixup(SEL_ARG *root,SEL_ARG *key, SEL_ARG *par); |
|
524 |
#ifdef EXTRA_DEBUG
|
|
525 |
friend int test_rb_tree(SEL_ARG *element,SEL_ARG *parent); |
|
526 |
void test_use_count(SEL_ARG *root); |
|
527 |
#endif
|
|
528 |
SEL_ARG *first(); |
|
529 |
SEL_ARG *last(); |
|
530 |
void make_root(); |
|
531 |
inline bool simple_key() |
|
532 |
{
|
|
533 |
return !next_key_part && elements == 1; |
|
534 |
}
|
|
535 |
void increment_use_count(long count) |
|
536 |
{
|
|
537 |
if (next_key_part) |
|
538 |
{
|
|
539 |
next_key_part->use_count+=count; |
|
540 |
count*= (next_key_part->use_count-count); |
|
541 |
for (SEL_ARG *pos=next_key_part->first(); pos ; pos=pos->next) |
|
542 |
if (pos->next_key_part) |
|
543 |
pos->increment_use_count(count); |
|
544 |
}
|
|
545 |
}
|
|
546 |
void free_tree() |
|
547 |
{
|
|
548 |
for (SEL_ARG *pos=first(); pos ; pos=pos->next) |
|
549 |
if (pos->next_key_part) |
|
550 |
{
|
|
551 |
pos->next_key_part->use_count--; |
|
552 |
pos->next_key_part->free_tree(); |
|
553 |
}
|
|
554 |
}
|
|
555 |
||
556 |
inline SEL_ARG **parent_ptr() |
|
557 |
{
|
|
558 |
return parent->left == this ? &parent->left : &parent->right; |
|
559 |
}
|
|
560 |
||
561 |
||
562 |
/*
|
|
563 |
Check if this SEL_ARG object represents a single-point interval
|
|
564 |
||
565 |
SYNOPSIS
|
|
566 |
is_singlepoint()
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
567 |
|
1
by brian
clean slate |
568 |
DESCRIPTION
|
569 |
Check if this SEL_ARG object (not tree) represents a single-point
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
570 |
interval, i.e. if it represents a "keypart = const" or
|
1
by brian
clean slate |
571 |
"keypart IS NULL".
|
572 |
||
573 |
RETURN
|
|
55
by brian
Update for using real bool types. |
574 |
true This SEL_ARG object represents a singlepoint interval
|
575 |
false Otherwise
|
|
1
by brian
clean slate |
576 |
*/
|
577 |
||
578 |
bool is_singlepoint() |
|
579 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
580 |
/*
|
581 |
Check for NEAR_MIN ("strictly less") and NO_MIN_RANGE (-inf < field)
|
|
1
by brian
clean slate |
582 |
flags, and the same for right edge.
|
583 |
*/
|
|
584 |
if (min_flag || max_flag) |
|
55
by brian
Update for using real bool types. |
585 |
return false; |
481
by Brian Aker
Remove all of uchar. |
586 |
unsigned char *min_val= min_value; |
587 |
unsigned char *max_val= max_value; |
|
1
by brian
clean slate |
588 |
|
589 |
if (maybe_null) |
|
590 |
{
|
|
591 |
/* First byte is a NULL value indicator */
|
|
592 |
if (*min_val != *max_val) |
|
55
by brian
Update for using real bool types. |
593 |
return false; |
1
by brian
clean slate |
594 |
|
595 |
if (*min_val) |
|
55
by brian
Update for using real bool types. |
596 |
return true; /* This "x IS NULL" */ |
1
by brian
clean slate |
597 |
min_val++; |
598 |
max_val++; |
|
599 |
}
|
|
600 |
return !field->key_cmp(min_val, max_val); |
|
601 |
}
|
|
602 |
SEL_ARG *clone_tree(RANGE_OPT_PARAM *param); |
|
603 |
};
|
|
604 |
||
605 |
class SEL_IMERGE; |
|
606 |
||
607 |
||
608 |
class SEL_TREE :public Sql_alloc |
|
609 |
{
|
|
610 |
public: |
|
611 |
/*
|
|
612 |
Starting an effort to document this field:
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
613 |
(for some i, keys[i]->type == SEL_ARG::IMPOSSIBLE) =>
|
1
by brian
clean slate |
614 |
(type == SEL_TREE::IMPOSSIBLE)
|
615 |
*/
|
|
616 |
enum Type { IMPOSSIBLE, ALWAYS, MAYBE, KEY, KEY_SMALLER } type; |
|
617 |
SEL_TREE(enum Type type_arg) :type(type_arg) {} |
|
618 |
SEL_TREE() :type(KEY) |
|
619 |
{
|
|
620 |
keys_map.clear_all(); |
|
212.6.6
by Mats Kindahl
Removing redundant use of casts in drizzled/ for memcmp(), memcpy(), memset(), and memmove(). |
621 |
memset(keys, 0, sizeof(keys)); |
1
by brian
clean slate |
622 |
}
|
623 |
/*
|
|
624 |
Note: there may exist SEL_TREE objects with sel_tree->type=KEY and
|
|
625 |
keys[i]=0 for all i. (SergeyP: it is not clear whether there is any
|
|
626 |
merit in range analyzer functions (e.g. get_mm_parts) returning a
|
|
627 |
pointer to such SEL_TREE instead of NULL)
|
|
628 |
*/
|
|
629 |
SEL_ARG *keys[MAX_KEY]; |
|
630 |
key_map keys_map; /* bitmask of non-NULL elements in keys */ |
|
631 |
||
632 |
/*
|
|
633 |
Possible ways to read rows using index_merge. The list is non-empty only
|
|
634 |
if type==KEY. Currently can be non empty only if keys_map.is_clear_all().
|
|
635 |
*/
|
|
636 |
List<SEL_IMERGE> merges; |
|
637 |
||
638 |
/* The members below are filled/used only after get_mm_tree is done */
|
|
639 |
key_map ror_scans_map; /* bitmask of ROR scan-able elements in keys */ |
|
482
by Brian Aker
Remove uint. |
640 |
uint32_t n_ror_scans; /* number of set bits in ror_scans_map */ |
1
by brian
clean slate |
641 |
|
642 |
struct st_ror_scan_info **ror_scans; /* list of ROR key scans */ |
|
643 |
struct st_ror_scan_info **ror_scans_end; /* last ROR scan */ |
|
644 |
/* Note that #records for each key scan is stored in table->quick_rows */
|
|
645 |
};
|
|
646 |
||
647 |
class RANGE_OPT_PARAM |
|
648 |
{
|
|
649 |
public: |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
650 |
Session *session; /* Current thread handle */ |
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
651 |
Table *table; /* Table being analyzed */ |
1
by brian
clean slate |
652 |
COND *cond; /* Used inside get_mm_tree(). */ |
653 |
table_map prev_tables; |
|
654 |
table_map read_tables; |
|
655 |
table_map current_table; /* Bit of the table being analyzed */ |
|
656 |
||
657 |
/* Array of parts of all keys for which range analysis is performed */
|
|
658 |
KEY_PART *key_parts; |
|
659 |
KEY_PART *key_parts_end; |
|
660 |
MEM_ROOT *mem_root; /* Memory that will be freed when range analysis completes */ |
|
661 |
MEM_ROOT *old_root; /* Memory that will last until the query end */ |
|
662 |
/*
|
|
663 |
Number of indexes used in range analysis (In SEL_TREE::keys only first
|
|
664 |
#keys elements are not empty)
|
|
665 |
*/
|
|
482
by Brian Aker
Remove uint. |
666 |
uint32_t keys; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
667 |
|
668 |
/*
|
|
1
by brian
clean slate |
669 |
If true, the index descriptions describe real indexes (and it is ok to
|
670 |
call field->optimize_range(real_keynr[...], ...).
|
|
671 |
Otherwise index description describes fake indexes.
|
|
672 |
*/
|
|
673 |
bool using_real_indexes; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
674 |
|
1
by brian
clean slate |
675 |
bool remove_jump_scans; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
676 |
|
1
by brian
clean slate |
677 |
/*
|
678 |
used_key_no -> table_key_no translation table. Only makes sense if
|
|
55
by brian
Update for using real bool types. |
679 |
using_real_indexes==true
|
1
by brian
clean slate |
680 |
*/
|
482
by Brian Aker
Remove uint. |
681 |
uint32_t real_keynr[MAX_KEY]; |
1
by brian
clean slate |
682 |
/* Number of SEL_ARG objects allocated by SEL_ARG::clone_tree operations */
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
683 |
uint32_t alloced_sel_args; |
1
by brian
clean slate |
684 |
bool force_default_mrr; |
685 |
};
|
|
686 |
||
687 |
class PARAM : public RANGE_OPT_PARAM |
|
688 |
{
|
|
689 |
public: |
|
690 |
KEY_PART *key[MAX_KEY]; /* First key parts of keys used in the query */ |
|
152
by Brian Aker
longlong replacement |
691 |
int64_t baseflag; |
482
by Brian Aker
Remove uint. |
692 |
uint32_t max_key_part; |
1
by brian
clean slate |
693 |
/* Number of ranges in the last checked tree->key */
|
482
by Brian Aker
Remove uint. |
694 |
uint32_t range_count; |
481
by Brian Aker
Remove all of uchar. |
695 |
unsigned char min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH], |
1
by brian
clean slate |
696 |
max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; |
697 |
bool quick; // Don't calulate possible keys |
|
698 |
||
482
by Brian Aker
Remove uint. |
699 |
uint32_t fields_bitmap_size; |
1
by brian
clean slate |
700 |
MY_BITMAP needed_fields; /* bitmask of fields needed by the query */ |
701 |
MY_BITMAP tmp_covered_fields; |
|
702 |
||
703 |
key_map *needed_reg; /* ptr to SQL_SELECT::needed_reg */ |
|
704 |
||
482
by Brian Aker
Remove uint. |
705 |
uint32_t *imerge_cost_buff; /* buffer for index_merge cost estimates */ |
706 |
uint32_t imerge_cost_buff_size; /* size of the buffer */ |
|
1
by brian
clean slate |
707 |
|
55
by brian
Update for using real bool types. |
708 |
/* true if last checked tree->key can be used for ROR-scan */
|
1
by brian
clean slate |
709 |
bool is_ror_scan; |
710 |
/* Number of ranges in the last checked tree->key */
|
|
482
by Brian Aker
Remove uint. |
711 |
uint32_t n_ranges; |
1
by brian
clean slate |
712 |
};
|
713 |
||
714 |
class TABLE_READ_PLAN; |
|
715 |
class TRP_RANGE; |
|
716 |
class TRP_ROR_INTERSECT; |
|
717 |
class TRP_ROR_UNION; |
|
718 |
class TRP_ROR_INDEX_MERGE; |
|
719 |
class TRP_GROUP_MIN_MAX; |
|
720 |
||
721 |
struct st_ror_scan_info; |
|
722 |
||
723 |
static SEL_TREE * get_mm_parts(RANGE_OPT_PARAM *param,COND *cond_func,Field *field, |
|
724 |
Item_func::Functype type,Item *value, |
|
725 |
Item_result cmp_type); |
|
726 |
static SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param,COND *cond_func,Field *field, |
|
727 |
KEY_PART *key_part, |
|
728 |
Item_func::Functype type,Item *value); |
|
729 |
static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond); |
|
730 |
||
482
by Brian Aker
Remove uint. |
731 |
static bool is_key_scan_ror(PARAM *param, uint32_t keynr, uint8_t nparts); |
732 |
static ha_rows check_quick_select(PARAM *param, uint32_t idx, bool index_only, |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
733 |
SEL_ARG *tree, bool update_tbl_stats, |
482
by Brian Aker
Remove uint. |
734 |
uint32_t *mrr_flags, uint32_t *bufsize, |
1
by brian
clean slate |
735 |
COST_VECT *cost); |
736 |
//bool update_tbl_stats);
|
|
482
by Brian Aker
Remove uint. |
737 |
/*static ha_rows check_quick_keys(PARAM *param,uint32_t index,SEL_ARG *key_tree,
|
738 |
unsigned char *min_key, uint32_t min_key_flag, int,
|
|
739 |
unsigned char *max_key, uint32_t max_key_flag, int);
|
|
1
by brian
clean slate |
740 |
*/
|
741 |
||
482
by Brian Aker
Remove uint. |
742 |
QUICK_RANGE_SELECT *get_quick_select(PARAM *param,uint32_t index, |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
743 |
SEL_ARG *key_tree, uint32_t mrr_flags, |
482
by Brian Aker
Remove uint. |
744 |
uint32_t mrr_buf_size, MEM_ROOT *alloc); |
1
by brian
clean slate |
745 |
static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, |
746 |
bool index_read_must_be_used, |
|
747 |
bool update_tbl_stats, |
|
748 |
double read_time); |
|
749 |
static
|
|
750 |
TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree, |
|
751 |
double read_time, |
|
752 |
bool *are_all_covering); |
|
753 |
static
|
|
754 |
TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param, |
|
755 |
SEL_TREE *tree, |
|
756 |
double read_time); |
|
757 |
static
|
|
758 |
TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, |
|
759 |
double read_time); |
|
760 |
static
|
|
761 |
TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree); |
|
762 |
||
763 |
static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map, |
|
764 |
const char *msg); |
|
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
765 |
static void print_ror_scans_arr(Table *table, const char *msg, |
1
by brian
clean slate |
766 |
struct st_ror_scan_info **start, |
767 |
struct st_ror_scan_info **end); |
|
768 |
||
769 |
static SEL_TREE *tree_and(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2); |
|
770 |
static SEL_TREE *tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2); |
|
771 |
static SEL_ARG *sel_add(SEL_ARG *key1,SEL_ARG *key2); |
|
772 |
static SEL_ARG *key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2); |
|
773 |
static SEL_ARG *key_and(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, |
|
482
by Brian Aker
Remove uint. |
774 |
uint32_t clone_flag); |
1
by brian
clean slate |
775 |
static bool get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1); |
776 |
bool get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, |
|
482
by Brian Aker
Remove uint. |
777 |
SEL_ARG *key_tree, unsigned char *min_key,uint32_t min_key_flag, |
778 |
unsigned char *max_key,uint32_t max_key_flag); |
|
1
by brian
clean slate |
779 |
static bool eq_tree(SEL_ARG* a,SEL_ARG *b); |
780 |
||
781 |
static SEL_ARG null_element(SEL_ARG::IMPOSSIBLE); |
|
481
by Brian Aker
Remove all of uchar. |
782 |
static bool null_part_in_key(KEY_PART *key_part, const unsigned char *key, |
482
by Brian Aker
Remove uint. |
783 |
uint32_t length); |
1
by brian
clean slate |
784 |
bool sel_trees_can_be_ored(SEL_TREE *tree1, SEL_TREE *tree2, RANGE_OPT_PARAM* param); |
785 |
||
786 |
||
787 |
/*
|
|
788 |
SEL_IMERGE is a list of possible ways to do index merge, i.e. it is
|
|
789 |
a condition in the following form:
|
|
790 |
(t_1||t_2||...||t_N) && (next)
|
|
791 |
||
792 |
where all t_i are SEL_TREEs, next is another SEL_IMERGE and no pair
|
|
793 |
(t_i,t_j) contains SEL_ARGS for the same index.
|
|
794 |
||
795 |
SEL_TREE contained in SEL_IMERGE always has merges=NULL.
|
|
796 |
||
797 |
This class relies on memory manager to do the cleanup.
|
|
798 |
*/
|
|
799 |
||
800 |
class SEL_IMERGE : public Sql_alloc |
|
801 |
{
|
|
802 |
enum { PREALLOCED_TREES= 10}; |
|
803 |
public: |
|
804 |
SEL_TREE *trees_prealloced[PREALLOCED_TREES]; |
|
805 |
SEL_TREE **trees; /* trees used to do index_merge */ |
|
806 |
SEL_TREE **trees_next; /* last of these trees */ |
|
807 |
SEL_TREE **trees_end; /* end of allocated space */ |
|
808 |
||
809 |
SEL_ARG ***best_keys; /* best keys to read in SEL_TREEs */ |
|
810 |
||
811 |
SEL_IMERGE() : |
|
812 |
trees(&trees_prealloced[0]), |
|
813 |
trees_next(trees), |
|
814 |
trees_end(trees + PREALLOCED_TREES) |
|
815 |
{}
|
|
816 |
int or_sel_tree(RANGE_OPT_PARAM *param, SEL_TREE *tree); |
|
817 |
int or_sel_tree_with_checks(RANGE_OPT_PARAM *param, SEL_TREE *new_tree); |
|
818 |
int or_sel_imerge_with_checks(RANGE_OPT_PARAM *param, SEL_IMERGE* imerge); |
|
819 |
};
|
|
820 |
||
821 |
||
822 |
/*
|
|
823 |
Add SEL_TREE to this index_merge without any checks,
|
|
824 |
||
825 |
NOTES
|
|
826 |
This function implements the following:
|
|
827 |
(x_1||...||x_N) || t = (x_1||...||x_N||t), where x_i, t are SEL_TREEs
|
|
828 |
||
829 |
RETURN
|
|
830 |
0 - OK
|
|
831 |
-1 - Out of memory.
|
|
832 |
*/
|
|
833 |
||
834 |
int SEL_IMERGE::or_sel_tree(RANGE_OPT_PARAM *param, SEL_TREE *tree) |
|
835 |
{
|
|
836 |
if (trees_next == trees_end) |
|
837 |
{
|
|
838 |
const int realloc_ratio= 2; /* Double size for next round */ |
|
482
by Brian Aker
Remove uint. |
839 |
uint32_t old_elements= (trees_end - trees); |
840 |
uint32_t old_size= sizeof(SEL_TREE**) * old_elements; |
|
841 |
uint32_t new_size= old_size * realloc_ratio; |
|
1
by brian
clean slate |
842 |
SEL_TREE **new_trees; |
843 |
if (!(new_trees= (SEL_TREE**)alloc_root(param->mem_root, new_size))) |
|
844 |
return -1; |
|
845 |
memcpy(new_trees, trees, old_size); |
|
846 |
trees= new_trees; |
|
847 |
trees_next= trees + old_elements; |
|
848 |
trees_end= trees + old_elements * realloc_ratio; |
|
849 |
}
|
|
850 |
*(trees_next++)= tree; |
|
851 |
return 0; |
|
852 |
}
|
|
853 |
||
854 |
||
855 |
/*
|
|
856 |
Perform OR operation on this SEL_IMERGE and supplied SEL_TREE new_tree,
|
|
857 |
combining new_tree with one of the trees in this SEL_IMERGE if they both
|
|
858 |
have SEL_ARGs for the same key.
|
|
859 |
||
860 |
SYNOPSIS
|
|
861 |
or_sel_tree_with_checks()
|
|
862 |
param PARAM from SQL_SELECT::test_quick_select
|
|
863 |
new_tree SEL_TREE with type KEY or KEY_SMALLER.
|
|
864 |
||
865 |
NOTES
|
|
866 |
This does the following:
|
|
867 |
(t_1||...||t_k)||new_tree =
|
|
868 |
either
|
|
869 |
= (t_1||...||t_k||new_tree)
|
|
870 |
or
|
|
871 |
= (t_1||....||(t_j|| new_tree)||...||t_k),
|
|
872 |
||
873 |
where t_i, y are SEL_TREEs.
|
|
874 |
new_tree is combined with the first t_j it has a SEL_ARG on common
|
|
875 |
key with. As a consequence of this, choice of keys to do index_merge
|
|
876 |
read may depend on the order of conditions in WHERE part of the query.
|
|
877 |
||
878 |
RETURN
|
|
879 |
0 OK
|
|
880 |
1 One of the trees was combined with new_tree to SEL_TREE::ALWAYS,
|
|
881 |
and (*this) should be discarded.
|
|
882 |
-1 An error occurred.
|
|
883 |
*/
|
|
884 |
||
885 |
int SEL_IMERGE::or_sel_tree_with_checks(RANGE_OPT_PARAM *param, SEL_TREE *new_tree) |
|
886 |
{
|
|
887 |
for (SEL_TREE** tree = trees; |
|
888 |
tree != trees_next; |
|
889 |
tree++) |
|
890 |
{
|
|
891 |
if (sel_trees_can_be_ored(*tree, new_tree, param)) |
|
892 |
{
|
|
893 |
*tree = tree_or(param, *tree, new_tree); |
|
894 |
if (!*tree) |
|
895 |
return 1; |
|
896 |
if (((*tree)->type == SEL_TREE::MAYBE) || |
|
897 |
((*tree)->type == SEL_TREE::ALWAYS)) |
|
898 |
return 1; |
|
899 |
/* SEL_TREE::IMPOSSIBLE is impossible here */
|
|
900 |
return 0; |
|
901 |
}
|
|
902 |
}
|
|
903 |
||
904 |
/* New tree cannot be combined with any of existing trees. */
|
|
905 |
return or_sel_tree(param, new_tree); |
|
906 |
}
|
|
907 |
||
908 |
||
909 |
/*
|
|
910 |
Perform OR operation on this index_merge and supplied index_merge list.
|
|
911 |
||
912 |
RETURN
|
|
913 |
0 - OK
|
|
55
by brian
Update for using real bool types. |
914 |
1 - One of conditions in result is always true and this SEL_IMERGE
|
1
by brian
clean slate |
915 |
should be discarded.
|
916 |
-1 - An error occurred
|
|
917 |
*/
|
|
918 |
||
919 |
int SEL_IMERGE::or_sel_imerge_with_checks(RANGE_OPT_PARAM *param, SEL_IMERGE* imerge) |
|
920 |
{
|
|
921 |
for (SEL_TREE** tree= imerge->trees; |
|
922 |
tree != imerge->trees_next; |
|
923 |
tree++) |
|
924 |
{
|
|
925 |
if (or_sel_tree_with_checks(param, *tree)) |
|
926 |
return 1; |
|
927 |
}
|
|
928 |
return 0; |
|
929 |
}
|
|
930 |
||
931 |
||
932 |
/*
|
|
933 |
Perform AND operation on two index_merge lists and store result in *im1.
|
|
934 |
*/
|
|
935 |
||
936 |
inline void imerge_list_and_list(List<SEL_IMERGE> *im1, List<SEL_IMERGE> *im2) |
|
937 |
{
|
|
938 |
im1->concat(im2); |
|
939 |
}
|
|
940 |
||
941 |
||
942 |
/*
|
|
943 |
Perform OR operation on 2 index_merge lists, storing result in first list.
|
|
944 |
||
945 |
NOTES
|
|
946 |
The following conversion is implemented:
|
|
947 |
(a_1 &&...&& a_N)||(b_1 &&...&& b_K) = AND_i,j(a_i || b_j) =>
|
|
948 |
=> (a_1||b_1).
|
|
949 |
||
950 |
i.e. all conjuncts except the first one are currently dropped.
|
|
951 |
This is done to avoid producing N*K ways to do index_merge.
|
|
952 |
||
55
by brian
Update for using real bool types. |
953 |
If (a_1||b_1) produce a condition that is always true, NULL is returned
|
1
by brian
clean slate |
954 |
and index_merge is discarded (while it is actually possible to try
|
955 |
harder).
|
|
956 |
||
957 |
As a consequence of this, choice of keys to do index_merge read may depend
|
|
958 |
on the order of conditions in WHERE part of the query.
|
|
959 |
||
960 |
RETURN
|
|
961 |
0 OK, result is stored in *im1
|
|
962 |
other Error, both passed lists are unusable
|
|
963 |
*/
|
|
964 |
||
965 |
int imerge_list_or_list(RANGE_OPT_PARAM *param, |
|
966 |
List<SEL_IMERGE> *im1, |
|
967 |
List<SEL_IMERGE> *im2) |
|
968 |
{
|
|
969 |
SEL_IMERGE *imerge= im1->head(); |
|
970 |
im1->empty(); |
|
971 |
im1->push_back(imerge); |
|
972 |
||
973 |
return imerge->or_sel_imerge_with_checks(param, im2->head()); |
|
974 |
}
|
|
975 |
||
976 |
||
977 |
/*
|
|
978 |
Perform OR operation on index_merge list and key tree.
|
|
979 |
||
980 |
RETURN
|
|
981 |
0 OK, result is stored in *im1.
|
|
982 |
other Error
|
|
983 |
*/
|
|
984 |
||
985 |
int imerge_list_or_tree(RANGE_OPT_PARAM *param, |
|
986 |
List<SEL_IMERGE> *im1, |
|
987 |
SEL_TREE *tree) |
|
988 |
{
|
|
989 |
SEL_IMERGE *imerge; |
|
990 |
List_iterator<SEL_IMERGE> it(*im1); |
|
991 |
while ((imerge= it++)) |
|
992 |
{
|
|
993 |
if (imerge->or_sel_tree_with_checks(param, tree)) |
|
994 |
it.remove(); |
|
995 |
}
|
|
996 |
return im1->is_empty(); |
|
997 |
}
|
|
998 |
||
999 |
||
1000 |
/***************************************************************************
|
|
1001 |
** Basic functions for SQL_SELECT and QUICK_RANGE_SELECT
|
|
1002 |
***************************************************************************/
|
|
1003 |
||
1004 |
/* make a select from mysql info
|
|
1005 |
Error is set as following:
|
|
1006 |
0 = ok
|
|
1007 |
1 = Got some error (out of memory?)
|
|
1008 |
*/
|
|
1009 |
||
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
1010 |
SQL_SELECT *make_select(Table *head, table_map const_tables, |
1
by brian
clean slate |
1011 |
table_map read_tables, COND *conds, |
1012 |
bool allow_null_cond, |
|
1013 |
int *error) |
|
1014 |
{
|
|
1015 |
SQL_SELECT *select; |
|
1016 |
||
1017 |
*error=0; |
|
1018 |
||
1019 |
if (!conds && !allow_null_cond) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1020 |
return 0; |
1
by brian
clean slate |
1021 |
if (!(select= new SQL_SELECT)) |
1022 |
{
|
|
1023 |
*error= 1; // out of memory |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1024 |
return 0; /* purecov: inspected */ |
1
by brian
clean slate |
1025 |
}
|
1026 |
select->read_tables=read_tables; |
|
1027 |
select->const_tables=const_tables; |
|
1028 |
select->head=head; |
|
1029 |
select->cond=conds; |
|
1030 |
||
1031 |
if (head->sort.io_cache) |
|
1032 |
{
|
|
1033 |
select->file= *head->sort.io_cache; |
|
1034 |
select->records=(ha_rows) (select->file.end_of_file/ |
|
1035 |
head->file->ref_length); |
|
760.1.3
by Kristian Nielsen
Fix IO_CACHE memory handling, if we allocate with new, we must not |
1036 |
delete head->sort.io_cache; |
1
by brian
clean slate |
1037 |
head->sort.io_cache=0; |
1038 |
}
|
|
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. |
1039 |
return(select); |
1
by brian
clean slate |
1040 |
}
|
1041 |
||
1042 |
||
1043 |
SQL_SELECT::SQL_SELECT() :quick(0),cond(0),free_cond(0) |
|
1044 |
{
|
|
1045 |
quick_keys.clear_all(); needed_reg.clear_all(); |
|
1046 |
my_b_clear(&file); |
|
1047 |
}
|
|
1048 |
||
1049 |
||
1050 |
void SQL_SELECT::cleanup() |
|
1051 |
{
|
|
1052 |
delete quick; |
|
1053 |
quick= 0; |
|
1054 |
if (free_cond) |
|
1055 |
{
|
|
1056 |
free_cond=0; |
|
1057 |
delete cond; |
|
1058 |
cond= 0; |
|
1059 |
}
|
|
1060 |
close_cached_file(&file); |
|
1061 |
}
|
|
1062 |
||
1063 |
||
1064 |
SQL_SELECT::~SQL_SELECT() |
|
1065 |
{
|
|
1066 |
cleanup(); |
|
1067 |
}
|
|
1068 |
||
584.1.15
by Monty Taylor
The mega-patch from hell. Renamed sql_class to session (since that's what it is) and removed it and field and table from common_includes. |
1069 |
|
1070 |
bool SQL_SELECT::check_quick(Session *session, bool force_quick_range, |
|
1071 |
ha_rows limit) |
|
1072 |
{
|
|
1073 |
key_map tmp; |
|
1074 |
tmp.set_all(); |
|
1075 |
return test_quick_select(session, tmp, 0, limit, |
|
1076 |
force_quick_range, false) < 0; |
|
1077 |
}
|
|
1078 |
||
1079 |
||
1080 |
bool SQL_SELECT::skip_record() |
|
1081 |
{
|
|
1082 |
return cond ? cond->val_int() == 0 : 0; |
|
1083 |
}
|
|
1084 |
||
1085 |
||
1
by brian
clean slate |
1086 |
QUICK_SELECT_I::QUICK_SELECT_I() |
1087 |
:max_used_key_length(0), |
|
1088 |
used_key_parts(0) |
|
1089 |
{}
|
|
1090 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
1091 |
QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(Session *session, Table *table, uint32_t key_nr, |
1
by brian
clean slate |
1092 |
bool no_alloc, MEM_ROOT *parent_alloc, |
1093 |
bool *create_error) |
|
1094 |
:free_file(0),cur_range(NULL),last_range(0),dont_free(0) |
|
1095 |
{
|
|
1096 |
my_bitmap_map *bitmap; |
|
1097 |
||
1098 |
in_ror_merged_scan= 0; |
|
1099 |
sorted= 0; |
|
1100 |
index= key_nr; |
|
1101 |
head= table; |
|
1102 |
key_part_info= head->key_info[index].key_part; |
|
1103 |
my_init_dynamic_array(&ranges, sizeof(QUICK_RANGE*), 16, 16); |
|
1104 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
1105 |
/* 'session' is not accessible in QUICK_RANGE_SELECT::reset(). */
|
1106 |
mrr_buf_size= session->variables.read_rnd_buff_size; |
|
1
by brian
clean slate |
1107 |
mrr_buf_desc= NULL; |
1108 |
||
1109 |
if (!no_alloc && !parent_alloc) |
|
1110 |
{
|
|
1111 |
// Allocates everything through the internal memroot
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
1112 |
init_sql_alloc(&alloc, session->variables.range_alloc_block_size, 0); |
1113 |
session->mem_root= &alloc; |
|
1
by brian
clean slate |
1114 |
}
|
1115 |
else
|
|
212.6.6
by Mats Kindahl
Removing redundant use of casts in drizzled/ for memcmp(), memcpy(), memset(), and memmove(). |
1116 |
memset(&alloc, 0, sizeof(alloc)); |
1
by brian
clean slate |
1117 |
file= head->file; |
1118 |
record= head->record[0]; |
|
1119 |
save_read_set= head->read_set; |
|
1120 |
save_write_set= head->write_set; |
|
1121 |
||
1122 |
/* Allocate a bitmap for used columns (Q: why not on MEM_ROOT?) */
|
|
641.3.8
by Monty Taylor
Removed my_malloc from drizzled. |
1123 |
if (!(bitmap= (my_bitmap_map*) malloc(head->s->column_bitmap_size))) |
1
by brian
clean slate |
1124 |
{
|
1125 |
column_bitmap.bitmap= 0; |
|
1126 |
*create_error= 1; |
|
1127 |
}
|
|
1128 |
else
|
|
55
by brian
Update for using real bool types. |
1129 |
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. |
1130 |
return; |
1
by brian
clean slate |
1131 |
}
|
1132 |
||
1133 |
||
1134 |
int QUICK_RANGE_SELECT::init() |
|
1135 |
{
|
|
1136 |
if (file->inited != handler::NONE) |
|
1137 |
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. |
1138 |
return(file->ha_index_init(index, 1)); |
1
by brian
clean slate |
1139 |
}
|
1140 |
||
1141 |
||
1142 |
void QUICK_RANGE_SELECT::range_end() |
|
1143 |
{
|
|
1144 |
if (file->inited != handler::NONE) |
|
1145 |
file->ha_index_or_rnd_end(); |
|
1146 |
}
|
|
1147 |
||
1148 |
||
1149 |
QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() |
|
1150 |
{
|
|
1151 |
if (!dont_free) |
|
1152 |
{
|
|
1153 |
/* file is NULL for CPK scan on covering ROR-intersection */
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1154 |
if (file) |
1
by brian
clean slate |
1155 |
{
|
1156 |
range_end(); |
|
1157 |
if (head->key_read) |
|
1158 |
{
|
|
1159 |
head->key_read= 0; |
|
1160 |
file->extra(HA_EXTRA_NO_KEYREAD); |
|
1161 |
}
|
|
1162 |
if (free_file) |
|
1163 |
{
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
1164 |
file->ha_external_lock(current_session, F_UNLCK); |
1
by brian
clean slate |
1165 |
file->close(); |
1166 |
delete file; |
|
1167 |
}
|
|
1168 |
}
|
|
1169 |
delete_dynamic(&ranges); /* ranges are allocated in alloc */ |
|
1170 |
free_root(&alloc,MYF(0)); |
|
477
by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that. |
1171 |
free((char*) column_bitmap.bitmap); |
1
by brian
clean slate |
1172 |
}
|
1173 |
head->column_bitmaps_set(save_read_set, save_write_set); |
|
460
by Monty Taylor
Removed x_free calls. |
1174 |
if (mrr_buf_desc) |
1175 |
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. |
1176 |
return; |
1
by brian
clean slate |
1177 |
}
|
1178 |
||
1179 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
1180 |
QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT(Session *session_param, |
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
1181 |
Table *table) |
520.1.22
by Brian Aker
Second pass of thd cleanup |
1182 |
:pk_quick_select(NULL), session(session_param) |
1
by brian
clean slate |
1183 |
{
|
1184 |
index= MAX_KEY; |
|
1185 |
head= table; |
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
1186 |
memset(&read_record, 0, sizeof(read_record)); |
520.1.22
by Brian Aker
Second pass of thd cleanup |
1187 |
init_sql_alloc(&alloc, session->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. |
1188 |
return; |
1
by brian
clean slate |
1189 |
}
|
1190 |
||
1191 |
int QUICK_INDEX_MERGE_SELECT::init() |
|
1192 |
{
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1193 |
return 0; |
1
by brian
clean slate |
1194 |
}
|
1195 |
||
1196 |
int QUICK_INDEX_MERGE_SELECT::reset() |
|
1197 |
{
|
|
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. |
1198 |
return(read_keys_and_merge()); |
1
by brian
clean slate |
1199 |
}
|
1200 |
||
1201 |
bool
|
|
1202 |
QUICK_INDEX_MERGE_SELECT::push_quick_back(QUICK_RANGE_SELECT *quick_sel_range) |
|
1203 |
{
|
|
1204 |
/*
|
|
1205 |
Save quick_select that does scan on clustered primary key as it will be
|
|
1206 |
processed separately.
|
|
1207 |
*/
|
|
1208 |
if (head->file->primary_key_is_clustered() && |
|
1209 |
quick_sel_range->index == head->s->primary_key) |
|
1210 |
pk_quick_select= quick_sel_range; |
|
1211 |
else
|
|
1212 |
return quick_selects.push_back(quick_sel_range); |
|
1213 |
return 0; |
|
1214 |
}
|
|
1215 |
||
1216 |
QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT() |
|
1217 |
{
|
|
1218 |
List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects); |
|
1219 |
QUICK_RANGE_SELECT* quick; |
|
1220 |
quick_it.rewind(); |
|
1221 |
while ((quick= quick_it++)) |
|
1222 |
quick->file= NULL; |
|
1223 |
quick_selects.delete_elements(); |
|
1224 |
delete pk_quick_select; |
|
1225 |
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. |
1226 |
return; |
1
by brian
clean slate |
1227 |
}
|
1228 |
||
1229 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
1230 |
QUICK_ROR_INTERSECT_SELECT::QUICK_ROR_INTERSECT_SELECT(Session *session_param, |
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
1231 |
Table *table, |
1
by brian
clean slate |
1232 |
bool retrieve_full_rows, |
1233 |
MEM_ROOT *parent_alloc) |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
1234 |
: cpk_quick(NULL), session(session_param), need_to_fetch_row(retrieve_full_rows), |
55
by brian
Update for using real bool types. |
1235 |
scans_inited(false) |
1
by brian
clean slate |
1236 |
{
|
1237 |
index= MAX_KEY; |
|
1238 |
head= table; |
|
1239 |
record= head->record[0]; |
|
1240 |
if (!parent_alloc) |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
1241 |
init_sql_alloc(&alloc, session->variables.range_alloc_block_size, 0); |
1
by brian
clean slate |
1242 |
else
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
1243 |
memset(&alloc, 0, sizeof(MEM_ROOT)); |
481
by Brian Aker
Remove all of uchar. |
1244 |
last_rowid= (unsigned char*) alloc_root(parent_alloc? parent_alloc : &alloc, |
1
by brian
clean slate |
1245 |
head->file->ref_length); |
1246 |
}
|
|
1247 |
||
1248 |
||
1249 |
/*
|
|
1250 |
Do post-constructor initialization.
|
|
1251 |
SYNOPSIS
|
|
1252 |
QUICK_ROR_INTERSECT_SELECT::init()
|
|
1253 |
||
1254 |
RETURN
|
|
1255 |
0 OK
|
|
1256 |
other Error code
|
|
1257 |
*/
|
|
1258 |
||
1259 |
int QUICK_ROR_INTERSECT_SELECT::init() |
|
1260 |
{
|
|
1261 |
/* 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. |
1262 |
return(!last_rowid); |
1
by brian
clean slate |
1263 |
}
|
1264 |
||
1265 |
||
1266 |
/*
|
|
1267 |
Initialize this quick select to be a ROR-merged scan.
|
|
1268 |
||
1269 |
SYNOPSIS
|
|
1270 |
QUICK_RANGE_SELECT::init_ror_merged_scan()
|
|
55
by brian
Update for using real bool types. |
1271 |
reuse_handler If true, use head->file, otherwise create a separate
|
1
by brian
clean slate |
1272 |
handler object
|
1273 |
||
1274 |
NOTES
|
|
1275 |
This function creates and prepares for subsequent use a separate handler
|
|
1276 |
object if it can't reuse head->file. The reason for this is that during
|
|
1277 |
ROR-merge several key scans are performed simultaneously, and a single
|
|
1278 |
handler is only capable of preserving context of a single key scan.
|
|
1279 |
||
1280 |
In ROR-merge the quick select doing merge does full records retrieval,
|
|
1281 |
merged quick selects read only keys.
|
|
1282 |
||
1283 |
RETURN
|
|
1284 |
0 ROR child scan initialized, ok to use.
|
|
1285 |
1 error
|
|
1286 |
*/
|
|
1287 |
||
1288 |
int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) |
|
1289 |
{
|
|
1290 |
handler *save_file= file, *org_file; |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
1291 |
Session *session; |
1
by brian
clean slate |
1292 |
|
1293 |
in_ror_merged_scan= 1; |
|
1294 |
if (reuse_handler) |
|
1295 |
{
|
|
1296 |
if (init() || reset()) |
|
1297 |
{
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1298 |
return 0; |
1
by brian
clean slate |
1299 |
}
|
1300 |
head->column_bitmaps_set(&column_bitmap, &column_bitmap); |
|
1301 |
goto end; |
|
1302 |
}
|
|
1303 |
||
1304 |
/* Create a separate handler object for this quick select */
|
|
1305 |
if (free_file) |
|
1306 |
{
|
|
1307 |
/* already have own 'handler' object. */
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1308 |
return 0; |
1
by brian
clean slate |
1309 |
}
|
1310 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
1311 |
session= head->in_use; |
1312 |
if (!(file= head->file->clone(session->mem_root))) |
|
1
by brian
clean slate |
1313 |
{
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1314 |
/*
|
1
by brian
clean slate |
1315 |
Manually set the error flag. Note: there seems to be quite a few
|
1316 |
places where a failure could cause the server to "hang" the client by
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1317 |
sending no response to a query. ATM those are not real errors because
|
1318 |
the storage engine calls in question happen to never fail with the
|
|
1319 |
existing storage engines.
|
|
1
by brian
clean slate |
1320 |
*/
|
1321 |
my_error(ER_OUT_OF_RESOURCES, MYF(0)); /* purecov: inspected */ |
|
1322 |
/* Caller will free the memory */
|
|
1323 |
goto failure; /* purecov: inspected */ |
|
1324 |
}
|
|
1325 |
||
1326 |
head->column_bitmaps_set(&column_bitmap, &column_bitmap); |
|
1327 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
1328 |
if (file->ha_external_lock(session, F_RDLCK)) |
1
by brian
clean slate |
1329 |
goto failure; |
1330 |
||
1331 |
if (init() || reset()) |
|
1332 |
{
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
1333 |
file->ha_external_lock(session, F_UNLCK); |
1
by brian
clean slate |
1334 |
file->close(); |
1335 |
goto failure; |
|
1336 |
}
|
|
55
by brian
Update for using real bool types. |
1337 |
free_file= true; |
1
by brian
clean slate |
1338 |
last_rowid= file->ref; |
1339 |
||
1340 |
end: |
|
1341 |
/*
|
|
1342 |
We are only going to read key fields and call position() on 'file'
|
|
1343 |
The following sets head->tmp_set to only use this key and then updates
|
|
1344 |
head->read_set and head->write_set to use this bitmap.
|
|
1345 |
The now bitmap is stored in 'column_bitmap' which is used in ::get_next()
|
|
1346 |
*/
|
|
1347 |
org_file= head->file; |
|
1348 |
head->file= file; |
|
1349 |
/* We don't have to set 'head->keyread' here as the 'file' is unique */
|
|
1350 |
if (!head->no_keyread) |
|
1351 |
{
|
|
1352 |
head->key_read= 1; |
|
1353 |
head->mark_columns_used_by_index(index); |
|
1354 |
}
|
|
1355 |
head->prepare_for_position(); |
|
1356 |
head->file= org_file; |
|
1357 |
bitmap_copy(&column_bitmap, head->read_set); |
|
1358 |
head->column_bitmaps_set(&column_bitmap, &column_bitmap); |
|
1359 |
||
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1360 |
return 0; |
1
by brian
clean slate |
1361 |
|
1362 |
failure: |
|
1363 |
head->column_bitmaps_set(save_read_set, save_write_set); |
|
1364 |
delete file; |
|
1365 |
file= save_file; |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1366 |
return 0; |
1
by brian
clean slate |
1367 |
}
|
1368 |
||
1369 |
||
584.1.15
by Monty Taylor
The mega-patch from hell. Renamed sql_class to session (since that's what it is) and removed it and field and table from common_includes. |
1370 |
void QUICK_RANGE_SELECT::save_last_pos() |
1371 |
{
|
|
1372 |
file->position(record); |
|
1373 |
}
|
|
1374 |
||
1375 |
||
1
by brian
clean slate |
1376 |
/*
|
1377 |
Initialize this quick select to be a part of a ROR-merged scan.
|
|
1378 |
SYNOPSIS
|
|
1379 |
QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan()
|
|
55
by brian
Update for using real bool types. |
1380 |
reuse_handler If true, use head->file, otherwise create separate
|
1
by brian
clean slate |
1381 |
handler object.
|
1382 |
RETURN
|
|
1383 |
0 OK
|
|
1384 |
other error code
|
|
1385 |
*/
|
|
1386 |
int QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan(bool reuse_handler) |
|
1387 |
{
|
|
1388 |
List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects); |
|
1389 |
QUICK_RANGE_SELECT* quick; |
|
1390 |
||
1391 |
/* 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. |
1392 |
assert(!need_to_fetch_row || reuse_handler); |
1
by brian
clean slate |
1393 |
if (!need_to_fetch_row && reuse_handler) |
1394 |
{
|
|
1395 |
quick= quick_it++; |
|
1396 |
/*
|
|
1397 |
There is no use of this->file. Use it for the first of merged range
|
|
1398 |
selects.
|
|
1399 |
*/
|
|
55
by brian
Update for using real bool types. |
1400 |
if (quick->init_ror_merged_scan(true)) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1401 |
return 0; |
1
by brian
clean slate |
1402 |
quick->file->extra(HA_EXTRA_KEYREAD_PRESERVE_FIELDS); |
1403 |
}
|
|
1404 |
while ((quick= quick_it++)) |
|
1405 |
{
|
|
55
by brian
Update for using real bool types. |
1406 |
if (quick->init_ror_merged_scan(false)) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1407 |
return 0; |
1
by brian
clean slate |
1408 |
quick->file->extra(HA_EXTRA_KEYREAD_PRESERVE_FIELDS); |
1409 |
/* All merged scans share the same record buffer in intersection. */
|
|
1410 |
quick->record= head->record[0]; |
|
1411 |
}
|
|
1412 |
||
1413 |
if (need_to_fetch_row && head->file->ha_rnd_init(1)) |
|
1414 |
{
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1415 |
return 0; |
1
by brian
clean slate |
1416 |
}
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1417 |
return 0; |
1
by brian
clean slate |
1418 |
}
|
1419 |
||
1420 |
||
1421 |
/*
|
|
1422 |
Initialize quick select for row retrieval.
|
|
1423 |
SYNOPSIS
|
|
1424 |
reset()
|
|
1425 |
RETURN
|
|
1426 |
0 OK
|
|
1427 |
other Error code
|
|
1428 |
*/
|
|
1429 |
||
1430 |
int QUICK_ROR_INTERSECT_SELECT::reset() |
|
1431 |
{
|
|
55
by brian
Update for using real bool types. |
1432 |
if (!scans_inited && init_ror_merged_scan(true)) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1433 |
return 0; |
55
by brian
Update for using real bool types. |
1434 |
scans_inited= true; |
1
by brian
clean slate |
1435 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
1436 |
QUICK_RANGE_SELECT *quick; |
|
1437 |
while ((quick= it++)) |
|
1438 |
quick->reset(); |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1439 |
return 0; |
1
by brian
clean slate |
1440 |
}
|
1441 |
||
1442 |
||
1443 |
/*
|
|
1444 |
Add a merged quick select to this ROR-intersection quick select.
|
|
1445 |
||
1446 |
SYNOPSIS
|
|
1447 |
QUICK_ROR_INTERSECT_SELECT::push_quick_back()
|
|
1448 |
quick Quick select to be added. The quick select must return
|
|
1449 |
rows in rowid order.
|
|
1450 |
NOTES
|
|
1451 |
This call can only be made before init() is called.
|
|
1452 |
||
1453 |
RETURN
|
|
55
by brian
Update for using real bool types. |
1454 |
false OK
|
1455 |
true Out of memory.
|
|
1
by brian
clean slate |
1456 |
*/
|
1457 |
||
1458 |
bool
|
|
1459 |
QUICK_ROR_INTERSECT_SELECT::push_quick_back(QUICK_RANGE_SELECT *quick) |
|
1460 |
{
|
|
1461 |
return quick_selects.push_back(quick); |
|
1462 |
}
|
|
1463 |
||
1464 |
QUICK_ROR_INTERSECT_SELECT::~QUICK_ROR_INTERSECT_SELECT() |
|
1465 |
{
|
|
1466 |
quick_selects.delete_elements(); |
|
1467 |
delete cpk_quick; |
|
1468 |
free_root(&alloc,MYF(0)); |
|
1469 |
if (need_to_fetch_row && head->file->inited != handler::NONE) |
|
1470 |
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. |
1471 |
return; |
1
by brian
clean slate |
1472 |
}
|
1473 |
||
1474 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
1475 |
QUICK_ROR_UNION_SELECT::QUICK_ROR_UNION_SELECT(Session *session_param, |
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
1476 |
Table *table) |
520.1.22
by Brian Aker
Second pass of thd cleanup |
1477 |
: session(session_param), scans_inited(false) |
1
by brian
clean slate |
1478 |
{
|
1479 |
index= MAX_KEY; |
|
1480 |
head= table; |
|
1481 |
rowid_length= table->file->ref_length; |
|
1482 |
record= head->record[0]; |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
1483 |
init_sql_alloc(&alloc, session->variables.range_alloc_block_size, 0); |
1484 |
session_param->mem_root= &alloc; |
|
1
by brian
clean slate |
1485 |
}
|
1486 |
||
1487 |
||
1488 |
/*
|
|
1489 |
Do post-constructor initialization.
|
|
1490 |
SYNOPSIS
|
|
1491 |
QUICK_ROR_UNION_SELECT::init()
|
|
1492 |
||
1493 |
RETURN
|
|
1494 |
0 OK
|
|
1495 |
other Error code
|
|
1496 |
*/
|
|
1497 |
||
1498 |
int QUICK_ROR_UNION_SELECT::init() |
|
1499 |
{
|
|
1500 |
if (init_queue(&queue, quick_selects.elements, 0, |
|
892.1.2
by Monty Taylor
Fixed solaris warnings. |
1501 |
false, quick_ror_union_select_queue_cmp, |
1
by brian
clean slate |
1502 |
(void*) this)) |
1503 |
{
|
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
1504 |
memset(&queue, 0, sizeof(QUEUE)); |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1505 |
return 0; |
1
by brian
clean slate |
1506 |
}
|
1507 |
||
481
by Brian Aker
Remove all of uchar. |
1508 |
if (!(cur_rowid= (unsigned char*) alloc_root(&alloc, 2*head->file->ref_length))) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1509 |
return 0; |
1
by brian
clean slate |
1510 |
prev_rowid= cur_rowid + head->file->ref_length; |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1511 |
return 0; |
1
by brian
clean slate |
1512 |
}
|
1513 |
||
1514 |
||
1515 |
/*
|
|
1516 |
Comparison function to be used QUICK_ROR_UNION_SELECT::queue priority
|
|
1517 |
queue.
|
|
1518 |
||
1519 |
SYNPOSIS
|
|
1520 |
QUICK_ROR_UNION_SELECT::queue_cmp()
|
|
1521 |
arg Pointer to QUICK_ROR_UNION_SELECT
|
|
1522 |
val1 First merged select
|
|
1523 |
val2 Second merged select
|
|
1524 |
*/
|
|
1525 |
||
892.1.2
by Monty Taylor
Fixed solaris warnings. |
1526 |
int quick_ror_union_select_queue_cmp(void *arg, unsigned char *val1, unsigned char *val2) |
1
by brian
clean slate |
1527 |
{
|
1528 |
QUICK_ROR_UNION_SELECT *self= (QUICK_ROR_UNION_SELECT*)arg; |
|
1529 |
return self->head->file->cmp_ref(((QUICK_SELECT_I*)val1)->last_rowid, |
|
1530 |
((QUICK_SELECT_I*)val2)->last_rowid); |
|
1531 |
}
|
|
1532 |
||
1533 |
||
1534 |
/*
|
|
1535 |
Initialize quick select for row retrieval.
|
|
1536 |
SYNOPSIS
|
|
1537 |
reset()
|
|
1538 |
||
1539 |
RETURN
|
|
1540 |
0 OK
|
|
1541 |
other Error code
|
|
1542 |
*/
|
|
1543 |
||
1544 |
int QUICK_ROR_UNION_SELECT::reset() |
|
1545 |
{
|
|
1546 |
QUICK_SELECT_I *quick; |
|
1547 |
int error; |
|
55
by brian
Update for using real bool types. |
1548 |
have_prev_rowid= false; |
1
by brian
clean slate |
1549 |
if (!scans_inited) |
1550 |
{
|
|
1551 |
List_iterator_fast<QUICK_SELECT_I> it(quick_selects); |
|
1552 |
while ((quick= it++)) |
|
1553 |
{
|
|
55
by brian
Update for using real bool types. |
1554 |
if (quick->init_ror_merged_scan(false)) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1555 |
return 0; |
1
by brian
clean slate |
1556 |
}
|
55
by brian
Update for using real bool types. |
1557 |
scans_inited= true; |
1
by brian
clean slate |
1558 |
}
|
1559 |
queue_remove_all(&queue); |
|
1560 |
/*
|
|
1561 |
Initialize scans for merged quick selects and put all merged quick
|
|
1562 |
selects into the queue.
|
|
1563 |
*/
|
|
1564 |
List_iterator_fast<QUICK_SELECT_I> it(quick_selects); |
|
1565 |
while ((quick= it++)) |
|
1566 |
{
|
|
1567 |
if (quick->reset()) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1568 |
return 0; |
1
by brian
clean slate |
1569 |
if ((error= quick->get_next())) |
1570 |
{
|
|
1571 |
if (error == HA_ERR_END_OF_FILE) |
|
1572 |
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. |
1573 |
return(error); |
1
by brian
clean slate |
1574 |
}
|
1575 |
quick->save_last_pos(); |
|
481
by Brian Aker
Remove all of uchar. |
1576 |
queue_insert(&queue, (unsigned char*)quick); |
1
by brian
clean slate |
1577 |
}
|
1578 |
||
1579 |
if (head->file->ha_rnd_init(1)) |
|
1580 |
{
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1581 |
return 0; |
1
by brian
clean slate |
1582 |
}
|
1583 |
||
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1584 |
return 0; |
1
by brian
clean slate |
1585 |
}
|
1586 |
||
1587 |
||
1588 |
bool
|
|
1589 |
QUICK_ROR_UNION_SELECT::push_quick_back(QUICK_SELECT_I *quick_sel_range) |
|
1590 |
{
|
|
1591 |
return quick_selects.push_back(quick_sel_range); |
|
1592 |
}
|
|
1593 |
||
1594 |
QUICK_ROR_UNION_SELECT::~QUICK_ROR_UNION_SELECT() |
|
1595 |
{
|
|
1596 |
delete_queue(&queue); |
|
1597 |
quick_selects.delete_elements(); |
|
1598 |
if (head->file->inited != handler::NONE) |
|
1599 |
head->file->ha_rnd_end(); |
|
1600 |
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. |
1601 |
return; |
1
by brian
clean slate |
1602 |
}
|
1603 |
||
1604 |
||
1605 |
QUICK_RANGE::QUICK_RANGE() |
|
1606 |
:min_key(0),max_key(0),min_length(0),max_length(0), |
|
1607 |
flag(NO_MIN_RANGE | NO_MAX_RANGE), |
|
1608 |
min_keypart_map(0), max_keypart_map(0) |
|
1609 |
{}
|
|
1610 |
||
1611 |
SEL_ARG::SEL_ARG(SEL_ARG &arg) :Sql_alloc() |
|
1612 |
{
|
|
1613 |
type=arg.type; |
|
1614 |
min_flag=arg.min_flag; |
|
1615 |
max_flag=arg.max_flag; |
|
1616 |
maybe_flag=arg.maybe_flag; |
|
1617 |
maybe_null=arg.maybe_null; |
|
1618 |
part=arg.part; |
|
1619 |
field=arg.field; |
|
1620 |
min_value=arg.min_value; |
|
1621 |
max_value=arg.max_value; |
|
1622 |
next_key_part=arg.next_key_part; |
|
1623 |
use_count=1; elements=1; |
|
1624 |
}
|
|
1625 |
||
1626 |
||
1627 |
inline void SEL_ARG::make_root() |
|
1628 |
{
|
|
1629 |
left=right= &null_element; |
|
1630 |
color=BLACK; |
|
1631 |
next=prev=0; |
|
1632 |
use_count=0; elements=1; |
|
1633 |
}
|
|
1634 |
||
481
by Brian Aker
Remove all of uchar. |
1635 |
SEL_ARG::SEL_ARG(Field *f,const unsigned char *min_value_arg, |
1636 |
const unsigned char *max_value_arg) |
|
1
by brian
clean slate |
1637 |
:min_flag(0), max_flag(0), maybe_flag(0), maybe_null(f->real_maybe_null()), |
481
by Brian Aker
Remove all of uchar. |
1638 |
elements(1), use_count(1), field(f), min_value((unsigned char*) min_value_arg), |
1639 |
max_value((unsigned char*) max_value_arg), next(0),prev(0), |
|
1
by brian
clean slate |
1640 |
next_key_part(0),color(BLACK),type(KEY_RANGE) |
1641 |
{
|
|
1642 |
left=right= &null_element; |
|
1643 |
}
|
|
1644 |
||
206
by Brian Aker
Removed final uint dead types. |
1645 |
SEL_ARG::SEL_ARG(Field *field_,uint8_t part_, |
481
by Brian Aker
Remove all of uchar. |
1646 |
unsigned char *min_value_, unsigned char *max_value_, |
206
by Brian Aker
Removed final uint dead types. |
1647 |
uint8_t min_flag_,uint8_t max_flag_,uint8_t maybe_flag_) |
1
by brian
clean slate |
1648 |
:min_flag(min_flag_),max_flag(max_flag_),maybe_flag(maybe_flag_), |
1649 |
part(part_),maybe_null(field_->real_maybe_null()), elements(1),use_count(1), |
|
1650 |
field(field_), min_value(min_value_), max_value(max_value_), |
|
1651 |
next(0),prev(0),next_key_part(0),color(BLACK),type(KEY_RANGE) |
|
1652 |
{
|
|
1653 |
left=right= &null_element; |
|
1654 |
}
|
|
1655 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1656 |
SEL_ARG *SEL_ARG::clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent, |
1
by brian
clean slate |
1657 |
SEL_ARG **next_arg) |
1658 |
{
|
|
1659 |
SEL_ARG *tmp; |
|
1660 |
||
1661 |
/* Bail out if we have already generated too many SEL_ARGs */
|
|
1662 |
if (++param->alloced_sel_args > MAX_SEL_ARGS) |
|
1663 |
return 0; |
|
1664 |
||
1665 |
if (type != KEY_RANGE) |
|
1666 |
{
|
|
1667 |
if (!(tmp= new (param->mem_root) SEL_ARG(type))) |
|
1668 |
return 0; // out of memory |
|
1669 |
tmp->prev= *next_arg; // Link into next/prev chain |
|
1670 |
(*next_arg)->next=tmp; |
|
1671 |
(*next_arg)= tmp; |
|
1672 |
}
|
|
1673 |
else
|
|
1674 |
{
|
|
1675 |
if (!(tmp= new (param->mem_root) SEL_ARG(field,part, min_value,max_value, |
|
1676 |
min_flag, max_flag, maybe_flag))) |
|
1677 |
return 0; // OOM |
|
1678 |
tmp->parent=new_parent; |
|
1679 |
tmp->next_key_part=next_key_part; |
|
1680 |
if (left != &null_element) |
|
1681 |
if (!(tmp->left=left->clone(param, tmp, next_arg))) |
|
1682 |
return 0; // OOM |
|
1683 |
||
1684 |
tmp->prev= *next_arg; // Link into next/prev chain |
|
1685 |
(*next_arg)->next=tmp; |
|
1686 |
(*next_arg)= tmp; |
|
1687 |
||
1688 |
if (right != &null_element) |
|
1689 |
if (!(tmp->right= right->clone(param, tmp, next_arg))) |
|
1690 |
return 0; // OOM |
|
1691 |
}
|
|
1692 |
increment_use_count(1); |
|
1693 |
tmp->color= color; |
|
1694 |
tmp->elements= this->elements; |
|
1695 |
return tmp; |
|
1696 |
}
|
|
1697 |
||
1698 |
SEL_ARG *SEL_ARG::first() |
|
1699 |
{
|
|
1700 |
SEL_ARG *next_arg=this; |
|
1701 |
if (!next_arg->left) |
|
1702 |
return 0; // MAYBE_KEY |
|
1703 |
while (next_arg->left != &null_element) |
|
1704 |
next_arg=next_arg->left; |
|
1705 |
return next_arg; |
|
1706 |
}
|
|
1707 |
||
1708 |
SEL_ARG *SEL_ARG::last() |
|
1709 |
{
|
|
1710 |
SEL_ARG *next_arg=this; |
|
1711 |
if (!next_arg->right) |
|
1712 |
return 0; // MAYBE_KEY |
|
1713 |
while (next_arg->right != &null_element) |
|
1714 |
next_arg=next_arg->right; |
|
1715 |
return next_arg; |
|
1716 |
}
|
|
1717 |
||
1718 |
||
1719 |
/*
|
|
1720 |
Check if a compare is ok, when one takes ranges in account
|
|
1721 |
Returns -2 or 2 if the ranges where 'joined' like < 2 and >= 2
|
|
1722 |
*/
|
|
1723 |
||
481
by Brian Aker
Remove all of uchar. |
1724 |
static int sel_cmp(Field *field, unsigned char *a, unsigned char *b, uint8_t a_flag, |
206
by Brian Aker
Removed final uint dead types. |
1725 |
uint8_t b_flag) |
1
by brian
clean slate |
1726 |
{
|
1727 |
int cmp; |
|
1728 |
/* First check if there was a compare to a min or max element */
|
|
1729 |
if (a_flag & (NO_MIN_RANGE | NO_MAX_RANGE)) |
|
1730 |
{
|
|
1731 |
if ((a_flag & (NO_MIN_RANGE | NO_MAX_RANGE)) == |
|
1732 |
(b_flag & (NO_MIN_RANGE | NO_MAX_RANGE))) |
|
1733 |
return 0; |
|
1734 |
return (a_flag & NO_MIN_RANGE) ? -1 : 1; |
|
1735 |
}
|
|
1736 |
if (b_flag & (NO_MIN_RANGE | NO_MAX_RANGE)) |
|
1737 |
return (b_flag & NO_MIN_RANGE) ? 1 : -1; |
|
1738 |
||
1739 |
if (field->real_maybe_null()) // If null is part of key |
|
1740 |
{
|
|
1741 |
if (*a != *b) |
|
1742 |
{
|
|
1743 |
return *a ? -1 : 1; |
|
1744 |
}
|
|
1745 |
if (*a) |
|
1746 |
goto end; // NULL where equal |
|
1747 |
a++; b++; // Skip NULL marker |
|
1748 |
}
|
|
1749 |
cmp=field->key_cmp(a , b); |
|
1750 |
if (cmp) return cmp < 0 ? -1 : 1; // The values differed |
|
1751 |
||
1752 |
// Check if the compared equal arguments was defined with open/closed range
|
|
1753 |
end: |
|
1754 |
if (a_flag & (NEAR_MIN | NEAR_MAX)) |
|
1755 |
{
|
|
1756 |
if ((a_flag & (NEAR_MIN | NEAR_MAX)) == (b_flag & (NEAR_MIN | NEAR_MAX))) |
|
1757 |
return 0; |
|
1758 |
if (!(b_flag & (NEAR_MIN | NEAR_MAX))) |
|
1759 |
return (a_flag & NEAR_MIN) ? 2 : -2; |
|
1760 |
return (a_flag & NEAR_MIN) ? 1 : -1; |
|
1761 |
}
|
|
1762 |
if (b_flag & (NEAR_MIN | NEAR_MAX)) |
|
1763 |
return (b_flag & NEAR_MIN) ? -2 : 2; |
|
1764 |
return 0; // The elements where equal |
|
1765 |
}
|
|
1766 |
||
1767 |
||
1768 |
SEL_ARG *SEL_ARG::clone_tree(RANGE_OPT_PARAM *param) |
|
1769 |
{
|
|
1770 |
SEL_ARG tmp_link,*next_arg,*root; |
|
1771 |
next_arg= &tmp_link; |
|
1772 |
if (!(root= clone(param, (SEL_ARG *) 0, &next_arg))) |
|
1773 |
return 0; |
|
1774 |
next_arg->next=0; // Fix last link |
|
1775 |
tmp_link.next->prev=0; // Fix first link |
|
1776 |
if (root) // If not OOM |
|
1777 |
root->use_count= 0; |
|
1778 |
return root; |
|
1779 |
}
|
|
1780 |
||
1781 |
||
1782 |
/*
|
|
1783 |
Find the best index to retrieve first N records in given order
|
|
1784 |
||
1785 |
SYNOPSIS
|
|
1786 |
get_index_for_order()
|
|
1787 |
table Table to be accessed
|
|
1788 |
order Required ordering
|
|
1789 |
limit Number of records that will be retrieved
|
|
1790 |
||
1791 |
DESCRIPTION
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1792 |
Find the best index that allows to retrieve first #limit records in the
|
1
by brian
clean slate |
1793 |
given order cheaper then one would retrieve them using full table scan.
|
1794 |
||
1795 |
IMPLEMENTATION
|
|
1796 |
Run through all table indexes and find the shortest index that allows
|
|
1797 |
records to be retrieved in given order. We look for the shortest index
|
|
1798 |
as we will have fewer index pages to read with it.
|
|
1799 |
||
1800 |
This function is used only by UPDATE/DELETE, so we take into account how
|
|
1801 |
the UPDATE/DELETE code will work:
|
|
1802 |
* index can only be scanned in forward direction
|
|
1803 |
* HA_EXTRA_KEYREAD will not be used
|
|
1804 |
Perhaps these assumptions could be relaxed.
|
|
1805 |
||
1806 |
RETURN
|
|
1807 |
Number of the index that produces the required ordering in the cheapest way
|
|
1808 |
MAX_KEY if no such index was found.
|
|
1809 |
*/
|
|
1810 |
||
482
by Brian Aker
Remove uint. |
1811 |
uint32_t get_index_for_order(Table *table, order_st *order, ha_rows limit) |
1
by brian
clean slate |
1812 |
{
|
482
by Brian Aker
Remove uint. |
1813 |
uint32_t idx; |
1814 |
uint32_t match_key= MAX_KEY, match_key_len= MAX_KEY_LENGTH + 1; |
|
327.2.3
by Brian Aker
Refactoring of class Table |
1815 |
order_st *ord; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1816 |
|
1
by brian
clean slate |
1817 |
for (ord= order; ord; ord= ord->next) |
1818 |
if (!ord->asc) |
|
1819 |
return MAX_KEY; |
|
1820 |
||
1821 |
for (idx= 0; idx < table->s->keys; idx++) |
|
1822 |
{
|
|
1823 |
if (!(table->keys_in_use_for_query.is_set(idx))) |
|
1824 |
continue; |
|
1825 |
KEY_PART_INFO *keyinfo= table->key_info[idx].key_part; |
|
482
by Brian Aker
Remove uint. |
1826 |
uint32_t n_parts= table->key_info[idx].key_parts; |
1827 |
uint32_t partno= 0; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1828 |
|
1829 |
/*
|
|
1830 |
The below check is sufficient considering we now have either BTREE
|
|
1831 |
indexes (records are returned in order for any index prefix) or HASH
|
|
1
by brian
clean slate |
1832 |
indexes (records are not returned in order for any index prefix).
|
1833 |
*/
|
|
1834 |
if (!(table->file->index_flags(idx, 0, 1) & HA_READ_ORDER)) |
|
1835 |
continue; |
|
1836 |
for (ord= order; ord && partno < n_parts; ord= ord->next, partno++) |
|
1837 |
{
|
|
1838 |
Item *item= order->item[0]; |
|
1839 |
if (!(item->type() == Item::FIELD_ITEM && |
|
1840 |
((Item_field*)item)->field->eq(keyinfo[partno].field))) |
|
1841 |
break; |
|
1842 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1843 |
|
1
by brian
clean slate |
1844 |
if (!ord && table->key_info[idx].key_length < match_key_len) |
1845 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1846 |
/*
|
1
by brian
clean slate |
1847 |
Ok, the ordering is compatible and this key is shorter then
|
1848 |
previous match (we want shorter keys as we'll have to read fewer
|
|
1849 |
index pages for the same number of records)
|
|
1850 |
*/
|
|
1851 |
match_key= idx; |
|
1852 |
match_key_len= table->key_info[idx].key_length; |
|
1853 |
}
|
|
1854 |
}
|
|
1855 |
||
1856 |
if (match_key != MAX_KEY) |
|
1857 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1858 |
/*
|
1859 |
Found an index that allows records to be retrieved in the requested
|
|
1
by brian
clean slate |
1860 |
order. Now we'll check if using the index is cheaper then doing a table
|
1861 |
scan.
|
|
1862 |
*/
|
|
1863 |
double full_scan_time= table->file->scan_time(); |
|
1864 |
double index_scan_time= table->file->read_time(match_key, 1, limit); |
|
1865 |
if (index_scan_time > full_scan_time) |
|
1866 |
match_key= MAX_KEY; |
|
1867 |
}
|
|
1868 |
return match_key; |
|
1869 |
}
|
|
1870 |
||
1871 |
||
1872 |
/*
|
|
1873 |
Table rows retrieval plan. Range optimizer creates QUICK_SELECT_I-derived
|
|
1874 |
objects from table read plans.
|
|
1875 |
*/
|
|
1876 |
class TABLE_READ_PLAN |
|
1877 |
{
|
|
1878 |
public: |
|
1879 |
/*
|
|
1880 |
Plan read cost, with or without cost of full row retrieval, depending
|
|
1881 |
on plan creation parameters.
|
|
1882 |
*/
|
|
1883 |
double read_cost; |
|
1884 |
ha_rows records; /* estimate of #rows to be examined */ |
|
1885 |
||
1886 |
/*
|
|
55
by brian
Update for using real bool types. |
1887 |
If true, the scan returns rows in rowid order. This is used only for
|
1
by brian
clean slate |
1888 |
scans that can be both ROR and non-ROR.
|
1889 |
*/
|
|
1890 |
bool is_ror; |
|
1891 |
||
1892 |
/*
|
|
1893 |
Create quick select for this plan.
|
|
1894 |
SYNOPSIS
|
|
1895 |
make_quick()
|
|
1896 |
param Parameter from test_quick_select
|
|
55
by brian
Update for using real bool types. |
1897 |
retrieve_full_rows If true, created quick select will do full record
|
1
by brian
clean slate |
1898 |
retrieval.
|
1899 |
parent_alloc Memory pool to use, if any.
|
|
1900 |
||
1901 |
NOTES
|
|
1902 |
retrieve_full_rows is ignored by some implementations.
|
|
1903 |
||
1904 |
RETURN
|
|
1905 |
created quick select
|
|
1906 |
NULL on any error.
|
|
1907 |
*/
|
|
1908 |
virtual QUICK_SELECT_I *make_quick(PARAM *param, |
|
1909 |
bool retrieve_full_rows, |
|
1910 |
MEM_ROOT *parent_alloc=NULL) = 0; |
|
1911 |
||
1912 |
/* Table read plans are allocated on MEM_ROOT and are never deleted */
|
|
1913 |
static void *operator new(size_t size, MEM_ROOT *mem_root) |
|
895
by Brian Aker
Completion (?) of uint conversion. |
1914 |
{ return (void*) alloc_root(mem_root, (uint32_t) size); } |
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
1915 |
static void operator delete(void *, size_t) |
77.1.46
by Monty Taylor
Finished the warnings work! |
1916 |
{ TRASH(ptr, size); } |
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
1917 |
static void operator delete(void *, MEM_ROOT *) |
77.1.46
by Monty Taylor
Finished the warnings work! |
1918 |
{ /* Never called */ } |
1
by brian
clean slate |
1919 |
virtual ~TABLE_READ_PLAN() {} /* Remove gcc warning */ |
1920 |
||
1921 |
};
|
|
1922 |
||
1923 |
class TRP_ROR_INTERSECT; |
|
1924 |
class TRP_ROR_UNION; |
|
1925 |
class TRP_INDEX_MERGE; |
|
1926 |
||
1927 |
||
1928 |
/*
|
|
1929 |
Plan for a QUICK_RANGE_SELECT scan.
|
|
1930 |
TRP_RANGE::make_quick ignores retrieve_full_rows parameter because
|
|
1931 |
QUICK_RANGE_SELECT doesn't distinguish between 'index only' scans and full
|
|
1932 |
record retrieval scans.
|
|
1933 |
*/
|
|
1934 |
||
1935 |
class TRP_RANGE : public TABLE_READ_PLAN |
|
1936 |
{
|
|
1937 |
public: |
|
1938 |
SEL_ARG *key; /* set of intervals to be used in "range" method retrieval */ |
|
482
by Brian Aker
Remove uint. |
1939 |
uint32_t key_idx; /* key number in PARAM::key */ |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1940 |
uint32_t mrr_flags; |
482
by Brian Aker
Remove uint. |
1941 |
uint32_t mrr_buf_size; |
1
by brian
clean slate |
1942 |
|
482
by Brian Aker
Remove uint. |
1943 |
TRP_RANGE(SEL_ARG *key_arg, uint32_t idx_arg, uint32_t mrr_flags_arg) |
1
by brian
clean slate |
1944 |
: key(key_arg), key_idx(idx_arg), mrr_flags(mrr_flags_arg) |
1945 |
{}
|
|
1946 |
virtual ~TRP_RANGE() {} /* Remove gcc warning */ |
|
1947 |
||
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
1948 |
QUICK_SELECT_I *make_quick(PARAM *param, bool, MEM_ROOT *parent_alloc) |
1
by brian
clean slate |
1949 |
{
|
1950 |
QUICK_RANGE_SELECT *quick; |
|
1951 |
if ((quick= get_quick_select(param, key_idx, key, mrr_flags, mrr_buf_size, |
|
1952 |
parent_alloc))) |
|
1953 |
{
|
|
1954 |
quick->records= records; |
|
1955 |
quick->read_time= read_cost; |
|
1956 |
}
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1957 |
return quick; |
1
by brian
clean slate |
1958 |
}
|
1959 |
};
|
|
1960 |
||
1961 |
||
1962 |
/* Plan for QUICK_ROR_INTERSECT_SELECT scan. */
|
|
1963 |
||
1964 |
class TRP_ROR_INTERSECT : public TABLE_READ_PLAN |
|
1965 |
{
|
|
1966 |
public: |
|
1967 |
TRP_ROR_INTERSECT() {} /* Remove gcc warning */ |
|
1968 |
virtual ~TRP_ROR_INTERSECT() {} /* Remove gcc warning */ |
|
1969 |
QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows, |
|
1970 |
MEM_ROOT *parent_alloc); |
|
1971 |
||
1972 |
/* Array of pointers to ROR range scans used in this intersection */
|
|
1973 |
struct st_ror_scan_info **first_scan; |
|
1974 |
struct st_ror_scan_info **last_scan; /* End of the above array */ |
|
1975 |
struct st_ror_scan_info *cpk_scan; /* Clustered PK scan, if there is one */ |
|
55
by brian
Update for using real bool types. |
1976 |
bool is_covering; /* true if no row retrieval phase is necessary */ |
1
by brian
clean slate |
1977 |
double index_scan_costs; /* SUM(cost(index_scan)) */ |
1978 |
};
|
|
1979 |
||
1980 |
||
1981 |
/*
|
|
1982 |
Plan for QUICK_ROR_UNION_SELECT scan.
|
|
1983 |
QUICK_ROR_UNION_SELECT always retrieves full rows, so retrieve_full_rows
|
|
1984 |
is ignored by make_quick.
|
|
1985 |
*/
|
|
1986 |
||
1987 |
class TRP_ROR_UNION : public TABLE_READ_PLAN |
|
1988 |
{
|
|
1989 |
public: |
|
1990 |
TRP_ROR_UNION() {} /* Remove gcc warning */ |
|
1991 |
virtual ~TRP_ROR_UNION() {} /* Remove gcc warning */ |
|
1992 |
QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows, |
|
1993 |
MEM_ROOT *parent_alloc); |
|
1994 |
TABLE_READ_PLAN **first_ror; /* array of ptrs to plans for merged scans */ |
|
1995 |
TABLE_READ_PLAN **last_ror; /* end of the above array */ |
|
1996 |
};
|
|
1997 |
||
1998 |
||
1999 |
/*
|
|
2000 |
Plan for QUICK_INDEX_MERGE_SELECT scan.
|
|
2001 |
QUICK_ROR_INTERSECT_SELECT always retrieves full rows, so retrieve_full_rows
|
|
2002 |
is ignored by make_quick.
|
|
2003 |
*/
|
|
2004 |
||
2005 |
class TRP_INDEX_MERGE : public TABLE_READ_PLAN |
|
2006 |
{
|
|
2007 |
public: |
|
2008 |
TRP_INDEX_MERGE() {} /* Remove gcc warning */ |
|
2009 |
virtual ~TRP_INDEX_MERGE() {} /* Remove gcc warning */ |
|
2010 |
QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows, |
|
2011 |
MEM_ROOT *parent_alloc); |
|
2012 |
TRP_RANGE **range_scans; /* array of ptrs to plans of merged scans */ |
|
2013 |
TRP_RANGE **range_scans_end; /* end of the array */ |
|
2014 |
};
|
|
2015 |
||
2016 |
||
2017 |
/*
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2018 |
Plan for a QUICK_GROUP_MIN_MAX_SELECT scan.
|
1
by brian
clean slate |
2019 |
*/
|
2020 |
||
2021 |
class TRP_GROUP_MIN_MAX : public TABLE_READ_PLAN |
|
2022 |
{
|
|
2023 |
private: |
|
2024 |
bool have_min, have_max; |
|
2025 |
KEY_PART_INFO *min_max_arg_part; |
|
482
by Brian Aker
Remove uint. |
2026 |
uint32_t group_prefix_len; |
2027 |
uint32_t used_key_parts; |
|
2028 |
uint32_t group_key_parts; |
|
1
by brian
clean slate |
2029 |
KEY *index_info; |
482
by Brian Aker
Remove uint. |
2030 |
uint32_t index; |
2031 |
uint32_t key_infix_len; |
|
481
by Brian Aker
Remove all of uchar. |
2032 |
unsigned char key_infix[MAX_KEY_LENGTH]; |
1
by brian
clean slate |
2033 |
SEL_TREE *range_tree; /* Represents all range predicates in the query. */ |
2034 |
SEL_ARG *index_tree; /* The SEL_ARG sub-tree corresponding to index_info. */ |
|
482
by Brian Aker
Remove uint. |
2035 |
uint32_t param_idx; /* Index of used key in param->key. */ |
1
by brian
clean slate |
2036 |
/* Number of records selected by the ranges in index_tree. */
|
2037 |
public: |
|
2038 |
ha_rows quick_prefix_records; |
|
2039 |
public: |
|
2040 |
TRP_GROUP_MIN_MAX(bool have_min_arg, bool have_max_arg, |
|
2041 |
KEY_PART_INFO *min_max_arg_part_arg, |
|
482
by Brian Aker
Remove uint. |
2042 |
uint32_t group_prefix_len_arg, uint32_t used_key_parts_arg, |
2043 |
uint32_t group_key_parts_arg, KEY *index_info_arg, |
|
2044 |
uint32_t index_arg, uint32_t key_infix_len_arg, |
|
481
by Brian Aker
Remove all of uchar. |
2045 |
unsigned char *key_infix_arg, |
1
by brian
clean slate |
2046 |
SEL_TREE *tree_arg, SEL_ARG *index_tree_arg, |
482
by Brian Aker
Remove uint. |
2047 |
uint32_t param_idx_arg, ha_rows quick_prefix_records_arg) |
1
by brian
clean slate |
2048 |
: have_min(have_min_arg), have_max(have_max_arg), |
2049 |
min_max_arg_part(min_max_arg_part_arg), |
|
2050 |
group_prefix_len(group_prefix_len_arg), used_key_parts(used_key_parts_arg), |
|
2051 |
group_key_parts(group_key_parts_arg), index_info(index_info_arg), |
|
2052 |
index(index_arg), key_infix_len(key_infix_len_arg), range_tree(tree_arg), |
|
2053 |
index_tree(index_tree_arg), param_idx(param_idx_arg), |
|
2054 |
quick_prefix_records(quick_prefix_records_arg) |
|
2055 |
{
|
|
2056 |
if (key_infix_len) |
|
2057 |
memcpy(this->key_infix, key_infix_arg, key_infix_len); |
|
2058 |
}
|
|
2059 |
virtual ~TRP_GROUP_MIN_MAX() {} /* Remove gcc warning */ |
|
2060 |
||
2061 |
QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows, |
|
2062 |
MEM_ROOT *parent_alloc); |
|
2063 |
};
|
|
2064 |
||
2065 |
||
2066 |
/*
|
|
2067 |
Fill param->needed_fields with bitmap of fields used in the query.
|
|
2068 |
SYNOPSIS
|
|
2069 |
fill_used_fields_bitmap()
|
|
2070 |
param Parameter from test_quick_select function.
|
|
2071 |
||
2072 |
NOTES
|
|
2073 |
Clustered PK members are not put into the bitmap as they are implicitly
|
|
2074 |
present in all keys (and it is impossible to avoid reading them).
|
|
2075 |
RETURN
|
|
2076 |
0 Ok
|
|
2077 |
1 Out of memory.
|
|
2078 |
*/
|
|
2079 |
||
2080 |
static int fill_used_fields_bitmap(PARAM *param) |
|
2081 |
{
|
|
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
2082 |
Table *table= param->table; |
1
by brian
clean slate |
2083 |
my_bitmap_map *tmp; |
482
by Brian Aker
Remove uint. |
2084 |
uint32_t pk; |
1
by brian
clean slate |
2085 |
param->tmp_covered_fields.bitmap= 0; |
2086 |
param->fields_bitmap_size= table->s->column_bitmap_size; |
|
2087 |
if (!(tmp= (my_bitmap_map*) alloc_root(param->mem_root, |
|
2088 |
param->fields_bitmap_size)) || |
|
55
by brian
Update for using real bool types. |
2089 |
bitmap_init(¶m->needed_fields, tmp, table->s->fields, false)) |
1
by brian
clean slate |
2090 |
return 1; |
2091 |
||
2092 |
bitmap_copy(¶m->needed_fields, table->read_set); |
|
2093 |
bitmap_union(¶m->needed_fields, table->write_set); |
|
2094 |
||
2095 |
pk= param->table->s->primary_key; |
|
2096 |
if (pk != MAX_KEY && param->table->file->primary_key_is_clustered()) |
|
2097 |
{
|
|
2098 |
/* The table uses clustered PK and it is not internally generated */
|
|
2099 |
KEY_PART_INFO *key_part= param->table->key_info[pk].key_part; |
|
2100 |
KEY_PART_INFO *key_part_end= key_part + |
|
2101 |
param->table->key_info[pk].key_parts; |
|
2102 |
for (;key_part != key_part_end; ++key_part) |
|
2103 |
bitmap_clear_bit(¶m->needed_fields, key_part->fieldnr-1); |
|
2104 |
}
|
|
2105 |
return 0; |
|
2106 |
}
|
|
2107 |
||
2108 |
||
2109 |
/*
|
|
2110 |
Test if a key can be used in different ranges
|
|
2111 |
||
2112 |
SYNOPSIS
|
|
2113 |
SQL_SELECT::test_quick_select()
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2114 |
session Current thread
|
1
by brian
clean slate |
2115 |
keys_to_use Keys to use for range retrieval
|
2116 |
prev_tables Tables assumed to be already read when the scan is
|
|
2117 |
performed (but not read at the moment of this call)
|
|
2118 |
limit Query limit
|
|
2119 |
force_quick_range Prefer to use range (instead of full table scan) even
|
|
2120 |
if it is more expensive.
|
|
2121 |
||
2122 |
NOTES
|
|
2123 |
Updates the following in the select parameter:
|
|
2124 |
needed_reg - Bits for keys with may be used if all prev regs are read
|
|
2125 |
quick - Parameter to use when reading records.
|
|
2126 |
||
2127 |
In the table struct the following information is updated:
|
|
2128 |
quick_keys - Which keys can be used
|
|
2129 |
quick_rows - How many rows the key matches
|
|
2130 |
quick_condition_rows - E(# rows that will satisfy the table condition)
|
|
2131 |
||
2132 |
IMPLEMENTATION
|
|
2133 |
quick_condition_rows value is obtained as follows:
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2134 |
|
1
by brian
clean slate |
2135 |
It is a minimum of E(#output rows) for all considered table access
|
2136 |
methods (range and index_merge accesses over various indexes).
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2137 |
|
1
by brian
clean slate |
2138 |
The obtained value is not a true E(#rows that satisfy table condition)
|
2139 |
but rather a pessimistic estimate. To obtain a true E(#...) one would
|
|
2140 |
need to combine estimates of various access methods, taking into account
|
|
2141 |
correlations between sets of rows they will return.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2142 |
|
1
by brian
clean slate |
2143 |
For example, if values of tbl.key1 and tbl.key2 are independent (a right
|
2144 |
assumption if we have no information about their correlation) then the
|
|
2145 |
correct estimate will be:
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2146 |
|
2147 |
E(#rows("tbl.key1 < c1 AND tbl.key2 < c2")) =
|
|
1
by brian
clean slate |
2148 |
= E(#rows(tbl.key1 < c1)) / total_rows(tbl) * E(#rows(tbl.key2 < c2)
|
2149 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2150 |
which is smaller than
|
2151 |
||
1
by brian
clean slate |
2152 |
MIN(E(#rows(tbl.key1 < c1), E(#rows(tbl.key2 < c2)))
|
2153 |
||
2154 |
which is currently produced.
|
|
2155 |
||
2156 |
TODO
|
|
2157 |
* Change the value returned in quick_condition_rows from a pessimistic
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2158 |
estimate to true E(#rows that satisfy table condition).
|
2159 |
(we can re-use some of E(#rows) calcuation code from index_merge/intersection
|
|
1
by brian
clean slate |
2160 |
for this)
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2161 |
|
1
by brian
clean slate |
2162 |
* Check if this function really needs to modify keys_to_use, and change the
|
2163 |
code to pass it by reference if it doesn't.
|
|
2164 |
||
2165 |
* In addition to force_quick_range other means can be (an usually are) used
|
|
2166 |
to make this function prefer range over full table scan. Figure out if
|
|
2167 |
force_quick_range is really needed.
|
|
2168 |
||
2169 |
RETURN
|
|
2170 |
-1 if impossible select (i.e. certainly no rows will be selected)
|
|
2171 |
0 if can't use quick_select
|
|
2172 |
1 if found usable ranges and quick select has been successfully created.
|
|
2173 |
*/
|
|
2174 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
2175 |
int SQL_SELECT::test_quick_select(Session *session, key_map keys_to_use, |
1
by brian
clean slate |
2176 |
table_map prev_tables, |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2177 |
ha_rows limit, bool force_quick_range, |
1
by brian
clean slate |
2178 |
bool ordered_output) |
2179 |
{
|
|
482
by Brian Aker
Remove uint. |
2180 |
uint32_t idx; |
1
by brian
clean slate |
2181 |
double scan_time; |
2182 |
delete quick; |
|
2183 |
quick=0; |
|
2184 |
needed_reg.clear_all(); |
|
2185 |
quick_keys.clear_all(); |
|
2186 |
if (keys_to_use.is_clear_all()) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
2187 |
return 0; |
1
by brian
clean slate |
2188 |
records= head->file->stats.records; |
2189 |
if (!records) |
|
2190 |
records++; /* purecov: inspected */ |
|
2191 |
scan_time= (double) records / TIME_FOR_COMPARE + 1; |
|
2192 |
read_time= (double) head->file->scan_time() + scan_time + 1.1; |
|
2193 |
if (head->force_index) |
|
2194 |
scan_time= read_time= DBL_MAX; |
|
2195 |
if (limit < records) |
|
2196 |
read_time= (double) records + scan_time + 1; // Force to use index |
|
2197 |
else if (read_time <= 2.0 && !force_quick_range) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
2198 |
return 0; /* No need for quick select */ |
1
by brian
clean slate |
2199 |
|
2200 |
keys_to_use.intersect(head->keys_in_use_for_query); |
|
2201 |
if (!keys_to_use.is_clear_all()) |
|
2202 |
{
|
|
2203 |
MEM_ROOT alloc; |
|
2204 |
SEL_TREE *tree= NULL; |
|
2205 |
KEY_PART *key_parts; |
|
2206 |
KEY *key_info; |
|
2207 |
PARAM param; |
|
2208 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
2209 |
if (check_stack_overrun(session, 2*STACK_MIN_SIZE, NULL)) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
2210 |
return 0; // Fatal error flag is set |
1
by brian
clean slate |
2211 |
|
2212 |
/* set up parameter that is passed to all functions */
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2213 |
param.session= session; |
1
by brian
clean slate |
2214 |
param.baseflag= head->file->ha_table_flags(); |
2215 |
param.prev_tables=prev_tables | const_tables; |
|
2216 |
param.read_tables=read_tables; |
|
2217 |
param.current_table= head->map; |
|
2218 |
param.table=head; |
|
2219 |
param.keys=0; |
|
2220 |
param.mem_root= &alloc; |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2221 |
param.old_root= session->mem_root; |
1
by brian
clean slate |
2222 |
param.needed_reg= &needed_reg; |
2223 |
param.imerge_cost_buff_size= 0; |
|
55
by brian
Update for using real bool types. |
2224 |
param.using_real_indexes= true; |
2225 |
param.remove_jump_scans= true; |
|
1
by brian
clean slate |
2226 |
param.force_default_mrr= ordered_output; |
2227 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
2228 |
session->no_errors=1; // Don't warn about NULL |
2229 |
init_sql_alloc(&alloc, session->variables.range_alloc_block_size, 0); |
|
1
by brian
clean slate |
2230 |
if (!(param.key_parts= (KEY_PART*) alloc_root(&alloc, |
2231 |
sizeof(KEY_PART)* |
|
2232 |
head->s->key_parts)) || |
|
2233 |
fill_used_fields_bitmap(¶m)) |
|
2234 |
{
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2235 |
session->no_errors=0; |
1
by brian
clean slate |
2236 |
free_root(&alloc,MYF(0)); // Return memory & allocator |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
2237 |
return 0; // Can't use range |
1
by brian
clean slate |
2238 |
}
|
2239 |
key_parts= param.key_parts; |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2240 |
session->mem_root= &alloc; |
1
by brian
clean slate |
2241 |
|
2242 |
/*
|
|
2243 |
Make an array with description of all key parts of all table keys.
|
|
2244 |
This is used in get_mm_parts function.
|
|
2245 |
*/
|
|
2246 |
key_info= head->key_info; |
|
2247 |
for (idx=0 ; idx < head->s->keys ; idx++, key_info++) |
|
2248 |
{
|
|
2249 |
KEY_PART_INFO *key_part_info; |
|
2250 |
if (!keys_to_use.is_set(idx)) |
|
2251 |
continue; |
|
2252 |
||
2253 |
param.key[param.keys]=key_parts; |
|
2254 |
key_part_info= key_info->key_part; |
|
482
by Brian Aker
Remove uint. |
2255 |
for (uint32_t part=0 ; part < key_info->key_parts ; |
1
by brian
clean slate |
2256 |
part++, key_parts++, key_part_info++) |
2257 |
{
|
|
2258 |
key_parts->key= param.keys; |
|
2259 |
key_parts->part= part; |
|
2260 |
key_parts->length= key_part_info->length; |
|
2261 |
key_parts->store_length= key_part_info->store_length; |
|
2262 |
key_parts->field= key_part_info->field; |
|
2263 |
key_parts->null_bit= key_part_info->null_bit; |
|
2264 |
key_parts->image_type = Field::itRAW; |
|
2265 |
/* Only HA_PART_KEY_SEG is used */
|
|
206
by Brian Aker
Removed final uint dead types. |
2266 |
key_parts->flag= (uint8_t) key_part_info->key_part_flag; |
1
by brian
clean slate |
2267 |
}
|
2268 |
param.real_keynr[param.keys++]=idx; |
|
2269 |
}
|
|
2270 |
param.key_parts_end=key_parts; |
|
2271 |
param.alloced_sel_args= 0; |
|
2272 |
||
2273 |
/* Calculate cost of full index read for the shortest covering index */
|
|
2274 |
if (!head->covering_keys.is_clear_all()) |
|
2275 |
{
|
|
355
by Brian Aker
More Table cleanup |
2276 |
int key_for_use= head->find_shortest_key(&head->covering_keys); |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2277 |
double key_read_time= |
2278 |
param.table->file->index_only_read_time(key_for_use, |
|
1
by brian
clean slate |
2279 |
rows2double(records)) + |
2280 |
(double) records / TIME_FOR_COMPARE; |
|
2281 |
if (key_read_time < read_time) |
|
2282 |
read_time= key_read_time; |
|
2283 |
}
|
|
2284 |
||
2285 |
TABLE_READ_PLAN *best_trp= NULL; |
|
2286 |
TRP_GROUP_MIN_MAX *group_trp; |
|
2287 |
double best_read_time= read_time; |
|
2288 |
||
2289 |
if (cond) |
|
2290 |
{
|
|
2291 |
if ((tree= get_mm_tree(¶m,cond))) |
|
2292 |
{
|
|
2293 |
if (tree->type == SEL_TREE::IMPOSSIBLE) |
|
2294 |
{
|
|
2295 |
records=0L; /* Return -1 from this function. */ |
|
2296 |
read_time= (double) HA_POS_ERROR; |
|
2297 |
goto free_mem; |
|
2298 |
}
|
|
2299 |
/*
|
|
2300 |
If the tree can't be used for range scans, proceed anyway, as we
|
|
2301 |
can construct a group-min-max quick select
|
|
2302 |
*/
|
|
2303 |
if (tree->type != SEL_TREE::KEY && tree->type != SEL_TREE::KEY_SMALLER) |
|
2304 |
tree= NULL; |
|
2305 |
}
|
|
2306 |
}
|
|
2307 |
||
2308 |
/*
|
|
2309 |
Try to construct a QUICK_GROUP_MIN_MAX_SELECT.
|
|
2310 |
Notice that it can be constructed no matter if there is a range tree.
|
|
2311 |
*/
|
|
2312 |
group_trp= get_best_group_min_max(¶m, tree); |
|
2313 |
if (group_trp) |
|
2314 |
{
|
|
398.1.4
by Monty Taylor
Renamed max/min. |
2315 |
param.table->quick_condition_rows= cmin(group_trp->records, |
1
by brian
clean slate |
2316 |
head->file->stats.records); |
2317 |
if (group_trp->read_cost < best_read_time) |
|
2318 |
{
|
|
2319 |
best_trp= group_trp; |
|
2320 |
best_read_time= best_trp->read_cost; |
|
2321 |
}
|
|
2322 |
}
|
|
2323 |
||
2324 |
if (tree) |
|
2325 |
{
|
|
2326 |
/*
|
|
2327 |
It is possible to use a range-based quick select (but it might be
|
|
2328 |
slower than 'all' table scan).
|
|
2329 |
*/
|
|
2330 |
if (tree->merges.is_empty()) |
|
2331 |
{
|
|
2332 |
TRP_RANGE *range_trp; |
|
2333 |
TRP_ROR_INTERSECT *rori_trp; |
|
55
by brian
Update for using real bool types. |
2334 |
bool can_build_covering= false; |
1
by brian
clean slate |
2335 |
|
2336 |
/* Get best 'range' plan and prepare data for making other plans */
|
|
55
by brian
Update for using real bool types. |
2337 |
if ((range_trp= get_key_scans_params(¶m, tree, false, true, |
1
by brian
clean slate |
2338 |
best_read_time))) |
2339 |
{
|
|
2340 |
best_trp= range_trp; |
|
2341 |
best_read_time= best_trp->read_cost; |
|
2342 |
}
|
|
2343 |
||
2344 |
/*
|
|
2345 |
Simultaneous key scans and row deletes on several handler
|
|
2346 |
objects are not allowed so don't use ROR-intersection for
|
|
2347 |
table deletes.
|
|
2348 |
*/
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2349 |
if ((session->lex->sql_command != SQLCOM_DELETE)) |
1
by brian
clean slate |
2350 |
{
|
2351 |
/*
|
|
2352 |
Get best non-covering ROR-intersection plan and prepare data for
|
|
2353 |
building covering ROR-intersection.
|
|
2354 |
*/
|
|
2355 |
if ((rori_trp= get_best_ror_intersect(¶m, tree, best_read_time, |
|
2356 |
&can_build_covering))) |
|
2357 |
{
|
|
2358 |
best_trp= rori_trp; |
|
2359 |
best_read_time= best_trp->read_cost; |
|
2360 |
/*
|
|
2361 |
Try constructing covering ROR-intersect only if it looks possible
|
|
2362 |
and worth doing.
|
|
2363 |
*/
|
|
2364 |
if (!rori_trp->is_covering && can_build_covering && |
|
2365 |
(rori_trp= get_best_covering_ror_intersect(¶m, tree, |
|
2366 |
best_read_time))) |
|
2367 |
best_trp= rori_trp; |
|
2368 |
}
|
|
2369 |
}
|
|
2370 |
}
|
|
2371 |
else
|
|
2372 |
{
|
|
2373 |
/* Try creating index_merge/ROR-union scan. */
|
|
2374 |
SEL_IMERGE *imerge; |
|
2375 |
TABLE_READ_PLAN *best_conj_trp= NULL, *new_conj_trp; |
|
2376 |
List_iterator_fast<SEL_IMERGE> it(tree->merges); |
|
2377 |
while ((imerge= it++)) |
|
2378 |
{
|
|
2379 |
new_conj_trp= get_best_disjunct_quick(¶m, imerge, best_read_time); |
|
2380 |
if (new_conj_trp) |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2381 |
set_if_smaller(param.table->quick_condition_rows, |
1
by brian
clean slate |
2382 |
new_conj_trp->records); |
2383 |
if (!best_conj_trp || (new_conj_trp && new_conj_trp->read_cost < |
|
2384 |
best_conj_trp->read_cost)) |
|
2385 |
best_conj_trp= new_conj_trp; |
|
2386 |
}
|
|
2387 |
if (best_conj_trp) |
|
2388 |
best_trp= best_conj_trp; |
|
2389 |
}
|
|
2390 |
}
|
|
2391 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
2392 |
session->mem_root= param.old_root; |
1
by brian
clean slate |
2393 |
|
2394 |
/* If we got a read plan, create a quick select from it. */
|
|
2395 |
if (best_trp) |
|
2396 |
{
|
|
2397 |
records= best_trp->records; |
|
55
by brian
Update for using real bool types. |
2398 |
if (!(quick= best_trp->make_quick(¶m, true)) || quick->init()) |
1
by brian
clean slate |
2399 |
{
|
2400 |
delete quick; |
|
2401 |
quick= NULL; |
|
2402 |
}
|
|
2403 |
}
|
|
2404 |
||
2405 |
free_mem: |
|
2406 |
free_root(&alloc,MYF(0)); // Return memory & allocator |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2407 |
session->mem_root= param.old_root; |
2408 |
session->no_errors=0; |
|
1
by brian
clean slate |
2409 |
}
|
2410 |
||
2411 |
/*
|
|
2412 |
Assume that if the user is using 'limit' we will only need to scan
|
|
2413 |
limit rows if we are using a key
|
|
2414 |
*/
|
|
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. |
2415 |
return(records ? test(quick) : -1); |
1
by brian
clean slate |
2416 |
}
|
2417 |
||
2418 |
/*
|
|
2419 |
Get best plan for a SEL_IMERGE disjunctive expression.
|
|
2420 |
SYNOPSIS
|
|
2421 |
get_best_disjunct_quick()
|
|
2422 |
param Parameter from check_quick_select function
|
|
2423 |
imerge Expression to use
|
|
2424 |
read_time Don't create scans with cost > read_time
|
|
2425 |
||
2426 |
NOTES
|
|
2427 |
index_merge cost is calculated as follows:
|
|
2428 |
index_merge_cost =
|
|
2429 |
cost(index_reads) + (see #1)
|
|
2430 |
cost(rowid_to_row_scan) + (see #2)
|
|
2431 |
cost(unique_use) (see #3)
|
|
2432 |
||
2433 |
1. cost(index_reads) =SUM_i(cost(index_read_i))
|
|
2434 |
For non-CPK scans,
|
|
2435 |
cost(index_read_i) = {cost of ordinary 'index only' scan}
|
|
2436 |
For CPK scan,
|
|
2437 |
cost(index_read_i) = {cost of non-'index only' scan}
|
|
2438 |
||
2439 |
2. cost(rowid_to_row_scan)
|
|
2440 |
If table PK is clustered then
|
|
2441 |
cost(rowid_to_row_scan) =
|
|
2442 |
{cost of ordinary clustered PK scan with n_ranges=n_rows}
|
|
2443 |
||
2444 |
Otherwise, we use the following model to calculate costs:
|
|
2445 |
We need to retrieve n_rows rows from file that occupies n_blocks blocks.
|
|
2446 |
We assume that offsets of rows we need are independent variates with
|
|
2447 |
uniform distribution in [0..max_file_offset] range.
|
|
2448 |
||
2449 |
We'll denote block as "busy" if it contains row(s) we need to retrieve
|
|
2450 |
and "empty" if doesn't contain rows we need.
|
|
2451 |
||
2452 |
Probability that a block is empty is (1 - 1/n_blocks)^n_rows (this
|
|
2453 |
applies to any block in file). Let x_i be a variate taking value 1 if
|
|
2454 |
block #i is empty and 0 otherwise.
|
|
2455 |
||
2456 |
Then E(x_i) = (1 - 1/n_blocks)^n_rows;
|
|
2457 |
||
2458 |
E(n_empty_blocks) = E(sum(x_i)) = sum(E(x_i)) =
|
|
2459 |
= n_blocks * ((1 - 1/n_blocks)^n_rows) =
|
|
2460 |
~= n_blocks * exp(-n_rows/n_blocks).
|
|
2461 |
||
2462 |
E(n_busy_blocks) = n_blocks*(1 - (1 - 1/n_blocks)^n_rows) =
|
|
2463 |
~= n_blocks * (1 - exp(-n_rows/n_blocks)).
|
|
2464 |
||
2465 |
Average size of "hole" between neighbor non-empty blocks is
|
|
2466 |
E(hole_size) = n_blocks/E(n_busy_blocks).
|
|
2467 |
||
2468 |
The total cost of reading all needed blocks in one "sweep" is:
|
|
2469 |
||
2470 |
E(n_busy_blocks)*
|
|
2471 |
(DISK_SEEK_BASE_COST + DISK_SEEK_PROP_COST*n_blocks/E(n_busy_blocks)).
|
|
2472 |
||
2473 |
3. Cost of Unique use is calculated in Unique::get_use_cost function.
|
|
2474 |
||
2475 |
ROR-union cost is calculated in the same way index_merge, but instead of
|
|
2476 |
Unique a priority queue is used.
|
|
2477 |
||
2478 |
RETURN
|
|
2479 |
Created read plan
|
|
2480 |
NULL - Out of memory or no read scan could be built.
|
|
2481 |
*/
|
|
2482 |
||
2483 |
static
|
|
2484 |
TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, |
|
2485 |
double read_time) |
|
2486 |
{
|
|
2487 |
SEL_TREE **ptree; |
|
2488 |
TRP_INDEX_MERGE *imerge_trp= NULL; |
|
482
by Brian Aker
Remove uint. |
2489 |
uint32_t n_child_scans= imerge->trees_next - imerge->trees; |
1
by brian
clean slate |
2490 |
TRP_RANGE **range_scans; |
2491 |
TRP_RANGE **cur_child; |
|
2492 |
TRP_RANGE **cpk_scan= NULL; |
|
55
by brian
Update for using real bool types. |
2493 |
bool imerge_too_expensive= false; |
1
by brian
clean slate |
2494 |
double imerge_cost= 0.0; |
2495 |
ha_rows cpk_scan_records= 0; |
|
2496 |
ha_rows non_cpk_scan_records= 0; |
|
2497 |
bool pk_is_clustered= param->table->file->primary_key_is_clustered(); |
|
55
by brian
Update for using real bool types. |
2498 |
bool all_scans_ror_able= true; |
2499 |
bool all_scans_rors= true; |
|
482
by Brian Aker
Remove uint. |
2500 |
uint32_t unique_calc_buff_size; |
1
by brian
clean slate |
2501 |
TABLE_READ_PLAN **roru_read_plans; |
2502 |
TABLE_READ_PLAN **cur_roru_plan; |
|
2503 |
double roru_index_costs; |
|
2504 |
ha_rows roru_total_records; |
|
2505 |
double roru_intersect_part= 1.0; |
|
2506 |
||
2507 |
if (!(range_scans= (TRP_RANGE**)alloc_root(param->mem_root, |
|
2508 |
sizeof(TRP_RANGE*)* |
|
2509 |
n_child_scans))) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
2510 |
return NULL; |
1
by brian
clean slate |
2511 |
/*
|
2512 |
Collect best 'range' scan for each of disjuncts, and, while doing so,
|
|
2513 |
analyze possibility of ROR scans. Also calculate some values needed by
|
|
2514 |
other parts of the code.
|
|
2515 |
*/
|
|
2516 |
for (ptree= imerge->trees, cur_child= range_scans; |
|
2517 |
ptree != imerge->trees_next; |
|
2518 |
ptree++, cur_child++) |
|
2519 |
{
|
|
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. |
2520 |
print_sel_tree(param, *ptree, &(*ptree)->keys_map, "tree in SEL_IMERGE"); |
55
by brian
Update for using real bool types. |
2521 |
if (!(*cur_child= get_key_scans_params(param, *ptree, true, false, read_time))) |
1
by brian
clean slate |
2522 |
{
|
2523 |
/*
|
|
2524 |
One of index scans in this index_merge is more expensive than entire
|
|
2525 |
table read for another available option. The entire index_merge (and
|
|
2526 |
any possible ROR-union) will be more expensive then, too. We continue
|
|
2527 |
here only to update SQL_SELECT members.
|
|
2528 |
*/
|
|
55
by brian
Update for using real bool types. |
2529 |
imerge_too_expensive= true; |
1
by brian
clean slate |
2530 |
}
|
2531 |
if (imerge_too_expensive) |
|
2532 |
continue; |
|
2533 |
||
2534 |
imerge_cost += (*cur_child)->read_cost; |
|
2535 |
all_scans_ror_able &= ((*ptree)->n_ror_scans > 0); |
|
2536 |
all_scans_rors &= (*cur_child)->is_ror; |
|
2537 |
if (pk_is_clustered && |
|
2538 |
param->real_keynr[(*cur_child)->key_idx] == |
|
2539 |
param->table->s->primary_key) |
|
2540 |
{
|
|
2541 |
cpk_scan= cur_child; |
|
2542 |
cpk_scan_records= (*cur_child)->records; |
|
2543 |
}
|
|
2544 |
else
|
|
2545 |
non_cpk_scan_records += (*cur_child)->records; |
|
2546 |
}
|
|
2547 |
||
2548 |
if (imerge_too_expensive || (imerge_cost > read_time) || |
|
2549 |
((non_cpk_scan_records+cpk_scan_records >= param->table->file->stats.records) && read_time != DBL_MAX)) |
|
2550 |
{
|
|
2551 |
/*
|
|
2552 |
Bail out if it is obvious that both index_merge and ROR-union will be
|
|
2553 |
more expensive
|
|
2554 |
*/
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
2555 |
return NULL; |
1
by brian
clean slate |
2556 |
}
|
2557 |
if (all_scans_rors) |
|
2558 |
{
|
|
2559 |
roru_read_plans= (TABLE_READ_PLAN**)range_scans; |
|
2560 |
goto skip_to_ror_scan; |
|
2561 |
}
|
|
2562 |
if (cpk_scan) |
|
2563 |
{
|
|
2564 |
/*
|
|
2565 |
Add one ROWID comparison for each row retrieved on non-CPK scan. (it
|
|
2566 |
is done in QUICK_RANGE_SELECT::row_in_ranges)
|
|
2567 |
*/
|
|
2568 |
imerge_cost += non_cpk_scan_records / TIME_FOR_COMPARE_ROWID; |
|
2569 |
}
|
|
2570 |
||
2571 |
/* Calculate cost(rowid_to_row_scan) */
|
|
2572 |
{
|
|
2573 |
COST_VECT sweep_cost; |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2574 |
JOIN *join= param->session->lex->select_lex.join; |
1
by brian
clean slate |
2575 |
bool is_interrupted= test(join && join->tables == 1); |
2576 |
get_sweep_read_cost(param->table, non_cpk_scan_records, is_interrupted, |
|
2577 |
&sweep_cost); |
|
2578 |
imerge_cost += sweep_cost.total_cost(); |
|
2579 |
}
|
|
2580 |
if (imerge_cost > read_time) |
|
2581 |
goto build_ror_index_merge; |
|
2582 |
||
2583 |
/* Add Unique operations cost */
|
|
2584 |
unique_calc_buff_size= |
|
2585 |
Unique::get_cost_calc_buff_size((ulong)non_cpk_scan_records, |
|
2586 |
param->table->file->ref_length, |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2587 |
param->session->variables.sortbuff_size); |
1
by brian
clean slate |
2588 |
if (param->imerge_cost_buff_size < unique_calc_buff_size) |
2589 |
{
|
|
2590 |
if (!(param->imerge_cost_buff= (uint*)alloc_root(param->mem_root, |
|
2591 |
unique_calc_buff_size))) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
2592 |
return NULL; |
1
by brian
clean slate |
2593 |
param->imerge_cost_buff_size= unique_calc_buff_size; |
2594 |
}
|
|
2595 |
||
2596 |
imerge_cost += |
|
895
by Brian Aker
Completion (?) of uint conversion. |
2597 |
Unique::get_use_cost(param->imerge_cost_buff, (uint32_t)non_cpk_scan_records, |
1
by brian
clean slate |
2598 |
param->table->file->ref_length, |
520.1.22
by Brian Aker
Second pass of thd cleanup |
2599 |
param->session->variables.sortbuff_size); |
1
by brian
clean slate |
2600 |
if (imerge_cost < read_time) |
2601 |
{
|
|
2602 |
if ((imerge_trp= new (param->mem_root)TRP_INDEX_MERGE)) |
|
2603 |
{
|
|
2604 |
imerge_trp->read_cost= imerge_cost; |
|
2605 |
imerge_trp->records= non_cpk_scan_records + cpk_scan_records; |
|
398.1.4
by Monty Taylor
Renamed max/min. |
2606 |
imerge_trp->records= cmin(imerge_trp->records, |
1
by brian
clean slate |
2607 |
param->table->file->stats.records); |
2608 |
imerge_trp->range_scans= range_scans; |
|
2609 |
imerge_trp->range_scans_end= range_scans + n_child_scans; |
|
2610 |
read_time= imerge_cost; |
|
2611 |
}
|
|
2612 |
}
|
|
2613 |
||
2614 |
build_ror_index_merge: |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2615 |
if (!all_scans_ror_able || param->session->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. |
2616 |
return(imerge_trp); |
1
by brian
clean slate |
2617 |
|
2618 |
/* Ok, it is possible to build a ROR-union, try it. */
|
|
2619 |
bool dummy; |
|
2620 |
if (!(roru_read_plans= |
|
2621 |
(TABLE_READ_PLAN**)alloc_root(param->mem_root, |
|
2622 |
sizeof(TABLE_READ_PLAN*)* |
|
2623 |
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. |
2624 |
return(imerge_trp); |
1
by brian
clean slate |
2625 |
skip_to_ror_scan: |
2626 |
roru_index_costs= 0.0; |
|
2627 |
roru_total_records= 0; |
|
2628 |
cur_roru_plan= roru_read_plans; |
|
2629 |
||
2630 |
/* Find 'best' ROR scan for each of trees in disjunction */
|
|
2631 |
for (ptree= imerge->trees, cur_child= range_scans; |
|
2632 |
ptree != imerge->trees_next; |
|
2633 |
ptree++, cur_child++, cur_roru_plan++) |
|
2634 |
{
|
|
2635 |
/*
|
|
2636 |
Assume the best ROR scan is the one that has cheapest full-row-retrieval
|
|
2637 |
scan cost.
|
|
2638 |
Also accumulate index_only scan costs as we'll need them to calculate
|
|
2639 |
overall index_intersection cost.
|
|
2640 |
*/
|
|
2641 |
double cost; |
|
2642 |
if ((*cur_child)->is_ror) |
|
2643 |
{
|
|
2644 |
/* Ok, we have index_only cost, now get full rows scan cost */
|
|
2645 |
cost= param->table->file-> |
|
2646 |
read_time(param->real_keynr[(*cur_child)->key_idx], 1, |
|
2647 |
(*cur_child)->records) + |
|
2648 |
rows2double((*cur_child)->records) / TIME_FOR_COMPARE; |
|
2649 |
}
|
|
2650 |
else
|
|
2651 |
cost= read_time; |
|
2652 |
||
2653 |
TABLE_READ_PLAN *prev_plan= *cur_child; |
|
2654 |
if (!(*cur_roru_plan= get_best_ror_intersect(param, *ptree, cost, |
|
2655 |
&dummy))) |
|
2656 |
{
|
|
2657 |
if (prev_plan->is_ror) |
|
2658 |
*cur_roru_plan= prev_plan; |
|
2659 |
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. |
2660 |
return(imerge_trp); |
1
by brian
clean slate |
2661 |
roru_index_costs += (*cur_roru_plan)->read_cost; |
2662 |
}
|
|
2663 |
else
|
|
2664 |
roru_index_costs += |
|
2665 |
((TRP_ROR_INTERSECT*)(*cur_roru_plan))->index_scan_costs; |
|
2666 |
roru_total_records += (*cur_roru_plan)->records; |
|
2667 |
roru_intersect_part *= (*cur_roru_plan)->records / |
|
2668 |
param->table->file->stats.records; |
|
2669 |
}
|
|
2670 |
||
2671 |
/*
|
|
2672 |
rows to retrieve=
|
|
2673 |
SUM(rows_in_scan_i) - table_rows * PROD(rows_in_scan_i / table_rows).
|
|
2674 |
This is valid because index_merge construction guarantees that conditions
|
|
2675 |
in disjunction do not share key parts.
|
|
2676 |
*/
|
|
2677 |
roru_total_records -= (ha_rows)(roru_intersect_part* |
|
2678 |
param->table->file->stats.records); |
|
2679 |
/* ok, got a ROR read plan for each of the disjuncts
|
|
2680 |
Calculate cost:
|
|
2681 |
cost(index_union_scan(scan_1, ... scan_n)) =
|
|
2682 |
SUM_i(cost_of_index_only_scan(scan_i)) +
|
|
2683 |
queue_use_cost(rowid_len, n) +
|
|
2684 |
cost_of_row_retrieval
|
|
2685 |
See get_merge_buffers_cost function for queue_use_cost formula derivation.
|
|
2686 |
*/
|
|
2687 |
double roru_total_cost; |
|
2688 |
{
|
|
2689 |
COST_VECT sweep_cost; |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2690 |
JOIN *join= param->session->lex->select_lex.join; |
1
by brian
clean slate |
2691 |
bool is_interrupted= test(join && join->tables == 1); |
2692 |
get_sweep_read_cost(param->table, roru_total_records, is_interrupted, |
|
2693 |
&sweep_cost); |
|
2694 |
roru_total_cost= roru_index_costs + |
|
2695 |
rows2double(roru_total_records)*log((double)n_child_scans) / |
|
2696 |
(TIME_FOR_COMPARE_ROWID * M_LN2) + |
|
2697 |
sweep_cost.total_cost(); |
|
2698 |
}
|
|
2699 |
||
2700 |
TRP_ROR_UNION* roru; |
|
2701 |
if (roru_total_cost < read_time) |
|
2702 |
{
|
|
2703 |
if ((roru= new (param->mem_root) TRP_ROR_UNION)) |
|
2704 |
{
|
|
2705 |
roru->first_ror= roru_read_plans; |
|
2706 |
roru->last_ror= roru_read_plans + n_child_scans; |
|
2707 |
roru->read_cost= roru_total_cost; |
|
2708 |
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. |
2709 |
return(roru); |
1
by brian
clean slate |
2710 |
}
|
2711 |
}
|
|
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. |
2712 |
return(imerge_trp); |
1
by brian
clean slate |
2713 |
}
|
2714 |
||
2715 |
||
2716 |
typedef struct st_ror_scan_info |
|
2717 |
{
|
|
482
by Brian Aker
Remove uint. |
2718 |
uint32_t idx; /* # of used key in param->keys */ |
2719 |
uint32_t keynr; /* # of used key in table */ |
|
1
by brian
clean slate |
2720 |
ha_rows records; /* estimate of # records this scan will return */ |
2721 |
||
2722 |
/* Set of intervals over key fields that will be used for row retrieval. */
|
|
2723 |
SEL_ARG *sel_arg; |
|
2724 |
||
2725 |
/* Fields used in the query and covered by this ROR scan. */
|
|
2726 |
MY_BITMAP covered_fields; |
|
482
by Brian Aker
Remove uint. |
2727 |
uint32_t used_fields_covered; /* # of set bits in covered_fields */ |
1
by brian
clean slate |
2728 |
int key_rec_length; /* length of key record (including rowid) */ |
2729 |
||
2730 |
/*
|
|
2731 |
Cost of reading all index records with values in sel_arg intervals set
|
|
2732 |
(assuming there is no need to access full table records)
|
|
2733 |
*/
|
|
2734 |
double index_read_cost; |
|
482
by Brian Aker
Remove uint. |
2735 |
uint32_t first_uncovered_field; /* first unused bit in covered_fields */ |
2736 |
uint32_t key_components; /* # of parts in the key */ |
|
1
by brian
clean slate |
2737 |
} ROR_SCAN_INFO; |
2738 |
||
2739 |
||
2740 |
/*
|
|
2741 |
Create ROR_SCAN_INFO* structure with a single ROR scan on index idx using
|
|
2742 |
sel_arg set of intervals.
|
|
2743 |
||
2744 |
SYNOPSIS
|
|
2745 |
make_ror_scan()
|
|
2746 |
param Parameter from test_quick_select function
|
|
2747 |
idx Index of key in param->keys
|
|
2748 |
sel_arg Set of intervals for a given key
|
|
2749 |
||
2750 |
RETURN
|
|
2751 |
NULL - out of memory
|
|
2752 |
ROR scan structure containing a scan for {idx, sel_arg}
|
|
2753 |
*/
|
|
2754 |
||
2755 |
static
|
|
2756 |
ROR_SCAN_INFO *make_ror_scan(const PARAM *param, int idx, SEL_ARG *sel_arg) |
|
2757 |
{
|
|
2758 |
ROR_SCAN_INFO *ror_scan; |
|
2759 |
my_bitmap_map *bitmap_buf; |
|
482
by Brian Aker
Remove uint. |
2760 |
uint32_t keynr; |
1
by brian
clean slate |
2761 |
|
2762 |
if (!(ror_scan= (ROR_SCAN_INFO*)alloc_root(param->mem_root, |
|
2763 |
sizeof(ROR_SCAN_INFO)))) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
2764 |
return NULL; |
1
by brian
clean slate |
2765 |
|
2766 |
ror_scan->idx= idx; |
|
2767 |
ror_scan->keynr= keynr= param->real_keynr[idx]; |
|
2768 |
ror_scan->key_rec_length= (param->table->key_info[keynr].key_length + |
|
2769 |
param->table->file->ref_length); |
|
2770 |
ror_scan->sel_arg= sel_arg; |
|
2771 |
ror_scan->records= param->table->quick_rows[keynr]; |
|
2772 |
||
2773 |
if (!(bitmap_buf= (my_bitmap_map*) alloc_root(param->mem_root, |
|
2774 |
param->fields_bitmap_size))) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
2775 |
return NULL; |
1
by brian
clean slate |
2776 |
|
2777 |
if (bitmap_init(&ror_scan->covered_fields, bitmap_buf, |
|
55
by brian
Update for using real bool types. |
2778 |
param->table->s->fields, false)) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
2779 |
return NULL; |
1
by brian
clean slate |
2780 |
bitmap_clear_all(&ror_scan->covered_fields); |
2781 |
||
2782 |
KEY_PART_INFO *key_part= param->table->key_info[keynr].key_part; |
|
2783 |
KEY_PART_INFO *key_part_end= key_part + |
|
2784 |
param->table->key_info[keynr].key_parts; |
|
2785 |
for (;key_part != key_part_end; ++key_part) |
|
2786 |
{
|
|
2787 |
if (bitmap_is_set(¶m->needed_fields, key_part->fieldnr-1)) |
|
2788 |
bitmap_set_bit(&ror_scan->covered_fields, key_part->fieldnr-1); |
|
2789 |
}
|
|
2790 |
double rows= rows2double(param->table->quick_rows[ror_scan->keynr]); |
|
2791 |
ror_scan->index_read_cost= |
|
2792 |
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. |
2793 |
return(ror_scan); |
1
by brian
clean slate |
2794 |
}
|
2795 |
||
2796 |
||
2797 |
/*
|
|
2798 |
Compare two ROR_SCAN_INFO** by E(#records_matched) * key_record_length.
|
|
2799 |
SYNOPSIS
|
|
2800 |
cmp_ror_scan_info()
|
|
2801 |
a ptr to first compared value
|
|
2802 |
b ptr to second compared value
|
|
2803 |
||
2804 |
RETURN
|
|
2805 |
-1 a < b
|
|
2806 |
0 a = b
|
|
2807 |
1 a > b
|
|
2808 |
*/
|
|
2809 |
||
2810 |
static int cmp_ror_scan_info(ROR_SCAN_INFO** a, ROR_SCAN_INFO** b) |
|
2811 |
{
|
|
2812 |
double val1= rows2double((*a)->records) * (*a)->key_rec_length; |
|
2813 |
double val2= rows2double((*b)->records) * (*b)->key_rec_length; |
|
2814 |
return (val1 < val2)? -1: (val1 == val2)? 0 : 1; |
|
2815 |
}
|
|
2816 |
||
2817 |
/*
|
|
2818 |
Compare two ROR_SCAN_INFO** by
|
|
2819 |
(#covered fields in F desc,
|
|
2820 |
#components asc,
|
|
2821 |
number of first not covered component asc)
|
|
2822 |
||
2823 |
SYNOPSIS
|
|
2824 |
cmp_ror_scan_info_covering()
|
|
2825 |
a ptr to first compared value
|
|
2826 |
b ptr to second compared value
|
|
2827 |
||
2828 |
RETURN
|
|
2829 |
-1 a < b
|
|
2830 |
0 a = b
|
|
2831 |
1 a > b
|
|
2832 |
*/
|
|
2833 |
||
2834 |
static int cmp_ror_scan_info_covering(ROR_SCAN_INFO** a, ROR_SCAN_INFO** b) |
|
2835 |
{
|
|
2836 |
if ((*a)->used_fields_covered > (*b)->used_fields_covered) |
|
2837 |
return -1; |
|
2838 |
if ((*a)->used_fields_covered < (*b)->used_fields_covered) |
|
2839 |
return 1; |
|
2840 |
if ((*a)->key_components < (*b)->key_components) |
|
2841 |
return -1; |
|
2842 |
if ((*a)->key_components > (*b)->key_components) |
|
2843 |
return 1; |
|
2844 |
if ((*a)->first_uncovered_field < (*b)->first_uncovered_field) |
|
2845 |
return -1; |
|
2846 |
if ((*a)->first_uncovered_field > (*b)->first_uncovered_field) |
|
2847 |
return 1; |
|
2848 |
return 0; |
|
2849 |
}
|
|
2850 |
||
2851 |
||
2852 |
/* Auxiliary structure for incremental ROR-intersection creation */
|
|
2853 |
typedef struct |
|
2854 |
{
|
|
2855 |
const PARAM *param; |
|
2856 |
MY_BITMAP covered_fields; /* union of fields covered by all scans */ |
|
2857 |
/*
|
|
2858 |
Fraction of table records that satisfies conditions of all scans.
|
|
2859 |
This is the number of full records that will be retrieved if a
|
|
2860 |
non-index_only index intersection will be employed.
|
|
2861 |
*/
|
|
2862 |
double out_rows; |
|
55
by brian
Update for using real bool types. |
2863 |
/* true if covered_fields is a superset of needed_fields */
|
1
by brian
clean slate |
2864 |
bool is_covering; |
2865 |
||
2866 |
ha_rows index_records; /* sum(#records to look in indexes) */ |
|
2867 |
double index_scan_costs; /* SUM(cost of 'index-only' scans) */ |
|
2868 |
double total_cost; |
|
2869 |
} ROR_INTERSECT_INFO; |
|
2870 |
||
2871 |
||
2872 |
/*
|
|
2873 |
Allocate a ROR_INTERSECT_INFO and initialize it to contain zero scans.
|
|
2874 |
||
2875 |
SYNOPSIS
|
|
2876 |
ror_intersect_init()
|
|
2877 |
param Parameter from test_quick_select
|
|
2878 |
||
2879 |
RETURN
|
|
2880 |
allocated structure
|
|
2881 |
NULL on error
|
|
2882 |
*/
|
|
2883 |
||
2884 |
static
|
|
2885 |
ROR_INTERSECT_INFO* ror_intersect_init(const PARAM *param) |
|
2886 |
{
|
|
2887 |
ROR_INTERSECT_INFO *info; |
|
2888 |
my_bitmap_map* buf; |
|
2889 |
if (!(info= (ROR_INTERSECT_INFO*)alloc_root(param->mem_root, |
|
2890 |
sizeof(ROR_INTERSECT_INFO)))) |
|
2891 |
return NULL; |
|
2892 |
info->param= param; |
|
2893 |
if (!(buf= (my_bitmap_map*) alloc_root(param->mem_root, |
|
2894 |
param->fields_bitmap_size))) |
|
2895 |
return NULL; |
|
2896 |
if (bitmap_init(&info->covered_fields, buf, param->table->s->fields, |
|
55
by brian
Update for using real bool types. |
2897 |
false)) |
1
by brian
clean slate |
2898 |
return NULL; |
55
by brian
Update for using real bool types. |
2899 |
info->is_covering= false; |
1
by brian
clean slate |
2900 |
info->index_scan_costs= 0.0; |
2901 |
info->index_records= 0; |
|
2902 |
info->out_rows= (double) param->table->file->stats.records; |
|
2903 |
bitmap_clear_all(&info->covered_fields); |
|
2904 |
return info; |
|
2905 |
}
|
|
2906 |
||
2907 |
void ror_intersect_cpy(ROR_INTERSECT_INFO *dst, const ROR_INTERSECT_INFO *src) |
|
2908 |
{
|
|
2909 |
dst->param= src->param; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2910 |
memcpy(dst->covered_fields.bitmap, src->covered_fields.bitmap, |
1
by brian
clean slate |
2911 |
no_bytes_in_map(&src->covered_fields)); |
2912 |
dst->out_rows= src->out_rows; |
|
2913 |
dst->is_covering= src->is_covering; |
|
2914 |
dst->index_records= src->index_records; |
|
2915 |
dst->index_scan_costs= src->index_scan_costs; |
|
2916 |
dst->total_cost= src->total_cost; |
|
2917 |
}
|
|
2918 |
||
2919 |
||
2920 |
/*
|
|
2921 |
Get selectivity of a ROR scan wrt ROR-intersection.
|
|
2922 |
||
2923 |
SYNOPSIS
|
|
2924 |
ror_scan_selectivity()
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2925 |
info ROR-interection
|
1
by brian
clean slate |
2926 |
scan ROR scan
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2927 |
|
1
by brian
clean slate |
2928 |
NOTES
|
2929 |
Suppose we have a condition on several keys
|
|
2930 |
cond=k_11=c_11 AND k_12=c_12 AND ... // parts of first key
|
|
2931 |
k_21=c_21 AND k_22=c_22 AND ... // parts of second key
|
|
2932 |
...
|
|
2933 |
k_n1=c_n1 AND k_n3=c_n3 AND ... (1) //parts of the key used by *scan
|
|
2934 |
||
2935 |
where k_ij may be the same as any k_pq (i.e. keys may have common parts).
|
|
2936 |
||
2937 |
A full row is retrieved if entire condition holds.
|
|
2938 |
||
2939 |
The recursive procedure for finding P(cond) is as follows:
|
|
2940 |
||
2941 |
First step:
|
|
2942 |
Pick 1st part of 1st key and break conjunction (1) into two parts:
|
|
2943 |
cond= (k_11=c_11 AND R)
|
|
2944 |
||
2945 |
Here R may still contain condition(s) equivalent to k_11=c_11.
|
|
2946 |
Nevertheless, the following holds:
|
|
2947 |
||
2948 |
P(k_11=c_11 AND R) = P(k_11=c_11) * P(R | k_11=c_11).
|
|
2949 |
||
2950 |
Mark k_11 as fixed field (and satisfied condition) F, save P(F),
|
|
2951 |
save R to be cond and proceed to recursion step.
|
|
2952 |
||
2953 |
Recursion step:
|
|
2954 |
We have a set of fixed fields/satisfied conditions) F, probability P(F),
|
|
2955 |
and remaining conjunction R
|
|
2956 |
Pick next key part on current key and its condition "k_ij=c_ij".
|
|
2957 |
We will add "k_ij=c_ij" into F and update P(F).
|
|
2958 |
Lets denote k_ij as t, R = t AND R1, where R1 may still contain t. Then
|
|
2959 |
||
2960 |
P((t AND R1)|F) = P(t|F) * P(R1|t|F) = P(t|F) * P(R1|(t AND F)) (2)
|
|
2961 |
||
2962 |
(where '|' mean conditional probability, not "or")
|
|
2963 |
||
2964 |
Consider the first multiplier in (2). One of the following holds:
|
|
2965 |
a) F contains condition on field used in t (i.e. t AND F = F).
|
|
2966 |
Then P(t|F) = 1
|
|
2967 |
||
2968 |
b) F doesn't contain condition on field used in t. Then F and t are
|
|
2969 |
considered independent.
|
|
2970 |
||
2971 |
P(t|F) = P(t|(fields_before_t_in_key AND other_fields)) =
|
|
2972 |
= P(t|fields_before_t_in_key).
|
|
2973 |
||
2974 |
P(t|fields_before_t_in_key) = #records(fields_before_t_in_key) /
|
|
2975 |
#records(fields_before_t_in_key, t)
|
|
2976 |
||
2977 |
The second multiplier is calculated by applying this step recursively.
|
|
2978 |
||
2979 |
IMPLEMENTATION
|
|
2980 |
This function calculates the result of application of the "recursion step"
|
|
2981 |
described above for all fixed key members of a single key, accumulating set
|
|
2982 |
of covered fields, selectivity, etc.
|
|
2983 |
||
2984 |
The calculation is conducted as follows:
|
|
2985 |
Lets denote #records(keypart1, ... keypartK) as n_k. We need to calculate
|
|
2986 |
||
2987 |
n_{k1} n_{k2}
|
|
2988 |
--------- * --------- * .... (3)
|
|
2989 |
n_{k1-1} n_{k2-1}
|
|
2990 |
||
2991 |
where k1,k2,... are key parts which fields were not yet marked as fixed
|
|
2992 |
( this is result of application of option b) of the recursion step for
|
|
2993 |
parts of a single key).
|
|
2994 |
Since it is reasonable to expect that most of the fields are not marked
|
|
2995 |
as fixed, we calculate (3) as
|
|
2996 |
||
2997 |
n_{i1} n_{i2}
|
|
2998 |
(3) = n_{max_key_part} / ( --------- * --------- * .... )
|
|
2999 |
n_{i1-1} n_{i2-1}
|
|
3000 |
||
3001 |
where i1,i2, .. are key parts that were already marked as fixed.
|
|
3002 |
||
3003 |
In order to minimize number of expensive records_in_range calls we group
|
|
3004 |
and reduce adjacent fractions.
|
|
3005 |
||
3006 |
RETURN
|
|
3007 |
Selectivity of given ROR scan.
|
|
3008 |
*/
|
|
3009 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3010 |
static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info, |
1
by brian
clean slate |
3011 |
const ROR_SCAN_INFO *scan) |
3012 |
{
|
|
3013 |
double selectivity_mult= 1.0; |
|
3014 |
KEY_PART_INFO *key_part= info->param->table->key_info[scan->keynr].key_part; |
|
481
by Brian Aker
Remove all of uchar. |
3015 |
unsigned char key_val[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; /* key values tuple */ |
3016 |
unsigned char *key_ptr= key_val; |
|
1
by brian
clean slate |
3017 |
SEL_ARG *sel_arg, *tuple_arg= NULL; |
3018 |
key_part_map keypart_map= 0; |
|
3019 |
bool cur_covered; |
|
3020 |
bool prev_covered= test(bitmap_is_set(&info->covered_fields, |
|
3021 |
key_part->fieldnr-1)); |
|
3022 |
key_range min_range; |
|
3023 |
key_range max_range; |
|
3024 |
min_range.key= key_val; |
|
3025 |
min_range.flag= HA_READ_KEY_EXACT; |
|
3026 |
max_range.key= key_val; |
|
3027 |
max_range.flag= HA_READ_AFTER_KEY; |
|
3028 |
ha_rows prev_records= info->param->table->file->stats.records; |
|
3029 |
||
3030 |
for (sel_arg= scan->sel_arg; sel_arg; |
|
3031 |
sel_arg= sel_arg->next_key_part) |
|
3032 |
{
|
|
3033 |
cur_covered= test(bitmap_is_set(&info->covered_fields, |
|
3034 |
key_part[sel_arg->part].fieldnr-1)); |
|
3035 |
if (cur_covered != prev_covered) |
|
3036 |
{
|
|
3037 |
/* create (part1val, ..., part{n-1}val) tuple. */
|
|
3038 |
ha_rows records; |
|
3039 |
if (!tuple_arg) |
|
3040 |
{
|
|
3041 |
tuple_arg= scan->sel_arg; |
|
3042 |
/* Here we use the length of the first key part */
|
|
3043 |
tuple_arg->store_min(key_part->store_length, &key_ptr, 0); |
|
3044 |
keypart_map= 1; |
|
3045 |
}
|
|
3046 |
while (tuple_arg->next_key_part != sel_arg) |
|
3047 |
{
|
|
3048 |
tuple_arg= tuple_arg->next_key_part; |
|
3049 |
tuple_arg->store_min(key_part[tuple_arg->part].store_length, |
|
3050 |
&key_ptr, 0); |
|
3051 |
keypart_map= (keypart_map << 1) | 1; |
|
3052 |
}
|
|
3053 |
min_range.length= max_range.length= (size_t) (key_ptr - key_val); |
|
3054 |
min_range.keypart_map= max_range.keypart_map= keypart_map; |
|
3055 |
records= (info->param->table->file-> |
|
3056 |
records_in_range(scan->keynr, &min_range, &max_range)); |
|
3057 |
if (cur_covered) |
|
3058 |
{
|
|
3059 |
/* uncovered -> covered */
|
|
3060 |
double tmp= rows2double(records)/rows2double(prev_records); |
|
3061 |
selectivity_mult *= tmp; |
|
3062 |
prev_records= HA_POS_ERROR; |
|
3063 |
}
|
|
3064 |
else
|
|
3065 |
{
|
|
3066 |
/* covered -> uncovered */
|
|
3067 |
prev_records= records; |
|
3068 |
}
|
|
3069 |
}
|
|
3070 |
prev_covered= cur_covered; |
|
3071 |
}
|
|
3072 |
if (!prev_covered) |
|
3073 |
{
|
|
3074 |
double tmp= rows2double(info->param->table->quick_rows[scan->keynr]) / |
|
3075 |
rows2double(prev_records); |
|
3076 |
selectivity_mult *= tmp; |
|
3077 |
}
|
|
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. |
3078 |
return(selectivity_mult); |
1
by brian
clean slate |
3079 |
}
|
3080 |
||
3081 |
||
3082 |
/*
|
|
3083 |
Check if adding a ROR scan to a ROR-intersection reduces its cost of
|
|
3084 |
ROR-intersection and if yes, update parameters of ROR-intersection,
|
|
3085 |
including its cost.
|
|
3086 |
||
3087 |
SYNOPSIS
|
|
3088 |
ror_intersect_add()
|
|
3089 |
param Parameter from test_quick_select
|
|
3090 |
info ROR-intersection structure to add the scan to.
|
|
3091 |
ror_scan ROR scan info to add.
|
|
55
by brian
Update for using real bool types. |
3092 |
is_cpk_scan If true, add the scan as CPK scan (this can be inferred
|
1
by brian
clean slate |
3093 |
from other parameters and is passed separately only to
|
3094 |
avoid duplicating the inference code)
|
|
3095 |
||
3096 |
NOTES
|
|
3097 |
Adding a ROR scan to ROR-intersect "makes sense" iff the cost of ROR-
|
|
3098 |
intersection decreases. The cost of ROR-intersection is calculated as
|
|
3099 |
follows:
|
|
3100 |
||
3101 |
cost= SUM_i(key_scan_cost_i) + cost_of_full_rows_retrieval
|
|
3102 |
||
3103 |
When we add a scan the first increases and the second decreases.
|
|
3104 |
||
3105 |
cost_of_full_rows_retrieval=
|
|
3106 |
(union of indexes used covers all needed fields) ?
|
|
3107 |
cost_of_sweep_read(E(rows_to_retrieve), rows_in_table) :
|
|
3108 |
0
|
|
3109 |
||
3110 |
E(rows_to_retrieve) = #rows_in_table * ror_scan_selectivity(null, scan1) *
|
|
3111 |
ror_scan_selectivity({scan1}, scan2) * ... *
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3112 |
ror_scan_selectivity({scan1,...}, scanN).
|
1
by brian
clean slate |
3113 |
RETURN
|
55
by brian
Update for using real bool types. |
3114 |
true ROR scan added to ROR-intersection, cost updated.
|
3115 |
false It doesn't make sense to add this ROR scan to this ROR-intersection.
|
|
1
by brian
clean slate |
3116 |
*/
|
3117 |
||
3118 |
static bool ror_intersect_add(ROR_INTERSECT_INFO *info, |
|
3119 |
ROR_SCAN_INFO* ror_scan, bool is_cpk_scan) |
|
3120 |
{
|
|
3121 |
double selectivity_mult= 1.0; |
|
3122 |
||
3123 |
selectivity_mult = ror_scan_selectivity(info, ror_scan); |
|
3124 |
if (selectivity_mult == 1.0) |
|
3125 |
{
|
|
3126 |
/* Don't add this scan if it doesn't improve selectivity. */
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3127 |
return false; |
1
by brian
clean slate |
3128 |
}
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3129 |
|
1
by brian
clean slate |
3130 |
info->out_rows *= selectivity_mult; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3131 |
|
1
by brian
clean slate |
3132 |
if (is_cpk_scan) |
3133 |
{
|
|
3134 |
/*
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3135 |
CPK scan is used to filter out rows. We apply filtering for
|
1
by brian
clean slate |
3136 |
each record of every scan. Assuming 1/TIME_FOR_COMPARE_ROWID
|
3137 |
per check this gives us:
|
|
3138 |
*/
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3139 |
info->index_scan_costs += rows2double(info->index_records) / |
1
by brian
clean slate |
3140 |
TIME_FOR_COMPARE_ROWID; |
3141 |
}
|
|
3142 |
else
|
|
3143 |
{
|
|
3144 |
info->index_records += info->param->table->quick_rows[ror_scan->keynr]; |
|
3145 |
info->index_scan_costs += ror_scan->index_read_cost; |
|
3146 |
bitmap_union(&info->covered_fields, &ror_scan->covered_fields); |
|
3147 |
if (!info->is_covering && bitmap_is_subset(&info->param->needed_fields, |
|
3148 |
&info->covered_fields)) |
|
3149 |
{
|
|
55
by brian
Update for using real bool types. |
3150 |
info->is_covering= true; |
1
by brian
clean slate |
3151 |
}
|
3152 |
}
|
|
3153 |
||
3154 |
info->total_cost= info->index_scan_costs; |
|
3155 |
if (!info->is_covering) |
|
3156 |
{
|
|
3157 |
COST_VECT sweep_cost; |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
3158 |
JOIN *join= info->param->session->lex->select_lex.join; |
1
by brian
clean slate |
3159 |
bool is_interrupted= test(join && join->tables == 1); |
3160 |
get_sweep_read_cost(info->param->table, double2rows(info->out_rows), |
|
3161 |
is_interrupted, &sweep_cost); |
|
3162 |
info->total_cost += sweep_cost.total_cost(); |
|
3163 |
}
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3164 |
return true; |
1
by brian
clean slate |
3165 |
}
|
3166 |
||
3167 |
||
3168 |
/*
|
|
3169 |
Get best ROR-intersection plan using non-covering ROR-intersection search
|
|
3170 |
algorithm. The returned plan may be covering.
|
|
3171 |
||
3172 |
SYNOPSIS
|
|
3173 |
get_best_ror_intersect()
|
|
3174 |
param Parameter from test_quick_select function.
|
|
3175 |
tree Transformed restriction condition to be used to look
|
|
3176 |
for ROR scans.
|
|
3177 |
read_time Do not return read plans with cost > read_time.
|
|
55
by brian
Update for using real bool types. |
3178 |
are_all_covering [out] set to true if union of all scans covers all
|
1
by brian
clean slate |
3179 |
fields needed by the query (and it is possible to build
|
3180 |
a covering ROR-intersection)
|
|
3181 |
||
3182 |
NOTES
|
|
3183 |
get_key_scans_params must be called before this function can be called.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3184 |
|
1
by brian
clean slate |
3185 |
When this function is called by ROR-union construction algorithm it
|
3186 |
assumes it is building an uncovered ROR-intersection (and thus # of full
|
|
3187 |
records to be retrieved is wrong here). This is a hack.
|
|
3188 |
||
3189 |
IMPLEMENTATION
|
|
3190 |
The approximate best non-covering plan search algorithm is as follows:
|
|
3191 |
||
3192 |
find_min_ror_intersection_scan()
|
|
3193 |
{
|
|
3194 |
R= select all ROR scans;
|
|
3195 |
order R by (E(#records_matched) * key_record_length).
|
|
3196 |
||
3197 |
S= first(R); -- set of scans that will be used for ROR-intersection
|
|
3198 |
R= R-first(S);
|
|
3199 |
min_cost= cost(S);
|
|
3200 |
min_scan= make_scan(S);
|
|
3201 |
while (R is not empty)
|
|
3202 |
{
|
|
3203 |
firstR= R - first(R);
|
|
3204 |
if (!selectivity(S + firstR < selectivity(S)))
|
|
3205 |
continue;
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3206 |
|
1
by brian
clean slate |
3207 |
S= S + first(R);
|
3208 |
if (cost(S) < min_cost)
|
|
3209 |
{
|
|
3210 |
min_cost= cost(S);
|
|
3211 |
min_scan= make_scan(S);
|
|
3212 |
}
|
|
3213 |
}
|
|
3214 |
return min_scan;
|
|
3215 |
}
|
|
3216 |
||
3217 |
See ror_intersect_add function for ROR intersection costs.
|
|
3218 |
||
3219 |
Special handling for Clustered PK scans
|
|
3220 |
Clustered PK contains all table fields, so using it as a regular scan in
|
|
3221 |
index intersection doesn't make sense: a range scan on CPK will be less
|
|
3222 |
expensive in this case.
|
|
3223 |
Clustered PK scan has special handling in ROR-intersection: it is not used
|
|
3224 |
to retrieve rows, instead its condition is used to filter row references
|
|
3225 |
we get from scans on other keys.
|
|
3226 |
||
3227 |
RETURN
|
|
3228 |
ROR-intersection table read plan
|
|
3229 |
NULL if out of memory or no suitable plan found.
|
|
3230 |
*/
|
|
3231 |
||
3232 |
static
|
|
3233 |
TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree, |
|
3234 |
double read_time, |
|
3235 |
bool *are_all_covering) |
|
3236 |
{
|
|
482
by Brian Aker
Remove uint. |
3237 |
uint32_t idx; |
1
by brian
clean slate |
3238 |
double min_cost= DBL_MAX; |
3239 |
||
3240 |
if ((tree->n_ror_scans < 2) || !param->table->file->stats.records) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3241 |
return NULL; |
1
by brian
clean slate |
3242 |
|
3243 |
/*
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3244 |
Step1: Collect ROR-able SEL_ARGs and create ROR_SCAN_INFO for each of
|
1
by brian
clean slate |
3245 |
them. Also find and save clustered PK scan if there is one.
|
3246 |
*/
|
|
3247 |
ROR_SCAN_INFO **cur_ror_scan; |
|
3248 |
ROR_SCAN_INFO *cpk_scan= NULL; |
|
482
by Brian Aker
Remove uint. |
3249 |
uint32_t cpk_no; |
55
by brian
Update for using real bool types. |
3250 |
bool cpk_scan_used= false; |
1
by brian
clean slate |
3251 |
|
3252 |
if (!(tree->ror_scans= (ROR_SCAN_INFO**)alloc_root(param->mem_root, |
|
3253 |
sizeof(ROR_SCAN_INFO*)* |
|
3254 |
param->keys))) |
|
3255 |
return NULL; |
|
3256 |
cpk_no= ((param->table->file->primary_key_is_clustered()) ? |
|
3257 |
param->table->s->primary_key : MAX_KEY); |
|
3258 |
||
3259 |
for (idx= 0, cur_ror_scan= tree->ror_scans; idx < param->keys; idx++) |
|
3260 |
{
|
|
3261 |
ROR_SCAN_INFO *scan; |
|
3262 |
if (!tree->ror_scans_map.is_set(idx)) |
|
3263 |
continue; |
|
3264 |
if (!(scan= make_ror_scan(param, idx, tree->keys[idx]))) |
|
3265 |
return NULL; |
|
3266 |
if (param->real_keynr[idx] == cpk_no) |
|
3267 |
{
|
|
3268 |
cpk_scan= scan; |
|
3269 |
tree->n_ror_scans--; |
|
3270 |
}
|
|
3271 |
else
|
|
3272 |
*(cur_ror_scan++)= scan; |
|
3273 |
}
|
|
3274 |
||
3275 |
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. |
3276 |
print_ror_scans_arr(param->table, "original", |
1
by brian
clean slate |
3277 |
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. |
3278 |
tree->ror_scans_end); |
1
by brian
clean slate |
3279 |
/*
|
3280 |
Ok, [ror_scans, ror_scans_end) is array of ptrs to initialized
|
|
3281 |
ROR_SCAN_INFO's.
|
|
3282 |
Step 2: Get best ROR-intersection using an approximate algorithm.
|
|
3283 |
*/
|
|
3284 |
my_qsort(tree->ror_scans, tree->n_ror_scans, sizeof(ROR_SCAN_INFO*), |
|
3285 |
(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. |
3286 |
print_ror_scans_arr(param->table, "ordered", |
1
by brian
clean slate |
3287 |
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. |
3288 |
tree->ror_scans_end); |
1
by brian
clean slate |
3289 |
|
3290 |
ROR_SCAN_INFO **intersect_scans; /* ROR scans used in index intersection */ |
|
3291 |
ROR_SCAN_INFO **intersect_scans_end; |
|
3292 |
if (!(intersect_scans= (ROR_SCAN_INFO**)alloc_root(param->mem_root, |
|
3293 |
sizeof(ROR_SCAN_INFO*)* |
|
3294 |
tree->n_ror_scans))) |
|
3295 |
return NULL; |
|
3296 |
intersect_scans_end= intersect_scans; |
|
3297 |
||
3298 |
/* Create and incrementally update ROR intersection. */
|
|
3299 |
ROR_INTERSECT_INFO *intersect, *intersect_best; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3300 |
if (!(intersect= ror_intersect_init(param)) || |
1
by brian
clean slate |
3301 |
!(intersect_best= ror_intersect_init(param))) |
3302 |
return NULL; |
|
3303 |
||
3304 |
/* [intersect_scans,intersect_scans_best) will hold the best intersection */
|
|
3305 |
ROR_SCAN_INFO **intersect_scans_best; |
|
3306 |
cur_ror_scan= tree->ror_scans; |
|
3307 |
intersect_scans_best= intersect_scans; |
|
3308 |
while (cur_ror_scan != tree->ror_scans_end && !intersect->is_covering) |
|
3309 |
{
|
|
3310 |
/* S= S + first(R); R= R - first(R); */
|
|
55
by brian
Update for using real bool types. |
3311 |
if (!ror_intersect_add(intersect, *cur_ror_scan, false)) |
1
by brian
clean slate |
3312 |
{
|
3313 |
cur_ror_scan++; |
|
3314 |
continue; |
|
3315 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3316 |
|
1
by brian
clean slate |
3317 |
*(intersect_scans_end++)= *(cur_ror_scan++); |
3318 |
||
3319 |
if (intersect->total_cost < min_cost) |
|
3320 |
{
|
|
3321 |
/* Local minimum found, save it */
|
|
3322 |
ror_intersect_cpy(intersect_best, intersect); |
|
3323 |
intersect_scans_best= intersect_scans_end; |
|
3324 |
min_cost = intersect->total_cost; |
|
3325 |
}
|
|
3326 |
}
|
|
3327 |
||
3328 |
if (intersect_scans_best == intersect_scans) |
|
3329 |
{
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3330 |
return NULL; |
1
by brian
clean slate |
3331 |
}
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3332 |
|
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. |
3333 |
print_ror_scans_arr(param->table, |
1
by brian
clean slate |
3334 |
"best ROR-intersection", |
3335 |
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. |
3336 |
intersect_scans_best); |
1
by brian
clean slate |
3337 |
|
3338 |
*are_all_covering= intersect->is_covering; |
|
482
by Brian Aker
Remove uint. |
3339 |
uint32_t best_num= intersect_scans_best - intersect_scans; |
1
by brian
clean slate |
3340 |
ror_intersect_cpy(intersect, intersect_best); |
3341 |
||
3342 |
/*
|
|
3343 |
Ok, found the best ROR-intersection of non-CPK key scans.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3344 |
Check if we should add a CPK scan. If the obtained ROR-intersection is
|
1
by brian
clean slate |
3345 |
covering, it doesn't make sense to add CPK scan.
|
3346 |
*/
|
|
3347 |
if (cpk_scan && !intersect->is_covering) |
|
3348 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3349 |
if (ror_intersect_add(intersect, cpk_scan, true) && |
1
by brian
clean slate |
3350 |
(intersect->total_cost < min_cost)) |
3351 |
{
|
|
55
by brian
Update for using real bool types. |
3352 |
cpk_scan_used= true; |
1
by brian
clean slate |
3353 |
intersect_best= intersect; //just set pointer here |
3354 |
}
|
|
3355 |
}
|
|
3356 |
||
3357 |
/* Ok, return ROR-intersect plan if we have found one */
|
|
3358 |
TRP_ROR_INTERSECT *trp= NULL; |
|
3359 |
if (min_cost < read_time && (cpk_scan_used || best_num > 1)) |
|
3360 |
{
|
|
3361 |
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. |
3362 |
return(trp); |
1
by brian
clean slate |
3363 |
if (!(trp->first_scan= |
3364 |
(ROR_SCAN_INFO**)alloc_root(param->mem_root, |
|
3365 |
sizeof(ROR_SCAN_INFO*)*best_num))) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3366 |
return NULL; |
1
by brian
clean slate |
3367 |
memcpy(trp->first_scan, intersect_scans, best_num*sizeof(ROR_SCAN_INFO*)); |
3368 |
trp->last_scan= trp->first_scan + best_num; |
|
3369 |
trp->is_covering= intersect_best->is_covering; |
|
3370 |
trp->read_cost= intersect_best->total_cost; |
|
3371 |
/* Prevent divisons by zero */
|
|
3372 |
ha_rows best_rows = double2rows(intersect_best->out_rows); |
|
3373 |
if (!best_rows) |
|
3374 |
best_rows= 1; |
|
3375 |
set_if_smaller(param->table->quick_condition_rows, best_rows); |
|
3376 |
trp->records= best_rows; |
|
3377 |
trp->index_scan_costs= intersect_best->index_scan_costs; |
|
3378 |
trp->cpk_scan= cpk_scan_used? cpk_scan: NULL; |
|
3379 |
}
|
|
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. |
3380 |
return(trp); |
1
by brian
clean slate |
3381 |
}
|
3382 |
||
3383 |
||
3384 |
/*
|
|
3385 |
Get best covering ROR-intersection.
|
|
3386 |
SYNOPSIS
|
|
3387 |
get_best_covering_ror_intersect()
|
|
3388 |
param Parameter from test_quick_select function.
|
|
3389 |
tree SEL_TREE with sets of intervals for different keys.
|
|
3390 |
read_time Don't return table read plans with cost > read_time.
|
|
3391 |
||
3392 |
RETURN
|
|
3393 |
Best covering ROR-intersection plan
|
|
3394 |
NULL if no plan found.
|
|
3395 |
||
3396 |
NOTES
|
|
3397 |
get_best_ror_intersect must be called for a tree before calling this
|
|
3398 |
function for it.
|
|
3399 |
This function invalidates tree->ror_scans member values.
|
|
3400 |
||
3401 |
The following approximate algorithm is used:
|
|
3402 |
I=set of all covering indexes
|
|
3403 |
F=set of all fields to cover
|
|
3404 |
S={}
|
|
3405 |
||
3406 |
do
|
|
3407 |
{
|
|
3408 |
Order I by (#covered fields in F desc,
|
|
3409 |
#components asc,
|
|
3410 |
number of first not covered component asc);
|
|
3411 |
F=F-covered by first(I);
|
|
3412 |
S=S+first(I);
|
|
3413 |
I=I-first(I);
|
|
3414 |
} while F is not empty.
|
|
3415 |
*/
|
|
3416 |
||
3417 |
static
|
|
3418 |
TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param, |
|
3419 |
SEL_TREE *tree, |
|
3420 |
double read_time) |
|
3421 |
{
|
|
3422 |
ROR_SCAN_INFO **ror_scan_mark; |
|
3423 |
ROR_SCAN_INFO **ror_scans_end= tree->ror_scans_end; |
|
3424 |
||
3425 |
for (ROR_SCAN_INFO **scan= tree->ror_scans; scan != ror_scans_end; ++scan) |
|
3426 |
(*scan)->key_components= |
|
3427 |
param->table->key_info[(*scan)->keynr].key_parts; |
|
3428 |
||
3429 |
/*
|
|
3430 |
Run covering-ROR-search algorithm.
|
|
3431 |
Assume set I is [ror_scan .. ror_scans_end)
|
|
3432 |
*/
|
|
3433 |
||
3434 |
/*I=set of all covering indexes */
|
|
3435 |
ror_scan_mark= tree->ror_scans; |
|
3436 |
||
3437 |
MY_BITMAP *covered_fields= ¶m->tmp_covered_fields; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3438 |
if (!covered_fields->bitmap) |
1
by brian
clean slate |
3439 |
covered_fields->bitmap= (my_bitmap_map*)alloc_root(param->mem_root, |
3440 |
param->fields_bitmap_size); |
|
3441 |
if (!covered_fields->bitmap || |
|
3442 |
bitmap_init(covered_fields, covered_fields->bitmap, |
|
55
by brian
Update for using real bool types. |
3443 |
param->table->s->fields, false)) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3444 |
return 0; |
1
by brian
clean slate |
3445 |
bitmap_clear_all(covered_fields); |
3446 |
||
3447 |
double total_cost= 0.0f; |
|
3448 |
ha_rows records=0; |
|
3449 |
bool all_covered; |
|
3450 |
||
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. |
3451 |
print_ror_scans_arr(param->table, |
1
by brian
clean slate |
3452 |
"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. |
3453 |
ror_scan_mark, ror_scans_end); |
1
by brian
clean slate |
3454 |
do
|
3455 |
{
|
|
3456 |
/*
|
|
3457 |
Update changed sorting info:
|
|
3458 |
#covered fields,
|
|
3459 |
number of first not covered component
|
|
3460 |
Calculate and save these values for each of remaining scans.
|
|
3461 |
*/
|
|
3462 |
for (ROR_SCAN_INFO **scan= ror_scan_mark; scan != ror_scans_end; ++scan) |
|
3463 |
{
|
|
3464 |
bitmap_subtract(&(*scan)->covered_fields, covered_fields); |
|
3465 |
(*scan)->used_fields_covered= |
|
3466 |
bitmap_bits_set(&(*scan)->covered_fields); |
|
3467 |
(*scan)->first_uncovered_field= |
|
3468 |
bitmap_get_first(&(*scan)->covered_fields); |
|
3469 |
}
|
|
3470 |
||
3471 |
my_qsort(ror_scan_mark, ror_scans_end-ror_scan_mark, sizeof(ROR_SCAN_INFO*), |
|
3472 |
(qsort_cmp)cmp_ror_scan_info_covering); |
|
3473 |
||
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. |
3474 |
print_ror_scans_arr(param->table, |
1
by brian
clean slate |
3475 |
"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. |
3476 |
ror_scan_mark, ror_scans_end); |
1
by brian
clean slate |
3477 |
|
3478 |
/* I=I-first(I) */
|
|
3479 |
total_cost += (*ror_scan_mark)->index_read_cost; |
|
3480 |
records += (*ror_scan_mark)->records; |
|
3481 |
if (total_cost > read_time) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3482 |
return NULL; |
1
by brian
clean slate |
3483 |
/* F=F-covered by first(I) */
|
3484 |
bitmap_union(covered_fields, &(*ror_scan_mark)->covered_fields); |
|
3485 |
all_covered= bitmap_is_subset(¶m->needed_fields, covered_fields); |
|
3486 |
} while ((++ror_scan_mark < ror_scans_end) && !all_covered); |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3487 |
|
1
by brian
clean slate |
3488 |
if (!all_covered || (ror_scan_mark - tree->ror_scans) == 1) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3489 |
return NULL; |
1
by brian
clean slate |
3490 |
|
3491 |
/*
|
|
3492 |
Ok, [tree->ror_scans .. ror_scan) holds covering index_intersection with
|
|
3493 |
cost total_cost.
|
|
3494 |
*/
|
|
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. |
3495 |
print_ror_scans_arr(param->table, |
1
by brian
clean slate |
3496 |
"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. |
3497 |
tree->ror_scans, ror_scan_mark); |
1
by brian
clean slate |
3498 |
|
3499 |
/* Add priority queue use cost. */
|
|
3500 |
total_cost += rows2double(records)* |
|
3501 |
log((double)(ror_scan_mark - tree->ror_scans)) / |
|
3502 |
(TIME_FOR_COMPARE_ROWID * M_LN2); |
|
3503 |
||
3504 |
if (total_cost > read_time) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3505 |
return NULL; |
1
by brian
clean slate |
3506 |
|
3507 |
TRP_ROR_INTERSECT *trp; |
|
3508 |
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. |
3509 |
return(trp); |
482
by Brian Aker
Remove uint. |
3510 |
uint32_t best_num= (ror_scan_mark - tree->ror_scans); |
1
by brian
clean slate |
3511 |
if (!(trp->first_scan= (ROR_SCAN_INFO**)alloc_root(param->mem_root, |
3512 |
sizeof(ROR_SCAN_INFO*)* |
|
3513 |
best_num))) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3514 |
return NULL; |
1
by brian
clean slate |
3515 |
memcpy(trp->first_scan, tree->ror_scans, best_num*sizeof(ROR_SCAN_INFO*)); |
3516 |
trp->last_scan= trp->first_scan + best_num; |
|
55
by brian
Update for using real bool types. |
3517 |
trp->is_covering= true; |
1
by brian
clean slate |
3518 |
trp->read_cost= total_cost; |
3519 |
trp->records= records; |
|
3520 |
trp->cpk_scan= NULL; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3521 |
set_if_smaller(param->table->quick_condition_rows, records); |
1
by brian
clean slate |
3522 |
|
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. |
3523 |
return(trp); |
1
by brian
clean slate |
3524 |
}
|
3525 |
||
3526 |
||
3527 |
/*
|
|
3528 |
Get best "range" table read plan for given SEL_TREE, also update some info
|
|
3529 |
||
3530 |
SYNOPSIS
|
|
3531 |
get_key_scans_params()
|
|
3532 |
param Parameters from test_quick_select
|
|
3533 |
tree Make range select for this SEL_TREE
|
|
55
by brian
Update for using real bool types. |
3534 |
index_read_must_be_used true <=> assume 'index only' option will be set
|
1
by brian
clean slate |
3535 |
(except for clustered PK indexes)
|
55
by brian
Update for using real bool types. |
3536 |
update_tbl_stats true <=> update table->quick_* with information
|
1
by brian
clean slate |
3537 |
about range scans we've evaluated.
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3538 |
read_time Maximum cost. i.e. don't create read plans with
|
1
by brian
clean slate |
3539 |
cost > read_time.
|
3540 |
||
3541 |
DESCRIPTION
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3542 |
Find the best "range" table read plan for given SEL_TREE.
|
3543 |
The side effects are
|
|
1
by brian
clean slate |
3544 |
- tree->ror_scans is updated to indicate which scans are ROR scans.
|
55
by brian
Update for using real bool types. |
3545 |
- if update_tbl_stats=true then table->quick_* is updated with info
|
1
by brian
clean slate |
3546 |
about every possible range scan.
|
3547 |
||
3548 |
RETURN
|
|
3549 |
Best range read plan
|
|
3550 |
NULL if no plan found or error occurred
|
|
3551 |
*/
|
|
3552 |
||
3553 |
static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3554 |
bool index_read_must_be_used, |
1
by brian
clean slate |
3555 |
bool update_tbl_stats, |
3556 |
double read_time) |
|
3557 |
{
|
|
482
by Brian Aker
Remove uint. |
3558 |
uint32_t idx; |
1
by brian
clean slate |
3559 |
SEL_ARG **key,**end, **key_to_read= NULL; |
3560 |
ha_rows best_records= 0; |
|
482
by Brian Aker
Remove uint. |
3561 |
uint32_t best_mrr_flags= 0, best_buf_size= 0; |
1
by brian
clean slate |
3562 |
TRP_RANGE* read_plan= NULL; |
3563 |
/*
|
|
3564 |
Note that there may be trees that have type SEL_TREE::KEY but contain no
|
|
3565 |
key reads at all, e.g. tree for expression "key1 is not null" where key1
|
|
3566 |
is defined as "not null".
|
|
3567 |
*/
|
|
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. |
3568 |
print_sel_tree(param, tree, &tree->keys_map, "tree scans"); |
1
by brian
clean slate |
3569 |
tree->ror_scans_map.clear_all(); |
3570 |
tree->n_ror_scans= 0; |
|
3571 |
for (idx= 0,key=tree->keys, end=key+param->keys; key != end; key++,idx++) |
|
3572 |
{
|
|
3573 |
if (*key) |
|
3574 |
{
|
|
3575 |
ha_rows found_records; |
|
3576 |
COST_VECT cost; |
|
3577 |
double found_read_time; |
|
482
by Brian Aker
Remove uint. |
3578 |
uint32_t mrr_flags, buf_size; |
3579 |
uint32_t keynr= param->real_keynr[idx]; |
|
1
by brian
clean slate |
3580 |
if ((*key)->type == SEL_ARG::MAYBE_KEY || |
3581 |
(*key)->maybe_flag) |
|
3582 |
param->needed_reg->set_bit(keynr); |
|
3583 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3584 |
bool read_index_only= index_read_must_be_used || |
1
by brian
clean slate |
3585 |
param->table->covering_keys.is_set(keynr); |
3586 |
||
3587 |
found_records= check_quick_select(param, idx, read_index_only, *key, |
|
3588 |
update_tbl_stats, &mrr_flags, |
|
3589 |
&buf_size, &cost); |
|
3590 |
found_read_time= cost.total_cost(); |
|
3591 |
if ((found_records != HA_POS_ERROR) && param->is_ror_scan) |
|
3592 |
{
|
|
3593 |
tree->n_ror_scans++; |
|
3594 |
tree->ror_scans_map.set_bit(idx); |
|
3595 |
}
|
|
3596 |
if (read_time > found_read_time && found_records != HA_POS_ERROR) |
|
3597 |
{
|
|
3598 |
read_time= found_read_time; |
|
3599 |
best_records= found_records; |
|
3600 |
key_to_read= key; |
|
3601 |
best_mrr_flags= mrr_flags; |
|
3602 |
best_buf_size= buf_size; |
|
3603 |
}
|
|
3604 |
}
|
|
3605 |
}
|
|
3606 |
||
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. |
3607 |
print_sel_tree(param, tree, &tree->ror_scans_map, "ROR scans"); |
1
by brian
clean slate |
3608 |
if (key_to_read) |
3609 |
{
|
|
3610 |
idx= key_to_read - tree->keys; |
|
3611 |
if ((read_plan= new (param->mem_root) TRP_RANGE(*key_to_read, idx, |
|
3612 |
best_mrr_flags))) |
|
3613 |
{
|
|
3614 |
read_plan->records= best_records; |
|
3615 |
read_plan->is_ror= tree->ror_scans_map.is_set(idx); |
|
3616 |
read_plan->read_cost= read_time; |
|
3617 |
read_plan->mrr_buf_size= best_buf_size; |
|
3618 |
}
|
|
3619 |
}
|
|
3620 |
||
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. |
3621 |
return(read_plan); |
1
by brian
clean slate |
3622 |
}
|
3623 |
||
3624 |
||
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
3625 |
QUICK_SELECT_I *TRP_INDEX_MERGE::make_quick(PARAM *param, bool, MEM_ROOT *) |
1
by brian
clean slate |
3626 |
{
|
3627 |
QUICK_INDEX_MERGE_SELECT *quick_imerge; |
|
3628 |
QUICK_RANGE_SELECT *quick; |
|
3629 |
/* index_merge always retrieves full rows, ignore retrieve_full_rows */
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
3630 |
if (!(quick_imerge= new QUICK_INDEX_MERGE_SELECT(param->session, param->table))) |
1
by brian
clean slate |
3631 |
return NULL; |
3632 |
||
3633 |
quick_imerge->records= records; |
|
3634 |
quick_imerge->read_time= read_cost; |
|
3635 |
for (TRP_RANGE **range_scan= range_scans; range_scan != range_scans_end; |
|
3636 |
range_scan++) |
|
3637 |
{
|
|
3638 |
if (!(quick= (QUICK_RANGE_SELECT*) |
|
55
by brian
Update for using real bool types. |
3639 |
((*range_scan)->make_quick(param, false, &quick_imerge->alloc)))|| |
1
by brian
clean slate |
3640 |
quick_imerge->push_quick_back(quick)) |
3641 |
{
|
|
3642 |
delete quick; |
|
3643 |
delete quick_imerge; |
|
3644 |
return NULL; |
|
3645 |
}
|
|
3646 |
}
|
|
3647 |
return quick_imerge; |
|
3648 |
}
|
|
3649 |
||
3650 |
QUICK_SELECT_I *TRP_ROR_INTERSECT::make_quick(PARAM *param, |
|
3651 |
bool retrieve_full_rows, |
|
3652 |
MEM_ROOT *parent_alloc) |
|
3653 |
{
|
|
3654 |
QUICK_ROR_INTERSECT_SELECT *quick_intrsect; |
|
3655 |
QUICK_RANGE_SELECT *quick; |
|
3656 |
MEM_ROOT *alloc; |
|
3657 |
||
3658 |
if ((quick_intrsect= |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
3659 |
new QUICK_ROR_INTERSECT_SELECT(param->session, param->table, |
1
by brian
clean slate |
3660 |
(retrieve_full_rows? (!is_covering) : |
55
by brian
Update for using real bool types. |
3661 |
false), |
1
by brian
clean slate |
3662 |
parent_alloc))) |
3663 |
{
|
|
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. |
3664 |
print_ror_scans_arr(param->table, |
1
by brian
clean slate |
3665 |
"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. |
3666 |
first_scan, last_scan); |
1
by brian
clean slate |
3667 |
alloc= parent_alloc? parent_alloc: &quick_intrsect->alloc; |
3668 |
for (; first_scan != last_scan;++first_scan) |
|
3669 |
{
|
|
3670 |
if (!(quick= get_quick_select(param, (*first_scan)->idx, |
|
3671 |
(*first_scan)->sel_arg, |
|
3672 |
HA_MRR_USE_DEFAULT_IMPL | HA_MRR_SORTED, |
|
3673 |
0, alloc)) || |
|
3674 |
quick_intrsect->push_quick_back(quick)) |
|
3675 |
{
|
|
3676 |
delete quick_intrsect; |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3677 |
return NULL; |
1
by brian
clean slate |
3678 |
}
|
3679 |
}
|
|
3680 |
if (cpk_scan) |
|
3681 |
{
|
|
3682 |
if (!(quick= get_quick_select(param, cpk_scan->idx, |
|
3683 |
cpk_scan->sel_arg, |
|
3684 |
HA_MRR_USE_DEFAULT_IMPL | HA_MRR_SORTED, |
|
3685 |
0, alloc))) |
|
3686 |
{
|
|
3687 |
delete quick_intrsect; |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3688 |
return NULL; |
1
by brian
clean slate |
3689 |
}
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3690 |
quick->file= NULL; |
1
by brian
clean slate |
3691 |
quick_intrsect->cpk_quick= quick; |
3692 |
}
|
|
3693 |
quick_intrsect->records= records; |
|
3694 |
quick_intrsect->read_time= read_cost; |
|
3695 |
}
|
|
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. |
3696 |
return(quick_intrsect); |
1
by brian
clean slate |
3697 |
}
|
3698 |
||
3699 |
||
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
3700 |
QUICK_SELECT_I *TRP_ROR_UNION::make_quick(PARAM *param, bool, MEM_ROOT *) |
1
by brian
clean slate |
3701 |
{
|
3702 |
QUICK_ROR_UNION_SELECT *quick_roru; |
|
3703 |
TABLE_READ_PLAN **scan; |
|
3704 |
QUICK_SELECT_I *quick; |
|
3705 |
/*
|
|
3706 |
It is impossible to construct a ROR-union that will not retrieve full
|
|
3707 |
rows, ignore retrieve_full_rows parameter.
|
|
3708 |
*/
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
3709 |
if ((quick_roru= new QUICK_ROR_UNION_SELECT(param->session, param->table))) |
1
by brian
clean slate |
3710 |
{
|
3711 |
for (scan= first_ror; scan != last_ror; scan++) |
|
3712 |
{
|
|
55
by brian
Update for using real bool types. |
3713 |
if (!(quick= (*scan)->make_quick(param, false, &quick_roru->alloc)) || |
1
by brian
clean slate |
3714 |
quick_roru->push_quick_back(quick)) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3715 |
return NULL; |
1
by brian
clean slate |
3716 |
}
|
3717 |
quick_roru->records= records; |
|
3718 |
quick_roru->read_time= read_cost; |
|
3719 |
}
|
|
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. |
3720 |
return(quick_roru); |
1
by brian
clean slate |
3721 |
}
|
3722 |
||
3723 |
||
3724 |
/*
|
|
3725 |
Build a SEL_TREE for <> or NOT BETWEEN predicate
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3726 |
|
1
by brian
clean slate |
3727 |
SYNOPSIS
|
3728 |
get_ne_mm_tree()
|
|
3729 |
param PARAM from SQL_SELECT::test_quick_select
|
|
3730 |
cond_func item for the predicate
|
|
3731 |
field field in the predicate
|
|
3732 |
lt_value constant that field should be smaller
|
|
3733 |
gt_value constant that field should be greaterr
|
|
3734 |
cmp_type compare type for the field
|
|
3735 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3736 |
RETURN
|
1
by brian
clean slate |
3737 |
# Pointer to tree built tree
|
3738 |
0 on error
|
|
3739 |
*/
|
|
3740 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3741 |
static SEL_TREE *get_ne_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func, |
1
by brian
clean slate |
3742 |
Field *field, |
3743 |
Item *lt_value, Item *gt_value, |
|
3744 |
Item_result cmp_type) |
|
3745 |
{
|
|
3746 |
SEL_TREE *tree; |
|
3747 |
tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC, |
|
3748 |
lt_value, cmp_type); |
|
3749 |
if (tree) |
|
3750 |
{
|
|
3751 |
tree= tree_or(param, tree, get_mm_parts(param, cond_func, field, |
|
3752 |
Item_func::GT_FUNC, |
|
3753 |
gt_value, cmp_type)); |
|
3754 |
}
|
|
3755 |
return tree; |
|
3756 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3757 |
|
1
by brian
clean slate |
3758 |
|
3759 |
/*
|
|
3760 |
Build a SEL_TREE for a simple predicate
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3761 |
|
1
by brian
clean slate |
3762 |
SYNOPSIS
|
3763 |
get_func_mm_tree()
|
|
3764 |
param PARAM from SQL_SELECT::test_quick_select
|
|
3765 |
cond_func item for the predicate
|
|
3766 |
field field in the predicate
|
|
3767 |
value constant in the predicate
|
|
3768 |
cmp_type compare type for the field
|
|
55
by brian
Update for using real bool types. |
3769 |
inv true <> NOT cond_func is considered
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3770 |
(makes sense only when cond_func is BETWEEN or IN)
|
1
by brian
clean slate |
3771 |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3772 |
RETURN
|
1
by brian
clean slate |
3773 |
Pointer to the tree built tree
|
3774 |
*/
|
|
3775 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3776 |
static SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func, |
1
by brian
clean slate |
3777 |
Field *field, Item *value, |
3778 |
Item_result cmp_type, bool inv) |
|
3779 |
{
|
|
3780 |
SEL_TREE *tree= 0; |
|
3781 |
||
3782 |
switch (cond_func->functype()) { |
|
3783 |
||
3784 |
case Item_func::NE_FUNC: |
|
3785 |
tree= get_ne_mm_tree(param, cond_func, field, value, value, cmp_type); |
|
3786 |
break; |
|
3787 |
||
3788 |
case Item_func::BETWEEN: |
|
3789 |
{
|
|
3790 |
if (!value) |
|
3791 |
{
|
|
3792 |
if (inv) |
|
3793 |
{
|
|
3794 |
tree= get_ne_mm_tree(param, cond_func, field, cond_func->arguments()[1], |
|
3795 |
cond_func->arguments()[2], cmp_type); |
|
3796 |
}
|
|
3797 |
else
|
|
3798 |
{
|
|
3799 |
tree= get_mm_parts(param, cond_func, field, Item_func::GE_FUNC, |
|
3800 |
cond_func->arguments()[1],cmp_type); |
|
3801 |
if (tree) |
|
3802 |
{
|
|
3803 |
tree= tree_and(param, tree, get_mm_parts(param, cond_func, field, |
|
3804 |
Item_func::LE_FUNC, |
|
3805 |
cond_func->arguments()[2], |
|
3806 |
cmp_type)); |
|
3807 |
}
|
|
3808 |
}
|
|
3809 |
}
|
|
3810 |
else
|
|
3811 |
tree= get_mm_parts(param, cond_func, field, |
|
3812 |
(inv ? |
|
3813 |
(value == (Item*)1 ? Item_func::GT_FUNC : |
|
3814 |
Item_func::LT_FUNC): |
|
3815 |
(value == (Item*)1 ? Item_func::LE_FUNC : |
|
3816 |
Item_func::GE_FUNC)), |
|
3817 |
cond_func->arguments()[0], cmp_type); |
|
3818 |
break; |
|
3819 |
}
|
|
3820 |
case Item_func::IN_FUNC: |
|
3821 |
{
|
|
3822 |
Item_func_in *func=(Item_func_in*) cond_func; |
|
3823 |
||
3824 |
/*
|
|
3825 |
Array for IN() is constructed when all values have the same result
|
|
3826 |
type. Tree won't be built for values with different result types,
|
|
3827 |
so we check it here to avoid unnecessary work.
|
|
3828 |
*/
|
|
3829 |
if (!func->arg_types_compatible) |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3830 |
break; |
1
by brian
clean slate |
3831 |
|
3832 |
if (inv) |
|
3833 |
{
|
|
3834 |
if (func->array && func->array->result_type() != ROW_RESULT) |
|
3835 |
{
|
|
3836 |
/*
|
|
3837 |
We get here for conditions in form "t.key NOT IN (c1, c2, ...)",
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3838 |
where c{i} are constants. Our goal is to produce a SEL_TREE that
|
1
by brian
clean slate |
3839 |
represents intervals:
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3840 |
|
1
by brian
clean slate |
3841 |
($MIN<t.key<c1) OR (c1<t.key<c2) OR (c2<t.key<c3) OR ... (*)
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3842 |
|
1
by brian
clean slate |
3843 |
where $MIN is either "-inf" or NULL.
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3844 |
|
1
by brian
clean slate |
3845 |
The most straightforward way to produce it is to convert NOT IN
|
3846 |
into "(t.key != c1) AND (t.key != c2) AND ... " and let the range
|
|
3847 |
analyzer to build SEL_TREE from that. The problem is that the
|
|
3848 |
range analyzer will use O(N^2) memory (which is probably a bug),
|
|
3849 |
and people do use big NOT IN lists (e.g. see BUG#15872, BUG#21282),
|
|
3850 |
will run out of memory.
|
|
3851 |
||
3852 |
Another problem with big lists like (*) is that a big list is
|
|
3853 |
unlikely to produce a good "range" access, while considering that
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3854 |
range access will require expensive CPU calculations (and for
|
1
by brian
clean slate |
3855 |
MyISAM even index accesses). In short, big NOT IN lists are rarely
|
3856 |
worth analyzing.
|
|
3857 |
||
3858 |
Considering the above, we'll handle NOT IN as follows:
|
|
3859 |
* if the number of entries in the NOT IN list is less than
|
|
3860 |
NOT_IN_IGNORE_THRESHOLD, construct the SEL_TREE (*) manually.
|
|
3861 |
* Otherwise, don't produce a SEL_TREE.
|
|
3862 |
*/
|
|
3863 |
#define NOT_IN_IGNORE_THRESHOLD 1000
|
|
3864 |
MEM_ROOT *tmp_root= param->mem_root; |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
3865 |
param->session->mem_root= param->old_root; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3866 |
/*
|
1
by brian
clean slate |
3867 |
Create one Item_type constant object. We'll need it as
|
3868 |
get_mm_parts only accepts constant values wrapped in Item_Type
|
|
3869 |
objects.
|
|
3870 |
We create the Item on param->mem_root which points to
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
3871 |
per-statement mem_root (while session->mem_root is currently pointing
|
1
by brian
clean slate |
3872 |
to mem_root local to range optimizer).
|
3873 |
*/
|
|
3874 |
Item *value_item= func->array->create_item(); |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
3875 |
param->session->mem_root= tmp_root; |
1
by brian
clean slate |
3876 |
|
3877 |
if (func->array->count > NOT_IN_IGNORE_THRESHOLD || !value_item) |
|
3878 |
break; |
|
3879 |
||
3880 |
/* Get a SEL_TREE for "(-inf|NULL) < X < c_0" interval. */
|
|
482
by Brian Aker
Remove uint. |
3881 |
uint32_t i=0; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3882 |
do
|
1
by brian
clean slate |
3883 |
{
|
3884 |
func->array->value_to_item(i, value_item); |
|
3885 |
tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC, |
|
3886 |
value_item, cmp_type); |
|
3887 |
if (!tree) |
|
3888 |
break; |
|
3889 |
i++; |
|
3890 |
} while (i < func->array->count && tree->type == SEL_TREE::IMPOSSIBLE); |
|
3891 |
||
3892 |
if (!tree || tree->type == SEL_TREE::IMPOSSIBLE) |
|
3893 |
{
|
|
3894 |
/* We get here in cases like "t.unsigned NOT IN (-1,-2,-3) */
|
|
3895 |
tree= NULL; |
|
3896 |
break; |
|
3897 |
}
|
|
3898 |
SEL_TREE *tree2; |
|
3899 |
for (; i < func->array->count; i++) |
|
3900 |
{
|
|
3901 |
if (func->array->compare_elems(i, i-1)) |
|
3902 |
{
|
|
3903 |
/* Get a SEL_TREE for "-inf < X < c_i" interval */
|
|
3904 |
func->array->value_to_item(i, value_item); |
|
3905 |
tree2= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC, |
|
3906 |
value_item, cmp_type); |
|
3907 |
if (!tree2) |
|
3908 |
{
|
|
3909 |
tree= NULL; |
|
3910 |
break; |
|
3911 |
}
|
|
3912 |
||
3913 |
/* Change all intervals to be "c_{i-1} < X < c_i" */
|
|
482
by Brian Aker
Remove uint. |
3914 |
for (uint32_t idx= 0; idx < param->keys; idx++) |
1
by brian
clean slate |
3915 |
{
|
3916 |
SEL_ARG *new_interval, *last_val; |
|
3917 |
if (((new_interval= tree2->keys[idx])) && |
|
3918 |
(tree->keys[idx]) && |
|
3919 |
((last_val= tree->keys[idx]->last()))) |
|
3920 |
{
|
|
3921 |
new_interval->min_value= last_val->max_value; |
|
3922 |
new_interval->min_flag= NEAR_MIN; |
|
3923 |
}
|
|
3924 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3925 |
/*
|
1
by brian
clean slate |
3926 |
The following doesn't try to allocate memory so no need to
|
3927 |
check for NULL.
|
|
3928 |
*/
|
|
3929 |
tree= tree_or(param, tree, tree2); |
|
3930 |
}
|
|
3931 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3932 |
|
1
by brian
clean slate |
3933 |
if (tree && tree->type != SEL_TREE::IMPOSSIBLE) |
3934 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3935 |
/*
|
3936 |
Get the SEL_TREE for the last "c_last < X < +inf" interval
|
|
1
by brian
clean slate |
3937 |
(value_item cotains c_last already)
|
3938 |
*/
|
|
3939 |
tree2= get_mm_parts(param, cond_func, field, Item_func::GT_FUNC, |
|
3940 |
value_item, cmp_type); |
|
3941 |
tree= tree_or(param, tree, tree2); |
|
3942 |
}
|
|
3943 |
}
|
|
3944 |
else
|
|
3945 |
{
|
|
3946 |
tree= get_ne_mm_tree(param, cond_func, field, |
|
3947 |
func->arguments()[1], func->arguments()[1], |
|
3948 |
cmp_type); |
|
3949 |
if (tree) |
|
3950 |
{
|
|
3951 |
Item **arg, **end; |
|
3952 |
for (arg= func->arguments()+2, end= arg+func->argument_count()-2; |
|
3953 |
arg < end ; arg++) |
|
3954 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3955 |
tree= tree_and(param, tree, get_ne_mm_tree(param, cond_func, field, |
1
by brian
clean slate |
3956 |
*arg, *arg, cmp_type)); |
3957 |
}
|
|
3958 |
}
|
|
3959 |
}
|
|
3960 |
}
|
|
3961 |
else
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3962 |
{
|
1
by brian
clean slate |
3963 |
tree= get_mm_parts(param, cond_func, field, Item_func::EQ_FUNC, |
3964 |
func->arguments()[1], cmp_type); |
|
3965 |
if (tree) |
|
3966 |
{
|
|
3967 |
Item **arg, **end; |
|
3968 |
for (arg= func->arguments()+2, end= arg+func->argument_count()-2; |
|
3969 |
arg < end ; arg++) |
|
3970 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3971 |
tree= tree_or(param, tree, get_mm_parts(param, cond_func, field, |
1
by brian
clean slate |
3972 |
Item_func::EQ_FUNC, |
3973 |
*arg, cmp_type)); |
|
3974 |
}
|
|
3975 |
}
|
|
3976 |
}
|
|
3977 |
break; |
|
3978 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3979 |
default: |
1
by brian
clean slate |
3980 |
{
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3981 |
/*
|
1
by brian
clean slate |
3982 |
Here the function for the following predicates are processed:
|
3983 |
<, <=, =, >=, >, LIKE, IS NULL, IS NOT NULL.
|
|
3984 |
If the predicate is of the form (value op field) it is handled
|
|
3985 |
as the equivalent predicate (field rev_op value), e.g.
|
|
3986 |
2 <= a is handled as a >= 2.
|
|
3987 |
*/
|
|
3988 |
Item_func::Functype func_type= |
|
3989 |
(value != cond_func->arguments()[0]) ? cond_func->functype() : |
|
3990 |
((Item_bool_func2*) cond_func)->rev_functype(); |
|
3991 |
tree= get_mm_parts(param, cond_func, field, func_type, value, cmp_type); |
|
3992 |
}
|
|
3993 |
}
|
|
3994 |
||
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. |
3995 |
return(tree); |
1
by brian
clean slate |
3996 |
}
|
3997 |
||
3998 |
||
3999 |
/*
|
|
4000 |
Build conjunction of all SEL_TREEs for a simple predicate applying equalities
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4001 |
|
1
by brian
clean slate |
4002 |
SYNOPSIS
|
4003 |
get_full_func_mm_tree()
|
|
4004 |
param PARAM from SQL_SELECT::test_quick_select
|
|
4005 |
cond_func item for the predicate
|
|
4006 |
field_item field in the predicate
|
|
4007 |
value constant in the predicate
|
|
4008 |
(for BETWEEN it contains the number of the field argument,
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4009 |
for IN it's always 0)
|
55
by brian
Update for using real bool types. |
4010 |
inv true <> NOT cond_func is considered
|
1
by brian
clean slate |
4011 |
(makes sense only when cond_func is BETWEEN or IN)
|
4012 |
||
4013 |
DESCRIPTION
|
|
4014 |
For a simple SARGable predicate of the form (f op c), where f is a field and
|
|
4015 |
c is a constant, the function builds a conjunction of all SEL_TREES that can
|
|
4016 |
be obtained by the substitution of f for all different fields equal to f.
|
|
4017 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4018 |
NOTES
|
1
by brian
clean slate |
4019 |
If the WHERE condition contains a predicate (fi op c),
|
4020 |
then not only SELL_TREE for this predicate is built, but
|
|
4021 |
the trees for the results of substitution of fi for
|
|
4022 |
each fj belonging to the same multiple equality as fi
|
|
4023 |
are built as well.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4024 |
E.g. for WHERE t1.a=t2.a AND t2.a > 10
|
1
by brian
clean slate |
4025 |
a SEL_TREE for t2.a > 10 will be built for quick select from t2
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4026 |
and
|
1
by brian
clean slate |
4027 |
a SEL_TREE for t1.a > 10 will be built for quick select from t1.
|
4028 |
||
4029 |
A BETWEEN predicate of the form (fi [NOT] BETWEEN c1 AND c2) is treated
|
|
4030 |
in a similar way: we build a conjuction of trees for the results
|
|
4031 |
of all substitutions of fi for equal fj.
|
|
4032 |
Yet a predicate of the form (c BETWEEN f1i AND f2i) is processed
|
|
4033 |
differently. It is considered as a conjuction of two SARGable
|
|
4034 |
predicates (f1i <= c) and (f2i <=c) and the function get_full_func_mm_tree
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4035 |
is called for each of them separately producing trees for
|
4036 |
AND j (f1j <=c ) and AND j (f2j <= c)
|
|
1
by brian
clean slate |
4037 |
After this these two trees are united in one conjunctive tree.
|
4038 |
It's easy to see that the same tree is obtained for
|
|
4039 |
AND j,k (f1j <=c AND f2k<=c)
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4040 |
which is equivalent to
|
1
by brian
clean slate |
4041 |
AND j,k (c BETWEEN f1j AND f2k).
|
4042 |
The validity of the processing of the predicate (c NOT BETWEEN f1i AND f2i)
|
|
4043 |
which equivalent to (f1i > c OR f2i < c) is not so obvious. Here the
|
|
4044 |
function get_full_func_mm_tree is called for (f1i > c) and (f2i < c)
|
|
4045 |
producing trees for AND j (f1j > c) and AND j (f2j < c). Then this two
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4046 |
trees are united in one OR-tree. The expression
|
1
by brian
clean slate |
4047 |
(AND j (f1j > c) OR AND j (f2j < c)
|
4048 |
is equivalent to the expression
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4049 |
AND j,k (f1j > c OR f2k < c)
|
4050 |
which is just a translation of
|
|
1
by brian
clean slate |
4051 |
AND j,k (c NOT BETWEEN f1j AND f2k)
|
4052 |
||
4053 |
In the cases when one of the items f1, f2 is a constant c1 we do not create
|
|
4054 |
a tree for it at all. It works for BETWEEN predicates but does not
|
|
4055 |
work for NOT BETWEEN predicates as we have to evaluate the expression
|
|
55
by brian
Update for using real bool types. |
4056 |
with it. If it is true then the other tree can be completely ignored.
|
1
by brian
clean slate |
4057 |
We do not do it now and no trees are built in these cases for
|
4058 |
NOT BETWEEN predicates.
|
|
4059 |
||
4060 |
As to IN predicates only ones of the form (f IN (c1,...,cn)),
|
|
4061 |
where f1 is a field and c1,...,cn are constant, are considered as
|
|
4062 |
SARGable. We never try to narrow the index scan using predicates of
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4063 |
the form (c IN (c1,...,f,...,cn)).
|
4064 |
||
4065 |
RETURN
|
|
1
by brian
clean slate |
4066 |
Pointer to the tree representing the built conjunction of SEL_TREEs
|
4067 |
*/
|
|
4068 |
||
4069 |
static SEL_TREE *get_full_func_mm_tree(RANGE_OPT_PARAM *param, |
|
4070 |
Item_func *cond_func, |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4071 |
Item_field *field_item, Item *value, |
1
by brian
clean slate |
4072 |
bool inv) |
4073 |
{
|
|
4074 |
SEL_TREE *tree= 0; |
|
4075 |
SEL_TREE *ftree= 0; |
|
4076 |
table_map ref_tables= 0; |
|
4077 |
table_map param_comp= ~(param->prev_tables | param->read_tables | |
|
4078 |
param->current_table); |
|
4079 |
||
482
by Brian Aker
Remove uint. |
4080 |
for (uint32_t i= 0; i < cond_func->arg_count; i++) |
1
by brian
clean slate |
4081 |
{
|
4082 |
Item *arg= cond_func->arguments()[i]->real_item(); |
|
4083 |
if (arg != field_item) |
|
4084 |
ref_tables|= arg->used_tables(); |
|
4085 |
}
|
|
4086 |
Field *field= field_item->field; |
|
4087 |
Item_result cmp_type= field->cmp_type(); |
|
4088 |
if (!((ref_tables | field->table->map) & param_comp)) |
|
4089 |
ftree= get_func_mm_tree(param, cond_func, field, value, cmp_type, inv); |
|
4090 |
Item_equal *item_equal= field_item->item_equal; |
|
4091 |
if (item_equal) |
|
4092 |
{
|
|
4093 |
Item_equal_iterator it(*item_equal); |
|
4094 |
Item_field *item; |
|
4095 |
while ((item= it++)) |
|
4096 |
{
|
|
4097 |
Field *f= item->field; |
|
4098 |
if (field->eq(f)) |
|
4099 |
continue; |
|
4100 |
if (!((ref_tables | f->table->map) & param_comp)) |
|
4101 |
{
|
|
4102 |
tree= get_func_mm_tree(param, cond_func, f, value, cmp_type, inv); |
|
4103 |
ftree= !ftree ? tree : tree_and(param, ftree, tree); |
|
4104 |
}
|
|
4105 |
}
|
|
4106 |
}
|
|
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. |
4107 |
return(ftree); |
1
by brian
clean slate |
4108 |
}
|
4109 |
||
4110 |
/* make a select tree of all keys in condition */
|
|
4111 |
||
4112 |
static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond) |
|
4113 |
{
|
|
4114 |
SEL_TREE *tree=0; |
|
4115 |
SEL_TREE *ftree= 0; |
|
4116 |
Item_field *field_item= 0; |
|
55
by brian
Update for using real bool types. |
4117 |
bool inv= false; |
1
by brian
clean slate |
4118 |
Item *value= 0; |
4119 |
||
4120 |
if (cond->type() == Item::COND_ITEM) |
|
4121 |
{
|
|
4122 |
List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); |
|
4123 |
||
4124 |
if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) |
|
4125 |
{
|
|
4126 |
tree=0; |
|
4127 |
Item *item; |
|
4128 |
while ((item=li++)) |
|
4129 |
{
|
|
4130 |
SEL_TREE *new_tree=get_mm_tree(param,item); |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4131 |
if (param->session->is_fatal_error || |
1
by brian
clean slate |
4132 |
param->alloced_sel_args > SEL_ARG::MAX_SEL_ARGS) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4133 |
return 0; // out of memory |
1
by brian
clean slate |
4134 |
tree=tree_and(param,tree,new_tree); |
4135 |
if (tree && tree->type == SEL_TREE::IMPOSSIBLE) |
|
4136 |
break; |
|
4137 |
}
|
|
4138 |
}
|
|
4139 |
else
|
|
4140 |
{ // COND OR |
|
4141 |
tree=get_mm_tree(param,li++); |
|
4142 |
if (tree) |
|
4143 |
{
|
|
4144 |
Item *item; |
|
4145 |
while ((item=li++)) |
|
4146 |
{
|
|
4147 |
SEL_TREE *new_tree=get_mm_tree(param,item); |
|
4148 |
if (!new_tree) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4149 |
return 0; // out of memory |
1
by brian
clean slate |
4150 |
tree=tree_or(param,tree,new_tree); |
4151 |
if (!tree || tree->type == SEL_TREE::ALWAYS) |
|
4152 |
break; |
|
4153 |
}
|
|
4154 |
}
|
|
4155 |
}
|
|
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. |
4156 |
return(tree); |
1
by brian
clean slate |
4157 |
}
|
4158 |
/* Here when simple cond */
|
|
4159 |
if (cond->const_item()) |
|
4160 |
{
|
|
4161 |
/*
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4162 |
During the cond->val_int() evaluation we can come across a subselect
|
4163 |
item which may allocate memory on the session->mem_root and assumes
|
|
4164 |
all the memory allocated has the same life span as the subselect
|
|
1
by brian
clean slate |
4165 |
item itself. So we have to restore the thread's mem_root here.
|
4166 |
*/
|
|
4167 |
MEM_ROOT *tmp_root= param->mem_root; |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
4168 |
param->session->mem_root= param->old_root; |
1
by brian
clean slate |
4169 |
tree= cond->val_int() ? new(tmp_root) SEL_TREE(SEL_TREE::ALWAYS) : |
4170 |
new(tmp_root) SEL_TREE(SEL_TREE::IMPOSSIBLE); |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
4171 |
param->session->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. |
4172 |
return(tree); |
1
by brian
clean slate |
4173 |
}
|
4174 |
||
4175 |
table_map ref_tables= 0; |
|
4176 |
table_map param_comp= ~(param->prev_tables | param->read_tables | |
|
4177 |
param->current_table); |
|
4178 |
if (cond->type() != Item::FUNC_ITEM) |
|
4179 |
{ // Should be a field |
|
4180 |
ref_tables= cond->used_tables(); |
|
4181 |
if ((ref_tables & param->current_table) || |
|
4182 |
(ref_tables & ~(param->prev_tables | param->read_tables))) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4183 |
return 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. |
4184 |
return(new SEL_TREE(SEL_TREE::MAYBE)); |
1
by brian
clean slate |
4185 |
}
|
4186 |
||
4187 |
Item_func *cond_func= (Item_func*) cond; |
|
4188 |
if (cond_func->functype() == Item_func::BETWEEN || |
|
4189 |
cond_func->functype() == Item_func::IN_FUNC) |
|
4190 |
inv= ((Item_func_opt_neg *) cond_func)->negated; |
|
4191 |
else if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4192 |
return 0; |
1
by brian
clean slate |
4193 |
|
4194 |
param->cond= cond; |
|
4195 |
||
4196 |
switch (cond_func->functype()) { |
|
4197 |
case Item_func::BETWEEN: |
|
4198 |
if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM) |
|
4199 |
{
|
|
4200 |
field_item= (Item_field*) (cond_func->arguments()[0]->real_item()); |
|
4201 |
ftree= get_full_func_mm_tree(param, cond_func, field_item, NULL, inv); |
|
4202 |
}
|
|
4203 |
||
4204 |
/*
|
|
4205 |
Concerning the code below see the NOTES section in
|
|
4206 |
the comments for the function get_full_func_mm_tree()
|
|
4207 |
*/
|
|
482
by Brian Aker
Remove uint. |
4208 |
for (uint32_t i= 1 ; i < cond_func->arg_count ; i++) |
1
by brian
clean slate |
4209 |
{
|
4210 |
if (cond_func->arguments()[i]->real_item()->type() == Item::FIELD_ITEM) |
|
4211 |
{
|
|
4212 |
field_item= (Item_field*) (cond_func->arguments()[i]->real_item()); |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4213 |
SEL_TREE *tmp= get_full_func_mm_tree(param, cond_func, |
157
by Brian Aker
Second pass cleanup on removal of my_uint types |
4214 |
field_item, (Item*)(intptr_t)i, inv); |
1
by brian
clean slate |
4215 |
if (inv) |
4216 |
tree= !tree ? tmp : tree_or(param, tree, tmp); |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4217 |
else
|
1
by brian
clean slate |
4218 |
tree= tree_and(param, tree, tmp); |
4219 |
}
|
|
4220 |
else if (inv) |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4221 |
{
|
1
by brian
clean slate |
4222 |
tree= 0; |
4223 |
break; |
|
4224 |
}
|
|
4225 |
}
|
|
4226 |
||
4227 |
ftree = tree_and(param, ftree, tree); |
|
4228 |
break; |
|
4229 |
case Item_func::IN_FUNC: |
|
4230 |
{
|
|
4231 |
Item_func_in *func=(Item_func_in*) cond_func; |
|
4232 |
if (func->key_item()->real_item()->type() != Item::FIELD_ITEM) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4233 |
return 0; |
1
by brian
clean slate |
4234 |
field_item= (Item_field*) (func->key_item()->real_item()); |
4235 |
ftree= get_full_func_mm_tree(param, cond_func, field_item, NULL, inv); |
|
4236 |
break; |
|
4237 |
}
|
|
4238 |
case Item_func::MULT_EQUAL_FUNC: |
|
4239 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4240 |
Item_equal *item_equal= (Item_equal *) cond; |
1
by brian
clean slate |
4241 |
if (!(value= item_equal->get_const())) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4242 |
return 0; |
1
by brian
clean slate |
4243 |
Item_equal_iterator it(*item_equal); |
4244 |
ref_tables= value->used_tables(); |
|
4245 |
while ((field_item= it++)) |
|
4246 |
{
|
|
4247 |
Field *field= field_item->field; |
|
4248 |
Item_result cmp_type= field->cmp_type(); |
|
4249 |
if (!((ref_tables | field->table->map) & param_comp)) |
|
4250 |
{
|
|
4251 |
tree= get_mm_parts(param, cond, field, Item_func::EQ_FUNC, |
|
4252 |
value,cmp_type); |
|
4253 |
ftree= !ftree ? tree : tree_and(param, ftree, tree); |
|
4254 |
}
|
|
4255 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4256 |
|
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. |
4257 |
return(ftree); |
1
by brian
clean slate |
4258 |
}
|
4259 |
default: |
|
4260 |
if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM) |
|
4261 |
{
|
|
4262 |
field_item= (Item_field*) (cond_func->arguments()[0]->real_item()); |
|
4263 |
value= cond_func->arg_count > 1 ? cond_func->arguments()[1] : 0; |
|
4264 |
}
|
|
4265 |
else if (cond_func->have_rev_func() && |
|
4266 |
cond_func->arguments()[1]->real_item()->type() == |
|
4267 |
Item::FIELD_ITEM) |
|
4268 |
{
|
|
4269 |
field_item= (Item_field*) (cond_func->arguments()[1]->real_item()); |
|
4270 |
value= cond_func->arguments()[0]; |
|
4271 |
}
|
|
4272 |
else
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4273 |
return 0; |
1
by brian
clean slate |
4274 |
ftree= get_full_func_mm_tree(param, cond_func, field_item, value, inv); |
4275 |
}
|
|
4276 |
||
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. |
4277 |
return(ftree); |
1
by brian
clean slate |
4278 |
}
|
4279 |
||
4280 |
||
4281 |
static SEL_TREE * |
|
4282 |
get_mm_parts(RANGE_OPT_PARAM *param, COND *cond_func, Field *field, |
|
4283 |
Item_func::Functype type, |
|
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
4284 |
Item *value, Item_result) |
1
by brian
clean slate |
4285 |
{
|
4286 |
if (field->table != param->table) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4287 |
return 0; |
1
by brian
clean slate |
4288 |
|
4289 |
KEY_PART *key_part = param->key_parts; |
|
4290 |
KEY_PART *end = param->key_parts_end; |
|
4291 |
SEL_TREE *tree=0; |
|
4292 |
if (value && |
|
4293 |
value->used_tables() & ~(param->prev_tables | param->read_tables)) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4294 |
return 0; |
1
by brian
clean slate |
4295 |
for (; key_part != end ; key_part++) |
4296 |
{
|
|
4297 |
if (field->eq(key_part->field)) |
|
4298 |
{
|
|
4299 |
SEL_ARG *sel_arg=0; |
|
4300 |
if (!tree && !(tree=new SEL_TREE())) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4301 |
return 0; // OOM |
1
by brian
clean slate |
4302 |
if (!value || !(value->used_tables() & ~param->read_tables)) |
4303 |
{
|
|
4304 |
sel_arg=get_mm_leaf(param,cond_func, |
|
4305 |
key_part->field,key_part,type,value); |
|
4306 |
if (!sel_arg) |
|
4307 |
continue; |
|
4308 |
if (sel_arg->type == SEL_ARG::IMPOSSIBLE) |
|
4309 |
{
|
|
4310 |
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. |
4311 |
return(tree); |
1
by brian
clean slate |
4312 |
}
|
4313 |
}
|
|
4314 |
else
|
|
4315 |
{
|
|
4316 |
// This key may be used later
|
|
4317 |
if (!(sel_arg= new SEL_ARG(SEL_ARG::MAYBE_KEY))) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4318 |
return 0; // OOM |
1
by brian
clean slate |
4319 |
}
|
481
by Brian Aker
Remove all of uchar. |
4320 |
sel_arg->part=(unsigned char) key_part->part; |
1
by brian
clean slate |
4321 |
tree->keys[key_part->key]=sel_add(tree->keys[key_part->key],sel_arg); |
4322 |
tree->keys_map.set_bit(key_part->key); |
|
4323 |
}
|
|
4324 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4325 |
|
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. |
4326 |
return(tree); |
1
by brian
clean slate |
4327 |
}
|
4328 |
||
4329 |
||
4330 |
static SEL_ARG * |
|
4331 |
get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, |
|
4332 |
KEY_PART *key_part, Item_func::Functype type,Item *value) |
|
4333 |
{
|
|
895
by Brian Aker
Completion (?) of uint conversion. |
4334 |
uint32_t maybe_null=(uint32_t) field->real_maybe_null(); |
1
by brian
clean slate |
4335 |
bool optimize_range; |
4336 |
SEL_ARG *tree= 0; |
|
4337 |
MEM_ROOT *alloc= param->mem_root; |
|
481
by Brian Aker
Remove all of uchar. |
4338 |
unsigned char *str; |
1
by brian
clean slate |
4339 |
ulong orig_sql_mode; |
4340 |
int err; |
|
4341 |
||
4342 |
/*
|
|
4343 |
We need to restore the runtime mem_root of the thread in this
|
|
4344 |
function because it evaluates the value of its argument, while
|
|
4345 |
the argument can be any, e.g. a subselect. The subselect
|
|
4346 |
items, in turn, assume that all the memory allocated during
|
|
4347 |
the evaluation has the same life span as the item itself.
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
4348 |
TODO: opt_range.cc should not reset session->mem_root at all.
|
1
by brian
clean slate |
4349 |
*/
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
4350 |
param->session->mem_root= param->old_root; |
1
by brian
clean slate |
4351 |
if (!value) // IS NULL or IS NOT NULL |
4352 |
{
|
|
4353 |
if (field->table->maybe_null) // Can't use a key on this |
|
4354 |
goto end; |
|
4355 |
if (!maybe_null) // Not null field |
|
4356 |
{
|
|
4357 |
if (type == Item_func::ISNULL_FUNC) |
|
4358 |
tree= &null_element; |
|
4359 |
goto end; |
|
4360 |
}
|
|
4361 |
if (!(tree= new (alloc) SEL_ARG(field,is_null_string,is_null_string))) |
|
4362 |
goto end; // out of memory |
|
4363 |
if (type == Item_func::ISNOTNULL_FUNC) |
|
4364 |
{
|
|
4365 |
tree->min_flag=NEAR_MIN; /* IS NOT NULL -> X > NULL */ |
|
4366 |
tree->max_flag=NO_MAX_RANGE; |
|
4367 |
}
|
|
4368 |
goto end; |
|
4369 |
}
|
|
4370 |
||
4371 |
/*
|
|
4372 |
1. Usually we can't use an index if the column collation
|
|
4373 |
differ from the operation collation.
|
|
4374 |
||
4375 |
2. However, we can reuse a case insensitive index for
|
|
4376 |
the binary searches:
|
|
4377 |
||
4378 |
WHERE latin1_swedish_ci_column = 'a' COLLATE lati1_bin;
|
|
4379 |
||
4380 |
WHERE latin1_swedish_ci_colimn = BINARY 'a '
|
|
4381 |
||
4382 |
*/
|
|
4383 |
if (field->result_type() == STRING_RESULT && |
|
4384 |
value->result_type() == STRING_RESULT && |
|
4385 |
key_part->image_type == Field::itRAW && |
|
4386 |
((Field_str*)field)->charset() != conf_func->compare_collation() && |
|
4387 |
!(conf_func->compare_collation()->state & MY_CS_BINSORT)) |
|
4388 |
goto end; |
|
4389 |
||
4390 |
if (param->using_real_indexes) |
|
4391 |
optimize_range= field->optimize_range(param->real_keynr[key_part->key], |
|
4392 |
key_part->part); |
|
4393 |
else
|
|
55
by brian
Update for using real bool types. |
4394 |
optimize_range= true; |
1
by brian
clean slate |
4395 |
|
4396 |
if (type == Item_func::LIKE_FUNC) |
|
4397 |
{
|
|
4398 |
bool like_error; |
|
4399 |
char buff1[MAX_FIELD_WIDTH]; |
|
481
by Brian Aker
Remove all of uchar. |
4400 |
unsigned char *min_str,*max_str; |
1
by brian
clean slate |
4401 |
String tmp(buff1,sizeof(buff1),value->collation.collation),*res; |
4402 |
size_t length, offset, min_length, max_length; |
|
482
by Brian Aker
Remove uint. |
4403 |
uint32_t field_length= field->pack_length()+maybe_null; |
1
by brian
clean slate |
4404 |
|
4405 |
if (!optimize_range) |
|
4406 |
goto end; |
|
4407 |
if (!(res= value->val_str(&tmp))) |
|
4408 |
{
|
|
4409 |
tree= &null_element; |
|
4410 |
goto end; |
|
4411 |
}
|
|
4412 |
||
4413 |
/*
|
|
4414 |
TODO:
|
|
4415 |
Check if this was a function. This should have be optimized away
|
|
4416 |
in the sql_select.cc
|
|
4417 |
*/
|
|
4418 |
if (res != &tmp) |
|
4419 |
{
|
|
4420 |
tmp.copy(*res); // Get own copy |
|
4421 |
res= &tmp; |
|
4422 |
}
|
|
4423 |
if (field->cmp_type() != STRING_RESULT) |
|
4424 |
goto end; // Can only optimize strings |
|
4425 |
||
4426 |
offset=maybe_null; |
|
4427 |
length=key_part->store_length; |
|
4428 |
||
4429 |
if (length != key_part->length + maybe_null) |
|
4430 |
{
|
|
4431 |
/* key packed with length prefix */
|
|
4432 |
offset+= HA_KEY_BLOB_LENGTH; |
|
4433 |
field_length= length - HA_KEY_BLOB_LENGTH; |
|
4434 |
}
|
|
4435 |
else
|
|
4436 |
{
|
|
4437 |
if (unlikely(length < field_length)) |
|
4438 |
{
|
|
4439 |
/*
|
|
4440 |
This can only happen in a table created with UNIREG where one key
|
|
4441 |
overlaps many fields
|
|
4442 |
*/
|
|
4443 |
length= field_length; |
|
4444 |
}
|
|
4445 |
else
|
|
4446 |
field_length= length; |
|
4447 |
}
|
|
4448 |
length+=offset; |
|
481
by Brian Aker
Remove all of uchar. |
4449 |
if (!(min_str= (unsigned char*) alloc_root(alloc, length*2))) |
1
by brian
clean slate |
4450 |
goto end; |
4451 |
||
4452 |
max_str=min_str+length; |
|
4453 |
if (maybe_null) |
|
4454 |
max_str[0]= min_str[0]=0; |
|
4455 |
||
4456 |
field_length-= maybe_null; |
|
4457 |
like_error= my_like_range(field->charset(), |
|
4458 |
res->ptr(), res->length(), |
|
4459 |
((Item_func_like*)(param->cond))->escape, |
|
4460 |
wild_one, wild_many, |
|
4461 |
field_length, |
|
4462 |
(char*) min_str+offset, (char*) max_str+offset, |
|
4463 |
&min_length, &max_length); |
|
4464 |
if (like_error) // Can't optimize with LIKE |
|
4465 |
goto end; |
|
4466 |
||
4467 |
if (offset != maybe_null) // BLOB or VARCHAR |
|
4468 |
{
|
|
4469 |
int2store(min_str+maybe_null,min_length); |
|
4470 |
int2store(max_str+maybe_null,max_length); |
|
4471 |
}
|
|
4472 |
tree= new (alloc) SEL_ARG(field, min_str, max_str); |
|
4473 |
goto end; |
|
4474 |
}
|
|
4475 |
||
4476 |
if (!optimize_range && |
|
4477 |
type != Item_func::EQ_FUNC && |
|
4478 |
type != Item_func::EQUAL_FUNC) |
|
4479 |
goto end; // Can't optimize this |
|
4480 |
||
4481 |
/*
|
|
4482 |
We can't always use indexes when comparing a string index to a number
|
|
4483 |
cmp_type() is checked to allow compare of dates to numbers
|
|
4484 |
*/
|
|
4485 |
if (field->result_type() == STRING_RESULT && |
|
4486 |
value->result_type() != STRING_RESULT && |
|
4487 |
field->cmp_type() != value->result_type()) |
|
4488 |
goto end; |
|
4489 |
/* For comparison purposes allow invalid dates like 2000-01-32 */
|
|
4490 |
orig_sql_mode= field->table->in_use->variables.sql_mode; |
|
4491 |
if (value->real_item()->type() == Item::STRING_ITEM && |
|
575.5.1
by David Axmark
Changed NEWDATE to DATE. One failing test but I think its somewhere else in the code |
4492 |
(field->type() == DRIZZLE_TYPE_DATE || |
212.2.2
by Patrick Galbraith
Renamed FIELD_TYPE to DRIZZLE_TYPE |
4493 |
field->type() == DRIZZLE_TYPE_DATETIME)) |
1
by brian
clean slate |
4494 |
field->table->in_use->variables.sql_mode|= MODE_INVALID_DATES; |
4495 |
err= value->save_in_field_no_warnings(field, 1); |
|
4496 |
if (err > 0) |
|
4497 |
{
|
|
4498 |
if (field->cmp_type() != value->result_type()) |
|
4499 |
{
|
|
4500 |
if ((type == Item_func::EQ_FUNC || type == Item_func::EQUAL_FUNC) && |
|
4501 |
value->result_type() == item_cmp_type(field->result_type(), |
|
4502 |
value->result_type())) |
|
4503 |
{
|
|
4504 |
tree= new (alloc) SEL_ARG(field, 0, 0); |
|
4505 |
tree->type= SEL_ARG::IMPOSSIBLE; |
|
4506 |
goto end; |
|
4507 |
}
|
|
4508 |
else
|
|
4509 |
{
|
|
4510 |
/*
|
|
4511 |
TODO: We should return trees of the type SEL_ARG::IMPOSSIBLE
|
|
4512 |
for the cases like int_field > 999999999999999999999999 as well.
|
|
4513 |
*/
|
|
4514 |
tree= 0; |
|
575.5.1
by David Axmark
Changed NEWDATE to DATE. One failing test but I think its somewhere else in the code |
4515 |
if (err == 3 && field->type() == DRIZZLE_TYPE_DATE && |
1
by brian
clean slate |
4516 |
(type == Item_func::GT_FUNC || type == Item_func::GE_FUNC || |
4517 |
type == Item_func::LT_FUNC || type == Item_func::LE_FUNC) ) |
|
4518 |
{
|
|
4519 |
/*
|
|
4520 |
We were saving DATETIME into a DATE column, the conversion went ok
|
|
4521 |
but a non-zero time part was cut off.
|
|
4522 |
||
4523 |
In MySQL's SQL dialect, DATE and DATETIME are compared as datetime
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4524 |
values. Index over a DATE column uses DATE comparison. Changing
|
1
by brian
clean slate |
4525 |
from one comparison to the other is possible:
|
4526 |
||
4527 |
datetime(date_col)< '2007-12-10 12:34:55' -> date_col<='2007-12-10'
|
|
4528 |
datetime(date_col)<='2007-12-10 12:34:55' -> date_col<='2007-12-10'
|
|
4529 |
||
4530 |
datetime(date_col)> '2007-12-10 12:34:55' -> date_col>='2007-12-10'
|
|
4531 |
datetime(date_col)>='2007-12-10 12:34:55' -> date_col>='2007-12-10'
|
|
4532 |
||
4533 |
but we'll need to convert '>' to '>=' and '<' to '<='. This will
|
|
4534 |
be done together with other types at the end of this function
|
|
4535 |
(grep for field_is_equal_to_item)
|
|
4536 |
*/
|
|
4537 |
}
|
|
4538 |
else
|
|
4539 |
goto end; |
|
4540 |
}
|
|
4541 |
}
|
|
4542 |
||
4543 |
/*
|
|
4544 |
guaranteed at this point: err > 0; field and const of same type
|
|
4545 |
If an integer got bounded (e.g. to within 0..255 / -128..127)
|
|
4546 |
for < or >, set flags as for <= or >= (no NEAR_MAX / NEAR_MIN)
|
|
4547 |
*/
|
|
4548 |
else if (err == 1 && field->result_type() == INT_RESULT) |
|
4549 |
{
|
|
4550 |
if (type == Item_func::LT_FUNC && (value->val_int() > 0)) |
|
4551 |
type = Item_func::LE_FUNC; |
|
4552 |
else if (type == Item_func::GT_FUNC && |
|
4553 |
!((Field_num*)field)->unsigned_flag && |
|
4554 |
!((Item_int*)value)->unsigned_flag && |
|
4555 |
(value->val_int() < 0)) |
|
4556 |
type = Item_func::GE_FUNC; |
|
4557 |
}
|
|
4558 |
}
|
|
4559 |
else if (err < 0) |
|
4560 |
{
|
|
4561 |
field->table->in_use->variables.sql_mode= orig_sql_mode; |
|
4562 |
/* This happens when we try to insert a NULL field in a not null column */
|
|
55
by brian
Update for using real bool types. |
4563 |
tree= &null_element; // cmp with NULL is never true |
1
by brian
clean slate |
4564 |
goto end; |
4565 |
}
|
|
4566 |
field->table->in_use->variables.sql_mode= orig_sql_mode; |
|
481
by Brian Aker
Remove all of uchar. |
4567 |
str= (unsigned char*) alloc_root(alloc, key_part->store_length+1); |
1
by brian
clean slate |
4568 |
if (!str) |
4569 |
goto end; |
|
4570 |
if (maybe_null) |
|
481
by Brian Aker
Remove all of uchar. |
4571 |
*str= (unsigned char) field->is_real_null(); // Set to 1 if null |
1
by brian
clean slate |
4572 |
field->get_key_image(str+maybe_null, key_part->length, |
4573 |
key_part->image_type); |
|
4574 |
if (!(tree= new (alloc) SEL_ARG(field, str, str))) |
|
4575 |
goto end; // out of memory |
|
4576 |
||
4577 |
/*
|
|
4578 |
Check if we are comparing an UNSIGNED integer with a negative constant.
|
|
4579 |
In this case we know that:
|
|
55
by brian
Update for using real bool types. |
4580 |
(a) (unsigned_int [< | <=] negative_constant) == false
|
4581 |
(b) (unsigned_int [> | >=] negative_constant) == true
|
|
1
by brian
clean slate |
4582 |
In case (a) the condition is false for all values, and in case (b) it
|
4583 |
is true for all values, so we can avoid unnecessary retrieval and condition
|
|
4584 |
testing, and we also get correct comparison of unsinged integers with
|
|
4585 |
negative integers (which otherwise fails because at query execution time
|
|
4586 |
negative integers are cast to unsigned if compared with unsigned).
|
|
4587 |
*/
|
|
4588 |
if (field->result_type() == INT_RESULT && |
|
4589 |
value->result_type() == INT_RESULT && |
|
4590 |
((Field_num*)field)->unsigned_flag && !((Item_int*)value)->unsigned_flag) |
|
4591 |
{
|
|
152
by Brian Aker
longlong replacement |
4592 |
int64_t item_val= value->val_int(); |
1
by brian
clean slate |
4593 |
if (item_val < 0) |
4594 |
{
|
|
4595 |
if (type == Item_func::LT_FUNC || type == Item_func::LE_FUNC) |
|
4596 |
{
|
|
4597 |
tree->type= SEL_ARG::IMPOSSIBLE; |
|
4598 |
goto end; |
|
4599 |
}
|
|
4600 |
if (type == Item_func::GT_FUNC || type == Item_func::GE_FUNC) |
|
4601 |
{
|
|
4602 |
tree= 0; |
|
4603 |
goto end; |
|
4604 |
}
|
|
4605 |
}
|
|
4606 |
}
|
|
4607 |
||
4608 |
switch (type) { |
|
4609 |
case Item_func::LT_FUNC: |
|
4610 |
if (field_is_equal_to_item(field,value)) |
|
4611 |
tree->max_flag=NEAR_MAX; |
|
4612 |
/* fall through */
|
|
4613 |
case Item_func::LE_FUNC: |
|
4614 |
if (!maybe_null) |
|
4615 |
tree->min_flag=NO_MIN_RANGE; /* From start */ |
|
4616 |
else
|
|
4617 |
{ // > NULL |
|
4618 |
tree->min_value=is_null_string; |
|
4619 |
tree->min_flag=NEAR_MIN; |
|
4620 |
}
|
|
4621 |
break; |
|
4622 |
case Item_func::GT_FUNC: |
|
4623 |
/* Don't use open ranges for partial key_segments */
|
|
4624 |
if (field_is_equal_to_item(field,value) && |
|
4625 |
!(key_part->flag & HA_PART_KEY_SEG)) |
|
4626 |
tree->min_flag=NEAR_MIN; |
|
4627 |
/* fall through */
|
|
4628 |
case Item_func::GE_FUNC: |
|
4629 |
tree->max_flag=NO_MAX_RANGE; |
|
4630 |
break; |
|
4631 |
default: |
|
4632 |
break; |
|
4633 |
}
|
|
4634 |
||
4635 |
end: |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
4636 |
param->session->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. |
4637 |
return(tree); |
1
by brian
clean slate |
4638 |
}
|
4639 |
||
4640 |
||
4641 |
/******************************************************************************
|
|
4642 |
** Tree manipulation functions
|
|
4643 |
** If tree is 0 it means that the condition can't be tested. It refers
|
|
4644 |
** to a non existent table or to a field in current table with isn't a key.
|
|
4645 |
** The different tree flags:
|
|
55
by brian
Update for using real bool types. |
4646 |
** IMPOSSIBLE: Condition is never true
|
4647 |
** ALWAYS: Condition is always true
|
|
1
by brian
clean slate |
4648 |
** MAYBE: Condition may exists when tables are read
|
4649 |
** MAYBE_KEY: Condition refers to a key that may be used in join loop
|
|
4650 |
** KEY_RANGE: Condition uses a key
|
|
4651 |
******************************************************************************/
|
|
4652 |
||
4653 |
/*
|
|
4654 |
Add a new key test to a key when scanning through all keys
|
|
4655 |
This will never be called for same key parts.
|
|
4656 |
*/
|
|
4657 |
||
4658 |
static SEL_ARG * |
|
4659 |
sel_add(SEL_ARG *key1,SEL_ARG *key2) |
|
4660 |
{
|
|
4661 |
SEL_ARG *root,**key_link; |
|
4662 |
||
4663 |
if (!key1) |
|
4664 |
return key2; |
|
4665 |
if (!key2) |
|
4666 |
return key1; |
|
4667 |
||
4668 |
key_link= &root; |
|
4669 |
while (key1 && key2) |
|
4670 |
{
|
|
4671 |
if (key1->part < key2->part) |
|
4672 |
{
|
|
4673 |
*key_link= key1; |
|
4674 |
key_link= &key1->next_key_part; |
|
4675 |
key1=key1->next_key_part; |
|
4676 |
}
|
|
4677 |
else
|
|
4678 |
{
|
|
4679 |
*key_link= key2; |
|
4680 |
key_link= &key2->next_key_part; |
|
4681 |
key2=key2->next_key_part; |
|
4682 |
}
|
|
4683 |
}
|
|
4684 |
*key_link=key1 ? key1 : key2; |
|
4685 |
return root; |
|
4686 |
}
|
|
4687 |
||
4688 |
#define CLONE_KEY1_MAYBE 1
|
|
4689 |
#define CLONE_KEY2_MAYBE 2
|
|
4690 |
#define swap_clone_flag(A) ((A & 1) << 1) | ((A & 2) >> 1)
|
|
4691 |
||
4692 |
||
4693 |
static SEL_TREE * |
|
4694 |
tree_and(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) |
|
4695 |
{
|
|
4696 |
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. |
4697 |
return(tree2); |
1
by brian
clean slate |
4698 |
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. |
4699 |
return(tree1); |
1
by brian
clean slate |
4700 |
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. |
4701 |
return(tree1); |
1
by brian
clean slate |
4702 |
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. |
4703 |
return(tree2); |
1
by brian
clean slate |
4704 |
if (tree1->type == SEL_TREE::MAYBE) |
4705 |
{
|
|
4706 |
if (tree2->type == SEL_TREE::KEY) |
|
4707 |
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. |
4708 |
return(tree2); |
1
by brian
clean slate |
4709 |
}
|
4710 |
if (tree2->type == SEL_TREE::MAYBE) |
|
4711 |
{
|
|
4712 |
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. |
4713 |
return(tree1); |
1
by brian
clean slate |
4714 |
}
|
4715 |
key_map result_keys; |
|
4716 |
result_keys.clear_all(); |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4717 |
|
1
by brian
clean slate |
4718 |
/* Join the trees key per key */
|
4719 |
SEL_ARG **key1,**key2,**end; |
|
4720 |
for (key1= tree1->keys,key2= tree2->keys,end=key1+param->keys ; |
|
4721 |
key1 != end ; key1++,key2++) |
|
4722 |
{
|
|
482
by Brian Aker
Remove uint. |
4723 |
uint32_t flag=0; |
1
by brian
clean slate |
4724 |
if (*key1 || *key2) |
4725 |
{
|
|
4726 |
if (*key1 && !(*key1)->simple_key()) |
|
4727 |
flag|=CLONE_KEY1_MAYBE; |
|
4728 |
if (*key2 && !(*key2)->simple_key()) |
|
4729 |
flag|=CLONE_KEY2_MAYBE; |
|
4730 |
*key1=key_and(param, *key1, *key2, flag); |
|
4731 |
if (*key1 && (*key1)->type == SEL_ARG::IMPOSSIBLE) |
|
4732 |
{
|
|
4733 |
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. |
4734 |
return(tree1); |
1
by brian
clean slate |
4735 |
}
|
4736 |
result_keys.set_bit(key1 - tree1->keys); |
|
4737 |
#ifdef EXTRA_DEBUG
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4738 |
if (*key1 && param->alloced_sel_args < SEL_ARG::MAX_SEL_ARGS) |
1
by brian
clean slate |
4739 |
(*key1)->test_use_count(*key1); |
4740 |
#endif
|
|
4741 |
}
|
|
4742 |
}
|
|
4743 |
tree1->keys_map= result_keys; |
|
4744 |
/* dispose index_merge if there is a "range" option */
|
|
4745 |
if (!result_keys.is_clear_all()) |
|
4746 |
{
|
|
4747 |
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. |
4748 |
return(tree1); |
1
by brian
clean slate |
4749 |
}
|
4750 |
||
4751 |
/* ok, both trees are index_merge trees */
|
|
4752 |
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. |
4753 |
return(tree1); |
1
by brian
clean slate |
4754 |
}
|
4755 |
||
4756 |
||
4757 |
/*
|
|
4758 |
Check if two SEL_TREES can be combined into one (i.e. a single key range
|
|
4759 |
read can be constructed for "cond_of_tree1 OR cond_of_tree2" ) without
|
|
4760 |
using index_merge.
|
|
4761 |
*/
|
|
4762 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4763 |
bool sel_trees_can_be_ored(SEL_TREE *tree1, SEL_TREE *tree2, |
1
by brian
clean slate |
4764 |
RANGE_OPT_PARAM* param) |
4765 |
{
|
|
4766 |
key_map common_keys= tree1->keys_map; |
|
4767 |
common_keys.intersect(tree2->keys_map); |
|
4768 |
||
4769 |
if (common_keys.is_clear_all()) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4770 |
return false; |
1
by brian
clean slate |
4771 |
|
4772 |
/* trees have a common key, check if they refer to same key part */
|
|
4773 |
SEL_ARG **key1,**key2; |
|
482
by Brian Aker
Remove uint. |
4774 |
for (uint32_t key_no=0; key_no < param->keys; key_no++) |
1
by brian
clean slate |
4775 |
{
|
4776 |
if (common_keys.is_set(key_no)) |
|
4777 |
{
|
|
4778 |
key1= tree1->keys + key_no; |
|
4779 |
key2= tree2->keys + key_no; |
|
4780 |
if ((*key1)->part == (*key2)->part) |
|
4781 |
{
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4782 |
return true; |
1
by brian
clean slate |
4783 |
}
|
4784 |
}
|
|
4785 |
}
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4786 |
return false; |
1
by brian
clean slate |
4787 |
}
|
4788 |
||
4789 |
||
4790 |
/*
|
|
4791 |
Remove the trees that are not suitable for record retrieval.
|
|
4792 |
SYNOPSIS
|
|
4793 |
param Range analysis parameter
|
|
4794 |
tree Tree to be processed, tree->type is KEY or KEY_SMALLER
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4795 |
|
1
by brian
clean slate |
4796 |
DESCRIPTION
|
4797 |
This function walks through tree->keys[] and removes the SEL_ARG* trees
|
|
4798 |
that are not "maybe" trees (*) and cannot be used to construct quick range
|
|
4799 |
selects.
|
|
4800 |
(*) - have type MAYBE or MAYBE_KEY. Perhaps we should remove trees of
|
|
4801 |
these types here as well.
|
|
4802 |
||
4803 |
A SEL_ARG* tree cannot be used to construct quick select if it has
|
|
4804 |
tree->part != 0. (e.g. it could represent "keypart2 < const").
|
|
4805 |
||
4806 |
WHY THIS FUNCTION IS NEEDED
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4807 |
|
1
by brian
clean slate |
4808 |
Normally we allow construction of SEL_TREE objects that have SEL_ARG
|
4809 |
trees that do not allow quick range select construction. For example for
|
|
4810 |
" keypart1=1 AND keypart2=2 " the execution will proceed as follows:
|
|
4811 |
tree1= SEL_TREE { SEL_ARG{keypart1=1} }
|
|
4812 |
tree2= SEL_TREE { SEL_ARG{keypart2=2} } -- can't make quick range select
|
|
4813 |
from this
|
|
4814 |
call tree_and(tree1, tree2) -- this joins SEL_ARGs into a usable SEL_ARG
|
|
4815 |
tree.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4816 |
|
1
by brian
clean slate |
4817 |
There is an exception though: when we construct index_merge SEL_TREE,
|
4818 |
any SEL_ARG* tree that cannot be used to construct quick range select can
|
|
4819 |
be removed, because current range analysis code doesn't provide any way
|
|
4820 |
that tree could be later combined with another tree.
|
|
4821 |
Consider an example: we should not construct
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4822 |
st1 = SEL_TREE {
|
4823 |
merges = SEL_IMERGE {
|
|
4824 |
SEL_TREE(t.key1part1 = 1),
|
|
1
by brian
clean slate |
4825 |
SEL_TREE(t.key2part2 = 2) -- (*)
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4826 |
}
|
1
by brian
clean slate |
4827 |
};
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4828 |
because
|
4829 |
- (*) cannot be used to construct quick range select,
|
|
4830 |
- There is no execution path that would cause (*) to be converted to
|
|
1
by brian
clean slate |
4831 |
a tree that could be used.
|
4832 |
||
4833 |
The latter is easy to verify: first, notice that the only way to convert
|
|
4834 |
(*) into a usable tree is to call tree_and(something, (*)).
|
|
4835 |
||
4836 |
Second look at what tree_and/tree_or function would do when passed a
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4837 |
SEL_TREE that has the structure like st1 tree has, and conlcude that
|
1
by brian
clean slate |
4838 |
tree_and(something, (*)) will not be called.
|
4839 |
||
4840 |
RETURN
|
|
4841 |
0 Ok, some suitable trees left
|
|
4842 |
1 No tree->keys[] left.
|
|
4843 |
*/
|
|
4844 |
||
4845 |
static bool remove_nonrange_trees(RANGE_OPT_PARAM *param, SEL_TREE *tree) |
|
4846 |
{
|
|
55
by brian
Update for using real bool types. |
4847 |
bool res= false; |
482
by Brian Aker
Remove uint. |
4848 |
for (uint32_t i=0; i < param->keys; i++) |
1
by brian
clean slate |
4849 |
{
|
4850 |
if (tree->keys[i]) |
|
4851 |
{
|
|
4852 |
if (tree->keys[i]->part) |
|
4853 |
{
|
|
4854 |
tree->keys[i]= NULL; |
|
4855 |
tree->keys_map.clear_bit(i); |
|
4856 |
}
|
|
4857 |
else
|
|
55
by brian
Update for using real bool types. |
4858 |
res= true; |
1
by brian
clean slate |
4859 |
}
|
4860 |
}
|
|
4861 |
return !res; |
|
4862 |
}
|
|
4863 |
||
4864 |
||
4865 |
static SEL_TREE * |
|
4866 |
tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) |
|
4867 |
{
|
|
4868 |
if (!tree1 || !tree2) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4869 |
return 0; |
1
by brian
clean slate |
4870 |
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. |
4871 |
return(tree2); |
1
by brian
clean slate |
4872 |
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. |
4873 |
return(tree1); |
1
by brian
clean slate |
4874 |
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. |
4875 |
return(tree1); // Can't use this |
1
by brian
clean slate |
4876 |
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. |
4877 |
return(tree2); |
1
by brian
clean slate |
4878 |
|
4879 |
SEL_TREE *result= 0; |
|
4880 |
key_map result_keys; |
|
4881 |
result_keys.clear_all(); |
|
4882 |
if (sel_trees_can_be_ored(tree1, tree2, param)) |
|
4883 |
{
|
|
4884 |
/* Join the trees key per key */
|
|
4885 |
SEL_ARG **key1,**key2,**end; |
|
4886 |
for (key1= tree1->keys,key2= tree2->keys,end= key1+param->keys ; |
|
4887 |
key1 != end ; key1++,key2++) |
|
4888 |
{
|
|
4889 |
*key1=key_or(param, *key1, *key2); |
|
4890 |
if (*key1) |
|
4891 |
{
|
|
4892 |
result=tree1; // Added to tree1 |
|
4893 |
result_keys.set_bit(key1 - tree1->keys); |
|
4894 |
#ifdef EXTRA_DEBUG
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4895 |
if (param->alloced_sel_args < SEL_ARG::MAX_SEL_ARGS) |
1
by brian
clean slate |
4896 |
(*key1)->test_use_count(*key1); |
4897 |
#endif
|
|
4898 |
}
|
|
4899 |
}
|
|
4900 |
if (result) |
|
4901 |
result->keys_map= result_keys; |
|
4902 |
}
|
|
4903 |
else
|
|
4904 |
{
|
|
4905 |
/* ok, two trees have KEY type but cannot be used without index merge */
|
|
4906 |
if (tree1->merges.is_empty() && tree2->merges.is_empty()) |
|
4907 |
{
|
|
4908 |
if (param->remove_jump_scans) |
|
4909 |
{
|
|
4910 |
bool no_trees= remove_nonrange_trees(param, tree1); |
|
4911 |
no_trees= no_trees || remove_nonrange_trees(param, tree2); |
|
4912 |
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. |
4913 |
return(new SEL_TREE(SEL_TREE::ALWAYS)); |
1
by brian
clean slate |
4914 |
}
|
4915 |
SEL_IMERGE *merge; |
|
4916 |
/* both trees are "range" trees, produce new index merge structure */
|
|
4917 |
if (!(result= new SEL_TREE()) || !(merge= new SEL_IMERGE()) || |
|
4918 |
(result->merges.push_back(merge)) || |
|
4919 |
(merge->or_sel_tree(param, tree1)) || |
|
4920 |
(merge->or_sel_tree(param, tree2))) |
|
4921 |
result= NULL; |
|
4922 |
else
|
|
4923 |
result->type= tree1->type; |
|
4924 |
}
|
|
4925 |
else if (!tree1->merges.is_empty() && !tree2->merges.is_empty()) |
|
4926 |
{
|
|
4927 |
if (imerge_list_or_list(param, &tree1->merges, &tree2->merges)) |
|
4928 |
result= new SEL_TREE(SEL_TREE::ALWAYS); |
|
4929 |
else
|
|
4930 |
result= tree1; |
|
4931 |
}
|
|
4932 |
else
|
|
4933 |
{
|
|
4934 |
/* one tree is index merge tree and another is range tree */
|
|
4935 |
if (tree1->merges.is_empty()) |
|
322.2.2
by Mats Kindahl
Hiding THD::proc_info field and providing a setter and getter. |
4936 |
std::swap(tree1, tree2); |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4937 |
|
1
by brian
clean slate |
4938 |
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. |
4939 |
return(new SEL_TREE(SEL_TREE::ALWAYS)); |
1
by brian
clean slate |
4940 |
/* add tree2 to tree1->merges, checking if it collapses to ALWAYS */
|
4941 |
if (imerge_list_or_tree(param, &tree1->merges, tree2)) |
|
4942 |
result= new SEL_TREE(SEL_TREE::ALWAYS); |
|
4943 |
else
|
|
4944 |
result= tree1; |
|
4945 |
}
|
|
4946 |
}
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4947 |
return result; |
1
by brian
clean slate |
4948 |
}
|
4949 |
||
4950 |
||
4951 |
/* And key trees where key1->part < key2 -> part */
|
|
4952 |
||
4953 |
static SEL_ARG * |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4954 |
and_all_keys(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, |
482
by Brian Aker
Remove uint. |
4955 |
uint32_t clone_flag) |
1
by brian
clean slate |
4956 |
{
|
4957 |
SEL_ARG *next; |
|
4958 |
ulong use_count=key1->use_count; |
|
4959 |
||
4960 |
if (key1->elements != 1) |
|
4961 |
{
|
|
4962 |
key2->use_count+=key1->elements-1; //psergey: why we don't count that key1 has n-k-p? |
|
4963 |
key2->increment_use_count((int) key1->elements-1); |
|
4964 |
}
|
|
4965 |
if (key1->type == SEL_ARG::MAYBE_KEY) |
|
4966 |
{
|
|
4967 |
key1->right= key1->left= &null_element; |
|
4968 |
key1->next= key1->prev= 0; |
|
4969 |
}
|
|
4970 |
for (next=key1->first(); next ; next=next->next) |
|
4971 |
{
|
|
4972 |
if (next->next_key_part) |
|
4973 |
{
|
|
4974 |
SEL_ARG *tmp= key_and(param, next->next_key_part, key2, clone_flag); |
|
4975 |
if (tmp && tmp->type == SEL_ARG::IMPOSSIBLE) |
|
4976 |
{
|
|
4977 |
key1=key1->tree_delete(next); |
|
4978 |
continue; |
|
4979 |
}
|
|
4980 |
next->next_key_part=tmp; |
|
4981 |
if (use_count) |
|
4982 |
next->increment_use_count(use_count); |
|
4983 |
if (param->alloced_sel_args > SEL_ARG::MAX_SEL_ARGS) |
|
4984 |
break; |
|
4985 |
}
|
|
4986 |
else
|
|
4987 |
next->next_key_part=key2; |
|
4988 |
}
|
|
4989 |
if (!key1) |
|
4990 |
return &null_element; // Impossible ranges |
|
4991 |
key1->use_count++; |
|
4992 |
return key1; |
|
4993 |
}
|
|
4994 |
||
4995 |
||
4996 |
/*
|
|
4997 |
Produce a SEL_ARG graph that represents "key1 AND key2"
|
|
4998 |
||
4999 |
SYNOPSIS
|
|
5000 |
key_and()
|
|
5001 |
param Range analysis context (needed to track if we have allocated
|
|
5002 |
too many SEL_ARGs)
|
|
5003 |
key1 First argument, root of its RB-tree
|
|
5004 |
key2 Second argument, root of its RB-tree
|
|
5005 |
||
5006 |
RETURN
|
|
5007 |
RB-tree root of the resulting SEL_ARG graph.
|
|
5008 |
NULL if the result of AND operation is an empty interval {0}.
|
|
5009 |
*/
|
|
5010 |
||
5011 |
static SEL_ARG * |
|
482
by Brian Aker
Remove uint. |
5012 |
key_and(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, uint32_t clone_flag) |
1
by brian
clean slate |
5013 |
{
|
5014 |
if (!key1) |
|
5015 |
return key2; |
|
5016 |
if (!key2) |
|
5017 |
return key1; |
|
5018 |
if (key1->part != key2->part) |
|
5019 |
{
|
|
5020 |
if (key1->part > key2->part) |
|
5021 |
{
|
|
322.2.2
by Mats Kindahl
Hiding THD::proc_info field and providing a setter and getter. |
5022 |
std::swap(key1, key2); |
1
by brian
clean slate |
5023 |
clone_flag=swap_clone_flag(clone_flag); |
5024 |
}
|
|
5025 |
// key1->part < key2->part
|
|
5026 |
key1->use_count--; |
|
5027 |
if (key1->use_count > 0) |
|
5028 |
if (!(key1= key1->clone_tree(param))) |
|
5029 |
return 0; // OOM |
|
5030 |
return and_all_keys(param, key1, key2, clone_flag); |
|
5031 |
}
|
|
5032 |
||
5033 |
if (((clone_flag & CLONE_KEY2_MAYBE) && |
|
5034 |
!(clone_flag & CLONE_KEY1_MAYBE) && |
|
5035 |
key2->type != SEL_ARG::MAYBE_KEY) || |
|
5036 |
key1->type == SEL_ARG::MAYBE_KEY) |
|
5037 |
{ // Put simple key in key2 |
|
322.2.2
by Mats Kindahl
Hiding THD::proc_info field and providing a setter and getter. |
5038 |
std::swap(key1, key2); |
1
by brian
clean slate |
5039 |
clone_flag=swap_clone_flag(clone_flag); |
5040 |
}
|
|
5041 |
||
5042 |
/* If one of the key is MAYBE_KEY then the found region may be smaller */
|
|
5043 |
if (key2->type == SEL_ARG::MAYBE_KEY) |
|
5044 |
{
|
|
5045 |
if (key1->use_count > 1) |
|
5046 |
{
|
|
5047 |
key1->use_count--; |
|
5048 |
if (!(key1=key1->clone_tree(param))) |
|
5049 |
return 0; // OOM |
|
5050 |
key1->use_count++; |
|
5051 |
}
|
|
5052 |
if (key1->type == SEL_ARG::MAYBE_KEY) |
|
5053 |
{ // Both are maybe key |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5054 |
key1->next_key_part=key_and(param, key1->next_key_part, |
1
by brian
clean slate |
5055 |
key2->next_key_part, clone_flag); |
5056 |
if (key1->next_key_part && |
|
5057 |
key1->next_key_part->type == SEL_ARG::IMPOSSIBLE) |
|
5058 |
return key1; |
|
5059 |
}
|
|
5060 |
else
|
|
5061 |
{
|
|
5062 |
key1->maybe_smaller(); |
|
5063 |
if (key2->next_key_part) |
|
5064 |
{
|
|
5065 |
key1->use_count--; // Incremented in and_all_keys |
|
5066 |
return and_all_keys(param, key1, key2, clone_flag); |
|
5067 |
}
|
|
5068 |
key2->use_count--; // Key2 doesn't have a tree |
|
5069 |
}
|
|
5070 |
return key1; |
|
5071 |
}
|
|
5072 |
||
5073 |
key1->use_count--; |
|
5074 |
key2->use_count--; |
|
5075 |
SEL_ARG *e1=key1->first(), *e2=key2->first(), *new_tree=0; |
|
5076 |
||
5077 |
while (e1 && e2) |
|
5078 |
{
|
|
5079 |
int cmp=e1->cmp_min_to_min(e2); |
|
5080 |
if (cmp < 0) |
|
5081 |
{
|
|
5082 |
if (get_range(&e1,&e2,key1)) |
|
5083 |
continue; |
|
5084 |
}
|
|
5085 |
else if (get_range(&e2,&e1,key2)) |
|
5086 |
continue; |
|
5087 |
SEL_ARG *next=key_and(param, e1->next_key_part, e2->next_key_part, |
|
5088 |
clone_flag); |
|
5089 |
e1->increment_use_count(1); |
|
5090 |
e2->increment_use_count(1); |
|
5091 |
if (!next || next->type != SEL_ARG::IMPOSSIBLE) |
|
5092 |
{
|
|
5093 |
SEL_ARG *new_arg= e1->clone_and(e2); |
|
5094 |
if (!new_arg) |
|
5095 |
return &null_element; // End of memory |
|
5096 |
new_arg->next_key_part=next; |
|
5097 |
if (!new_tree) |
|
5098 |
{
|
|
5099 |
new_tree=new_arg; |
|
5100 |
}
|
|
5101 |
else
|
|
5102 |
new_tree=new_tree->insert(new_arg); |
|
5103 |
}
|
|
5104 |
if (e1->cmp_max_to_max(e2) < 0) |
|
5105 |
e1=e1->next; // e1 can't overlapp next e2 |
|
5106 |
else
|
|
5107 |
e2=e2->next; |
|
5108 |
}
|
|
5109 |
key1->free_tree(); |
|
5110 |
key2->free_tree(); |
|
5111 |
if (!new_tree) |
|
5112 |
return &null_element; // Impossible range |
|
5113 |
return new_tree; |
|
5114 |
}
|
|
5115 |
||
5116 |
||
5117 |
static bool |
|
5118 |
get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1) |
|
5119 |
{
|
|
5120 |
(*e1)=root1->find_range(*e2); // first e1->min < e2->min |
|
5121 |
if ((*e1)->cmp_max_to_min(*e2) < 0) |
|
5122 |
{
|
|
5123 |
if (!((*e1)=(*e1)->next)) |
|
5124 |
return 1; |
|
5125 |
if ((*e1)->cmp_min_to_max(*e2) > 0) |
|
5126 |
{
|
|
5127 |
(*e2)=(*e2)->next; |
|
5128 |
return 1; |
|
5129 |
}
|
|
5130 |
}
|
|
5131 |
return 0; |
|
5132 |
}
|
|
5133 |
||
5134 |
||
5135 |
static SEL_ARG * |
|
5136 |
key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) |
|
5137 |
{
|
|
5138 |
if (!key1) |
|
5139 |
{
|
|
5140 |
if (key2) |
|
5141 |
{
|
|
5142 |
key2->use_count--; |
|
5143 |
key2->free_tree(); |
|
5144 |
}
|
|
5145 |
return 0; |
|
5146 |
}
|
|
5147 |
if (!key2) |
|
5148 |
{
|
|
5149 |
key1->use_count--; |
|
5150 |
key1->free_tree(); |
|
5151 |
return 0; |
|
5152 |
}
|
|
5153 |
key1->use_count--; |
|
5154 |
key2->use_count--; |
|
5155 |
||
5156 |
if (key1->part != key2->part) |
|
5157 |
{
|
|
5158 |
key1->free_tree(); |
|
5159 |
key2->free_tree(); |
|
5160 |
return 0; // Can't optimize this |
|
5161 |
}
|
|
5162 |
||
5163 |
// If one of the key is MAYBE_KEY then the found region may be bigger
|
|
5164 |
if (key1->type == SEL_ARG::MAYBE_KEY) |
|
5165 |
{
|
|
5166 |
key2->free_tree(); |
|
5167 |
key1->use_count++; |
|
5168 |
return key1; |
|
5169 |
}
|
|
5170 |
if (key2->type == SEL_ARG::MAYBE_KEY) |
|
5171 |
{
|
|
5172 |
key1->free_tree(); |
|
5173 |
key2->use_count++; |
|
5174 |
return key2; |
|
5175 |
}
|
|
5176 |
||
5177 |
if (key1->use_count > 0) |
|
5178 |
{
|
|
5179 |
if (key2->use_count == 0 || key1->elements > key2->elements) |
|
5180 |
{
|
|
322.2.2
by Mats Kindahl
Hiding THD::proc_info field and providing a setter and getter. |
5181 |
std::swap(key1,key2); |
1
by brian
clean slate |
5182 |
}
|
5183 |
if (key1->use_count > 0 || !(key1=key1->clone_tree(param))) |
|
5184 |
return 0; // OOM |
|
5185 |
}
|
|
5186 |
||
5187 |
// Add tree at key2 to tree at key1
|
|
5188 |
bool key2_shared=key2->use_count != 0; |
|
5189 |
key1->maybe_flag|=key2->maybe_flag; |
|
5190 |
||
5191 |
for (key2=key2->first(); key2; ) |
|
5192 |
{
|
|
5193 |
SEL_ARG *tmp=key1->find_range(key2); // Find key1.min <= key2.min |
|
5194 |
int cmp; |
|
5195 |
||
5196 |
if (!tmp) |
|
5197 |
{
|
|
5198 |
tmp=key1->first(); // tmp.min > key2.min |
|
5199 |
cmp= -1; |
|
5200 |
}
|
|
5201 |
else if ((cmp=tmp->cmp_max_to_min(key2)) < 0) |
|
5202 |
{ // Found tmp.max < key2.min |
|
5203 |
SEL_ARG *next=tmp->next; |
|
5204 |
if (cmp == -2 && eq_tree(tmp->next_key_part,key2->next_key_part)) |
|
5205 |
{
|
|
5206 |
// Join near ranges like tmp.max < 0 and key2.min >= 0
|
|
5207 |
SEL_ARG *key2_next=key2->next; |
|
5208 |
if (key2_shared) |
|
5209 |
{
|
|
5210 |
if (!(key2=new SEL_ARG(*key2))) |
|
5211 |
return 0; // out of memory |
|
5212 |
key2->increment_use_count(key1->use_count+1); |
|
5213 |
key2->next=key2_next; // New copy of key2 |
|
5214 |
}
|
|
5215 |
key2->copy_min(tmp); |
|
5216 |
if (!(key1=key1->tree_delete(tmp))) |
|
5217 |
{ // Only one key in tree |
|
5218 |
key1=key2; |
|
5219 |
key1->make_root(); |
|
5220 |
key2=key2_next; |
|
5221 |
break; |
|
5222 |
}
|
|
5223 |
}
|
|
5224 |
if (!(tmp=next)) // tmp.min > key2.min |
|
5225 |
break; // Copy rest of key2 |
|
5226 |
}
|
|
5227 |
if (cmp < 0) |
|
5228 |
{ // tmp.min > key2.min |
|
5229 |
int tmp_cmp; |
|
5230 |
if ((tmp_cmp=tmp->cmp_min_to_max(key2)) > 0) // if tmp.min > key2.max |
|
5231 |
{
|
|
5232 |
if (tmp_cmp == 2 && eq_tree(tmp->next_key_part,key2->next_key_part)) |
|
5233 |
{ // ranges are connected |
|
5234 |
tmp->copy_min_to_min(key2); |
|
5235 |
key1->merge_flags(key2); |
|
5236 |
if (tmp->min_flag & NO_MIN_RANGE && |
|
5237 |
tmp->max_flag & NO_MAX_RANGE) |
|
5238 |
{
|
|
5239 |
if (key1->maybe_flag) |
|
5240 |
return new SEL_ARG(SEL_ARG::MAYBE_KEY); |
|
5241 |
return 0; |
|
5242 |
}
|
|
5243 |
key2->increment_use_count(-1); // Free not used tree |
|
5244 |
key2=key2->next; |
|
5245 |
continue; |
|
5246 |
}
|
|
5247 |
else
|
|
5248 |
{
|
|
5249 |
SEL_ARG *next=key2->next; // Keys are not overlapping |
|
5250 |
if (key2_shared) |
|
5251 |
{
|
|
5252 |
SEL_ARG *cpy= new SEL_ARG(*key2); // Must make copy |
|
5253 |
if (!cpy) |
|
5254 |
return 0; // OOM |
|
5255 |
key1=key1->insert(cpy); |
|
5256 |
key2->increment_use_count(key1->use_count+1); |
|
5257 |
}
|
|
5258 |
else
|
|
5259 |
key1=key1->insert(key2); // Will destroy key2_root |
|
5260 |
key2=next; |
|
5261 |
continue; |
|
5262 |
}
|
|
5263 |
}
|
|
5264 |
}
|
|
5265 |
||
398.1.4
by Monty Taylor
Renamed max/min. |
5266 |
// tmp.max >= key2.min && tmp.min <= key.cmax(overlapping ranges)
|
1
by brian
clean slate |
5267 |
if (eq_tree(tmp->next_key_part,key2->next_key_part)) |
5268 |
{
|
|
5269 |
if (tmp->is_same(key2)) |
|
5270 |
{
|
|
5271 |
tmp->merge_flags(key2); // Copy maybe flags |
|
5272 |
key2->increment_use_count(-1); // Free not used tree |
|
5273 |
}
|
|
5274 |
else
|
|
5275 |
{
|
|
5276 |
SEL_ARG *last=tmp; |
|
5277 |
while (last->next && last->next->cmp_min_to_max(key2) <= 0 && |
|
5278 |
eq_tree(last->next->next_key_part,key2->next_key_part)) |
|
5279 |
{
|
|
5280 |
SEL_ARG *save=last; |
|
5281 |
last=last->next; |
|
5282 |
key1=key1->tree_delete(save); |
|
5283 |
}
|
|
5284 |
last->copy_min(tmp); |
|
5285 |
if (last->copy_min(key2) || last->copy_max(key2)) |
|
5286 |
{ // Full range |
|
5287 |
key1->free_tree(); |
|
5288 |
for (; key2 ; key2=key2->next) |
|
5289 |
key2->increment_use_count(-1); // Free not used tree |
|
5290 |
if (key1->maybe_flag) |
|
5291 |
return new SEL_ARG(SEL_ARG::MAYBE_KEY); |
|
5292 |
return 0; |
|
5293 |
}
|
|
5294 |
}
|
|
5295 |
key2=key2->next; |
|
5296 |
continue; |
|
5297 |
}
|
|
5298 |
||
5299 |
if (cmp >= 0 && tmp->cmp_min_to_min(key2) < 0) |
|
5300 |
{ // tmp.min <= x < key2.min |
|
5301 |
SEL_ARG *new_arg=tmp->clone_first(key2); |
|
5302 |
if (!new_arg) |
|
5303 |
return 0; // OOM |
|
5304 |
if ((new_arg->next_key_part= key1->next_key_part)) |
|
5305 |
new_arg->increment_use_count(key1->use_count+1); |
|
5306 |
tmp->copy_min_to_min(key2); |
|
5307 |
key1=key1->insert(new_arg); |
|
5308 |
}
|
|
5309 |
||
5310 |
// tmp.min >= key2.min && tmp.min <= key2.max
|
|
5311 |
SEL_ARG key(*key2); // Get copy we can modify |
|
5312 |
for (;;) |
|
5313 |
{
|
|
5314 |
if (tmp->cmp_min_to_min(&key) > 0) |
|
5315 |
{ // key.min <= x < tmp.min |
|
5316 |
SEL_ARG *new_arg=key.clone_first(tmp); |
|
5317 |
if (!new_arg) |
|
5318 |
return 0; // OOM |
|
5319 |
if ((new_arg->next_key_part=key.next_key_part)) |
|
5320 |
new_arg->increment_use_count(key1->use_count+1); |
|
5321 |
key1=key1->insert(new_arg); |
|
5322 |
}
|
|
5323 |
if ((cmp=tmp->cmp_max_to_max(&key)) <= 0) |
|
5324 |
{ // tmp.min. <= x <= tmp.max |
|
5325 |
tmp->maybe_flag|= key.maybe_flag; |
|
5326 |
key.increment_use_count(key1->use_count+1); |
|
5327 |
tmp->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part); |
|
5328 |
if (!cmp) // Key2 is ready |
|
5329 |
break; |
|
5330 |
key.copy_max_to_min(tmp); |
|
5331 |
if (!(tmp=tmp->next)) |
|
5332 |
{
|
|
5333 |
SEL_ARG *tmp2= new SEL_ARG(key); |
|
5334 |
if (!tmp2) |
|
5335 |
return 0; // OOM |
|
5336 |
key1=key1->insert(tmp2); |
|
5337 |
key2=key2->next; |
|
5338 |
goto end; |
|
5339 |
}
|
|
5340 |
if (tmp->cmp_min_to_max(&key) > 0) |
|
5341 |
{
|
|
5342 |
SEL_ARG *tmp2= new SEL_ARG(key); |
|
5343 |
if (!tmp2) |
|
5344 |
return 0; // OOM |
|
5345 |
key1=key1->insert(tmp2); |
|
5346 |
break; |
|
5347 |
}
|
|
5348 |
}
|
|
5349 |
else
|
|
5350 |
{
|
|
5351 |
SEL_ARG *new_arg=tmp->clone_last(&key); // tmp.min <= x <= key.max |
|
5352 |
if (!new_arg) |
|
5353 |
return 0; // OOM |
|
5354 |
tmp->copy_max_to_min(&key); |
|
5355 |
tmp->increment_use_count(key1->use_count+1); |
|
5356 |
/* Increment key count as it may be used for next loop */
|
|
5357 |
key.increment_use_count(1); |
|
5358 |
new_arg->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part); |
|
5359 |
key1=key1->insert(new_arg); |
|
5360 |
break; |
|
5361 |
}
|
|
5362 |
}
|
|
5363 |
key2=key2->next; |
|
5364 |
}
|
|
5365 |
||
5366 |
end: |
|
5367 |
while (key2) |
|
5368 |
{
|
|
5369 |
SEL_ARG *next=key2->next; |
|
5370 |
if (key2_shared) |
|
5371 |
{
|
|
5372 |
SEL_ARG *tmp=new SEL_ARG(*key2); // Must make copy |
|
5373 |
if (!tmp) |
|
5374 |
return 0; |
|
5375 |
key2->increment_use_count(key1->use_count+1); |
|
5376 |
key1=key1->insert(tmp); |
|
5377 |
}
|
|
5378 |
else
|
|
5379 |
key1=key1->insert(key2); // Will destroy key2_root |
|
5380 |
key2=next; |
|
5381 |
}
|
|
5382 |
key1->use_count++; |
|
5383 |
return key1; |
|
5384 |
}
|
|
5385 |
||
5386 |
||
5387 |
/* Compare if two trees are equal */
|
|
5388 |
||
5389 |
static bool eq_tree(SEL_ARG* a,SEL_ARG *b) |
|
5390 |
{
|
|
5391 |
if (a == b) |
|
5392 |
return 1; |
|
5393 |
if (!a || !b || !a->is_same(b)) |
|
5394 |
return 0; |
|
5395 |
if (a->left != &null_element && b->left != &null_element) |
|
5396 |
{
|
|
5397 |
if (!eq_tree(a->left,b->left)) |
|
5398 |
return 0; |
|
5399 |
}
|
|
5400 |
else if (a->left != &null_element || b->left != &null_element) |
|
5401 |
return 0; |
|
5402 |
if (a->right != &null_element && b->right != &null_element) |
|
5403 |
{
|
|
5404 |
if (!eq_tree(a->right,b->right)) |
|
5405 |
return 0; |
|
5406 |
}
|
|
5407 |
else if (a->right != &null_element || b->right != &null_element) |
|
5408 |
return 0; |
|
5409 |
if (a->next_key_part != b->next_key_part) |
|
5410 |
{ // Sub range |
|
5411 |
if (!a->next_key_part != !b->next_key_part || |
|
5412 |
!eq_tree(a->next_key_part, b->next_key_part)) |
|
5413 |
return 0; |
|
5414 |
}
|
|
5415 |
return 1; |
|
5416 |
}
|
|
5417 |
||
5418 |
||
5419 |
SEL_ARG * |
|
5420 |
SEL_ARG::insert(SEL_ARG *key) |
|
5421 |
{
|
|
5422 |
SEL_ARG *element, **par= NULL, *last_element= NULL; |
|
5423 |
||
5424 |
for (element= this; element != &null_element ; ) |
|
5425 |
{
|
|
5426 |
last_element=element; |
|
5427 |
if (key->cmp_min_to_min(element) > 0) |
|
5428 |
{
|
|
5429 |
par= &element->right; element= element->right; |
|
5430 |
}
|
|
5431 |
else
|
|
5432 |
{
|
|
5433 |
par = &element->left; element= element->left; |
|
5434 |
}
|
|
5435 |
}
|
|
5436 |
*par=key; |
|
5437 |
key->parent=last_element; |
|
5438 |
/* Link in list */
|
|
5439 |
if (par == &last_element->left) |
|
5440 |
{
|
|
5441 |
key->next=last_element; |
|
5442 |
if ((key->prev=last_element->prev)) |
|
5443 |
key->prev->next=key; |
|
5444 |
last_element->prev=key; |
|
5445 |
}
|
|
5446 |
else
|
|
5447 |
{
|
|
5448 |
if ((key->next=last_element->next)) |
|
5449 |
key->next->prev=key; |
|
5450 |
key->prev=last_element; |
|
5451 |
last_element->next=key; |
|
5452 |
}
|
|
5453 |
key->left=key->right= &null_element; |
|
5454 |
SEL_ARG *root=rb_insert(key); // rebalance tree |
|
5455 |
root->use_count=this->use_count; // copy root info |
|
5456 |
root->elements= this->elements+1; |
|
5457 |
root->maybe_flag=this->maybe_flag; |
|
5458 |
return root; |
|
5459 |
}
|
|
5460 |
||
5461 |
||
5462 |
/*
|
|
5463 |
** Find best key with min <= given key
|
|
5464 |
** Because the call context this should never return 0 to get_range
|
|
5465 |
*/
|
|
5466 |
||
5467 |
SEL_ARG * |
|
5468 |
SEL_ARG::find_range(SEL_ARG *key) |
|
5469 |
{
|
|
5470 |
SEL_ARG *element=this,*found=0; |
|
5471 |
||
5472 |
for (;;) |
|
5473 |
{
|
|
5474 |
if (element == &null_element) |
|
5475 |
return found; |
|
5476 |
int cmp=element->cmp_min_to_min(key); |
|
5477 |
if (cmp == 0) |
|
5478 |
return element; |
|
5479 |
if (cmp < 0) |
|
5480 |
{
|
|
5481 |
found=element; |
|
5482 |
element=element->right; |
|
5483 |
}
|
|
5484 |
else
|
|
5485 |
element=element->left; |
|
5486 |
}
|
|
5487 |
}
|
|
5488 |
||
5489 |
||
5490 |
/*
|
|
5491 |
Remove a element from the tree
|
|
5492 |
||
5493 |
SYNOPSIS
|
|
5494 |
tree_delete()
|
|
5495 |
key Key that is to be deleted from tree (this)
|
|
5496 |
||
5497 |
NOTE
|
|
5498 |
This also frees all sub trees that is used by the element
|
|
5499 |
||
5500 |
RETURN
|
|
5501 |
root of new tree (with key deleted)
|
|
5502 |
*/
|
|
5503 |
||
5504 |
SEL_ARG * |
|
5505 |
SEL_ARG::tree_delete(SEL_ARG *key) |
|
5506 |
{
|
|
5507 |
enum leaf_color remove_color; |
|
5508 |
SEL_ARG *root,*nod,**par,*fix_par; |
|
5509 |
||
5510 |
root=this; |
|
5511 |
this->parent= 0; |
|
5512 |
||
5513 |
/* Unlink from list */
|
|
5514 |
if (key->prev) |
|
5515 |
key->prev->next=key->next; |
|
5516 |
if (key->next) |
|
5517 |
key->next->prev=key->prev; |
|
5518 |
key->increment_use_count(-1); |
|
5519 |
if (!key->parent) |
|
5520 |
par= &root; |
|
5521 |
else
|
|
5522 |
par=key->parent_ptr(); |
|
5523 |
||
5524 |
if (key->left == &null_element) |
|
5525 |
{
|
|
5526 |
*par=nod=key->right; |
|
5527 |
fix_par=key->parent; |
|
5528 |
if (nod != &null_element) |
|
5529 |
nod->parent=fix_par; |
|
5530 |
remove_color= key->color; |
|
5531 |
}
|
|
5532 |
else if (key->right == &null_element) |
|
5533 |
{
|
|
5534 |
*par= nod=key->left; |
|
5535 |
nod->parent=fix_par=key->parent; |
|
5536 |
remove_color= key->color; |
|
5537 |
}
|
|
5538 |
else
|
|
5539 |
{
|
|
5540 |
SEL_ARG *tmp=key->next; // next bigger key (exist!) |
|
5541 |
nod= *tmp->parent_ptr()= tmp->right; // unlink tmp from tree |
|
5542 |
fix_par=tmp->parent; |
|
5543 |
if (nod != &null_element) |
|
5544 |
nod->parent=fix_par; |
|
5545 |
remove_color= tmp->color; |
|
5546 |
||
5547 |
tmp->parent=key->parent; // Move node in place of key |
|
5548 |
(tmp->left=key->left)->parent=tmp; |
|
5549 |
if ((tmp->right=key->right) != &null_element) |
|
5550 |
tmp->right->parent=tmp; |
|
5551 |
tmp->color=key->color; |
|
5552 |
*par=tmp; |
|
5553 |
if (fix_par == key) // key->right == key->next |
|
5554 |
fix_par=tmp; // new parent of nod |
|
5555 |
}
|
|
5556 |
||
5557 |
if (root == &null_element) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
5558 |
return 0; // Maybe root later |
1
by brian
clean slate |
5559 |
if (remove_color == BLACK) |
5560 |
root=rb_delete_fixup(root,nod,fix_par); |
|
511.2.6
by Monty Taylor
drizzled/ and storage/archive/ are clean. |
5561 |
#ifdef EXTRA_DEBUG
|
1
by brian
clean slate |
5562 |
test_rb_tree(root,root->parent); |
511.2.6
by Monty Taylor
drizzled/ and storage/archive/ are clean. |
5563 |
#endif /* EXTRA_DEBUG */ |
1
by brian
clean slate |
5564 |
|
5565 |
root->use_count=this->use_count; // Fix root counters |
|
5566 |
root->elements=this->elements-1; |
|
5567 |
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. |
5568 |
return(root); |
1
by brian
clean slate |
5569 |
}
|
5570 |
||
5571 |
||
5572 |
/* Functions to fix up the tree after insert and delete */
|
|
5573 |
||
5574 |
static void left_rotate(SEL_ARG **root,SEL_ARG *leaf) |
|
5575 |
{
|
|
5576 |
SEL_ARG *y=leaf->right; |
|
5577 |
leaf->right=y->left; |
|
5578 |
if (y->left != &null_element) |
|
5579 |
y->left->parent=leaf; |
|
5580 |
if (!(y->parent=leaf->parent)) |
|
5581 |
*root=y; |
|
5582 |
else
|
|
5583 |
*leaf->parent_ptr()=y; |
|
5584 |
y->left=leaf; |
|
5585 |
leaf->parent=y; |
|
5586 |
}
|
|
5587 |
||
5588 |
static void right_rotate(SEL_ARG **root,SEL_ARG *leaf) |
|
5589 |
{
|
|
5590 |
SEL_ARG *y=leaf->left; |
|
5591 |
leaf->left=y->right; |
|
5592 |
if (y->right != &null_element) |
|
5593 |
y->right->parent=leaf; |
|
5594 |
if (!(y->parent=leaf->parent)) |
|
5595 |
*root=y; |
|
5596 |
else
|
|
5597 |
*leaf->parent_ptr()=y; |
|
5598 |
y->right=leaf; |
|
5599 |
leaf->parent=y; |
|
5600 |
}
|
|
5601 |
||
5602 |
||
5603 |
SEL_ARG * |
|
5604 |
SEL_ARG::rb_insert(SEL_ARG *leaf) |
|
5605 |
{
|
|
5606 |
SEL_ARG *y,*par,*par2,*root; |
|
5607 |
root= this; root->parent= 0; |
|
5608 |
||
5609 |
leaf->color=RED; |
|
5610 |
while (leaf != root && (par= leaf->parent)->color == RED) |
|
5611 |
{ // This can't be root or 1 level under |
|
5612 |
if (par == (par2= leaf->parent->parent)->left) |
|
5613 |
{
|
|
5614 |
y= par2->right; |
|
5615 |
if (y->color == RED) |
|
5616 |
{
|
|
5617 |
par->color=BLACK; |
|
5618 |
y->color=BLACK; |
|
5619 |
leaf=par2; |
|
5620 |
leaf->color=RED; /* And the loop continues */ |
|
5621 |
}
|
|
5622 |
else
|
|
5623 |
{
|
|
5624 |
if (leaf == par->right) |
|
5625 |
{
|
|
5626 |
left_rotate(&root,leaf->parent); |
|
5627 |
par=leaf; /* leaf is now parent to old leaf */ |
|
5628 |
}
|
|
5629 |
par->color=BLACK; |
|
5630 |
par2->color=RED; |
|
5631 |
right_rotate(&root,par2); |
|
5632 |
break; |
|
5633 |
}
|
|
5634 |
}
|
|
5635 |
else
|
|
5636 |
{
|
|
5637 |
y= par2->left; |
|
5638 |
if (y->color == RED) |
|
5639 |
{
|
|
5640 |
par->color=BLACK; |
|
5641 |
y->color=BLACK; |
|
5642 |
leaf=par2; |
|
5643 |
leaf->color=RED; /* And the loop continues */ |
|
5644 |
}
|
|
5645 |
else
|
|
5646 |
{
|
|
5647 |
if (leaf == par->left) |
|
5648 |
{
|
|
5649 |
right_rotate(&root,par); |
|
5650 |
par=leaf; |
|
5651 |
}
|
|
5652 |
par->color=BLACK; |
|
5653 |
par2->color=RED; |
|
5654 |
left_rotate(&root,par2); |
|
5655 |
break; |
|
5656 |
}
|
|
5657 |
}
|
|
5658 |
}
|
|
5659 |
root->color=BLACK; |
|
511.2.6
by Monty Taylor
drizzled/ and storage/archive/ are clean. |
5660 |
#ifdef EXTRA_DEBUG
|
1
by brian
clean slate |
5661 |
test_rb_tree(root,root->parent); |
511.2.6
by Monty Taylor
drizzled/ and storage/archive/ are clean. |
5662 |
#endif /* EXTRA_DEBUG */ |
5663 |
||
1
by brian
clean slate |
5664 |
return root; |
5665 |
}
|
|
5666 |
||
5667 |
||
5668 |
SEL_ARG *rb_delete_fixup(SEL_ARG *root,SEL_ARG *key,SEL_ARG *par) |
|
5669 |
{
|
|
5670 |
SEL_ARG *x,*w; |
|
5671 |
root->parent=0; |
|
5672 |
||
5673 |
x= key; |
|
5674 |
while (x != root && x->color == SEL_ARG::BLACK) |
|
5675 |
{
|
|
5676 |
if (x == par->left) |
|
5677 |
{
|
|
5678 |
w=par->right; |
|
5679 |
if (w->color == SEL_ARG::RED) |
|
5680 |
{
|
|
5681 |
w->color=SEL_ARG::BLACK; |
|
5682 |
par->color=SEL_ARG::RED; |
|
5683 |
left_rotate(&root,par); |
|
5684 |
w=par->right; |
|
5685 |
}
|
|
5686 |
if (w->left->color == SEL_ARG::BLACK && w->right->color == SEL_ARG::BLACK) |
|
5687 |
{
|
|
5688 |
w->color=SEL_ARG::RED; |
|
5689 |
x=par; |
|
5690 |
}
|
|
5691 |
else
|
|
5692 |
{
|
|
5693 |
if (w->right->color == SEL_ARG::BLACK) |
|
5694 |
{
|
|
5695 |
w->left->color=SEL_ARG::BLACK; |
|
5696 |
w->color=SEL_ARG::RED; |
|
5697 |
right_rotate(&root,w); |
|
5698 |
w=par->right; |
|
5699 |
}
|
|
5700 |
w->color=par->color; |
|
5701 |
par->color=SEL_ARG::BLACK; |
|
5702 |
w->right->color=SEL_ARG::BLACK; |
|
5703 |
left_rotate(&root,par); |
|
5704 |
x=root; |
|
5705 |
break; |
|
5706 |
}
|
|
5707 |
}
|
|
5708 |
else
|
|
5709 |
{
|
|
5710 |
w=par->left; |
|
5711 |
if (w->color == SEL_ARG::RED) |
|
5712 |
{
|
|
5713 |
w->color=SEL_ARG::BLACK; |
|
5714 |
par->color=SEL_ARG::RED; |
|
5715 |
right_rotate(&root,par); |
|
5716 |
w=par->left; |
|
5717 |
}
|
|
5718 |
if (w->right->color == SEL_ARG::BLACK && w->left->color == SEL_ARG::BLACK) |
|
5719 |
{
|
|
5720 |
w->color=SEL_ARG::RED; |
|
5721 |
x=par; |
|
5722 |
}
|
|
5723 |
else
|
|
5724 |
{
|
|
5725 |
if (w->left->color == SEL_ARG::BLACK) |
|
5726 |
{
|
|
5727 |
w->right->color=SEL_ARG::BLACK; |
|
5728 |
w->color=SEL_ARG::RED; |
|
5729 |
left_rotate(&root,w); |
|
5730 |
w=par->left; |
|
5731 |
}
|
|
5732 |
w->color=par->color; |
|
5733 |
par->color=SEL_ARG::BLACK; |
|
5734 |
w->left->color=SEL_ARG::BLACK; |
|
5735 |
right_rotate(&root,par); |
|
5736 |
x=root; |
|
5737 |
break; |
|
5738 |
}
|
|
5739 |
}
|
|
5740 |
par=x->parent; |
|
5741 |
}
|
|
5742 |
x->color=SEL_ARG::BLACK; |
|
5743 |
return root; |
|
5744 |
}
|
|
5745 |
||
5746 |
||
5747 |
/* Test that the properties for a red-black tree hold */
|
|
5748 |
||
5749 |
#ifdef EXTRA_DEBUG
|
|
5750 |
int test_rb_tree(SEL_ARG *element,SEL_ARG *parent) |
|
5751 |
{
|
|
5752 |
int count_l,count_r; |
|
5753 |
||
5754 |
if (element == &null_element) |
|
5755 |
return 0; // Found end of tree |
|
5756 |
if (element->parent != parent) |
|
5757 |
{
|
|
755.2.1
by Mark Atwood
replace sql_print_error etc with errmsg_print |
5758 |
errmsg_printf(ERRMSG_LVL_ERROR, "Wrong tree: Parent doesn't point at parent"); |
1
by brian
clean slate |
5759 |
return -1; |
5760 |
}
|
|
5761 |
if (element->color == SEL_ARG::RED && |
|
5762 |
(element->left->color == SEL_ARG::RED || |
|
5763 |
element->right->color == SEL_ARG::RED)) |
|
5764 |
{
|
|
755.2.1
by Mark Atwood
replace sql_print_error etc with errmsg_print |
5765 |
errmsg_printf(ERRMSG_LVL_ERROR, "Wrong tree: Found two red in a row"); |
1
by brian
clean slate |
5766 |
return -1; |
5767 |
}
|
|
5768 |
if (element->left == element->right && element->left != &null_element) |
|
5769 |
{ // Dummy test |
|
755.2.1
by Mark Atwood
replace sql_print_error etc with errmsg_print |
5770 |
errmsg_printf(ERRMSG_LVL_ERROR, "Wrong tree: Found right == left"); |
1
by brian
clean slate |
5771 |
return -1; |
5772 |
}
|
|
5773 |
count_l=test_rb_tree(element->left,element); |
|
5774 |
count_r=test_rb_tree(element->right,element); |
|
5775 |
if (count_l >= 0 && count_r >= 0) |
|
5776 |
{
|
|
5777 |
if (count_l == count_r) |
|
5778 |
return count_l+(element->color == SEL_ARG::BLACK); |
|
755.2.1
by Mark Atwood
replace sql_print_error etc with errmsg_print |
5779 |
errmsg_printf(ERRMSG_LVL_ERROR, "Wrong tree: Incorrect black-count: %d - %d", |
1
by brian
clean slate |
5780 |
count_l,count_r); |
5781 |
}
|
|
5782 |
return -1; // Error, no more warnings |
|
5783 |
}
|
|
5784 |
||
5785 |
||
5786 |
/*
|
|
5787 |
Count how many times SEL_ARG graph "root" refers to its part "key"
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5788 |
|
1
by brian
clean slate |
5789 |
SYNOPSIS
|
5790 |
count_key_part_usage()
|
|
5791 |
root An RB-Root node in a SEL_ARG graph.
|
|
5792 |
key Another RB-Root node in that SEL_ARG graph.
|
|
5793 |
||
5794 |
DESCRIPTION
|
|
5795 |
The passed "root" node may refer to "key" node via root->next_key_part,
|
|
5796 |
root->next->n
|
|
5797 |
||
5798 |
This function counts how many times the node "key" is referred (via
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5799 |
SEL_ARG::next_key_part) by
|
5800 |
- intervals of RB-tree pointed by "root",
|
|
5801 |
- intervals of RB-trees that are pointed by SEL_ARG::next_key_part from
|
|
1
by brian
clean slate |
5802 |
intervals of RB-tree pointed by "root",
|
5803 |
- and so on.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5804 |
|
5805 |
Here is an example (horizontal links represent next_key_part pointers,
|
|
5806 |
vertical links - next/prev prev pointers):
|
|
5807 |
||
1
by brian
clean slate |
5808 |
+----+ $
|
5809 |
|root|-----------------+
|
|
5810 |
+----+ $ |
|
|
5811 |
| $ |
|
|
5812 |
| $ |
|
|
5813 |
+----+ +---+ $ | +---+ Here the return value
|
|
5814 |
| |- ... -| |---$-+--+->|key| will be 4.
|
|
5815 |
+----+ +---+ $ | | +---+
|
|
5816 |
| $ | |
|
|
5817 |
... $ | |
|
|
5818 |
| $ | |
|
|
5819 |
+----+ +---+ $ | |
|
|
5820 |
| |---| |---------+ |
|
|
5821 |
+----+ +---+ $ |
|
|
5822 |
| | $ |
|
|
5823 |
... +---+ $ |
|
|
5824 |
| |------------+
|
|
5825 |
+---+ $
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5826 |
RETURN
|
1
by brian
clean slate |
5827 |
Number of links to "key" from nodes reachable from "root".
|
5828 |
*/
|
|
5829 |
||
5830 |
static ulong count_key_part_usage(SEL_ARG *root, SEL_ARG *key) |
|
5831 |
{
|
|
5832 |
ulong count= 0; |
|
5833 |
for (root=root->first(); root ; root=root->next) |
|
5834 |
{
|
|
5835 |
if (root->next_key_part) |
|
5836 |
{
|
|
5837 |
if (root->next_key_part == key) |
|
5838 |
count++; |
|
5839 |
if (root->next_key_part->part < key->part) |
|
5840 |
count+=count_key_part_usage(root->next_key_part,key); |
|
5841 |
}
|
|
5842 |
}
|
|
5843 |
return count; |
|
5844 |
}
|
|
5845 |
||
5846 |
||
5847 |
/*
|
|
5848 |
Check if SEL_ARG::use_count value is correct
|
|
5849 |
||
5850 |
SYNOPSIS
|
|
5851 |
SEL_ARG::test_use_count()
|
|
5852 |
root The root node of the SEL_ARG graph (an RB-tree root node that
|
|
5853 |
has the least value of sel_arg->part in the entire graph, and
|
|
5854 |
thus is the "origin" of the graph)
|
|
5855 |
||
5856 |
DESCRIPTION
|
|
5857 |
Check if SEL_ARG::use_count value is correct. See the definition of
|
|
5858 |
use_count for what is "correct".
|
|
5859 |
*/
|
|
5860 |
||
5861 |
void SEL_ARG::test_use_count(SEL_ARG *root) |
|
5862 |
{
|
|
482
by Brian Aker
Remove uint. |
5863 |
uint32_t e_count=0; |
1
by brian
clean slate |
5864 |
if (this == root && use_count != 1) |
5865 |
{
|
|
755.2.1
by Mark Atwood
replace sql_print_error etc with errmsg_print |
5866 |
errmsg_printf(ERRMSG_LVL_INFO, "Use_count: Wrong count %lu for root",use_count); |
1
by brian
clean slate |
5867 |
return; |
5868 |
}
|
|
5869 |
if (this->type != SEL_ARG::KEY_RANGE) |
|
5870 |
return; |
|
5871 |
for (SEL_ARG *pos=first(); pos ; pos=pos->next) |
|
5872 |
{
|
|
5873 |
e_count++; |
|
5874 |
if (pos->next_key_part) |
|
5875 |
{
|
|
5876 |
ulong count=count_key_part_usage(root,pos->next_key_part); |
|
5877 |
if (count > pos->next_key_part->use_count) |
|
5878 |
{
|
|
755.2.1
by Mark Atwood
replace sql_print_error etc with errmsg_print |
5879 |
errmsg_printf(ERRMSG_LVL_INFO, "Use_count: Wrong count for key at 0x%lx, %lu " |
1
by brian
clean slate |
5880 |
"should be %lu", (long unsigned int)pos, |
5881 |
pos->next_key_part->use_count, count); |
|
5882 |
return; |
|
5883 |
}
|
|
5884 |
pos->next_key_part->test_use_count(root); |
|
5885 |
}
|
|
5886 |
}
|
|
5887 |
if (e_count != elements) |
|
755.2.1
by Mark Atwood
replace sql_print_error etc with errmsg_print |
5888 |
errmsg_printf(ERRMSG_LVL_WARN, "Wrong use count: %u (should be %u) for tree at 0x%lx", |
1
by brian
clean slate |
5889 |
e_count, elements, (long unsigned int) this); |
5890 |
}
|
|
5891 |
||
5892 |
#endif
|
|
5893 |
||
5894 |
/****************************************************************************
|
|
5895 |
MRR Range Sequence Interface implementation that walks a SEL_ARG* tree.
|
|
5896 |
****************************************************************************/
|
|
5897 |
||
5898 |
/* MRR range sequence, SEL_ARG* implementation: stack entry */
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5899 |
typedef struct st_range_seq_entry |
1
by brian
clean slate |
5900 |
{
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5901 |
/*
|
1
by brian
clean slate |
5902 |
Pointers in min and max keys. They point to right-after-end of key
|
5903 |
images. The 0-th entry has these pointing to key tuple start.
|
|
5904 |
*/
|
|
481
by Brian Aker
Remove all of uchar. |
5905 |
unsigned char *min_key, *max_key; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5906 |
|
5907 |
/*
|
|
1
by brian
clean slate |
5908 |
Flags, for {keypart0, keypart1, ... this_keypart} subtuple.
|
5909 |
min_key_flag may have NULL_RANGE set.
|
|
5910 |
*/
|
|
482
by Brian Aker
Remove uint. |
5911 |
uint32_t min_key_flag, max_key_flag; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5912 |
|
1
by brian
clean slate |
5913 |
/* Number of key parts */
|
482
by Brian Aker
Remove uint. |
5914 |
uint32_t min_key_parts, max_key_parts; |
1
by brian
clean slate |
5915 |
SEL_ARG *key_tree; |
5916 |
} RANGE_SEQ_ENTRY; |
|
5917 |
||
5918 |
||
5919 |
/*
|
|
5920 |
MRR range sequence, SEL_ARG* implementation: SEL_ARG graph traversal context
|
|
5921 |
*/
|
|
5922 |
typedef struct st_sel_arg_range_seq |
|
5923 |
{
|
|
482
by Brian Aker
Remove uint. |
5924 |
uint32_t keyno; /* index of used tree in SEL_TREE structure */ |
5925 |
uint32_t real_keyno; /* Number of the index in tables */ |
|
1
by brian
clean slate |
5926 |
PARAM *param; |
5927 |
SEL_ARG *start; /* Root node of the traversed SEL_ARG* graph */ |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5928 |
|
1
by brian
clean slate |
5929 |
RANGE_SEQ_ENTRY stack[MAX_REF_PARTS]; |
5930 |
int i; /* Index of last used element in the above array */ |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5931 |
|
55
by brian
Update for using real bool types. |
5932 |
bool at_start; /* true <=> The traversal has just started */ |
1
by brian
clean slate |
5933 |
} SEL_ARG_RANGE_SEQ; |
5934 |
||
5935 |
||
5936 |
/*
|
|
5937 |
Range sequence interface, SEL_ARG* implementation: Initialize the traversal
|
|
5938 |
||
5939 |
SYNOPSIS
|
|
5940 |
init()
|
|
5941 |
init_params SEL_ARG tree traversal context
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5942 |
n_ranges [ignored] The number of ranges obtained
|
1
by brian
clean slate |
5943 |
flags [ignored] HA_MRR_SINGLE_POINT, HA_MRR_FIXED_KEY
|
5944 |
||
5945 |
RETURN
|
|
5946 |
Value of init_param
|
|
5947 |
*/
|
|
5948 |
||
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
5949 |
range_seq_t sel_arg_range_seq_init(void *init_param, uint32_t, uint32_t) |
1
by brian
clean slate |
5950 |
{
|
5951 |
SEL_ARG_RANGE_SEQ *seq= (SEL_ARG_RANGE_SEQ*)init_param; |
|
55
by brian
Update for using real bool types. |
5952 |
seq->at_start= true; |
1
by brian
clean slate |
5953 |
seq->stack[0].key_tree= NULL; |
5954 |
seq->stack[0].min_key= seq->param->min_key; |
|
5955 |
seq->stack[0].min_key_flag= 0; |
|
5956 |
seq->stack[0].min_key_parts= 0; |
|
5957 |
||
5958 |
seq->stack[0].max_key= seq->param->max_key; |
|
5959 |
seq->stack[0].max_key_flag= 0; |
|
5960 |
seq->stack[0].max_key_parts= 0; |
|
5961 |
seq->i= 0; |
|
5962 |
return init_param; |
|
5963 |
}
|
|
5964 |
||
5965 |
||
5966 |
static void step_down_to(SEL_ARG_RANGE_SEQ *arg, SEL_ARG *key_tree) |
|
5967 |
{
|
|
5968 |
RANGE_SEQ_ENTRY *cur= &arg->stack[arg->i+1]; |
|
5969 |
RANGE_SEQ_ENTRY *prev= &arg->stack[arg->i]; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5970 |
|
1
by brian
clean slate |
5971 |
cur->key_tree= key_tree; |
5972 |
cur->min_key= prev->min_key; |
|
5973 |
cur->max_key= prev->max_key; |
|
5974 |
cur->min_key_parts= prev->min_key_parts; |
|
5975 |
cur->max_key_parts= prev->max_key_parts; |
|
5976 |
||
206
by Brian Aker
Removed final uint dead types. |
5977 |
uint16_t stor_length= arg->param->key[arg->keyno][key_tree->part].store_length; |
1
by brian
clean slate |
5978 |
cur->min_key_parts += key_tree->store_min(stor_length, &cur->min_key, |
5979 |
prev->min_key_flag); |
|
5980 |
cur->max_key_parts += key_tree->store_max(stor_length, &cur->max_key, |
|
5981 |
prev->max_key_flag); |
|
5982 |
||
5983 |
cur->min_key_flag= prev->min_key_flag | key_tree->min_flag; |
|
5984 |
cur->max_key_flag= prev->max_key_flag | key_tree->max_flag; |
|
5985 |
||
5986 |
if (key_tree->is_null_interval()) |
|
5987 |
cur->min_key_flag |= NULL_RANGE; |
|
5988 |
(arg->i)++; |
|
5989 |
}
|
|
5990 |
||
5991 |
||
5992 |
/*
|
|
5993 |
Range sequence interface, SEL_ARG* implementation: get the next interval
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5994 |
|
1
by brian
clean slate |
5995 |
SYNOPSIS
|
5996 |
sel_arg_range_seq_next()
|
|
5997 |
rseq Value returned from sel_arg_range_seq_init
|
|
5998 |
range OUT Store information about the range here
|
|
5999 |
||
6000 |
DESCRIPTION
|
|
6001 |
This is "get_next" function for Range sequence interface implementation
|
|
6002 |
for SEL_ARG* tree.
|
|
6003 |
||
6004 |
IMPLEMENTATION
|
|
6005 |
The traversal also updates those param members:
|
|
6006 |
- is_ror_scan
|
|
6007 |
- range_count
|
|
6008 |
- max_key_part
|
|
6009 |
||
6010 |
RETURN
|
|
6011 |
0 Ok
|
|
6012 |
1 No more ranges in the sequence
|
|
6013 |
*/
|
|
6014 |
||
6015 |
//psergey-merge-todo: support check_quick_keys:max_keypart
|
|
482
by Brian Aker
Remove uint. |
6016 |
uint32_t sel_arg_range_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range) |
1
by brian
clean slate |
6017 |
{
|
6018 |
SEL_ARG *key_tree; |
|
6019 |
SEL_ARG_RANGE_SEQ *seq= (SEL_ARG_RANGE_SEQ*)rseq; |
|
6020 |
if (seq->at_start) |
|
6021 |
{
|
|
6022 |
key_tree= seq->start; |
|
55
by brian
Update for using real bool types. |
6023 |
seq->at_start= false; |
1
by brian
clean slate |
6024 |
goto walk_up_n_right; |
6025 |
}
|
|
6026 |
||
6027 |
key_tree= seq->stack[seq->i].key_tree; |
|
6028 |
/* Ok, we're at some "full tuple" position in the tree */
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6029 |
|
1
by brian
clean slate |
6030 |
/* Step down if we can */
|
6031 |
if (key_tree->next && key_tree->next != &null_element) |
|
6032 |
{
|
|
6033 |
//step down; (update the tuple, we'll step right and stay there)
|
|
6034 |
seq->i--; |
|
6035 |
step_down_to(seq, key_tree->next); |
|
6036 |
key_tree= key_tree->next; |
|
55
by brian
Update for using real bool types. |
6037 |
seq->param->is_ror_scan= false; |
1
by brian
clean slate |
6038 |
goto walk_right_n_up; |
6039 |
}
|
|
6040 |
||
6041 |
/* Ok, can't step down, walk left until we can step down */
|
|
6042 |
while (1) |
|
6043 |
{
|
|
6044 |
if (seq->i == 1) // can't step left |
|
6045 |
return 1; |
|
6046 |
/* Step left */
|
|
6047 |
seq->i--; |
|
6048 |
key_tree= seq->stack[seq->i].key_tree; |
|
6049 |
||
6050 |
/* Step down if we can */
|
|
6051 |
if (key_tree->next && key_tree->next != &null_element) |
|
6052 |
{
|
|
6053 |
// Step down; update the tuple
|
|
6054 |
seq->i--; |
|
6055 |
step_down_to(seq, key_tree->next); |
|
6056 |
key_tree= key_tree->next; |
|
6057 |
break; |
|
6058 |
}
|
|
6059 |
}
|
|
6060 |
||
6061 |
/*
|
|
6062 |
Ok, we've stepped down from the path to previous tuple.
|
|
6063 |
Walk right-up while we can
|
|
6064 |
*/
|
|
6065 |
walk_right_n_up: |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6066 |
while (key_tree->next_key_part && key_tree->next_key_part != &null_element && |
1
by brian
clean slate |
6067 |
key_tree->next_key_part->part == key_tree->part + 1 && |
6068 |
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) |
|
6069 |
{
|
|
6070 |
{
|
|
6071 |
RANGE_SEQ_ENTRY *cur= &seq->stack[seq->i]; |
|
482
by Brian Aker
Remove uint. |
6072 |
uint32_t min_key_length= cur->min_key - seq->param->min_key; |
6073 |
uint32_t max_key_length= cur->max_key - seq->param->max_key; |
|
6074 |
uint32_t len= cur->min_key - cur[-1].min_key; |
|
1
by brian
clean slate |
6075 |
if (!(min_key_length == max_key_length && |
6076 |
!memcmp(cur[-1].min_key, cur[-1].max_key, len) && |
|
6077 |
!key_tree->min_flag && !key_tree->max_flag)) |
|
6078 |
{
|
|
55
by brian
Update for using real bool types. |
6079 |
seq->param->is_ror_scan= false; |
1
by brian
clean slate |
6080 |
if (!key_tree->min_flag) |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6081 |
cur->min_key_parts += |
1
by brian
clean slate |
6082 |
key_tree->next_key_part->store_min_key(seq->param->key[seq->keyno], |
6083 |
&cur->min_key, |
|
6084 |
&cur->min_key_flag); |
|
6085 |
if (!key_tree->max_flag) |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6086 |
cur->max_key_parts += |
1
by brian
clean slate |
6087 |
key_tree->next_key_part->store_max_key(seq->param->key[seq->keyno], |
6088 |
&cur->max_key, |
|
6089 |
&cur->max_key_flag); |
|
6090 |
break; |
|
6091 |
}
|
|
6092 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6093 |
|
1
by brian
clean slate |
6094 |
/*
|
6095 |
Ok, current atomic interval is in form "t.field=const" and there is
|
|
6096 |
next_key_part interval. Step right, and walk up from there.
|
|
6097 |
*/
|
|
6098 |
key_tree= key_tree->next_key_part; |
|
6099 |
||
6100 |
walk_up_n_right: |
|
6101 |
while (key_tree->prev && key_tree->prev != &null_element) |
|
6102 |
{
|
|
6103 |
/* Step up */
|
|
6104 |
key_tree= key_tree->prev; |
|
6105 |
}
|
|
6106 |
step_down_to(seq, key_tree); |
|
6107 |
}
|
|
6108 |
||
6109 |
/* Ok got a tuple */
|
|
6110 |
RANGE_SEQ_ENTRY *cur= &seq->stack[seq->i]; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6111 |
|
1
by brian
clean slate |
6112 |
range->ptr= (char*)(int)(key_tree->part); |
6113 |
{
|
|
6114 |
range->range_flag= cur->min_key_flag | cur->max_key_flag; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6115 |
|
1
by brian
clean slate |
6116 |
range->start_key.key= seq->param->min_key; |
6117 |
range->start_key.length= cur->min_key - seq->param->min_key; |
|
6118 |
range->start_key.keypart_map= make_prev_keypart_map(cur->min_key_parts); |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6119 |
range->start_key.flag= (cur->min_key_flag & NEAR_MIN ? HA_READ_AFTER_KEY : |
1
by brian
clean slate |
6120 |
HA_READ_KEY_EXACT); |
6121 |
||
6122 |
range->end_key.key= seq->param->max_key; |
|
6123 |
range->end_key.length= cur->max_key - seq->param->max_key; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6124 |
range->end_key.flag= (cur->max_key_flag & NEAR_MAX ? HA_READ_BEFORE_KEY : |
1
by brian
clean slate |
6125 |
HA_READ_AFTER_KEY); |
6126 |
range->end_key.keypart_map= make_prev_keypart_map(cur->max_key_parts); |
|
6127 |
||
6128 |
if (!(cur->min_key_flag & ~NULL_RANGE) && !cur->max_key_flag && |
|
895
by Brian Aker
Completion (?) of uint conversion. |
6129 |
(uint32_t)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.) |
6130 |
(seq->param->table->key_info[seq->real_keyno].flags & (HA_NOSAME)) == |
1
by brian
clean slate |
6131 |
HA_NOSAME && |
6132 |
range->start_key.length == range->end_key.length && |
|
6133 |
!memcmp(seq->param->min_key,seq->param->max_key,range->start_key.length)) |
|
6134 |
range->range_flag= UNIQUE_RANGE | (cur->min_key_flag & NULL_RANGE); |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6135 |
|
1
by brian
clean slate |
6136 |
if (seq->param->is_ror_scan) |
6137 |
{
|
|
6138 |
/*
|
|
6139 |
If we get here, the condition on the key was converted to form
|
|
6140 |
"(keyXpart1 = c1) AND ... AND (keyXpart{key_tree->part - 1} = cN) AND
|
|
6141 |
somecond(keyXpart{key_tree->part})"
|
|
6142 |
Check if
|
|
6143 |
somecond is "keyXpart{key_tree->part} = const" and
|
|
6144 |
uncovered "tail" of KeyX parts is either empty or is identical to
|
|
6145 |
first members of clustered primary key.
|
|
6146 |
*/
|
|
6147 |
if (!(!(cur->min_key_flag & ~NULL_RANGE) && !cur->max_key_flag && |
|
6148 |
(range->start_key.length == range->end_key.length) && |
|
6149 |
!memcmp(range->start_key.key, range->end_key.key, range->start_key.length) && |
|
6150 |
is_key_scan_ror(seq->param, seq->real_keyno, key_tree->part + 1))) |
|
55
by brian
Update for using real bool types. |
6151 |
seq->param->is_ror_scan= false; |
1
by brian
clean slate |
6152 |
}
|
6153 |
}
|
|
6154 |
seq->param->range_count++; |
|
895
by Brian Aker
Completion (?) of uint conversion. |
6155 |
seq->param->max_key_part=cmax(seq->param->max_key_part,(uint32_t)key_tree->part); |
1
by brian
clean slate |
6156 |
return 0; |
6157 |
}
|
|
6158 |
||
6159 |
||
6160 |
/*
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6161 |
Calculate cost and E(#rows) for a given index and intervals tree
|
1
by brian
clean slate |
6162 |
|
6163 |
SYNOPSIS
|
|
6164 |
check_quick_select()
|
|
6165 |
param Parameter from test_quick_select
|
|
6166 |
idx Number of index to use in PARAM::key SEL_TREE::key
|
|
55
by brian
Update for using real bool types. |
6167 |
index_only true - assume only index tuples will be accessed
|
6168 |
false - assume full table rows will be read
|
|
1
by brian
clean slate |
6169 |
tree Transformed selection condition, tree->key[idx] holds
|
6170 |
the intervals for the given index.
|
|
55
by brian
Update for using real bool types. |
6171 |
update_tbl_stats true <=> update table->quick_* with information
|
1
by brian
clean slate |
6172 |
about range scan we've evaluated.
|
6173 |
mrr_flags INOUT MRR access flags
|
|
6174 |
cost OUT Scan cost
|
|
6175 |
||
6176 |
NOTES
|
|
6177 |
param->is_ror_scan is set to reflect if the key scan is a ROR (see
|
|
6178 |
is_key_scan_ror function for more info)
|
|
6179 |
param->table->quick_*, param->range_count (and maybe others) are
|
|
6180 |
updated with data of given key scan, see quick_range_seq_next for details.
|
|
6181 |
||
6182 |
RETURN
|
|
6183 |
Estimate # of records to be retrieved.
|
|
6184 |
HA_POS_ERROR if estimate calculation failed due to table handler problems.
|
|
6185 |
*/
|
|
6186 |
||
6187 |
static
|
|
482
by Brian Aker
Remove uint. |
6188 |
ha_rows check_quick_select(PARAM *param, uint32_t idx, bool index_only, |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6189 |
SEL_ARG *tree, bool update_tbl_stats, |
482
by Brian Aker
Remove uint. |
6190 |
uint32_t *mrr_flags, uint32_t *bufsize, COST_VECT *cost) |
1
by brian
clean slate |
6191 |
{
|
6192 |
SEL_ARG_RANGE_SEQ seq; |
|
6193 |
RANGE_SEQ_IF seq_if = {sel_arg_range_seq_init, sel_arg_range_seq_next}; |
|
6194 |
handler *file= param->table->file; |
|
6195 |
ha_rows rows; |
|
482
by Brian Aker
Remove uint. |
6196 |
uint32_t keynr= param->real_keynr[idx]; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6197 |
|
1
by brian
clean slate |
6198 |
/* Handle cases when we don't have a valid non-empty list of range */
|
6199 |
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. |
6200 |
return(HA_POS_ERROR); |
1
by brian
clean slate |
6201 |
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. |
6202 |
return(0L); |
1
by brian
clean slate |
6203 |
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. |
6204 |
return(HA_POS_ERROR); |
1
by brian
clean slate |
6205 |
|
6206 |
seq.keyno= idx; |
|
6207 |
seq.real_keyno= keynr; |
|
6208 |
seq.param= param; |
|
6209 |
seq.start= tree; |
|
6210 |
||
6211 |
param->range_count=0; |
|
6212 |
param->max_key_part=0; |
|
6213 |
||
55
by brian
Update for using real bool types. |
6214 |
param->is_ror_scan= true; |
6215 |
if (file->index_flags(keynr, 0, true) & HA_KEY_SCAN_NOT_ROR) |
|
6216 |
param->is_ror_scan= false; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6217 |
|
1
by brian
clean slate |
6218 |
*mrr_flags= param->force_default_mrr? HA_MRR_USE_DEFAULT_IMPL: 0; |
6219 |
*mrr_flags|= HA_MRR_NO_ASSOCIATION; |
|
6220 |
||
6221 |
bool pk_is_clustered= file->primary_key_is_clustered(); |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6222 |
if (index_only && |
1
by brian
clean slate |
6223 |
(file->index_flags(keynr, param->max_key_part, 1) & HA_KEYREAD_ONLY) && |
6224 |
!(pk_is_clustered && keynr == param->table->s->primary_key)) |
|
6225 |
*mrr_flags |= HA_MRR_INDEX_ONLY; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6226 |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
6227 |
if (current_session->lex->sql_command != SQLCOM_SELECT) |
1
by brian
clean slate |
6228 |
*mrr_flags |= HA_MRR_USE_DEFAULT_IMPL; |
6229 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
6230 |
*bufsize= param->session->variables.read_rnd_buff_size; |
1
by brian
clean slate |
6231 |
rows= file->multi_range_read_info_const(keynr, &seq_if, (void*)&seq, 0, |
6232 |
bufsize, mrr_flags, cost); |
|
6233 |
if (rows != HA_POS_ERROR) |
|
6234 |
{
|
|
6235 |
param->table->quick_rows[keynr]=rows; |
|
6236 |
if (update_tbl_stats) |
|
6237 |
{
|
|
6238 |
param->table->quick_keys.set_bit(keynr); |
|
6239 |
param->table->quick_key_parts[keynr]=param->max_key_part+1; |
|
6240 |
param->table->quick_n_ranges[keynr]= param->range_count; |
|
6241 |
param->table->quick_condition_rows= |
|
398.1.4
by Monty Taylor
Renamed max/min. |
6242 |
cmin(param->table->quick_condition_rows, rows); |
1
by brian
clean slate |
6243 |
}
|
6244 |
}
|
|
6245 |
/* Figure out if the key scan is ROR (returns rows in ROWID order) or not */
|
|
6246 |
enum ha_key_alg key_alg= param->table->key_info[seq.real_keyno].algorithm; |
|
6247 |
if ((key_alg != HA_KEY_ALG_BTREE) && (key_alg!= HA_KEY_ALG_UNDEF)) |
|
6248 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6249 |
/*
|
1
by brian
clean slate |
6250 |
All scans are non-ROR scans for those index types.
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6251 |
TODO: Don't have this logic here, make table engines return
|
1
by brian
clean slate |
6252 |
appropriate flags instead.
|
6253 |
*/
|
|
55
by brian
Update for using real bool types. |
6254 |
param->is_ror_scan= false; |
1
by brian
clean slate |
6255 |
}
|
6256 |
else
|
|
6257 |
{
|
|
6258 |
/* Clustered PK scan is always a ROR scan (TODO: same as above) */
|
|
6259 |
if (param->table->s->primary_key == keynr && pk_is_clustered) |
|
55
by brian
Update for using real bool types. |
6260 |
param->is_ror_scan= true; |
1
by brian
clean slate |
6261 |
}
|
6262 |
||
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. |
6263 |
return(rows); //psergey-merge:todo: maintain first_null_comp. |
1
by brian
clean slate |
6264 |
}
|
6265 |
||
6266 |
||
6267 |
/*
|
|
6268 |
Check if key scan on given index with equality conditions on first n key
|
|
6269 |
parts is a ROR scan.
|
|
6270 |
||
6271 |
SYNOPSIS
|
|
6272 |
is_key_scan_ror()
|
|
6273 |
param Parameter from test_quick_select
|
|
6274 |
keynr Number of key in the table. The key must not be a clustered
|
|
6275 |
primary key.
|
|
6276 |
nparts Number of first key parts for which equality conditions
|
|
6277 |
are present.
|
|
6278 |
||
6279 |
NOTES
|
|
6280 |
ROR (Rowid Ordered Retrieval) key scan is a key scan that produces
|
|
6281 |
ordered sequence of rowids (ha_xxx::cmp_ref is the comparison function)
|
|
6282 |
||
6283 |
This function is needed to handle a practically-important special case:
|
|
6284 |
an index scan is a ROR scan if it is done using a condition in form
|
|
6285 |
||
6286 |
"key1_1=c_1 AND ... AND key1_n=c_n"
|
|
6287 |
||
6288 |
where the index is defined on (key1_1, ..., key1_N [,a_1, ..., a_n])
|
|
6289 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6290 |
and the table has a clustered Primary Key defined as
|
6291 |
PRIMARY KEY(a_1, ..., a_n, b1, ..., b_k)
|
|
6292 |
||
6293 |
i.e. the first key parts of it are identical to uncovered parts ot the
|
|
1
by brian
clean slate |
6294 |
key being scanned. This function assumes that the index flags do not
|
6295 |
include HA_KEY_SCAN_NOT_ROR flag (that is checked elsewhere).
|
|
6296 |
||
6297 |
Check (1) is made in quick_range_seq_next()
|
|
6298 |
||
6299 |
RETURN
|
|
55
by brian
Update for using real bool types. |
6300 |
true The scan is ROR-scan
|
6301 |
false Otherwise
|
|
1
by brian
clean slate |
6302 |
*/
|
6303 |
||
482
by Brian Aker
Remove uint. |
6304 |
static bool is_key_scan_ror(PARAM *param, uint32_t keynr, uint8_t nparts) |
1
by brian
clean slate |
6305 |
{
|
6306 |
KEY *table_key= param->table->key_info + keynr; |
|
6307 |
KEY_PART_INFO *key_part= table_key->key_part + nparts; |
|
6308 |
KEY_PART_INFO *key_part_end= (table_key->key_part + |
|
6309 |
table_key->key_parts); |
|
482
by Brian Aker
Remove uint. |
6310 |
uint32_t pk_number; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6311 |
|
1
by brian
clean slate |
6312 |
for (KEY_PART_INFO *kp= table_key->key_part; kp < key_part; kp++) |
6313 |
{
|
|
206
by Brian Aker
Removed final uint dead types. |
6314 |
uint16_t fieldnr= param->table->key_info[keynr]. |
1
by brian
clean slate |
6315 |
key_part[kp - table_key->key_part].fieldnr - 1; |
6316 |
if (param->table->field[fieldnr]->key_length() != kp->length) |
|
55
by brian
Update for using real bool types. |
6317 |
return false; |
1
by brian
clean slate |
6318 |
}
|
6319 |
||
6320 |
if (key_part == key_part_end) |
|
55
by brian
Update for using real bool types. |
6321 |
return true; |
1
by brian
clean slate |
6322 |
|
6323 |
key_part= table_key->key_part + nparts; |
|
6324 |
pk_number= param->table->s->primary_key; |
|
6325 |
if (!param->table->file->primary_key_is_clustered() || pk_number == MAX_KEY) |
|
55
by brian
Update for using real bool types. |
6326 |
return false; |
1
by brian
clean slate |
6327 |
|
6328 |
KEY_PART_INFO *pk_part= param->table->key_info[pk_number].key_part; |
|
6329 |
KEY_PART_INFO *pk_part_end= pk_part + |
|
6330 |
param->table->key_info[pk_number].key_parts; |
|
6331 |
for (;(key_part!=key_part_end) && (pk_part != pk_part_end); |
|
6332 |
++key_part, ++pk_part) |
|
6333 |
{
|
|
6334 |
if ((key_part->field != pk_part->field) || |
|
6335 |
(key_part->length != pk_part->length)) |
|
55
by brian
Update for using real bool types. |
6336 |
return false; |
1
by brian
clean slate |
6337 |
}
|
6338 |
return (key_part == key_part_end); |
|
6339 |
}
|
|
6340 |
||
6341 |
||
6342 |
/*
|
|
6343 |
Create a QUICK_RANGE_SELECT from given key and SEL_ARG tree for that key.
|
|
6344 |
||
6345 |
SYNOPSIS
|
|
6346 |
get_quick_select()
|
|
6347 |
param
|
|
6348 |
idx Index of used key in param->key.
|
|
6349 |
key_tree SEL_ARG tree for the used key
|
|
6350 |
mrr_flags MRR parameter for quick select
|
|
6351 |
mrr_buf_size MRR parameter for quick select
|
|
6352 |
parent_alloc If not NULL, use it to allocate memory for
|
|
6353 |
quick select data. Otherwise use quick->alloc.
|
|
6354 |
NOTES
|
|
6355 |
The caller must call QUICK_SELECT::init for returned quick select.
|
|
6356 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
6357 |
CAUTION! This function may change session->mem_root to a MEM_ROOT which will be
|
1
by brian
clean slate |
6358 |
deallocated when the returned quick select is deleted.
|
6359 |
||
6360 |
RETURN
|
|
6361 |
NULL on error
|
|
6362 |
otherwise created quick select
|
|
6363 |
*/
|
|
6364 |
||
6365 |
QUICK_RANGE_SELECT * |
|
482
by Brian Aker
Remove uint. |
6366 |
get_quick_select(PARAM *param,uint32_t idx,SEL_ARG *key_tree, uint32_t mrr_flags, |
6367 |
uint32_t mrr_buf_size, MEM_ROOT *parent_alloc) |
|
1
by brian
clean slate |
6368 |
{
|
6369 |
QUICK_RANGE_SELECT *quick; |
|
55
by brian
Update for using real bool types. |
6370 |
bool create_err= false; |
1
by brian
clean slate |
6371 |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
6372 |
quick=new QUICK_RANGE_SELECT(param->session, param->table, |
1
by brian
clean slate |
6373 |
param->real_keynr[idx], |
6374 |
test(parent_alloc), NULL, &create_err); |
|
6375 |
||
6376 |
if (quick) |
|
6377 |
{
|
|
6378 |
if (create_err || |
|
6379 |
get_quick_keys(param,quick,param->key[idx],key_tree,param->min_key,0, |
|
6380 |
param->max_key,0)) |
|
6381 |
{
|
|
6382 |
delete quick; |
|
6383 |
quick=0; |
|
6384 |
}
|
|
6385 |
else
|
|
6386 |
{
|
|
6387 |
quick->mrr_flags= mrr_flags; |
|
6388 |
quick->mrr_buf_size= mrr_buf_size; |
|
6389 |
quick->key_parts=(KEY_PART*) |
|
6390 |
memdup_root(parent_alloc? parent_alloc : &quick->alloc, |
|
6391 |
(char*) param->key[idx], |
|
6392 |
sizeof(KEY_PART)* |
|
6393 |
param->table->key_info[param->real_keynr[idx]].key_parts); |
|
6394 |
}
|
|
6395 |
}
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6396 |
return quick; |
1
by brian
clean slate |
6397 |
}
|
6398 |
||
6399 |
||
6400 |
/*
|
|
6401 |
** Fix this to get all possible sub_ranges
|
|
6402 |
*/
|
|
6403 |
bool
|
|
6404 |
get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, |
|
482
by Brian Aker
Remove uint. |
6405 |
SEL_ARG *key_tree, unsigned char *min_key,uint32_t min_key_flag, |
6406 |
unsigned char *max_key, uint32_t max_key_flag) |
|
1
by brian
clean slate |
6407 |
{
|
6408 |
QUICK_RANGE *range; |
|
482
by Brian Aker
Remove uint. |
6409 |
uint32_t flag; |
1
by brian
clean slate |
6410 |
int min_part= key_tree->part-1, // # of keypart values in min_key buffer |
6411 |
max_part= key_tree->part-1; // # of keypart values in max_key buffer |
|
6412 |
||
6413 |
if (key_tree->left != &null_element) |
|
6414 |
{
|
|
6415 |
if (get_quick_keys(param,quick,key,key_tree->left, |
|
6416 |
min_key,min_key_flag, max_key, max_key_flag)) |
|
6417 |
return 1; |
|
6418 |
}
|
|
481
by Brian Aker
Remove all of uchar. |
6419 |
unsigned char *tmp_min_key=min_key,*tmp_max_key=max_key; |
1
by brian
clean slate |
6420 |
min_part+= key_tree->store_min(key[key_tree->part].store_length, |
6421 |
&tmp_min_key,min_key_flag); |
|
6422 |
max_part+= key_tree->store_max(key[key_tree->part].store_length, |
|
6423 |
&tmp_max_key,max_key_flag); |
|
6424 |
||
6425 |
if (key_tree->next_key_part && |
|
6426 |
key_tree->next_key_part->part == key_tree->part+1 && |
|
6427 |
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) |
|
6428 |
{ // const key as prefix |
|
6429 |
if ((tmp_min_key - min_key) == (tmp_max_key - max_key) && |
|
895
by Brian Aker
Completion (?) of uint conversion. |
6430 |
memcmp(min_key, max_key, (uint32_t)(tmp_max_key - max_key))==0 && |
1
by brian
clean slate |
6431 |
key_tree->min_flag==0 && key_tree->max_flag==0) |
6432 |
{
|
|
6433 |
if (get_quick_keys(param,quick,key,key_tree->next_key_part, |
|
6434 |
tmp_min_key, min_key_flag | key_tree->min_flag, |
|
6435 |
tmp_max_key, max_key_flag | key_tree->max_flag)) |
|
6436 |
return 1; |
|
6437 |
goto end; // Ugly, but efficient |
|
6438 |
}
|
|
6439 |
{
|
|
482
by Brian Aker
Remove uint. |
6440 |
uint32_t tmp_min_flag=key_tree->min_flag,tmp_max_flag=key_tree->max_flag; |
1
by brian
clean slate |
6441 |
if (!tmp_min_flag) |
6442 |
min_part+= key_tree->next_key_part->store_min_key(key, &tmp_min_key, |
|
6443 |
&tmp_min_flag); |
|
6444 |
if (!tmp_max_flag) |
|
6445 |
max_part+= key_tree->next_key_part->store_max_key(key, &tmp_max_key, |
|
6446 |
&tmp_max_flag); |
|
6447 |
flag=tmp_min_flag | tmp_max_flag; |
|
6448 |
}
|
|
6449 |
}
|
|
6450 |
else
|
|
6451 |
{
|
|
6452 |
flag= key_tree->min_flag | key_tree->max_flag; |
|
6453 |
}
|
|
6454 |
||
6455 |
/*
|
|
6456 |
Ensure that some part of min_key and max_key are used. If not,
|
|
6457 |
regard this as no lower/upper range
|
|
6458 |
*/
|
|
6459 |
{
|
|
6460 |
if (tmp_min_key != param->min_key) |
|
6461 |
flag&= ~NO_MIN_RANGE; |
|
6462 |
else
|
|
6463 |
flag|= NO_MIN_RANGE; |
|
6464 |
if (tmp_max_key != param->max_key) |
|
6465 |
flag&= ~NO_MAX_RANGE; |
|
6466 |
else
|
|
6467 |
flag|= NO_MAX_RANGE; |
|
6468 |
}
|
|
6469 |
if (flag == 0) |
|
6470 |
{
|
|
895
by Brian Aker
Completion (?) of uint conversion. |
6471 |
uint32_t length= (uint32_t) (tmp_min_key - param->min_key); |
6472 |
if (length == (uint32_t) (tmp_max_key - param->max_key) && |
|
1
by brian
clean slate |
6473 |
!memcmp(param->min_key,param->max_key,length)) |
6474 |
{
|
|
6475 |
KEY *table_key=quick->head->key_info+quick->index; |
|
6476 |
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.) |
6477 |
if ((table_key->flags & (HA_NOSAME)) == HA_NOSAME && |
1
by brian
clean slate |
6478 |
key->part == table_key->key_parts-1) |
6479 |
{
|
|
6480 |
if (!(table_key->flags & HA_NULL_PART_KEY) || |
|
6481 |
!null_part_in_key(key, |
|
6482 |
param->min_key, |
|
895
by Brian Aker
Completion (?) of uint conversion. |
6483 |
(uint32_t) (tmp_min_key - param->min_key))) |
1
by brian
clean slate |
6484 |
flag|= UNIQUE_RANGE; |
6485 |
else
|
|
6486 |
flag|= NULL_RANGE; |
|
6487 |
}
|
|
6488 |
}
|
|
6489 |
}
|
|
6490 |
||
6491 |
/* Get range for retrieving rows in QUICK_SELECT::get_next */
|
|
6492 |
if (!(range= new QUICK_RANGE(param->min_key, |
|
895
by Brian Aker
Completion (?) of uint conversion. |
6493 |
(uint32_t) (tmp_min_key - param->min_key), |
1
by brian
clean slate |
6494 |
min_part >=0 ? make_keypart_map(min_part) : 0, |
6495 |
param->max_key, |
|
895
by Brian Aker
Completion (?) of uint conversion. |
6496 |
(uint32_t) (tmp_max_key - param->max_key), |
1
by brian
clean slate |
6497 |
max_part >=0 ? make_keypart_map(max_part) : 0, |
6498 |
flag))) |
|
6499 |
return 1; // out of memory |
|
6500 |
||
6501 |
set_if_bigger(quick->max_used_key_length, range->min_length); |
|
6502 |
set_if_bigger(quick->max_used_key_length, range->max_length); |
|
895
by Brian Aker
Completion (?) of uint conversion. |
6503 |
set_if_bigger(quick->used_key_parts, (uint32_t) key_tree->part+1); |
481
by Brian Aker
Remove all of uchar. |
6504 |
if (insert_dynamic(&quick->ranges, (unsigned char*) &range)) |
1
by brian
clean slate |
6505 |
return 1; |
6506 |
||
6507 |
end: |
|
6508 |
if (key_tree->right != &null_element) |
|
6509 |
return get_quick_keys(param,quick,key,key_tree->right, |
|
6510 |
min_key,min_key_flag, |
|
6511 |
max_key,max_key_flag); |
|
6512 |
return 0; |
|
6513 |
}
|
|
6514 |
||
6515 |
/*
|
|
6516 |
Return 1 if there is only one range and this uses the whole primary key
|
|
6517 |
*/
|
|
6518 |
||
6519 |
bool QUICK_RANGE_SELECT::unique_key_range() |
|
6520 |
{
|
|
6521 |
if (ranges.elements == 1) |
|
6522 |
{
|
|
6523 |
QUICK_RANGE *tmp= *((QUICK_RANGE**)ranges.buffer); |
|
6524 |
if ((tmp->flag & (EQ_RANGE | NULL_RANGE)) == EQ_RANGE) |
|
6525 |
{
|
|
6526 |
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.) |
6527 |
return ((key->flags & (HA_NOSAME)) == HA_NOSAME && |
1
by brian
clean slate |
6528 |
key->key_length == tmp->min_length); |
6529 |
}
|
|
6530 |
}
|
|
6531 |
return 0; |
|
6532 |
}
|
|
6533 |
||
6534 |
||
6535 |
||
6536 |
/*
|
|
55
by brian
Update for using real bool types. |
6537 |
Return true if any part of the key is NULL
|
1
by brian
clean slate |
6538 |
|
6539 |
SYNOPSIS
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6540 |
null_part_in_key()
|
1
by brian
clean slate |
6541 |
key_part Array of key parts (index description)
|
6542 |
key Key values tuple
|
|
6543 |
length Length of key values tuple in bytes.
|
|
6544 |
||
6545 |
RETURN
|
|
55
by brian
Update for using real bool types. |
6546 |
true The tuple has at least one "keypartX is NULL"
|
6547 |
false Otherwise
|
|
1
by brian
clean slate |
6548 |
*/
|
6549 |
||
482
by Brian Aker
Remove uint. |
6550 |
static bool null_part_in_key(KEY_PART *key_part, const unsigned char *key, uint32_t length) |
1
by brian
clean slate |
6551 |
{
|
481
by Brian Aker
Remove all of uchar. |
6552 |
for (const unsigned char *end=key+length ; |
1
by brian
clean slate |
6553 |
key < end; |
6554 |
key+= key_part++->store_length) |
|
6555 |
{
|
|
6556 |
if (key_part->null_bit && *key) |
|
6557 |
return 1; |
|
6558 |
}
|
|
6559 |
return 0; |
|
6560 |
}
|
|
6561 |
||
6562 |
||
6563 |
bool QUICK_SELECT_I::is_keys_used(const MY_BITMAP *fields) |
|
6564 |
{
|
|
6565 |
return is_key_used(head, index, fields); |
|
6566 |
}
|
|
6567 |
||
6568 |
bool QUICK_INDEX_MERGE_SELECT::is_keys_used(const MY_BITMAP *fields) |
|
6569 |
{
|
|
6570 |
QUICK_RANGE_SELECT *quick; |
|
6571 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
|
6572 |
while ((quick= it++)) |
|
6573 |
{
|
|
6574 |
if (is_key_used(head, quick->index, fields)) |
|
6575 |
return 1; |
|
6576 |
}
|
|
6577 |
return 0; |
|
6578 |
}
|
|
6579 |
||
6580 |
bool QUICK_ROR_INTERSECT_SELECT::is_keys_used(const MY_BITMAP *fields) |
|
6581 |
{
|
|
6582 |
QUICK_RANGE_SELECT *quick; |
|
6583 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
|
6584 |
while ((quick= it++)) |
|
6585 |
{
|
|
6586 |
if (is_key_used(head, quick->index, fields)) |
|
6587 |
return 1; |
|
6588 |
}
|
|
6589 |
return 0; |
|
6590 |
}
|
|
6591 |
||
6592 |
bool QUICK_ROR_UNION_SELECT::is_keys_used(const MY_BITMAP *fields) |
|
6593 |
{
|
|
6594 |
QUICK_SELECT_I *quick; |
|
6595 |
List_iterator_fast<QUICK_SELECT_I> it(quick_selects); |
|
6596 |
while ((quick= it++)) |
|
6597 |
{
|
|
6598 |
if (quick->is_keys_used(fields)) |
|
6599 |
return 1; |
|
6600 |
}
|
|
6601 |
return 0; |
|
6602 |
}
|
|
6603 |
||
6604 |
||
6605 |
/*
|
|
6606 |
Create quick select from ref/ref_or_null scan.
|
|
6607 |
||
6608 |
SYNOPSIS
|
|
6609 |
get_quick_select_for_ref()
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
6610 |
session Thread handle
|
1
by brian
clean slate |
6611 |
table Table to access
|
6612 |
ref ref[_or_null] scan parameters
|
|
6613 |
records Estimate of number of records (needed only to construct
|
|
6614 |
quick select)
|
|
6615 |
NOTES
|
|
6616 |
This allocates things in a new memory root, as this may be called many
|
|
6617 |
times during a query.
|
|
6618 |
||
6619 |
RETURN
|
|
6620 |
Quick select that retrieves the same rows as passed ref scan
|
|
6621 |
NULL on error.
|
|
6622 |
*/
|
|
6623 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
6624 |
QUICK_RANGE_SELECT *get_quick_select_for_ref(Session *session, Table *table, |
1
by brian
clean slate |
6625 |
TABLE_REF *ref, ha_rows records) |
6626 |
{
|
|
6627 |
MEM_ROOT *old_root, *alloc; |
|
6628 |
QUICK_RANGE_SELECT *quick; |
|
6629 |
KEY *key_info = &table->key_info[ref->key]; |
|
6630 |
KEY_PART *key_part; |
|
6631 |
QUICK_RANGE *range; |
|
482
by Brian Aker
Remove uint. |
6632 |
uint32_t part; |
55
by brian
Update for using real bool types. |
6633 |
bool create_err= false; |
1
by brian
clean slate |
6634 |
COST_VECT cost; |
6635 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
6636 |
old_root= session->mem_root; |
6637 |
/* The following call may change session->mem_root */
|
|
6638 |
quick= new QUICK_RANGE_SELECT(session, table, ref->key, 0, 0, &create_err); |
|
1
by brian
clean slate |
6639 |
/* save mem_root set by QUICK_RANGE_SELECT constructor */
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
6640 |
alloc= session->mem_root; |
1
by brian
clean slate |
6641 |
/*
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
6642 |
return back default mem_root (session->mem_root) changed by
|
1
by brian
clean slate |
6643 |
QUICK_RANGE_SELECT constructor
|
6644 |
*/
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
6645 |
session->mem_root= old_root; |
1
by brian
clean slate |
6646 |
|
6647 |
if (!quick || create_err) |
|
6648 |
return 0; /* no ranges found */ |
|
6649 |
if (quick->init()) |
|
6650 |
goto err; |
|
6651 |
quick->records= records; |
|
6652 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
6653 |
if ((cp_buffer_from_ref(session, ref) && session->is_fatal_error) || |
1
by brian
clean slate |
6654 |
!(range= new(alloc) QUICK_RANGE())) |
6655 |
goto err; // out of memory |
|
6656 |
||
6657 |
range->min_key= range->max_key= ref->key_buff; |
|
6658 |
range->min_length= range->max_length= ref->key_length; |
|
6659 |
range->min_keypart_map= range->max_keypart_map= |
|
6660 |
make_prev_keypart_map(ref->key_parts); |
|
6661 |
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.) |
6662 |
key_info->flags == 0) ? EQ_RANGE : 0); |
1
by brian
clean slate |
6663 |
|
6664 |
if (!(quick->key_parts=key_part=(KEY_PART *) |
|
6665 |
alloc_root(&quick->alloc,sizeof(KEY_PART)*ref->key_parts))) |
|
6666 |
goto err; |
|
6667 |
||
6668 |
for (part=0 ; part < ref->key_parts ;part++,key_part++) |
|
6669 |
{
|
|
6670 |
key_part->part=part; |
|
6671 |
key_part->field= key_info->key_part[part].field; |
|
6672 |
key_part->length= key_info->key_part[part].length; |
|
6673 |
key_part->store_length= key_info->key_part[part].store_length; |
|
6674 |
key_part->null_bit= key_info->key_part[part].null_bit; |
|
206
by Brian Aker
Removed final uint dead types. |
6675 |
key_part->flag= (uint8_t) key_info->key_part[part].key_part_flag; |
1
by brian
clean slate |
6676 |
}
|
481
by Brian Aker
Remove all of uchar. |
6677 |
if (insert_dynamic(&quick->ranges,(unsigned char*)&range)) |
1
by brian
clean slate |
6678 |
goto err; |
6679 |
||
6680 |
/*
|
|
6681 |
Add a NULL range if REF_OR_NULL optimization is used.
|
|
6682 |
For example:
|
|
6683 |
if we have "WHERE A=2 OR A IS NULL" we created the (A=2) range above
|
|
6684 |
and have ref->null_ref_key set. Will create a new NULL range here.
|
|
6685 |
*/
|
|
6686 |
if (ref->null_ref_key) |
|
6687 |
{
|
|
6688 |
QUICK_RANGE *null_range; |
|
6689 |
||
6690 |
*ref->null_ref_key= 1; // Set null byte then create a range |
|
6691 |
if (!(null_range= new (alloc) |
|
6692 |
QUICK_RANGE(ref->key_buff, ref->key_length, |
|
6693 |
make_prev_keypart_map(ref->key_parts), |
|
6694 |
ref->key_buff, ref->key_length, |
|
6695 |
make_prev_keypart_map(ref->key_parts), EQ_RANGE))) |
|
6696 |
goto err; |
|
6697 |
*ref->null_ref_key= 0; // Clear null byte |
|
481
by Brian Aker
Remove all of uchar. |
6698 |
if (insert_dynamic(&quick->ranges,(unsigned char*)&null_range)) |
1
by brian
clean slate |
6699 |
goto err; |
6700 |
}
|
|
6701 |
||
6702 |
/* Call multi_range_read_info() to get the MRR flags and buffer size */
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6703 |
quick->mrr_flags= HA_MRR_NO_ASSOCIATION | |
1
by brian
clean slate |
6704 |
(table->key_read ? HA_MRR_INDEX_ONLY : 0); |
520.1.22
by Brian Aker
Second pass of thd cleanup |
6705 |
if (session->lex->sql_command != SQLCOM_SELECT) |
1
by brian
clean slate |
6706 |
quick->mrr_flags |= HA_MRR_USE_DEFAULT_IMPL; |
6707 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
6708 |
quick->mrr_buf_size= session->variables.read_rnd_buff_size; |
895
by Brian Aker
Completion (?) of uint conversion. |
6709 |
if (table->file->multi_range_read_info(quick->index, 1, (uint32_t)records, |
1
by brian
clean slate |
6710 |
&quick->mrr_buf_size, |
6711 |
&quick->mrr_flags, &cost)) |
|
6712 |
goto err; |
|
6713 |
||
6714 |
return quick; |
|
6715 |
err: |
|
6716 |
delete quick; |
|
6717 |
return 0; |
|
6718 |
}
|
|
6719 |
||
6720 |
||
6721 |
/*
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6722 |
Perform key scans for all used indexes (except CPK), get rowids and merge
|
1
by brian
clean slate |
6723 |
them into an ordered non-recurrent sequence of rowids.
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6724 |
|
1
by brian
clean slate |
6725 |
The merge/duplicate removal is performed using Unique class. We put all
|
6726 |
rowids into Unique, get the sorted sequence and destroy the Unique.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6727 |
|
55
by brian
Update for using real bool types. |
6728 |
If table has a clustered primary key that covers all rows (true for bdb
|
1
by brian
clean slate |
6729 |
and innodb currently) and one of the index_merge scans is a scan on PK,
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6730 |
then rows that will be retrieved by PK scan are not put into Unique and
|
1
by brian
clean slate |
6731 |
primary key scan is not performed here, it is performed later separately.
|
6732 |
||
6733 |
RETURN
|
|
6734 |
0 OK
|
|
6735 |
other error
|
|
6736 |
*/
|
|
6737 |
||
6738 |
int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() |
|
6739 |
{
|
|
6740 |
List_iterator_fast<QUICK_RANGE_SELECT> cur_quick_it(quick_selects); |
|
6741 |
QUICK_RANGE_SELECT* cur_quick; |
|
6742 |
int result; |
|
6743 |
Unique *unique; |
|
6744 |
handler *file= head->file; |
|
6745 |
||
6746 |
file->extra(HA_EXTRA_KEYREAD); |
|
6747 |
head->prepare_for_position(); |
|
6748 |
||
6749 |
cur_quick_it.rewind(); |
|
6750 |
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. |
6751 |
assert(cur_quick != 0); |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6752 |
|
1
by brian
clean slate |
6753 |
/*
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6754 |
We reuse the same instance of handler so we need to call both init and
|
1
by brian
clean slate |
6755 |
reset here.
|
6756 |
*/
|
|
6757 |
if (cur_quick->init() || cur_quick->reset()) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6758 |
return 0; |
1
by brian
clean slate |
6759 |
|
6760 |
unique= new Unique(refpos_order_cmp, (void *)file, |
|
6761 |
file->ref_length, |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
6762 |
session->variables.sortbuff_size); |
1
by brian
clean slate |
6763 |
if (!unique) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6764 |
return 0; |
1
by brian
clean slate |
6765 |
for (;;) |
6766 |
{
|
|
6767 |
while ((result= cur_quick->get_next()) == HA_ERR_END_OF_FILE) |
|
6768 |
{
|
|
6769 |
cur_quick->range_end(); |
|
6770 |
cur_quick= cur_quick_it++; |
|
6771 |
if (!cur_quick) |
|
6772 |
break; |
|
6773 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6774 |
if (cur_quick->file->inited != handler::NONE) |
1
by brian
clean slate |
6775 |
cur_quick->file->ha_index_end(); |
6776 |
if (cur_quick->init() || cur_quick->reset()) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6777 |
return 0; |
1
by brian
clean slate |
6778 |
}
|
6779 |
||
6780 |
if (result) |
|
6781 |
{
|
|
6782 |
if (result != HA_ERR_END_OF_FILE) |
|
6783 |
{
|
|
6784 |
cur_quick->range_end(); |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6785 |
return result; |
1
by brian
clean slate |
6786 |
}
|
6787 |
break; |
|
6788 |
}
|
|
6789 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
6790 |
if (session->killed) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6791 |
return 0; |
1
by brian
clean slate |
6792 |
|
6793 |
/* skip row if it will be retrieved by clustered PK scan */
|
|
6794 |
if (pk_quick_select && pk_quick_select->row_in_ranges()) |
|
6795 |
continue; |
|
6796 |
||
6797 |
cur_quick->file->position(cur_quick->record); |
|
6798 |
result= unique->unique_add((char*)cur_quick->file->ref); |
|
6799 |
if (result) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6800 |
return 0; |
1
by brian
clean slate |
6801 |
|
6802 |
}
|
|
6803 |
||
6804 |
/* ok, all row ids are in Unique */
|
|
6805 |
result= unique->get(head); |
|
6806 |
delete unique; |
|
55
by brian
Update for using real bool types. |
6807 |
doing_pk_scan= false; |
1
by brian
clean slate |
6808 |
/* index_merge currently doesn't support "using index" at all */
|
6809 |
file->extra(HA_EXTRA_NO_KEYREAD); |
|
6810 |
/* start table scan */
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
6811 |
init_read_record(&read_record, session, head, (SQL_SELECT*) 0, 1, 1); |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6812 |
return result; |
1
by brian
clean slate |
6813 |
}
|
6814 |
||
6815 |
||
6816 |
/*
|
|
6817 |
Get next row for index_merge.
|
|
6818 |
NOTES
|
|
6819 |
The rows are read from
|
|
6820 |
1. rowids stored in Unique.
|
|
6821 |
2. QUICK_RANGE_SELECT with clustered primary key (if any).
|
|
6822 |
The sets of rows retrieved in 1) and 2) are guaranteed to be disjoint.
|
|
6823 |
*/
|
|
6824 |
||
6825 |
int QUICK_INDEX_MERGE_SELECT::get_next() |
|
6826 |
{
|
|
6827 |
int result; |
|
6828 |
||
6829 |
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. |
6830 |
return(pk_quick_select->get_next()); |
1
by brian
clean slate |
6831 |
|
6832 |
if ((result= read_record.read_record(&read_record)) == -1) |
|
6833 |
{
|
|
6834 |
result= HA_ERR_END_OF_FILE; |
|
6835 |
end_read_record(&read_record); |
|
6836 |
/* All rows from Unique have been retrieved, do a clustered PK scan */
|
|
6837 |
if (pk_quick_select) |
|
6838 |
{
|
|
55
by brian
Update for using real bool types. |
6839 |
doing_pk_scan= true; |
1
by brian
clean slate |
6840 |
if ((result= pk_quick_select->init()) || |
6841 |
(result= pk_quick_select->reset())) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6842 |
return 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. |
6843 |
return(pk_quick_select->get_next()); |
1
by brian
clean slate |
6844 |
}
|
6845 |
}
|
|
6846 |
||
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6847 |
return result; |
1
by brian
clean slate |
6848 |
}
|
6849 |
||
6850 |
||
6851 |
/*
|
|
6852 |
Retrieve next record.
|
|
6853 |
SYNOPSIS
|
|
6854 |
QUICK_ROR_INTERSECT_SELECT::get_next()
|
|
6855 |
||
6856 |
NOTES
|
|
6857 |
Invariant on enter/exit: all intersected selects have retrieved all index
|
|
6858 |
records with rowid <= some_rowid_val and no intersected select has
|
|
6859 |
retrieved any index records with rowid > some_rowid_val.
|
|
6860 |
We start fresh and loop until we have retrieved the same rowid in each of
|
|
6861 |
the key scans or we got an error.
|
|
6862 |
||
6863 |
If a Clustered PK scan is present, it is used only to check if row
|
|
6864 |
satisfies its condition (and never used for row retrieval).
|
|
6865 |
||
6866 |
RETURN
|
|
6867 |
0 - Ok
|
|
6868 |
other - Error code if any error occurred.
|
|
6869 |
*/
|
|
6870 |
||
6871 |
int QUICK_ROR_INTERSECT_SELECT::get_next() |
|
6872 |
{
|
|
6873 |
List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects); |
|
6874 |
QUICK_RANGE_SELECT* quick; |
|
6875 |
int error, cmp; |
|
482
by Brian Aker
Remove uint. |
6876 |
uint32_t last_rowid_count=0; |
1
by brian
clean slate |
6877 |
|
6878 |
do
|
|
6879 |
{
|
|
6880 |
/* Get a rowid for first quick and save it as a 'candidate' */
|
|
6881 |
quick= quick_it++; |
|
6882 |
error= quick->get_next(); |
|
6883 |
if (cpk_quick) |
|
6884 |
{
|
|
6885 |
while (!error && !cpk_quick->row_in_ranges()) |
|
6886 |
error= quick->get_next(); |
|
6887 |
}
|
|
6888 |
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. |
6889 |
return(error); |
1
by brian
clean slate |
6890 |
|
6891 |
quick->file->position(quick->record); |
|
6892 |
memcpy(last_rowid, quick->file->ref, head->file->ref_length); |
|
6893 |
last_rowid_count= 1; |
|
6894 |
||
6895 |
while (last_rowid_count < quick_selects.elements) |
|
6896 |
{
|
|
6897 |
if (!(quick= quick_it++)) |
|
6898 |
{
|
|
6899 |
quick_it.rewind(); |
|
6900 |
quick= quick_it++; |
|
6901 |
}
|
|
6902 |
||
6903 |
do
|
|
6904 |
{
|
|
6905 |
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. |
6906 |
return(error); |
1
by brian
clean slate |
6907 |
quick->file->position(quick->record); |
6908 |
cmp= head->file->cmp_ref(quick->file->ref, last_rowid); |
|
6909 |
} while (cmp < 0); |
|
6910 |
||
6911 |
/* Ok, current select 'caught up' and returned ref >= cur_ref */
|
|
6912 |
if (cmp > 0) |
|
6913 |
{
|
|
6914 |
/* Found a row with ref > cur_ref. Make it a new 'candidate' */
|
|
6915 |
if (cpk_quick) |
|
6916 |
{
|
|
6917 |
while (!cpk_quick->row_in_ranges()) |
|
6918 |
{
|
|
6919 |
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. |
6920 |
return(error); |
1
by brian
clean slate |
6921 |
}
|
6922 |
}
|
|
6923 |
memcpy(last_rowid, quick->file->ref, head->file->ref_length); |
|
6924 |
last_rowid_count= 1; |
|
6925 |
}
|
|
6926 |
else
|
|
6927 |
{
|
|
6928 |
/* current 'candidate' row confirmed by this select */
|
|
6929 |
last_rowid_count++; |
|
6930 |
}
|
|
6931 |
}
|
|
6932 |
||
6933 |
/* We get here if we got the same row ref in all scans. */
|
|
6934 |
if (need_to_fetch_row) |
|
6935 |
error= head->file->rnd_pos(head->record[0], last_rowid); |
|
6936 |
} 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. |
6937 |
return(error); |
1
by brian
clean slate |
6938 |
}
|
6939 |
||
6940 |
||
6941 |
/*
|
|
6942 |
Retrieve next record.
|
|
6943 |
SYNOPSIS
|
|
6944 |
QUICK_ROR_UNION_SELECT::get_next()
|
|
6945 |
||
6946 |
NOTES
|
|
6947 |
Enter/exit invariant:
|
|
6948 |
For each quick select in the queue a {key,rowid} tuple has been
|
|
6949 |
retrieved but the corresponding row hasn't been passed to output.
|
|
6950 |
||
6951 |
RETURN
|
|
6952 |
0 - Ok
|
|
6953 |
other - Error code if any error occurred.
|
|
6954 |
*/
|
|
6955 |
||
6956 |
int QUICK_ROR_UNION_SELECT::get_next() |
|
6957 |
{
|
|
6958 |
int error, dup_row; |
|
6959 |
QUICK_SELECT_I *quick; |
|
481
by Brian Aker
Remove all of uchar. |
6960 |
unsigned char *tmp; |
1
by brian
clean slate |
6961 |
|
6962 |
do
|
|
6963 |
{
|
|
6964 |
do
|
|
6965 |
{
|
|
6966 |
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. |
6967 |
return(HA_ERR_END_OF_FILE); |
1
by brian
clean slate |
6968 |
/* Ok, we have a queue with >= 1 scans */
|
6969 |
||
6970 |
quick= (QUICK_SELECT_I*)queue_top(&queue); |
|
6971 |
memcpy(cur_rowid, quick->last_rowid, rowid_length); |
|
6972 |
||
6973 |
/* put into queue rowid from the same stream as top element */
|
|
6974 |
if ((error= quick->get_next())) |
|
6975 |
{
|
|
6976 |
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. |
6977 |
return(error); |
1
by brian
clean slate |
6978 |
queue_remove(&queue, 0); |
6979 |
}
|
|
6980 |
else
|
|
6981 |
{
|
|
6982 |
quick->save_last_pos(); |
|
6983 |
queue_replaced(&queue); |
|
6984 |
}
|
|
6985 |
||
6986 |
if (!have_prev_rowid) |
|
6987 |
{
|
|
6988 |
/* No rows have been returned yet */
|
|
55
by brian
Update for using real bool types. |
6989 |
dup_row= false; |
6990 |
have_prev_rowid= true; |
|
1
by brian
clean slate |
6991 |
}
|
6992 |
else
|
|
6993 |
dup_row= !head->file->cmp_ref(cur_rowid, prev_rowid); |
|
6994 |
} while (dup_row); |
|
6995 |
||
6996 |
tmp= cur_rowid; |
|
6997 |
cur_rowid= prev_rowid; |
|
6998 |
prev_rowid= tmp; |
|
6999 |
||
7000 |
error= head->file->rnd_pos(quick->record, prev_rowid); |
|
7001 |
} 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. |
7002 |
return(error); |
1
by brian
clean slate |
7003 |
}
|
7004 |
||
7005 |
||
7006 |
int QUICK_RANGE_SELECT::reset() |
|
7007 |
{
|
|
482
by Brian Aker
Remove uint. |
7008 |
uint32_t buf_size; |
481
by Brian Aker
Remove all of uchar. |
7009 |
unsigned char *mrange_buff; |
1
by brian
clean slate |
7010 |
int error; |
7011 |
HANDLER_BUFFER empty_buf; |
|
7012 |
last_range= NULL; |
|
7013 |
cur_range= (QUICK_RANGE**) ranges.buffer; |
|
7014 |
||
7015 |
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. |
7016 |
return(error); |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7017 |
|
1
by brian
clean slate |
7018 |
/* Allocate buffer if we need one but haven't allocated it yet */
|
7019 |
if (mrr_buf_size && !mrr_buf_desc) |
|
7020 |
{
|
|
7021 |
buf_size= mrr_buf_size; |
|
7022 |
while (buf_size && !my_multi_malloc(MYF(MY_WME), |
|
7023 |
&mrr_buf_desc, sizeof(*mrr_buf_desc), |
|
7024 |
&mrange_buff, buf_size, |
|
461
by Monty Taylor
Removed NullS. bu-bye. |
7025 |
NULL)) |
1
by brian
clean slate |
7026 |
{
|
7027 |
/* Try to shrink the buffers until both are 0. */
|
|
7028 |
buf_size/= 2; |
|
7029 |
}
|
|
7030 |
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. |
7031 |
return(HA_ERR_OUT_OF_MEM); |
1
by brian
clean slate |
7032 |
|
7033 |
/* Initialize the handler buffer. */
|
|
7034 |
mrr_buf_desc->buffer= mrange_buff; |
|
7035 |
mrr_buf_desc->buffer_end= mrange_buff + buf_size; |
|
7036 |
mrr_buf_desc->end_of_used_area= mrange_buff; |
|
7037 |
}
|
|
7038 |
||
7039 |
if (!mrr_buf_desc) |
|
7040 |
empty_buf.buffer= empty_buf.buffer_end= empty_buf.end_of_used_area= NULL; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7041 |
|
1
by brian
clean slate |
7042 |
if (sorted) |
7043 |
mrr_flags |= HA_MRR_SORTED; |
|
7044 |
RANGE_SEQ_IF seq_funcs= {quick_range_seq_init, quick_range_seq_next}; |
|
7045 |
error= file->multi_range_read_init(&seq_funcs, (void*)this, ranges.elements, |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7046 |
mrr_flags, mrr_buf_desc? mrr_buf_desc: |
1
by brian
clean slate |
7047 |
&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. |
7048 |
return(error); |
1
by brian
clean slate |
7049 |
}
|
7050 |
||
7051 |
||
7052 |
/*
|
|
7053 |
Range sequence interface implementation for array<QUICK_RANGE>: initialize
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7054 |
|
1
by brian
clean slate |
7055 |
SYNOPSIS
|
7056 |
quick_range_seq_init()
|
|
7057 |
init_param Caller-opaque paramenter: QUICK_RANGE_SELECT* pointer
|
|
7058 |
n_ranges Number of ranges in the sequence (ignored)
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7059 |
flags MRR flags (currently not used)
|
1
by brian
clean slate |
7060 |
|
7061 |
RETURN
|
|
7062 |
Opaque value to be passed to quick_range_seq_next
|
|
7063 |
*/
|
|
7064 |
||
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
7065 |
range_seq_t quick_range_seq_init(void *init_param, uint32_t, uint32_t) |
1
by brian
clean slate |
7066 |
{
|
7067 |
QUICK_RANGE_SELECT *quick= (QUICK_RANGE_SELECT*)init_param; |
|
7068 |
quick->qr_traversal_ctx.first= (QUICK_RANGE**)quick->ranges.buffer; |
|
7069 |
quick->qr_traversal_ctx.cur= (QUICK_RANGE**)quick->ranges.buffer; |
|
77.1.46
by Monty Taylor
Finished the warnings work! |
7070 |
quick->qr_traversal_ctx.last= quick->qr_traversal_ctx.cur + |
1
by brian
clean slate |
7071 |
quick->ranges.elements; |
7072 |
return &quick->qr_traversal_ctx; |
|
7073 |
}
|
|
7074 |
||
7075 |
||
7076 |
/*
|
|
7077 |
Range sequence interface implementation for array<QUICK_RANGE>: get next
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7078 |
|
1
by brian
clean slate |
7079 |
SYNOPSIS
|
7080 |
quick_range_seq_next()
|
|
7081 |
rseq Value returned from quick_range_seq_init
|
|
7082 |
range OUT Store information about the range here
|
|
7083 |
||
7084 |
RETURN
|
|
7085 |
0 Ok
|
|
7086 |
1 No more ranges in the sequence
|
|
7087 |
*/
|
|
7088 |
||
482
by Brian Aker
Remove uint. |
7089 |
uint32_t quick_range_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range) |
1
by brian
clean slate |
7090 |
{
|
7091 |
QUICK_RANGE_SEQ_CTX *ctx= (QUICK_RANGE_SEQ_CTX*)rseq; |
|
7092 |
||
7093 |
if (ctx->cur == ctx->last) |
|
7094 |
return 1; /* no more ranges */ |
|
7095 |
||
7096 |
QUICK_RANGE *cur= *(ctx->cur); |
|
7097 |
key_range *start_key= &range->start_key; |
|
7098 |
key_range *end_key= &range->end_key; |
|
7099 |
||
7100 |
start_key->key= cur->min_key; |
|
7101 |
start_key->length= cur->min_length; |
|
7102 |
start_key->keypart_map= cur->min_keypart_map; |
|
7103 |
start_key->flag= ((cur->flag & NEAR_MIN) ? HA_READ_AFTER_KEY : |
|
7104 |
(cur->flag & EQ_RANGE) ? |
|
7105 |
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT); |
|
7106 |
end_key->key= cur->max_key; |
|
7107 |
end_key->length= cur->max_length; |
|
7108 |
end_key->keypart_map= cur->max_keypart_map; |
|
7109 |
/*
|
|
7110 |
We use HA_READ_AFTER_KEY here because if we are reading on a key
|
|
7111 |
prefix. We want to find all keys with this prefix.
|
|
7112 |
*/
|
|
7113 |
end_key->flag= (cur->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : |
|
7114 |
HA_READ_AFTER_KEY); |
|
7115 |
range->range_flag= cur->flag; |
|
7116 |
ctx->cur++; |
|
7117 |
return 0; |
|
7118 |
}
|
|
7119 |
||
7120 |
||
7121 |
/*
|
|
7122 |
MRR range sequence interface: array<QUICK_RANGE> impl: utility func for NDB
|
|
7123 |
||
7124 |
SYNOPSIS
|
|
7125 |
mrr_persistent_flag_storage()
|
|
7126 |
seq Range sequence being traversed
|
|
7127 |
idx Number of range
|
|
7128 |
||
7129 |
DESCRIPTION
|
|
7130 |
MRR/NDB implementation needs to store some bits for each range. This
|
|
7131 |
function returns a reference to the "range_flag" associated with the
|
|
7132 |
range number idx.
|
|
7133 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7134 |
This function should be removed when we get a proper MRR/NDB
|
1
by brian
clean slate |
7135 |
implementation.
|
7136 |
||
7137 |
RETURN
|
|
7138 |
Reference to range_flag associated with range number #idx
|
|
7139 |
*/
|
|
7140 |
||
482
by Brian Aker
Remove uint. |
7141 |
uint16_t &mrr_persistent_flag_storage(range_seq_t seq, uint32_t idx) |
1
by brian
clean slate |
7142 |
{
|
7143 |
QUICK_RANGE_SEQ_CTX *ctx= (QUICK_RANGE_SEQ_CTX*)seq; |
|
7144 |
return ctx->first[idx]->flag; |
|
7145 |
}
|
|
7146 |
||
7147 |
||
7148 |
/*
|
|
7149 |
MRR range sequence interface: array<QUICK_RANGE> impl: utility func for NDB
|
|
7150 |
||
7151 |
SYNOPSIS
|
|
7152 |
mrr_get_ptr_by_idx()
|
|
7153 |
seq Range sequence bening traversed
|
|
7154 |
idx Number of the range
|
|
7155 |
||
7156 |
DESCRIPTION
|
|
7157 |
An extension of MRR range sequence interface needed by NDB: return the
|
|
7158 |
data associated with the given range.
|
|
7159 |
||
7160 |
A proper MRR interface implementer is supposed to store and return
|
|
7161 |
range-associated data. NDB stores number of the range instead. So this
|
|
7162 |
is a helper function that translates range number to range associated
|
|
7163 |
data.
|
|
7164 |
||
7165 |
This function does nothing, as currrently there is only one user of the
|
|
7166 |
MRR interface - the quick range select code, and this user doesn't need
|
|
7167 |
to use range-associated data.
|
|
7168 |
||
7169 |
RETURN
|
|
7170 |
Reference to range-associated data
|
|
7171 |
*/
|
|
7172 |
||
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
7173 |
char* &mrr_get_ptr_by_idx(range_seq_t, uint32_t) |
1
by brian
clean slate |
7174 |
{
|
7175 |
static char *dummy; |
|
7176 |
return dummy; |
|
7177 |
}
|
|
7178 |
||
7179 |
||
7180 |
/*
|
|
7181 |
Get next possible record using quick-struct.
|
|
7182 |
||
7183 |
SYNOPSIS
|
|
7184 |
QUICK_RANGE_SELECT::get_next()
|
|
7185 |
||
7186 |
NOTES
|
|
7187 |
Record is read into table->record[0]
|
|
7188 |
||
7189 |
RETURN
|
|
7190 |
0 Found row
|
|
7191 |
HA_ERR_END_OF_FILE No (more) rows in range
|
|
7192 |
# Error code
|
|
7193 |
*/
|
|
7194 |
||
7195 |
int QUICK_RANGE_SELECT::get_next() |
|
7196 |
{
|
|
7197 |
char *dummy; |
|
7198 |
if (in_ror_merged_scan) |
|
7199 |
{
|
|
7200 |
/*
|
|
7201 |
We don't need to signal the bitmap change as the bitmap is always the
|
|
7202 |
same for this head->file
|
|
7203 |
*/
|
|
7204 |
head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap); |
|
7205 |
}
|
|
7206 |
||
7207 |
int result= file->multi_range_read_next(&dummy); |
|
7208 |
||
7209 |
if (in_ror_merged_scan) |
|
7210 |
{
|
|
7211 |
/* Restore bitmaps set on entry */
|
|
7212 |
head->column_bitmaps_set_no_signal(save_read_set, save_write_set); |
|
7213 |
}
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7214 |
return result; |
1
by brian
clean slate |
7215 |
}
|
7216 |
||
7217 |
||
7218 |
/*
|
|
7219 |
Get the next record with a different prefix.
|
|
7220 |
||
7221 |
SYNOPSIS
|
|
7222 |
QUICK_RANGE_SELECT::get_next_prefix()
|
|
7223 |
prefix_length length of cur_prefix
|
|
7224 |
cur_prefix prefix of a key to be searched for
|
|
7225 |
||
7226 |
DESCRIPTION
|
|
7227 |
Each subsequent call to the method retrieves the first record that has a
|
|
7228 |
prefix with length prefix_length different from cur_prefix, such that the
|
|
7229 |
record with the new prefix is within the ranges described by
|
|
7230 |
this->ranges. The record found is stored into the buffer pointed by
|
|
7231 |
this->record.
|
|
7232 |
The method is useful for GROUP-BY queries with range conditions to
|
|
7233 |
discover the prefix of the next group that satisfies the range conditions.
|
|
7234 |
||
7235 |
TODO
|
|
7236 |
This method is a modified copy of QUICK_RANGE_SELECT::get_next(), so both
|
|
7237 |
methods should be unified into a more general one to reduce code
|
|
7238 |
duplication.
|
|
7239 |
||
7240 |
RETURN
|
|
7241 |
0 on success
|
|
7242 |
HA_ERR_END_OF_FILE if returned all keys
|
|
7243 |
other if some error occurred
|
|
7244 |
*/
|
|
7245 |
||
482
by Brian Aker
Remove uint. |
7246 |
int QUICK_RANGE_SELECT::get_next_prefix(uint32_t prefix_length, |
1
by brian
clean slate |
7247 |
key_part_map keypart_map, |
481
by Brian Aker
Remove all of uchar. |
7248 |
unsigned char *cur_prefix) |
1
by brian
clean slate |
7249 |
{
|
7250 |
for (;;) |
|
7251 |
{
|
|
7252 |
int result; |
|
7253 |
key_range start_key, end_key; |
|
7254 |
if (last_range) |
|
7255 |
{
|
|
7256 |
/* 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. |
7257 |
assert(cur_prefix != 0); |
1
by brian
clean slate |
7258 |
result= file->index_read_map(record, cur_prefix, keypart_map, |
7259 |
HA_READ_AFTER_KEY); |
|
7260 |
if (result || (file->compare_key(file->end_range) <= 0)) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7261 |
return result; |
1
by brian
clean slate |
7262 |
}
|
7263 |
||
482
by Brian Aker
Remove uint. |
7264 |
uint32_t count= ranges.elements - (cur_range - (QUICK_RANGE**) ranges.buffer); |
1
by brian
clean slate |
7265 |
if (count == 0) |
7266 |
{
|
|
7267 |
/* Ranges have already been used up before. None is left for read. */
|
|
7268 |
last_range= 0; |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7269 |
return HA_ERR_END_OF_FILE; |
1
by brian
clean slate |
7270 |
}
|
7271 |
last_range= *(cur_range++); |
|
7272 |
||
481
by Brian Aker
Remove all of uchar. |
7273 |
start_key.key= (const unsigned char*) last_range->min_key; |
398.1.4
by Monty Taylor
Renamed max/min. |
7274 |
start_key.length= cmin(last_range->min_length, (uint16_t)prefix_length); |
1
by brian
clean slate |
7275 |
start_key.keypart_map= last_range->min_keypart_map & keypart_map; |
7276 |
start_key.flag= ((last_range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY : |
|
7277 |
(last_range->flag & EQ_RANGE) ? |
|
7278 |
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT); |
|
481
by Brian Aker
Remove all of uchar. |
7279 |
end_key.key= (const unsigned char*) last_range->max_key; |
398.1.4
by Monty Taylor
Renamed max/min. |
7280 |
end_key.length= cmin(last_range->max_length, (uint16_t)prefix_length); |
1
by brian
clean slate |
7281 |
end_key.keypart_map= last_range->max_keypart_map & keypart_map; |
7282 |
/*
|
|
7283 |
We use READ_AFTER_KEY here because if we are reading on a key
|
|
7284 |
prefix we want to find all keys with this prefix
|
|
7285 |
*/
|
|
7286 |
end_key.flag= (last_range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : |
|
7287 |
HA_READ_AFTER_KEY); |
|
7288 |
||
7289 |
result= file->read_range_first(last_range->min_keypart_map ? &start_key : 0, |
|
7290 |
last_range->max_keypart_map ? &end_key : 0, |
|
7291 |
test(last_range->flag & EQ_RANGE), |
|
7292 |
sorted); |
|
7293 |
if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE)) |
|
7294 |
last_range= 0; // Stop searching |
|
7295 |
||
7296 |
if (result != HA_ERR_END_OF_FILE) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7297 |
return result; |
1
by brian
clean slate |
7298 |
last_range= 0; // No matching rows; go to next range |
7299 |
}
|
|
7300 |
}
|
|
7301 |
||
7302 |
||
7303 |
/*
|
|
7304 |
Check if current row will be retrieved by this QUICK_RANGE_SELECT
|
|
7305 |
||
7306 |
NOTES
|
|
7307 |
It is assumed that currently a scan is being done on another index
|
|
7308 |
which reads all necessary parts of the index that is scanned by this
|
|
7309 |
quick select.
|
|
7310 |
The implementation does a binary search on sorted array of disjoint
|
|
7311 |
ranges, without taking size of range into account.
|
|
7312 |
||
7313 |
This function is used to filter out clustered PK scan rows in
|
|
7314 |
index_merge quick select.
|
|
7315 |
||
7316 |
RETURN
|
|
55
by brian
Update for using real bool types. |
7317 |
true if current row will be retrieved by this quick select
|
7318 |
false if not
|
|
1
by brian
clean slate |
7319 |
*/
|
7320 |
||
7321 |
bool QUICK_RANGE_SELECT::row_in_ranges() |
|
7322 |
{
|
|
7323 |
QUICK_RANGE *res; |
|
482
by Brian Aker
Remove uint. |
7324 |
uint32_t min= 0; |
7325 |
uint32_t max= ranges.elements - 1; |
|
7326 |
uint32_t mid= (max + min)/2; |
|
1
by brian
clean slate |
7327 |
|
7328 |
while (min != max) |
|
7329 |
{
|
|
7330 |
if (cmp_next(*(QUICK_RANGE**)dynamic_array_ptr(&ranges, mid))) |
|
7331 |
{
|
|
7332 |
/* current row value > mid->max */
|
|
7333 |
min= mid + 1; |
|
7334 |
}
|
|
7335 |
else
|
|
7336 |
max= mid; |
|
7337 |
mid= (min + max) / 2; |
|
7338 |
}
|
|
7339 |
res= *(QUICK_RANGE**)dynamic_array_ptr(&ranges, mid); |
|
7340 |
return (!cmp_next(res) && !cmp_prev(res)); |
|
7341 |
}
|
|
7342 |
||
7343 |
/*
|
|
7344 |
This is a hack: we inherit from QUICK_SELECT so that we can use the
|
|
7345 |
get_next() interface, but we have to hold a pointer to the original
|
|
7346 |
QUICK_SELECT because its data are used all over the place. What
|
|
7347 |
should be done is to factor out the data that is needed into a base
|
|
7348 |
class (QUICK_SELECT), and then have two subclasses (_ASC and _DESC)
|
|
7349 |
which handle the ranges and implement the get_next() function. But
|
|
7350 |
for now, this seems to work right at least.
|
|
7351 |
*/
|
|
7352 |
||
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
7353 |
QUICK_SELECT_DESC::QUICK_SELECT_DESC(QUICK_RANGE_SELECT *q, uint32_t, bool *) |
1
by brian
clean slate |
7354 |
:QUICK_RANGE_SELECT(*q), rev_it(rev_ranges) |
7355 |
{
|
|
7356 |
QUICK_RANGE *r; |
|
7357 |
||
7358 |
QUICK_RANGE **pr= (QUICK_RANGE**)ranges.buffer; |
|
7359 |
QUICK_RANGE **end_range= pr + ranges.elements; |
|
7360 |
for (; pr!=end_range; pr++) |
|
7361 |
rev_ranges.push_front(*pr); |
|
7362 |
||
7363 |
/* Remove EQ_RANGE flag for keys that are not using the full key */
|
|
7364 |
for (r = rev_it++; r; r = rev_it++) |
|
7365 |
{
|
|
7366 |
if ((r->flag & EQ_RANGE) && |
|
7367 |
head->key_info[index].key_length != r->max_length) |
|
7368 |
r->flag&= ~EQ_RANGE; |
|
7369 |
}
|
|
7370 |
rev_it.rewind(); |
|
7371 |
q->dont_free=1; // Don't free shared mem |
|
7372 |
delete q; |
|
7373 |
}
|
|
7374 |
||
7375 |
||
7376 |
int QUICK_SELECT_DESC::get_next() |
|
7377 |
{
|
|
7378 |
/* The max key is handled as follows:
|
|
7379 |
* - if there is NO_MAX_RANGE, start at the end and move backwards
|
|
7380 |
* - if it is an EQ_RANGE, which means that max key covers the entire
|
|
7381 |
* key, go directly to the key and read through it (sorting backwards is
|
|
7382 |
* same as sorting forwards)
|
|
7383 |
* - if it is NEAR_MAX, go to the key or next, step back once, and
|
|
7384 |
* move backwards
|
|
7385 |
* - otherwise (not NEAR_MAX == include the key), go after the key,
|
|
7386 |
* step back once, and move backwards
|
|
7387 |
*/
|
|
7388 |
||
7389 |
for (;;) |
|
7390 |
{
|
|
7391 |
int result; |
|
7392 |
if (last_range) |
|
7393 |
{ // Already read through key |
|
7394 |
result = ((last_range->flag & EQ_RANGE) |
|
7395 |
? file->index_next_same(record, last_range->min_key, |
|
7396 |
last_range->min_length) : |
|
7397 |
file->index_prev(record)); |
|
7398 |
if (!result) |
|
7399 |
{
|
|
7400 |
if (cmp_prev(*rev_it.ref()) == 0) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7401 |
return 0; |
1
by brian
clean slate |
7402 |
}
|
7403 |
else if (result != HA_ERR_END_OF_FILE) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7404 |
return result; |
1
by brian
clean slate |
7405 |
}
|
7406 |
||
7407 |
if (!(last_range= rev_it++)) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7408 |
return HA_ERR_END_OF_FILE; // All ranges used |
1
by brian
clean slate |
7409 |
|
7410 |
if (last_range->flag & NO_MAX_RANGE) // Read last record |
|
7411 |
{
|
|
7412 |
int local_error; |
|
7413 |
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. |
7414 |
return(local_error); // Empty table |
1
by brian
clean slate |
7415 |
if (cmp_prev(last_range) == 0) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7416 |
return 0; |
1
by brian
clean slate |
7417 |
last_range= 0; // No match; go to next range |
7418 |
continue; |
|
7419 |
}
|
|
7420 |
||
7421 |
if (last_range->flag & EQ_RANGE) |
|
7422 |
{
|
|
7423 |
result = file->index_read_map(record, last_range->max_key, |
|
7424 |
last_range->max_keypart_map, |
|
7425 |
HA_READ_KEY_EXACT); |
|
7426 |
}
|
|
7427 |
else
|
|
7428 |
{
|
|
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. |
7429 |
assert(last_range->flag & NEAR_MAX || |
1
by brian
clean slate |
7430 |
range_reads_after_key(last_range)); |
7431 |
result=file->index_read_map(record, last_range->max_key, |
|
7432 |
last_range->max_keypart_map, |
|
7433 |
((last_range->flag & NEAR_MAX) ? |
|
7434 |
HA_READ_BEFORE_KEY : |
|
7435 |
HA_READ_PREFIX_LAST_OR_PREV)); |
|
7436 |
}
|
|
7437 |
if (result) |
|
7438 |
{
|
|
7439 |
if (result != HA_ERR_KEY_NOT_FOUND && result != HA_ERR_END_OF_FILE) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7440 |
return result; |
1
by brian
clean slate |
7441 |
last_range= 0; // Not found, to next range |
7442 |
continue; |
|
7443 |
}
|
|
7444 |
if (cmp_prev(last_range) == 0) |
|
7445 |
{
|
|
7446 |
if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE)) |
|
7447 |
last_range= 0; // Stop searching |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7448 |
return 0; // Found key is in range |
1
by brian
clean slate |
7449 |
}
|
7450 |
last_range= 0; // To next range |
|
7451 |
}
|
|
7452 |
}
|
|
7453 |
||
7454 |
||
7455 |
/*
|
|
7456 |
Compare if found key is over max-value
|
|
7457 |
Returns 0 if key <= range->max_key
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7458 |
TODO: Figure out why can't this function be as simple as cmp_prev().
|
1
by brian
clean slate |
7459 |
*/
|
7460 |
||
7461 |
int QUICK_RANGE_SELECT::cmp_next(QUICK_RANGE *range_arg) |
|
7462 |
{
|
|
7463 |
if (range_arg->flag & NO_MAX_RANGE) |
|
7464 |
return 0; /* key can't be to large */ |
|
7465 |
||
7466 |
KEY_PART *key_part=key_parts; |
|
482
by Brian Aker
Remove uint. |
7467 |
uint32_t store_length; |
1
by brian
clean slate |
7468 |
|
481
by Brian Aker
Remove all of uchar. |
7469 |
for (unsigned char *key=range_arg->max_key, *end=key+range_arg->max_length; |
1
by brian
clean slate |
7470 |
key < end; |
7471 |
key+= store_length, key_part++) |
|
7472 |
{
|
|
7473 |
int cmp; |
|
7474 |
store_length= key_part->store_length; |
|
7475 |
if (key_part->null_bit) |
|
7476 |
{
|
|
7477 |
if (*key) |
|
7478 |
{
|
|
7479 |
if (!key_part->field->is_null()) |
|
7480 |
return 1; |
|
7481 |
continue; |
|
7482 |
}
|
|
7483 |
else if (key_part->field->is_null()) |
|
7484 |
return 0; |
|
7485 |
key++; // Skip null byte |
|
7486 |
store_length--; |
|
7487 |
}
|
|
7488 |
if ((cmp=key_part->field->key_cmp(key, key_part->length)) < 0) |
|
7489 |
return 0; |
|
7490 |
if (cmp > 0) |
|
7491 |
return 1; |
|
7492 |
}
|
|
7493 |
return (range_arg->flag & NEAR_MAX) ? 1 : 0; // Exact match |
|
7494 |
}
|
|
7495 |
||
7496 |
||
7497 |
/*
|
|
7498 |
Returns 0 if found key is inside range (found key >= range->min_key).
|
|
7499 |
*/
|
|
7500 |
||
7501 |
int QUICK_RANGE_SELECT::cmp_prev(QUICK_RANGE *range_arg) |
|
7502 |
{
|
|
7503 |
int cmp; |
|
7504 |
if (range_arg->flag & NO_MIN_RANGE) |
|
7505 |
return 0; /* key can't be to small */ |
|
7506 |
||
7507 |
cmp= key_cmp(key_part_info, range_arg->min_key, |
|
7508 |
range_arg->min_length); |
|
7509 |
if (cmp > 0 || (cmp == 0 && (range_arg->flag & NEAR_MIN) == false)) |
|
7510 |
return 0; |
|
7511 |
return 1; // outside of range |
|
7512 |
}
|
|
7513 |
||
7514 |
||
7515 |
/*
|
|
55
by brian
Update for using real bool types. |
7516 |
* true if this range will require using HA_READ_AFTER_KEY
|
1
by brian
clean slate |
7517 |
See comment in get_next() about this
|
7518 |
*/
|
|
7519 |
||
7520 |
bool QUICK_SELECT_DESC::range_reads_after_key(QUICK_RANGE *range_arg) |
|
7521 |
{
|
|
7522 |
return ((range_arg->flag & (NO_MAX_RANGE | NEAR_MAX)) || |
|
7523 |
!(range_arg->flag & EQ_RANGE) || |
|
7524 |
head->key_info[index].key_length != range_arg->max_length) ? 1 : 0; |
|
7525 |
}
|
|
7526 |
||
7527 |
||
7528 |
void QUICK_RANGE_SELECT::add_info_string(String *str) |
|
7529 |
{
|
|
7530 |
KEY *key_info= head->key_info + index; |
|
7531 |
str->append(key_info->name); |
|
7532 |
}
|
|
7533 |
||
7534 |
void QUICK_INDEX_MERGE_SELECT::add_info_string(String *str) |
|
7535 |
{
|
|
7536 |
QUICK_RANGE_SELECT *quick; |
|
55
by brian
Update for using real bool types. |
7537 |
bool first= true; |
1
by brian
clean slate |
7538 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
7539 |
str->append(STRING_WITH_LEN("sort_union(")); |
|
7540 |
while ((quick= it++)) |
|
7541 |
{
|
|
7542 |
if (!first) |
|
7543 |
str->append(','); |
|
7544 |
else
|
|
55
by brian
Update for using real bool types. |
7545 |
first= false; |
1
by brian
clean slate |
7546 |
quick->add_info_string(str); |
7547 |
}
|
|
7548 |
if (pk_quick_select) |
|
7549 |
{
|
|
7550 |
str->append(','); |
|
7551 |
pk_quick_select->add_info_string(str); |
|
7552 |
}
|
|
7553 |
str->append(')'); |
|
7554 |
}
|
|
7555 |
||
7556 |
void QUICK_ROR_INTERSECT_SELECT::add_info_string(String *str) |
|
7557 |
{
|
|
55
by brian
Update for using real bool types. |
7558 |
bool first= true; |
1
by brian
clean slate |
7559 |
QUICK_RANGE_SELECT *quick; |
7560 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
|
7561 |
str->append(STRING_WITH_LEN("intersect(")); |
|
7562 |
while ((quick= it++)) |
|
7563 |
{
|
|
7564 |
KEY *key_info= head->key_info + quick->index; |
|
7565 |
if (!first) |
|
7566 |
str->append(','); |
|
7567 |
else
|
|
55
by brian
Update for using real bool types. |
7568 |
first= false; |
1
by brian
clean slate |
7569 |
str->append(key_info->name); |
7570 |
}
|
|
7571 |
if (cpk_quick) |
|
7572 |
{
|
|
7573 |
KEY *key_info= head->key_info + cpk_quick->index; |
|
7574 |
str->append(','); |
|
7575 |
str->append(key_info->name); |
|
7576 |
}
|
|
7577 |
str->append(')'); |
|
7578 |
}
|
|
7579 |
||
7580 |
void QUICK_ROR_UNION_SELECT::add_info_string(String *str) |
|
7581 |
{
|
|
55
by brian
Update for using real bool types. |
7582 |
bool first= true; |
1
by brian
clean slate |
7583 |
QUICK_SELECT_I *quick; |
7584 |
List_iterator_fast<QUICK_SELECT_I> it(quick_selects); |
|
7585 |
str->append(STRING_WITH_LEN("union(")); |
|
7586 |
while ((quick= it++)) |
|
7587 |
{
|
|
7588 |
if (!first) |
|
7589 |
str->append(','); |
|
7590 |
else
|
|
55
by brian
Update for using real bool types. |
7591 |
first= false; |
1
by brian
clean slate |
7592 |
quick->add_info_string(str); |
7593 |
}
|
|
7594 |
str->append(')'); |
|
7595 |
}
|
|
7596 |
||
7597 |
||
7598 |
void QUICK_RANGE_SELECT::add_keys_and_lengths(String *key_names, |
|
7599 |
String *used_lengths) |
|
7600 |
{
|
|
7601 |
char buf[64]; |
|
482
by Brian Aker
Remove uint. |
7602 |
uint32_t length; |
1
by brian
clean slate |
7603 |
KEY *key_info= head->key_info + index; |
7604 |
key_names->append(key_info->name); |
|
152
by Brian Aker
longlong replacement |
7605 |
length= int64_t2str(max_used_key_length, buf, 10) - buf; |
1
by brian
clean slate |
7606 |
used_lengths->append(buf, length); |
7607 |
}
|
|
7608 |
||
7609 |
void QUICK_INDEX_MERGE_SELECT::add_keys_and_lengths(String *key_names, |
|
7610 |
String *used_lengths) |
|
7611 |
{
|
|
7612 |
char buf[64]; |
|
482
by Brian Aker
Remove uint. |
7613 |
uint32_t length; |
55
by brian
Update for using real bool types. |
7614 |
bool first= true; |
1
by brian
clean slate |
7615 |
QUICK_RANGE_SELECT *quick; |
7616 |
||
7617 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
|
7618 |
while ((quick= it++)) |
|
7619 |
{
|
|
7620 |
if (first) |
|
55
by brian
Update for using real bool types. |
7621 |
first= false; |
1
by brian
clean slate |
7622 |
else
|
7623 |
{
|
|
7624 |
key_names->append(','); |
|
7625 |
used_lengths->append(','); |
|
7626 |
}
|
|
7627 |
||
7628 |
KEY *key_info= head->key_info + quick->index; |
|
7629 |
key_names->append(key_info->name); |
|
152
by Brian Aker
longlong replacement |
7630 |
length= int64_t2str(quick->max_used_key_length, buf, 10) - buf; |
1
by brian
clean slate |
7631 |
used_lengths->append(buf, length); |
7632 |
}
|
|
7633 |
if (pk_quick_select) |
|
7634 |
{
|
|
7635 |
KEY *key_info= head->key_info + pk_quick_select->index; |
|
7636 |
key_names->append(','); |
|
7637 |
key_names->append(key_info->name); |
|
152
by Brian Aker
longlong replacement |
7638 |
length= int64_t2str(pk_quick_select->max_used_key_length, buf, 10) - buf; |
1
by brian
clean slate |
7639 |
used_lengths->append(','); |
7640 |
used_lengths->append(buf, length); |
|
7641 |
}
|
|
7642 |
}
|
|
7643 |
||
7644 |
void QUICK_ROR_INTERSECT_SELECT::add_keys_and_lengths(String *key_names, |
|
7645 |
String *used_lengths) |
|
7646 |
{
|
|
7647 |
char buf[64]; |
|
482
by Brian Aker
Remove uint. |
7648 |
uint32_t length; |
55
by brian
Update for using real bool types. |
7649 |
bool first= true; |
1
by brian
clean slate |
7650 |
QUICK_RANGE_SELECT *quick; |
7651 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
|
7652 |
while ((quick= it++)) |
|
7653 |
{
|
|
7654 |
KEY *key_info= head->key_info + quick->index; |
|
7655 |
if (first) |
|
55
by brian
Update for using real bool types. |
7656 |
first= false; |
1
by brian
clean slate |
7657 |
else
|
7658 |
{
|
|
7659 |
key_names->append(','); |
|
7660 |
used_lengths->append(','); |
|
7661 |
}
|
|
7662 |
key_names->append(key_info->name); |
|
152
by Brian Aker
longlong replacement |
7663 |
length= int64_t2str(quick->max_used_key_length, buf, 10) - buf; |
1
by brian
clean slate |
7664 |
used_lengths->append(buf, length); |
7665 |
}
|
|
7666 |
||
7667 |
if (cpk_quick) |
|
7668 |
{
|
|
7669 |
KEY *key_info= head->key_info + cpk_quick->index; |
|
7670 |
key_names->append(','); |
|
7671 |
key_names->append(key_info->name); |
|
152
by Brian Aker
longlong replacement |
7672 |
length= int64_t2str(cpk_quick->max_used_key_length, buf, 10) - buf; |
1
by brian
clean slate |
7673 |
used_lengths->append(','); |
7674 |
used_lengths->append(buf, length); |
|
7675 |
}
|
|
7676 |
}
|
|
7677 |
||
7678 |
void QUICK_ROR_UNION_SELECT::add_keys_and_lengths(String *key_names, |
|
7679 |
String *used_lengths) |
|
7680 |
{
|
|
55
by brian
Update for using real bool types. |
7681 |
bool first= true; |
1
by brian
clean slate |
7682 |
QUICK_SELECT_I *quick; |
7683 |
List_iterator_fast<QUICK_SELECT_I> it(quick_selects); |
|
7684 |
while ((quick= it++)) |
|
7685 |
{
|
|
7686 |
if (first) |
|
55
by brian
Update for using real bool types. |
7687 |
first= false; |
1
by brian
clean slate |
7688 |
else
|
7689 |
{
|
|
7690 |
used_lengths->append(','); |
|
7691 |
key_names->append(','); |
|
7692 |
}
|
|
7693 |
quick->add_keys_and_lengths(key_names, used_lengths); |
|
7694 |
}
|
|
7695 |
}
|
|
7696 |
||
7697 |
||
7698 |
/*******************************************************************************
|
|
7699 |
* Implementation of QUICK_GROUP_MIN_MAX_SELECT
|
|
7700 |
*******************************************************************************/
|
|
7701 |
||
482
by Brian Aker
Remove uint. |
7702 |
static inline uint32_t get_field_keypart(KEY *index, Field *field); |
7703 |
static inline SEL_ARG * get_index_range_tree(uint32_t index, SEL_TREE* range_tree, |
|
7704 |
PARAM *param, uint32_t *param_idx); |
|
1
by brian
clean slate |
7705 |
static bool get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree, |
7706 |
KEY_PART_INFO *first_non_group_part, |
|
7707 |
KEY_PART_INFO *min_max_arg_part, |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
7708 |
KEY_PART_INFO *last_part, Session *session, |
482
by Brian Aker
Remove uint. |
7709 |
unsigned char *key_infix, uint32_t *key_infix_len, |
1
by brian
clean slate |
7710 |
KEY_PART_INFO **first_non_infix_part); |
7711 |
static bool |
|
7712 |
check_group_min_max_predicates(COND *cond, Item_field *min_max_arg_item, |
|
7713 |
Field::imagetype image_type); |
|
7714 |
||
7715 |
static void |
|
482
by Brian Aker
Remove uint. |
7716 |
cost_group_min_max(Table* table, KEY *index_info, uint32_t used_key_parts, |
7717 |
uint32_t group_key_parts, SEL_TREE *range_tree, |
|
1
by brian
clean slate |
7718 |
SEL_ARG *index_tree, ha_rows quick_prefix_records, |
7719 |
bool have_min, bool have_max, |
|
7720 |
double *read_cost, ha_rows *records); |
|
7721 |
||
7722 |
||
7723 |
/*
|
|
7724 |
Test if this access method is applicable to a GROUP query with MIN/MAX
|
|
7725 |
functions, and if so, construct a new TRP object.
|
|
7726 |
||
7727 |
SYNOPSIS
|
|
7728 |
get_best_group_min_max()
|
|
7729 |
param Parameter from test_quick_select
|
|
7730 |
sel_tree Range tree generated by get_mm_tree
|
|
7731 |
||
7732 |
DESCRIPTION
|
|
7733 |
Test whether a query can be computed via a QUICK_GROUP_MIN_MAX_SELECT.
|
|
7734 |
Queries computable via a QUICK_GROUP_MIN_MAX_SELECT must satisfy the
|
|
7735 |
following conditions:
|
|
7736 |
A) Table T has at least one compound index I of the form:
|
|
7737 |
I = <A_1, ...,A_k, [B_1,..., B_m], C, [D_1,...,D_n]>
|
|
7738 |
B) Query conditions:
|
|
7739 |
B0. Q is over a single table T.
|
|
7740 |
B1. The attributes referenced by Q are a subset of the attributes of I.
|
|
7741 |
B2. All attributes QA in Q can be divided into 3 overlapping groups:
|
|
7742 |
- SA = {S_1, ..., S_l, [C]} - from the SELECT clause, where C is
|
|
7743 |
referenced by any number of MIN and/or MAX functions if present.
|
|
7744 |
- WA = {W_1, ..., W_p} - from the WHERE clause
|
|
7745 |
- GA = <G_1, ..., G_k> - from the GROUP BY clause (if any)
|
|
7746 |
= SA - if Q is a DISTINCT query (based on the
|
|
7747 |
equivalence of DISTINCT and GROUP queries.
|
|
7748 |
- NGA = QA - (GA union C) = {NG_1, ..., NG_m} - the ones not in
|
|
7749 |
GROUP BY and not referenced by MIN/MAX functions.
|
|
7750 |
with the following properties specified below.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7751 |
B3. If Q has a GROUP BY WITH ROLLUP clause the access method is not
|
1
by brian
clean slate |
7752 |
applicable.
|
7753 |
||
7754 |
SA1. There is at most one attribute in SA referenced by any number of
|
|
7755 |
MIN and/or MAX functions which, which if present, is denoted as C.
|
|
7756 |
SA2. The position of the C attribute in the index is after the last A_k.
|
|
7757 |
SA3. The attribute C can be referenced in the WHERE clause only in
|
|
7758 |
predicates of the forms:
|
|
7759 |
- (C {< | <= | > | >= | =} const)
|
|
7760 |
- (const {< | <= | > | >= | =} C)
|
|
7761 |
- (C between const_i and const_j)
|
|
7762 |
- C IS NULL
|
|
7763 |
- C IS NOT NULL
|
|
7764 |
- C != const
|
|
7765 |
SA4. If Q has a GROUP BY clause, there are no other aggregate functions
|
|
7766 |
except MIN and MAX. For queries with DISTINCT, aggregate functions
|
|
7767 |
are allowed.
|
|
7768 |
SA5. The select list in DISTINCT queries should not contain expressions.
|
|
7769 |
GA1. If Q has a GROUP BY clause, then GA is a prefix of I. That is, if
|
|
7770 |
G_i = A_j => i = j.
|
|
7771 |
GA2. If Q has a DISTINCT clause, then there is a permutation of SA that
|
|
7772 |
forms a prefix of I. This permutation is used as the GROUP clause
|
|
7773 |
when the DISTINCT query is converted to a GROUP query.
|
|
7774 |
GA3. The attributes in GA may participate in arbitrary predicates, divided
|
|
7775 |
into two groups:
|
|
7776 |
- RNG(G_1,...,G_q ; where q <= k) is a range condition over the
|
|
7777 |
attributes of a prefix of GA
|
|
7778 |
- PA(G_i1,...G_iq) is an arbitrary predicate over an arbitrary subset
|
|
7779 |
of GA. Since P is applied to only GROUP attributes it filters some
|
|
7780 |
groups, and thus can be applied after the grouping.
|
|
7781 |
GA4. There are no expressions among G_i, just direct column references.
|
|
7782 |
NGA1.If in the index I there is a gap between the last GROUP attribute G_k,
|
|
7783 |
and the MIN/MAX attribute C, then NGA must consist of exactly the
|
|
7784 |
index attributes that constitute the gap. As a result there is a
|
|
7785 |
permutation of NGA that coincides with the gap in the index
|
|
7786 |
<B_1, ..., B_m>.
|
|
7787 |
NGA2.If BA <> {}, then the WHERE clause must contain a conjunction EQ of
|
|
7788 |
equality conditions for all NG_i of the form (NG_i = const) or
|
|
7789 |
(const = NG_i), such that each NG_i is referenced in exactly one
|
|
7790 |
conjunct. Informally, the predicates provide constants to fill the
|
|
7791 |
gap in the index.
|
|
7792 |
WA1. There are no other attributes in the WHERE clause except the ones
|
|
7793 |
referenced in predicates RNG, PA, PC, EQ defined above. Therefore
|
|
7794 |
WA is subset of (GA union NGA union C) for GA,NGA,C that pass the
|
|
7795 |
above tests. By transitivity then it also follows that each WA_i
|
|
7796 |
participates in the index I (if this was already tested for GA, NGA
|
|
7797 |
and C).
|
|
7798 |
||
7799 |
C) Overall query form:
|
|
7800 |
SELECT EXPR([A_1,...,A_k], [B_1,...,B_m], [MIN(C)], [MAX(C)])
|
|
7801 |
FROM T
|
|
7802 |
WHERE [RNG(A_1,...,A_p ; where p <= k)]
|
|
7803 |
[AND EQ(B_1,...,B_m)]
|
|
7804 |
[AND PC(C)]
|
|
7805 |
[AND PA(A_i1,...,A_iq)]
|
|
7806 |
GROUP BY A_1,...,A_k
|
|
7807 |
[HAVING PH(A_1, ..., B_1,..., C)]
|
|
7808 |
where EXPR(...) is an arbitrary expression over some or all SELECT fields,
|
|
7809 |
or:
|
|
7810 |
SELECT DISTINCT A_i1,...,A_ik
|
|
7811 |
FROM T
|
|
7812 |
WHERE [RNG(A_1,...,A_p ; where p <= k)]
|
|
7813 |
[AND PA(A_i1,...,A_iq)];
|
|
7814 |
||
7815 |
NOTES
|
|
7816 |
If the current query satisfies the conditions above, and if
|
|
7817 |
(mem_root! = NULL), then the function constructs and returns a new TRP
|
|
7818 |
object, that is later used to construct a new QUICK_GROUP_MIN_MAX_SELECT.
|
|
7819 |
If (mem_root == NULL), then the function only tests whether the current
|
|
7820 |
query satisfies the conditions above, and, if so, sets
|
|
55
by brian
Update for using real bool types. |
7821 |
is_applicable = true.
|
1
by brian
clean slate |
7822 |
|
7823 |
Queries with DISTINCT for which index access can be used are transformed
|
|
7824 |
into equivalent group-by queries of the form:
|
|
7825 |
||
7826 |
SELECT A_1,...,A_k FROM T
|
|
7827 |
WHERE [RNG(A_1,...,A_p ; where p <= k)]
|
|
7828 |
[AND PA(A_i1,...,A_iq)]
|
|
7829 |
GROUP BY A_1,...,A_k;
|
|
7830 |
||
7831 |
The group-by list is a permutation of the select attributes, according
|
|
7832 |
to their order in the index.
|
|
7833 |
||
7834 |
TODO
|
|
7835 |
- What happens if the query groups by the MIN/MAX field, and there is no
|
|
7836 |
other field as in: "select min(a) from t1 group by a" ?
|
|
7837 |
- We assume that the general correctness of the GROUP-BY query was checked
|
|
7838 |
before this point. Is this correct, or do we have to check it completely?
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7839 |
- Lift the limitation in condition (B3), that is, make this access method
|
1
by brian
clean slate |
7840 |
applicable to ROLLUP queries.
|
7841 |
||
7842 |
RETURN
|
|
7843 |
If mem_root != NULL
|
|
7844 |
- valid TRP_GROUP_MIN_MAX object if this QUICK class can be used for
|
|
7845 |
the query
|
|
7846 |
- NULL o/w.
|
|
7847 |
If mem_root == NULL
|
|
7848 |
- NULL
|
|
7849 |
*/
|
|
7850 |
||
7851 |
static TRP_GROUP_MIN_MAX * |
|
7852 |
get_best_group_min_max(PARAM *param, SEL_TREE *tree) |
|
7853 |
{
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
7854 |
Session *session= param->session; |
7855 |
JOIN *join= session->lex->current_select->join; |
|
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
7856 |
Table *table= param->table; |
55
by brian
Update for using real bool types. |
7857 |
bool have_min= false; /* true if there is a MIN function. */ |
7858 |
bool have_max= false; /* true if there is a MAX function. */ |
|
1
by brian
clean slate |
7859 |
Item_field *min_max_arg_item= NULL; // The argument of all MIN/MAX functions |
7860 |
KEY_PART_INFO *min_max_arg_part= NULL; /* The corresponding keypart. */ |
|
482
by Brian Aker
Remove uint. |
7861 |
uint32_t group_prefix_len= 0; /* Length (in bytes) of the key prefix. */ |
1
by brian
clean slate |
7862 |
KEY *index_info= NULL; /* The index chosen for data access. */ |
482
by Brian Aker
Remove uint. |
7863 |
uint32_t index= 0; /* The id of the chosen index. */ |
7864 |
uint32_t group_key_parts= 0; // Number of index key parts in the group prefix. |
|
7865 |
uint32_t used_key_parts= 0; /* Number of index key parts used for access. */ |
|
481
by Brian Aker
Remove all of uchar. |
7866 |
unsigned char key_infix[MAX_KEY_LENGTH]; /* Constants from equality predicates.*/ |
482
by Brian Aker
Remove uint. |
7867 |
uint32_t key_infix_len= 0; /* Length of key_infix. */ |
1
by brian
clean slate |
7868 |
TRP_GROUP_MIN_MAX *read_plan= NULL; /* The eventually constructed TRP. */ |
482
by Brian Aker
Remove uint. |
7869 |
uint32_t key_part_nr; |
327.2.3
by Brian Aker
Refactoring of class Table |
7870 |
order_st *tmp_group; |
1
by brian
clean slate |
7871 |
Item *item; |
7872 |
Item_field *item_field; |
|
7873 |
||
7874 |
/* Perform few 'cheap' tests whether this access method is applicable. */
|
|
7875 |
if (!join) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7876 |
return NULL; /* This is not a select statement. */ |
1
by brian
clean slate |
7877 |
if ((join->tables != 1) || /* The query must reference one table. */ |
7878 |
((!join->group_list) && /* Neither GROUP BY nor a DISTINCT query. */ |
|
7879 |
(!join->select_distinct)) || |
|
7880 |
(join->select_lex->olap == ROLLUP_TYPE)) /* Check (B3) for ROLLUP */ |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7881 |
return NULL; |
1
by brian
clean slate |
7882 |
if (table->s->keys == 0) /* There are no indexes to use. */ |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7883 |
return NULL; |
1
by brian
clean slate |
7884 |
|
7885 |
/* Analyze the query in more detail. */
|
|
7886 |
List_iterator<Item> select_items_it(join->fields_list); |
|
7887 |
||
7888 |
/* Check (SA1,SA4) and store the only MIN/MAX argument - the C attribute.*/
|
|
7889 |
if (join->make_sum_func_list(join->all_fields, join->fields_list, 1)) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7890 |
return NULL; |
1
by brian
clean slate |
7891 |
if (join->sum_funcs[0]) |
7892 |
{
|
|
7893 |
Item_sum *min_max_item; |
|
7894 |
Item_sum **func_ptr= join->sum_funcs; |
|
7895 |
while ((min_max_item= *(func_ptr++))) |
|
7896 |
{
|
|
7897 |
if (min_max_item->sum_func() == Item_sum::MIN_FUNC) |
|
55
by brian
Update for using real bool types. |
7898 |
have_min= true; |
1
by brian
clean slate |
7899 |
else if (min_max_item->sum_func() == Item_sum::MAX_FUNC) |
55
by brian
Update for using real bool types. |
7900 |
have_max= true; |
1
by brian
clean slate |
7901 |
else
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7902 |
return NULL; |
1
by brian
clean slate |
7903 |
|
7904 |
/* The argument of MIN/MAX. */
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7905 |
Item *expr= min_max_item->args[0]->real_item(); |
1
by brian
clean slate |
7906 |
if (expr->type() == Item::FIELD_ITEM) /* Is it an attribute? */ |
7907 |
{
|
|
7908 |
if (! min_max_arg_item) |
|
7909 |
min_max_arg_item= (Item_field*) expr; |
|
7910 |
else if (! min_max_arg_item->eq(expr, 1)) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7911 |
return NULL; |
1
by brian
clean slate |
7912 |
}
|
7913 |
else
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7914 |
return NULL; |
1
by brian
clean slate |
7915 |
}
|
7916 |
}
|
|
7917 |
||
7918 |
/* Check (SA5). */
|
|
7919 |
if (join->select_distinct) |
|
7920 |
{
|
|
7921 |
while ((item= select_items_it++)) |
|
7922 |
{
|
|
7923 |
if (item->type() != Item::FIELD_ITEM) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7924 |
return NULL; |
1
by brian
clean slate |
7925 |
}
|
7926 |
}
|
|
7927 |
||
7928 |
/* Check (GA4) - that there are no expressions among the group attributes. */
|
|
7929 |
for (tmp_group= join->group_list; tmp_group; tmp_group= tmp_group->next) |
|
7930 |
{
|
|
7931 |
if ((*tmp_group->item)->type() != Item::FIELD_ITEM) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7932 |
return NULL; |
1
by brian
clean slate |
7933 |
}
|
7934 |
||
7935 |
/*
|
|
7936 |
Check that table has at least one compound index such that the conditions
|
|
55
by brian
Update for using real bool types. |
7937 |
(GA1,GA2) are all true. If there is more than one such index, select the
|
1
by brian
clean slate |
7938 |
first one. Here we set the variables: group_prefix_len and index_info.
|
7939 |
*/
|
|
7940 |
KEY *cur_index_info= table->key_info; |
|
7941 |
KEY *cur_index_info_end= cur_index_info + table->s->keys; |
|
7942 |
KEY_PART_INFO *cur_part= NULL; |
|
7943 |
KEY_PART_INFO *end_part; /* Last part for loops. */ |
|
7944 |
/* Last index part. */
|
|
7945 |
KEY_PART_INFO *last_part= NULL; |
|
7946 |
KEY_PART_INFO *first_non_group_part= NULL; |
|
7947 |
KEY_PART_INFO *first_non_infix_part= NULL; |
|
482
by Brian Aker
Remove uint. |
7948 |
uint32_t key_infix_parts= 0; |
7949 |
uint32_t cur_group_key_parts= 0; |
|
7950 |
uint32_t cur_group_prefix_len= 0; |
|
1
by brian
clean slate |
7951 |
/* Cost-related variables for the best index so far. */
|
7952 |
double best_read_cost= DBL_MAX; |
|
7953 |
ha_rows best_records= 0; |
|
7954 |
SEL_ARG *best_index_tree= NULL; |
|
7955 |
ha_rows best_quick_prefix_records= 0; |
|
482
by Brian Aker
Remove uint. |
7956 |
uint32_t best_param_idx= 0; |
1
by brian
clean slate |
7957 |
double cur_read_cost= DBL_MAX; |
7958 |
ha_rows cur_records; |
|
7959 |
SEL_ARG *cur_index_tree= NULL; |
|
7960 |
ha_rows cur_quick_prefix_records= 0; |
|
482
by Brian Aker
Remove uint. |
7961 |
uint32_t cur_param_idx=MAX_KEY; |
1
by brian
clean slate |
7962 |
key_map cur_used_key_parts; |
482
by Brian Aker
Remove uint. |
7963 |
uint32_t pk= param->table->s->primary_key; |
1
by brian
clean slate |
7964 |
|
482
by Brian Aker
Remove uint. |
7965 |
for (uint32_t cur_index= 0 ; cur_index_info != cur_index_info_end ; |
1
by brian
clean slate |
7966 |
cur_index_info++, cur_index++) |
7967 |
{
|
|
7968 |
/* Check (B1) - if current index is covering. */
|
|
7969 |
if (!table->covering_keys.is_set(cur_index)) |
|
7970 |
goto next_index; |
|
7971 |
||
7972 |
/*
|
|
7973 |
If the current storage manager is such that it appends the primary key to
|
|
7974 |
each index, then the above condition is insufficient to check if the
|
|
7975 |
index is covering. In such cases it may happen that some fields are
|
|
7976 |
covered by the PK index, but not by the current index. Since we can't
|
|
7977 |
use the concatenation of both indexes for index lookup, such an index
|
|
7978 |
does not qualify as covering in our case. If this is the case, below
|
|
7979 |
we check that all query fields are indeed covered by 'cur_index'.
|
|
7980 |
*/
|
|
7981 |
if (pk < MAX_KEY && cur_index != pk && |
|
7982 |
(table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX)) |
|
7983 |
{
|
|
7984 |
/* For each table field */
|
|
482
by Brian Aker
Remove uint. |
7985 |
for (uint32_t i= 0; i < table->s->fields; i++) |
1
by brian
clean slate |
7986 |
{
|
7987 |
Field *cur_field= table->field[i]; |
|
7988 |
/*
|
|
7989 |
If the field is used in the current query ensure that it's
|
|
7990 |
part of 'cur_index'
|
|
7991 |
*/
|
|
7992 |
if (bitmap_is_set(table->read_set, cur_field->field_index) && |
|
7993 |
!cur_field->part_of_key_not_clustered.is_set(cur_index)) |
|
7994 |
goto next_index; // Field was not part of key |
|
7995 |
}
|
|
7996 |
}
|
|
7997 |
||
7998 |
/*
|
|
7999 |
Check (GA1) for GROUP BY queries.
|
|
8000 |
*/
|
|
8001 |
if (join->group_list) |
|
8002 |
{
|
|
8003 |
cur_part= cur_index_info->key_part; |
|
8004 |
end_part= cur_part + cur_index_info->key_parts; |
|
8005 |
/* Iterate in parallel over the GROUP list and the index parts. */
|
|
8006 |
for (tmp_group= join->group_list; tmp_group && (cur_part != end_part); |
|
8007 |
tmp_group= tmp_group->next, cur_part++) |
|
8008 |
{
|
|
8009 |
/*
|
|
8010 |
TODO:
|
|
8011 |
tmp_group::item is an array of Item, is it OK to consider only the
|
|
8012 |
first Item? If so, then why? What is the array for?
|
|
8013 |
*/
|
|
8014 |
/* 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. |
8015 |
assert((*tmp_group->item)->type() == Item::FIELD_ITEM); |
1
by brian
clean slate |
8016 |
Item_field *group_field= (Item_field *) (*tmp_group->item); |
8017 |
if (group_field->field->eq(cur_part->field)) |
|
8018 |
{
|
|
8019 |
cur_group_prefix_len+= cur_part->store_length; |
|
8020 |
++cur_group_key_parts; |
|
8021 |
}
|
|
8022 |
else
|
|
8023 |
goto next_index; |
|
8024 |
}
|
|
8025 |
}
|
|
8026 |
/*
|
|
8027 |
Check (GA2) if this is a DISTINCT query.
|
|
327.2.3
by Brian Aker
Refactoring of class Table |
8028 |
If GA2, then Store a new order_st object in group_fields_array at the
|
8029 |
position of the key part of item_field->field. Thus we get the order_st
|
|
1
by brian
clean slate |
8030 |
objects for each field ordered as the corresponding key parts.
|
327.2.3
by Brian Aker
Refactoring of class Table |
8031 |
Later group_fields_array of order_st objects is used to convert the query
|
1
by brian
clean slate |
8032 |
to a GROUP query.
|
8033 |
*/
|
|
8034 |
else if (join->select_distinct) |
|
8035 |
{
|
|
8036 |
select_items_it.rewind(); |
|
8037 |
cur_used_key_parts.clear_all(); |
|
482
by Brian Aker
Remove uint. |
8038 |
uint32_t max_key_part= 0; |
1
by brian
clean slate |
8039 |
while ((item= select_items_it++)) |
8040 |
{
|
|
8041 |
item_field= (Item_field*) item; /* (SA5) already checked above. */ |
|
8042 |
/* Find the order of the key part in the index. */
|
|
8043 |
key_part_nr= get_field_keypart(cur_index_info, item_field->field); |
|
8044 |
/*
|
|
8045 |
Check if this attribute was already present in the select list.
|
|
8046 |
If it was present, then its corresponding key part was alredy used.
|
|
8047 |
*/
|
|
8048 |
if (cur_used_key_parts.is_set(key_part_nr)) |
|
8049 |
continue; |
|
8050 |
if (key_part_nr < 1 || key_part_nr > join->fields_list.elements) |
|
8051 |
goto next_index; |
|
8052 |
cur_part= cur_index_info->key_part + key_part_nr - 1; |
|
8053 |
cur_group_prefix_len+= cur_part->store_length; |
|
8054 |
cur_used_key_parts.set_bit(key_part_nr); |
|
8055 |
++cur_group_key_parts; |
|
398.1.4
by Monty Taylor
Renamed max/min. |
8056 |
max_key_part= cmax(max_key_part,key_part_nr); |
1
by brian
clean slate |
8057 |
}
|
8058 |
/*
|
|
8059 |
Check that used key parts forms a prefix of the index.
|
|
8060 |
To check this we compare bits in all_parts and cur_parts.
|
|
8061 |
all_parts have all bits set from 0 to (max_key_part-1).
|
|
8062 |
cur_parts have bits set for only used keyparts.
|
|
8063 |
*/
|
|
151
by Brian Aker
Ulonglong to uint64_t |
8064 |
uint64_t all_parts, cur_parts; |
1
by brian
clean slate |
8065 |
all_parts= (1<<max_key_part) - 1; |
151
by Brian Aker
Ulonglong to uint64_t |
8066 |
cur_parts= cur_used_key_parts.to_uint64_t() >> 1; |
1
by brian
clean slate |
8067 |
if (all_parts != cur_parts) |
8068 |
goto next_index; |
|
8069 |
}
|
|
8070 |
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. |
8071 |
assert(false); |
1
by brian
clean slate |
8072 |
|
8073 |
/* Check (SA2). */
|
|
8074 |
if (min_max_arg_item) |
|
8075 |
{
|
|
8076 |
key_part_nr= get_field_keypart(cur_index_info, min_max_arg_item->field); |
|
8077 |
if (key_part_nr <= cur_group_key_parts) |
|
8078 |
goto next_index; |
|
8079 |
min_max_arg_part= cur_index_info->key_part + key_part_nr - 1; |
|
8080 |
}
|
|
8081 |
||
8082 |
/*
|
|
8083 |
Check (NGA1, NGA2) and extract a sequence of constants to be used as part
|
|
8084 |
of all search keys.
|
|
8085 |
*/
|
|
8086 |
||
8087 |
/*
|
|
8088 |
If there is MIN/MAX, each keypart between the last group part and the
|
|
8089 |
MIN/MAX part must participate in one equality with constants, and all
|
|
8090 |
keyparts after the MIN/MAX part must not be referenced in the query.
|
|
8091 |
||
8092 |
If there is no MIN/MAX, the keyparts after the last group part can be
|
|
8093 |
referenced only in equalities with constants, and the referenced keyparts
|
|
8094 |
must form a sequence without any gaps that starts immediately after the
|
|
8095 |
last group keypart.
|
|
8096 |
*/
|
|
8097 |
last_part= cur_index_info->key_part + cur_index_info->key_parts; |
|
8098 |
first_non_group_part= (cur_group_key_parts < cur_index_info->key_parts) ? |
|
8099 |
cur_index_info->key_part + cur_group_key_parts : |
|
8100 |
NULL; |
|
8101 |
first_non_infix_part= min_max_arg_part ? |
|
8102 |
(min_max_arg_part < last_part) ? |
|
8103 |
min_max_arg_part : |
|
8104 |
NULL : |
|
8105 |
NULL; |
|
8106 |
if (first_non_group_part && |
|
8107 |
(!min_max_arg_part || (min_max_arg_part - first_non_group_part > 0))) |
|
8108 |
{
|
|
8109 |
if (tree) |
|
8110 |
{
|
|
482
by Brian Aker
Remove uint. |
8111 |
uint32_t dummy; |
1
by brian
clean slate |
8112 |
SEL_ARG *index_range_tree= get_index_range_tree(cur_index, tree, param, |
8113 |
&dummy); |
|
8114 |
if (!get_constant_key_infix(cur_index_info, index_range_tree, |
|
8115 |
first_non_group_part, min_max_arg_part, |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
8116 |
last_part, session, key_infix, &key_infix_len, |
1
by brian
clean slate |
8117 |
&first_non_infix_part)) |
8118 |
goto next_index; |
|
8119 |
}
|
|
8120 |
else if (min_max_arg_part && |
|
8121 |
(min_max_arg_part - first_non_group_part > 0)) |
|
8122 |
{
|
|
8123 |
/*
|
|
8124 |
There is a gap but no range tree, thus no predicates at all for the
|
|
8125 |
non-group keyparts.
|
|
8126 |
*/
|
|
8127 |
goto next_index; |
|
8128 |
}
|
|
8129 |
else if (first_non_group_part && join->conds) |
|
8130 |
{
|
|
8131 |
/*
|
|
8132 |
If there is no MIN/MAX function in the query, but some index
|
|
8133 |
key part is referenced in the WHERE clause, then this index
|
|
8134 |
cannot be used because the WHERE condition over the keypart's
|
|
8135 |
field cannot be 'pushed' to the index (because there is no
|
|
8136 |
range 'tree'), and the WHERE clause must be evaluated before
|
|
8137 |
GROUP BY/DISTINCT.
|
|
8138 |
*/
|
|
8139 |
/*
|
|
8140 |
Store the first and last keyparts that need to be analyzed
|
|
8141 |
into one array that can be passed as parameter.
|
|
8142 |
*/
|
|
8143 |
KEY_PART_INFO *key_part_range[2]; |
|
8144 |
key_part_range[0]= first_non_group_part; |
|
8145 |
key_part_range[1]= last_part; |
|
8146 |
||
8147 |
/* Check if cur_part is referenced in the WHERE clause. */
|
|
8148 |
if (join->conds->walk(&Item::find_item_in_field_list_processor, 0, |
|
481
by Brian Aker
Remove all of uchar. |
8149 |
(unsigned char*) key_part_range)) |
1
by brian
clean slate |
8150 |
goto next_index; |
8151 |
}
|
|
8152 |
}
|
|
8153 |
||
8154 |
/*
|
|
8155 |
Test (WA1) partially - that no other keypart after the last infix part is
|
|
8156 |
referenced in the query.
|
|
8157 |
*/
|
|
8158 |
if (first_non_infix_part) |
|
8159 |
{
|
|
8160 |
cur_part= first_non_infix_part + |
|
8161 |
(min_max_arg_part && (min_max_arg_part < last_part)); |
|
8162 |
for (; cur_part != last_part; cur_part++) |
|
8163 |
{
|
|
8164 |
if (bitmap_is_set(table->read_set, cur_part->field->field_index)) |
|
8165 |
goto next_index; |
|
8166 |
}
|
|
8167 |
}
|
|
8168 |
||
8169 |
/* If we got to this point, cur_index_info passes the test. */
|
|
8170 |
key_infix_parts= key_infix_len ? |
|
8171 |
(first_non_infix_part - first_non_group_part) : 0; |
|
8172 |
used_key_parts= cur_group_key_parts + key_infix_parts; |
|
8173 |
||
8174 |
/* Compute the cost of using this index. */
|
|
8175 |
if (tree) |
|
8176 |
{
|
|
8177 |
/* Find the SEL_ARG sub-tree that corresponds to the chosen index. */
|
|
8178 |
cur_index_tree= get_index_range_tree(cur_index, tree, param, |
|
8179 |
&cur_param_idx); |
|
8180 |
/* Check if this range tree can be used for prefix retrieval. */
|
|
8181 |
COST_VECT dummy_cost; |
|
482
by Brian Aker
Remove uint. |
8182 |
uint32_t mrr_flags= HA_MRR_USE_DEFAULT_IMPL; |
8183 |
uint32_t mrr_bufsize=0; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
8184 |
cur_quick_prefix_records= check_quick_select(param, cur_param_idx, |
8185 |
false /*don't care*/, |
|
55
by brian
Update for using real bool types. |
8186 |
cur_index_tree, true, |
1
by brian
clean slate |
8187 |
&mrr_flags, &mrr_bufsize, |
8188 |
&dummy_cost); |
|
8189 |
}
|
|
8190 |
cost_group_min_max(table, cur_index_info, used_key_parts, |
|
8191 |
cur_group_key_parts, tree, cur_index_tree, |
|
8192 |
cur_quick_prefix_records, have_min, have_max, |
|
8193 |
&cur_read_cost, &cur_records); |
|
8194 |
/*
|
|
8195 |
If cur_read_cost is lower than best_read_cost use cur_index.
|
|
8196 |
Do not compare doubles directly because they may have different
|
|
8197 |
representations (64 vs. 80 bits).
|
|
8198 |
*/
|
|
8199 |
if (cur_read_cost < best_read_cost - (DBL_EPSILON * cur_read_cost)) |
|
8200 |
{
|
|
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. |
8201 |
assert(tree != 0 || cur_param_idx == MAX_KEY); |
1
by brian
clean slate |
8202 |
index_info= cur_index_info; |
8203 |
index= cur_index; |
|
8204 |
best_read_cost= cur_read_cost; |
|
8205 |
best_records= cur_records; |
|
8206 |
best_index_tree= cur_index_tree; |
|
8207 |
best_quick_prefix_records= cur_quick_prefix_records; |
|
8208 |
best_param_idx= cur_param_idx; |
|
8209 |
group_key_parts= cur_group_key_parts; |
|
8210 |
group_prefix_len= cur_group_prefix_len; |
|
8211 |
}
|
|
8212 |
||
8213 |
next_index: |
|
8214 |
cur_group_key_parts= 0; |
|
8215 |
cur_group_prefix_len= 0; |
|
8216 |
}
|
|
8217 |
if (!index_info) /* No usable index found. */ |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8218 |
return NULL; |
1
by brian
clean slate |
8219 |
|
8220 |
/* Check (SA3) for the where clause. */
|
|
8221 |
if (join->conds && min_max_arg_item && |
|
248
by Brian Aker
Random cleanup in base.h |
8222 |
!check_group_min_max_predicates(join->conds, min_max_arg_item, Field::itRAW)) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8223 |
return NULL; |
1
by brian
clean slate |
8224 |
|
8225 |
/* The query passes all tests, so construct a new TRP object. */
|
|
8226 |
read_plan= new (param->mem_root) |
|
8227 |
TRP_GROUP_MIN_MAX(have_min, have_max, min_max_arg_part, |
|
8228 |
group_prefix_len, used_key_parts, |
|
8229 |
group_key_parts, index_info, index, |
|
8230 |
key_infix_len, |
|
8231 |
(key_infix_len > 0) ? key_infix : NULL, |
|
8232 |
tree, best_index_tree, best_param_idx, |
|
8233 |
best_quick_prefix_records); |
|
8234 |
if (read_plan) |
|
8235 |
{
|
|
8236 |
if (tree && read_plan->quick_prefix_records == 0) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8237 |
return NULL; |
1
by brian
clean slate |
8238 |
|
8239 |
read_plan->read_cost= best_read_cost; |
|
8240 |
read_plan->records= best_records; |
|
8241 |
}
|
|
8242 |
||
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8243 |
return read_plan; |
1
by brian
clean slate |
8244 |
}
|
8245 |
||
8246 |
||
8247 |
/*
|
|
8248 |
Check that the MIN/MAX attribute participates only in range predicates
|
|
8249 |
with constants.
|
|
8250 |
||
8251 |
SYNOPSIS
|
|
8252 |
check_group_min_max_predicates()
|
|
8253 |
cond tree (or subtree) describing all or part of the WHERE
|
|
8254 |
clause being analyzed
|
|
8255 |
min_max_arg_item the field referenced by the MIN/MAX function(s)
|
|
8256 |
min_max_arg_part the keypart of the MIN/MAX argument if any
|
|
8257 |
||
8258 |
DESCRIPTION
|
|
8259 |
The function walks recursively over the cond tree representing a WHERE
|
|
8260 |
clause, and checks condition (SA3) - if a field is referenced by a MIN/MAX
|
|
8261 |
aggregate function, it is referenced only by one of the following
|
|
8262 |
predicates: {=, !=, <, <=, >, >=, between, is null, is not null}.
|
|
8263 |
||
8264 |
RETURN
|
|
55
by brian
Update for using real bool types. |
8265 |
true if cond passes the test
|
8266 |
false o/w
|
|
1
by brian
clean slate |
8267 |
*/
|
8268 |
||
8269 |
static bool |
|
8270 |
check_group_min_max_predicates(COND *cond, Item_field *min_max_arg_item, |
|
8271 |
Field::imagetype image_type) |
|
8272 |
{
|
|
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. |
8273 |
assert(cond && min_max_arg_item); |
1
by brian
clean slate |
8274 |
|
8275 |
cond= cond->real_item(); |
|
8276 |
Item::Type cond_type= cond->type(); |
|
8277 |
if (cond_type == Item::COND_ITEM) /* 'AND' or 'OR' */ |
|
8278 |
{
|
|
8279 |
List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list()); |
|
8280 |
Item *and_or_arg; |
|
8281 |
while ((and_or_arg= li++)) |
|
8282 |
{
|
|
8283 |
if (!check_group_min_max_predicates(and_or_arg, min_max_arg_item, |
|
8284 |
image_type)) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8285 |
return false; |
1
by brian
clean slate |
8286 |
}
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8287 |
return true; |
1
by brian
clean slate |
8288 |
}
|
8289 |
||
8290 |
/*
|
|
8291 |
TODO:
|
|
8292 |
This is a very crude fix to handle sub-selects in the WHERE clause
|
|
8293 |
(Item_subselect objects). With the test below we rule out from the
|
|
8294 |
optimization all queries with subselects in the WHERE clause. What has to
|
|
8295 |
be done, is that here we should analyze whether the subselect references
|
|
8296 |
the MIN/MAX argument field, and disallow the optimization only if this is
|
|
8297 |
so.
|
|
8298 |
*/
|
|
8299 |
if (cond_type == Item::SUBSELECT_ITEM) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8300 |
return false; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
8301 |
|
1
by brian
clean slate |
8302 |
/* 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. |
8303 |
assert(cond_type == Item::FUNC_ITEM); |
1
by brian
clean slate |
8304 |
|
8305 |
/* Test if cond references only group-by or non-group fields. */
|
|
8306 |
Item_func *pred= (Item_func*) cond; |
|
8307 |
Item **arguments= pred->arguments(); |
|
8308 |
Item *cur_arg; |
|
482
by Brian Aker
Remove uint. |
8309 |
for (uint32_t arg_idx= 0; arg_idx < pred->argument_count (); arg_idx++) |
1
by brian
clean slate |
8310 |
{
|
8311 |
cur_arg= arguments[arg_idx]->real_item(); |
|
8312 |
if (cur_arg->type() == Item::FIELD_ITEM) |
|
8313 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
8314 |
if (min_max_arg_item->eq(cur_arg, 1)) |
1
by brian
clean slate |
8315 |
{
|
8316 |
/*
|
|
8317 |
If pred references the MIN/MAX argument, check whether pred is a range
|
|
8318 |
condition that compares the MIN/MAX argument with a constant.
|
|
8319 |
*/
|
|
8320 |
Item_func::Functype pred_type= pred->functype(); |
|
8321 |
if (pred_type != Item_func::EQUAL_FUNC && |
|
8322 |
pred_type != Item_func::LT_FUNC && |
|
8323 |
pred_type != Item_func::LE_FUNC && |
|
8324 |
pred_type != Item_func::GT_FUNC && |
|
8325 |
pred_type != Item_func::GE_FUNC && |
|
8326 |
pred_type != Item_func::BETWEEN && |
|
8327 |
pred_type != Item_func::ISNULL_FUNC && |
|
8328 |
pred_type != Item_func::ISNOTNULL_FUNC && |
|
8329 |
pred_type != Item_func::EQ_FUNC && |
|
8330 |
pred_type != Item_func::NE_FUNC) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8331 |
return false; |
1
by brian
clean slate |
8332 |
|
8333 |
/* Check that pred compares min_max_arg_item with a constant. */
|
|
8334 |
Item *args[3]; |
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
8335 |
memset(args, 0, 3 * sizeof(Item*)); |
1
by brian
clean slate |
8336 |
bool inv; |
8337 |
/* Test if this is a comparison of a field and a constant. */
|
|
8338 |
if (!simple_pred(pred, args, &inv)) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8339 |
return false; |
1
by brian
clean slate |
8340 |
|
8341 |
/* Check for compatible string comparisons - similar to get_mm_leaf. */
|
|
8342 |
if (args[0] && args[1] && !args[2] && // this is a binary function |
|
8343 |
min_max_arg_item->result_type() == STRING_RESULT && |
|
8344 |
/*
|
|
8345 |
Don't use an index when comparing strings of different collations.
|
|
8346 |
*/
|
|
8347 |
((args[1]->result_type() == STRING_RESULT && |
|
8348 |
image_type == Field::itRAW && |
|
8349 |
((Field_str*) min_max_arg_item->field)->charset() != |
|
8350 |
pred->compare_collation()) |
|
8351 |
||
|
|
8352 |
/*
|
|
8353 |
We can't always use indexes when comparing a string index to a
|
|
8354 |
number.
|
|
8355 |
*/
|
|
8356 |
(args[1]->result_type() != STRING_RESULT && |
|
8357 |
min_max_arg_item->field->cmp_type() != args[1]->result_type()))) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8358 |
return false; |
1
by brian
clean slate |
8359 |
}
|
8360 |
}
|
|
8361 |
else if (cur_arg->type() == Item::FUNC_ITEM) |
|
8362 |
{
|
|
8363 |
if (!check_group_min_max_predicates(cur_arg, min_max_arg_item, |
|
8364 |
image_type)) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8365 |
return false; |
1
by brian
clean slate |
8366 |
}
|
8367 |
else if (cur_arg->const_item()) |
|
8368 |
{
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8369 |
return true; |
1
by brian
clean slate |
8370 |
}
|
8371 |
else
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8372 |
return false; |
1
by brian
clean slate |
8373 |
}
|
8374 |
||
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8375 |
return true; |
1
by brian
clean slate |
8376 |
}
|
8377 |
||
8378 |
||
8379 |
/*
|
|
8380 |
Extract a sequence of constants from a conjunction of equality predicates.
|
|
8381 |
||
8382 |
SYNOPSIS
|
|
8383 |
get_constant_key_infix()
|
|
8384 |
index_info [in] Descriptor of the chosen index.
|
|
8385 |
index_range_tree [in] Range tree for the chosen index
|
|
8386 |
first_non_group_part [in] First index part after group attribute parts
|
|
8387 |
min_max_arg_part [in] The keypart of the MIN/MAX argument if any
|
|
8388 |
last_part [in] Last keypart of the index
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
8389 |
session [in] Current thread
|
1
by brian
clean slate |
8390 |
key_infix [out] Infix of constants to be used for index lookup
|
8391 |
key_infix_len [out] Lenghth of the infix
|
|
8392 |
first_non_infix_part [out] The first keypart after the infix (if any)
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
8393 |
|
1
by brian
clean slate |
8394 |
DESCRIPTION
|
8395 |
Test conditions (NGA1, NGA2) from get_best_group_min_max(). Namely,
|
|
8396 |
for each keypart field NGF_i not in GROUP-BY, check that there is a
|
|
8397 |
constant equality predicate among conds with the form (NGF_i = const_ci) or
|
|
8398 |
(const_ci = NGF_i).
|
|
8399 |
Thus all the NGF_i attributes must fill the 'gap' between the last group-by
|
|
8400 |
attribute and the MIN/MAX attribute in the index (if present). If these
|
|
8401 |
conditions hold, copy each constant from its corresponding predicate into
|
|
8402 |
key_infix, in the order its NG_i attribute appears in the index, and update
|
|
8403 |
key_infix_len with the total length of the key parts in key_infix.
|
|
8404 |
||
8405 |
RETURN
|
|
55
by brian
Update for using real bool types. |
8406 |
true if the index passes the test
|
8407 |
false o/w
|
|
1
by brian
clean slate |
8408 |
*/
|
8409 |
||
8410 |
static bool |
|
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
8411 |
get_constant_key_infix(KEY *, SEL_ARG *index_range_tree, |
1
by brian
clean slate |
8412 |
KEY_PART_INFO *first_non_group_part, |
8413 |
KEY_PART_INFO *min_max_arg_part, |
|
77.1.46
by Monty Taylor
Finished the warnings work! |
8414 |
KEY_PART_INFO *last_part, |
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
8415 |
Session *, unsigned char *key_infix, uint32_t *key_infix_len, |
1
by brian
clean slate |
8416 |
KEY_PART_INFO **first_non_infix_part) |
8417 |
{
|
|
8418 |
SEL_ARG *cur_range; |
|
8419 |
KEY_PART_INFO *cur_part; |
|
8420 |
/* End part for the first loop below. */
|
|
8421 |
KEY_PART_INFO *end_part= min_max_arg_part ? min_max_arg_part : last_part; |
|
8422 |
||
8423 |
*key_infix_len= 0; |
|
481
by Brian Aker
Remove all of uchar. |
8424 |
unsigned char *key_ptr= key_infix; |
1
by brian
clean slate |
8425 |
for (cur_part= first_non_group_part; cur_part != end_part; cur_part++) |
8426 |
{
|
|
8427 |
/*
|
|
8428 |
Find the range tree for the current keypart. We assume that
|
|
8429 |
index_range_tree points to the leftmost keypart in the index.
|
|
8430 |
*/
|
|
8431 |
for (cur_range= index_range_tree; cur_range; |
|
8432 |
cur_range= cur_range->next_key_part) |
|
8433 |
{
|
|
8434 |
if (cur_range->field->eq(cur_part->field)) |
|
8435 |
break; |
|
8436 |
}
|
|
8437 |
if (!cur_range) |
|
8438 |
{
|
|
8439 |
if (min_max_arg_part) |
|
55
by brian
Update for using real bool types. |
8440 |
return false; /* The current keypart has no range predicates at all. */ |
1
by brian
clean slate |
8441 |
else
|
8442 |
{
|
|
8443 |
*first_non_infix_part= cur_part; |
|
55
by brian
Update for using real bool types. |
8444 |
return true; |
1
by brian
clean slate |
8445 |
}
|
8446 |
}
|
|
8447 |
||
8448 |
/* Check that the current range tree is a single point interval. */
|
|
8449 |
if (cur_range->prev || cur_range->next) |
|
55
by brian
Update for using real bool types. |
8450 |
return false; /* This is not the only range predicate for the field. */ |
1
by brian
clean slate |
8451 |
if ((cur_range->min_flag & NO_MIN_RANGE) || |
8452 |
(cur_range->max_flag & NO_MAX_RANGE) || |
|
8453 |
(cur_range->min_flag & NEAR_MIN) || (cur_range->max_flag & NEAR_MAX)) |
|
55
by brian
Update for using real bool types. |
8454 |
return false; |
1
by brian
clean slate |
8455 |
|
482
by Brian Aker
Remove uint. |
8456 |
uint32_t field_length= cur_part->store_length; |
1
by brian
clean slate |
8457 |
if ((cur_range->maybe_null && |
8458 |
cur_range->min_value[0] && cur_range->max_value[0]) || |
|
8459 |
!memcmp(cur_range->min_value, cur_range->max_value, field_length)) |
|
8460 |
{
|
|
8461 |
/* cur_range specifies 'IS NULL' or an equality condition. */
|
|
8462 |
memcpy(key_ptr, cur_range->min_value, field_length); |
|
8463 |
key_ptr+= field_length; |
|
8464 |
*key_infix_len+= field_length; |
|
8465 |
}
|
|
8466 |
else
|
|
55
by brian
Update for using real bool types. |
8467 |
return false; |
1
by brian
clean slate |
8468 |
}
|
8469 |
||
8470 |
if (!min_max_arg_part && (cur_part == last_part)) |
|
8471 |
*first_non_infix_part= last_part; |
|
8472 |
||
55
by brian
Update for using real bool types. |
8473 |
return true; |
1
by brian
clean slate |
8474 |
}
|
8475 |
||
8476 |
||
8477 |
/*
|
|
8478 |
Find the key part referenced by a field.
|
|
8479 |
||
8480 |
SYNOPSIS
|
|
8481 |
get_field_keypart()
|
|
8482 |
index descriptor of an index
|
|
8483 |
field field that possibly references some key part in index
|
|
8484 |
||
8485 |
NOTES
|
|
8486 |
The return value can be used to get a KEY_PART_INFO pointer by
|
|
8487 |
part= index->key_part + get_field_keypart(...) - 1;
|
|
8488 |
||
8489 |
RETURN
|
|
8490 |
Positive number which is the consecutive number of the key part, or
|
|
8491 |
0 if field does not reference any index field.
|
|
8492 |
*/
|
|
8493 |
||
8494 |
static inline uint |
|
8495 |
get_field_keypart(KEY *index, Field *field) |
|
8496 |
{
|
|
8497 |
KEY_PART_INFO *part, *end; |
|
8498 |
||
8499 |
for (part= index->key_part, end= part + index->key_parts; part < end; part++) |
|
8500 |
{
|
|
8501 |
if (field->eq(part->field)) |
|
8502 |
return part - index->key_part + 1; |
|
8503 |
}
|
|
8504 |
return 0; |
|
8505 |
}
|
|
8506 |
||
8507 |
||
8508 |
/*
|
|
8509 |
Find the SEL_ARG sub-tree that corresponds to the chosen index.
|
|
8510 |
||
8511 |
SYNOPSIS
|
|
8512 |
get_index_range_tree()
|
|
8513 |
index [in] The ID of the index being looked for
|
|
8514 |
range_tree[in] Tree of ranges being searched
|
|
8515 |
param [in] PARAM from SQL_SELECT::test_quick_select
|
|
8516 |
param_idx [out] Index in the array PARAM::key that corresponds to 'index'
|
|
8517 |
||
8518 |
DESCRIPTION
|
|
8519 |
||
8520 |
A SEL_TREE contains range trees for all usable indexes. This procedure
|
|
8521 |
finds the SEL_ARG sub-tree for 'index'. The members of a SEL_TREE are
|
|
8522 |
ordered in the same way as the members of PARAM::key, thus we first find
|
|
8523 |
the corresponding index in the array PARAM::key. This index is returned
|
|
8524 |
through the variable param_idx, to be used later as argument of
|
|
8525 |
check_quick_select().
|
|
8526 |
||
8527 |
RETURN
|
|
8528 |
Pointer to the SEL_ARG subtree that corresponds to index.
|
|
8529 |
*/
|
|
8530 |
||
482
by Brian Aker
Remove uint. |
8531 |
SEL_ARG * get_index_range_tree(uint32_t index, SEL_TREE* range_tree, PARAM *param, |
8532 |
uint32_t *param_idx) |
|
1
by brian
clean slate |
8533 |
{
|
482
by Brian Aker
Remove uint. |
8534 |
uint32_t idx= 0; /* Index nr in param->key_parts */ |
1
by brian
clean slate |
8535 |
while (idx < param->keys) |
8536 |
{
|
|
8537 |
if (index == param->real_keynr[idx]) |
|
8538 |
break; |
|
8539 |
idx++; |
|
8540 |
}
|
|
8541 |
*param_idx= idx; |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8542 |
return range_tree->keys[idx]; |
1
by brian
clean slate |
8543 |
}
|
8544 |
||
8545 |
||
8546 |
/*
|
|
8547 |
Compute the cost of a quick_group_min_max_select for a particular index.
|
|
8548 |
||
8549 |
SYNOPSIS
|
|
8550 |
cost_group_min_max()
|
|
8551 |
table [in] The table being accessed
|
|
8552 |
index_info [in] The index used to access the table
|
|
8553 |
used_key_parts [in] Number of key parts used to access the index
|
|
8554 |
group_key_parts [in] Number of index key parts in the group prefix
|
|
8555 |
range_tree [in] Tree of ranges for all indexes
|
|
8556 |
index_tree [in] The range tree for the current index
|
|
8557 |
quick_prefix_records [in] Number of records retrieved by the internally
|
|
8558 |
used quick range select if any
|
|
8559 |
have_min [in] True if there is a MIN function
|
|
8560 |
have_max [in] True if there is a MAX function
|
|
8561 |
read_cost [out] The cost to retrieve rows via this quick select
|
|
8562 |
records [out] The number of rows retrieved
|
|
8563 |
||
8564 |
DESCRIPTION
|
|
8565 |
This method computes the access cost of a TRP_GROUP_MIN_MAX instance and
|
|
8566 |
the number of rows returned. It updates this->read_cost and this->records.
|
|
8567 |
||
8568 |
NOTES
|
|
8569 |
The cost computation distinguishes several cases:
|
|
8570 |
1) No equality predicates over non-group attributes (thus no key_infix).
|
|
8571 |
If groups are bigger than blocks on the average, then we assume that it
|
|
8572 |
is very unlikely that block ends are aligned with group ends, thus even
|
|
8573 |
if we look for both MIN and MAX keys, all pairs of neighbor MIN/MAX
|
|
8574 |
keys, except for the first MIN and the last MAX keys, will be in the
|
|
8575 |
same block. If groups are smaller than blocks, then we are going to
|
|
8576 |
read all blocks.
|
|
8577 |
2) There are equality predicates over non-group attributes.
|
|
8578 |
In this case the group prefix is extended by additional constants, and
|
|
8579 |
as a result the min/max values are inside sub-groups of the original
|
|
8580 |
groups. The number of blocks that will be read depends on whether the
|
|
8581 |
ends of these sub-groups will be contained in the same or in different
|
|
8582 |
blocks. We compute the probability for the two ends of a subgroup to be
|
|
8583 |
in two different blocks as the ratio of:
|
|
8584 |
- the number of positions of the left-end of a subgroup inside a group,
|
|
8585 |
such that the right end of the subgroup is past the end of the buffer
|
|
8586 |
containing the left-end, and
|
|
8587 |
- the total number of possible positions for the left-end of the
|
|
8588 |
subgroup, which is the number of keys in the containing group.
|
|
8589 |
We assume it is very unlikely that two ends of subsequent subgroups are
|
|
8590 |
in the same block.
|
|
8591 |
3) The are range predicates over the group attributes.
|
|
8592 |
Then some groups may be filtered by the range predicates. We use the
|
|
8593 |
selectivity of the range predicates to decide how many groups will be
|
|
8594 |
filtered.
|
|
8595 |
||
8596 |
TODO
|
|
8597 |
- Take into account the optional range predicates over the MIN/MAX
|
|
8598 |
argument.
|
|
8599 |
- Check if we have a PK index and we use all cols - then each key is a
|
|
8600 |
group, and it will be better to use an index scan.
|
|
8601 |
||
8602 |
RETURN
|
|
8603 |
None
|
|
8604 |
*/
|
|
8605 |
||
482
by Brian Aker
Remove uint. |
8606 |
void cost_group_min_max(Table* table, KEY *index_info, uint32_t used_key_parts, |
8607 |
uint32_t group_key_parts, SEL_TREE *range_tree, |
|
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
8608 |
SEL_ARG *, ha_rows quick_prefix_records, |
1
by brian
clean slate |
8609 |
bool have_min, bool have_max, |
8610 |
double *read_cost, ha_rows *records) |
|
8611 |
{
|
|
8612 |
ha_rows table_records; |
|
482
by Brian Aker
Remove uint. |
8613 |
uint32_t num_groups; |
8614 |
uint32_t num_blocks; |
|
8615 |
uint32_t keys_per_block; |
|
8616 |
uint32_t keys_per_group; |
|
8617 |
uint32_t keys_per_subgroup; /* Average number of keys in sub-groups */ |
|
1
by brian
clean slate |
8618 |
/* formed by a key infix. */
|
8619 |
double p_overlap; /* Probability that a sub-group overlaps two blocks. */ |
|
8620 |
double quick_prefix_selectivity; |
|
8621 |
double io_cost; |
|
8622 |
double cpu_cost= 0; /* TODO: CPU cost of index_read calls? */ |
|
8623 |
||
8624 |
table_records= table->file->stats.records; |
|
8625 |
keys_per_block= (table->file->stats.block_size / 2 / |
|
8626 |
(index_info->key_length + table->file->ref_length) |
|
8627 |
+ 1); |
|
895
by Brian Aker
Completion (?) of uint conversion. |
8628 |
num_blocks= (uint32_t)(table_records / keys_per_block) + 1; |
1
by brian
clean slate |
8629 |
|
8630 |
/* Compute the number of keys in a group. */
|
|
8631 |
keys_per_group= index_info->rec_per_key[group_key_parts - 1]; |
|
8632 |
if (keys_per_group == 0) /* If there is no statistics try to guess */ |
|
8633 |
/* each group contains 10% of all records */
|
|
895
by Brian Aker
Completion (?) of uint conversion. |
8634 |
keys_per_group= (uint32_t)(table_records / 10) + 1; |
8635 |
num_groups= (uint32_t)(table_records / keys_per_group) + 1; |
|
1
by brian
clean slate |
8636 |
|
8637 |
/* Apply the selectivity of the quick select for group prefixes. */
|
|
8638 |
if (range_tree && (quick_prefix_records != HA_POS_ERROR)) |
|
8639 |
{
|
|
8640 |
quick_prefix_selectivity= (double) quick_prefix_records / |
|
8641 |
(double) table_records; |
|
895
by Brian Aker
Completion (?) of uint conversion. |
8642 |
num_groups= (uint32_t) rint(num_groups * quick_prefix_selectivity); |
1
by brian
clean slate |
8643 |
set_if_bigger(num_groups, 1); |
8644 |
}
|
|
8645 |
||
8646 |
if (used_key_parts > group_key_parts) |
|
8647 |
{ /* |
|
8648 |
Compute the probability that two ends of a subgroup are inside
|
|
8649 |
different blocks.
|
|
8650 |
*/
|
|
8651 |
keys_per_subgroup= index_info->rec_per_key[used_key_parts - 1]; |
|
8652 |
if (keys_per_subgroup >= keys_per_block) /* If a subgroup is bigger than */ |
|
8653 |
p_overlap= 1.0; /* a block, it will overlap at least two blocks. */ |
|
8654 |
else
|
|
8655 |
{
|
|
8656 |
double blocks_per_group= (double) num_blocks / (double) num_groups; |
|
8657 |
p_overlap= (blocks_per_group * (keys_per_subgroup - 1)) / keys_per_group; |
|
398.1.4
by Monty Taylor
Renamed max/min. |
8658 |
p_overlap= cmin(p_overlap, 1.0); |
1
by brian
clean slate |
8659 |
}
|
398.1.4
by Monty Taylor
Renamed max/min. |
8660 |
io_cost= (double) cmin(num_groups * (1 + p_overlap), (double)num_blocks); |
1
by brian
clean slate |
8661 |
}
|
8662 |
else
|
|
8663 |
io_cost= (keys_per_group > keys_per_block) ? |
|
8664 |
(have_min && have_max) ? (double) (num_groups + 1) : |
|
8665 |
(double) num_groups : |
|
8666 |
(double) num_blocks; |
|
8667 |
||
8668 |
/*
|
|
8669 |
TODO: If there is no WHERE clause and no other expressions, there should be
|
|
8670 |
no CPU cost. We leave it here to make this cost comparable to that of index
|
|
8671 |
scan as computed in SQL_SELECT::test_quick_select().
|
|
8672 |
*/
|
|
8673 |
cpu_cost= (double) num_groups / TIME_FOR_COMPARE; |
|
8674 |
||
8675 |
*read_cost= io_cost + cpu_cost; |
|
8676 |
*records= num_groups; |
|
8677 |
}
|
|
8678 |
||
8679 |
||
8680 |
/*
|
|
8681 |
Construct a new quick select object for queries with group by with min/max.
|
|
8682 |
||
8683 |
SYNOPSIS
|
|
8684 |
TRP_GROUP_MIN_MAX::make_quick()
|
|
8685 |
param Parameter from test_quick_select
|
|
8686 |
retrieve_full_rows ignored
|
|
8687 |
parent_alloc Memory pool to use, if any.
|
|
8688 |
||
8689 |
NOTES
|
|
8690 |
Make_quick ignores the retrieve_full_rows parameter because
|
|
8691 |
QUICK_GROUP_MIN_MAX_SELECT always performs 'index only' scans.
|
|
8692 |
The other parameter are ignored as well because all necessary
|
|
8693 |
data to create the QUICK object is computed at this TRP creation
|
|
8694 |
time.
|
|
8695 |
||
8696 |
RETURN
|
|
8697 |
New QUICK_GROUP_MIN_MAX_SELECT object if successfully created,
|
|
8698 |
NULL otherwise.
|
|
8699 |
*/
|
|
8700 |
||
8701 |
QUICK_SELECT_I * |
|
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
8702 |
TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool, MEM_ROOT *parent_alloc) |
1
by brian
clean slate |
8703 |
{
|
8704 |
QUICK_GROUP_MIN_MAX_SELECT *quick; |
|
8705 |
||
8706 |
quick= new QUICK_GROUP_MIN_MAX_SELECT(param->table, |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
8707 |
param->session->lex->current_select->join, |
1
by brian
clean slate |
8708 |
have_min, have_max, min_max_arg_part, |
8709 |
group_prefix_len, group_key_parts, |
|
8710 |
used_key_parts, index_info, index, |
|
8711 |
read_cost, records, key_infix_len, |
|
8712 |
key_infix, parent_alloc); |
|
8713 |
if (!quick) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8714 |
return NULL; |
1
by brian
clean slate |
8715 |
|
8716 |
if (quick->init()) |
|
8717 |
{
|
|
8718 |
delete quick; |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8719 |
return NULL; |
1
by brian
clean slate |
8720 |
}
|
8721 |
||
8722 |
if (range_tree) |
|
8723 |
{
|
|
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. |
8724 |
assert(quick_prefix_records > 0); |
1
by brian
clean slate |
8725 |
if (quick_prefix_records == HA_POS_ERROR) |
8726 |
quick->quick_prefix_select= NULL; /* Can't construct a quick select. */ |
|
8727 |
else
|
|
8728 |
/* Make a QUICK_RANGE_SELECT to be used for group prefix retrieval. */
|
|
8729 |
quick->quick_prefix_select= get_quick_select(param, param_idx, |
|
8730 |
index_tree, |
|
8731 |
HA_MRR_USE_DEFAULT_IMPL, 0, |
|
8732 |
&quick->alloc); |
|
8733 |
||
8734 |
/*
|
|
8735 |
Extract the SEL_ARG subtree that contains only ranges for the MIN/MAX
|
|
8736 |
attribute, and create an array of QUICK_RANGES to be used by the
|
|
8737 |
new quick select.
|
|
8738 |
*/
|
|
8739 |
if (min_max_arg_part) |
|
8740 |
{
|
|
8741 |
SEL_ARG *min_max_range= index_tree; |
|
8742 |
while (min_max_range) /* Find the tree for the MIN/MAX key part. */ |
|
8743 |
{
|
|
8744 |
if (min_max_range->field->eq(min_max_arg_part->field)) |
|
8745 |
break; |
|
8746 |
min_max_range= min_max_range->next_key_part; |
|
8747 |
}
|
|
8748 |
/* Scroll to the leftmost interval for the MIN/MAX argument. */
|
|
8749 |
while (min_max_range && min_max_range->prev) |
|
8750 |
min_max_range= min_max_range->prev; |
|
8751 |
/* Create an array of QUICK_RANGEs for the MIN/MAX argument. */
|
|
8752 |
while (min_max_range) |
|
8753 |
{
|
|
8754 |
if (quick->add_range(min_max_range)) |
|
8755 |
{
|
|
8756 |
delete quick; |
|
8757 |
quick= NULL; |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8758 |
return NULL; |
1
by brian
clean slate |
8759 |
}
|
8760 |
min_max_range= min_max_range->next; |
|
8761 |
}
|
|
8762 |
}
|
|
8763 |
}
|
|
8764 |
else
|
|
8765 |
quick->quick_prefix_select= NULL; |
|
8766 |
||
8767 |
quick->update_key_stat(); |
|
8768 |
quick->adjust_prefix_ranges(); |
|
8769 |
||
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8770 |
return quick; |
1
by brian
clean slate |
8771 |
}
|
8772 |
||
8773 |
||
8774 |
/*
|
|
8775 |
Construct new quick select for group queries with min/max.
|
|
8776 |
||
8777 |
SYNOPSIS
|
|
8778 |
QUICK_GROUP_MIN_MAX_SELECT::QUICK_GROUP_MIN_MAX_SELECT()
|
|
8779 |
table The table being accessed
|
|
8780 |
join Descriptor of the current query
|
|
55
by brian
Update for using real bool types. |
8781 |
have_min true if the query selects a MIN function
|
8782 |
have_max true if the query selects a MAX function
|
|
1
by brian
clean slate |
8783 |
min_max_arg_part The only argument field of all MIN/MAX functions
|
8784 |
group_prefix_len Length of all key parts in the group prefix
|
|
8785 |
prefix_key_parts All key parts in the group prefix
|
|
8786 |
index_info The index chosen for data access
|
|
8787 |
use_index The id of index_info
|
|
8788 |
read_cost Cost of this access method
|
|
8789 |
records Number of records returned
|
|
8790 |
key_infix_len Length of the key infix appended to the group prefix
|
|
8791 |
key_infix Infix of constants from equality predicates
|
|
8792 |
parent_alloc Memory pool for this and quick_prefix_select data
|
|
8793 |
||
8794 |
RETURN
|
|
8795 |
None
|
|
8796 |
*/
|
|
8797 |
||
8798 |
QUICK_GROUP_MIN_MAX_SELECT:: |
|
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
8799 |
QUICK_GROUP_MIN_MAX_SELECT(Table *table, JOIN *join_arg, bool have_min_arg, |
1
by brian
clean slate |
8800 |
bool have_max_arg, |
8801 |
KEY_PART_INFO *min_max_arg_part_arg, |
|
482
by Brian Aker
Remove uint. |
8802 |
uint32_t group_prefix_len_arg, uint32_t group_key_parts_arg, |
8803 |
uint32_t used_key_parts_arg, KEY *index_info_arg, |
|
8804 |
uint32_t use_index, double read_cost_arg, |
|
8805 |
ha_rows records_arg, uint32_t key_infix_len_arg, |
|
481
by Brian Aker
Remove all of uchar. |
8806 |
unsigned char *key_infix_arg, MEM_ROOT *parent_alloc) |
1
by brian
clean slate |
8807 |
:join(join_arg), index_info(index_info_arg), |
8808 |
group_prefix_len(group_prefix_len_arg), |
|
8809 |
group_key_parts(group_key_parts_arg), have_min(have_min_arg), |
|
55
by brian
Update for using real bool types. |
8810 |
have_max(have_max_arg), seen_first_key(false), |
1
by brian
clean slate |
8811 |
min_max_arg_part(min_max_arg_part_arg), key_infix(key_infix_arg), |
8812 |
key_infix_len(key_infix_len_arg), min_functions_it(NULL), |
|
8813 |
max_functions_it(NULL) |
|
8814 |
{
|
|
8815 |
head= table; |
|
8816 |
file= head->file; |
|
8817 |
index= use_index; |
|
8818 |
record= head->record[0]; |
|
8819 |
tmp_record= head->record[1]; |
|
8820 |
read_time= read_cost_arg; |
|
8821 |
records= records_arg; |
|
8822 |
used_key_parts= used_key_parts_arg; |
|
8823 |
real_key_parts= used_key_parts_arg; |
|
8824 |
real_prefix_len= group_prefix_len + key_infix_len; |
|
8825 |
group_prefix= NULL; |
|
8826 |
min_max_arg_len= min_max_arg_part ? min_max_arg_part->store_length : 0; |
|
8827 |
||
8828 |
/*
|
|
8829 |
We can't have parent_alloc set as the init function can't handle this case
|
|
8830 |
yet.
|
|
8831 |
*/
|
|
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. |
8832 |
assert(!parent_alloc); |
1
by brian
clean slate |
8833 |
if (!parent_alloc) |
8834 |
{
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
8835 |
init_sql_alloc(&alloc, join->session->variables.range_alloc_block_size, 0); |
8836 |
join->session->mem_root= &alloc; |
|
1
by brian
clean slate |
8837 |
}
|
8838 |
else
|
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
8839 |
memset(&alloc, 0, sizeof(MEM_ROOT)); // ensure that it's not used |
1
by brian
clean slate |
8840 |
}
|
8841 |
||
8842 |
||
8843 |
/*
|
|
8844 |
Do post-constructor initialization.
|
|
8845 |
||
8846 |
SYNOPSIS
|
|
8847 |
QUICK_GROUP_MIN_MAX_SELECT::init()
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
8848 |
|
1
by brian
clean slate |
8849 |
DESCRIPTION
|
8850 |
The method performs initialization that cannot be done in the constructor
|
|
8851 |
such as memory allocations that may fail. It allocates memory for the
|
|
8852 |
group prefix and inifix buffers, and for the lists of MIN/MAX item to be
|
|
8853 |
updated during execution.
|
|
8854 |
||
8855 |
RETURN
|
|
8856 |
0 OK
|
|
8857 |
other Error code
|
|
8858 |
*/
|
|
8859 |
||
8860 |
int QUICK_GROUP_MIN_MAX_SELECT::init() |
|
8861 |
{
|
|
8862 |
if (group_prefix) /* Already initialized. */ |
|
8863 |
return 0; |
|
8864 |
||
481
by Brian Aker
Remove all of uchar. |
8865 |
if (!(last_prefix= (unsigned char*) alloc_root(&alloc, group_prefix_len))) |
1
by brian
clean slate |
8866 |
return 1; |
8867 |
/*
|
|
8868 |
We may use group_prefix to store keys with all select fields, so allocate
|
|
8869 |
enough space for it.
|
|
8870 |
*/
|
|
481
by Brian Aker
Remove all of uchar. |
8871 |
if (!(group_prefix= (unsigned char*) alloc_root(&alloc, |
1
by brian
clean slate |
8872 |
real_prefix_len + min_max_arg_len))) |
8873 |
return 1; |
|
8874 |
||
8875 |
if (key_infix_len > 0) |
|
8876 |
{
|
|
8877 |
/*
|
|
8878 |
The memory location pointed to by key_infix will be deleted soon, so
|
|
8879 |
allocate a new buffer and copy the key_infix into it.
|
|
8880 |
*/
|
|
481
by Brian Aker
Remove all of uchar. |
8881 |
unsigned char *tmp_key_infix= (unsigned char*) alloc_root(&alloc, key_infix_len); |
1
by brian
clean slate |
8882 |
if (!tmp_key_infix) |
8883 |
return 1; |
|
8884 |
memcpy(tmp_key_infix, this->key_infix, key_infix_len); |
|
8885 |
this->key_infix= tmp_key_infix; |
|
8886 |
}
|
|
8887 |
||
8888 |
if (min_max_arg_part) |
|
8889 |
{
|
|
8890 |
if (my_init_dynamic_array(&min_max_ranges, sizeof(QUICK_RANGE*), 16, 16)) |
|
8891 |
return 1; |
|
8892 |
||
8893 |
if (have_min) |
|
8894 |
{
|
|
8895 |
if (!(min_functions= new List<Item_sum>)) |
|
8896 |
return 1; |
|
8897 |
}
|
|
8898 |
else
|
|
8899 |
min_functions= NULL; |
|
8900 |
if (have_max) |
|
8901 |
{
|
|
8902 |
if (!(max_functions= new List<Item_sum>)) |
|
8903 |
return 1; |
|
8904 |
}
|
|
8905 |
else
|
|
8906 |
max_functions= NULL; |
|
8907 |
||
8908 |
Item_sum *min_max_item; |
|
8909 |
Item_sum **func_ptr= join->sum_funcs; |
|
8910 |
while ((min_max_item= *(func_ptr++))) |
|
8911 |
{
|
|
8912 |
if (have_min && (min_max_item->sum_func() == Item_sum::MIN_FUNC)) |
|
8913 |
min_functions->push_back(min_max_item); |
|
8914 |
else if (have_max && (min_max_item->sum_func() == Item_sum::MAX_FUNC)) |
|
8915 |
max_functions->push_back(min_max_item); |
|
8916 |
}
|
|
8917 |
||
8918 |
if (have_min) |
|
8919 |
{
|
|
8920 |
if (!(min_functions_it= new List_iterator<Item_sum>(*min_functions))) |
|
8921 |
return 1; |
|
8922 |
}
|
|
8923 |
||
8924 |
if (have_max) |
|
8925 |
{
|
|
8926 |
if (!(max_functions_it= new List_iterator<Item_sum>(*max_functions))) |
|
8927 |
return 1; |
|
8928 |
}
|
|
8929 |
}
|
|
8930 |
else
|
|
8931 |
min_max_ranges.elements= 0; |
|
8932 |
||
8933 |
return 0; |
|
8934 |
}
|
|
8935 |
||
8936 |
||
8937 |
QUICK_GROUP_MIN_MAX_SELECT::~QUICK_GROUP_MIN_MAX_SELECT() |
|
8938 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
8939 |
if (file->inited != handler::NONE) |
1
by brian
clean slate |
8940 |
file->ha_index_end(); |
8941 |
if (min_max_arg_part) |
|
8942 |
delete_dynamic(&min_max_ranges); |
|
8943 |
free_root(&alloc,MYF(0)); |
|
8944 |
delete min_functions_it; |
|
8945 |
delete max_functions_it; |
|
8946 |
delete quick_prefix_select; |
|
8947 |
}
|
|
8948 |
||
8949 |
||
8950 |
/*
|
|
8951 |
Eventually create and add a new quick range object.
|
|
8952 |
||
8953 |
SYNOPSIS
|
|
8954 |
QUICK_GROUP_MIN_MAX_SELECT::add_range()
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
8955 |
sel_range Range object from which a
|
1
by brian
clean slate |
8956 |
|
8957 |
NOTES
|
|
8958 |
Construct a new QUICK_RANGE object from a SEL_ARG object, and
|
|
8959 |
add it to the array min_max_ranges. If sel_arg is an infinite
|
|
8960 |
range, e.g. (x < 5 or x > 4), then skip it and do not construct
|
|
8961 |
a quick range.
|
|
8962 |
||
8963 |
RETURN
|
|
55
by brian
Update for using real bool types. |
8964 |
false on success
|
8965 |
true otherwise
|
|
1
by brian
clean slate |
8966 |
*/
|
8967 |
||
8968 |
bool QUICK_GROUP_MIN_MAX_SELECT::add_range(SEL_ARG *sel_range) |
|
8969 |
{
|
|
8970 |
QUICK_RANGE *range; |
|
482
by Brian Aker
Remove uint. |
8971 |
uint32_t range_flag= sel_range->min_flag | sel_range->max_flag; |
1
by brian
clean slate |
8972 |
|
8973 |
/* Skip (-inf,+inf) ranges, e.g. (x < 5 or x > 4). */
|
|
8974 |
if ((range_flag & NO_MIN_RANGE) && (range_flag & NO_MAX_RANGE)) |
|
55
by brian
Update for using real bool types. |
8975 |
return false; |
1
by brian
clean slate |
8976 |
|
8977 |
if (!(sel_range->min_flag & NO_MIN_RANGE) && |
|
8978 |
!(sel_range->max_flag & NO_MAX_RANGE)) |
|
8979 |
{
|
|
8980 |
if (sel_range->maybe_null && |
|
8981 |
sel_range->min_value[0] && sel_range->max_value[0]) |
|
8982 |
range_flag|= NULL_RANGE; /* IS NULL condition */ |
|
8983 |
else if (memcmp(sel_range->min_value, sel_range->max_value, |
|
8984 |
min_max_arg_len) == 0) |
|
8985 |
range_flag|= EQ_RANGE; /* equality condition */ |
|
8986 |
}
|
|
8987 |
range= new QUICK_RANGE(sel_range->min_value, min_max_arg_len, |
|
8988 |
make_keypart_map(sel_range->part), |
|
8989 |
sel_range->max_value, min_max_arg_len, |
|
8990 |
make_keypart_map(sel_range->part), |
|
8991 |
range_flag); |
|
8992 |
if (!range) |
|
55
by brian
Update for using real bool types. |
8993 |
return true; |
481
by Brian Aker
Remove all of uchar. |
8994 |
if (insert_dynamic(&min_max_ranges, (unsigned char*)&range)) |
55
by brian
Update for using real bool types. |
8995 |
return true; |
8996 |
return false; |
|
1
by brian
clean slate |
8997 |
}
|
8998 |
||
8999 |
||
9000 |
/*
|
|
9001 |
Opens the ranges if there are more conditions in quick_prefix_select than
|
|
9002 |
the ones used for jumping through the prefixes.
|
|
9003 |
||
9004 |
SYNOPSIS
|
|
9005 |
QUICK_GROUP_MIN_MAX_SELECT::adjust_prefix_ranges()
|
|
9006 |
||
9007 |
NOTES
|
|
9008 |
quick_prefix_select is made over the conditions on the whole key.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
9009 |
It defines a number of ranges of length x.
|
9010 |
However when jumping through the prefixes we use only the the first
|
|
1
by brian
clean slate |
9011 |
few most significant keyparts in the range key. However if there
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
9012 |
are more keyparts to follow the ones we are using we must make the
|
9013 |
condition on the key inclusive (because x < "ab" means
|
|
1
by brian
clean slate |
9014 |
x[0] < 'a' OR (x[0] == 'a' AND x[1] < 'b').
|
9015 |
To achive the above we must turn off the NEAR_MIN/NEAR_MAX
|
|
9016 |
*/
|
|
9017 |
void QUICK_GROUP_MIN_MAX_SELECT::adjust_prefix_ranges () |
|
9018 |
{
|
|
9019 |
if (quick_prefix_select && |
|
9020 |
group_prefix_len < quick_prefix_select->max_used_key_length) |
|
9021 |
{
|
|
9022 |
DYNAMIC_ARRAY *arr; |
|
482
by Brian Aker
Remove uint. |
9023 |
uint32_t inx; |
1
by brian
clean slate |
9024 |
|
9025 |
for (inx= 0, arr= &quick_prefix_select->ranges; inx < arr->elements; inx++) |
|
9026 |
{
|
|
9027 |
QUICK_RANGE *range; |
|
9028 |
||
481
by Brian Aker
Remove all of uchar. |
9029 |
get_dynamic(arr, (unsigned char*)&range, inx); |
1
by brian
clean slate |
9030 |
range->flag &= ~(NEAR_MIN | NEAR_MAX); |
9031 |
}
|
|
9032 |
}
|
|
9033 |
}
|
|
9034 |
||
9035 |
||
9036 |
/*
|
|
9037 |
Determine the total number and length of the keys that will be used for
|
|
9038 |
index lookup.
|
|
9039 |
||
9040 |
SYNOPSIS
|
|
9041 |
QUICK_GROUP_MIN_MAX_SELECT::update_key_stat()
|
|
9042 |
||
9043 |
DESCRIPTION
|
|
9044 |
The total length of the keys used for index lookup depends on whether
|
|
9045 |
there are any predicates referencing the min/max argument, and/or if
|
|
9046 |
the min/max argument field can be NULL.
|
|
9047 |
This function does an optimistic analysis whether the search key might
|
|
9048 |
be extended by a constant for the min/max keypart. It is 'optimistic'
|
|
9049 |
because during actual execution it may happen that a particular range
|
|
9050 |
is skipped, and then a shorter key will be used. However this is data
|
|
9051 |
dependent and can't be easily estimated here.
|
|
9052 |
||
9053 |
RETURN
|
|
9054 |
None
|
|
9055 |
*/
|
|
9056 |
||
9057 |
void QUICK_GROUP_MIN_MAX_SELECT::update_key_stat() |
|
9058 |
{
|
|
9059 |
max_used_key_length= real_prefix_len; |
|
9060 |
if (min_max_ranges.elements > 0) |
|
9061 |
{
|
|
9062 |
QUICK_RANGE *cur_range; |
|
9063 |
if (have_min) |
|
9064 |
{ /* Check if the right-most range has a lower boundary. */ |
|
481
by Brian Aker
Remove all of uchar. |
9065 |
get_dynamic(&min_max_ranges, (unsigned char*)&cur_range, |
1
by brian
clean slate |
9066 |
min_max_ranges.elements - 1); |
9067 |
if (!(cur_range->flag & NO_MIN_RANGE)) |
|
9068 |
{
|
|
9069 |
max_used_key_length+= min_max_arg_len; |
|
9070 |
used_key_parts++; |
|
9071 |
return; |
|
9072 |
}
|
|
9073 |
}
|
|
9074 |
if (have_max) |
|
9075 |
{ /* Check if the left-most range has an upper boundary. */ |
|
481
by Brian Aker
Remove all of uchar. |
9076 |
get_dynamic(&min_max_ranges, (unsigned char*)&cur_range, 0); |
1
by brian
clean slate |
9077 |
if (!(cur_range->flag & NO_MAX_RANGE)) |
9078 |
{
|
|
9079 |
max_used_key_length+= min_max_arg_len; |
|
9080 |
used_key_parts++; |
|
9081 |
return; |
|
9082 |
}
|
|
9083 |
}
|
|
9084 |
}
|
|
9085 |
else if (have_min && min_max_arg_part && |
|
9086 |
min_max_arg_part->field->real_maybe_null()) |
|
9087 |
{
|
|
9088 |
/*
|
|
9089 |
If a MIN/MAX argument value is NULL, we can quickly determine
|
|
9090 |
that we're in the beginning of the next group, because NULLs
|
|
9091 |
are always < any other value. This allows us to quickly
|
|
9092 |
determine the end of the current group and jump to the next
|
|
9093 |
group (see next_min()) and thus effectively increases the
|
|
9094 |
usable key length.
|
|
9095 |
*/
|
|
9096 |
max_used_key_length+= min_max_arg_len; |
|
9097 |
used_key_parts++; |
|
9098 |
}
|
|
9099 |
}
|
|
9100 |
||
9101 |
||
9102 |
/*
|
|
9103 |
Initialize a quick group min/max select for key retrieval.
|
|
9104 |
||
9105 |
SYNOPSIS
|
|
9106 |
QUICK_GROUP_MIN_MAX_SELECT::reset()
|
|
9107 |
||
9108 |
DESCRIPTION
|
|
9109 |
Initialize the index chosen for access and find and store the prefix
|
|
9110 |
of the last group. The method is expensive since it performs disk access.
|
|
9111 |
||
9112 |
RETURN
|
|
9113 |
0 OK
|
|
9114 |
other Error code
|
|
9115 |
*/
|
|
9116 |
||
9117 |
int QUICK_GROUP_MIN_MAX_SELECT::reset(void) |
|
9118 |
{
|
|
9119 |
int result; |
|
9120 |
||
9121 |
file->extra(HA_EXTRA_KEYREAD); /* We need only the key attributes */ |
|
9122 |
if ((result= file->ha_index_init(index,1))) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9123 |
return result; |
1
by brian
clean slate |
9124 |
if (quick_prefix_select && quick_prefix_select->reset()) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9125 |
return 0; |
1
by brian
clean slate |
9126 |
result= file->index_last(record); |
9127 |
if (result == HA_ERR_END_OF_FILE) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9128 |
return 0; |
1
by brian
clean slate |
9129 |
/* Save the prefix of the last group. */
|
9130 |
key_copy(last_prefix, record, index_info, group_prefix_len); |
|
9131 |
||
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9132 |
return 0; |
1
by brian
clean slate |
9133 |
}
|
9134 |
||
9135 |
||
9136 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
9137 |
/*
|
1
by brian
clean slate |
9138 |
Get the next key containing the MIN and/or MAX key for the next group.
|
9139 |
||
9140 |
SYNOPSIS
|
|
9141 |
QUICK_GROUP_MIN_MAX_SELECT::get_next()
|
|
9142 |
||
9143 |
DESCRIPTION
|
|
9144 |
The method finds the next subsequent group of records that satisfies the
|
|
9145 |
query conditions and finds the keys that contain the MIN/MAX values for
|
|
9146 |
the key part referenced by the MIN/MAX function(s). Once a group and its
|
|
9147 |
MIN/MAX values are found, store these values in the Item_sum objects for
|
|
9148 |
the MIN/MAX functions. The rest of the values in the result row are stored
|
|
9149 |
in the Item_field::result_field of each select field. If the query does
|
|
9150 |
not contain MIN and/or MAX functions, then the function only finds the
|
|
9151 |
group prefix, which is a query answer itself.
|
|
9152 |
||
9153 |
NOTES
|
|
9154 |
If both MIN and MAX are computed, then we use the fact that if there is
|
|
9155 |
no MIN key, there can't be a MAX key as well, so we can skip looking
|
|
9156 |
for a MAX key in this case.
|
|
9157 |
||
9158 |
RETURN
|
|
9159 |
0 on success
|
|
9160 |
HA_ERR_END_OF_FILE if returned all keys
|
|
9161 |
other if some error occurred
|
|
9162 |
*/
|
|
9163 |
||
9164 |
int QUICK_GROUP_MIN_MAX_SELECT::get_next() |
|
9165 |
{
|
|
9166 |
int min_res= 0; |
|
9167 |
int max_res= 0; |
|
9168 |
int result; |
|
9169 |
int is_last_prefix= 0; |
|
9170 |
||
9171 |
/*
|
|
9172 |
Loop until a group is found that satisfies all query conditions or the last
|
|
9173 |
group is reached.
|
|
9174 |
*/
|
|
9175 |
do
|
|
9176 |
{
|
|
9177 |
result= next_prefix(); |
|
9178 |
/*
|
|
9179 |
Check if this is the last group prefix. Notice that at this point
|
|
9180 |
this->record contains the current prefix in record format.
|
|
9181 |
*/
|
|
9182 |
if (!result) |
|
9183 |
{
|
|
9184 |
is_last_prefix= key_cmp(index_info->key_part, last_prefix, |
|
9185 |
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. |
9186 |
assert(is_last_prefix <= 0); |
1
by brian
clean slate |
9187 |
}
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
9188 |
else
|
1
by brian
clean slate |
9189 |
{
|
9190 |
if (result == HA_ERR_KEY_NOT_FOUND) |
|
9191 |
continue; |
|
9192 |
break; |
|
9193 |
}
|
|
9194 |
||
9195 |
if (have_min) |
|
9196 |
{
|
|
9197 |
min_res= next_min(); |
|
9198 |
if (min_res == 0) |
|
9199 |
update_min_result(); |
|
9200 |
}
|
|
9201 |
/* If there is no MIN in the group, there is no MAX either. */
|
|
9202 |
if ((have_max && !have_min) || |
|
9203 |
(have_max && have_min && (min_res == 0))) |
|
9204 |
{
|
|
9205 |
max_res= next_max(); |
|
9206 |
if (max_res == 0) |
|
9207 |
update_max_result(); |
|
9208 |
/* If a MIN was found, a MAX must have been found as well. */
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9209 |
assert(((have_max && !have_min) || |
9210 |
(have_max && have_min && (max_res == 0)))); |
|
1
by brian
clean slate |
9211 |
}
|
9212 |
/*
|
|
9213 |
If this is just a GROUP BY or DISTINCT without MIN or MAX and there
|
|
9214 |
are equality predicates for the key parts after the group, find the
|
|
9215 |
first sub-group with the extended prefix.
|
|
9216 |
*/
|
|
9217 |
if (!have_min && !have_max && key_infix_len > 0) |
|
9218 |
result= file->index_read_map(record, group_prefix, |
|
9219 |
make_prev_keypart_map(real_key_parts), |
|
9220 |
HA_READ_KEY_EXACT); |
|
9221 |
||
9222 |
result= have_min ? min_res : have_max ? max_res : result; |
|
9223 |
} while ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) && |
|
9224 |
is_last_prefix != 0); |
|
9225 |
||
9226 |
if (result == 0) |
|
9227 |
{
|
|
9228 |
/*
|
|
9229 |
Partially mimic the behavior of end_select_send. Copy the
|
|
9230 |
field data from Item_field::field into Item_field::result_field
|
|
9231 |
of each non-aggregated field (the group fields, and optionally
|
|
9232 |
other fields in non-ANSI SQL mode).
|
|
9233 |
*/
|
|
9234 |
copy_fields(&join->tmp_table_param); |
|
9235 |
}
|
|
9236 |
else if (result == HA_ERR_KEY_NOT_FOUND) |
|
9237 |
result= HA_ERR_END_OF_FILE; |
|
9238 |
||
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9239 |
return result; |
1
by brian
clean slate |
9240 |
}
|
9241 |
||
9242 |
||
9243 |
/*
|
|
9244 |
Retrieve the minimal key in the next group.
|
|
9245 |
||
9246 |
SYNOPSIS
|
|
9247 |
QUICK_GROUP_MIN_MAX_SELECT::next_min()
|
|
9248 |
||
9249 |
DESCRIPTION
|
|
9250 |
Find the minimal key within this group such that the key satisfies the query
|
|
9251 |
conditions and NULL semantics. The found key is loaded into this->record.
|
|
9252 |
||
9253 |
IMPLEMENTATION
|
|
9254 |
Depending on the values of min_max_ranges.elements, key_infix_len, and
|
|
9255 |
whether there is a NULL in the MIN field, this function may directly
|
|
9256 |
return without any data access. In this case we use the key loaded into
|
|
9257 |
this->record by the call to this->next_prefix() just before this call.
|
|
9258 |
||
9259 |
RETURN
|
|
9260 |
0 on success
|
|
9261 |
HA_ERR_KEY_NOT_FOUND if no MIN key was found that fulfills all conditions.
|
|
9262 |
HA_ERR_END_OF_FILE - "" -
|
|
9263 |
other if some error occurred
|
|
9264 |
*/
|
|
9265 |
||
9266 |
int QUICK_GROUP_MIN_MAX_SELECT::next_min() |
|
9267 |
{
|
|
9268 |
int result= 0; |
|
9269 |
||
9270 |
/* Find the MIN key using the eventually extended group prefix. */
|
|
9271 |
if (min_max_ranges.elements > 0) |
|
9272 |
{
|
|
9273 |
if ((result= next_min_in_range())) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9274 |
return result; |
1
by brian
clean slate |
9275 |
}
|
9276 |
else
|
|
9277 |
{
|
|
9278 |
/* Apply the constant equality conditions to the non-group select fields */
|
|
9279 |
if (key_infix_len > 0) |
|
9280 |
{
|
|
9281 |
if ((result= file->index_read_map(record, group_prefix, |
|
9282 |
make_prev_keypart_map(real_key_parts), |
|
9283 |
HA_READ_KEY_EXACT))) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9284 |
return result; |
1
by brian
clean slate |
9285 |
}
|
9286 |
||
9287 |
/*
|
|
9288 |
If the min/max argument field is NULL, skip subsequent rows in the same
|
|
9289 |
group with NULL in it. Notice that:
|
|
9290 |
- if the first row in a group doesn't have a NULL in the field, no row
|
|
9291 |
in the same group has (because NULL < any other value),
|
|
9292 |
- min_max_arg_part->field->ptr points to some place in 'record'.
|
|
9293 |
*/
|
|
9294 |
if (min_max_arg_part && min_max_arg_part->field->is_null()) |
|
9295 |
{
|
|
9296 |
/* Find the first subsequent record without NULL in the MIN/MAX field. */
|
|
9297 |
key_copy(tmp_record, record, index_info, 0); |
|
9298 |
result= file->index_read_map(record, tmp_record, |
|
9299 |
make_keypart_map(real_key_parts), |
|
9300 |
HA_READ_AFTER_KEY); |
|
9301 |
/*
|
|
9302 |
Check if the new record belongs to the current group by comparing its
|
|
9303 |
prefix with the group's prefix. If it is from the next group, then the
|
|
9304 |
whole group has NULLs in the MIN/MAX field, so use the first record in
|
|
9305 |
the group as a result.
|
|
9306 |
TODO:
|
|
9307 |
It is possible to reuse this new record as the result candidate for the
|
|
9308 |
next call to next_min(), and to save one lookup in the next call. For
|
|
9309 |
this add a new member 'this->next_group_prefix'.
|
|
9310 |
*/
|
|
9311 |
if (!result) |
|
9312 |
{
|
|
9313 |
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len)) |
|
9314 |
key_restore(record, tmp_record, index_info, 0); |
|
9315 |
}
|
|
9316 |
else if (result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) |
|
9317 |
result= 0; /* There is a result in any case. */ |
|
9318 |
}
|
|
9319 |
}
|
|
9320 |
||
9321 |
/*
|
|
9322 |
If the MIN attribute is non-nullable, this->record already contains the
|
|
9323 |
MIN key in the group, so just return.
|
|
9324 |
*/
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9325 |
return result; |
1
by brian
clean slate |
9326 |
}
|
9327 |
||
9328 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
9329 |
/*
|
1
by brian
clean slate |
9330 |
Retrieve the maximal key in the next group.
|
9331 |
||
9332 |
SYNOPSIS
|
|
9333 |
QUICK_GROUP_MIN_MAX_SELECT::next_max()
|
|
9334 |
||
9335 |
DESCRIPTION
|
|
9336 |
Lookup the maximal key of the group, and store it into this->record.
|
|
9337 |
||
9338 |
RETURN
|
|
9339 |
0 on success
|
|
9340 |
HA_ERR_KEY_NOT_FOUND if no MAX key was found that fulfills all conditions.
|
|
9341 |
HA_ERR_END_OF_FILE - "" -
|
|
9342 |
other if some error occurred
|
|
9343 |
*/
|
|
9344 |
||
9345 |
int QUICK_GROUP_MIN_MAX_SELECT::next_max() |
|
9346 |
{
|
|
9347 |
int result; |
|
9348 |
||
9349 |
/* Get the last key in the (possibly extended) group. */
|
|
9350 |
if (min_max_ranges.elements > 0) |
|
9351 |
result= next_max_in_range(); |
|
9352 |
else
|
|
9353 |
result= file->index_read_map(record, group_prefix, |
|
9354 |
make_prev_keypart_map(real_key_parts), |
|
9355 |
HA_READ_PREFIX_LAST); |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9356 |
return result; |
1
by brian
clean slate |
9357 |
}
|
9358 |
||
9359 |
||
9360 |
/*
|
|
9361 |
Determine the prefix of the next group.
|
|
9362 |
||
9363 |
SYNOPSIS
|
|
9364 |
QUICK_GROUP_MIN_MAX_SELECT::next_prefix()
|
|
9365 |
||
9366 |
DESCRIPTION
|
|
9367 |
Determine the prefix of the next group that satisfies the query conditions.
|
|
9368 |
If there is a range condition referencing the group attributes, use a
|
|
9369 |
QUICK_RANGE_SELECT object to retrieve the *first* key that satisfies the
|
|
9370 |
condition. If there is a key infix of constants, append this infix
|
|
9371 |
immediately after the group attributes. The possibly extended prefix is
|
|
9372 |
stored in this->group_prefix. The first key of the found group is stored in
|
|
9373 |
this->record, on which relies this->next_min().
|
|
9374 |
||
9375 |
RETURN
|
|
9376 |
0 on success
|
|
9377 |
HA_ERR_KEY_NOT_FOUND if there is no key with the formed prefix
|
|
9378 |
HA_ERR_END_OF_FILE if there are no more keys
|
|
9379 |
other if some error occurred
|
|
9380 |
*/
|
|
9381 |
int QUICK_GROUP_MIN_MAX_SELECT::next_prefix() |
|
9382 |
{
|
|
9383 |
int result; |
|
9384 |
||
9385 |
if (quick_prefix_select) |
|
9386 |
{
|
|
481
by Brian Aker
Remove all of uchar. |
9387 |
unsigned char *cur_prefix= seen_first_key ? group_prefix : NULL; |
1
by brian
clean slate |
9388 |
if ((result= quick_prefix_select->get_next_prefix(group_prefix_len, |
9389 |
make_prev_keypart_map(group_key_parts), cur_prefix))) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9390 |
return result; |
55
by brian
Update for using real bool types. |
9391 |
seen_first_key= true; |
1
by brian
clean slate |
9392 |
}
|
9393 |
else
|
|
9394 |
{
|
|
9395 |
if (!seen_first_key) |
|
9396 |
{
|
|
9397 |
result= file->index_first(record); |
|
9398 |
if (result) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9399 |
return result; |
55
by brian
Update for using real bool types. |
9400 |
seen_first_key= true; |
1
by brian
clean slate |
9401 |
}
|
9402 |
else
|
|
9403 |
{
|
|
9404 |
/* Load the first key in this group into record. */
|
|
9405 |
result= file->index_read_map(record, group_prefix, |
|
9406 |
make_prev_keypart_map(group_key_parts), |
|
9407 |
HA_READ_AFTER_KEY); |
|
9408 |
if (result) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9409 |
return result; |
1
by brian
clean slate |
9410 |
}
|
9411 |
}
|
|
9412 |
||
9413 |
/* Save the prefix of this group for subsequent calls. */
|
|
9414 |
key_copy(group_prefix, record, index_info, group_prefix_len); |
|
9415 |
/* Append key_infix to group_prefix. */
|
|
9416 |
if (key_infix_len > 0) |
|
9417 |
memcpy(group_prefix + group_prefix_len, |
|
9418 |
key_infix, key_infix_len); |
|
9419 |
||
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9420 |
return 0; |
1
by brian
clean slate |
9421 |
}
|
9422 |
||
9423 |
||
9424 |
/*
|
|
9425 |
Find the minimal key in a group that satisfies some range conditions for the
|
|
9426 |
min/max argument field.
|
|
9427 |
||
9428 |
SYNOPSIS
|
|
9429 |
QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range()
|
|
9430 |
||
9431 |
DESCRIPTION
|
|
9432 |
Given the sequence of ranges min_max_ranges, find the minimal key that is
|
|
9433 |
in the left-most possible range. If there is no such key, then the current
|
|
9434 |
group does not have a MIN key that satisfies the WHERE clause. If a key is
|
|
9435 |
found, its value is stored in this->record.
|
|
9436 |
||
9437 |
RETURN
|
|
9438 |
0 on success
|
|
9439 |
HA_ERR_KEY_NOT_FOUND if there is no key with the given prefix in any of
|
|
9440 |
the ranges
|
|
9441 |
HA_ERR_END_OF_FILE - "" -
|
|
9442 |
other if some error
|
|
9443 |
*/
|
|
9444 |
||
9445 |
int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range() |
|
9446 |
{
|
|
9447 |
ha_rkey_function find_flag; |
|
9448 |
key_part_map keypart_map; |
|
9449 |
QUICK_RANGE *cur_range; |
|
55
by brian
Update for using real bool types. |
9450 |
bool found_null= false; |
1
by brian
clean slate |
9451 |
int result= HA_ERR_KEY_NOT_FOUND; |
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
9452 |
basic_string<unsigned char> max_key; |
660.1.6
by Eric Herman
trailing whitespace fixup |
9453 |
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
9454 |
max_key.reserve(real_prefix_len + min_max_arg_len); |
1
by brian
clean slate |
9455 |
|
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. |
9456 |
assert(min_max_ranges.elements > 0); |
1
by brian
clean slate |
9457 |
|
482
by Brian Aker
Remove uint. |
9458 |
for (uint32_t range_idx= 0; range_idx < min_max_ranges.elements; range_idx++) |
1
by brian
clean slate |
9459 |
{ /* Search from the left-most range to the right. */ |
481
by Brian Aker
Remove all of uchar. |
9460 |
get_dynamic(&min_max_ranges, (unsigned char*)&cur_range, range_idx); |
1
by brian
clean slate |
9461 |
|
9462 |
/*
|
|
9463 |
If the current value for the min/max argument is bigger than the right
|
|
9464 |
boundary of cur_range, there is no need to check this range.
|
|
9465 |
*/
|
|
9466 |
if (range_idx != 0 && !(cur_range->flag & NO_MAX_RANGE) && |
|
481
by Brian Aker
Remove all of uchar. |
9467 |
(key_cmp(min_max_arg_part, (const unsigned char*) cur_range->max_key, |
1
by brian
clean slate |
9468 |
min_max_arg_len) == 1)) |
9469 |
continue; |
|
9470 |
||
9471 |
if (cur_range->flag & NO_MIN_RANGE) |
|
9472 |
{
|
|
9473 |
keypart_map= make_prev_keypart_map(real_key_parts); |
|
9474 |
find_flag= HA_READ_KEY_EXACT; |
|
9475 |
}
|
|
9476 |
else
|
|
9477 |
{
|
|
9478 |
/* Extend the search key with the lower boundary for this range. */
|
|
9479 |
memcpy(group_prefix + real_prefix_len, cur_range->min_key, |
|
9480 |
cur_range->min_length); |
|
9481 |
keypart_map= make_keypart_map(real_key_parts); |
|
9482 |
find_flag= (cur_range->flag & (EQ_RANGE | NULL_RANGE)) ? |
|
9483 |
HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MIN) ? |
|
9484 |
HA_READ_AFTER_KEY : HA_READ_KEY_OR_NEXT; |
|
9485 |
}
|
|
9486 |
||
9487 |
result= file->index_read_map(record, group_prefix, keypart_map, find_flag); |
|
9488 |
if (result) |
|
9489 |
{
|
|
9490 |
if ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) && |
|
9491 |
(cur_range->flag & (EQ_RANGE | NULL_RANGE))) |
|
9492 |
continue; /* Check the next range. */ |
|
9493 |
||
9494 |
/*
|
|
9495 |
In all other cases (HA_ERR_*, HA_READ_KEY_EXACT with NO_MIN_RANGE,
|
|
9496 |
HA_READ_AFTER_KEY, HA_READ_KEY_OR_NEXT) if the lookup failed for this
|
|
9497 |
range, it can't succeed for any other subsequent range.
|
|
9498 |
*/
|
|
9499 |
break; |
|
9500 |
}
|
|
9501 |
||
9502 |
/* A key was found. */
|
|
9503 |
if (cur_range->flag & EQ_RANGE) |
|
9504 |
break; /* No need to perform the checks below for equal keys. */ |
|
9505 |
||
9506 |
if (cur_range->flag & NULL_RANGE) |
|
9507 |
{
|
|
9508 |
/*
|
|
9509 |
Remember this key, and continue looking for a non-NULL key that
|
|
9510 |
satisfies some other condition.
|
|
9511 |
*/
|
|
9512 |
memcpy(tmp_record, record, head->s->rec_buff_length); |
|
55
by brian
Update for using real bool types. |
9513 |
found_null= true; |
1
by brian
clean slate |
9514 |
continue; |
9515 |
}
|
|
9516 |
||
9517 |
/* Check if record belongs to the current group. */
|
|
9518 |
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len)) |
|
9519 |
{
|
|
9520 |
result= HA_ERR_KEY_NOT_FOUND; |
|
9521 |
continue; |
|
9522 |
}
|
|
9523 |
||
9524 |
/* If there is an upper limit, check if the found key is in the range. */
|
|
9525 |
if ( !(cur_range->flag & NO_MAX_RANGE) ) |
|
9526 |
{
|
|
9527 |
/* Compose the MAX key for the range. */
|
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
9528 |
max_key.clear(); |
9529 |
max_key.append(group_prefix, real_prefix_len); |
|
9530 |
max_key.append(cur_range->max_key, cur_range->max_length); |
|
1
by brian
clean slate |
9531 |
/* Compare the found key with max_key. */
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
9532 |
int cmp_res= key_cmp(index_info->key_part, |
9533 |
max_key.data(), |
|
1
by brian
clean slate |
9534 |
real_prefix_len + min_max_arg_len); |
9535 |
if ((!((cur_range->flag & NEAR_MAX) && (cmp_res == -1)) || (cmp_res <= 0))) |
|
9536 |
{
|
|
9537 |
result= HA_ERR_KEY_NOT_FOUND; |
|
9538 |
continue; |
|
9539 |
}
|
|
9540 |
}
|
|
9541 |
/* 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. |
9542 |
assert(result == 0); |
1
by brian
clean slate |
9543 |
break; |
9544 |
}
|
|
9545 |
/*
|
|
9546 |
If there was a key with NULL in the MIN/MAX field, and there was no other
|
|
9547 |
key without NULL from the same group that satisfies some other condition,
|
|
9548 |
then use the key with the NULL.
|
|
9549 |
*/
|
|
9550 |
if (found_null && result) |
|
9551 |
{
|
|
9552 |
memcpy(record, tmp_record, head->s->rec_buff_length); |
|
9553 |
result= 0; |
|
9554 |
}
|
|
9555 |
return result; |
|
9556 |
}
|
|
9557 |
||
9558 |
||
9559 |
/*
|
|
9560 |
Find the maximal key in a group that satisfies some range conditions for the
|
|
9561 |
min/max argument field.
|
|
9562 |
||
9563 |
SYNOPSIS
|
|
9564 |
QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range()
|
|
9565 |
||
9566 |
DESCRIPTION
|
|
9567 |
Given the sequence of ranges min_max_ranges, find the maximal key that is
|
|
9568 |
in the right-most possible range. If there is no such key, then the current
|
|
9569 |
group does not have a MAX key that satisfies the WHERE clause. If a key is
|
|
9570 |
found, its value is stored in this->record.
|
|
9571 |
||
9572 |
RETURN
|
|
9573 |
0 on success
|
|
9574 |
HA_ERR_KEY_NOT_FOUND if there is no key with the given prefix in any of
|
|
9575 |
the ranges
|
|
9576 |
HA_ERR_END_OF_FILE - "" -
|
|
9577 |
other if some error
|
|
9578 |
*/
|
|
9579 |
||
9580 |
int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range() |
|
9581 |
{
|
|
9582 |
ha_rkey_function find_flag; |
|
9583 |
key_part_map keypart_map; |
|
9584 |
QUICK_RANGE *cur_range; |
|
9585 |
int result; |
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
9586 |
basic_string<unsigned char> min_key; |
9587 |
min_key.reserve(real_prefix_len + min_max_arg_len); |
|
1
by brian
clean slate |
9588 |
|
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. |
9589 |
assert(min_max_ranges.elements > 0); |
1
by brian
clean slate |
9590 |
|
482
by Brian Aker
Remove uint. |
9591 |
for (uint32_t range_idx= min_max_ranges.elements; range_idx > 0; range_idx--) |
1
by brian
clean slate |
9592 |
{ /* Search from the right-most range to the left. */ |
481
by Brian Aker
Remove all of uchar. |
9593 |
get_dynamic(&min_max_ranges, (unsigned char*)&cur_range, range_idx - 1); |
1
by brian
clean slate |
9594 |
|
9595 |
/*
|
|
9596 |
If the current value for the min/max argument is smaller than the left
|
|
9597 |
boundary of cur_range, there is no need to check this range.
|
|
9598 |
*/
|
|
9599 |
if (range_idx != min_max_ranges.elements && |
|
9600 |
!(cur_range->flag & NO_MIN_RANGE) && |
|
481
by Brian Aker
Remove all of uchar. |
9601 |
(key_cmp(min_max_arg_part, (const unsigned char*) cur_range->min_key, |
1
by brian
clean slate |
9602 |
min_max_arg_len) == -1)) |
9603 |
continue; |
|
9604 |
||
9605 |
if (cur_range->flag & NO_MAX_RANGE) |
|
9606 |
{
|
|
9607 |
keypart_map= make_prev_keypart_map(real_key_parts); |
|
9608 |
find_flag= HA_READ_PREFIX_LAST; |
|
9609 |
}
|
|
9610 |
else
|
|
9611 |
{
|
|
9612 |
/* Extend the search key with the upper boundary for this range. */
|
|
9613 |
memcpy(group_prefix + real_prefix_len, cur_range->max_key, |
|
9614 |
cur_range->max_length); |
|
9615 |
keypart_map= make_keypart_map(real_key_parts); |
|
9616 |
find_flag= (cur_range->flag & EQ_RANGE) ? |
|
9617 |
HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MAX) ? |
|
9618 |
HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV; |
|
9619 |
}
|
|
9620 |
||
9621 |
result= file->index_read_map(record, group_prefix, keypart_map, find_flag); |
|
9622 |
||
9623 |
if (result) |
|
9624 |
{
|
|
9625 |
if ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) && |
|
9626 |
(cur_range->flag & EQ_RANGE)) |
|
9627 |
continue; /* Check the next range. */ |
|
9628 |
||
9629 |
/*
|
|
9630 |
In no key was found with this upper bound, there certainly are no keys
|
|
9631 |
in the ranges to the left.
|
|
9632 |
*/
|
|
9633 |
return result; |
|
9634 |
}
|
|
9635 |
/* A key was found. */
|
|
9636 |
if (cur_range->flag & EQ_RANGE) |
|
9637 |
return 0; /* No need to perform the checks below for equal keys. */ |
|
9638 |
||
9639 |
/* Check if record belongs to the current group. */
|
|
9640 |
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len)) |
|
9641 |
continue; // Row not found |
|
9642 |
||
9643 |
/* If there is a lower limit, check if the found key is in the range. */
|
|
9644 |
if ( !(cur_range->flag & NO_MIN_RANGE) ) |
|
9645 |
{
|
|
9646 |
/* Compose the MIN key for the range. */
|
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
9647 |
min_key.clear(); |
9648 |
min_key.append(group_prefix, real_prefix_len); |
|
9649 |
min_key.append(cur_range->min_key, cur_range->min_length); |
|
9650 |
||
1
by brian
clean slate |
9651 |
/* Compare the found key with min_key. */
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
9652 |
int cmp_res= key_cmp(index_info->key_part, |
9653 |
min_key.data(), |
|
1
by brian
clean slate |
9654 |
real_prefix_len + min_max_arg_len); |
9655 |
if ((!((cur_range->flag & NEAR_MIN) && (cmp_res == 1)) || |
|
9656 |
(cmp_res >= 0))) |
|
9657 |
continue; |
|
9658 |
}
|
|
9659 |
/* If we got to this point, the current key qualifies as MAX. */
|
|
9660 |
return result; |
|
9661 |
}
|
|
9662 |
return HA_ERR_KEY_NOT_FOUND; |
|
9663 |
}
|
|
9664 |
||
9665 |
||
9666 |
/*
|
|
9667 |
Update all MIN function results with the newly found value.
|
|
9668 |
||
9669 |
SYNOPSIS
|
|
9670 |
QUICK_GROUP_MIN_MAX_SELECT::update_min_result()
|
|
9671 |
||
9672 |
DESCRIPTION
|
|
9673 |
The method iterates through all MIN functions and updates the result value
|
|
9674 |
of each function by calling Item_sum::reset(), which in turn picks the new
|
|
9675 |
result value from this->head->record[0], previously updated by
|
|
9676 |
next_min(). The updated value is stored in a member variable of each of the
|
|
9677 |
Item_sum objects, depending on the value type.
|
|
9678 |
||
9679 |
IMPLEMENTATION
|
|
9680 |
The update must be done separately for MIN and MAX, immediately after
|
|
9681 |
next_min() was called and before next_max() is called, because both MIN and
|
|
9682 |
MAX take their result value from the same buffer this->head->record[0]
|
|
9683 |
(i.e. this->record).
|
|
9684 |
||
9685 |
RETURN
|
|
9686 |
None
|
|
9687 |
*/
|
|
9688 |
||
9689 |
void QUICK_GROUP_MIN_MAX_SELECT::update_min_result() |
|
9690 |
{
|
|
9691 |
Item_sum *min_func; |
|
9692 |
||
9693 |
min_functions_it->rewind(); |
|
9694 |
while ((min_func= (*min_functions_it)++)) |
|
9695 |
min_func->reset(); |
|
9696 |
}
|
|
9697 |
||
9698 |
||
9699 |
/*
|
|
9700 |
Update all MAX function results with the newly found value.
|
|
9701 |
||
9702 |
SYNOPSIS
|
|
9703 |
QUICK_GROUP_MIN_MAX_SELECT::update_max_result()
|
|
9704 |
||
9705 |
DESCRIPTION
|
|
9706 |
The method iterates through all MAX functions and updates the result value
|
|
9707 |
of each function by calling Item_sum::reset(), which in turn picks the new
|
|
9708 |
result value from this->head->record[0], previously updated by
|
|
9709 |
next_max(). The updated value is stored in a member variable of each of the
|
|
9710 |
Item_sum objects, depending on the value type.
|
|
9711 |
||
9712 |
IMPLEMENTATION
|
|
9713 |
The update must be done separately for MIN and MAX, immediately after
|
|
9714 |
next_max() was called, because both MIN and MAX take their result value
|
|
9715 |
from the same buffer this->head->record[0] (i.e. this->record).
|
|
9716 |
||
9717 |
RETURN
|
|
9718 |
None
|
|
9719 |
*/
|
|
9720 |
||
9721 |
void QUICK_GROUP_MIN_MAX_SELECT::update_max_result() |
|
9722 |
{
|
|
9723 |
Item_sum *max_func; |
|
9724 |
||
9725 |
max_functions_it->rewind(); |
|
9726 |
while ((max_func= (*max_functions_it)++)) |
|
9727 |
max_func->reset(); |
|
9728 |
}
|
|
9729 |
||
9730 |
||
9731 |
/*
|
|
9732 |
Append comma-separated list of keys this quick select uses to key_names;
|
|
9733 |
append comma-separated list of corresponding used lengths to used_lengths.
|
|
9734 |
||
9735 |
SYNOPSIS
|
|
9736 |
QUICK_GROUP_MIN_MAX_SELECT::add_keys_and_lengths()
|
|
9737 |
key_names [out] Names of used indexes
|
|
9738 |
used_lengths [out] Corresponding lengths of the index names
|
|
9739 |
||
9740 |
DESCRIPTION
|
|
9741 |
This method is used by select_describe to extract the names of the
|
|
9742 |
indexes used by a quick select.
|
|
9743 |
||
9744 |
*/
|
|
9745 |
||
9746 |
void QUICK_GROUP_MIN_MAX_SELECT::add_keys_and_lengths(String *key_names, |
|
9747 |
String *used_lengths) |
|
9748 |
{
|
|
9749 |
char buf[64]; |
|
482
by Brian Aker
Remove uint. |
9750 |
uint32_t length; |
1
by brian
clean slate |
9751 |
key_names->append(index_info->name); |
152
by Brian Aker
longlong replacement |
9752 |
length= int64_t2str(max_used_key_length, buf, 10) - buf; |
1
by brian
clean slate |
9753 |
used_lengths->append(buf, length); |
9754 |
}
|
|
9755 |
||
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
9756 |
static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map, const char *) |
1
by brian
clean slate |
9757 |
{
|
9758 |
SEL_ARG **key,**end; |
|
9759 |
int idx; |
|
9760 |
char buff[1024]; |
|
9761 |
||
9762 |
String tmp(buff,sizeof(buff),&my_charset_bin); |
|
9763 |
tmp.length(0); |
|
9764 |
for (idx= 0,key=tree->keys, end=key+param->keys ; |
|
9765 |
key != end ; |
|
9766 |
key++,idx++) |
|
9767 |
{
|
|
9768 |
if (tree_map->is_set(idx)) |
|
9769 |
{
|
|
482
by Brian Aker
Remove uint. |
9770 |
uint32_t keynr= param->real_keynr[idx]; |
1
by brian
clean slate |
9771 |
if (tmp.length()) |
9772 |
tmp.append(','); |
|
9773 |
tmp.append(param->table->key_info[keynr].name); |
|
9774 |
}
|
|
9775 |
}
|
|
9776 |
if (!tmp.length()) |
|
9777 |
tmp.append(STRING_WITH_LEN("(empty)")); |
|
9778 |
}
|
|
9779 |
||
9780 |
||
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
9781 |
static void print_ror_scans_arr(Table *table, |
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
9782 |
const char *, struct st_ror_scan_info **start, |
1
by brian
clean slate |
9783 |
struct st_ror_scan_info **end) |
9784 |
{
|
|
9785 |
char buff[1024]; |
|
9786 |
String tmp(buff,sizeof(buff),&my_charset_bin); |
|
9787 |
tmp.length(0); |
|
9788 |
for (;start != end; start++) |
|
9789 |
{
|
|
9790 |
if (tmp.length()) |
|
9791 |
tmp.append(','); |
|
9792 |
tmp.append(table->key_info[(*start)->keynr].name); |
|
9793 |
}
|
|
9794 |
if (!tmp.length()) |
|
9795 |
tmp.append(STRING_WITH_LEN("(empty)")); |
|
9796 |
}
|
|
9797 |
||
9798 |
/*****************************************************************************
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
9799 |
** Instantiate templates
|
1
by brian
clean slate |
9800 |
*****************************************************************************/
|
9801 |
||
9802 |
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
|
|
9803 |
template class List<QUICK_RANGE>; |
|
9804 |
template class List_iterator<QUICK_RANGE>; |
|
9805 |
#endif
|