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 |
|
907.1.7
by Jay Pipes
Merged in remove-timezone work |
114 |
#include "drizzled/temporal.h" /* Needed in get_mm_leaf() for timestamp -> datetime comparisons */ |
115 |
||
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
116 |
#include <string> |
572.1.4
by Monty Taylor
Removed a bunch of unusued tests and defines from autoconf. |
117 |
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
118 |
using namespace std; |
1
by brian
clean slate |
119 |
|
120 |
/*
|
|
121 |
Convert double value to #rows. Currently this does floor(), and we
|
|
122 |
might consider using round() instead.
|
|
123 |
*/
|
|
919.2.11
by Monty Taylor
Removed C99 isnan() usage, which allows us to remove the util/math.{cc,h} workarounds. Yay for standards! |
124 |
static inline ha_rows double2rows(double x) |
125 |
{
|
|
126 |
return static_cast<ha_rows>(x); |
|
127 |
}
|
|
1
by brian
clean slate |
128 |
|
481
by Brian Aker
Remove all of uchar. |
129 |
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 |
130 |
|
481
by Brian Aker
Remove all of uchar. |
131 |
static unsigned char is_null_string[2]= {1,0}; |
1
by brian
clean slate |
132 |
|
133 |
class RANGE_OPT_PARAM; |
|
134 |
/*
|
|
135 |
A construction block of the SEL_ARG-graph.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
136 |
|
137 |
The following description only covers graphs of SEL_ARG objects with
|
|
1
by brian
clean slate |
138 |
sel_arg->type==KEY_RANGE:
|
139 |
||
140 |
One SEL_ARG object represents an "elementary interval" in form
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
141 |
|
1
by brian
clean slate |
142 |
min_value <=? table.keypartX <=? max_value
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
143 |
|
1
by brian
clean slate |
144 |
The interval is a non-empty interval of any kind: with[out] minimum/maximum
|
145 |
bound, [half]open/closed, single-point interval, etc.
|
|
146 |
||
147 |
1. SEL_ARG GRAPH STRUCTURE
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
148 |
|
1
by brian
clean slate |
149 |
SEL_ARG objects are linked together in a graph. The meaning of the graph
|
150 |
is better demostrated by an example:
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
151 |
|
1
by brian
clean slate |
152 |
tree->keys[i]
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
153 |
|
|
1
by brian
clean slate |
154 |
| $ $
|
155 |
| part=1 $ part=2 $ part=3
|
|
156 |
| $ $
|
|
157 |
| +-------+ $ +-------+ $ +--------+
|
|
158 |
| | kp1<1 |--$-->| kp2=5 |--$-->| kp3=10 |
|
|
159 |
| +-------+ $ +-------+ $ +--------+
|
|
160 |
| | $ $ |
|
|
161 |
| | $ $ +--------+
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
162 |
| | $ $ | kp3=12 |
|
163 |
| | $ $ +--------+
|
|
164 |
| +-------+ $ $
|
|
165 |
\->| kp1=2 |--$--------------$-+
|
|
1
by brian
clean slate |
166 |
+-------+ $ $ | +--------+
|
167 |
| $ $ ==>| kp3=11 |
|
|
168 |
+-------+ $ $ | +--------+
|
|
169 |
| kp1=3 |--$--------------$-+ |
|
|
170 |
+-------+ $ $ +--------+
|
|
171 |
| $ $ | kp3=14 |
|
|
172 |
... $ $ +--------+
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
173 |
|
1
by brian
clean slate |
174 |
The entire graph is partitioned into "interval lists".
|
175 |
||
176 |
An interval list is a sequence of ordered disjoint intervals over the same
|
|
177 |
key part. SEL_ARG are linked via "next" and "prev" pointers. Additionally,
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
178 |
all intervals in the list form an RB-tree, linked via left/right/parent
|
1
by brian
clean slate |
179 |
pointers. The RB-tree root SEL_ARG object will be further called "root of the
|
180 |
interval list".
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
181 |
|
182 |
In the example pic, there are 4 interval lists:
|
|
1
by brian
clean slate |
183 |
"kp<1 OR kp1=2 OR kp1=3", "kp2=5", "kp3=10 OR kp3=12", "kp3=11 OR kp3=13".
|
184 |
The vertical lines represent SEL_ARG::next/prev pointers.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
185 |
|
1
by brian
clean slate |
186 |
In an interval list, each member X may have SEL_ARG::next_key_part pointer
|
187 |
pointing to the root of another interval list Y. The pointed interval list
|
|
188 |
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: |
189 |
|
1
by brian
clean slate |
190 |
In the example pic, the next_key_part pointers are represented by
|
191 |
horisontal lines.
|
|
192 |
||
193 |
2. SEL_ARG GRAPH SEMANTICS
|
|
194 |
||
195 |
It represents a condition in a special form (we don't have a name for it ATM)
|
|
196 |
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: |
197 |
|
1
by brian
clean slate |
198 |
For example, the picture represents the condition in form:
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
199 |
(kp1 < 1 AND kp2=5 AND (kp3=10 OR kp3=12)) OR
|
200 |
(kp1=2 AND (kp3=11 OR kp3=14)) OR
|
|
1
by brian
clean slate |
201 |
(kp1=3 AND (kp3=11 OR kp3=14))
|
202 |
||
203 |
||
204 |
3. SEL_ARG GRAPH USE
|
|
205 |
||
206 |
Use get_mm_tree() to construct SEL_ARG graph from WHERE condition.
|
|
207 |
Then walk the SEL_ARG graph and get a list of dijsoint ordered key
|
|
208 |
intervals (i.e. intervals in form
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
209 |
|
1
by brian
clean slate |
210 |
(constA1, .., const1_K) < (keypart1,.., keypartK) < (constB1, .., constB_K)
|
211 |
||
212 |
Those intervals can be used to access the index. The uses are in:
|
|
213 |
- check_quick_select() - Walk the SEL_ARG graph and find an estimate of
|
|
214 |
how many table records are contained within all
|
|
215 |
intervals.
|
|
216 |
- get_quick_select() - Walk the SEL_ARG, materialize the key intervals,
|
|
217 |
and create QUICK_RANGE_SELECT object that will
|
|
218 |
read records within these intervals.
|
|
219 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
220 |
4. SPACE COMPLEXITY NOTES
|
1
by brian
clean slate |
221 |
|
222 |
SEL_ARG graph is a representation of an ordered disjoint sequence of
|
|
223 |
intervals over the ordered set of index tuple values.
|
|
224 |
||
225 |
For multi-part keys, one can construct a WHERE expression such that its
|
|
226 |
list of intervals will be of combinatorial size. Here is an example:
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
227 |
|
228 |
(keypart1 IN (1,2, ..., n1)) AND
|
|
229 |
(keypart2 IN (1,2, ..., n2)) AND
|
|
1
by brian
clean slate |
230 |
(keypart3 IN (1,2, ..., n3))
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
231 |
|
1
by brian
clean slate |
232 |
For this WHERE clause the list of intervals will have n1*n2*n3 intervals
|
233 |
of form
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
234 |
|
1
by brian
clean slate |
235 |
(keypart1, keypart2, keypart3) = (k1, k2, k3), where 1 <= k{i} <= n{i}
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
236 |
|
1
by brian
clean slate |
237 |
SEL_ARG graph structure aims to reduce the amount of required space by
|
238 |
"sharing" the elementary intervals when possible (the pic at the
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
239 |
beginning of this comment has examples of such sharing). The sharing may
|
1
by brian
clean slate |
240 |
prevent combinatorial blowup:
|
241 |
||
242 |
There are WHERE clauses that have combinatorial-size interval lists but
|
|
243 |
will be represented by a compact SEL_ARG graph.
|
|
244 |
Example:
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
245 |
(keypartN IN (1,2, ..., n1)) AND
|
1
by brian
clean slate |
246 |
...
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
247 |
(keypart2 IN (1,2, ..., n2)) AND
|
1
by brian
clean slate |
248 |
(keypart1 IN (1,2, ..., n3))
|
249 |
||
250 |
but not in all cases:
|
|
251 |
||
252 |
- There are WHERE clauses that do have a compact SEL_ARG-graph
|
|
253 |
representation but get_mm_tree() and its callees will construct a
|
|
254 |
graph of combinatorial size.
|
|
255 |
Example:
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
256 |
(keypart1 IN (1,2, ..., n1)) AND
|
257 |
(keypart2 IN (1,2, ..., n2)) AND
|
|
1
by brian
clean slate |
258 |
...
|
259 |
(keypartN IN (1,2, ..., n3))
|
|
260 |
||
261 |
- There are WHERE clauses for which the minimal possible SEL_ARG graph
|
|
262 |
representation will have combinatorial size.
|
|
263 |
Example:
|
|
264 |
By induction: Let's take any interval on some keypart in the middle:
|
|
265 |
||
266 |
kp15=c0
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
267 |
|
1
by brian
clean slate |
268 |
Then let's AND it with this interval 'structure' from preceding and
|
269 |
following keyparts:
|
|
270 |
||
271 |
(kp14=c1 AND kp16=c3) OR keypart14=c2) (*)
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
272 |
|
1
by brian
clean slate |
273 |
We will obtain this SEL_ARG graph:
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
274 |
|
1
by brian
clean slate |
275 |
kp14 $ kp15 $ kp16
|
276 |
$ $
|
|
277 |
+---------+ $ +---------+ $ +---------+
|
|
278 |
| kp14=c1 |--$-->| kp15=c0 |--$-->| kp16=c3 |
|
|
279 |
+---------+ $ +---------+ $ +---------+
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
280 |
| $ $
|
281 |
+---------+ $ +---------+ $
|
|
282 |
| kp14=c2 |--$-->| kp15=c0 | $
|
|
283 |
+---------+ $ +---------+ $
|
|
1
by brian
clean slate |
284 |
$ $
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
285 |
|
1
by brian
clean slate |
286 |
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: |
287 |
that.
|
1
by brian
clean slate |
288 |
The induction step: AND the obtained expression with another "wrapping"
|
289 |
expression like (*).
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
290 |
When the process ends because of the limit on max. number of keyparts
|
1
by brian
clean slate |
291 |
we'll have:
|
292 |
||
293 |
WHERE clause length is O(3*#max_keyparts)
|
|
294 |
SEL_ARG graph size is O(2^(#max_keyparts/2))
|
|
295 |
||
296 |
(it is also possible to construct a case where instead of 2 in 2^n we
|
|
297 |
have a bigger constant, e.g. 4, and get a graph with 4^(31/2)= 2^31
|
|
298 |
nodes)
|
|
299 |
||
300 |
We avoid consuming too much memory by setting a limit on the number of
|
|
301 |
SEL_ARG object we can construct during one range analysis invocation.
|
|
302 |
*/
|
|
303 |
||
304 |
class SEL_ARG :public Sql_alloc |
|
305 |
{
|
|
306 |
public: |
|
206
by Brian Aker
Removed final uint dead types. |
307 |
uint8_t min_flag,max_flag,maybe_flag; |
308 |
uint8_t part; // Which key part |
|
309 |
uint8_t maybe_null; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
310 |
/*
|
1
by brian
clean slate |
311 |
Number of children of this element in the RB-tree, plus 1 for this
|
312 |
element itself.
|
|
313 |
*/
|
|
206
by Brian Aker
Removed final uint dead types. |
314 |
uint16_t elements; |
1
by brian
clean slate |
315 |
/*
|
316 |
Valid only for elements which are RB-tree roots: Number of times this
|
|
317 |
RB-tree is referred to (it is referred by SEL_ARG::next_key_part or by
|
|
318 |
SEL_TREE::keys[i] or by a temporary SEL_ARG* variable)
|
|
319 |
*/
|
|
320 |
ulong use_count; |
|
321 |
||
322 |
Field *field; |
|
481
by Brian Aker
Remove all of uchar. |
323 |
unsigned char *min_value,*max_value; // Pointer to range |
1
by brian
clean slate |
324 |
|
325 |
/*
|
|
326 |
eq_tree() requires that left == right == 0 if the type is MAYBE_KEY.
|
|
327 |
*/
|
|
328 |
SEL_ARG *left,*right; /* R-B tree children */ |
|
329 |
SEL_ARG *next,*prev; /* Links for bi-directional interval list */ |
|
330 |
SEL_ARG *parent; /* R-B tree parent */ |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
331 |
SEL_ARG *next_key_part; |
1
by brian
clean slate |
332 |
enum leaf_color { BLACK,RED } color; |
333 |
enum Type { IMPOSSIBLE, MAYBE, MAYBE_KEY, KEY_RANGE } type; |
|
334 |
||
335 |
enum { MAX_SEL_ARGS = 16000 }; |
|
336 |
||
337 |
SEL_ARG() {} |
|
338 |
SEL_ARG(SEL_ARG &); |
|
481
by Brian Aker
Remove all of uchar. |
339 |
SEL_ARG(Field *,const unsigned char *, const unsigned char *); |
340 |
SEL_ARG(Field *field, uint8_t part, unsigned char *min_value, unsigned char *max_value, |
|
206
by Brian Aker
Removed final uint dead types. |
341 |
uint8_t min_flag, uint8_t max_flag, uint8_t maybe_flag); |
1
by brian
clean slate |
342 |
SEL_ARG(enum Type type_arg) |
343 |
:min_flag(0),elements(1),use_count(1),left(0),right(0),next_key_part(0), |
|
344 |
color(BLACK), type(type_arg) |
|
345 |
{}
|
|
346 |
inline bool is_same(SEL_ARG *arg) |
|
347 |
{
|
|
348 |
if (type != arg->type || part != arg->part) |
|
349 |
return 0; |
|
350 |
if (type != KEY_RANGE) |
|
351 |
return 1; |
|
352 |
return cmp_min_to_min(arg) == 0 && cmp_max_to_max(arg) == 0; |
|
353 |
}
|
|
354 |
inline void merge_flags(SEL_ARG *arg) { maybe_flag|=arg->maybe_flag; } |
|
355 |
inline void maybe_smaller() { maybe_flag=1; } |
|
356 |
/* Return true iff it's a single-point null interval */
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
357 |
inline bool is_null_interval() { return maybe_null && max_value[0] == 1; } |
1
by brian
clean slate |
358 |
inline int cmp_min_to_min(SEL_ARG* arg) |
359 |
{
|
|
360 |
return sel_cmp(field,min_value, arg->min_value, min_flag, arg->min_flag); |
|
361 |
}
|
|
362 |
inline int cmp_min_to_max(SEL_ARG* arg) |
|
363 |
{
|
|
364 |
return sel_cmp(field,min_value, arg->max_value, min_flag, arg->max_flag); |
|
365 |
}
|
|
366 |
inline int cmp_max_to_max(SEL_ARG* arg) |
|
367 |
{
|
|
368 |
return sel_cmp(field,max_value, arg->max_value, max_flag, arg->max_flag); |
|
369 |
}
|
|
370 |
inline int cmp_max_to_min(SEL_ARG* arg) |
|
371 |
{
|
|
372 |
return sel_cmp(field,max_value, arg->min_value, max_flag, arg->min_flag); |
|
373 |
}
|
|
374 |
SEL_ARG *clone_and(SEL_ARG* arg) |
|
375 |
{ // Get overlapping range |
|
481
by Brian Aker
Remove all of uchar. |
376 |
unsigned char *new_min,*new_max; |
206
by Brian Aker
Removed final uint dead types. |
377 |
uint8_t flag_min,flag_max; |
1
by brian
clean slate |
378 |
if (cmp_min_to_min(arg) >= 0) |
379 |
{
|
|
380 |
new_min=min_value; flag_min=min_flag; |
|
381 |
}
|
|
382 |
else
|
|
383 |
{
|
|
384 |
new_min=arg->min_value; flag_min=arg->min_flag; /* purecov: deadcode */ |
|
385 |
}
|
|
386 |
if (cmp_max_to_max(arg) <= 0) |
|
387 |
{
|
|
388 |
new_max=max_value; flag_max=max_flag; |
|
389 |
}
|
|
390 |
else
|
|
391 |
{
|
|
392 |
new_max=arg->max_value; flag_max=arg->max_flag; |
|
393 |
}
|
|
394 |
return new SEL_ARG(field, part, new_min, new_max, flag_min, flag_max, |
|
395 |
test(maybe_flag && arg->maybe_flag)); |
|
396 |
}
|
|
397 |
SEL_ARG *clone_first(SEL_ARG *arg) |
|
398 |
{ // min <= X < arg->min |
|
399 |
return new SEL_ARG(field,part, min_value, arg->min_value, |
|
400 |
min_flag, arg->min_flag & NEAR_MIN ? 0 : NEAR_MAX, |
|
401 |
maybe_flag | arg->maybe_flag); |
|
402 |
}
|
|
403 |
SEL_ARG *clone_last(SEL_ARG *arg) |
|
404 |
{ // min <= X <= key_max |
|
405 |
return new SEL_ARG(field, part, min_value, arg->max_value, |
|
406 |
min_flag, arg->max_flag, maybe_flag | arg->maybe_flag); |
|
407 |
}
|
|
408 |
SEL_ARG *clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent, SEL_ARG **next); |
|
409 |
||
410 |
bool copy_min(SEL_ARG* arg) |
|
411 |
{ // Get overlapping range |
|
412 |
if (cmp_min_to_min(arg) > 0) |
|
413 |
{
|
|
414 |
min_value=arg->min_value; min_flag=arg->min_flag; |
|
415 |
if ((max_flag & (NO_MAX_RANGE | NO_MIN_RANGE)) == |
|
416 |
(NO_MAX_RANGE | NO_MIN_RANGE)) |
|
417 |
return 1; // Full range |
|
418 |
}
|
|
419 |
maybe_flag|=arg->maybe_flag; |
|
420 |
return 0; |
|
421 |
}
|
|
422 |
bool copy_max(SEL_ARG* arg) |
|
423 |
{ // Get overlapping range |
|
424 |
if (cmp_max_to_max(arg) <= 0) |
|
425 |
{
|
|
426 |
max_value=arg->max_value; max_flag=arg->max_flag; |
|
427 |
if ((max_flag & (NO_MAX_RANGE | NO_MIN_RANGE)) == |
|
428 |
(NO_MAX_RANGE | NO_MIN_RANGE)) |
|
429 |
return 1; // Full range |
|
430 |
}
|
|
431 |
maybe_flag|=arg->maybe_flag; |
|
432 |
return 0; |
|
433 |
}
|
|
434 |
||
435 |
void copy_min_to_min(SEL_ARG *arg) |
|
436 |
{
|
|
437 |
min_value=arg->min_value; min_flag=arg->min_flag; |
|
438 |
}
|
|
439 |
void copy_min_to_max(SEL_ARG *arg) |
|
440 |
{
|
|
441 |
max_value=arg->min_value; |
|
442 |
max_flag=arg->min_flag & NEAR_MIN ? 0 : NEAR_MAX; |
|
443 |
}
|
|
444 |
void copy_max_to_min(SEL_ARG *arg) |
|
445 |
{
|
|
446 |
min_value=arg->max_value; |
|
447 |
min_flag=arg->max_flag & NEAR_MAX ? 0 : NEAR_MIN; |
|
448 |
}
|
|
449 |
/* returns a number of keypart values (0 or 1) appended to the key buffer */
|
|
482
by Brian Aker
Remove uint. |
450 |
int store_min(uint32_t length, unsigned char **min_key,uint32_t min_key_flag) |
1
by brian
clean slate |
451 |
{
|
452 |
/* "(kp1 > c1) AND (kp2 OP c2) AND ..." -> (kp1 > c1) */
|
|
453 |
if ((!(min_flag & NO_MIN_RANGE) && |
|
454 |
!(min_key_flag & (NO_MIN_RANGE | NEAR_MIN)))) |
|
455 |
{
|
|
456 |
if (maybe_null && *min_value) |
|
457 |
{
|
|
458 |
**min_key=1; |
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
459 |
memset(*min_key+1, 0, length-1); |
1
by brian
clean slate |
460 |
}
|
461 |
else
|
|
462 |
memcpy(*min_key,min_value,length); |
|
463 |
(*min_key)+= length; |
|
464 |
return 1; |
|
465 |
}
|
|
466 |
return 0; |
|
467 |
}
|
|
468 |
/* returns a number of keypart values (0 or 1) appended to the key buffer */
|
|
482
by Brian Aker
Remove uint. |
469 |
int store_max(uint32_t length, unsigned char **max_key, uint32_t max_key_flag) |
1
by brian
clean slate |
470 |
{
|
471 |
if (!(max_flag & NO_MAX_RANGE) && |
|
472 |
!(max_key_flag & (NO_MAX_RANGE | NEAR_MAX))) |
|
473 |
{
|
|
474 |
if (maybe_null && *max_value) |
|
475 |
{
|
|
476 |
**max_key=1; |
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
477 |
memset(*max_key+1, 0, length-1); |
1
by brian
clean slate |
478 |
}
|
479 |
else
|
|
480 |
memcpy(*max_key,max_value,length); |
|
481 |
(*max_key)+= length; |
|
482 |
return 1; |
|
483 |
}
|
|
484 |
return 0; |
|
485 |
}
|
|
486 |
||
487 |
/* returns a number of keypart values appended to the key buffer */
|
|
482
by Brian Aker
Remove uint. |
488 |
int store_min_key(KEY_PART *key, unsigned char **range_key, uint32_t *range_key_flag) |
1
by brian
clean slate |
489 |
{
|
490 |
SEL_ARG *key_tree= first(); |
|
482
by Brian Aker
Remove uint. |
491 |
uint32_t res= key_tree->store_min(key[key_tree->part].store_length, |
1
by brian
clean slate |
492 |
range_key, *range_key_flag); |
493 |
*range_key_flag|= key_tree->min_flag; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
494 |
|
1
by brian
clean slate |
495 |
if (key_tree->next_key_part && |
496 |
key_tree->next_key_part->part == key_tree->part+1 && |
|
497 |
!(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN)) && |
|
498 |
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) |
|
499 |
res+= key_tree->next_key_part->store_min_key(key, range_key, |
|
500 |
range_key_flag); |
|
501 |
return res; |
|
502 |
}
|
|
503 |
||
504 |
/* returns a number of keypart values appended to the key buffer */
|
|
482
by Brian Aker
Remove uint. |
505 |
int store_max_key(KEY_PART *key, unsigned char **range_key, uint32_t *range_key_flag) |
1
by brian
clean slate |
506 |
{
|
507 |
SEL_ARG *key_tree= last(); |
|
482
by Brian Aker
Remove uint. |
508 |
uint32_t res=key_tree->store_max(key[key_tree->part].store_length, |
1
by brian
clean slate |
509 |
range_key, *range_key_flag); |
510 |
(*range_key_flag)|= key_tree->max_flag; |
|
511 |
if (key_tree->next_key_part && |
|
512 |
key_tree->next_key_part->part == key_tree->part+1 && |
|
513 |
!(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX)) && |
|
514 |
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) |
|
515 |
res+= key_tree->next_key_part->store_max_key(key, range_key, |
|
516 |
range_key_flag); |
|
517 |
return res; |
|
518 |
}
|
|
519 |
||
520 |
SEL_ARG *insert(SEL_ARG *key); |
|
521 |
SEL_ARG *tree_delete(SEL_ARG *key); |
|
522 |
SEL_ARG *find_range(SEL_ARG *key); |
|
523 |
SEL_ARG *rb_insert(SEL_ARG *leaf); |
|
524 |
friend SEL_ARG *rb_delete_fixup(SEL_ARG *root,SEL_ARG *key, SEL_ARG *par); |
|
525 |
#ifdef EXTRA_DEBUG
|
|
526 |
friend int test_rb_tree(SEL_ARG *element,SEL_ARG *parent); |
|
527 |
void test_use_count(SEL_ARG *root); |
|
528 |
#endif
|
|
529 |
SEL_ARG *first(); |
|
530 |
SEL_ARG *last(); |
|
531 |
void make_root(); |
|
532 |
inline bool simple_key() |
|
533 |
{
|
|
534 |
return !next_key_part && elements == 1; |
|
535 |
}
|
|
536 |
void increment_use_count(long count) |
|
537 |
{
|
|
538 |
if (next_key_part) |
|
539 |
{
|
|
540 |
next_key_part->use_count+=count; |
|
541 |
count*= (next_key_part->use_count-count); |
|
542 |
for (SEL_ARG *pos=next_key_part->first(); pos ; pos=pos->next) |
|
543 |
if (pos->next_key_part) |
|
544 |
pos->increment_use_count(count); |
|
545 |
}
|
|
546 |
}
|
|
547 |
void free_tree() |
|
548 |
{
|
|
549 |
for (SEL_ARG *pos=first(); pos ; pos=pos->next) |
|
550 |
if (pos->next_key_part) |
|
551 |
{
|
|
552 |
pos->next_key_part->use_count--; |
|
553 |
pos->next_key_part->free_tree(); |
|
554 |
}
|
|
555 |
}
|
|
556 |
||
557 |
inline SEL_ARG **parent_ptr() |
|
558 |
{
|
|
559 |
return parent->left == this ? &parent->left : &parent->right; |
|
560 |
}
|
|
561 |
||
562 |
||
563 |
/*
|
|
564 |
Check if this SEL_ARG object represents a single-point interval
|
|
565 |
||
566 |
SYNOPSIS
|
|
567 |
is_singlepoint()
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
568 |
|
1
by brian
clean slate |
569 |
DESCRIPTION
|
570 |
Check if this SEL_ARG object (not tree) represents a single-point
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
571 |
interval, i.e. if it represents a "keypart = const" or
|
1
by brian
clean slate |
572 |
"keypart IS NULL".
|
573 |
||
574 |
RETURN
|
|
55
by brian
Update for using real bool types. |
575 |
true This SEL_ARG object represents a singlepoint interval
|
576 |
false Otherwise
|
|
1
by brian
clean slate |
577 |
*/
|
578 |
||
579 |
bool is_singlepoint() |
|
580 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
581 |
/*
|
582 |
Check for NEAR_MIN ("strictly less") and NO_MIN_RANGE (-inf < field)
|
|
1
by brian
clean slate |
583 |
flags, and the same for right edge.
|
584 |
*/
|
|
585 |
if (min_flag || max_flag) |
|
55
by brian
Update for using real bool types. |
586 |
return false; |
481
by Brian Aker
Remove all of uchar. |
587 |
unsigned char *min_val= min_value; |
588 |
unsigned char *max_val= max_value; |
|
1
by brian
clean slate |
589 |
|
590 |
if (maybe_null) |
|
591 |
{
|
|
592 |
/* First byte is a NULL value indicator */
|
|
593 |
if (*min_val != *max_val) |
|
55
by brian
Update for using real bool types. |
594 |
return false; |
1
by brian
clean slate |
595 |
|
596 |
if (*min_val) |
|
55
by brian
Update for using real bool types. |
597 |
return true; /* This "x IS NULL" */ |
1
by brian
clean slate |
598 |
min_val++; |
599 |
max_val++; |
|
600 |
}
|
|
601 |
return !field->key_cmp(min_val, max_val); |
|
602 |
}
|
|
603 |
SEL_ARG *clone_tree(RANGE_OPT_PARAM *param); |
|
604 |
};
|
|
605 |
||
606 |
class SEL_IMERGE; |
|
607 |
||
608 |
||
609 |
class SEL_TREE :public Sql_alloc |
|
610 |
{
|
|
611 |
public: |
|
612 |
/*
|
|
613 |
Starting an effort to document this field:
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
614 |
(for some i, keys[i]->type == SEL_ARG::IMPOSSIBLE) =>
|
1
by brian
clean slate |
615 |
(type == SEL_TREE::IMPOSSIBLE)
|
616 |
*/
|
|
617 |
enum Type { IMPOSSIBLE, ALWAYS, MAYBE, KEY, KEY_SMALLER } type; |
|
618 |
SEL_TREE(enum Type type_arg) :type(type_arg) {} |
|
619 |
SEL_TREE() :type(KEY) |
|
620 |
{
|
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
621 |
keys_map.reset(); |
212.6.6
by Mats Kindahl
Removing redundant use of casts in drizzled/ for memcmp(), memcpy(), memset(), and memmove(). |
622 |
memset(keys, 0, sizeof(keys)); |
1
by brian
clean slate |
623 |
}
|
624 |
/*
|
|
625 |
Note: there may exist SEL_TREE objects with sel_tree->type=KEY and
|
|
626 |
keys[i]=0 for all i. (SergeyP: it is not clear whether there is any
|
|
627 |
merit in range analyzer functions (e.g. get_mm_parts) returning a
|
|
628 |
pointer to such SEL_TREE instead of NULL)
|
|
629 |
*/
|
|
630 |
SEL_ARG *keys[MAX_KEY]; |
|
631 |
key_map keys_map; /* bitmask of non-NULL elements in keys */ |
|
632 |
||
633 |
/*
|
|
634 |
Possible ways to read rows using index_merge. The list is non-empty only
|
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
635 |
if type==KEY. Currently can be non empty only if keys_map.none().
|
1
by brian
clean slate |
636 |
*/
|
637 |
List<SEL_IMERGE> merges; |
|
638 |
||
639 |
/* The members below are filled/used only after get_mm_tree is done */
|
|
640 |
key_map ror_scans_map; /* bitmask of ROR scan-able elements in keys */ |
|
482
by Brian Aker
Remove uint. |
641 |
uint32_t n_ror_scans; /* number of set bits in ror_scans_map */ |
1
by brian
clean slate |
642 |
|
643 |
struct st_ror_scan_info **ror_scans; /* list of ROR key scans */ |
|
644 |
struct st_ror_scan_info **ror_scans_end; /* last ROR scan */ |
|
645 |
/* Note that #records for each key scan is stored in table->quick_rows */
|
|
646 |
};
|
|
647 |
||
648 |
class RANGE_OPT_PARAM |
|
649 |
{
|
|
650 |
public: |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
651 |
Session *session; /* Current thread handle */ |
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
652 |
Table *table; /* Table being analyzed */ |
1
by brian
clean slate |
653 |
COND *cond; /* Used inside get_mm_tree(). */ |
654 |
table_map prev_tables; |
|
655 |
table_map read_tables; |
|
656 |
table_map current_table; /* Bit of the table being analyzed */ |
|
657 |
||
658 |
/* Array of parts of all keys for which range analysis is performed */
|
|
659 |
KEY_PART *key_parts; |
|
660 |
KEY_PART *key_parts_end; |
|
661 |
MEM_ROOT *mem_root; /* Memory that will be freed when range analysis completes */ |
|
662 |
MEM_ROOT *old_root; /* Memory that will last until the query end */ |
|
663 |
/*
|
|
664 |
Number of indexes used in range analysis (In SEL_TREE::keys only first
|
|
665 |
#keys elements are not empty)
|
|
666 |
*/
|
|
482
by Brian Aker
Remove uint. |
667 |
uint32_t keys; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
668 |
|
669 |
/*
|
|
1
by brian
clean slate |
670 |
If true, the index descriptions describe real indexes (and it is ok to
|
671 |
call field->optimize_range(real_keynr[...], ...).
|
|
672 |
Otherwise index description describes fake indexes.
|
|
673 |
*/
|
|
674 |
bool using_real_indexes; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
675 |
|
1
by brian
clean slate |
676 |
bool remove_jump_scans; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
677 |
|
1
by brian
clean slate |
678 |
/*
|
679 |
used_key_no -> table_key_no translation table. Only makes sense if
|
|
55
by brian
Update for using real bool types. |
680 |
using_real_indexes==true
|
1
by brian
clean slate |
681 |
*/
|
482
by Brian Aker
Remove uint. |
682 |
uint32_t real_keynr[MAX_KEY]; |
1
by brian
clean slate |
683 |
/* Number of SEL_ARG objects allocated by SEL_ARG::clone_tree operations */
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
684 |
uint32_t alloced_sel_args; |
1
by brian
clean slate |
685 |
bool force_default_mrr; |
686 |
};
|
|
687 |
||
688 |
class PARAM : public RANGE_OPT_PARAM |
|
689 |
{
|
|
690 |
public: |
|
691 |
KEY_PART *key[MAX_KEY]; /* First key parts of keys used in the query */ |
|
152
by Brian Aker
longlong replacement |
692 |
int64_t baseflag; |
482
by Brian Aker
Remove uint. |
693 |
uint32_t max_key_part; |
1
by brian
clean slate |
694 |
/* Number of ranges in the last checked tree->key */
|
482
by Brian Aker
Remove uint. |
695 |
uint32_t range_count; |
481
by Brian Aker
Remove all of uchar. |
696 |
unsigned char min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH], |
1
by brian
clean slate |
697 |
max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; |
698 |
bool quick; // Don't calulate possible keys |
|
699 |
||
482
by Brian Aker
Remove uint. |
700 |
uint32_t fields_bitmap_size; |
1005.2.3
by Monty Taylor
Further reversion of P. |
701 |
MY_BITMAP needed_fields; /* bitmask of fields needed by the query */ |
702 |
MY_BITMAP tmp_covered_fields; |
|
1
by brian
clean slate |
703 |
|
704 |
key_map *needed_reg; /* ptr to SQL_SELECT::needed_reg */ |
|
705 |
||
482
by Brian Aker
Remove uint. |
706 |
uint32_t *imerge_cost_buff; /* buffer for index_merge cost estimates */ |
707 |
uint32_t imerge_cost_buff_size; /* size of the buffer */ |
|
1
by brian
clean slate |
708 |
|
55
by brian
Update for using real bool types. |
709 |
/* true if last checked tree->key can be used for ROR-scan */
|
1
by brian
clean slate |
710 |
bool is_ror_scan; |
711 |
/* Number of ranges in the last checked tree->key */
|
|
482
by Brian Aker
Remove uint. |
712 |
uint32_t n_ranges; |
1
by brian
clean slate |
713 |
};
|
714 |
||
715 |
class TABLE_READ_PLAN; |
|
716 |
class TRP_RANGE; |
|
717 |
class TRP_ROR_INTERSECT; |
|
718 |
class TRP_ROR_UNION; |
|
719 |
class TRP_ROR_INDEX_MERGE; |
|
720 |
class TRP_GROUP_MIN_MAX; |
|
721 |
||
722 |
struct st_ror_scan_info; |
|
723 |
||
724 |
static SEL_TREE * get_mm_parts(RANGE_OPT_PARAM *param,COND *cond_func,Field *field, |
|
725 |
Item_func::Functype type,Item *value, |
|
726 |
Item_result cmp_type); |
|
727 |
static SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param,COND *cond_func,Field *field, |
|
728 |
KEY_PART *key_part, |
|
729 |
Item_func::Functype type,Item *value); |
|
730 |
static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond); |
|
731 |
||
482
by Brian Aker
Remove uint. |
732 |
static bool is_key_scan_ror(PARAM *param, uint32_t keynr, uint8_t nparts); |
733 |
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: |
734 |
SEL_ARG *tree, bool update_tbl_stats, |
482
by Brian Aker
Remove uint. |
735 |
uint32_t *mrr_flags, uint32_t *bufsize, |
1
by brian
clean slate |
736 |
COST_VECT *cost); |
737 |
//bool update_tbl_stats);
|
|
482
by Brian Aker
Remove uint. |
738 |
/*static ha_rows check_quick_keys(PARAM *param,uint32_t index,SEL_ARG *key_tree,
|
739 |
unsigned char *min_key, uint32_t min_key_flag, int,
|
|
740 |
unsigned char *max_key, uint32_t max_key_flag, int);
|
|
1
by brian
clean slate |
741 |
*/
|
742 |
||
482
by Brian Aker
Remove uint. |
743 |
QUICK_RANGE_SELECT *get_quick_select(PARAM *param,uint32_t index, |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
744 |
SEL_ARG *key_tree, uint32_t mrr_flags, |
482
by Brian Aker
Remove uint. |
745 |
uint32_t mrr_buf_size, MEM_ROOT *alloc); |
1
by brian
clean slate |
746 |
static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, |
747 |
bool index_read_must_be_used, |
|
748 |
bool update_tbl_stats, |
|
749 |
double read_time); |
|
750 |
static
|
|
751 |
TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree, |
|
752 |
double read_time, |
|
753 |
bool *are_all_covering); |
|
754 |
static
|
|
755 |
TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param, |
|
756 |
SEL_TREE *tree, |
|
757 |
double read_time); |
|
758 |
static
|
|
759 |
TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, |
|
760 |
double read_time); |
|
761 |
static
|
|
762 |
TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree); |
|
763 |
||
764 |
static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map, |
|
765 |
const char *msg); |
|
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
766 |
static void print_ror_scans_arr(Table *table, const char *msg, |
1
by brian
clean slate |
767 |
struct st_ror_scan_info **start, |
768 |
struct st_ror_scan_info **end); |
|
769 |
||
770 |
static SEL_TREE *tree_and(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2); |
|
771 |
static SEL_TREE *tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2); |
|
772 |
static SEL_ARG *sel_add(SEL_ARG *key1,SEL_ARG *key2); |
|
773 |
static SEL_ARG *key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2); |
|
774 |
static SEL_ARG *key_and(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, |
|
482
by Brian Aker
Remove uint. |
775 |
uint32_t clone_flag); |
1
by brian
clean slate |
776 |
static bool get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1); |
777 |
bool get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, |
|
482
by Brian Aker
Remove uint. |
778 |
SEL_ARG *key_tree, unsigned char *min_key,uint32_t min_key_flag, |
779 |
unsigned char *max_key,uint32_t max_key_flag); |
|
1
by brian
clean slate |
780 |
static bool eq_tree(SEL_ARG* a,SEL_ARG *b); |
781 |
||
782 |
static SEL_ARG null_element(SEL_ARG::IMPOSSIBLE); |
|
481
by Brian Aker
Remove all of uchar. |
783 |
static bool null_part_in_key(KEY_PART *key_part, const unsigned char *key, |
482
by Brian Aker
Remove uint. |
784 |
uint32_t length); |
1
by brian
clean slate |
785 |
bool sel_trees_can_be_ored(SEL_TREE *tree1, SEL_TREE *tree2, RANGE_OPT_PARAM* param); |
786 |
||
787 |
||
788 |
/*
|
|
789 |
SEL_IMERGE is a list of possible ways to do index merge, i.e. it is
|
|
790 |
a condition in the following form:
|
|
791 |
(t_1||t_2||...||t_N) && (next)
|
|
792 |
||
793 |
where all t_i are SEL_TREEs, next is another SEL_IMERGE and no pair
|
|
794 |
(t_i,t_j) contains SEL_ARGS for the same index.
|
|
795 |
||
796 |
SEL_TREE contained in SEL_IMERGE always has merges=NULL.
|
|
797 |
||
798 |
This class relies on memory manager to do the cleanup.
|
|
799 |
*/
|
|
800 |
||
801 |
class SEL_IMERGE : public Sql_alloc |
|
802 |
{
|
|
803 |
enum { PREALLOCED_TREES= 10}; |
|
804 |
public: |
|
805 |
SEL_TREE *trees_prealloced[PREALLOCED_TREES]; |
|
806 |
SEL_TREE **trees; /* trees used to do index_merge */ |
|
807 |
SEL_TREE **trees_next; /* last of these trees */ |
|
808 |
SEL_TREE **trees_end; /* end of allocated space */ |
|
809 |
||
810 |
SEL_ARG ***best_keys; /* best keys to read in SEL_TREEs */ |
|
811 |
||
812 |
SEL_IMERGE() : |
|
813 |
trees(&trees_prealloced[0]), |
|
814 |
trees_next(trees), |
|
815 |
trees_end(trees + PREALLOCED_TREES) |
|
816 |
{}
|
|
817 |
int or_sel_tree(RANGE_OPT_PARAM *param, SEL_TREE *tree); |
|
818 |
int or_sel_tree_with_checks(RANGE_OPT_PARAM *param, SEL_TREE *new_tree); |
|
819 |
int or_sel_imerge_with_checks(RANGE_OPT_PARAM *param, SEL_IMERGE* imerge); |
|
820 |
};
|
|
821 |
||
822 |
||
823 |
/*
|
|
824 |
Add SEL_TREE to this index_merge without any checks,
|
|
825 |
||
826 |
NOTES
|
|
827 |
This function implements the following:
|
|
828 |
(x_1||...||x_N) || t = (x_1||...||x_N||t), where x_i, t are SEL_TREEs
|
|
829 |
||
830 |
RETURN
|
|
831 |
0 - OK
|
|
832 |
-1 - Out of memory.
|
|
833 |
*/
|
|
834 |
||
835 |
int SEL_IMERGE::or_sel_tree(RANGE_OPT_PARAM *param, SEL_TREE *tree) |
|
836 |
{
|
|
837 |
if (trees_next == trees_end) |
|
838 |
{
|
|
839 |
const int realloc_ratio= 2; /* Double size for next round */ |
|
482
by Brian Aker
Remove uint. |
840 |
uint32_t old_elements= (trees_end - trees); |
841 |
uint32_t old_size= sizeof(SEL_TREE**) * old_elements; |
|
842 |
uint32_t new_size= old_size * realloc_ratio; |
|
1
by brian
clean slate |
843 |
SEL_TREE **new_trees; |
844 |
if (!(new_trees= (SEL_TREE**)alloc_root(param->mem_root, new_size))) |
|
845 |
return -1; |
|
846 |
memcpy(new_trees, trees, old_size); |
|
847 |
trees= new_trees; |
|
848 |
trees_next= trees + old_elements; |
|
849 |
trees_end= trees + old_elements * realloc_ratio; |
|
850 |
}
|
|
851 |
*(trees_next++)= tree; |
|
852 |
return 0; |
|
853 |
}
|
|
854 |
||
855 |
||
856 |
/*
|
|
857 |
Perform OR operation on this SEL_IMERGE and supplied SEL_TREE new_tree,
|
|
858 |
combining new_tree with one of the trees in this SEL_IMERGE if they both
|
|
859 |
have SEL_ARGs for the same key.
|
|
860 |
||
861 |
SYNOPSIS
|
|
862 |
or_sel_tree_with_checks()
|
|
863 |
param PARAM from SQL_SELECT::test_quick_select
|
|
864 |
new_tree SEL_TREE with type KEY or KEY_SMALLER.
|
|
865 |
||
866 |
NOTES
|
|
867 |
This does the following:
|
|
868 |
(t_1||...||t_k)||new_tree =
|
|
869 |
either
|
|
870 |
= (t_1||...||t_k||new_tree)
|
|
871 |
or
|
|
872 |
= (t_1||....||(t_j|| new_tree)||...||t_k),
|
|
873 |
||
874 |
where t_i, y are SEL_TREEs.
|
|
875 |
new_tree is combined with the first t_j it has a SEL_ARG on common
|
|
876 |
key with. As a consequence of this, choice of keys to do index_merge
|
|
877 |
read may depend on the order of conditions in WHERE part of the query.
|
|
878 |
||
879 |
RETURN
|
|
880 |
0 OK
|
|
881 |
1 One of the trees was combined with new_tree to SEL_TREE::ALWAYS,
|
|
882 |
and (*this) should be discarded.
|
|
883 |
-1 An error occurred.
|
|
884 |
*/
|
|
885 |
||
886 |
int SEL_IMERGE::or_sel_tree_with_checks(RANGE_OPT_PARAM *param, SEL_TREE *new_tree) |
|
887 |
{
|
|
888 |
for (SEL_TREE** tree = trees; |
|
889 |
tree != trees_next; |
|
890 |
tree++) |
|
891 |
{
|
|
892 |
if (sel_trees_can_be_ored(*tree, new_tree, param)) |
|
893 |
{
|
|
894 |
*tree = tree_or(param, *tree, new_tree); |
|
895 |
if (!*tree) |
|
896 |
return 1; |
|
897 |
if (((*tree)->type == SEL_TREE::MAYBE) || |
|
898 |
((*tree)->type == SEL_TREE::ALWAYS)) |
|
899 |
return 1; |
|
900 |
/* SEL_TREE::IMPOSSIBLE is impossible here */
|
|
901 |
return 0; |
|
902 |
}
|
|
903 |
}
|
|
904 |
||
905 |
/* New tree cannot be combined with any of existing trees. */
|
|
906 |
return or_sel_tree(param, new_tree); |
|
907 |
}
|
|
908 |
||
909 |
||
910 |
/*
|
|
911 |
Perform OR operation on this index_merge and supplied index_merge list.
|
|
912 |
||
913 |
RETURN
|
|
914 |
0 - OK
|
|
55
by brian
Update for using real bool types. |
915 |
1 - One of conditions in result is always true and this SEL_IMERGE
|
1
by brian
clean slate |
916 |
should be discarded.
|
917 |
-1 - An error occurred
|
|
918 |
*/
|
|
919 |
||
920 |
int SEL_IMERGE::or_sel_imerge_with_checks(RANGE_OPT_PARAM *param, SEL_IMERGE* imerge) |
|
921 |
{
|
|
922 |
for (SEL_TREE** tree= imerge->trees; |
|
923 |
tree != imerge->trees_next; |
|
924 |
tree++) |
|
925 |
{
|
|
926 |
if (or_sel_tree_with_checks(param, *tree)) |
|
927 |
return 1; |
|
928 |
}
|
|
929 |
return 0; |
|
930 |
}
|
|
931 |
||
932 |
||
933 |
/*
|
|
934 |
Perform AND operation on two index_merge lists and store result in *im1.
|
|
935 |
*/
|
|
936 |
||
937 |
inline void imerge_list_and_list(List<SEL_IMERGE> *im1, List<SEL_IMERGE> *im2) |
|
938 |
{
|
|
939 |
im1->concat(im2); |
|
940 |
}
|
|
941 |
||
942 |
||
943 |
/*
|
|
944 |
Perform OR operation on 2 index_merge lists, storing result in first list.
|
|
945 |
||
946 |
NOTES
|
|
947 |
The following conversion is implemented:
|
|
948 |
(a_1 &&...&& a_N)||(b_1 &&...&& b_K) = AND_i,j(a_i || b_j) =>
|
|
949 |
=> (a_1||b_1).
|
|
950 |
||
951 |
i.e. all conjuncts except the first one are currently dropped.
|
|
952 |
This is done to avoid producing N*K ways to do index_merge.
|
|
953 |
||
55
by brian
Update for using real bool types. |
954 |
If (a_1||b_1) produce a condition that is always true, NULL is returned
|
1
by brian
clean slate |
955 |
and index_merge is discarded (while it is actually possible to try
|
956 |
harder).
|
|
957 |
||
958 |
As a consequence of this, choice of keys to do index_merge read may depend
|
|
959 |
on the order of conditions in WHERE part of the query.
|
|
960 |
||
961 |
RETURN
|
|
962 |
0 OK, result is stored in *im1
|
|
963 |
other Error, both passed lists are unusable
|
|
964 |
*/
|
|
965 |
||
966 |
int imerge_list_or_list(RANGE_OPT_PARAM *param, |
|
967 |
List<SEL_IMERGE> *im1, |
|
968 |
List<SEL_IMERGE> *im2) |
|
969 |
{
|
|
970 |
SEL_IMERGE *imerge= im1->head(); |
|
971 |
im1->empty(); |
|
972 |
im1->push_back(imerge); |
|
973 |
||
974 |
return imerge->or_sel_imerge_with_checks(param, im2->head()); |
|
975 |
}
|
|
976 |
||
977 |
||
978 |
/*
|
|
979 |
Perform OR operation on index_merge list and key tree.
|
|
980 |
||
981 |
RETURN
|
|
982 |
0 OK, result is stored in *im1.
|
|
983 |
other Error
|
|
984 |
*/
|
|
985 |
||
986 |
int imerge_list_or_tree(RANGE_OPT_PARAM *param, |
|
987 |
List<SEL_IMERGE> *im1, |
|
988 |
SEL_TREE *tree) |
|
989 |
{
|
|
990 |
SEL_IMERGE *imerge; |
|
991 |
List_iterator<SEL_IMERGE> it(*im1); |
|
992 |
while ((imerge= it++)) |
|
993 |
{
|
|
994 |
if (imerge->or_sel_tree_with_checks(param, tree)) |
|
995 |
it.remove(); |
|
996 |
}
|
|
997 |
return im1->is_empty(); |
|
998 |
}
|
|
999 |
||
1000 |
||
1001 |
/***************************************************************************
|
|
1002 |
** Basic functions for SQL_SELECT and QUICK_RANGE_SELECT
|
|
1003 |
***************************************************************************/
|
|
1004 |
||
1005 |
/* make a select from mysql info
|
|
1006 |
Error is set as following:
|
|
1007 |
0 = ok
|
|
1008 |
1 = Got some error (out of memory?)
|
|
1009 |
*/
|
|
1010 |
||
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
1011 |
SQL_SELECT *make_select(Table *head, table_map const_tables, |
1
by brian
clean slate |
1012 |
table_map read_tables, COND *conds, |
1013 |
bool allow_null_cond, |
|
1014 |
int *error) |
|
1015 |
{
|
|
1016 |
SQL_SELECT *select; |
|
1017 |
||
1018 |
*error=0; |
|
1019 |
||
1020 |
if (!conds && !allow_null_cond) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1021 |
return 0; |
1
by brian
clean slate |
1022 |
if (!(select= new SQL_SELECT)) |
1023 |
{
|
|
1024 |
*error= 1; // out of memory |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1025 |
return 0; /* purecov: inspected */ |
1
by brian
clean slate |
1026 |
}
|
1027 |
select->read_tables=read_tables; |
|
1028 |
select->const_tables=const_tables; |
|
1029 |
select->head=head; |
|
1030 |
select->cond=conds; |
|
1031 |
||
1032 |
if (head->sort.io_cache) |
|
1033 |
{
|
|
1034 |
select->file= *head->sort.io_cache; |
|
1035 |
select->records=(ha_rows) (select->file.end_of_file/ |
|
1036 |
head->file->ref_length); |
|
760.1.3
by Kristian Nielsen
Fix IO_CACHE memory handling, if we allocate with new, we must not |
1037 |
delete head->sort.io_cache; |
1
by brian
clean slate |
1038 |
head->sort.io_cache=0; |
1039 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1040 |
return(select); |
1
by brian
clean slate |
1041 |
}
|
1042 |
||
1043 |
||
1044 |
SQL_SELECT::SQL_SELECT() :quick(0),cond(0),free_cond(0) |
|
1045 |
{
|
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
1046 |
quick_keys.reset(); |
1047 |
needed_reg.reset(); |
|
1
by brian
clean slate |
1048 |
my_b_clear(&file); |
1049 |
}
|
|
1050 |
||
1051 |
||
1052 |
void SQL_SELECT::cleanup() |
|
1053 |
{
|
|
1054 |
delete quick; |
|
1055 |
quick= 0; |
|
1056 |
if (free_cond) |
|
1057 |
{
|
|
1058 |
free_cond=0; |
|
1059 |
delete cond; |
|
1060 |
cond= 0; |
|
1061 |
}
|
|
1062 |
close_cached_file(&file); |
|
1063 |
}
|
|
1064 |
||
1065 |
||
1066 |
SQL_SELECT::~SQL_SELECT() |
|
1067 |
{
|
|
1068 |
cleanup(); |
|
1069 |
}
|
|
1070 |
||
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. |
1071 |
|
1072 |
bool SQL_SELECT::check_quick(Session *session, bool force_quick_range, |
|
1073 |
ha_rows limit) |
|
1074 |
{
|
|
1075 |
key_map tmp; |
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
1076 |
tmp.set(); |
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. |
1077 |
return test_quick_select(session, tmp, 0, limit, |
1078 |
force_quick_range, false) < 0; |
|
1079 |
}
|
|
1080 |
||
1081 |
||
1082 |
bool SQL_SELECT::skip_record() |
|
1083 |
{
|
|
1084 |
return cond ? cond->val_int() == 0 : 0; |
|
1085 |
}
|
|
1086 |
||
1087 |
||
1
by brian
clean slate |
1088 |
QUICK_SELECT_I::QUICK_SELECT_I() |
1089 |
:max_used_key_length(0), |
|
1090 |
used_key_parts(0) |
|
1091 |
{}
|
|
1092 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
1093 |
QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(Session *session, Table *table, uint32_t key_nr, |
1005.2.3
by Monty Taylor
Further reversion of P. |
1094 |
bool no_alloc, MEM_ROOT *parent_alloc, |
1095 |
bool *create_error) |
|
1
by brian
clean slate |
1096 |
:free_file(0),cur_range(NULL),last_range(0),dont_free(0) |
1097 |
{
|
|
1005.2.3
by Monty Taylor
Further reversion of P. |
1098 |
my_bitmap_map *bitmap; |
1099 |
||
1
by brian
clean slate |
1100 |
in_ror_merged_scan= 0; |
1101 |
sorted= 0; |
|
1102 |
index= key_nr; |
|
1103 |
head= table; |
|
1104 |
key_part_info= head->key_info[index].key_part; |
|
1105 |
my_init_dynamic_array(&ranges, sizeof(QUICK_RANGE*), 16, 16); |
|
1106 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
1107 |
/* 'session' is not accessible in QUICK_RANGE_SELECT::reset(). */
|
1108 |
mrr_buf_size= session->variables.read_rnd_buff_size; |
|
1
by brian
clean slate |
1109 |
mrr_buf_desc= NULL; |
1110 |
||
1111 |
if (!no_alloc && !parent_alloc) |
|
1112 |
{
|
|
1113 |
// Allocates everything through the internal memroot
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
1114 |
init_sql_alloc(&alloc, session->variables.range_alloc_block_size, 0); |
1115 |
session->mem_root= &alloc; |
|
1
by brian
clean slate |
1116 |
}
|
1117 |
else
|
|
212.6.6
by Mats Kindahl
Removing redundant use of casts in drizzled/ for memcmp(), memcpy(), memset(), and memmove(). |
1118 |
memset(&alloc, 0, sizeof(alloc)); |
1
by brian
clean slate |
1119 |
file= head->file; |
1120 |
record= head->record[0]; |
|
1121 |
save_read_set= head->read_set; |
|
1122 |
save_write_set= head->write_set; |
|
1123 |
||
1005.2.3
by Monty Taylor
Further reversion of P. |
1124 |
/* Allocate a bitmap for used columns (Q: why not on MEM_ROOT?) */
|
1125 |
if (!(bitmap= (my_bitmap_map*) malloc(head->s->column_bitmap_size))) |
|
1126 |
{
|
|
1127 |
column_bitmap.bitmap= 0; |
|
1128 |
*create_error= 1; |
|
1129 |
}
|
|
1130 |
else
|
|
1014.2.12
by Monty Taylor
Removed the thread-safe crap in MY_BITMAP. Also remove the temp-pool option for |
1131 |
bitmap_init(&column_bitmap, bitmap, head->s->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. |
1132 |
return; |
1
by brian
clean slate |
1133 |
}
|
1134 |
||
1135 |
||
1136 |
int QUICK_RANGE_SELECT::init() |
|
1137 |
{
|
|
1138 |
if (file->inited != handler::NONE) |
|
1139 |
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. |
1140 |
return(file->ha_index_init(index, 1)); |
1
by brian
clean slate |
1141 |
}
|
1142 |
||
1143 |
||
1144 |
void QUICK_RANGE_SELECT::range_end() |
|
1145 |
{
|
|
1146 |
if (file->inited != handler::NONE) |
|
1147 |
file->ha_index_or_rnd_end(); |
|
1148 |
}
|
|
1149 |
||
1150 |
||
1151 |
QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() |
|
1152 |
{
|
|
1153 |
if (!dont_free) |
|
1154 |
{
|
|
1155 |
/* file is NULL for CPK scan on covering ROR-intersection */
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1156 |
if (file) |
1
by brian
clean slate |
1157 |
{
|
1158 |
range_end(); |
|
1159 |
if (head->key_read) |
|
1160 |
{
|
|
1161 |
head->key_read= 0; |
|
1162 |
file->extra(HA_EXTRA_NO_KEYREAD); |
|
1163 |
}
|
|
1164 |
if (free_file) |
|
1165 |
{
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
1166 |
file->ha_external_lock(current_session, F_UNLCK); |
1
by brian
clean slate |
1167 |
file->close(); |
1168 |
delete file; |
|
1169 |
}
|
|
1170 |
}
|
|
1171 |
delete_dynamic(&ranges); /* ranges are allocated in alloc */ |
|
1172 |
free_root(&alloc,MYF(0)); |
|
1005.2.3
by Monty Taylor
Further reversion of P. |
1173 |
free((char*) column_bitmap.bitmap); |
1
by brian
clean slate |
1174 |
}
|
1175 |
head->column_bitmaps_set(save_read_set, save_write_set); |
|
460
by Monty Taylor
Removed x_free calls. |
1176 |
if (mrr_buf_desc) |
1177 |
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. |
1178 |
return; |
1
by brian
clean slate |
1179 |
}
|
1180 |
||
1181 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
1182 |
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 |
1183 |
Table *table) |
520.1.22
by Brian Aker
Second pass of thd cleanup |
1184 |
:pk_quick_select(NULL), session(session_param) |
1
by brian
clean slate |
1185 |
{
|
1186 |
index= MAX_KEY; |
|
1187 |
head= table; |
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
1188 |
memset(&read_record, 0, sizeof(read_record)); |
520.1.22
by Brian Aker
Second pass of thd cleanup |
1189 |
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. |
1190 |
return; |
1
by brian
clean slate |
1191 |
}
|
1192 |
||
1193 |
int QUICK_INDEX_MERGE_SELECT::init() |
|
1194 |
{
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1195 |
return 0; |
1
by brian
clean slate |
1196 |
}
|
1197 |
||
1198 |
int QUICK_INDEX_MERGE_SELECT::reset() |
|
1199 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
1200 |
return(read_keys_and_merge()); |
1
by brian
clean slate |
1201 |
}
|
1202 |
||
1203 |
bool
|
|
1204 |
QUICK_INDEX_MERGE_SELECT::push_quick_back(QUICK_RANGE_SELECT *quick_sel_range) |
|
1205 |
{
|
|
1206 |
/*
|
|
1207 |
Save quick_select that does scan on clustered primary key as it will be
|
|
1208 |
processed separately.
|
|
1209 |
*/
|
|
1210 |
if (head->file->primary_key_is_clustered() && |
|
1211 |
quick_sel_range->index == head->s->primary_key) |
|
1212 |
pk_quick_select= quick_sel_range; |
|
1213 |
else
|
|
1214 |
return quick_selects.push_back(quick_sel_range); |
|
1215 |
return 0; |
|
1216 |
}
|
|
1217 |
||
1218 |
QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT() |
|
1219 |
{
|
|
1220 |
List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects); |
|
1221 |
QUICK_RANGE_SELECT* quick; |
|
1222 |
quick_it.rewind(); |
|
1223 |
while ((quick= quick_it++)) |
|
1224 |
quick->file= NULL; |
|
1225 |
quick_selects.delete_elements(); |
|
1226 |
delete pk_quick_select; |
|
1227 |
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. |
1228 |
return; |
1
by brian
clean slate |
1229 |
}
|
1230 |
||
1231 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
1232 |
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 |
1233 |
Table *table, |
1
by brian
clean slate |
1234 |
bool retrieve_full_rows, |
1235 |
MEM_ROOT *parent_alloc) |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
1236 |
: cpk_quick(NULL), session(session_param), need_to_fetch_row(retrieve_full_rows), |
55
by brian
Update for using real bool types. |
1237 |
scans_inited(false) |
1
by brian
clean slate |
1238 |
{
|
1239 |
index= MAX_KEY; |
|
1240 |
head= table; |
|
1241 |
record= head->record[0]; |
|
1242 |
if (!parent_alloc) |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
1243 |
init_sql_alloc(&alloc, session->variables.range_alloc_block_size, 0); |
1
by brian
clean slate |
1244 |
else
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
1245 |
memset(&alloc, 0, sizeof(MEM_ROOT)); |
481
by Brian Aker
Remove all of uchar. |
1246 |
last_rowid= (unsigned char*) alloc_root(parent_alloc? parent_alloc : &alloc, |
1
by brian
clean slate |
1247 |
head->file->ref_length); |
1248 |
}
|
|
1249 |
||
1250 |
||
1251 |
/*
|
|
1252 |
Do post-constructor initialization.
|
|
1253 |
SYNOPSIS
|
|
1254 |
QUICK_ROR_INTERSECT_SELECT::init()
|
|
1255 |
||
1256 |
RETURN
|
|
1257 |
0 OK
|
|
1258 |
other Error code
|
|
1259 |
*/
|
|
1260 |
||
1261 |
int QUICK_ROR_INTERSECT_SELECT::init() |
|
1262 |
{
|
|
1263 |
/* 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. |
1264 |
return(!last_rowid); |
1
by brian
clean slate |
1265 |
}
|
1266 |
||
1267 |
||
1268 |
/*
|
|
1269 |
Initialize this quick select to be a ROR-merged scan.
|
|
1270 |
||
1271 |
SYNOPSIS
|
|
1272 |
QUICK_RANGE_SELECT::init_ror_merged_scan()
|
|
55
by brian
Update for using real bool types. |
1273 |
reuse_handler If true, use head->file, otherwise create a separate
|
1
by brian
clean slate |
1274 |
handler object
|
1275 |
||
1276 |
NOTES
|
|
1277 |
This function creates and prepares for subsequent use a separate handler
|
|
1278 |
object if it can't reuse head->file. The reason for this is that during
|
|
1279 |
ROR-merge several key scans are performed simultaneously, and a single
|
|
1280 |
handler is only capable of preserving context of a single key scan.
|
|
1281 |
||
1282 |
In ROR-merge the quick select doing merge does full records retrieval,
|
|
1283 |
merged quick selects read only keys.
|
|
1284 |
||
1285 |
RETURN
|
|
1286 |
0 ROR child scan initialized, ok to use.
|
|
1287 |
1 error
|
|
1288 |
*/
|
|
1289 |
||
1290 |
int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) |
|
1291 |
{
|
|
1292 |
handler *save_file= file, *org_file; |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
1293 |
Session *session; |
1
by brian
clean slate |
1294 |
|
1295 |
in_ror_merged_scan= 1; |
|
1296 |
if (reuse_handler) |
|
1297 |
{
|
|
1298 |
if (init() || reset()) |
|
1299 |
{
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1300 |
return 0; |
1
by brian
clean slate |
1301 |
}
|
1302 |
head->column_bitmaps_set(&column_bitmap, &column_bitmap); |
|
1303 |
goto end; |
|
1304 |
}
|
|
1305 |
||
1306 |
/* Create a separate handler object for this quick select */
|
|
1307 |
if (free_file) |
|
1308 |
{
|
|
1309 |
/* already have own 'handler' object. */
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1310 |
return 0; |
1
by brian
clean slate |
1311 |
}
|
1312 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
1313 |
session= head->in_use; |
1314 |
if (!(file= head->file->clone(session->mem_root))) |
|
1
by brian
clean slate |
1315 |
{
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1316 |
/*
|
1
by brian
clean slate |
1317 |
Manually set the error flag. Note: there seems to be quite a few
|
1318 |
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: |
1319 |
sending no response to a query. ATM those are not real errors because
|
1320 |
the storage engine calls in question happen to never fail with the
|
|
1321 |
existing storage engines.
|
|
1
by brian
clean slate |
1322 |
*/
|
1323 |
my_error(ER_OUT_OF_RESOURCES, MYF(0)); /* purecov: inspected */ |
|
1324 |
/* Caller will free the memory */
|
|
1325 |
goto failure; /* purecov: inspected */ |
|
1326 |
}
|
|
1327 |
||
1328 |
head->column_bitmaps_set(&column_bitmap, &column_bitmap); |
|
1329 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
1330 |
if (file->ha_external_lock(session, F_RDLCK)) |
1
by brian
clean slate |
1331 |
goto failure; |
1332 |
||
1333 |
if (init() || reset()) |
|
1334 |
{
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
1335 |
file->ha_external_lock(session, F_UNLCK); |
1
by brian
clean slate |
1336 |
file->close(); |
1337 |
goto failure; |
|
1338 |
}
|
|
55
by brian
Update for using real bool types. |
1339 |
free_file= true; |
1
by brian
clean slate |
1340 |
last_rowid= file->ref; |
1341 |
||
1342 |
end: |
|
1343 |
/*
|
|
1344 |
We are only going to read key fields and call position() on 'file'
|
|
1345 |
The following sets head->tmp_set to only use this key and then updates
|
|
1346 |
head->read_set and head->write_set to use this bitmap.
|
|
1347 |
The now bitmap is stored in 'column_bitmap' which is used in ::get_next()
|
|
1348 |
*/
|
|
1349 |
org_file= head->file; |
|
1350 |
head->file= file; |
|
1351 |
/* We don't have to set 'head->keyread' here as the 'file' is unique */
|
|
1352 |
if (!head->no_keyread) |
|
1353 |
{
|
|
1354 |
head->key_read= 1; |
|
1355 |
head->mark_columns_used_by_index(index); |
|
1356 |
}
|
|
1357 |
head->prepare_for_position(); |
|
1358 |
head->file= org_file; |
|
1005.2.3
by Monty Taylor
Further reversion of P. |
1359 |
bitmap_copy(&column_bitmap, head->read_set); |
1
by brian
clean slate |
1360 |
head->column_bitmaps_set(&column_bitmap, &column_bitmap); |
1361 |
||
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1362 |
return 0; |
1
by brian
clean slate |
1363 |
|
1364 |
failure: |
|
1365 |
head->column_bitmaps_set(save_read_set, save_write_set); |
|
1366 |
delete file; |
|
1367 |
file= save_file; |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1368 |
return 0; |
1
by brian
clean slate |
1369 |
}
|
1370 |
||
1371 |
||
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. |
1372 |
void QUICK_RANGE_SELECT::save_last_pos() |
1373 |
{
|
|
1374 |
file->position(record); |
|
1375 |
}
|
|
1376 |
||
1377 |
||
1
by brian
clean slate |
1378 |
/*
|
1379 |
Initialize this quick select to be a part of a ROR-merged scan.
|
|
1380 |
SYNOPSIS
|
|
1381 |
QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan()
|
|
55
by brian
Update for using real bool types. |
1382 |
reuse_handler If true, use head->file, otherwise create separate
|
1
by brian
clean slate |
1383 |
handler object.
|
1384 |
RETURN
|
|
1385 |
0 OK
|
|
1386 |
other error code
|
|
1387 |
*/
|
|
1388 |
int QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan(bool reuse_handler) |
|
1389 |
{
|
|
1390 |
List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects); |
|
1391 |
QUICK_RANGE_SELECT* quick; |
|
1392 |
||
1393 |
/* 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. |
1394 |
assert(!need_to_fetch_row || reuse_handler); |
1
by brian
clean slate |
1395 |
if (!need_to_fetch_row && reuse_handler) |
1396 |
{
|
|
1397 |
quick= quick_it++; |
|
1398 |
/*
|
|
1399 |
There is no use of this->file. Use it for the first of merged range
|
|
1400 |
selects.
|
|
1401 |
*/
|
|
55
by brian
Update for using real bool types. |
1402 |
if (quick->init_ror_merged_scan(true)) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1403 |
return 0; |
1
by brian
clean slate |
1404 |
quick->file->extra(HA_EXTRA_KEYREAD_PRESERVE_FIELDS); |
1405 |
}
|
|
1406 |
while ((quick= quick_it++)) |
|
1407 |
{
|
|
55
by brian
Update for using real bool types. |
1408 |
if (quick->init_ror_merged_scan(false)) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1409 |
return 0; |
1
by brian
clean slate |
1410 |
quick->file->extra(HA_EXTRA_KEYREAD_PRESERVE_FIELDS); |
1411 |
/* All merged scans share the same record buffer in intersection. */
|
|
1412 |
quick->record= head->record[0]; |
|
1413 |
}
|
|
1414 |
||
1415 |
if (need_to_fetch_row && head->file->ha_rnd_init(1)) |
|
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 |
}
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1419 |
return 0; |
1
by brian
clean slate |
1420 |
}
|
1421 |
||
1422 |
||
1423 |
/*
|
|
1424 |
Initialize quick select for row retrieval.
|
|
1425 |
SYNOPSIS
|
|
1426 |
reset()
|
|
1427 |
RETURN
|
|
1428 |
0 OK
|
|
1429 |
other Error code
|
|
1430 |
*/
|
|
1431 |
||
1432 |
int QUICK_ROR_INTERSECT_SELECT::reset() |
|
1433 |
{
|
|
55
by brian
Update for using real bool types. |
1434 |
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 |
1435 |
return 0; |
55
by brian
Update for using real bool types. |
1436 |
scans_inited= true; |
1
by brian
clean slate |
1437 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
1438 |
QUICK_RANGE_SELECT *quick; |
|
1439 |
while ((quick= it++)) |
|
1440 |
quick->reset(); |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1441 |
return 0; |
1
by brian
clean slate |
1442 |
}
|
1443 |
||
1444 |
||
1445 |
/*
|
|
1446 |
Add a merged quick select to this ROR-intersection quick select.
|
|
1447 |
||
1448 |
SYNOPSIS
|
|
1449 |
QUICK_ROR_INTERSECT_SELECT::push_quick_back()
|
|
1450 |
quick Quick select to be added. The quick select must return
|
|
1451 |
rows in rowid order.
|
|
1452 |
NOTES
|
|
1453 |
This call can only be made before init() is called.
|
|
1454 |
||
1455 |
RETURN
|
|
55
by brian
Update for using real bool types. |
1456 |
false OK
|
1457 |
true Out of memory.
|
|
1
by brian
clean slate |
1458 |
*/
|
1459 |
||
1460 |
bool
|
|
1461 |
QUICK_ROR_INTERSECT_SELECT::push_quick_back(QUICK_RANGE_SELECT *quick) |
|
1462 |
{
|
|
1463 |
return quick_selects.push_back(quick); |
|
1464 |
}
|
|
1465 |
||
1466 |
QUICK_ROR_INTERSECT_SELECT::~QUICK_ROR_INTERSECT_SELECT() |
|
1467 |
{
|
|
1468 |
quick_selects.delete_elements(); |
|
1469 |
delete cpk_quick; |
|
1470 |
free_root(&alloc,MYF(0)); |
|
1471 |
if (need_to_fetch_row && head->file->inited != handler::NONE) |
|
1472 |
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. |
1473 |
return; |
1
by brian
clean slate |
1474 |
}
|
1475 |
||
1476 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
1477 |
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 |
1478 |
Table *table) |
520.1.22
by Brian Aker
Second pass of thd cleanup |
1479 |
: session(session_param), scans_inited(false) |
1
by brian
clean slate |
1480 |
{
|
1481 |
index= MAX_KEY; |
|
1482 |
head= table; |
|
1483 |
rowid_length= table->file->ref_length; |
|
1484 |
record= head->record[0]; |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
1485 |
init_sql_alloc(&alloc, session->variables.range_alloc_block_size, 0); |
1486 |
session_param->mem_root= &alloc; |
|
1
by brian
clean slate |
1487 |
}
|
1488 |
||
957.1.6
by Padraig O'Sullivan
Fixed function object to ensure it correctly returns a boolean type since |
1489 |
/*
|
1490 |
* Function object that is used as the comparison function
|
|
1491 |
* for the priority queue in the QUICK_ROR_UNION_SELECT
|
|
1492 |
* class.
|
|
1493 |
*/
|
|
1494 |
class compare_functor |
|
1495 |
{
|
|
1496 |
QUICK_ROR_UNION_SELECT *self; |
|
1497 |
public: |
|
1498 |
compare_functor(QUICK_ROR_UNION_SELECT *in_arg) |
|
1499 |
: self(in_arg) { } |
|
1500 |
inline bool operator()(const QUICK_SELECT_I *i, const QUICK_SELECT_I *j) const |
|
1501 |
{
|
|
1502 |
int val= self->head->file->cmp_ref(i->last_rowid, |
|
1503 |
j->last_rowid); |
|
1504 |
return (val >= 0); |
|
1505 |
}
|
|
1506 |
};
|
|
1
by brian
clean slate |
1507 |
|
1508 |
/*
|
|
1509 |
Do post-constructor initialization.
|
|
1510 |
SYNOPSIS
|
|
1511 |
QUICK_ROR_UNION_SELECT::init()
|
|
1512 |
||
1513 |
RETURN
|
|
1514 |
0 OK
|
|
1515 |
other Error code
|
|
1516 |
*/
|
|
1517 |
||
1518 |
int QUICK_ROR_UNION_SELECT::init() |
|
1519 |
{
|
|
957.1.6
by Padraig O'Sullivan
Fixed function object to ensure it correctly returns a boolean type since |
1520 |
queue= |
1521 |
new priority_queue<QUICK_SELECT_I *, vector<QUICK_SELECT_I *>, compare_functor >(compare_functor(this)); |
|
481
by Brian Aker
Remove all of uchar. |
1522 |
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 |
1523 |
return 0; |
1
by brian
clean slate |
1524 |
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 |
1525 |
return 0; |
1
by brian
clean slate |
1526 |
}
|
1527 |
||
1528 |
||
1529 |
/*
|
|
1530 |
Comparison function to be used QUICK_ROR_UNION_SELECT::queue priority
|
|
1531 |
queue.
|
|
1532 |
||
1533 |
SYNPOSIS
|
|
1534 |
QUICK_ROR_UNION_SELECT::queue_cmp()
|
|
1535 |
arg Pointer to QUICK_ROR_UNION_SELECT
|
|
1536 |
val1 First merged select
|
|
1537 |
val2 Second merged select
|
|
1538 |
*/
|
|
1539 |
||
892.1.2
by Monty Taylor
Fixed solaris warnings. |
1540 |
int quick_ror_union_select_queue_cmp(void *arg, unsigned char *val1, unsigned char *val2) |
1
by brian
clean slate |
1541 |
{
|
1542 |
QUICK_ROR_UNION_SELECT *self= (QUICK_ROR_UNION_SELECT*)arg; |
|
1543 |
return self->head->file->cmp_ref(((QUICK_SELECT_I*)val1)->last_rowid, |
|
1544 |
((QUICK_SELECT_I*)val2)->last_rowid); |
|
1545 |
}
|
|
1546 |
||
1547 |
||
1548 |
/*
|
|
1549 |
Initialize quick select for row retrieval.
|
|
1550 |
SYNOPSIS
|
|
1551 |
reset()
|
|
1552 |
||
1553 |
RETURN
|
|
1554 |
0 OK
|
|
1555 |
other Error code
|
|
1556 |
*/
|
|
1557 |
||
1558 |
int QUICK_ROR_UNION_SELECT::reset() |
|
1559 |
{
|
|
1560 |
QUICK_SELECT_I *quick; |
|
1561 |
int error; |
|
55
by brian
Update for using real bool types. |
1562 |
have_prev_rowid= false; |
1
by brian
clean slate |
1563 |
if (!scans_inited) |
1564 |
{
|
|
1565 |
List_iterator_fast<QUICK_SELECT_I> it(quick_selects); |
|
1566 |
while ((quick= it++)) |
|
1567 |
{
|
|
55
by brian
Update for using real bool types. |
1568 |
if (quick->init_ror_merged_scan(false)) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1569 |
return 0; |
1
by brian
clean slate |
1570 |
}
|
55
by brian
Update for using real bool types. |
1571 |
scans_inited= true; |
1
by brian
clean slate |
1572 |
}
|
957.1.6
by Padraig O'Sullivan
Fixed function object to ensure it correctly returns a boolean type since |
1573 |
while (!queue->empty()) |
1574 |
queue->pop(); |
|
1
by brian
clean slate |
1575 |
/*
|
1576 |
Initialize scans for merged quick selects and put all merged quick
|
|
1577 |
selects into the queue.
|
|
1578 |
*/
|
|
1579 |
List_iterator_fast<QUICK_SELECT_I> it(quick_selects); |
|
1580 |
while ((quick= it++)) |
|
1581 |
{
|
|
1582 |
if (quick->reset()) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1583 |
return 0; |
1
by brian
clean slate |
1584 |
if ((error= quick->get_next())) |
1585 |
{
|
|
1586 |
if (error == HA_ERR_END_OF_FILE) |
|
1587 |
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. |
1588 |
return(error); |
1
by brian
clean slate |
1589 |
}
|
1590 |
quick->save_last_pos(); |
|
957.1.6
by Padraig O'Sullivan
Fixed function object to ensure it correctly returns a boolean type since |
1591 |
queue->push(quick); |
1
by brian
clean slate |
1592 |
}
|
1593 |
||
1594 |
if (head->file->ha_rnd_init(1)) |
|
1595 |
{
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1596 |
return 0; |
1
by brian
clean slate |
1597 |
}
|
1598 |
||
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1599 |
return 0; |
1
by brian
clean slate |
1600 |
}
|
1601 |
||
1602 |
||
1603 |
bool
|
|
1604 |
QUICK_ROR_UNION_SELECT::push_quick_back(QUICK_SELECT_I *quick_sel_range) |
|
1605 |
{
|
|
1606 |
return quick_selects.push_back(quick_sel_range); |
|
1607 |
}
|
|
1608 |
||
1609 |
QUICK_ROR_UNION_SELECT::~QUICK_ROR_UNION_SELECT() |
|
1610 |
{
|
|
957.1.6
by Padraig O'Sullivan
Fixed function object to ensure it correctly returns a boolean type since |
1611 |
while (!queue->empty()) |
1612 |
queue->pop(); |
|
1613 |
delete queue; |
|
1
by brian
clean slate |
1614 |
quick_selects.delete_elements(); |
1615 |
if (head->file->inited != handler::NONE) |
|
1616 |
head->file->ha_rnd_end(); |
|
1617 |
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. |
1618 |
return; |
1
by brian
clean slate |
1619 |
}
|
1620 |
||
1621 |
||
1622 |
QUICK_RANGE::QUICK_RANGE() |
|
1623 |
:min_key(0),max_key(0),min_length(0),max_length(0), |
|
1624 |
flag(NO_MIN_RANGE | NO_MAX_RANGE), |
|
1625 |
min_keypart_map(0), max_keypart_map(0) |
|
1626 |
{}
|
|
1627 |
||
1628 |
SEL_ARG::SEL_ARG(SEL_ARG &arg) :Sql_alloc() |
|
1629 |
{
|
|
1630 |
type=arg.type; |
|
1631 |
min_flag=arg.min_flag; |
|
1632 |
max_flag=arg.max_flag; |
|
1633 |
maybe_flag=arg.maybe_flag; |
|
1634 |
maybe_null=arg.maybe_null; |
|
1635 |
part=arg.part; |
|
1636 |
field=arg.field; |
|
1637 |
min_value=arg.min_value; |
|
1638 |
max_value=arg.max_value; |
|
1639 |
next_key_part=arg.next_key_part; |
|
1640 |
use_count=1; elements=1; |
|
1641 |
}
|
|
1642 |
||
1643 |
||
1644 |
inline void SEL_ARG::make_root() |
|
1645 |
{
|
|
1646 |
left=right= &null_element; |
|
1647 |
color=BLACK; |
|
1648 |
next=prev=0; |
|
1649 |
use_count=0; elements=1; |
|
1650 |
}
|
|
1651 |
||
481
by Brian Aker
Remove all of uchar. |
1652 |
SEL_ARG::SEL_ARG(Field *f,const unsigned char *min_value_arg, |
1653 |
const unsigned char *max_value_arg) |
|
1
by brian
clean slate |
1654 |
:min_flag(0), max_flag(0), maybe_flag(0), maybe_null(f->real_maybe_null()), |
481
by Brian Aker
Remove all of uchar. |
1655 |
elements(1), use_count(1), field(f), min_value((unsigned char*) min_value_arg), |
1656 |
max_value((unsigned char*) max_value_arg), next(0),prev(0), |
|
1
by brian
clean slate |
1657 |
next_key_part(0),color(BLACK),type(KEY_RANGE) |
1658 |
{
|
|
1659 |
left=right= &null_element; |
|
1660 |
}
|
|
1661 |
||
206
by Brian Aker
Removed final uint dead types. |
1662 |
SEL_ARG::SEL_ARG(Field *field_,uint8_t part_, |
481
by Brian Aker
Remove all of uchar. |
1663 |
unsigned char *min_value_, unsigned char *max_value_, |
206
by Brian Aker
Removed final uint dead types. |
1664 |
uint8_t min_flag_,uint8_t max_flag_,uint8_t maybe_flag_) |
1
by brian
clean slate |
1665 |
:min_flag(min_flag_),max_flag(max_flag_),maybe_flag(maybe_flag_), |
1666 |
part(part_),maybe_null(field_->real_maybe_null()), elements(1),use_count(1), |
|
1667 |
field(field_), min_value(min_value_), max_value(max_value_), |
|
1668 |
next(0),prev(0),next_key_part(0),color(BLACK),type(KEY_RANGE) |
|
1669 |
{
|
|
1670 |
left=right= &null_element; |
|
1671 |
}
|
|
1672 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1673 |
SEL_ARG *SEL_ARG::clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent, |
1
by brian
clean slate |
1674 |
SEL_ARG **next_arg) |
1675 |
{
|
|
1676 |
SEL_ARG *tmp; |
|
1677 |
||
1678 |
/* Bail out if we have already generated too many SEL_ARGs */
|
|
1679 |
if (++param->alloced_sel_args > MAX_SEL_ARGS) |
|
1680 |
return 0; |
|
1681 |
||
1682 |
if (type != KEY_RANGE) |
|
1683 |
{
|
|
1684 |
if (!(tmp= new (param->mem_root) SEL_ARG(type))) |
|
1685 |
return 0; // out of memory |
|
1686 |
tmp->prev= *next_arg; // Link into next/prev chain |
|
1687 |
(*next_arg)->next=tmp; |
|
1688 |
(*next_arg)= tmp; |
|
1689 |
}
|
|
1690 |
else
|
|
1691 |
{
|
|
1692 |
if (!(tmp= new (param->mem_root) SEL_ARG(field,part, min_value,max_value, |
|
1693 |
min_flag, max_flag, maybe_flag))) |
|
1694 |
return 0; // OOM |
|
1695 |
tmp->parent=new_parent; |
|
1696 |
tmp->next_key_part=next_key_part; |
|
1697 |
if (left != &null_element) |
|
1698 |
if (!(tmp->left=left->clone(param, tmp, next_arg))) |
|
1699 |
return 0; // OOM |
|
1700 |
||
1701 |
tmp->prev= *next_arg; // Link into next/prev chain |
|
1702 |
(*next_arg)->next=tmp; |
|
1703 |
(*next_arg)= tmp; |
|
1704 |
||
1705 |
if (right != &null_element) |
|
1706 |
if (!(tmp->right= right->clone(param, tmp, next_arg))) |
|
1707 |
return 0; // OOM |
|
1708 |
}
|
|
1709 |
increment_use_count(1); |
|
1710 |
tmp->color= color; |
|
1711 |
tmp->elements= this->elements; |
|
1712 |
return tmp; |
|
1713 |
}
|
|
1714 |
||
1715 |
SEL_ARG *SEL_ARG::first() |
|
1716 |
{
|
|
1717 |
SEL_ARG *next_arg=this; |
|
1718 |
if (!next_arg->left) |
|
1719 |
return 0; // MAYBE_KEY |
|
1720 |
while (next_arg->left != &null_element) |
|
1721 |
next_arg=next_arg->left; |
|
1722 |
return next_arg; |
|
1723 |
}
|
|
1724 |
||
1725 |
SEL_ARG *SEL_ARG::last() |
|
1726 |
{
|
|
1727 |
SEL_ARG *next_arg=this; |
|
1728 |
if (!next_arg->right) |
|
1729 |
return 0; // MAYBE_KEY |
|
1730 |
while (next_arg->right != &null_element) |
|
1731 |
next_arg=next_arg->right; |
|
1732 |
return next_arg; |
|
1733 |
}
|
|
1734 |
||
1735 |
||
1736 |
/*
|
|
1737 |
Check if a compare is ok, when one takes ranges in account
|
|
1738 |
Returns -2 or 2 if the ranges where 'joined' like < 2 and >= 2
|
|
1739 |
*/
|
|
1740 |
||
481
by Brian Aker
Remove all of uchar. |
1741 |
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. |
1742 |
uint8_t b_flag) |
1
by brian
clean slate |
1743 |
{
|
1744 |
int cmp; |
|
1745 |
/* First check if there was a compare to a min or max element */
|
|
1746 |
if (a_flag & (NO_MIN_RANGE | NO_MAX_RANGE)) |
|
1747 |
{
|
|
1748 |
if ((a_flag & (NO_MIN_RANGE | NO_MAX_RANGE)) == |
|
1749 |
(b_flag & (NO_MIN_RANGE | NO_MAX_RANGE))) |
|
1750 |
return 0; |
|
1751 |
return (a_flag & NO_MIN_RANGE) ? -1 : 1; |
|
1752 |
}
|
|
1753 |
if (b_flag & (NO_MIN_RANGE | NO_MAX_RANGE)) |
|
1754 |
return (b_flag & NO_MIN_RANGE) ? 1 : -1; |
|
1755 |
||
1756 |
if (field->real_maybe_null()) // If null is part of key |
|
1757 |
{
|
|
1758 |
if (*a != *b) |
|
1759 |
{
|
|
1760 |
return *a ? -1 : 1; |
|
1761 |
}
|
|
1762 |
if (*a) |
|
1763 |
goto end; // NULL where equal |
|
1764 |
a++; b++; // Skip NULL marker |
|
1765 |
}
|
|
1766 |
cmp=field->key_cmp(a , b); |
|
1767 |
if (cmp) return cmp < 0 ? -1 : 1; // The values differed |
|
1768 |
||
1769 |
// Check if the compared equal arguments was defined with open/closed range
|
|
1770 |
end: |
|
1771 |
if (a_flag & (NEAR_MIN | NEAR_MAX)) |
|
1772 |
{
|
|
1773 |
if ((a_flag & (NEAR_MIN | NEAR_MAX)) == (b_flag & (NEAR_MIN | NEAR_MAX))) |
|
1774 |
return 0; |
|
1775 |
if (!(b_flag & (NEAR_MIN | NEAR_MAX))) |
|
1776 |
return (a_flag & NEAR_MIN) ? 2 : -2; |
|
1777 |
return (a_flag & NEAR_MIN) ? 1 : -1; |
|
1778 |
}
|
|
1779 |
if (b_flag & (NEAR_MIN | NEAR_MAX)) |
|
1780 |
return (b_flag & NEAR_MIN) ? -2 : 2; |
|
1781 |
return 0; // The elements where equal |
|
1782 |
}
|
|
1783 |
||
1784 |
||
1785 |
SEL_ARG *SEL_ARG::clone_tree(RANGE_OPT_PARAM *param) |
|
1786 |
{
|
|
1787 |
SEL_ARG tmp_link,*next_arg,*root; |
|
1788 |
next_arg= &tmp_link; |
|
1789 |
if (!(root= clone(param, (SEL_ARG *) 0, &next_arg))) |
|
1790 |
return 0; |
|
1791 |
next_arg->next=0; // Fix last link |
|
1792 |
tmp_link.next->prev=0; // Fix first link |
|
1793 |
if (root) // If not OOM |
|
1794 |
root->use_count= 0; |
|
1795 |
return root; |
|
1796 |
}
|
|
1797 |
||
1798 |
||
1799 |
/*
|
|
1800 |
Find the best index to retrieve first N records in given order
|
|
1801 |
||
1802 |
SYNOPSIS
|
|
1803 |
get_index_for_order()
|
|
1804 |
table Table to be accessed
|
|
1805 |
order Required ordering
|
|
1806 |
limit Number of records that will be retrieved
|
|
1807 |
||
1808 |
DESCRIPTION
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1809 |
Find the best index that allows to retrieve first #limit records in the
|
1
by brian
clean slate |
1810 |
given order cheaper then one would retrieve them using full table scan.
|
1811 |
||
1812 |
IMPLEMENTATION
|
|
1813 |
Run through all table indexes and find the shortest index that allows
|
|
1814 |
records to be retrieved in given order. We look for the shortest index
|
|
1815 |
as we will have fewer index pages to read with it.
|
|
1816 |
||
1817 |
This function is used only by UPDATE/DELETE, so we take into account how
|
|
1818 |
the UPDATE/DELETE code will work:
|
|
1819 |
* index can only be scanned in forward direction
|
|
1820 |
* HA_EXTRA_KEYREAD will not be used
|
|
1821 |
Perhaps these assumptions could be relaxed.
|
|
1822 |
||
1823 |
RETURN
|
|
1824 |
Number of the index that produces the required ordering in the cheapest way
|
|
1825 |
MAX_KEY if no such index was found.
|
|
1826 |
*/
|
|
1827 |
||
482
by Brian Aker
Remove uint. |
1828 |
uint32_t get_index_for_order(Table *table, order_st *order, ha_rows limit) |
1
by brian
clean slate |
1829 |
{
|
482
by Brian Aker
Remove uint. |
1830 |
uint32_t idx; |
1831 |
uint32_t match_key= MAX_KEY, match_key_len= MAX_KEY_LENGTH + 1; |
|
327.2.3
by Brian Aker
Refactoring of class Table |
1832 |
order_st *ord; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1833 |
|
1
by brian
clean slate |
1834 |
for (ord= order; ord; ord= ord->next) |
1835 |
if (!ord->asc) |
|
1836 |
return MAX_KEY; |
|
1837 |
||
1838 |
for (idx= 0; idx < table->s->keys; idx++) |
|
1839 |
{
|
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
1840 |
if (!(table->keys_in_use_for_query.test(idx))) |
1
by brian
clean slate |
1841 |
continue; |
1842 |
KEY_PART_INFO *keyinfo= table->key_info[idx].key_part; |
|
482
by Brian Aker
Remove uint. |
1843 |
uint32_t n_parts= table->key_info[idx].key_parts; |
1844 |
uint32_t partno= 0; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1845 |
|
1846 |
/*
|
|
1847 |
The below check is sufficient considering we now have either BTREE
|
|
1848 |
indexes (records are returned in order for any index prefix) or HASH
|
|
1
by brian
clean slate |
1849 |
indexes (records are not returned in order for any index prefix).
|
1850 |
*/
|
|
1851 |
if (!(table->file->index_flags(idx, 0, 1) & HA_READ_ORDER)) |
|
1852 |
continue; |
|
1853 |
for (ord= order; ord && partno < n_parts; ord= ord->next, partno++) |
|
1854 |
{
|
|
1855 |
Item *item= order->item[0]; |
|
1856 |
if (!(item->type() == Item::FIELD_ITEM && |
|
1857 |
((Item_field*)item)->field->eq(keyinfo[partno].field))) |
|
1858 |
break; |
|
1859 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1860 |
|
1
by brian
clean slate |
1861 |
if (!ord && table->key_info[idx].key_length < match_key_len) |
1862 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1863 |
/*
|
1
by brian
clean slate |
1864 |
Ok, the ordering is compatible and this key is shorter then
|
1865 |
previous match (we want shorter keys as we'll have to read fewer
|
|
1866 |
index pages for the same number of records)
|
|
1867 |
*/
|
|
1868 |
match_key= idx; |
|
1869 |
match_key_len= table->key_info[idx].key_length; |
|
1870 |
}
|
|
1871 |
}
|
|
1872 |
||
1873 |
if (match_key != MAX_KEY) |
|
1874 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1875 |
/*
|
1876 |
Found an index that allows records to be retrieved in the requested
|
|
1
by brian
clean slate |
1877 |
order. Now we'll check if using the index is cheaper then doing a table
|
1878 |
scan.
|
|
1879 |
*/
|
|
1880 |
double full_scan_time= table->file->scan_time(); |
|
1881 |
double index_scan_time= table->file->read_time(match_key, 1, limit); |
|
1882 |
if (index_scan_time > full_scan_time) |
|
1883 |
match_key= MAX_KEY; |
|
1884 |
}
|
|
1885 |
return match_key; |
|
1886 |
}
|
|
1887 |
||
1888 |
||
1889 |
/*
|
|
1890 |
Table rows retrieval plan. Range optimizer creates QUICK_SELECT_I-derived
|
|
1891 |
objects from table read plans.
|
|
1892 |
*/
|
|
1893 |
class TABLE_READ_PLAN |
|
1894 |
{
|
|
1895 |
public: |
|
1896 |
/*
|
|
1897 |
Plan read cost, with or without cost of full row retrieval, depending
|
|
1898 |
on plan creation parameters.
|
|
1899 |
*/
|
|
1900 |
double read_cost; |
|
1901 |
ha_rows records; /* estimate of #rows to be examined */ |
|
1902 |
||
1903 |
/*
|
|
55
by brian
Update for using real bool types. |
1904 |
If true, the scan returns rows in rowid order. This is used only for
|
1
by brian
clean slate |
1905 |
scans that can be both ROR and non-ROR.
|
1906 |
*/
|
|
1907 |
bool is_ror; |
|
1908 |
||
1909 |
/*
|
|
1910 |
Create quick select for this plan.
|
|
1911 |
SYNOPSIS
|
|
1912 |
make_quick()
|
|
1913 |
param Parameter from test_quick_select
|
|
55
by brian
Update for using real bool types. |
1914 |
retrieve_full_rows If true, created quick select will do full record
|
1
by brian
clean slate |
1915 |
retrieval.
|
1916 |
parent_alloc Memory pool to use, if any.
|
|
1917 |
||
1918 |
NOTES
|
|
1919 |
retrieve_full_rows is ignored by some implementations.
|
|
1920 |
||
1921 |
RETURN
|
|
1922 |
created quick select
|
|
1923 |
NULL on any error.
|
|
1924 |
*/
|
|
1925 |
virtual QUICK_SELECT_I *make_quick(PARAM *param, |
|
1926 |
bool retrieve_full_rows, |
|
1927 |
MEM_ROOT *parent_alloc=NULL) = 0; |
|
1928 |
||
1929 |
/* Table read plans are allocated on MEM_ROOT and are never deleted */
|
|
1930 |
static void *operator new(size_t size, MEM_ROOT *mem_root) |
|
895
by Brian Aker
Completion (?) of uint conversion. |
1931 |
{ return (void*) alloc_root(mem_root, (uint32_t) size); } |
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
1932 |
static void operator delete(void *, size_t) |
77.1.46
by Monty Taylor
Finished the warnings work! |
1933 |
{ TRASH(ptr, size); } |
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
1934 |
static void operator delete(void *, MEM_ROOT *) |
77.1.46
by Monty Taylor
Finished the warnings work! |
1935 |
{ /* Never called */ } |
1
by brian
clean slate |
1936 |
virtual ~TABLE_READ_PLAN() {} /* Remove gcc warning */ |
1937 |
||
1938 |
};
|
|
1939 |
||
1940 |
class TRP_ROR_INTERSECT; |
|
1941 |
class TRP_ROR_UNION; |
|
1942 |
class TRP_INDEX_MERGE; |
|
1943 |
||
1944 |
||
1945 |
/*
|
|
1946 |
Plan for a QUICK_RANGE_SELECT scan.
|
|
1947 |
TRP_RANGE::make_quick ignores retrieve_full_rows parameter because
|
|
1948 |
QUICK_RANGE_SELECT doesn't distinguish between 'index only' scans and full
|
|
1949 |
record retrieval scans.
|
|
1950 |
*/
|
|
1951 |
||
1952 |
class TRP_RANGE : public TABLE_READ_PLAN |
|
1953 |
{
|
|
1954 |
public: |
|
1955 |
SEL_ARG *key; /* set of intervals to be used in "range" method retrieval */ |
|
482
by Brian Aker
Remove uint. |
1956 |
uint32_t key_idx; /* key number in PARAM::key */ |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
1957 |
uint32_t mrr_flags; |
482
by Brian Aker
Remove uint. |
1958 |
uint32_t mrr_buf_size; |
1
by brian
clean slate |
1959 |
|
482
by Brian Aker
Remove uint. |
1960 |
TRP_RANGE(SEL_ARG *key_arg, uint32_t idx_arg, uint32_t mrr_flags_arg) |
1
by brian
clean slate |
1961 |
: key(key_arg), key_idx(idx_arg), mrr_flags(mrr_flags_arg) |
1962 |
{}
|
|
1963 |
virtual ~TRP_RANGE() {} /* Remove gcc warning */ |
|
1964 |
||
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
1965 |
QUICK_SELECT_I *make_quick(PARAM *param, bool, MEM_ROOT *parent_alloc) |
1
by brian
clean slate |
1966 |
{
|
1967 |
QUICK_RANGE_SELECT *quick; |
|
1968 |
if ((quick= get_quick_select(param, key_idx, key, mrr_flags, mrr_buf_size, |
|
1969 |
parent_alloc))) |
|
1970 |
{
|
|
1971 |
quick->records= records; |
|
1972 |
quick->read_time= read_cost; |
|
1973 |
}
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
1974 |
return quick; |
1
by brian
clean slate |
1975 |
}
|
1976 |
};
|
|
1977 |
||
1978 |
||
1979 |
/* Plan for QUICK_ROR_INTERSECT_SELECT scan. */
|
|
1980 |
||
1981 |
class TRP_ROR_INTERSECT : public TABLE_READ_PLAN |
|
1982 |
{
|
|
1983 |
public: |
|
1984 |
TRP_ROR_INTERSECT() {} /* Remove gcc warning */ |
|
1985 |
virtual ~TRP_ROR_INTERSECT() {} /* Remove gcc warning */ |
|
1986 |
QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows, |
|
1987 |
MEM_ROOT *parent_alloc); |
|
1988 |
||
1989 |
/* Array of pointers to ROR range scans used in this intersection */
|
|
1990 |
struct st_ror_scan_info **first_scan; |
|
1991 |
struct st_ror_scan_info **last_scan; /* End of the above array */ |
|
1992 |
struct st_ror_scan_info *cpk_scan; /* Clustered PK scan, if there is one */ |
|
55
by brian
Update for using real bool types. |
1993 |
bool is_covering; /* true if no row retrieval phase is necessary */ |
1
by brian
clean slate |
1994 |
double index_scan_costs; /* SUM(cost(index_scan)) */ |
1995 |
};
|
|
1996 |
||
1997 |
||
1998 |
/*
|
|
1999 |
Plan for QUICK_ROR_UNION_SELECT scan.
|
|
2000 |
QUICK_ROR_UNION_SELECT always retrieves full rows, so retrieve_full_rows
|
|
2001 |
is ignored by make_quick.
|
|
2002 |
*/
|
|
2003 |
||
2004 |
class TRP_ROR_UNION : public TABLE_READ_PLAN |
|
2005 |
{
|
|
2006 |
public: |
|
2007 |
TRP_ROR_UNION() {} /* Remove gcc warning */ |
|
2008 |
virtual ~TRP_ROR_UNION() {} /* Remove gcc warning */ |
|
2009 |
QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows, |
|
2010 |
MEM_ROOT *parent_alloc); |
|
2011 |
TABLE_READ_PLAN **first_ror; /* array of ptrs to plans for merged scans */ |
|
2012 |
TABLE_READ_PLAN **last_ror; /* end of the above array */ |
|
2013 |
};
|
|
2014 |
||
2015 |
||
2016 |
/*
|
|
2017 |
Plan for QUICK_INDEX_MERGE_SELECT scan.
|
|
2018 |
QUICK_ROR_INTERSECT_SELECT always retrieves full rows, so retrieve_full_rows
|
|
2019 |
is ignored by make_quick.
|
|
2020 |
*/
|
|
2021 |
||
2022 |
class TRP_INDEX_MERGE : public TABLE_READ_PLAN |
|
2023 |
{
|
|
2024 |
public: |
|
2025 |
TRP_INDEX_MERGE() {} /* Remove gcc warning */ |
|
2026 |
virtual ~TRP_INDEX_MERGE() {} /* Remove gcc warning */ |
|
2027 |
QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows, |
|
2028 |
MEM_ROOT *parent_alloc); |
|
2029 |
TRP_RANGE **range_scans; /* array of ptrs to plans of merged scans */ |
|
2030 |
TRP_RANGE **range_scans_end; /* end of the array */ |
|
2031 |
};
|
|
2032 |
||
2033 |
||
2034 |
/*
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2035 |
Plan for a QUICK_GROUP_MIN_MAX_SELECT scan.
|
1
by brian
clean slate |
2036 |
*/
|
2037 |
||
2038 |
class TRP_GROUP_MIN_MAX : public TABLE_READ_PLAN |
|
2039 |
{
|
|
2040 |
private: |
|
2041 |
bool have_min, have_max; |
|
2042 |
KEY_PART_INFO *min_max_arg_part; |
|
482
by Brian Aker
Remove uint. |
2043 |
uint32_t group_prefix_len; |
2044 |
uint32_t used_key_parts; |
|
2045 |
uint32_t group_key_parts; |
|
1
by brian
clean slate |
2046 |
KEY *index_info; |
482
by Brian Aker
Remove uint. |
2047 |
uint32_t index; |
2048 |
uint32_t key_infix_len; |
|
481
by Brian Aker
Remove all of uchar. |
2049 |
unsigned char key_infix[MAX_KEY_LENGTH]; |
1
by brian
clean slate |
2050 |
SEL_TREE *range_tree; /* Represents all range predicates in the query. */ |
2051 |
SEL_ARG *index_tree; /* The SEL_ARG sub-tree corresponding to index_info. */ |
|
482
by Brian Aker
Remove uint. |
2052 |
uint32_t param_idx; /* Index of used key in param->key. */ |
1
by brian
clean slate |
2053 |
/* Number of records selected by the ranges in index_tree. */
|
2054 |
public: |
|
2055 |
ha_rows quick_prefix_records; |
|
2056 |
public: |
|
2057 |
TRP_GROUP_MIN_MAX(bool have_min_arg, bool have_max_arg, |
|
2058 |
KEY_PART_INFO *min_max_arg_part_arg, |
|
482
by Brian Aker
Remove uint. |
2059 |
uint32_t group_prefix_len_arg, uint32_t used_key_parts_arg, |
2060 |
uint32_t group_key_parts_arg, KEY *index_info_arg, |
|
2061 |
uint32_t index_arg, uint32_t key_infix_len_arg, |
|
481
by Brian Aker
Remove all of uchar. |
2062 |
unsigned char *key_infix_arg, |
1
by brian
clean slate |
2063 |
SEL_TREE *tree_arg, SEL_ARG *index_tree_arg, |
482
by Brian Aker
Remove uint. |
2064 |
uint32_t param_idx_arg, ha_rows quick_prefix_records_arg) |
1
by brian
clean slate |
2065 |
: have_min(have_min_arg), have_max(have_max_arg), |
2066 |
min_max_arg_part(min_max_arg_part_arg), |
|
2067 |
group_prefix_len(group_prefix_len_arg), used_key_parts(used_key_parts_arg), |
|
2068 |
group_key_parts(group_key_parts_arg), index_info(index_info_arg), |
|
2069 |
index(index_arg), key_infix_len(key_infix_len_arg), range_tree(tree_arg), |
|
2070 |
index_tree(index_tree_arg), param_idx(param_idx_arg), |
|
2071 |
quick_prefix_records(quick_prefix_records_arg) |
|
2072 |
{
|
|
2073 |
if (key_infix_len) |
|
2074 |
memcpy(this->key_infix, key_infix_arg, key_infix_len); |
|
2075 |
}
|
|
2076 |
virtual ~TRP_GROUP_MIN_MAX() {} /* Remove gcc warning */ |
|
2077 |
||
2078 |
QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows, |
|
2079 |
MEM_ROOT *parent_alloc); |
|
2080 |
};
|
|
2081 |
||
2082 |
||
2083 |
/*
|
|
2084 |
Fill param->needed_fields with bitmap of fields used in the query.
|
|
2085 |
SYNOPSIS
|
|
2086 |
fill_used_fields_bitmap()
|
|
2087 |
param Parameter from test_quick_select function.
|
|
2088 |
||
2089 |
NOTES
|
|
2090 |
Clustered PK members are not put into the bitmap as they are implicitly
|
|
2091 |
present in all keys (and it is impossible to avoid reading them).
|
|
2092 |
RETURN
|
|
2093 |
0 Ok
|
|
2094 |
1 Out of memory.
|
|
2095 |
*/
|
|
2096 |
||
2097 |
static int fill_used_fields_bitmap(PARAM *param) |
|
2098 |
{
|
|
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
2099 |
Table *table= param->table; |
1005.2.3
by Monty Taylor
Further reversion of P. |
2100 |
my_bitmap_map *tmp; |
482
by Brian Aker
Remove uint. |
2101 |
uint32_t pk; |
1005.2.3
by Monty Taylor
Further reversion of P. |
2102 |
param->tmp_covered_fields.bitmap= 0; |
1
by brian
clean slate |
2103 |
param->fields_bitmap_size= table->s->column_bitmap_size; |
1005.2.3
by Monty Taylor
Further reversion of P. |
2104 |
if (!(tmp= (my_bitmap_map*) alloc_root(param->mem_root, |
2105 |
param->fields_bitmap_size)) || |
|
1014.2.12
by Monty Taylor
Removed the thread-safe crap in MY_BITMAP. Also remove the temp-pool option for |
2106 |
bitmap_init(¶m->needed_fields, tmp, table->s->fields)) |
1005.2.3
by Monty Taylor
Further reversion of P. |
2107 |
return 1; |
982.1.4
by Padraig O'Sullivan
More changes to some files to reflect the changes I've made by removing |
2108 |
|
1005.2.3
by Monty Taylor
Further reversion of P. |
2109 |
bitmap_copy(¶m->needed_fields, table->read_set); |
2110 |
bitmap_union(¶m->needed_fields, table->write_set); |
|
1
by brian
clean slate |
2111 |
|
2112 |
pk= param->table->s->primary_key; |
|
2113 |
if (pk != MAX_KEY && param->table->file->primary_key_is_clustered()) |
|
2114 |
{
|
|
2115 |
/* The table uses clustered PK and it is not internally generated */
|
|
2116 |
KEY_PART_INFO *key_part= param->table->key_info[pk].key_part; |
|
2117 |
KEY_PART_INFO *key_part_end= key_part + |
|
2118 |
param->table->key_info[pk].key_parts; |
|
2119 |
for (;key_part != key_part_end; ++key_part) |
|
1005.2.3
by Monty Taylor
Further reversion of P. |
2120 |
bitmap_clear_bit(¶m->needed_fields, key_part->fieldnr-1); |
1
by brian
clean slate |
2121 |
}
|
2122 |
return 0; |
|
2123 |
}
|
|
2124 |
||
2125 |
||
2126 |
/*
|
|
2127 |
Test if a key can be used in different ranges
|
|
2128 |
||
2129 |
SYNOPSIS
|
|
2130 |
SQL_SELECT::test_quick_select()
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2131 |
session Current thread
|
1
by brian
clean slate |
2132 |
keys_to_use Keys to use for range retrieval
|
2133 |
prev_tables Tables assumed to be already read when the scan is
|
|
2134 |
performed (but not read at the moment of this call)
|
|
2135 |
limit Query limit
|
|
2136 |
force_quick_range Prefer to use range (instead of full table scan) even
|
|
2137 |
if it is more expensive.
|
|
2138 |
||
2139 |
NOTES
|
|
2140 |
Updates the following in the select parameter:
|
|
2141 |
needed_reg - Bits for keys with may be used if all prev regs are read
|
|
2142 |
quick - Parameter to use when reading records.
|
|
2143 |
||
2144 |
In the table struct the following information is updated:
|
|
2145 |
quick_keys - Which keys can be used
|
|
2146 |
quick_rows - How many rows the key matches
|
|
2147 |
quick_condition_rows - E(# rows that will satisfy the table condition)
|
|
2148 |
||
2149 |
IMPLEMENTATION
|
|
2150 |
quick_condition_rows value is obtained as follows:
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2151 |
|
1
by brian
clean slate |
2152 |
It is a minimum of E(#output rows) for all considered table access
|
2153 |
methods (range and index_merge accesses over various indexes).
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2154 |
|
1
by brian
clean slate |
2155 |
The obtained value is not a true E(#rows that satisfy table condition)
|
2156 |
but rather a pessimistic estimate. To obtain a true E(#...) one would
|
|
2157 |
need to combine estimates of various access methods, taking into account
|
|
2158 |
correlations between sets of rows they will return.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2159 |
|
1
by brian
clean slate |
2160 |
For example, if values of tbl.key1 and tbl.key2 are independent (a right
|
2161 |
assumption if we have no information about their correlation) then the
|
|
2162 |
correct estimate will be:
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2163 |
|
2164 |
E(#rows("tbl.key1 < c1 AND tbl.key2 < c2")) =
|
|
1
by brian
clean slate |
2165 |
= E(#rows(tbl.key1 < c1)) / total_rows(tbl) * E(#rows(tbl.key2 < c2)
|
2166 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2167 |
which is smaller than
|
2168 |
||
1
by brian
clean slate |
2169 |
MIN(E(#rows(tbl.key1 < c1), E(#rows(tbl.key2 < c2)))
|
2170 |
||
2171 |
which is currently produced.
|
|
2172 |
||
2173 |
TODO
|
|
2174 |
* Change the value returned in quick_condition_rows from a pessimistic
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2175 |
estimate to true E(#rows that satisfy table condition).
|
2176 |
(we can re-use some of E(#rows) calcuation code from index_merge/intersection
|
|
1
by brian
clean slate |
2177 |
for this)
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2178 |
|
1
by brian
clean slate |
2179 |
* Check if this function really needs to modify keys_to_use, and change the
|
2180 |
code to pass it by reference if it doesn't.
|
|
2181 |
||
2182 |
* In addition to force_quick_range other means can be (an usually are) used
|
|
2183 |
to make this function prefer range over full table scan. Figure out if
|
|
2184 |
force_quick_range is really needed.
|
|
2185 |
||
2186 |
RETURN
|
|
2187 |
-1 if impossible select (i.e. certainly no rows will be selected)
|
|
2188 |
0 if can't use quick_select
|
|
2189 |
1 if found usable ranges and quick select has been successfully created.
|
|
2190 |
*/
|
|
2191 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
2192 |
int SQL_SELECT::test_quick_select(Session *session, key_map keys_to_use, |
1
by brian
clean slate |
2193 |
table_map prev_tables, |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2194 |
ha_rows limit, bool force_quick_range, |
1
by brian
clean slate |
2195 |
bool ordered_output) |
2196 |
{
|
|
482
by Brian Aker
Remove uint. |
2197 |
uint32_t idx; |
1
by brian
clean slate |
2198 |
double scan_time; |
2199 |
delete quick; |
|
2200 |
quick=0; |
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
2201 |
needed_reg.reset(); |
2202 |
quick_keys.reset(); |
|
2203 |
if (keys_to_use.none()) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
2204 |
return 0; |
1
by brian
clean slate |
2205 |
records= head->file->stats.records; |
2206 |
if (!records) |
|
2207 |
records++; /* purecov: inspected */ |
|
2208 |
scan_time= (double) records / TIME_FOR_COMPARE + 1; |
|
2209 |
read_time= (double) head->file->scan_time() + scan_time + 1.1; |
|
2210 |
if (head->force_index) |
|
2211 |
scan_time= read_time= DBL_MAX; |
|
2212 |
if (limit < records) |
|
2213 |
read_time= (double) records + scan_time + 1; // Force to use index |
|
2214 |
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 |
2215 |
return 0; /* No need for quick select */ |
1
by brian
clean slate |
2216 |
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
2217 |
keys_to_use&= head->keys_in_use_for_query; |
2218 |
if (keys_to_use.any()) |
|
1
by brian
clean slate |
2219 |
{
|
2220 |
MEM_ROOT alloc; |
|
2221 |
SEL_TREE *tree= NULL; |
|
2222 |
KEY_PART *key_parts; |
|
2223 |
KEY *key_info; |
|
2224 |
PARAM param; |
|
2225 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
2226 |
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 |
2227 |
return 0; // Fatal error flag is set |
1
by brian
clean slate |
2228 |
|
2229 |
/* set up parameter that is passed to all functions */
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2230 |
param.session= session; |
1
by brian
clean slate |
2231 |
param.baseflag= head->file->ha_table_flags(); |
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
2232 |
param.prev_tables= prev_tables | const_tables; |
2233 |
param.read_tables= read_tables; |
|
1
by brian
clean slate |
2234 |
param.current_table= head->map; |
2235 |
param.table=head; |
|
2236 |
param.keys=0; |
|
2237 |
param.mem_root= &alloc; |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2238 |
param.old_root= session->mem_root; |
1
by brian
clean slate |
2239 |
param.needed_reg= &needed_reg; |
2240 |
param.imerge_cost_buff_size= 0; |
|
55
by brian
Update for using real bool types. |
2241 |
param.using_real_indexes= true; |
2242 |
param.remove_jump_scans= true; |
|
1
by brian
clean slate |
2243 |
param.force_default_mrr= ordered_output; |
2244 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
2245 |
session->no_errors=1; // Don't warn about NULL |
2246 |
init_sql_alloc(&alloc, session->variables.range_alloc_block_size, 0); |
|
1
by brian
clean slate |
2247 |
if (!(param.key_parts= (KEY_PART*) alloc_root(&alloc, |
2248 |
sizeof(KEY_PART)* |
|
2249 |
head->s->key_parts)) || |
|
2250 |
fill_used_fields_bitmap(¶m)) |
|
2251 |
{
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2252 |
session->no_errors=0; |
1
by brian
clean slate |
2253 |
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 |
2254 |
return 0; // Can't use range |
1
by brian
clean slate |
2255 |
}
|
2256 |
key_parts= param.key_parts; |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2257 |
session->mem_root= &alloc; |
1
by brian
clean slate |
2258 |
|
2259 |
/*
|
|
2260 |
Make an array with description of all key parts of all table keys.
|
|
2261 |
This is used in get_mm_parts function.
|
|
2262 |
*/
|
|
2263 |
key_info= head->key_info; |
|
2264 |
for (idx=0 ; idx < head->s->keys ; idx++, key_info++) |
|
2265 |
{
|
|
2266 |
KEY_PART_INFO *key_part_info; |
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
2267 |
if (! keys_to_use.test(idx)) |
1
by brian
clean slate |
2268 |
continue; |
2269 |
||
2270 |
param.key[param.keys]=key_parts; |
|
2271 |
key_part_info= key_info->key_part; |
|
482
by Brian Aker
Remove uint. |
2272 |
for (uint32_t part=0 ; part < key_info->key_parts ; |
1
by brian
clean slate |
2273 |
part++, key_parts++, key_part_info++) |
2274 |
{
|
|
2275 |
key_parts->key= param.keys; |
|
2276 |
key_parts->part= part; |
|
2277 |
key_parts->length= key_part_info->length; |
|
2278 |
key_parts->store_length= key_part_info->store_length; |
|
2279 |
key_parts->field= key_part_info->field; |
|
2280 |
key_parts->null_bit= key_part_info->null_bit; |
|
2281 |
key_parts->image_type = Field::itRAW; |
|
2282 |
/* Only HA_PART_KEY_SEG is used */
|
|
206
by Brian Aker
Removed final uint dead types. |
2283 |
key_parts->flag= (uint8_t) key_part_info->key_part_flag; |
1
by brian
clean slate |
2284 |
}
|
2285 |
param.real_keynr[param.keys++]=idx; |
|
2286 |
}
|
|
2287 |
param.key_parts_end=key_parts; |
|
2288 |
param.alloced_sel_args= 0; |
|
2289 |
||
2290 |
/* Calculate cost of full index read for the shortest covering index */
|
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
2291 |
if (!head->covering_keys.none()) |
1
by brian
clean slate |
2292 |
{
|
355
by Brian Aker
More Table cleanup |
2293 |
int key_for_use= head->find_shortest_key(&head->covering_keys); |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2294 |
double key_read_time= |
2295 |
param.table->file->index_only_read_time(key_for_use, |
|
1
by brian
clean slate |
2296 |
rows2double(records)) + |
2297 |
(double) records / TIME_FOR_COMPARE; |
|
2298 |
if (key_read_time < read_time) |
|
2299 |
read_time= key_read_time; |
|
2300 |
}
|
|
2301 |
||
2302 |
TABLE_READ_PLAN *best_trp= NULL; |
|
2303 |
TRP_GROUP_MIN_MAX *group_trp; |
|
2304 |
double best_read_time= read_time; |
|
2305 |
||
2306 |
if (cond) |
|
2307 |
{
|
|
2308 |
if ((tree= get_mm_tree(¶m,cond))) |
|
2309 |
{
|
|
2310 |
if (tree->type == SEL_TREE::IMPOSSIBLE) |
|
2311 |
{
|
|
2312 |
records=0L; /* Return -1 from this function. */ |
|
2313 |
read_time= (double) HA_POS_ERROR; |
|
2314 |
goto free_mem; |
|
2315 |
}
|
|
2316 |
/*
|
|
2317 |
If the tree can't be used for range scans, proceed anyway, as we
|
|
2318 |
can construct a group-min-max quick select
|
|
2319 |
*/
|
|
2320 |
if (tree->type != SEL_TREE::KEY && tree->type != SEL_TREE::KEY_SMALLER) |
|
2321 |
tree= NULL; |
|
2322 |
}
|
|
2323 |
}
|
|
2324 |
||
2325 |
/*
|
|
2326 |
Try to construct a QUICK_GROUP_MIN_MAX_SELECT.
|
|
2327 |
Notice that it can be constructed no matter if there is a range tree.
|
|
2328 |
*/
|
|
2329 |
group_trp= get_best_group_min_max(¶m, tree); |
|
2330 |
if (group_trp) |
|
2331 |
{
|
|
398.1.4
by Monty Taylor
Renamed max/min. |
2332 |
param.table->quick_condition_rows= cmin(group_trp->records, |
1
by brian
clean slate |
2333 |
head->file->stats.records); |
2334 |
if (group_trp->read_cost < best_read_time) |
|
2335 |
{
|
|
2336 |
best_trp= group_trp; |
|
2337 |
best_read_time= best_trp->read_cost; |
|
2338 |
}
|
|
2339 |
}
|
|
2340 |
||
2341 |
if (tree) |
|
2342 |
{
|
|
2343 |
/*
|
|
2344 |
It is possible to use a range-based quick select (but it might be
|
|
2345 |
slower than 'all' table scan).
|
|
2346 |
*/
|
|
2347 |
if (tree->merges.is_empty()) |
|
2348 |
{
|
|
2349 |
TRP_RANGE *range_trp; |
|
2350 |
TRP_ROR_INTERSECT *rori_trp; |
|
55
by brian
Update for using real bool types. |
2351 |
bool can_build_covering= false; |
1
by brian
clean slate |
2352 |
|
2353 |
/* Get best 'range' plan and prepare data for making other plans */
|
|
55
by brian
Update for using real bool types. |
2354 |
if ((range_trp= get_key_scans_params(¶m, tree, false, true, |
1
by brian
clean slate |
2355 |
best_read_time))) |
2356 |
{
|
|
2357 |
best_trp= range_trp; |
|
2358 |
best_read_time= best_trp->read_cost; |
|
2359 |
}
|
|
2360 |
||
2361 |
/*
|
|
2362 |
Simultaneous key scans and row deletes on several handler
|
|
2363 |
objects are not allowed so don't use ROR-intersection for
|
|
2364 |
table deletes.
|
|
2365 |
*/
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2366 |
if ((session->lex->sql_command != SQLCOM_DELETE)) |
1
by brian
clean slate |
2367 |
{
|
2368 |
/*
|
|
2369 |
Get best non-covering ROR-intersection plan and prepare data for
|
|
2370 |
building covering ROR-intersection.
|
|
2371 |
*/
|
|
2372 |
if ((rori_trp= get_best_ror_intersect(¶m, tree, best_read_time, |
|
2373 |
&can_build_covering))) |
|
2374 |
{
|
|
2375 |
best_trp= rori_trp; |
|
2376 |
best_read_time= best_trp->read_cost; |
|
2377 |
/*
|
|
2378 |
Try constructing covering ROR-intersect only if it looks possible
|
|
2379 |
and worth doing.
|
|
2380 |
*/
|
|
2381 |
if (!rori_trp->is_covering && can_build_covering && |
|
2382 |
(rori_trp= get_best_covering_ror_intersect(¶m, tree, |
|
2383 |
best_read_time))) |
|
2384 |
best_trp= rori_trp; |
|
2385 |
}
|
|
2386 |
}
|
|
2387 |
}
|
|
2388 |
else
|
|
2389 |
{
|
|
2390 |
/* Try creating index_merge/ROR-union scan. */
|
|
2391 |
SEL_IMERGE *imerge; |
|
2392 |
TABLE_READ_PLAN *best_conj_trp= NULL, *new_conj_trp; |
|
2393 |
List_iterator_fast<SEL_IMERGE> it(tree->merges); |
|
2394 |
while ((imerge= it++)) |
|
2395 |
{
|
|
2396 |
new_conj_trp= get_best_disjunct_quick(¶m, imerge, best_read_time); |
|
2397 |
if (new_conj_trp) |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2398 |
set_if_smaller(param.table->quick_condition_rows, |
1
by brian
clean slate |
2399 |
new_conj_trp->records); |
2400 |
if (!best_conj_trp || (new_conj_trp && new_conj_trp->read_cost < |
|
2401 |
best_conj_trp->read_cost)) |
|
2402 |
best_conj_trp= new_conj_trp; |
|
2403 |
}
|
|
2404 |
if (best_conj_trp) |
|
2405 |
best_trp= best_conj_trp; |
|
2406 |
}
|
|
2407 |
}
|
|
2408 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
2409 |
session->mem_root= param.old_root; |
1
by brian
clean slate |
2410 |
|
2411 |
/* If we got a read plan, create a quick select from it. */
|
|
2412 |
if (best_trp) |
|
2413 |
{
|
|
2414 |
records= best_trp->records; |
|
55
by brian
Update for using real bool types. |
2415 |
if (!(quick= best_trp->make_quick(¶m, true)) || quick->init()) |
1
by brian
clean slate |
2416 |
{
|
2417 |
delete quick; |
|
2418 |
quick= NULL; |
|
2419 |
}
|
|
2420 |
}
|
|
2421 |
||
2422 |
free_mem: |
|
2423 |
free_root(&alloc,MYF(0)); // Return memory & allocator |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2424 |
session->mem_root= param.old_root; |
2425 |
session->no_errors=0; |
|
1
by brian
clean slate |
2426 |
}
|
2427 |
||
2428 |
/*
|
|
2429 |
Assume that if the user is using 'limit' we will only need to scan
|
|
2430 |
limit rows if we are using a key
|
|
2431 |
*/
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2432 |
return(records ? test(quick) : -1); |
1
by brian
clean slate |
2433 |
}
|
2434 |
||
2435 |
/*
|
|
2436 |
Get best plan for a SEL_IMERGE disjunctive expression.
|
|
2437 |
SYNOPSIS
|
|
2438 |
get_best_disjunct_quick()
|
|
2439 |
param Parameter from check_quick_select function
|
|
2440 |
imerge Expression to use
|
|
2441 |
read_time Don't create scans with cost > read_time
|
|
2442 |
||
2443 |
NOTES
|
|
2444 |
index_merge cost is calculated as follows:
|
|
2445 |
index_merge_cost =
|
|
2446 |
cost(index_reads) + (see #1)
|
|
2447 |
cost(rowid_to_row_scan) + (see #2)
|
|
2448 |
cost(unique_use) (see #3)
|
|
2449 |
||
2450 |
1. cost(index_reads) =SUM_i(cost(index_read_i))
|
|
2451 |
For non-CPK scans,
|
|
2452 |
cost(index_read_i) = {cost of ordinary 'index only' scan}
|
|
2453 |
For CPK scan,
|
|
2454 |
cost(index_read_i) = {cost of non-'index only' scan}
|
|
2455 |
||
2456 |
2. cost(rowid_to_row_scan)
|
|
2457 |
If table PK is clustered then
|
|
2458 |
cost(rowid_to_row_scan) =
|
|
2459 |
{cost of ordinary clustered PK scan with n_ranges=n_rows}
|
|
2460 |
||
2461 |
Otherwise, we use the following model to calculate costs:
|
|
2462 |
We need to retrieve n_rows rows from file that occupies n_blocks blocks.
|
|
2463 |
We assume that offsets of rows we need are independent variates with
|
|
2464 |
uniform distribution in [0..max_file_offset] range.
|
|
2465 |
||
2466 |
We'll denote block as "busy" if it contains row(s) we need to retrieve
|
|
2467 |
and "empty" if doesn't contain rows we need.
|
|
2468 |
||
2469 |
Probability that a block is empty is (1 - 1/n_blocks)^n_rows (this
|
|
2470 |
applies to any block in file). Let x_i be a variate taking value 1 if
|
|
2471 |
block #i is empty and 0 otherwise.
|
|
2472 |
||
2473 |
Then E(x_i) = (1 - 1/n_blocks)^n_rows;
|
|
2474 |
||
2475 |
E(n_empty_blocks) = E(sum(x_i)) = sum(E(x_i)) =
|
|
2476 |
= n_blocks * ((1 - 1/n_blocks)^n_rows) =
|
|
2477 |
~= n_blocks * exp(-n_rows/n_blocks).
|
|
2478 |
||
2479 |
E(n_busy_blocks) = n_blocks*(1 - (1 - 1/n_blocks)^n_rows) =
|
|
2480 |
~= n_blocks * (1 - exp(-n_rows/n_blocks)).
|
|
2481 |
||
2482 |
Average size of "hole" between neighbor non-empty blocks is
|
|
2483 |
E(hole_size) = n_blocks/E(n_busy_blocks).
|
|
2484 |
||
2485 |
The total cost of reading all needed blocks in one "sweep" is:
|
|
2486 |
||
2487 |
E(n_busy_blocks)*
|
|
2488 |
(DISK_SEEK_BASE_COST + DISK_SEEK_PROP_COST*n_blocks/E(n_busy_blocks)).
|
|
2489 |
||
2490 |
3. Cost of Unique use is calculated in Unique::get_use_cost function.
|
|
2491 |
||
2492 |
ROR-union cost is calculated in the same way index_merge, but instead of
|
|
2493 |
Unique a priority queue is used.
|
|
2494 |
||
2495 |
RETURN
|
|
2496 |
Created read plan
|
|
2497 |
NULL - Out of memory or no read scan could be built.
|
|
2498 |
*/
|
|
2499 |
||
2500 |
static
|
|
2501 |
TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, |
|
2502 |
double read_time) |
|
2503 |
{
|
|
2504 |
SEL_TREE **ptree; |
|
2505 |
TRP_INDEX_MERGE *imerge_trp= NULL; |
|
482
by Brian Aker
Remove uint. |
2506 |
uint32_t n_child_scans= imerge->trees_next - imerge->trees; |
1
by brian
clean slate |
2507 |
TRP_RANGE **range_scans; |
2508 |
TRP_RANGE **cur_child; |
|
2509 |
TRP_RANGE **cpk_scan= NULL; |
|
55
by brian
Update for using real bool types. |
2510 |
bool imerge_too_expensive= false; |
1
by brian
clean slate |
2511 |
double imerge_cost= 0.0; |
2512 |
ha_rows cpk_scan_records= 0; |
|
2513 |
ha_rows non_cpk_scan_records= 0; |
|
2514 |
bool pk_is_clustered= param->table->file->primary_key_is_clustered(); |
|
55
by brian
Update for using real bool types. |
2515 |
bool all_scans_ror_able= true; |
2516 |
bool all_scans_rors= true; |
|
482
by Brian Aker
Remove uint. |
2517 |
uint32_t unique_calc_buff_size; |
1
by brian
clean slate |
2518 |
TABLE_READ_PLAN **roru_read_plans; |
2519 |
TABLE_READ_PLAN **cur_roru_plan; |
|
2520 |
double roru_index_costs; |
|
2521 |
ha_rows roru_total_records; |
|
2522 |
double roru_intersect_part= 1.0; |
|
2523 |
||
2524 |
if (!(range_scans= (TRP_RANGE**)alloc_root(param->mem_root, |
|
2525 |
sizeof(TRP_RANGE*)* |
|
2526 |
n_child_scans))) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
2527 |
return NULL; |
1
by brian
clean slate |
2528 |
/*
|
2529 |
Collect best 'range' scan for each of disjuncts, and, while doing so,
|
|
2530 |
analyze possibility of ROR scans. Also calculate some values needed by
|
|
2531 |
other parts of the code.
|
|
2532 |
*/
|
|
2533 |
for (ptree= imerge->trees, cur_child= range_scans; |
|
2534 |
ptree != imerge->trees_next; |
|
2535 |
ptree++, cur_child++) |
|
2536 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2537 |
print_sel_tree(param, *ptree, &(*ptree)->keys_map, "tree in SEL_IMERGE"); |
55
by brian
Update for using real bool types. |
2538 |
if (!(*cur_child= get_key_scans_params(param, *ptree, true, false, read_time))) |
1
by brian
clean slate |
2539 |
{
|
2540 |
/*
|
|
2541 |
One of index scans in this index_merge is more expensive than entire
|
|
2542 |
table read for another available option. The entire index_merge (and
|
|
2543 |
any possible ROR-union) will be more expensive then, too. We continue
|
|
2544 |
here only to update SQL_SELECT members.
|
|
2545 |
*/
|
|
55
by brian
Update for using real bool types. |
2546 |
imerge_too_expensive= true; |
1
by brian
clean slate |
2547 |
}
|
2548 |
if (imerge_too_expensive) |
|
2549 |
continue; |
|
2550 |
||
2551 |
imerge_cost += (*cur_child)->read_cost; |
|
2552 |
all_scans_ror_able &= ((*ptree)->n_ror_scans > 0); |
|
2553 |
all_scans_rors &= (*cur_child)->is_ror; |
|
2554 |
if (pk_is_clustered && |
|
2555 |
param->real_keynr[(*cur_child)->key_idx] == |
|
2556 |
param->table->s->primary_key) |
|
2557 |
{
|
|
2558 |
cpk_scan= cur_child; |
|
2559 |
cpk_scan_records= (*cur_child)->records; |
|
2560 |
}
|
|
2561 |
else
|
|
2562 |
non_cpk_scan_records += (*cur_child)->records; |
|
2563 |
}
|
|
2564 |
||
2565 |
if (imerge_too_expensive || (imerge_cost > read_time) || |
|
2566 |
((non_cpk_scan_records+cpk_scan_records >= param->table->file->stats.records) && read_time != DBL_MAX)) |
|
2567 |
{
|
|
2568 |
/*
|
|
2569 |
Bail out if it is obvious that both index_merge and ROR-union will be
|
|
2570 |
more expensive
|
|
2571 |
*/
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
2572 |
return NULL; |
1
by brian
clean slate |
2573 |
}
|
2574 |
if (all_scans_rors) |
|
2575 |
{
|
|
2576 |
roru_read_plans= (TABLE_READ_PLAN**)range_scans; |
|
2577 |
goto skip_to_ror_scan; |
|
2578 |
}
|
|
2579 |
if (cpk_scan) |
|
2580 |
{
|
|
2581 |
/*
|
|
2582 |
Add one ROWID comparison for each row retrieved on non-CPK scan. (it
|
|
2583 |
is done in QUICK_RANGE_SELECT::row_in_ranges)
|
|
2584 |
*/
|
|
2585 |
imerge_cost += non_cpk_scan_records / TIME_FOR_COMPARE_ROWID; |
|
2586 |
}
|
|
2587 |
||
2588 |
/* Calculate cost(rowid_to_row_scan) */
|
|
2589 |
{
|
|
2590 |
COST_VECT sweep_cost; |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2591 |
JOIN *join= param->session->lex->select_lex.join; |
1
by brian
clean slate |
2592 |
bool is_interrupted= test(join && join->tables == 1); |
2593 |
get_sweep_read_cost(param->table, non_cpk_scan_records, is_interrupted, |
|
2594 |
&sweep_cost); |
|
2595 |
imerge_cost += sweep_cost.total_cost(); |
|
2596 |
}
|
|
2597 |
if (imerge_cost > read_time) |
|
2598 |
goto build_ror_index_merge; |
|
2599 |
||
2600 |
/* Add Unique operations cost */
|
|
2601 |
unique_calc_buff_size= |
|
2602 |
Unique::get_cost_calc_buff_size((ulong)non_cpk_scan_records, |
|
2603 |
param->table->file->ref_length, |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2604 |
param->session->variables.sortbuff_size); |
1
by brian
clean slate |
2605 |
if (param->imerge_cost_buff_size < unique_calc_buff_size) |
2606 |
{
|
|
2607 |
if (!(param->imerge_cost_buff= (uint*)alloc_root(param->mem_root, |
|
2608 |
unique_calc_buff_size))) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
2609 |
return NULL; |
1
by brian
clean slate |
2610 |
param->imerge_cost_buff_size= unique_calc_buff_size; |
2611 |
}
|
|
2612 |
||
2613 |
imerge_cost += |
|
895
by Brian Aker
Completion (?) of uint conversion. |
2614 |
Unique::get_use_cost(param->imerge_cost_buff, (uint32_t)non_cpk_scan_records, |
1
by brian
clean slate |
2615 |
param->table->file->ref_length, |
520.1.22
by Brian Aker
Second pass of thd cleanup |
2616 |
param->session->variables.sortbuff_size); |
1
by brian
clean slate |
2617 |
if (imerge_cost < read_time) |
2618 |
{
|
|
2619 |
if ((imerge_trp= new (param->mem_root)TRP_INDEX_MERGE)) |
|
2620 |
{
|
|
2621 |
imerge_trp->read_cost= imerge_cost; |
|
2622 |
imerge_trp->records= non_cpk_scan_records + cpk_scan_records; |
|
398.1.4
by Monty Taylor
Renamed max/min. |
2623 |
imerge_trp->records= cmin(imerge_trp->records, |
1
by brian
clean slate |
2624 |
param->table->file->stats.records); |
2625 |
imerge_trp->range_scans= range_scans; |
|
2626 |
imerge_trp->range_scans_end= range_scans + n_child_scans; |
|
2627 |
read_time= imerge_cost; |
|
2628 |
}
|
|
2629 |
}
|
|
2630 |
||
2631 |
build_ror_index_merge: |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2632 |
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. |
2633 |
return(imerge_trp); |
1
by brian
clean slate |
2634 |
|
2635 |
/* Ok, it is possible to build a ROR-union, try it. */
|
|
2636 |
bool dummy; |
|
2637 |
if (!(roru_read_plans= |
|
2638 |
(TABLE_READ_PLAN**)alloc_root(param->mem_root, |
|
2639 |
sizeof(TABLE_READ_PLAN*)* |
|
2640 |
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. |
2641 |
return(imerge_trp); |
1
by brian
clean slate |
2642 |
skip_to_ror_scan: |
2643 |
roru_index_costs= 0.0; |
|
2644 |
roru_total_records= 0; |
|
2645 |
cur_roru_plan= roru_read_plans; |
|
2646 |
||
2647 |
/* Find 'best' ROR scan for each of trees in disjunction */
|
|
2648 |
for (ptree= imerge->trees, cur_child= range_scans; |
|
2649 |
ptree != imerge->trees_next; |
|
2650 |
ptree++, cur_child++, cur_roru_plan++) |
|
2651 |
{
|
|
2652 |
/*
|
|
2653 |
Assume the best ROR scan is the one that has cheapest full-row-retrieval
|
|
2654 |
scan cost.
|
|
2655 |
Also accumulate index_only scan costs as we'll need them to calculate
|
|
2656 |
overall index_intersection cost.
|
|
2657 |
*/
|
|
2658 |
double cost; |
|
2659 |
if ((*cur_child)->is_ror) |
|
2660 |
{
|
|
2661 |
/* Ok, we have index_only cost, now get full rows scan cost */
|
|
2662 |
cost= param->table->file-> |
|
2663 |
read_time(param->real_keynr[(*cur_child)->key_idx], 1, |
|
2664 |
(*cur_child)->records) + |
|
2665 |
rows2double((*cur_child)->records) / TIME_FOR_COMPARE; |
|
2666 |
}
|
|
2667 |
else
|
|
2668 |
cost= read_time; |
|
2669 |
||
2670 |
TABLE_READ_PLAN *prev_plan= *cur_child; |
|
2671 |
if (!(*cur_roru_plan= get_best_ror_intersect(param, *ptree, cost, |
|
2672 |
&dummy))) |
|
2673 |
{
|
|
2674 |
if (prev_plan->is_ror) |
|
2675 |
*cur_roru_plan= prev_plan; |
|
2676 |
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. |
2677 |
return(imerge_trp); |
1
by brian
clean slate |
2678 |
roru_index_costs += (*cur_roru_plan)->read_cost; |
2679 |
}
|
|
2680 |
else
|
|
2681 |
roru_index_costs += |
|
2682 |
((TRP_ROR_INTERSECT*)(*cur_roru_plan))->index_scan_costs; |
|
2683 |
roru_total_records += (*cur_roru_plan)->records; |
|
2684 |
roru_intersect_part *= (*cur_roru_plan)->records / |
|
2685 |
param->table->file->stats.records; |
|
2686 |
}
|
|
2687 |
||
2688 |
/*
|
|
2689 |
rows to retrieve=
|
|
2690 |
SUM(rows_in_scan_i) - table_rows * PROD(rows_in_scan_i / table_rows).
|
|
2691 |
This is valid because index_merge construction guarantees that conditions
|
|
2692 |
in disjunction do not share key parts.
|
|
2693 |
*/
|
|
2694 |
roru_total_records -= (ha_rows)(roru_intersect_part* |
|
2695 |
param->table->file->stats.records); |
|
2696 |
/* ok, got a ROR read plan for each of the disjuncts
|
|
2697 |
Calculate cost:
|
|
2698 |
cost(index_union_scan(scan_1, ... scan_n)) =
|
|
2699 |
SUM_i(cost_of_index_only_scan(scan_i)) +
|
|
2700 |
queue_use_cost(rowid_len, n) +
|
|
2701 |
cost_of_row_retrieval
|
|
2702 |
See get_merge_buffers_cost function for queue_use_cost formula derivation.
|
|
2703 |
*/
|
|
2704 |
double roru_total_cost; |
|
2705 |
{
|
|
2706 |
COST_VECT sweep_cost; |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
2707 |
JOIN *join= param->session->lex->select_lex.join; |
1
by brian
clean slate |
2708 |
bool is_interrupted= test(join && join->tables == 1); |
2709 |
get_sweep_read_cost(param->table, roru_total_records, is_interrupted, |
|
2710 |
&sweep_cost); |
|
2711 |
roru_total_cost= roru_index_costs + |
|
2712 |
rows2double(roru_total_records)*log((double)n_child_scans) / |
|
2713 |
(TIME_FOR_COMPARE_ROWID * M_LN2) + |
|
2714 |
sweep_cost.total_cost(); |
|
2715 |
}
|
|
2716 |
||
2717 |
TRP_ROR_UNION* roru; |
|
2718 |
if (roru_total_cost < read_time) |
|
2719 |
{
|
|
2720 |
if ((roru= new (param->mem_root) TRP_ROR_UNION)) |
|
2721 |
{
|
|
2722 |
roru->first_ror= roru_read_plans; |
|
2723 |
roru->last_ror= roru_read_plans + n_child_scans; |
|
2724 |
roru->read_cost= roru_total_cost; |
|
2725 |
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. |
2726 |
return(roru); |
1
by brian
clean slate |
2727 |
}
|
2728 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
2729 |
return(imerge_trp); |
1
by brian
clean slate |
2730 |
}
|
2731 |
||
2732 |
||
2733 |
typedef struct st_ror_scan_info |
|
2734 |
{
|
|
482
by Brian Aker
Remove uint. |
2735 |
uint32_t idx; /* # of used key in param->keys */ |
2736 |
uint32_t keynr; /* # of used key in table */ |
|
1
by brian
clean slate |
2737 |
ha_rows records; /* estimate of # records this scan will return */ |
2738 |
||
2739 |
/* Set of intervals over key fields that will be used for row retrieval. */
|
|
2740 |
SEL_ARG *sel_arg; |
|
2741 |
||
2742 |
/* Fields used in the query and covered by this ROR scan. */
|
|
1005.2.3
by Monty Taylor
Further reversion of P. |
2743 |
MY_BITMAP covered_fields; |
482
by Brian Aker
Remove uint. |
2744 |
uint32_t used_fields_covered; /* # of set bits in covered_fields */ |
1
by brian
clean slate |
2745 |
int key_rec_length; /* length of key record (including rowid) */ |
2746 |
||
2747 |
/*
|
|
2748 |
Cost of reading all index records with values in sel_arg intervals set
|
|
2749 |
(assuming there is no need to access full table records)
|
|
2750 |
*/
|
|
2751 |
double index_read_cost; |
|
482
by Brian Aker
Remove uint. |
2752 |
uint32_t first_uncovered_field; /* first unused bit in covered_fields */ |
2753 |
uint32_t key_components; /* # of parts in the key */ |
|
1
by brian
clean slate |
2754 |
} ROR_SCAN_INFO; |
2755 |
||
2756 |
||
2757 |
/*
|
|
2758 |
Create ROR_SCAN_INFO* structure with a single ROR scan on index idx using
|
|
2759 |
sel_arg set of intervals.
|
|
2760 |
||
2761 |
SYNOPSIS
|
|
2762 |
make_ror_scan()
|
|
2763 |
param Parameter from test_quick_select function
|
|
2764 |
idx Index of key in param->keys
|
|
2765 |
sel_arg Set of intervals for a given key
|
|
2766 |
||
2767 |
RETURN
|
|
2768 |
NULL - out of memory
|
|
2769 |
ROR scan structure containing a scan for {idx, sel_arg}
|
|
2770 |
*/
|
|
2771 |
||
2772 |
static
|
|
2773 |
ROR_SCAN_INFO *make_ror_scan(const PARAM *param, int idx, SEL_ARG *sel_arg) |
|
2774 |
{
|
|
2775 |
ROR_SCAN_INFO *ror_scan; |
|
1005.2.1
by Monty Taylor
Reverted a crap-ton of padraig's work. |
2776 |
my_bitmap_map *bitmap_buf; |
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
2777 |
|
482
by Brian Aker
Remove uint. |
2778 |
uint32_t keynr; |
1
by brian
clean slate |
2779 |
|
2780 |
if (!(ror_scan= (ROR_SCAN_INFO*)alloc_root(param->mem_root, |
|
2781 |
sizeof(ROR_SCAN_INFO)))) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
2782 |
return NULL; |
1
by brian
clean slate |
2783 |
|
2784 |
ror_scan->idx= idx; |
|
2785 |
ror_scan->keynr= keynr= param->real_keynr[idx]; |
|
2786 |
ror_scan->key_rec_length= (param->table->key_info[keynr].key_length + |
|
2787 |
param->table->file->ref_length); |
|
2788 |
ror_scan->sel_arg= sel_arg; |
|
2789 |
ror_scan->records= param->table->quick_rows[keynr]; |
|
1005.2.1
by Monty Taylor
Reverted a crap-ton of padraig's work. |
2790 |
|
2791 |
if (!(bitmap_buf= (my_bitmap_map*) alloc_root(param->mem_root, |
|
2792 |
param->fields_bitmap_size))) |
|
2793 |
return NULL; |
|
2794 |
||
1005.2.3
by Monty Taylor
Further reversion of P. |
2795 |
if (bitmap_init(&ror_scan->covered_fields, bitmap_buf, |
1014.2.12
by Monty Taylor
Removed the thread-safe crap in MY_BITMAP. Also remove the temp-pool option for |
2796 |
param->table->s->fields)) |
1005.2.3
by Monty Taylor
Further reversion of P. |
2797 |
return NULL; |
2798 |
bitmap_clear_all(&ror_scan->covered_fields); |
|
1
by brian
clean slate |
2799 |
|
2800 |
KEY_PART_INFO *key_part= param->table->key_info[keynr].key_part; |
|
2801 |
KEY_PART_INFO *key_part_end= key_part + |
|
2802 |
param->table->key_info[keynr].key_parts; |
|
2803 |
for (;key_part != key_part_end; ++key_part) |
|
2804 |
{
|
|
1005.2.3
by Monty Taylor
Further reversion of P. |
2805 |
if (bitmap_is_set(¶m->needed_fields, key_part->fieldnr-1)) |
2806 |
bitmap_set_bit(&ror_scan->covered_fields, key_part->fieldnr-1); |
|
1
by brian
clean slate |
2807 |
}
|
2808 |
double rows= rows2double(param->table->quick_rows[ror_scan->keynr]); |
|
2809 |
ror_scan->index_read_cost= |
|
2810 |
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. |
2811 |
return(ror_scan); |
1
by brian
clean slate |
2812 |
}
|
2813 |
||
2814 |
||
2815 |
/*
|
|
2816 |
Compare two ROR_SCAN_INFO** by E(#records_matched) * key_record_length.
|
|
2817 |
SYNOPSIS
|
|
2818 |
cmp_ror_scan_info()
|
|
2819 |
a ptr to first compared value
|
|
2820 |
b ptr to second compared value
|
|
2821 |
||
2822 |
RETURN
|
|
2823 |
-1 a < b
|
|
2824 |
0 a = b
|
|
2825 |
1 a > b
|
|
2826 |
*/
|
|
2827 |
||
2828 |
static int cmp_ror_scan_info(ROR_SCAN_INFO** a, ROR_SCAN_INFO** b) |
|
2829 |
{
|
|
2830 |
double val1= rows2double((*a)->records) * (*a)->key_rec_length; |
|
2831 |
double val2= rows2double((*b)->records) * (*b)->key_rec_length; |
|
2832 |
return (val1 < val2)? -1: (val1 == val2)? 0 : 1; |
|
2833 |
}
|
|
2834 |
||
2835 |
/*
|
|
2836 |
Compare two ROR_SCAN_INFO** by
|
|
2837 |
(#covered fields in F desc,
|
|
2838 |
#components asc,
|
|
2839 |
number of first not covered component asc)
|
|
2840 |
||
2841 |
SYNOPSIS
|
|
2842 |
cmp_ror_scan_info_covering()
|
|
2843 |
a ptr to first compared value
|
|
2844 |
b ptr to second compared value
|
|
2845 |
||
2846 |
RETURN
|
|
2847 |
-1 a < b
|
|
2848 |
0 a = b
|
|
2849 |
1 a > b
|
|
2850 |
*/
|
|
2851 |
||
2852 |
static int cmp_ror_scan_info_covering(ROR_SCAN_INFO** a, ROR_SCAN_INFO** b) |
|
2853 |
{
|
|
2854 |
if ((*a)->used_fields_covered > (*b)->used_fields_covered) |
|
2855 |
return -1; |
|
2856 |
if ((*a)->used_fields_covered < (*b)->used_fields_covered) |
|
2857 |
return 1; |
|
2858 |
if ((*a)->key_components < (*b)->key_components) |
|
2859 |
return -1; |
|
2860 |
if ((*a)->key_components > (*b)->key_components) |
|
2861 |
return 1; |
|
2862 |
if ((*a)->first_uncovered_field < (*b)->first_uncovered_field) |
|
2863 |
return -1; |
|
2864 |
if ((*a)->first_uncovered_field > (*b)->first_uncovered_field) |
|
2865 |
return 1; |
|
2866 |
return 0; |
|
2867 |
}
|
|
2868 |
||
2869 |
||
2870 |
/* Auxiliary structure for incremental ROR-intersection creation */
|
|
2871 |
typedef struct |
|
2872 |
{
|
|
2873 |
const PARAM *param; |
|
1005.2.3
by Monty Taylor
Further reversion of P. |
2874 |
MY_BITMAP covered_fields; /* union of fields covered by all scans */ |
1
by brian
clean slate |
2875 |
/*
|
2876 |
Fraction of table records that satisfies conditions of all scans.
|
|
2877 |
This is the number of full records that will be retrieved if a
|
|
2878 |
non-index_only index intersection will be employed.
|
|
2879 |
*/
|
|
2880 |
double out_rows; |
|
55
by brian
Update for using real bool types. |
2881 |
/* true if covered_fields is a superset of needed_fields */
|
1
by brian
clean slate |
2882 |
bool is_covering; |
2883 |
||
2884 |
ha_rows index_records; /* sum(#records to look in indexes) */ |
|
2885 |
double index_scan_costs; /* SUM(cost of 'index-only' scans) */ |
|
2886 |
double total_cost; |
|
2887 |
} ROR_INTERSECT_INFO; |
|
2888 |
||
2889 |
||
2890 |
/*
|
|
2891 |
Allocate a ROR_INTERSECT_INFO and initialize it to contain zero scans.
|
|
2892 |
||
2893 |
SYNOPSIS
|
|
2894 |
ror_intersect_init()
|
|
2895 |
param Parameter from test_quick_select
|
|
2896 |
||
2897 |
RETURN
|
|
2898 |
allocated structure
|
|
2899 |
NULL on error
|
|
2900 |
*/
|
|
2901 |
||
2902 |
static
|
|
2903 |
ROR_INTERSECT_INFO* ror_intersect_init(const PARAM *param) |
|
2904 |
{
|
|
2905 |
ROR_INTERSECT_INFO *info; |
|
1005.2.3
by Monty Taylor
Further reversion of P. |
2906 |
my_bitmap_map* buf; |
1
by brian
clean slate |
2907 |
if (!(info= (ROR_INTERSECT_INFO*)alloc_root(param->mem_root, |
2908 |
sizeof(ROR_INTERSECT_INFO)))) |
|
2909 |
return NULL; |
|
2910 |
info->param= param; |
|
1005.2.3
by Monty Taylor
Further reversion of P. |
2911 |
if (!(buf= (my_bitmap_map*) alloc_root(param->mem_root, |
2912 |
param->fields_bitmap_size))) |
|
2913 |
return NULL; |
|
1014.2.12
by Monty Taylor
Removed the thread-safe crap in MY_BITMAP. Also remove the temp-pool option for |
2914 |
if (bitmap_init(&info->covered_fields, buf, param->table->s->fields)) |
1005.2.3
by Monty Taylor
Further reversion of P. |
2915 |
return NULL; |
55
by brian
Update for using real bool types. |
2916 |
info->is_covering= false; |
1
by brian
clean slate |
2917 |
info->index_scan_costs= 0.0; |
2918 |
info->index_records= 0; |
|
2919 |
info->out_rows= (double) param->table->file->stats.records; |
|
1005.2.3
by Monty Taylor
Further reversion of P. |
2920 |
bitmap_clear_all(&info->covered_fields); |
1
by brian
clean slate |
2921 |
return info; |
2922 |
}
|
|
2923 |
||
2924 |
void ror_intersect_cpy(ROR_INTERSECT_INFO *dst, const ROR_INTERSECT_INFO *src) |
|
2925 |
{
|
|
2926 |
dst->param= src->param; |
|
1005.2.3
by Monty Taylor
Further reversion of P. |
2927 |
memcpy(dst->covered_fields.bitmap, src->covered_fields.bitmap, |
2928 |
no_bytes_in_map(&src->covered_fields)); |
|
1
by brian
clean slate |
2929 |
dst->out_rows= src->out_rows; |
2930 |
dst->is_covering= src->is_covering; |
|
2931 |
dst->index_records= src->index_records; |
|
2932 |
dst->index_scan_costs= src->index_scan_costs; |
|
2933 |
dst->total_cost= src->total_cost; |
|
2934 |
}
|
|
2935 |
||
2936 |
||
2937 |
/*
|
|
2938 |
Get selectivity of a ROR scan wrt ROR-intersection.
|
|
2939 |
||
2940 |
SYNOPSIS
|
|
2941 |
ror_scan_selectivity()
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2942 |
info ROR-interection
|
1
by brian
clean slate |
2943 |
scan ROR scan
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2944 |
|
1
by brian
clean slate |
2945 |
NOTES
|
2946 |
Suppose we have a condition on several keys
|
|
2947 |
cond=k_11=c_11 AND k_12=c_12 AND ... // parts of first key
|
|
2948 |
k_21=c_21 AND k_22=c_22 AND ... // parts of second key
|
|
2949 |
...
|
|
2950 |
k_n1=c_n1 AND k_n3=c_n3 AND ... (1) //parts of the key used by *scan
|
|
2951 |
||
2952 |
where k_ij may be the same as any k_pq (i.e. keys may have common parts).
|
|
2953 |
||
2954 |
A full row is retrieved if entire condition holds.
|
|
2955 |
||
2956 |
The recursive procedure for finding P(cond) is as follows:
|
|
2957 |
||
2958 |
First step:
|
|
2959 |
Pick 1st part of 1st key and break conjunction (1) into two parts:
|
|
2960 |
cond= (k_11=c_11 AND R)
|
|
2961 |
||
2962 |
Here R may still contain condition(s) equivalent to k_11=c_11.
|
|
2963 |
Nevertheless, the following holds:
|
|
2964 |
||
2965 |
P(k_11=c_11 AND R) = P(k_11=c_11) * P(R | k_11=c_11).
|
|
2966 |
||
2967 |
Mark k_11 as fixed field (and satisfied condition) F, save P(F),
|
|
2968 |
save R to be cond and proceed to recursion step.
|
|
2969 |
||
2970 |
Recursion step:
|
|
2971 |
We have a set of fixed fields/satisfied conditions) F, probability P(F),
|
|
2972 |
and remaining conjunction R
|
|
2973 |
Pick next key part on current key and its condition "k_ij=c_ij".
|
|
2974 |
We will add "k_ij=c_ij" into F and update P(F).
|
|
2975 |
Lets denote k_ij as t, R = t AND R1, where R1 may still contain t. Then
|
|
2976 |
||
2977 |
P((t AND R1)|F) = P(t|F) * P(R1|t|F) = P(t|F) * P(R1|(t AND F)) (2)
|
|
2978 |
||
2979 |
(where '|' mean conditional probability, not "or")
|
|
2980 |
||
2981 |
Consider the first multiplier in (2). One of the following holds:
|
|
2982 |
a) F contains condition on field used in t (i.e. t AND F = F).
|
|
2983 |
Then P(t|F) = 1
|
|
2984 |
||
2985 |
b) F doesn't contain condition on field used in t. Then F and t are
|
|
2986 |
considered independent.
|
|
2987 |
||
2988 |
P(t|F) = P(t|(fields_before_t_in_key AND other_fields)) =
|
|
2989 |
= P(t|fields_before_t_in_key).
|
|
2990 |
||
2991 |
P(t|fields_before_t_in_key) = #records(fields_before_t_in_key) /
|
|
2992 |
#records(fields_before_t_in_key, t)
|
|
2993 |
||
2994 |
The second multiplier is calculated by applying this step recursively.
|
|
2995 |
||
2996 |
IMPLEMENTATION
|
|
2997 |
This function calculates the result of application of the "recursion step"
|
|
2998 |
described above for all fixed key members of a single key, accumulating set
|
|
2999 |
of covered fields, selectivity, etc.
|
|
3000 |
||
3001 |
The calculation is conducted as follows:
|
|
3002 |
Lets denote #records(keypart1, ... keypartK) as n_k. We need to calculate
|
|
3003 |
||
3004 |
n_{k1} n_{k2}
|
|
3005 |
--------- * --------- * .... (3)
|
|
3006 |
n_{k1-1} n_{k2-1}
|
|
3007 |
||
3008 |
where k1,k2,... are key parts which fields were not yet marked as fixed
|
|
3009 |
( this is result of application of option b) of the recursion step for
|
|
3010 |
parts of a single key).
|
|
3011 |
Since it is reasonable to expect that most of the fields are not marked
|
|
3012 |
as fixed, we calculate (3) as
|
|
3013 |
||
3014 |
n_{i1} n_{i2}
|
|
3015 |
(3) = n_{max_key_part} / ( --------- * --------- * .... )
|
|
3016 |
n_{i1-1} n_{i2-1}
|
|
3017 |
||
3018 |
where i1,i2, .. are key parts that were already marked as fixed.
|
|
3019 |
||
3020 |
In order to minimize number of expensive records_in_range calls we group
|
|
3021 |
and reduce adjacent fractions.
|
|
3022 |
||
3023 |
RETURN
|
|
3024 |
Selectivity of given ROR scan.
|
|
3025 |
*/
|
|
3026 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3027 |
static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info, |
1
by brian
clean slate |
3028 |
const ROR_SCAN_INFO *scan) |
3029 |
{
|
|
3030 |
double selectivity_mult= 1.0; |
|
3031 |
KEY_PART_INFO *key_part= info->param->table->key_info[scan->keynr].key_part; |
|
481
by Brian Aker
Remove all of uchar. |
3032 |
unsigned char key_val[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; /* key values tuple */ |
3033 |
unsigned char *key_ptr= key_val; |
|
1
by brian
clean slate |
3034 |
SEL_ARG *sel_arg, *tuple_arg= NULL; |
3035 |
key_part_map keypart_map= 0; |
|
3036 |
bool cur_covered; |
|
1005.2.3
by Monty Taylor
Further reversion of P. |
3037 |
bool prev_covered= test(bitmap_is_set(&info->covered_fields, |
3038 |
key_part->fieldnr-1)); |
|
1
by brian
clean slate |
3039 |
key_range min_range; |
3040 |
key_range max_range; |
|
3041 |
min_range.key= key_val; |
|
3042 |
min_range.flag= HA_READ_KEY_EXACT; |
|
3043 |
max_range.key= key_val; |
|
3044 |
max_range.flag= HA_READ_AFTER_KEY; |
|
3045 |
ha_rows prev_records= info->param->table->file->stats.records; |
|
3046 |
||
3047 |
for (sel_arg= scan->sel_arg; sel_arg; |
|
3048 |
sel_arg= sel_arg->next_key_part) |
|
3049 |
{
|
|
1005.2.3
by Monty Taylor
Further reversion of P. |
3050 |
cur_covered= test(bitmap_is_set(&info->covered_fields, |
3051 |
key_part[sel_arg->part].fieldnr-1)); |
|
1
by brian
clean slate |
3052 |
if (cur_covered != prev_covered) |
3053 |
{
|
|
3054 |
/* create (part1val, ..., part{n-1}val) tuple. */
|
|
3055 |
ha_rows records; |
|
3056 |
if (!tuple_arg) |
|
3057 |
{
|
|
3058 |
tuple_arg= scan->sel_arg; |
|
3059 |
/* Here we use the length of the first key part */
|
|
3060 |
tuple_arg->store_min(key_part->store_length, &key_ptr, 0); |
|
3061 |
keypart_map= 1; |
|
3062 |
}
|
|
3063 |
while (tuple_arg->next_key_part != sel_arg) |
|
3064 |
{
|
|
3065 |
tuple_arg= tuple_arg->next_key_part; |
|
3066 |
tuple_arg->store_min(key_part[tuple_arg->part].store_length, |
|
3067 |
&key_ptr, 0); |
|
3068 |
keypart_map= (keypart_map << 1) | 1; |
|
3069 |
}
|
|
3070 |
min_range.length= max_range.length= (size_t) (key_ptr - key_val); |
|
3071 |
min_range.keypart_map= max_range.keypart_map= keypart_map; |
|
3072 |
records= (info->param->table->file-> |
|
3073 |
records_in_range(scan->keynr, &min_range, &max_range)); |
|
3074 |
if (cur_covered) |
|
3075 |
{
|
|
3076 |
/* uncovered -> covered */
|
|
3077 |
double tmp= rows2double(records)/rows2double(prev_records); |
|
3078 |
selectivity_mult *= tmp; |
|
3079 |
prev_records= HA_POS_ERROR; |
|
3080 |
}
|
|
3081 |
else
|
|
3082 |
{
|
|
3083 |
/* covered -> uncovered */
|
|
3084 |
prev_records= records; |
|
3085 |
}
|
|
3086 |
}
|
|
3087 |
prev_covered= cur_covered; |
|
3088 |
}
|
|
3089 |
if (!prev_covered) |
|
3090 |
{
|
|
3091 |
double tmp= rows2double(info->param->table->quick_rows[scan->keynr]) / |
|
3092 |
rows2double(prev_records); |
|
3093 |
selectivity_mult *= tmp; |
|
3094 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3095 |
return(selectivity_mult); |
1
by brian
clean slate |
3096 |
}
|
3097 |
||
3098 |
||
3099 |
/*
|
|
3100 |
Check if adding a ROR scan to a ROR-intersection reduces its cost of
|
|
3101 |
ROR-intersection and if yes, update parameters of ROR-intersection,
|
|
3102 |
including its cost.
|
|
3103 |
||
3104 |
SYNOPSIS
|
|
3105 |
ror_intersect_add()
|
|
3106 |
param Parameter from test_quick_select
|
|
3107 |
info ROR-intersection structure to add the scan to.
|
|
3108 |
ror_scan ROR scan info to add.
|
|
55
by brian
Update for using real bool types. |
3109 |
is_cpk_scan If true, add the scan as CPK scan (this can be inferred
|
1
by brian
clean slate |
3110 |
from other parameters and is passed separately only to
|
3111 |
avoid duplicating the inference code)
|
|
3112 |
||
3113 |
NOTES
|
|
3114 |
Adding a ROR scan to ROR-intersect "makes sense" iff the cost of ROR-
|
|
3115 |
intersection decreases. The cost of ROR-intersection is calculated as
|
|
3116 |
follows:
|
|
3117 |
||
3118 |
cost= SUM_i(key_scan_cost_i) + cost_of_full_rows_retrieval
|
|
3119 |
||
3120 |
When we add a scan the first increases and the second decreases.
|
|
3121 |
||
3122 |
cost_of_full_rows_retrieval=
|
|
3123 |
(union of indexes used covers all needed fields) ?
|
|
3124 |
cost_of_sweep_read(E(rows_to_retrieve), rows_in_table) :
|
|
3125 |
0
|
|
3126 |
||
3127 |
E(rows_to_retrieve) = #rows_in_table * ror_scan_selectivity(null, scan1) *
|
|
3128 |
ror_scan_selectivity({scan1}, scan2) * ... *
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3129 |
ror_scan_selectivity({scan1,...}, scanN).
|
1
by brian
clean slate |
3130 |
RETURN
|
55
by brian
Update for using real bool types. |
3131 |
true ROR scan added to ROR-intersection, cost updated.
|
3132 |
false It doesn't make sense to add this ROR scan to this ROR-intersection.
|
|
1
by brian
clean slate |
3133 |
*/
|
3134 |
||
3135 |
static bool ror_intersect_add(ROR_INTERSECT_INFO *info, |
|
3136 |
ROR_SCAN_INFO* ror_scan, bool is_cpk_scan) |
|
3137 |
{
|
|
3138 |
double selectivity_mult= 1.0; |
|
3139 |
||
3140 |
selectivity_mult = ror_scan_selectivity(info, ror_scan); |
|
3141 |
if (selectivity_mult == 1.0) |
|
3142 |
{
|
|
3143 |
/* 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 |
3144 |
return false; |
1
by brian
clean slate |
3145 |
}
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3146 |
|
1
by brian
clean slate |
3147 |
info->out_rows *= selectivity_mult; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3148 |
|
1
by brian
clean slate |
3149 |
if (is_cpk_scan) |
3150 |
{
|
|
3151 |
/*
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3152 |
CPK scan is used to filter out rows. We apply filtering for
|
1
by brian
clean slate |
3153 |
each record of every scan. Assuming 1/TIME_FOR_COMPARE_ROWID
|
3154 |
per check this gives us:
|
|
3155 |
*/
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3156 |
info->index_scan_costs += rows2double(info->index_records) / |
1
by brian
clean slate |
3157 |
TIME_FOR_COMPARE_ROWID; |
3158 |
}
|
|
3159 |
else
|
|
3160 |
{
|
|
3161 |
info->index_records += info->param->table->quick_rows[ror_scan->keynr]; |
|
3162 |
info->index_scan_costs += ror_scan->index_read_cost; |
|
1005.2.3
by Monty Taylor
Further reversion of P. |
3163 |
bitmap_union(&info->covered_fields, &ror_scan->covered_fields); |
3164 |
if (!info->is_covering && bitmap_is_subset(&info->param->needed_fields, |
|
3165 |
&info->covered_fields)) |
|
1
by brian
clean slate |
3166 |
{
|
55
by brian
Update for using real bool types. |
3167 |
info->is_covering= true; |
1
by brian
clean slate |
3168 |
}
|
3169 |
}
|
|
3170 |
||
3171 |
info->total_cost= info->index_scan_costs; |
|
3172 |
if (!info->is_covering) |
|
3173 |
{
|
|
3174 |
COST_VECT sweep_cost; |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
3175 |
JOIN *join= info->param->session->lex->select_lex.join; |
1
by brian
clean slate |
3176 |
bool is_interrupted= test(join && join->tables == 1); |
3177 |
get_sweep_read_cost(info->param->table, double2rows(info->out_rows), |
|
3178 |
is_interrupted, &sweep_cost); |
|
3179 |
info->total_cost += sweep_cost.total_cost(); |
|
3180 |
}
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3181 |
return true; |
1
by brian
clean slate |
3182 |
}
|
3183 |
||
3184 |
||
3185 |
/*
|
|
3186 |
Get best ROR-intersection plan using non-covering ROR-intersection search
|
|
3187 |
algorithm. The returned plan may be covering.
|
|
3188 |
||
3189 |
SYNOPSIS
|
|
3190 |
get_best_ror_intersect()
|
|
3191 |
param Parameter from test_quick_select function.
|
|
3192 |
tree Transformed restriction condition to be used to look
|
|
3193 |
for ROR scans.
|
|
3194 |
read_time Do not return read plans with cost > read_time.
|
|
55
by brian
Update for using real bool types. |
3195 |
are_all_covering [out] set to true if union of all scans covers all
|
1
by brian
clean slate |
3196 |
fields needed by the query (and it is possible to build
|
3197 |
a covering ROR-intersection)
|
|
3198 |
||
3199 |
NOTES
|
|
3200 |
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: |
3201 |
|
1
by brian
clean slate |
3202 |
When this function is called by ROR-union construction algorithm it
|
3203 |
assumes it is building an uncovered ROR-intersection (and thus # of full
|
|
3204 |
records to be retrieved is wrong here). This is a hack.
|
|
3205 |
||
3206 |
IMPLEMENTATION
|
|
3207 |
The approximate best non-covering plan search algorithm is as follows:
|
|
3208 |
||
3209 |
find_min_ror_intersection_scan()
|
|
3210 |
{
|
|
3211 |
R= select all ROR scans;
|
|
3212 |
order R by (E(#records_matched) * key_record_length).
|
|
3213 |
||
3214 |
S= first(R); -- set of scans that will be used for ROR-intersection
|
|
3215 |
R= R-first(S);
|
|
3216 |
min_cost= cost(S);
|
|
3217 |
min_scan= make_scan(S);
|
|
3218 |
while (R is not empty)
|
|
3219 |
{
|
|
3220 |
firstR= R - first(R);
|
|
3221 |
if (!selectivity(S + firstR < selectivity(S)))
|
|
3222 |
continue;
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3223 |
|
1
by brian
clean slate |
3224 |
S= S + first(R);
|
3225 |
if (cost(S) < min_cost)
|
|
3226 |
{
|
|
3227 |
min_cost= cost(S);
|
|
3228 |
min_scan= make_scan(S);
|
|
3229 |
}
|
|
3230 |
}
|
|
3231 |
return min_scan;
|
|
3232 |
}
|
|
3233 |
||
3234 |
See ror_intersect_add function for ROR intersection costs.
|
|
3235 |
||
3236 |
Special handling for Clustered PK scans
|
|
3237 |
Clustered PK contains all table fields, so using it as a regular scan in
|
|
3238 |
index intersection doesn't make sense: a range scan on CPK will be less
|
|
3239 |
expensive in this case.
|
|
3240 |
Clustered PK scan has special handling in ROR-intersection: it is not used
|
|
3241 |
to retrieve rows, instead its condition is used to filter row references
|
|
3242 |
we get from scans on other keys.
|
|
3243 |
||
3244 |
RETURN
|
|
3245 |
ROR-intersection table read plan
|
|
3246 |
NULL if out of memory or no suitable plan found.
|
|
3247 |
*/
|
|
3248 |
||
3249 |
static
|
|
3250 |
TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree, |
|
3251 |
double read_time, |
|
3252 |
bool *are_all_covering) |
|
3253 |
{
|
|
482
by Brian Aker
Remove uint. |
3254 |
uint32_t idx; |
1
by brian
clean slate |
3255 |
double min_cost= DBL_MAX; |
3256 |
||
3257 |
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 |
3258 |
return NULL; |
1
by brian
clean slate |
3259 |
|
3260 |
/*
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3261 |
Step1: Collect ROR-able SEL_ARGs and create ROR_SCAN_INFO for each of
|
1
by brian
clean slate |
3262 |
them. Also find and save clustered PK scan if there is one.
|
3263 |
*/
|
|
3264 |
ROR_SCAN_INFO **cur_ror_scan; |
|
3265 |
ROR_SCAN_INFO *cpk_scan= NULL; |
|
482
by Brian Aker
Remove uint. |
3266 |
uint32_t cpk_no; |
55
by brian
Update for using real bool types. |
3267 |
bool cpk_scan_used= false; |
1
by brian
clean slate |
3268 |
|
3269 |
if (!(tree->ror_scans= (ROR_SCAN_INFO**)alloc_root(param->mem_root, |
|
3270 |
sizeof(ROR_SCAN_INFO*)* |
|
3271 |
param->keys))) |
|
3272 |
return NULL; |
|
3273 |
cpk_no= ((param->table->file->primary_key_is_clustered()) ? |
|
3274 |
param->table->s->primary_key : MAX_KEY); |
|
3275 |
||
3276 |
for (idx= 0, cur_ror_scan= tree->ror_scans; idx < param->keys; idx++) |
|
3277 |
{
|
|
3278 |
ROR_SCAN_INFO *scan; |
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
3279 |
if (! tree->ror_scans_map.test(idx)) |
1
by brian
clean slate |
3280 |
continue; |
3281 |
if (!(scan= make_ror_scan(param, idx, tree->keys[idx]))) |
|
3282 |
return NULL; |
|
3283 |
if (param->real_keynr[idx] == cpk_no) |
|
3284 |
{
|
|
3285 |
cpk_scan= scan; |
|
3286 |
tree->n_ror_scans--; |
|
3287 |
}
|
|
3288 |
else
|
|
3289 |
*(cur_ror_scan++)= scan; |
|
3290 |
}
|
|
3291 |
||
3292 |
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. |
3293 |
print_ror_scans_arr(param->table, "original", |
1
by brian
clean slate |
3294 |
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. |
3295 |
tree->ror_scans_end); |
1
by brian
clean slate |
3296 |
/*
|
3297 |
Ok, [ror_scans, ror_scans_end) is array of ptrs to initialized
|
|
3298 |
ROR_SCAN_INFO's.
|
|
3299 |
Step 2: Get best ROR-intersection using an approximate algorithm.
|
|
3300 |
*/
|
|
3301 |
my_qsort(tree->ror_scans, tree->n_ror_scans, sizeof(ROR_SCAN_INFO*), |
|
3302 |
(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. |
3303 |
print_ror_scans_arr(param->table, "ordered", |
1
by brian
clean slate |
3304 |
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. |
3305 |
tree->ror_scans_end); |
1
by brian
clean slate |
3306 |
|
3307 |
ROR_SCAN_INFO **intersect_scans; /* ROR scans used in index intersection */ |
|
3308 |
ROR_SCAN_INFO **intersect_scans_end; |
|
3309 |
if (!(intersect_scans= (ROR_SCAN_INFO**)alloc_root(param->mem_root, |
|
3310 |
sizeof(ROR_SCAN_INFO*)* |
|
3311 |
tree->n_ror_scans))) |
|
3312 |
return NULL; |
|
3313 |
intersect_scans_end= intersect_scans; |
|
3314 |
||
3315 |
/* Create and incrementally update ROR intersection. */
|
|
3316 |
ROR_INTERSECT_INFO *intersect, *intersect_best; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3317 |
if (!(intersect= ror_intersect_init(param)) || |
1
by brian
clean slate |
3318 |
!(intersect_best= ror_intersect_init(param))) |
3319 |
return NULL; |
|
3320 |
||
3321 |
/* [intersect_scans,intersect_scans_best) will hold the best intersection */
|
|
3322 |
ROR_SCAN_INFO **intersect_scans_best; |
|
3323 |
cur_ror_scan= tree->ror_scans; |
|
3324 |
intersect_scans_best= intersect_scans; |
|
3325 |
while (cur_ror_scan != tree->ror_scans_end && !intersect->is_covering) |
|
3326 |
{
|
|
3327 |
/* S= S + first(R); R= R - first(R); */
|
|
55
by brian
Update for using real bool types. |
3328 |
if (!ror_intersect_add(intersect, *cur_ror_scan, false)) |
1
by brian
clean slate |
3329 |
{
|
3330 |
cur_ror_scan++; |
|
3331 |
continue; |
|
3332 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3333 |
|
1
by brian
clean slate |
3334 |
*(intersect_scans_end++)= *(cur_ror_scan++); |
3335 |
||
3336 |
if (intersect->total_cost < min_cost) |
|
3337 |
{
|
|
3338 |
/* Local minimum found, save it */
|
|
3339 |
ror_intersect_cpy(intersect_best, intersect); |
|
3340 |
intersect_scans_best= intersect_scans_end; |
|
3341 |
min_cost = intersect->total_cost; |
|
3342 |
}
|
|
3343 |
}
|
|
3344 |
||
3345 |
if (intersect_scans_best == intersect_scans) |
|
3346 |
{
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3347 |
return NULL; |
1
by brian
clean slate |
3348 |
}
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3349 |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3350 |
print_ror_scans_arr(param->table, |
1
by brian
clean slate |
3351 |
"best ROR-intersection", |
3352 |
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. |
3353 |
intersect_scans_best); |
1
by brian
clean slate |
3354 |
|
3355 |
*are_all_covering= intersect->is_covering; |
|
482
by Brian Aker
Remove uint. |
3356 |
uint32_t best_num= intersect_scans_best - intersect_scans; |
1
by brian
clean slate |
3357 |
ror_intersect_cpy(intersect, intersect_best); |
3358 |
||
3359 |
/*
|
|
3360 |
Ok, found the best ROR-intersection of non-CPK key scans.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3361 |
Check if we should add a CPK scan. If the obtained ROR-intersection is
|
1
by brian
clean slate |
3362 |
covering, it doesn't make sense to add CPK scan.
|
3363 |
*/
|
|
3364 |
if (cpk_scan && !intersect->is_covering) |
|
3365 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3366 |
if (ror_intersect_add(intersect, cpk_scan, true) && |
1
by brian
clean slate |
3367 |
(intersect->total_cost < min_cost)) |
3368 |
{
|
|
55
by brian
Update for using real bool types. |
3369 |
cpk_scan_used= true; |
1
by brian
clean slate |
3370 |
intersect_best= intersect; //just set pointer here |
3371 |
}
|
|
3372 |
}
|
|
3373 |
||
3374 |
/* Ok, return ROR-intersect plan if we have found one */
|
|
3375 |
TRP_ROR_INTERSECT *trp= NULL; |
|
3376 |
if (min_cost < read_time && (cpk_scan_used || best_num > 1)) |
|
3377 |
{
|
|
3378 |
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. |
3379 |
return(trp); |
1
by brian
clean slate |
3380 |
if (!(trp->first_scan= |
3381 |
(ROR_SCAN_INFO**)alloc_root(param->mem_root, |
|
3382 |
sizeof(ROR_SCAN_INFO*)*best_num))) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3383 |
return NULL; |
1
by brian
clean slate |
3384 |
memcpy(trp->first_scan, intersect_scans, best_num*sizeof(ROR_SCAN_INFO*)); |
3385 |
trp->last_scan= trp->first_scan + best_num; |
|
3386 |
trp->is_covering= intersect_best->is_covering; |
|
3387 |
trp->read_cost= intersect_best->total_cost; |
|
3388 |
/* Prevent divisons by zero */
|
|
3389 |
ha_rows best_rows = double2rows(intersect_best->out_rows); |
|
3390 |
if (!best_rows) |
|
3391 |
best_rows= 1; |
|
3392 |
set_if_smaller(param->table->quick_condition_rows, best_rows); |
|
3393 |
trp->records= best_rows; |
|
3394 |
trp->index_scan_costs= intersect_best->index_scan_costs; |
|
3395 |
trp->cpk_scan= cpk_scan_used? cpk_scan: NULL; |
|
3396 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3397 |
return(trp); |
1
by brian
clean slate |
3398 |
}
|
3399 |
||
1005.2.3
by Monty Taylor
Further reversion of P. |
3400 |
|
982.1.7
by Padraig O'Sullivan
Added a new helper function for testing and setting a bit in a bitset. Also, |
3401 |
/*
|
1
by brian
clean slate |
3402 |
Get best covering ROR-intersection.
|
3403 |
SYNOPSIS
|
|
3404 |
get_best_covering_ror_intersect()
|
|
3405 |
param Parameter from test_quick_select function.
|
|
3406 |
tree SEL_TREE with sets of intervals for different keys.
|
|
3407 |
read_time Don't return table read plans with cost > read_time.
|
|
3408 |
||
3409 |
RETURN
|
|
3410 |
Best covering ROR-intersection plan
|
|
3411 |
NULL if no plan found.
|
|
3412 |
||
3413 |
NOTES
|
|
3414 |
get_best_ror_intersect must be called for a tree before calling this
|
|
3415 |
function for it.
|
|
3416 |
This function invalidates tree->ror_scans member values.
|
|
3417 |
||
3418 |
The following approximate algorithm is used:
|
|
3419 |
I=set of all covering indexes
|
|
3420 |
F=set of all fields to cover
|
|
3421 |
S={}
|
|
3422 |
||
3423 |
do
|
|
3424 |
{
|
|
3425 |
Order I by (#covered fields in F desc,
|
|
3426 |
#components asc,
|
|
3427 |
number of first not covered component asc);
|
|
3428 |
F=F-covered by first(I);
|
|
3429 |
S=S+first(I);
|
|
3430 |
I=I-first(I);
|
|
3431 |
} while F is not empty.
|
|
3432 |
*/
|
|
3433 |
||
3434 |
static
|
|
3435 |
TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param, |
|
3436 |
SEL_TREE *tree, |
|
3437 |
double read_time) |
|
3438 |
{
|
|
3439 |
ROR_SCAN_INFO **ror_scan_mark; |
|
3440 |
ROR_SCAN_INFO **ror_scans_end= tree->ror_scans_end; |
|
3441 |
||
3442 |
for (ROR_SCAN_INFO **scan= tree->ror_scans; scan != ror_scans_end; ++scan) |
|
3443 |
(*scan)->key_components= |
|
3444 |
param->table->key_info[(*scan)->keynr].key_parts; |
|
3445 |
||
3446 |
/*
|
|
3447 |
Run covering-ROR-search algorithm.
|
|
3448 |
Assume set I is [ror_scan .. ror_scans_end)
|
|
3449 |
*/
|
|
3450 |
||
3451 |
/*I=set of all covering indexes */
|
|
3452 |
ror_scan_mark= tree->ror_scans; |
|
3453 |
||
1005.2.3
by Monty Taylor
Further reversion of P. |
3454 |
MY_BITMAP *covered_fields= ¶m->tmp_covered_fields; |
3455 |
if (!covered_fields->bitmap) |
|
3456 |
covered_fields->bitmap= (my_bitmap_map*)alloc_root(param->mem_root, |
|
3457 |
param->fields_bitmap_size); |
|
3458 |
if (!covered_fields->bitmap || |
|
3459 |
bitmap_init(covered_fields, covered_fields->bitmap, |
|
1014.2.12
by Monty Taylor
Removed the thread-safe crap in MY_BITMAP. Also remove the temp-pool option for |
3460 |
param->table->s->fields)) |
1005.2.3
by Monty Taylor
Further reversion of P. |
3461 |
return 0; |
3462 |
bitmap_clear_all(covered_fields); |
|
1
by brian
clean slate |
3463 |
|
3464 |
double total_cost= 0.0f; |
|
3465 |
ha_rows records=0; |
|
3466 |
bool all_covered; |
|
3467 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3468 |
print_ror_scans_arr(param->table, |
1
by brian
clean slate |
3469 |
"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. |
3470 |
ror_scan_mark, ror_scans_end); |
1
by brian
clean slate |
3471 |
do
|
3472 |
{
|
|
3473 |
/*
|
|
3474 |
Update changed sorting info:
|
|
3475 |
#covered fields,
|
|
3476 |
number of first not covered component
|
|
3477 |
Calculate and save these values for each of remaining scans.
|
|
3478 |
*/
|
|
3479 |
for (ROR_SCAN_INFO **scan= ror_scan_mark; scan != ror_scans_end; ++scan) |
|
3480 |
{
|
|
1005.2.3
by Monty Taylor
Further reversion of P. |
3481 |
bitmap_subtract(&(*scan)->covered_fields, covered_fields); |
3482 |
(*scan)->used_fields_covered= |
|
3483 |
bitmap_bits_set(&(*scan)->covered_fields); |
|
3484 |
(*scan)->first_uncovered_field= |
|
3485 |
bitmap_get_first(&(*scan)->covered_fields); |
|
1
by brian
clean slate |
3486 |
}
|
3487 |
||
3488 |
my_qsort(ror_scan_mark, ror_scans_end-ror_scan_mark, sizeof(ROR_SCAN_INFO*), |
|
3489 |
(qsort_cmp)cmp_ror_scan_info_covering); |
|
3490 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3491 |
print_ror_scans_arr(param->table, |
1
by brian
clean slate |
3492 |
"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. |
3493 |
ror_scan_mark, ror_scans_end); |
1
by brian
clean slate |
3494 |
|
3495 |
/* I=I-first(I) */
|
|
3496 |
total_cost += (*ror_scan_mark)->index_read_cost; |
|
3497 |
records += (*ror_scan_mark)->records; |
|
3498 |
if (total_cost > read_time) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3499 |
return NULL; |
1
by brian
clean slate |
3500 |
/* F=F-covered by first(I) */
|
1005.2.3
by Monty Taylor
Further reversion of P. |
3501 |
bitmap_union(covered_fields, &(*ror_scan_mark)->covered_fields); |
3502 |
all_covered= bitmap_is_subset(¶m->needed_fields, covered_fields); |
|
1
by brian
clean slate |
3503 |
} while ((++ror_scan_mark < ror_scans_end) && !all_covered); |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3504 |
|
1
by brian
clean slate |
3505 |
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 |
3506 |
return NULL; |
1
by brian
clean slate |
3507 |
|
3508 |
/*
|
|
3509 |
Ok, [tree->ror_scans .. ror_scan) holds covering index_intersection with
|
|
3510 |
cost total_cost.
|
|
3511 |
*/
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3512 |
print_ror_scans_arr(param->table, |
1
by brian
clean slate |
3513 |
"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. |
3514 |
tree->ror_scans, ror_scan_mark); |
1
by brian
clean slate |
3515 |
|
3516 |
/* Add priority queue use cost. */
|
|
3517 |
total_cost += rows2double(records)* |
|
3518 |
log((double)(ror_scan_mark - tree->ror_scans)) / |
|
3519 |
(TIME_FOR_COMPARE_ROWID * M_LN2); |
|
3520 |
||
3521 |
if (total_cost > read_time) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3522 |
return NULL; |
1
by brian
clean slate |
3523 |
|
3524 |
TRP_ROR_INTERSECT *trp; |
|
3525 |
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. |
3526 |
return(trp); |
482
by Brian Aker
Remove uint. |
3527 |
uint32_t best_num= (ror_scan_mark - tree->ror_scans); |
1
by brian
clean slate |
3528 |
if (!(trp->first_scan= (ROR_SCAN_INFO**)alloc_root(param->mem_root, |
3529 |
sizeof(ROR_SCAN_INFO*)* |
|
3530 |
best_num))) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3531 |
return NULL; |
1
by brian
clean slate |
3532 |
memcpy(trp->first_scan, tree->ror_scans, best_num*sizeof(ROR_SCAN_INFO*)); |
3533 |
trp->last_scan= trp->first_scan + best_num; |
|
55
by brian
Update for using real bool types. |
3534 |
trp->is_covering= true; |
1
by brian
clean slate |
3535 |
trp->read_cost= total_cost; |
3536 |
trp->records= records; |
|
3537 |
trp->cpk_scan= NULL; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3538 |
set_if_smaller(param->table->quick_condition_rows, records); |
1
by brian
clean slate |
3539 |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3540 |
return(trp); |
1
by brian
clean slate |
3541 |
}
|
3542 |
||
3543 |
||
3544 |
/*
|
|
3545 |
Get best "range" table read plan for given SEL_TREE, also update some info
|
|
3546 |
||
3547 |
SYNOPSIS
|
|
3548 |
get_key_scans_params()
|
|
3549 |
param Parameters from test_quick_select
|
|
3550 |
tree Make range select for this SEL_TREE
|
|
55
by brian
Update for using real bool types. |
3551 |
index_read_must_be_used true <=> assume 'index only' option will be set
|
1
by brian
clean slate |
3552 |
(except for clustered PK indexes)
|
55
by brian
Update for using real bool types. |
3553 |
update_tbl_stats true <=> update table->quick_* with information
|
1
by brian
clean slate |
3554 |
about range scans we've evaluated.
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3555 |
read_time Maximum cost. i.e. don't create read plans with
|
1
by brian
clean slate |
3556 |
cost > read_time.
|
3557 |
||
3558 |
DESCRIPTION
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3559 |
Find the best "range" table read plan for given SEL_TREE.
|
3560 |
The side effects are
|
|
1
by brian
clean slate |
3561 |
- tree->ror_scans is updated to indicate which scans are ROR scans.
|
55
by brian
Update for using real bool types. |
3562 |
- if update_tbl_stats=true then table->quick_* is updated with info
|
1
by brian
clean slate |
3563 |
about every possible range scan.
|
3564 |
||
3565 |
RETURN
|
|
3566 |
Best range read plan
|
|
3567 |
NULL if no plan found or error occurred
|
|
3568 |
*/
|
|
3569 |
||
3570 |
static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3571 |
bool index_read_must_be_used, |
1
by brian
clean slate |
3572 |
bool update_tbl_stats, |
3573 |
double read_time) |
|
3574 |
{
|
|
482
by Brian Aker
Remove uint. |
3575 |
uint32_t idx; |
1
by brian
clean slate |
3576 |
SEL_ARG **key,**end, **key_to_read= NULL; |
3577 |
ha_rows best_records= 0; |
|
482
by Brian Aker
Remove uint. |
3578 |
uint32_t best_mrr_flags= 0, best_buf_size= 0; |
1
by brian
clean slate |
3579 |
TRP_RANGE* read_plan= NULL; |
3580 |
/*
|
|
3581 |
Note that there may be trees that have type SEL_TREE::KEY but contain no
|
|
3582 |
key reads at all, e.g. tree for expression "key1 is not null" where key1
|
|
3583 |
is defined as "not null".
|
|
3584 |
*/
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3585 |
print_sel_tree(param, tree, &tree->keys_map, "tree scans"); |
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
3586 |
tree->ror_scans_map.reset(); |
1
by brian
clean slate |
3587 |
tree->n_ror_scans= 0; |
3588 |
for (idx= 0,key=tree->keys, end=key+param->keys; key != end; key++,idx++) |
|
3589 |
{
|
|
3590 |
if (*key) |
|
3591 |
{
|
|
3592 |
ha_rows found_records; |
|
3593 |
COST_VECT cost; |
|
3594 |
double found_read_time; |
|
482
by Brian Aker
Remove uint. |
3595 |
uint32_t mrr_flags, buf_size; |
3596 |
uint32_t keynr= param->real_keynr[idx]; |
|
1
by brian
clean slate |
3597 |
if ((*key)->type == SEL_ARG::MAYBE_KEY || |
3598 |
(*key)->maybe_flag) |
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
3599 |
param->needed_reg->set(keynr); |
1
by brian
clean slate |
3600 |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3601 |
bool read_index_only= index_read_must_be_used || |
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
3602 |
param->table->covering_keys.test(keynr); |
1
by brian
clean slate |
3603 |
|
3604 |
found_records= check_quick_select(param, idx, read_index_only, *key, |
|
3605 |
update_tbl_stats, &mrr_flags, |
|
3606 |
&buf_size, &cost); |
|
3607 |
found_read_time= cost.total_cost(); |
|
3608 |
if ((found_records != HA_POS_ERROR) && param->is_ror_scan) |
|
3609 |
{
|
|
3610 |
tree->n_ror_scans++; |
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
3611 |
tree->ror_scans_map.set(idx); |
1
by brian
clean slate |
3612 |
}
|
3613 |
if (read_time > found_read_time && found_records != HA_POS_ERROR) |
|
3614 |
{
|
|
3615 |
read_time= found_read_time; |
|
3616 |
best_records= found_records; |
|
3617 |
key_to_read= key; |
|
3618 |
best_mrr_flags= mrr_flags; |
|
3619 |
best_buf_size= buf_size; |
|
3620 |
}
|
|
3621 |
}
|
|
3622 |
}
|
|
3623 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3624 |
print_sel_tree(param, tree, &tree->ror_scans_map, "ROR scans"); |
1
by brian
clean slate |
3625 |
if (key_to_read) |
3626 |
{
|
|
3627 |
idx= key_to_read - tree->keys; |
|
3628 |
if ((read_plan= new (param->mem_root) TRP_RANGE(*key_to_read, idx, |
|
3629 |
best_mrr_flags))) |
|
3630 |
{
|
|
3631 |
read_plan->records= best_records; |
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
3632 |
read_plan->is_ror= tree->ror_scans_map.test(idx); |
1
by brian
clean slate |
3633 |
read_plan->read_cost= read_time; |
3634 |
read_plan->mrr_buf_size= best_buf_size; |
|
3635 |
}
|
|
3636 |
}
|
|
3637 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3638 |
return(read_plan); |
1
by brian
clean slate |
3639 |
}
|
3640 |
||
3641 |
||
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
3642 |
QUICK_SELECT_I *TRP_INDEX_MERGE::make_quick(PARAM *param, bool, MEM_ROOT *) |
1
by brian
clean slate |
3643 |
{
|
3644 |
QUICK_INDEX_MERGE_SELECT *quick_imerge; |
|
3645 |
QUICK_RANGE_SELECT *quick; |
|
3646 |
/* index_merge always retrieves full rows, ignore retrieve_full_rows */
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
3647 |
if (!(quick_imerge= new QUICK_INDEX_MERGE_SELECT(param->session, param->table))) |
1
by brian
clean slate |
3648 |
return NULL; |
3649 |
||
3650 |
quick_imerge->records= records; |
|
3651 |
quick_imerge->read_time= read_cost; |
|
3652 |
for (TRP_RANGE **range_scan= range_scans; range_scan != range_scans_end; |
|
3653 |
range_scan++) |
|
3654 |
{
|
|
3655 |
if (!(quick= (QUICK_RANGE_SELECT*) |
|
55
by brian
Update for using real bool types. |
3656 |
((*range_scan)->make_quick(param, false, &quick_imerge->alloc)))|| |
1
by brian
clean slate |
3657 |
quick_imerge->push_quick_back(quick)) |
3658 |
{
|
|
3659 |
delete quick; |
|
3660 |
delete quick_imerge; |
|
3661 |
return NULL; |
|
3662 |
}
|
|
3663 |
}
|
|
3664 |
return quick_imerge; |
|
3665 |
}
|
|
3666 |
||
3667 |
QUICK_SELECT_I *TRP_ROR_INTERSECT::make_quick(PARAM *param, |
|
3668 |
bool retrieve_full_rows, |
|
3669 |
MEM_ROOT *parent_alloc) |
|
3670 |
{
|
|
3671 |
QUICK_ROR_INTERSECT_SELECT *quick_intrsect; |
|
3672 |
QUICK_RANGE_SELECT *quick; |
|
3673 |
MEM_ROOT *alloc; |
|
3674 |
||
3675 |
if ((quick_intrsect= |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
3676 |
new QUICK_ROR_INTERSECT_SELECT(param->session, param->table, |
1
by brian
clean slate |
3677 |
(retrieve_full_rows? (!is_covering) : |
55
by brian
Update for using real bool types. |
3678 |
false), |
1
by brian
clean slate |
3679 |
parent_alloc))) |
3680 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3681 |
print_ror_scans_arr(param->table, |
1
by brian
clean slate |
3682 |
"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. |
3683 |
first_scan, last_scan); |
1
by brian
clean slate |
3684 |
alloc= parent_alloc? parent_alloc: &quick_intrsect->alloc; |
3685 |
for (; first_scan != last_scan;++first_scan) |
|
3686 |
{
|
|
3687 |
if (!(quick= get_quick_select(param, (*first_scan)->idx, |
|
3688 |
(*first_scan)->sel_arg, |
|
3689 |
HA_MRR_USE_DEFAULT_IMPL | HA_MRR_SORTED, |
|
3690 |
0, alloc)) || |
|
3691 |
quick_intrsect->push_quick_back(quick)) |
|
3692 |
{
|
|
3693 |
delete quick_intrsect; |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3694 |
return NULL; |
1
by brian
clean slate |
3695 |
}
|
3696 |
}
|
|
3697 |
if (cpk_scan) |
|
3698 |
{
|
|
3699 |
if (!(quick= get_quick_select(param, cpk_scan->idx, |
|
3700 |
cpk_scan->sel_arg, |
|
3701 |
HA_MRR_USE_DEFAULT_IMPL | HA_MRR_SORTED, |
|
3702 |
0, alloc))) |
|
3703 |
{
|
|
3704 |
delete quick_intrsect; |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3705 |
return NULL; |
1
by brian
clean slate |
3706 |
}
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3707 |
quick->file= NULL; |
1
by brian
clean slate |
3708 |
quick_intrsect->cpk_quick= quick; |
3709 |
}
|
|
3710 |
quick_intrsect->records= records; |
|
3711 |
quick_intrsect->read_time= read_cost; |
|
3712 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3713 |
return(quick_intrsect); |
1
by brian
clean slate |
3714 |
}
|
3715 |
||
3716 |
||
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
3717 |
QUICK_SELECT_I *TRP_ROR_UNION::make_quick(PARAM *param, bool, MEM_ROOT *) |
1
by brian
clean slate |
3718 |
{
|
3719 |
QUICK_ROR_UNION_SELECT *quick_roru; |
|
3720 |
TABLE_READ_PLAN **scan; |
|
3721 |
QUICK_SELECT_I *quick; |
|
3722 |
/*
|
|
3723 |
It is impossible to construct a ROR-union that will not retrieve full
|
|
3724 |
rows, ignore retrieve_full_rows parameter.
|
|
3725 |
*/
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
3726 |
if ((quick_roru= new QUICK_ROR_UNION_SELECT(param->session, param->table))) |
1
by brian
clean slate |
3727 |
{
|
3728 |
for (scan= first_ror; scan != last_ror; scan++) |
|
3729 |
{
|
|
55
by brian
Update for using real bool types. |
3730 |
if (!(quick= (*scan)->make_quick(param, false, &quick_roru->alloc)) || |
1
by brian
clean slate |
3731 |
quick_roru->push_quick_back(quick)) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
3732 |
return NULL; |
1
by brian
clean slate |
3733 |
}
|
3734 |
quick_roru->records= records; |
|
3735 |
quick_roru->read_time= read_cost; |
|
3736 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
3737 |
return(quick_roru); |
1
by brian
clean slate |
3738 |
}
|
3739 |
||
3740 |
||
3741 |
/*
|
|
3742 |
Build a SEL_TREE for <> or NOT BETWEEN predicate
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3743 |
|
1
by brian
clean slate |
3744 |
SYNOPSIS
|
3745 |
get_ne_mm_tree()
|
|
3746 |
param PARAM from SQL_SELECT::test_quick_select
|
|
3747 |
cond_func item for the predicate
|
|
3748 |
field field in the predicate
|
|
3749 |
lt_value constant that field should be smaller
|
|
3750 |
gt_value constant that field should be greaterr
|
|
3751 |
cmp_type compare type for the field
|
|
3752 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3753 |
RETURN
|
1
by brian
clean slate |
3754 |
# Pointer to tree built tree
|
3755 |
0 on error
|
|
3756 |
*/
|
|
3757 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3758 |
static SEL_TREE *get_ne_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func, |
1
by brian
clean slate |
3759 |
Field *field, |
3760 |
Item *lt_value, Item *gt_value, |
|
3761 |
Item_result cmp_type) |
|
3762 |
{
|
|
3763 |
SEL_TREE *tree; |
|
3764 |
tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC, |
|
3765 |
lt_value, cmp_type); |
|
3766 |
if (tree) |
|
3767 |
{
|
|
3768 |
tree= tree_or(param, tree, get_mm_parts(param, cond_func, field, |
|
3769 |
Item_func::GT_FUNC, |
|
3770 |
gt_value, cmp_type)); |
|
3771 |
}
|
|
3772 |
return tree; |
|
3773 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3774 |
|
1
by brian
clean slate |
3775 |
|
3776 |
/*
|
|
3777 |
Build a SEL_TREE for a simple predicate
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3778 |
|
1
by brian
clean slate |
3779 |
SYNOPSIS
|
3780 |
get_func_mm_tree()
|
|
3781 |
param PARAM from SQL_SELECT::test_quick_select
|
|
3782 |
cond_func item for the predicate
|
|
3783 |
field field in the predicate
|
|
3784 |
value constant in the predicate
|
|
3785 |
cmp_type compare type for the field
|
|
55
by brian
Update for using real bool types. |
3786 |
inv true <> NOT cond_func is considered
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3787 |
(makes sense only when cond_func is BETWEEN or IN)
|
1
by brian
clean slate |
3788 |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3789 |
RETURN
|
1
by brian
clean slate |
3790 |
Pointer to the tree built tree
|
3791 |
*/
|
|
3792 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3793 |
static SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func, |
1
by brian
clean slate |
3794 |
Field *field, Item *value, |
3795 |
Item_result cmp_type, bool inv) |
|
3796 |
{
|
|
3797 |
SEL_TREE *tree= 0; |
|
3798 |
||
3799 |
switch (cond_func->functype()) { |
|
3800 |
||
3801 |
case Item_func::NE_FUNC: |
|
3802 |
tree= get_ne_mm_tree(param, cond_func, field, value, value, cmp_type); |
|
3803 |
break; |
|
3804 |
||
3805 |
case Item_func::BETWEEN: |
|
3806 |
{
|
|
3807 |
if (!value) |
|
3808 |
{
|
|
3809 |
if (inv) |
|
3810 |
{
|
|
3811 |
tree= get_ne_mm_tree(param, cond_func, field, cond_func->arguments()[1], |
|
3812 |
cond_func->arguments()[2], cmp_type); |
|
3813 |
}
|
|
3814 |
else
|
|
3815 |
{
|
|
3816 |
tree= get_mm_parts(param, cond_func, field, Item_func::GE_FUNC, |
|
3817 |
cond_func->arguments()[1],cmp_type); |
|
3818 |
if (tree) |
|
3819 |
{
|
|
3820 |
tree= tree_and(param, tree, get_mm_parts(param, cond_func, field, |
|
3821 |
Item_func::LE_FUNC, |
|
3822 |
cond_func->arguments()[2], |
|
3823 |
cmp_type)); |
|
3824 |
}
|
|
3825 |
}
|
|
3826 |
}
|
|
3827 |
else
|
|
3828 |
tree= get_mm_parts(param, cond_func, field, |
|
3829 |
(inv ? |
|
3830 |
(value == (Item*)1 ? Item_func::GT_FUNC : |
|
3831 |
Item_func::LT_FUNC): |
|
3832 |
(value == (Item*)1 ? Item_func::LE_FUNC : |
|
3833 |
Item_func::GE_FUNC)), |
|
3834 |
cond_func->arguments()[0], cmp_type); |
|
3835 |
break; |
|
3836 |
}
|
|
3837 |
case Item_func::IN_FUNC: |
|
3838 |
{
|
|
3839 |
Item_func_in *func=(Item_func_in*) cond_func; |
|
3840 |
||
3841 |
/*
|
|
3842 |
Array for IN() is constructed when all values have the same result
|
|
3843 |
type. Tree won't be built for values with different result types,
|
|
3844 |
so we check it here to avoid unnecessary work.
|
|
3845 |
*/
|
|
3846 |
if (!func->arg_types_compatible) |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3847 |
break; |
1
by brian
clean slate |
3848 |
|
3849 |
if (inv) |
|
3850 |
{
|
|
3851 |
if (func->array && func->array->result_type() != ROW_RESULT) |
|
3852 |
{
|
|
3853 |
/*
|
|
3854 |
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: |
3855 |
where c{i} are constants. Our goal is to produce a SEL_TREE that
|
1
by brian
clean slate |
3856 |
represents intervals:
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3857 |
|
1
by brian
clean slate |
3858 |
($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: |
3859 |
|
1
by brian
clean slate |
3860 |
where $MIN is either "-inf" or NULL.
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3861 |
|
1
by brian
clean slate |
3862 |
The most straightforward way to produce it is to convert NOT IN
|
3863 |
into "(t.key != c1) AND (t.key != c2) AND ... " and let the range
|
|
3864 |
analyzer to build SEL_TREE from that. The problem is that the
|
|
3865 |
range analyzer will use O(N^2) memory (which is probably a bug),
|
|
3866 |
and people do use big NOT IN lists (e.g. see BUG#15872, BUG#21282),
|
|
3867 |
will run out of memory.
|
|
3868 |
||
3869 |
Another problem with big lists like (*) is that a big list is
|
|
3870 |
unlikely to produce a good "range" access, while considering that
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3871 |
range access will require expensive CPU calculations (and for
|
1
by brian
clean slate |
3872 |
MyISAM even index accesses). In short, big NOT IN lists are rarely
|
3873 |
worth analyzing.
|
|
3874 |
||
3875 |
Considering the above, we'll handle NOT IN as follows:
|
|
3876 |
* if the number of entries in the NOT IN list is less than
|
|
3877 |
NOT_IN_IGNORE_THRESHOLD, construct the SEL_TREE (*) manually.
|
|
3878 |
* Otherwise, don't produce a SEL_TREE.
|
|
3879 |
*/
|
|
3880 |
#define NOT_IN_IGNORE_THRESHOLD 1000
|
|
3881 |
MEM_ROOT *tmp_root= param->mem_root; |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
3882 |
param->session->mem_root= param->old_root; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3883 |
/*
|
1
by brian
clean slate |
3884 |
Create one Item_type constant object. We'll need it as
|
3885 |
get_mm_parts only accepts constant values wrapped in Item_Type
|
|
3886 |
objects.
|
|
3887 |
We create the Item on param->mem_root which points to
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
3888 |
per-statement mem_root (while session->mem_root is currently pointing
|
1
by brian
clean slate |
3889 |
to mem_root local to range optimizer).
|
3890 |
*/
|
|
3891 |
Item *value_item= func->array->create_item(); |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
3892 |
param->session->mem_root= tmp_root; |
1
by brian
clean slate |
3893 |
|
3894 |
if (func->array->count > NOT_IN_IGNORE_THRESHOLD || !value_item) |
|
3895 |
break; |
|
3896 |
||
3897 |
/* Get a SEL_TREE for "(-inf|NULL) < X < c_0" interval. */
|
|
482
by Brian Aker
Remove uint. |
3898 |
uint32_t i=0; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3899 |
do
|
1
by brian
clean slate |
3900 |
{
|
3901 |
func->array->value_to_item(i, value_item); |
|
3902 |
tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC, |
|
3903 |
value_item, cmp_type); |
|
3904 |
if (!tree) |
|
3905 |
break; |
|
3906 |
i++; |
|
3907 |
} while (i < func->array->count && tree->type == SEL_TREE::IMPOSSIBLE); |
|
3908 |
||
3909 |
if (!tree || tree->type == SEL_TREE::IMPOSSIBLE) |
|
3910 |
{
|
|
3911 |
/* We get here in cases like "t.unsigned NOT IN (-1,-2,-3) */
|
|
3912 |
tree= NULL; |
|
3913 |
break; |
|
3914 |
}
|
|
3915 |
SEL_TREE *tree2; |
|
3916 |
for (; i < func->array->count; i++) |
|
3917 |
{
|
|
3918 |
if (func->array->compare_elems(i, i-1)) |
|
3919 |
{
|
|
3920 |
/* Get a SEL_TREE for "-inf < X < c_i" interval */
|
|
3921 |
func->array->value_to_item(i, value_item); |
|
3922 |
tree2= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC, |
|
3923 |
value_item, cmp_type); |
|
3924 |
if (!tree2) |
|
3925 |
{
|
|
3926 |
tree= NULL; |
|
3927 |
break; |
|
3928 |
}
|
|
3929 |
||
3930 |
/* Change all intervals to be "c_{i-1} < X < c_i" */
|
|
482
by Brian Aker
Remove uint. |
3931 |
for (uint32_t idx= 0; idx < param->keys; idx++) |
1
by brian
clean slate |
3932 |
{
|
3933 |
SEL_ARG *new_interval, *last_val; |
|
3934 |
if (((new_interval= tree2->keys[idx])) && |
|
3935 |
(tree->keys[idx]) && |
|
3936 |
((last_val= tree->keys[idx]->last()))) |
|
3937 |
{
|
|
3938 |
new_interval->min_value= last_val->max_value; |
|
3939 |
new_interval->min_flag= NEAR_MIN; |
|
3940 |
}
|
|
3941 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3942 |
/*
|
1
by brian
clean slate |
3943 |
The following doesn't try to allocate memory so no need to
|
3944 |
check for NULL.
|
|
3945 |
*/
|
|
3946 |
tree= tree_or(param, tree, tree2); |
|
3947 |
}
|
|
3948 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3949 |
|
1
by brian
clean slate |
3950 |
if (tree && tree->type != SEL_TREE::IMPOSSIBLE) |
3951 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3952 |
/*
|
3953 |
Get the SEL_TREE for the last "c_last < X < +inf" interval
|
|
1
by brian
clean slate |
3954 |
(value_item cotains c_last already)
|
3955 |
*/
|
|
3956 |
tree2= get_mm_parts(param, cond_func, field, Item_func::GT_FUNC, |
|
3957 |
value_item, cmp_type); |
|
3958 |
tree= tree_or(param, tree, tree2); |
|
3959 |
}
|
|
3960 |
}
|
|
3961 |
else
|
|
3962 |
{
|
|
3963 |
tree= get_ne_mm_tree(param, cond_func, field, |
|
3964 |
func->arguments()[1], func->arguments()[1], |
|
3965 |
cmp_type); |
|
3966 |
if (tree) |
|
3967 |
{
|
|
3968 |
Item **arg, **end; |
|
3969 |
for (arg= func->arguments()+2, end= arg+func->argument_count()-2; |
|
3970 |
arg < end ; arg++) |
|
3971 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3972 |
tree= tree_and(param, tree, get_ne_mm_tree(param, cond_func, field, |
1
by brian
clean slate |
3973 |
*arg, *arg, cmp_type)); |
3974 |
}
|
|
3975 |
}
|
|
3976 |
}
|
|
3977 |
}
|
|
3978 |
else
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3979 |
{
|
1
by brian
clean slate |
3980 |
tree= get_mm_parts(param, cond_func, field, Item_func::EQ_FUNC, |
3981 |
func->arguments()[1], cmp_type); |
|
3982 |
if (tree) |
|
3983 |
{
|
|
3984 |
Item **arg, **end; |
|
3985 |
for (arg= func->arguments()+2, end= arg+func->argument_count()-2; |
|
3986 |
arg < end ; arg++) |
|
3987 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3988 |
tree= tree_or(param, tree, get_mm_parts(param, cond_func, field, |
1
by brian
clean slate |
3989 |
Item_func::EQ_FUNC, |
3990 |
*arg, cmp_type)); |
|
3991 |
}
|
|
3992 |
}
|
|
3993 |
}
|
|
3994 |
break; |
|
3995 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3996 |
default: |
1
by brian
clean slate |
3997 |
{
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3998 |
/*
|
1
by brian
clean slate |
3999 |
Here the function for the following predicates are processed:
|
4000 |
<, <=, =, >=, >, LIKE, IS NULL, IS NOT NULL.
|
|
4001 |
If the predicate is of the form (value op field) it is handled
|
|
4002 |
as the equivalent predicate (field rev_op value), e.g.
|
|
4003 |
2 <= a is handled as a >= 2.
|
|
4004 |
*/
|
|
4005 |
Item_func::Functype func_type= |
|
4006 |
(value != cond_func->arguments()[0]) ? cond_func->functype() : |
|
4007 |
((Item_bool_func2*) cond_func)->rev_functype(); |
|
4008 |
tree= get_mm_parts(param, cond_func, field, func_type, value, cmp_type); |
|
4009 |
}
|
|
4010 |
}
|
|
4011 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4012 |
return(tree); |
1
by brian
clean slate |
4013 |
}
|
4014 |
||
4015 |
||
4016 |
/*
|
|
4017 |
Build conjunction of all SEL_TREEs for a simple predicate applying equalities
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4018 |
|
1
by brian
clean slate |
4019 |
SYNOPSIS
|
4020 |
get_full_func_mm_tree()
|
|
4021 |
param PARAM from SQL_SELECT::test_quick_select
|
|
4022 |
cond_func item for the predicate
|
|
4023 |
field_item field in the predicate
|
|
4024 |
value constant in the predicate
|
|
4025 |
(for BETWEEN it contains the number of the field argument,
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4026 |
for IN it's always 0)
|
55
by brian
Update for using real bool types. |
4027 |
inv true <> NOT cond_func is considered
|
1
by brian
clean slate |
4028 |
(makes sense only when cond_func is BETWEEN or IN)
|
4029 |
||
4030 |
DESCRIPTION
|
|
4031 |
For a simple SARGable predicate of the form (f op c), where f is a field and
|
|
4032 |
c is a constant, the function builds a conjunction of all SEL_TREES that can
|
|
4033 |
be obtained by the substitution of f for all different fields equal to f.
|
|
4034 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4035 |
NOTES
|
1
by brian
clean slate |
4036 |
If the WHERE condition contains a predicate (fi op c),
|
4037 |
then not only SELL_TREE for this predicate is built, but
|
|
4038 |
the trees for the results of substitution of fi for
|
|
4039 |
each fj belonging to the same multiple equality as fi
|
|
4040 |
are built as well.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4041 |
E.g. for WHERE t1.a=t2.a AND t2.a > 10
|
1
by brian
clean slate |
4042 |
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: |
4043 |
and
|
1
by brian
clean slate |
4044 |
a SEL_TREE for t1.a > 10 will be built for quick select from t1.
|
4045 |
||
4046 |
A BETWEEN predicate of the form (fi [NOT] BETWEEN c1 AND c2) is treated
|
|
4047 |
in a similar way: we build a conjuction of trees for the results
|
|
4048 |
of all substitutions of fi for equal fj.
|
|
4049 |
Yet a predicate of the form (c BETWEEN f1i AND f2i) is processed
|
|
4050 |
differently. It is considered as a conjuction of two SARGable
|
|
4051 |
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: |
4052 |
is called for each of them separately producing trees for
|
4053 |
AND j (f1j <=c ) and AND j (f2j <= c)
|
|
1
by brian
clean slate |
4054 |
After this these two trees are united in one conjunctive tree.
|
4055 |
It's easy to see that the same tree is obtained for
|
|
4056 |
AND j,k (f1j <=c AND f2k<=c)
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4057 |
which is equivalent to
|
1
by brian
clean slate |
4058 |
AND j,k (c BETWEEN f1j AND f2k).
|
4059 |
The validity of the processing of the predicate (c NOT BETWEEN f1i AND f2i)
|
|
4060 |
which equivalent to (f1i > c OR f2i < c) is not so obvious. Here the
|
|
4061 |
function get_full_func_mm_tree is called for (f1i > c) and (f2i < c)
|
|
4062 |
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: |
4063 |
trees are united in one OR-tree. The expression
|
1
by brian
clean slate |
4064 |
(AND j (f1j > c) OR AND j (f2j < c)
|
4065 |
is equivalent to the expression
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4066 |
AND j,k (f1j > c OR f2k < c)
|
4067 |
which is just a translation of
|
|
1
by brian
clean slate |
4068 |
AND j,k (c NOT BETWEEN f1j AND f2k)
|
4069 |
||
4070 |
In the cases when one of the items f1, f2 is a constant c1 we do not create
|
|
4071 |
a tree for it at all. It works for BETWEEN predicates but does not
|
|
4072 |
work for NOT BETWEEN predicates as we have to evaluate the expression
|
|
55
by brian
Update for using real bool types. |
4073 |
with it. If it is true then the other tree can be completely ignored.
|
1
by brian
clean slate |
4074 |
We do not do it now and no trees are built in these cases for
|
4075 |
NOT BETWEEN predicates.
|
|
4076 |
||
4077 |
As to IN predicates only ones of the form (f IN (c1,...,cn)),
|
|
4078 |
where f1 is a field and c1,...,cn are constant, are considered as
|
|
4079 |
SARGable. We never try to narrow the index scan using predicates of
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4080 |
the form (c IN (c1,...,f,...,cn)).
|
4081 |
||
4082 |
RETURN
|
|
1
by brian
clean slate |
4083 |
Pointer to the tree representing the built conjunction of SEL_TREEs
|
4084 |
*/
|
|
4085 |
||
4086 |
static SEL_TREE *get_full_func_mm_tree(RANGE_OPT_PARAM *param, |
|
4087 |
Item_func *cond_func, |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4088 |
Item_field *field_item, Item *value, |
1
by brian
clean slate |
4089 |
bool inv) |
4090 |
{
|
|
4091 |
SEL_TREE *tree= 0; |
|
4092 |
SEL_TREE *ftree= 0; |
|
4093 |
table_map ref_tables= 0; |
|
4094 |
table_map param_comp= ~(param->prev_tables | param->read_tables | |
|
4095 |
param->current_table); |
|
4096 |
||
482
by Brian Aker
Remove uint. |
4097 |
for (uint32_t i= 0; i < cond_func->arg_count; i++) |
1
by brian
clean slate |
4098 |
{
|
4099 |
Item *arg= cond_func->arguments()[i]->real_item(); |
|
4100 |
if (arg != field_item) |
|
4101 |
ref_tables|= arg->used_tables(); |
|
4102 |
}
|
|
4103 |
Field *field= field_item->field; |
|
4104 |
Item_result cmp_type= field->cmp_type(); |
|
4105 |
if (!((ref_tables | field->table->map) & param_comp)) |
|
4106 |
ftree= get_func_mm_tree(param, cond_func, field, value, cmp_type, inv); |
|
4107 |
Item_equal *item_equal= field_item->item_equal; |
|
4108 |
if (item_equal) |
|
4109 |
{
|
|
4110 |
Item_equal_iterator it(*item_equal); |
|
4111 |
Item_field *item; |
|
4112 |
while ((item= it++)) |
|
4113 |
{
|
|
4114 |
Field *f= item->field; |
|
4115 |
if (field->eq(f)) |
|
4116 |
continue; |
|
4117 |
if (!((ref_tables | f->table->map) & param_comp)) |
|
4118 |
{
|
|
4119 |
tree= get_func_mm_tree(param, cond_func, f, value, cmp_type, inv); |
|
4120 |
ftree= !ftree ? tree : tree_and(param, ftree, tree); |
|
4121 |
}
|
|
4122 |
}
|
|
4123 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4124 |
return(ftree); |
1
by brian
clean slate |
4125 |
}
|
4126 |
||
4127 |
/* make a select tree of all keys in condition */
|
|
4128 |
||
4129 |
static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond) |
|
4130 |
{
|
|
4131 |
SEL_TREE *tree=0; |
|
4132 |
SEL_TREE *ftree= 0; |
|
4133 |
Item_field *field_item= 0; |
|
55
by brian
Update for using real bool types. |
4134 |
bool inv= false; |
1
by brian
clean slate |
4135 |
Item *value= 0; |
4136 |
||
4137 |
if (cond->type() == Item::COND_ITEM) |
|
4138 |
{
|
|
4139 |
List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); |
|
4140 |
||
4141 |
if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) |
|
4142 |
{
|
|
4143 |
tree=0; |
|
4144 |
Item *item; |
|
4145 |
while ((item=li++)) |
|
4146 |
{
|
|
4147 |
SEL_TREE *new_tree=get_mm_tree(param,item); |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4148 |
if (param->session->is_fatal_error || |
1
by brian
clean slate |
4149 |
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 |
4150 |
return 0; // out of memory |
1
by brian
clean slate |
4151 |
tree=tree_and(param,tree,new_tree); |
4152 |
if (tree && tree->type == SEL_TREE::IMPOSSIBLE) |
|
4153 |
break; |
|
4154 |
}
|
|
4155 |
}
|
|
4156 |
else
|
|
4157 |
{ // COND OR |
|
4158 |
tree=get_mm_tree(param,li++); |
|
4159 |
if (tree) |
|
4160 |
{
|
|
4161 |
Item *item; |
|
4162 |
while ((item=li++)) |
|
4163 |
{
|
|
4164 |
SEL_TREE *new_tree=get_mm_tree(param,item); |
|
4165 |
if (!new_tree) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4166 |
return 0; // out of memory |
1
by brian
clean slate |
4167 |
tree=tree_or(param,tree,new_tree); |
4168 |
if (!tree || tree->type == SEL_TREE::ALWAYS) |
|
4169 |
break; |
|
4170 |
}
|
|
4171 |
}
|
|
4172 |
}
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4173 |
return(tree); |
1
by brian
clean slate |
4174 |
}
|
4175 |
/* Here when simple cond */
|
|
4176 |
if (cond->const_item()) |
|
4177 |
{
|
|
4178 |
/*
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4179 |
During the cond->val_int() evaluation we can come across a subselect
|
4180 |
item which may allocate memory on the session->mem_root and assumes
|
|
4181 |
all the memory allocated has the same life span as the subselect
|
|
1
by brian
clean slate |
4182 |
item itself. So we have to restore the thread's mem_root here.
|
4183 |
*/
|
|
4184 |
MEM_ROOT *tmp_root= param->mem_root; |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
4185 |
param->session->mem_root= param->old_root; |
1
by brian
clean slate |
4186 |
tree= cond->val_int() ? new(tmp_root) SEL_TREE(SEL_TREE::ALWAYS) : |
4187 |
new(tmp_root) SEL_TREE(SEL_TREE::IMPOSSIBLE); |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
4188 |
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. |
4189 |
return(tree); |
1
by brian
clean slate |
4190 |
}
|
4191 |
||
4192 |
table_map ref_tables= 0; |
|
4193 |
table_map param_comp= ~(param->prev_tables | param->read_tables | |
|
4194 |
param->current_table); |
|
4195 |
if (cond->type() != Item::FUNC_ITEM) |
|
4196 |
{ // Should be a field |
|
4197 |
ref_tables= cond->used_tables(); |
|
4198 |
if ((ref_tables & param->current_table) || |
|
4199 |
(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 |
4200 |
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. |
4201 |
return(new SEL_TREE(SEL_TREE::MAYBE)); |
1
by brian
clean slate |
4202 |
}
|
4203 |
||
4204 |
Item_func *cond_func= (Item_func*) cond; |
|
4205 |
if (cond_func->functype() == Item_func::BETWEEN || |
|
4206 |
cond_func->functype() == Item_func::IN_FUNC) |
|
4207 |
inv= ((Item_func_opt_neg *) cond_func)->negated; |
|
4208 |
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 |
4209 |
return 0; |
1
by brian
clean slate |
4210 |
|
4211 |
param->cond= cond; |
|
4212 |
||
4213 |
switch (cond_func->functype()) { |
|
4214 |
case Item_func::BETWEEN: |
|
4215 |
if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM) |
|
4216 |
{
|
|
4217 |
field_item= (Item_field*) (cond_func->arguments()[0]->real_item()); |
|
4218 |
ftree= get_full_func_mm_tree(param, cond_func, field_item, NULL, inv); |
|
4219 |
}
|
|
4220 |
||
4221 |
/*
|
|
4222 |
Concerning the code below see the NOTES section in
|
|
4223 |
the comments for the function get_full_func_mm_tree()
|
|
4224 |
*/
|
|
482
by Brian Aker
Remove uint. |
4225 |
for (uint32_t i= 1 ; i < cond_func->arg_count ; i++) |
1
by brian
clean slate |
4226 |
{
|
4227 |
if (cond_func->arguments()[i]->real_item()->type() == Item::FIELD_ITEM) |
|
4228 |
{
|
|
4229 |
field_item= (Item_field*) (cond_func->arguments()[i]->real_item()); |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4230 |
SEL_TREE *tmp= get_full_func_mm_tree(param, cond_func, |
157
by Brian Aker
Second pass cleanup on removal of my_uint types |
4231 |
field_item, (Item*)(intptr_t)i, inv); |
1
by brian
clean slate |
4232 |
if (inv) |
4233 |
tree= !tree ? tmp : tree_or(param, tree, tmp); |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4234 |
else
|
1
by brian
clean slate |
4235 |
tree= tree_and(param, tree, tmp); |
4236 |
}
|
|
4237 |
else if (inv) |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4238 |
{
|
1
by brian
clean slate |
4239 |
tree= 0; |
4240 |
break; |
|
4241 |
}
|
|
4242 |
}
|
|
4243 |
||
4244 |
ftree = tree_and(param, ftree, tree); |
|
4245 |
break; |
|
4246 |
case Item_func::IN_FUNC: |
|
4247 |
{
|
|
4248 |
Item_func_in *func=(Item_func_in*) cond_func; |
|
4249 |
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 |
4250 |
return 0; |
1
by brian
clean slate |
4251 |
field_item= (Item_field*) (func->key_item()->real_item()); |
4252 |
ftree= get_full_func_mm_tree(param, cond_func, field_item, NULL, inv); |
|
4253 |
break; |
|
4254 |
}
|
|
4255 |
case Item_func::MULT_EQUAL_FUNC: |
|
4256 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4257 |
Item_equal *item_equal= (Item_equal *) cond; |
1
by brian
clean slate |
4258 |
if (!(value= item_equal->get_const())) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4259 |
return 0; |
1
by brian
clean slate |
4260 |
Item_equal_iterator it(*item_equal); |
4261 |
ref_tables= value->used_tables(); |
|
4262 |
while ((field_item= it++)) |
|
4263 |
{
|
|
4264 |
Field *field= field_item->field; |
|
4265 |
Item_result cmp_type= field->cmp_type(); |
|
4266 |
if (!((ref_tables | field->table->map) & param_comp)) |
|
4267 |
{
|
|
4268 |
tree= get_mm_parts(param, cond, field, Item_func::EQ_FUNC, |
|
4269 |
value,cmp_type); |
|
4270 |
ftree= !ftree ? tree : tree_and(param, ftree, tree); |
|
4271 |
}
|
|
4272 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4273 |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4274 |
return(ftree); |
1
by brian
clean slate |
4275 |
}
|
4276 |
default: |
|
4277 |
if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM) |
|
4278 |
{
|
|
4279 |
field_item= (Item_field*) (cond_func->arguments()[0]->real_item()); |
|
4280 |
value= cond_func->arg_count > 1 ? cond_func->arguments()[1] : 0; |
|
4281 |
}
|
|
4282 |
else if (cond_func->have_rev_func() && |
|
4283 |
cond_func->arguments()[1]->real_item()->type() == |
|
4284 |
Item::FIELD_ITEM) |
|
4285 |
{
|
|
4286 |
field_item= (Item_field*) (cond_func->arguments()[1]->real_item()); |
|
4287 |
value= cond_func->arguments()[0]; |
|
4288 |
}
|
|
4289 |
else
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4290 |
return 0; |
1
by brian
clean slate |
4291 |
ftree= get_full_func_mm_tree(param, cond_func, field_item, value, inv); |
4292 |
}
|
|
4293 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4294 |
return(ftree); |
1
by brian
clean slate |
4295 |
}
|
4296 |
||
4297 |
||
4298 |
static SEL_TREE * |
|
4299 |
get_mm_parts(RANGE_OPT_PARAM *param, COND *cond_func, Field *field, |
|
4300 |
Item_func::Functype type, |
|
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
4301 |
Item *value, Item_result) |
1
by brian
clean slate |
4302 |
{
|
4303 |
if (field->table != param->table) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4304 |
return 0; |
1
by brian
clean slate |
4305 |
|
4306 |
KEY_PART *key_part = param->key_parts; |
|
4307 |
KEY_PART *end = param->key_parts_end; |
|
4308 |
SEL_TREE *tree=0; |
|
4309 |
if (value && |
|
4310 |
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 |
4311 |
return 0; |
1
by brian
clean slate |
4312 |
for (; key_part != end ; key_part++) |
4313 |
{
|
|
4314 |
if (field->eq(key_part->field)) |
|
4315 |
{
|
|
4316 |
SEL_ARG *sel_arg=0; |
|
4317 |
if (!tree && !(tree=new SEL_TREE())) |
|
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 |
if (!value || !(value->used_tables() & ~param->read_tables)) |
4320 |
{
|
|
4321 |
sel_arg=get_mm_leaf(param,cond_func, |
|
4322 |
key_part->field,key_part,type,value); |
|
4323 |
if (!sel_arg) |
|
4324 |
continue; |
|
4325 |
if (sel_arg->type == SEL_ARG::IMPOSSIBLE) |
|
4326 |
{
|
|
4327 |
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. |
4328 |
return(tree); |
1
by brian
clean slate |
4329 |
}
|
4330 |
}
|
|
4331 |
else
|
|
4332 |
{
|
|
4333 |
// This key may be used later
|
|
4334 |
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 |
4335 |
return 0; // OOM |
1
by brian
clean slate |
4336 |
}
|
481
by Brian Aker
Remove all of uchar. |
4337 |
sel_arg->part=(unsigned char) key_part->part; |
1
by brian
clean slate |
4338 |
tree->keys[key_part->key]=sel_add(tree->keys[key_part->key],sel_arg); |
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
4339 |
tree->keys_map.set(key_part->key); |
1
by brian
clean slate |
4340 |
}
|
4341 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4342 |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
4343 |
return(tree); |
1
by brian
clean slate |
4344 |
}
|
4345 |
||
4346 |
||
4347 |
static SEL_ARG * |
|
4348 |
get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, |
|
4349 |
KEY_PART *key_part, Item_func::Functype type,Item *value) |
|
4350 |
{
|
|
895
by Brian Aker
Completion (?) of uint conversion. |
4351 |
uint32_t maybe_null=(uint32_t) field->real_maybe_null(); |
1
by brian
clean slate |
4352 |
bool optimize_range; |
4353 |
SEL_ARG *tree= 0; |
|
4354 |
MEM_ROOT *alloc= param->mem_root; |
|
481
by Brian Aker
Remove all of uchar. |
4355 |
unsigned char *str; |
910.2.7
by Monty Taylor
Merged from Jay. |
4356 |
int err= 0; |
1
by brian
clean slate |
4357 |
|
4358 |
/*
|
|
4359 |
We need to restore the runtime mem_root of the thread in this
|
|
4360 |
function because it evaluates the value of its argument, while
|
|
4361 |
the argument can be any, e.g. a subselect. The subselect
|
|
4362 |
items, in turn, assume that all the memory allocated during
|
|
4363 |
the evaluation has the same life span as the item itself.
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
4364 |
TODO: opt_range.cc should not reset session->mem_root at all.
|
1
by brian
clean slate |
4365 |
*/
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
4366 |
param->session->mem_root= param->old_root; |
1
by brian
clean slate |
4367 |
if (!value) // IS NULL or IS NOT NULL |
4368 |
{
|
|
4369 |
if (field->table->maybe_null) // Can't use a key on this |
|
4370 |
goto end; |
|
4371 |
if (!maybe_null) // Not null field |
|
4372 |
{
|
|
4373 |
if (type == Item_func::ISNULL_FUNC) |
|
4374 |
tree= &null_element; |
|
4375 |
goto end; |
|
4376 |
}
|
|
4377 |
if (!(tree= new (alloc) SEL_ARG(field,is_null_string,is_null_string))) |
|
4378 |
goto end; // out of memory |
|
4379 |
if (type == Item_func::ISNOTNULL_FUNC) |
|
4380 |
{
|
|
4381 |
tree->min_flag=NEAR_MIN; /* IS NOT NULL -> X > NULL */ |
|
4382 |
tree->max_flag=NO_MAX_RANGE; |
|
4383 |
}
|
|
4384 |
goto end; |
|
4385 |
}
|
|
4386 |
||
4387 |
/*
|
|
4388 |
1. Usually we can't use an index if the column collation
|
|
4389 |
differ from the operation collation.
|
|
4390 |
||
4391 |
2. However, we can reuse a case insensitive index for
|
|
4392 |
the binary searches:
|
|
4393 |
||
4394 |
WHERE latin1_swedish_ci_column = 'a' COLLATE lati1_bin;
|
|
4395 |
||
4396 |
WHERE latin1_swedish_ci_colimn = BINARY 'a '
|
|
4397 |
||
4398 |
*/
|
|
4399 |
if (field->result_type() == STRING_RESULT && |
|
4400 |
value->result_type() == STRING_RESULT && |
|
4401 |
key_part->image_type == Field::itRAW && |
|
4402 |
((Field_str*)field)->charset() != conf_func->compare_collation() && |
|
4403 |
!(conf_func->compare_collation()->state & MY_CS_BINSORT)) |
|
4404 |
goto end; |
|
4405 |
||
4406 |
if (param->using_real_indexes) |
|
4407 |
optimize_range= field->optimize_range(param->real_keynr[key_part->key], |
|
4408 |
key_part->part); |
|
4409 |
else
|
|
55
by brian
Update for using real bool types. |
4410 |
optimize_range= true; |
1
by brian
clean slate |
4411 |
|
4412 |
if (type == Item_func::LIKE_FUNC) |
|
4413 |
{
|
|
4414 |
bool like_error; |
|
4415 |
char buff1[MAX_FIELD_WIDTH]; |
|
481
by Brian Aker
Remove all of uchar. |
4416 |
unsigned char *min_str,*max_str; |
1
by brian
clean slate |
4417 |
String tmp(buff1,sizeof(buff1),value->collation.collation),*res; |
4418 |
size_t length, offset, min_length, max_length; |
|
482
by Brian Aker
Remove uint. |
4419 |
uint32_t field_length= field->pack_length()+maybe_null; |
1
by brian
clean slate |
4420 |
|
4421 |
if (!optimize_range) |
|
4422 |
goto end; |
|
4423 |
if (!(res= value->val_str(&tmp))) |
|
4424 |
{
|
|
4425 |
tree= &null_element; |
|
4426 |
goto end; |
|
4427 |
}
|
|
4428 |
||
4429 |
/*
|
|
4430 |
TODO:
|
|
4431 |
Check if this was a function. This should have be optimized away
|
|
4432 |
in the sql_select.cc
|
|
4433 |
*/
|
|
4434 |
if (res != &tmp) |
|
4435 |
{
|
|
4436 |
tmp.copy(*res); // Get own copy |
|
4437 |
res= &tmp; |
|
4438 |
}
|
|
4439 |
if (field->cmp_type() != STRING_RESULT) |
|
4440 |
goto end; // Can only optimize strings |
|
4441 |
||
4442 |
offset=maybe_null; |
|
4443 |
length=key_part->store_length; |
|
4444 |
||
4445 |
if (length != key_part->length + maybe_null) |
|
4446 |
{
|
|
4447 |
/* key packed with length prefix */
|
|
4448 |
offset+= HA_KEY_BLOB_LENGTH; |
|
4449 |
field_length= length - HA_KEY_BLOB_LENGTH; |
|
4450 |
}
|
|
4451 |
else
|
|
4452 |
{
|
|
4453 |
if (unlikely(length < field_length)) |
|
4454 |
{
|
|
4455 |
/*
|
|
4456 |
This can only happen in a table created with UNIREG where one key
|
|
4457 |
overlaps many fields
|
|
4458 |
*/
|
|
4459 |
length= field_length; |
|
4460 |
}
|
|
4461 |
else
|
|
4462 |
field_length= length; |
|
4463 |
}
|
|
4464 |
length+=offset; |
|
481
by Brian Aker
Remove all of uchar. |
4465 |
if (!(min_str= (unsigned char*) alloc_root(alloc, length*2))) |
1
by brian
clean slate |
4466 |
goto end; |
4467 |
||
4468 |
max_str=min_str+length; |
|
4469 |
if (maybe_null) |
|
4470 |
max_str[0]= min_str[0]=0; |
|
4471 |
||
4472 |
field_length-= maybe_null; |
|
4473 |
like_error= my_like_range(field->charset(), |
|
4474 |
res->ptr(), res->length(), |
|
4475 |
((Item_func_like*)(param->cond))->escape, |
|
4476 |
wild_one, wild_many, |
|
4477 |
field_length, |
|
4478 |
(char*) min_str+offset, (char*) max_str+offset, |
|
4479 |
&min_length, &max_length); |
|
4480 |
if (like_error) // Can't optimize with LIKE |
|
4481 |
goto end; |
|
4482 |
||
4483 |
if (offset != maybe_null) // BLOB or VARCHAR |
|
4484 |
{
|
|
4485 |
int2store(min_str+maybe_null,min_length); |
|
4486 |
int2store(max_str+maybe_null,max_length); |
|
4487 |
}
|
|
4488 |
tree= new (alloc) SEL_ARG(field, min_str, max_str); |
|
4489 |
goto end; |
|
4490 |
}
|
|
4491 |
||
4492 |
if (!optimize_range && |
|
4493 |
type != Item_func::EQ_FUNC && |
|
4494 |
type != Item_func::EQUAL_FUNC) |
|
4495 |
goto end; // Can't optimize this |
|
4496 |
||
4497 |
/*
|
|
4498 |
We can't always use indexes when comparing a string index to a number
|
|
4499 |
cmp_type() is checked to allow compare of dates to numbers
|
|
4500 |
*/
|
|
4501 |
if (field->result_type() == STRING_RESULT && |
|
4502 |
value->result_type() != STRING_RESULT && |
|
4503 |
field->cmp_type() != value->result_type()) |
|
4504 |
goto end; |
|
907.1.7
by Jay Pipes
Merged in remove-timezone work |
4505 |
|
4506 |
/*
|
|
4507 |
* Some notes from Jay...
|
|
4508 |
*
|
|
4509 |
* OK, so previously, and in MySQL, what the optimizer does here is
|
|
4510 |
* override the sql_mode variable to ignore out-of-range or bad date-
|
|
4511 |
* time values. It does this because the optimizer is populating the
|
|
4512 |
* field variable with the incoming value from the comparison field,
|
|
4513 |
* and the value may exceed the bounds of a proper column type.
|
|
4514 |
*
|
|
4515 |
* For instance, assume the following:
|
|
4516 |
*
|
|
4517 |
* CREATE TABLE t1 (ts TIMESTAMP);
|
|
4518 |
* INSERT INTO t1 ('2009-03-04 00:00:00');
|
|
4519 |
* CREATE TABLE t2 (dt1 DATETIME, dt2 DATETIME);
|
|
4520 |
* INSERT INT t2 ('2003-12-31 00:00:00','2999-12-31 00:00:00');
|
|
4521 |
*
|
|
4522 |
* If we issue this query:
|
|
4523 |
*
|
|
4524 |
* SELECT * FROM t1, t2 WHERE t1.ts BETWEEN t2.dt1 AND t2.dt2;
|
|
4525 |
*
|
|
4526 |
* We will come into bounds issues. Field_timestamp::store() will be
|
|
4527 |
* called with a datetime value of "2999-12-31 00:00:00" and will throw
|
|
4528 |
* an error for out-of-bounds. MySQL solves this via a hack with sql_mode
|
|
4529 |
* but Drizzle always throws errors on bad data storage in a Field class.
|
|
4530 |
*
|
|
4531 |
* Therefore, to get around the problem of the Field class being used for
|
|
4532 |
* "storage" here without actually storing anything...we must check to see
|
|
4533 |
* if the value being stored in a Field_timestamp here is out of range. If
|
|
4534 |
* it is, then we must convert to the highest Timestamp value (or lowest,
|
|
4535 |
* depending on whether the datetime is before or after the epoch.
|
|
4536 |
*/
|
|
4537 |
if (field->type() == DRIZZLE_TYPE_TIMESTAMP) |
|
4538 |
{
|
|
4539 |
/*
|
|
4540 |
* The left-side of the range comparison is a timestamp field. Therefore,
|
|
4541 |
* we must check to see if the value in the right-hand side is outside the
|
|
4542 |
* range of the UNIX epoch, and cut to the epoch bounds if it is.
|
|
4543 |
*/
|
|
4544 |
/* Datetime and date columns are Item::FIELD_ITEM ... and have a result type of STRING_RESULT */
|
|
4545 |
if (value->real_item()->type() == Item::FIELD_ITEM |
|
4546 |
&& value->result_type() == STRING_RESULT) |
|
4547 |
{
|
|
4548 |
char buff[MAX_DATETIME_FULL_WIDTH]; |
|
4549 |
String tmp(buff, sizeof(buff), &my_charset_bin); |
|
4550 |
String *res= value->val_str(&tmp); |
|
4551 |
||
4552 |
if (!res) |
|
4553 |
goto end; |
|
4554 |
else
|
|
4555 |
{
|
|
4556 |
/*
|
|
4557 |
* Create a datetime from the string and compare to fixed timestamp
|
|
4558 |
* instances representing the epoch boundaries.
|
|
4559 |
*/
|
|
4560 |
drizzled::DateTime value_datetime; |
|
4561 |
||
4562 |
if (! value_datetime.from_string(res->c_ptr(), (size_t) res->length())) |
|
4563 |
goto end; |
|
4564 |
||
4565 |
drizzled::Timestamp max_timestamp; |
|
4566 |
drizzled::Timestamp min_timestamp; |
|
4567 |
||
4568 |
(void) max_timestamp.from_time_t((time_t) INT32_MAX); |
|
4569 |
(void) min_timestamp.from_time_t((time_t) 0); |
|
4570 |
||
4571 |
/* We rely on Temporal class operator overloads to do our comparisons. */
|
|
4572 |
if (value_datetime < min_timestamp) |
|
4573 |
{
|
|
4574 |
/*
|
|
4575 |
* Datetime in right-hand side column is before UNIX epoch, so adjust to
|
|
4576 |
* lower bound.
|
|
4577 |
*/
|
|
4578 |
char new_value_buff[MAX_DATETIME_FULL_WIDTH]; |
|
4579 |
size_t new_value_length; |
|
4580 |
String new_value_string(new_value_buff, sizeof(new_value_buff), &my_charset_bin); |
|
4581 |
||
4582 |
min_timestamp.to_string(new_value_string.c_ptr(), &new_value_length); |
|
4583 |
new_value_string.length(new_value_length); |
|
4584 |
err= value->save_str_value_in_field(field, &new_value_string); |
|
4585 |
}
|
|
4586 |
else if (value_datetime > max_timestamp) |
|
4587 |
{
|
|
4588 |
/*
|
|
4589 |
* Datetime in right hand side column is after UNIX epoch, so adjust
|
|
4590 |
* to the higher bound of the epoch.
|
|
4591 |
*/
|
|
4592 |
char new_value_buff[MAX_DATETIME_FULL_WIDTH]; |
|
4593 |
size_t new_value_length; |
|
4594 |
String new_value_string(new_value_buff, sizeof(new_value_buff), &my_charset_bin); |
|
4595 |
||
4596 |
max_timestamp.to_string(new_value_string.c_ptr(), &new_value_length); |
|
4597 |
new_value_string.length(new_value_length); |
|
4598 |
err= value->save_str_value_in_field(field, &new_value_string); |
|
4599 |
}
|
|
4600 |
else
|
|
4601 |
err= value->save_in_field(field, 1); |
|
4602 |
}
|
|
4603 |
}
|
|
4604 |
else /* Not a datetime -> timestamp comparison */ |
|
4605 |
err= value->save_in_field(field, 1); |
|
4606 |
}
|
|
4607 |
else /* Not a timestamp comparison */ |
|
4608 |
err= value->save_in_field(field, 1); |
|
4609 |
||
1
by brian
clean slate |
4610 |
if (err > 0) |
4611 |
{
|
|
4612 |
if (field->cmp_type() != value->result_type()) |
|
4613 |
{
|
|
4614 |
if ((type == Item_func::EQ_FUNC || type == Item_func::EQUAL_FUNC) && |
|
4615 |
value->result_type() == item_cmp_type(field->result_type(), |
|
4616 |
value->result_type())) |
|
4617 |
{
|
|
4618 |
tree= new (alloc) SEL_ARG(field, 0, 0); |
|
4619 |
tree->type= SEL_ARG::IMPOSSIBLE; |
|
4620 |
goto end; |
|
4621 |
}
|
|
4622 |
else
|
|
4623 |
{
|
|
4624 |
/*
|
|
4625 |
TODO: We should return trees of the type SEL_ARG::IMPOSSIBLE
|
|
4626 |
for the cases like int_field > 999999999999999999999999 as well.
|
|
4627 |
*/
|
|
4628 |
tree= 0; |
|
575.5.1
by David Axmark
Changed NEWDATE to DATE. One failing test but I think its somewhere else in the code |
4629 |
if (err == 3 && field->type() == DRIZZLE_TYPE_DATE && |
1
by brian
clean slate |
4630 |
(type == Item_func::GT_FUNC || type == Item_func::GE_FUNC || |
4631 |
type == Item_func::LT_FUNC || type == Item_func::LE_FUNC) ) |
|
4632 |
{
|
|
4633 |
/*
|
|
4634 |
We were saving DATETIME into a DATE column, the conversion went ok
|
|
4635 |
but a non-zero time part was cut off.
|
|
4636 |
||
4637 |
In MySQL's SQL dialect, DATE and DATETIME are compared as datetime
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4638 |
values. Index over a DATE column uses DATE comparison. Changing
|
1
by brian
clean slate |
4639 |
from one comparison to the other is possible:
|
4640 |
||
4641 |
datetime(date_col)< '2007-12-10 12:34:55' -> date_col<='2007-12-10'
|
|
4642 |
datetime(date_col)<='2007-12-10 12:34:55' -> date_col<='2007-12-10'
|
|
4643 |
||
4644 |
datetime(date_col)> '2007-12-10 12:34:55' -> date_col>='2007-12-10'
|
|
4645 |
datetime(date_col)>='2007-12-10 12:34:55' -> date_col>='2007-12-10'
|
|
4646 |
||
4647 |
but we'll need to convert '>' to '>=' and '<' to '<='. This will
|
|
4648 |
be done together with other types at the end of this function
|
|
4649 |
(grep for field_is_equal_to_item)
|
|
4650 |
*/
|
|
4651 |
}
|
|
4652 |
else
|
|
4653 |
goto end; |
|
4654 |
}
|
|
4655 |
}
|
|
4656 |
||
4657 |
/*
|
|
4658 |
guaranteed at this point: err > 0; field and const of same type
|
|
4659 |
If an integer got bounded (e.g. to within 0..255 / -128..127)
|
|
4660 |
for < or >, set flags as for <= or >= (no NEAR_MAX / NEAR_MIN)
|
|
4661 |
*/
|
|
4662 |
else if (err == 1 && field->result_type() == INT_RESULT) |
|
4663 |
{
|
|
4664 |
if (type == Item_func::LT_FUNC && (value->val_int() > 0)) |
|
4665 |
type = Item_func::LE_FUNC; |
|
4666 |
else if (type == Item_func::GT_FUNC && |
|
4667 |
!((Field_num*)field)->unsigned_flag && |
|
4668 |
!((Item_int*)value)->unsigned_flag && |
|
4669 |
(value->val_int() < 0)) |
|
4670 |
type = Item_func::GE_FUNC; |
|
4671 |
}
|
|
4672 |
}
|
|
4673 |
else if (err < 0) |
|
4674 |
{
|
|
4675 |
/* This happens when we try to insert a NULL field in a not null column */
|
|
55
by brian
Update for using real bool types. |
4676 |
tree= &null_element; // cmp with NULL is never true |
1
by brian
clean slate |
4677 |
goto end; |
4678 |
}
|
|
481
by Brian Aker
Remove all of uchar. |
4679 |
str= (unsigned char*) alloc_root(alloc, key_part->store_length+1); |
1
by brian
clean slate |
4680 |
if (!str) |
4681 |
goto end; |
|
4682 |
if (maybe_null) |
|
481
by Brian Aker
Remove all of uchar. |
4683 |
*str= (unsigned char) field->is_real_null(); // Set to 1 if null |
1
by brian
clean slate |
4684 |
field->get_key_image(str+maybe_null, key_part->length, |
4685 |
key_part->image_type); |
|
4686 |
if (!(tree= new (alloc) SEL_ARG(field, str, str))) |
|
4687 |
goto end; // out of memory |
|
4688 |
||
4689 |
/*
|
|
4690 |
Check if we are comparing an UNSIGNED integer with a negative constant.
|
|
4691 |
In this case we know that:
|
|
55
by brian
Update for using real bool types. |
4692 |
(a) (unsigned_int [< | <=] negative_constant) == false
|
4693 |
(b) (unsigned_int [> | >=] negative_constant) == true
|
|
1
by brian
clean slate |
4694 |
In case (a) the condition is false for all values, and in case (b) it
|
4695 |
is true for all values, so we can avoid unnecessary retrieval and condition
|
|
4696 |
testing, and we also get correct comparison of unsinged integers with
|
|
4697 |
negative integers (which otherwise fails because at query execution time
|
|
4698 |
negative integers are cast to unsigned if compared with unsigned).
|
|
4699 |
*/
|
|
4700 |
if (field->result_type() == INT_RESULT && |
|
4701 |
value->result_type() == INT_RESULT && |
|
4702 |
((Field_num*)field)->unsigned_flag && !((Item_int*)value)->unsigned_flag) |
|
4703 |
{
|
|
152
by Brian Aker
longlong replacement |
4704 |
int64_t item_val= value->val_int(); |
1
by brian
clean slate |
4705 |
if (item_val < 0) |
4706 |
{
|
|
4707 |
if (type == Item_func::LT_FUNC || type == Item_func::LE_FUNC) |
|
4708 |
{
|
|
4709 |
tree->type= SEL_ARG::IMPOSSIBLE; |
|
4710 |
goto end; |
|
4711 |
}
|
|
4712 |
if (type == Item_func::GT_FUNC || type == Item_func::GE_FUNC) |
|
4713 |
{
|
|
4714 |
tree= 0; |
|
4715 |
goto end; |
|
4716 |
}
|
|
4717 |
}
|
|
4718 |
}
|
|
4719 |
||
4720 |
switch (type) { |
|
4721 |
case Item_func::LT_FUNC: |
|
4722 |
if (field_is_equal_to_item(field,value)) |
|
4723 |
tree->max_flag=NEAR_MAX; |
|
4724 |
/* fall through */
|
|
4725 |
case Item_func::LE_FUNC: |
|
4726 |
if (!maybe_null) |
|
4727 |
tree->min_flag=NO_MIN_RANGE; /* From start */ |
|
4728 |
else
|
|
4729 |
{ // > NULL |
|
4730 |
tree->min_value=is_null_string; |
|
4731 |
tree->min_flag=NEAR_MIN; |
|
4732 |
}
|
|
4733 |
break; |
|
4734 |
case Item_func::GT_FUNC: |
|
4735 |
/* Don't use open ranges for partial key_segments */
|
|
4736 |
if (field_is_equal_to_item(field,value) && |
|
4737 |
!(key_part->flag & HA_PART_KEY_SEG)) |
|
4738 |
tree->min_flag=NEAR_MIN; |
|
4739 |
/* fall through */
|
|
4740 |
case Item_func::GE_FUNC: |
|
4741 |
tree->max_flag=NO_MAX_RANGE; |
|
4742 |
break; |
|
4743 |
default: |
|
4744 |
break; |
|
4745 |
}
|
|
4746 |
||
4747 |
end: |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
4748 |
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. |
4749 |
return(tree); |
1
by brian
clean slate |
4750 |
}
|
4751 |
||
4752 |
||
4753 |
/******************************************************************************
|
|
4754 |
** Tree manipulation functions
|
|
4755 |
** If tree is 0 it means that the condition can't be tested. It refers
|
|
4756 |
** to a non existent table or to a field in current table with isn't a key.
|
|
4757 |
** The different tree flags:
|
|
55
by brian
Update for using real bool types. |
4758 |
** IMPOSSIBLE: Condition is never true
|
4759 |
** ALWAYS: Condition is always true
|
|
1
by brian
clean slate |
4760 |
** MAYBE: Condition may exists when tables are read
|
4761 |
** MAYBE_KEY: Condition refers to a key that may be used in join loop
|
|
4762 |
** KEY_RANGE: Condition uses a key
|
|
4763 |
******************************************************************************/
|
|
4764 |
||
4765 |
/*
|
|
4766 |
Add a new key test to a key when scanning through all keys
|
|
4767 |
This will never be called for same key parts.
|
|
4768 |
*/
|
|
4769 |
||
4770 |
static SEL_ARG * |
|
4771 |
sel_add(SEL_ARG *key1,SEL_ARG *key2) |
|
4772 |
{
|
|
4773 |
SEL_ARG *root,**key_link; |
|
4774 |
||
4775 |
if (!key1) |
|
4776 |
return key2; |
|
4777 |
if (!key2) |
|
4778 |
return key1; |
|
4779 |
||
4780 |
key_link= &root; |
|
4781 |
while (key1 && key2) |
|
4782 |
{
|
|
4783 |
if (key1->part < key2->part) |
|
4784 |
{
|
|
4785 |
*key_link= key1; |
|
4786 |
key_link= &key1->next_key_part; |
|
4787 |
key1=key1->next_key_part; |
|
4788 |
}
|
|
4789 |
else
|
|
4790 |
{
|
|
4791 |
*key_link= key2; |
|
4792 |
key_link= &key2->next_key_part; |
|
4793 |
key2=key2->next_key_part; |
|
4794 |
}
|
|
4795 |
}
|
|
4796 |
*key_link=key1 ? key1 : key2; |
|
4797 |
return root; |
|
4798 |
}
|
|
4799 |
||
4800 |
#define CLONE_KEY1_MAYBE 1
|
|
4801 |
#define CLONE_KEY2_MAYBE 2
|
|
4802 |
#define swap_clone_flag(A) ((A & 1) << 1) | ((A & 2) >> 1)
|
|
4803 |
||
4804 |
||
4805 |
static SEL_TREE * |
|
4806 |
tree_and(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) |
|
4807 |
{
|
|
4808 |
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. |
4809 |
return(tree2); |
1
by brian
clean slate |
4810 |
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. |
4811 |
return(tree1); |
1
by brian
clean slate |
4812 |
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. |
4813 |
return(tree1); |
1
by brian
clean slate |
4814 |
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. |
4815 |
return(tree2); |
1
by brian
clean slate |
4816 |
if (tree1->type == SEL_TREE::MAYBE) |
4817 |
{
|
|
4818 |
if (tree2->type == SEL_TREE::KEY) |
|
4819 |
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. |
4820 |
return(tree2); |
1
by brian
clean slate |
4821 |
}
|
4822 |
if (tree2->type == SEL_TREE::MAYBE) |
|
4823 |
{
|
|
4824 |
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. |
4825 |
return(tree1); |
1
by brian
clean slate |
4826 |
}
|
4827 |
key_map result_keys; |
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
4828 |
result_keys.reset(); |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4829 |
|
1
by brian
clean slate |
4830 |
/* Join the trees key per key */
|
4831 |
SEL_ARG **key1,**key2,**end; |
|
4832 |
for (key1= tree1->keys,key2= tree2->keys,end=key1+param->keys ; |
|
4833 |
key1 != end ; key1++,key2++) |
|
4834 |
{
|
|
482
by Brian Aker
Remove uint. |
4835 |
uint32_t flag=0; |
1
by brian
clean slate |
4836 |
if (*key1 || *key2) |
4837 |
{
|
|
4838 |
if (*key1 && !(*key1)->simple_key()) |
|
4839 |
flag|=CLONE_KEY1_MAYBE; |
|
4840 |
if (*key2 && !(*key2)->simple_key()) |
|
4841 |
flag|=CLONE_KEY2_MAYBE; |
|
4842 |
*key1=key_and(param, *key1, *key2, flag); |
|
4843 |
if (*key1 && (*key1)->type == SEL_ARG::IMPOSSIBLE) |
|
4844 |
{
|
|
4845 |
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. |
4846 |
return(tree1); |
1
by brian
clean slate |
4847 |
}
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
4848 |
result_keys.set(key1 - tree1->keys); |
1
by brian
clean slate |
4849 |
#ifdef EXTRA_DEBUG
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4850 |
if (*key1 && param->alloced_sel_args < SEL_ARG::MAX_SEL_ARGS) |
1
by brian
clean slate |
4851 |
(*key1)->test_use_count(*key1); |
4852 |
#endif
|
|
4853 |
}
|
|
4854 |
}
|
|
4855 |
tree1->keys_map= result_keys; |
|
4856 |
/* dispose index_merge if there is a "range" option */
|
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
4857 |
if (result_keys.any()) |
1
by brian
clean slate |
4858 |
{
|
4859 |
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. |
4860 |
return(tree1); |
1
by brian
clean slate |
4861 |
}
|
4862 |
||
4863 |
/* ok, both trees are index_merge trees */
|
|
4864 |
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. |
4865 |
return(tree1); |
1
by brian
clean slate |
4866 |
}
|
4867 |
||
4868 |
||
4869 |
/*
|
|
4870 |
Check if two SEL_TREES can be combined into one (i.e. a single key range
|
|
4871 |
read can be constructed for "cond_of_tree1 OR cond_of_tree2" ) without
|
|
4872 |
using index_merge.
|
|
4873 |
*/
|
|
4874 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4875 |
bool sel_trees_can_be_ored(SEL_TREE *tree1, SEL_TREE *tree2, |
1
by brian
clean slate |
4876 |
RANGE_OPT_PARAM* param) |
4877 |
{
|
|
4878 |
key_map common_keys= tree1->keys_map; |
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
4879 |
common_keys&= tree2->keys_map; |
1
by brian
clean slate |
4880 |
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
4881 |
if (common_keys.none()) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4882 |
return false; |
1
by brian
clean slate |
4883 |
|
4884 |
/* trees have a common key, check if they refer to same key part */
|
|
4885 |
SEL_ARG **key1,**key2; |
|
482
by Brian Aker
Remove uint. |
4886 |
for (uint32_t key_no=0; key_no < param->keys; key_no++) |
1
by brian
clean slate |
4887 |
{
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
4888 |
if (common_keys.test(key_no)) |
1
by brian
clean slate |
4889 |
{
|
4890 |
key1= tree1->keys + key_no; |
|
4891 |
key2= tree2->keys + key_no; |
|
4892 |
if ((*key1)->part == (*key2)->part) |
|
4893 |
{
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4894 |
return true; |
1
by brian
clean slate |
4895 |
}
|
4896 |
}
|
|
4897 |
}
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4898 |
return false; |
1
by brian
clean slate |
4899 |
}
|
4900 |
||
4901 |
||
4902 |
/*
|
|
4903 |
Remove the trees that are not suitable for record retrieval.
|
|
4904 |
SYNOPSIS
|
|
4905 |
param Range analysis parameter
|
|
4906 |
tree Tree to be processed, tree->type is KEY or KEY_SMALLER
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4907 |
|
1
by brian
clean slate |
4908 |
DESCRIPTION
|
4909 |
This function walks through tree->keys[] and removes the SEL_ARG* trees
|
|
4910 |
that are not "maybe" trees (*) and cannot be used to construct quick range
|
|
4911 |
selects.
|
|
4912 |
(*) - have type MAYBE or MAYBE_KEY. Perhaps we should remove trees of
|
|
4913 |
these types here as well.
|
|
4914 |
||
4915 |
A SEL_ARG* tree cannot be used to construct quick select if it has
|
|
4916 |
tree->part != 0. (e.g. it could represent "keypart2 < const").
|
|
4917 |
||
4918 |
WHY THIS FUNCTION IS NEEDED
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4919 |
|
1
by brian
clean slate |
4920 |
Normally we allow construction of SEL_TREE objects that have SEL_ARG
|
4921 |
trees that do not allow quick range select construction. For example for
|
|
4922 |
" keypart1=1 AND keypart2=2 " the execution will proceed as follows:
|
|
4923 |
tree1= SEL_TREE { SEL_ARG{keypart1=1} }
|
|
4924 |
tree2= SEL_TREE { SEL_ARG{keypart2=2} } -- can't make quick range select
|
|
4925 |
from this
|
|
4926 |
call tree_and(tree1, tree2) -- this joins SEL_ARGs into a usable SEL_ARG
|
|
4927 |
tree.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4928 |
|
1
by brian
clean slate |
4929 |
There is an exception though: when we construct index_merge SEL_TREE,
|
4930 |
any SEL_ARG* tree that cannot be used to construct quick range select can
|
|
4931 |
be removed, because current range analysis code doesn't provide any way
|
|
4932 |
that tree could be later combined with another tree.
|
|
4933 |
Consider an example: we should not construct
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4934 |
st1 = SEL_TREE {
|
4935 |
merges = SEL_IMERGE {
|
|
4936 |
SEL_TREE(t.key1part1 = 1),
|
|
1
by brian
clean slate |
4937 |
SEL_TREE(t.key2part2 = 2) -- (*)
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4938 |
}
|
1
by brian
clean slate |
4939 |
};
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4940 |
because
|
4941 |
- (*) cannot be used to construct quick range select,
|
|
4942 |
- There is no execution path that would cause (*) to be converted to
|
|
1
by brian
clean slate |
4943 |
a tree that could be used.
|
4944 |
||
4945 |
The latter is easy to verify: first, notice that the only way to convert
|
|
4946 |
(*) into a usable tree is to call tree_and(something, (*)).
|
|
4947 |
||
4948 |
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: |
4949 |
SEL_TREE that has the structure like st1 tree has, and conlcude that
|
1
by brian
clean slate |
4950 |
tree_and(something, (*)) will not be called.
|
4951 |
||
4952 |
RETURN
|
|
4953 |
0 Ok, some suitable trees left
|
|
4954 |
1 No tree->keys[] left.
|
|
4955 |
*/
|
|
4956 |
||
4957 |
static bool remove_nonrange_trees(RANGE_OPT_PARAM *param, SEL_TREE *tree) |
|
4958 |
{
|
|
55
by brian
Update for using real bool types. |
4959 |
bool res= false; |
482
by Brian Aker
Remove uint. |
4960 |
for (uint32_t i=0; i < param->keys; i++) |
1
by brian
clean slate |
4961 |
{
|
4962 |
if (tree->keys[i]) |
|
4963 |
{
|
|
4964 |
if (tree->keys[i]->part) |
|
4965 |
{
|
|
4966 |
tree->keys[i]= NULL; |
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
4967 |
tree->keys_map.reset(i); |
1
by brian
clean slate |
4968 |
}
|
4969 |
else
|
|
55
by brian
Update for using real bool types. |
4970 |
res= true; |
1
by brian
clean slate |
4971 |
}
|
4972 |
}
|
|
4973 |
return !res; |
|
4974 |
}
|
|
4975 |
||
4976 |
||
4977 |
static SEL_TREE * |
|
4978 |
tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) |
|
4979 |
{
|
|
4980 |
if (!tree1 || !tree2) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
4981 |
return 0; |
1
by brian
clean slate |
4982 |
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. |
4983 |
return(tree2); |
1
by brian
clean slate |
4984 |
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. |
4985 |
return(tree1); |
1
by brian
clean slate |
4986 |
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. |
4987 |
return(tree1); // Can't use this |
1
by brian
clean slate |
4988 |
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. |
4989 |
return(tree2); |
1
by brian
clean slate |
4990 |
|
4991 |
SEL_TREE *result= 0; |
|
4992 |
key_map result_keys; |
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
4993 |
result_keys.reset(); |
1
by brian
clean slate |
4994 |
if (sel_trees_can_be_ored(tree1, tree2, param)) |
4995 |
{
|
|
4996 |
/* Join the trees key per key */
|
|
4997 |
SEL_ARG **key1,**key2,**end; |
|
4998 |
for (key1= tree1->keys,key2= tree2->keys,end= key1+param->keys ; |
|
4999 |
key1 != end ; key1++,key2++) |
|
5000 |
{
|
|
5001 |
*key1=key_or(param, *key1, *key2); |
|
5002 |
if (*key1) |
|
5003 |
{
|
|
5004 |
result=tree1; // Added to tree1 |
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
5005 |
result_keys.set(key1 - tree1->keys); |
1
by brian
clean slate |
5006 |
#ifdef EXTRA_DEBUG
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5007 |
if (param->alloced_sel_args < SEL_ARG::MAX_SEL_ARGS) |
1
by brian
clean slate |
5008 |
(*key1)->test_use_count(*key1); |
5009 |
#endif
|
|
5010 |
}
|
|
5011 |
}
|
|
5012 |
if (result) |
|
5013 |
result->keys_map= result_keys; |
|
5014 |
}
|
|
5015 |
else
|
|
5016 |
{
|
|
5017 |
/* ok, two trees have KEY type but cannot be used without index merge */
|
|
5018 |
if (tree1->merges.is_empty() && tree2->merges.is_empty()) |
|
5019 |
{
|
|
5020 |
if (param->remove_jump_scans) |
|
5021 |
{
|
|
5022 |
bool no_trees= remove_nonrange_trees(param, tree1); |
|
5023 |
no_trees= no_trees || remove_nonrange_trees(param, tree2); |
|
5024 |
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. |
5025 |
return(new SEL_TREE(SEL_TREE::ALWAYS)); |
1
by brian
clean slate |
5026 |
}
|
5027 |
SEL_IMERGE *merge; |
|
5028 |
/* both trees are "range" trees, produce new index merge structure */
|
|
5029 |
if (!(result= new SEL_TREE()) || !(merge= new SEL_IMERGE()) || |
|
5030 |
(result->merges.push_back(merge)) || |
|
5031 |
(merge->or_sel_tree(param, tree1)) || |
|
5032 |
(merge->or_sel_tree(param, tree2))) |
|
5033 |
result= NULL; |
|
5034 |
else
|
|
5035 |
result->type= tree1->type; |
|
5036 |
}
|
|
5037 |
else if (!tree1->merges.is_empty() && !tree2->merges.is_empty()) |
|
5038 |
{
|
|
5039 |
if (imerge_list_or_list(param, &tree1->merges, &tree2->merges)) |
|
5040 |
result= new SEL_TREE(SEL_TREE::ALWAYS); |
|
5041 |
else
|
|
5042 |
result= tree1; |
|
5043 |
}
|
|
5044 |
else
|
|
5045 |
{
|
|
5046 |
/* one tree is index merge tree and another is range tree */
|
|
5047 |
if (tree1->merges.is_empty()) |
|
322.2.2
by Mats Kindahl
Hiding THD::proc_info field and providing a setter and getter. |
5048 |
std::swap(tree1, tree2); |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5049 |
|
1
by brian
clean slate |
5050 |
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. |
5051 |
return(new SEL_TREE(SEL_TREE::ALWAYS)); |
1
by brian
clean slate |
5052 |
/* add tree2 to tree1->merges, checking if it collapses to ALWAYS */
|
5053 |
if (imerge_list_or_tree(param, &tree1->merges, tree2)) |
|
5054 |
result= new SEL_TREE(SEL_TREE::ALWAYS); |
|
5055 |
else
|
|
5056 |
result= tree1; |
|
5057 |
}
|
|
5058 |
}
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
5059 |
return result; |
1
by brian
clean slate |
5060 |
}
|
5061 |
||
5062 |
||
5063 |
/* And key trees where key1->part < key2 -> part */
|
|
5064 |
||
5065 |
static SEL_ARG * |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5066 |
and_all_keys(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, |
482
by Brian Aker
Remove uint. |
5067 |
uint32_t clone_flag) |
1
by brian
clean slate |
5068 |
{
|
5069 |
SEL_ARG *next; |
|
5070 |
ulong use_count=key1->use_count; |
|
5071 |
||
5072 |
if (key1->elements != 1) |
|
5073 |
{
|
|
5074 |
key2->use_count+=key1->elements-1; //psergey: why we don't count that key1 has n-k-p? |
|
5075 |
key2->increment_use_count((int) key1->elements-1); |
|
5076 |
}
|
|
5077 |
if (key1->type == SEL_ARG::MAYBE_KEY) |
|
5078 |
{
|
|
5079 |
key1->right= key1->left= &null_element; |
|
5080 |
key1->next= key1->prev= 0; |
|
5081 |
}
|
|
5082 |
for (next=key1->first(); next ; next=next->next) |
|
5083 |
{
|
|
5084 |
if (next->next_key_part) |
|
5085 |
{
|
|
5086 |
SEL_ARG *tmp= key_and(param, next->next_key_part, key2, clone_flag); |
|
5087 |
if (tmp && tmp->type == SEL_ARG::IMPOSSIBLE) |
|
5088 |
{
|
|
5089 |
key1=key1->tree_delete(next); |
|
5090 |
continue; |
|
5091 |
}
|
|
5092 |
next->next_key_part=tmp; |
|
5093 |
if (use_count) |
|
5094 |
next->increment_use_count(use_count); |
|
5095 |
if (param->alloced_sel_args > SEL_ARG::MAX_SEL_ARGS) |
|
5096 |
break; |
|
5097 |
}
|
|
5098 |
else
|
|
5099 |
next->next_key_part=key2; |
|
5100 |
}
|
|
5101 |
if (!key1) |
|
5102 |
return &null_element; // Impossible ranges |
|
5103 |
key1->use_count++; |
|
5104 |
return key1; |
|
5105 |
}
|
|
5106 |
||
5107 |
||
5108 |
/*
|
|
5109 |
Produce a SEL_ARG graph that represents "key1 AND key2"
|
|
5110 |
||
5111 |
SYNOPSIS
|
|
5112 |
key_and()
|
|
5113 |
param Range analysis context (needed to track if we have allocated
|
|
5114 |
too many SEL_ARGs)
|
|
5115 |
key1 First argument, root of its RB-tree
|
|
5116 |
key2 Second argument, root of its RB-tree
|
|
5117 |
||
5118 |
RETURN
|
|
5119 |
RB-tree root of the resulting SEL_ARG graph.
|
|
5120 |
NULL if the result of AND operation is an empty interval {0}.
|
|
5121 |
*/
|
|
5122 |
||
5123 |
static SEL_ARG * |
|
482
by Brian Aker
Remove uint. |
5124 |
key_and(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, uint32_t clone_flag) |
1
by brian
clean slate |
5125 |
{
|
5126 |
if (!key1) |
|
5127 |
return key2; |
|
5128 |
if (!key2) |
|
5129 |
return key1; |
|
5130 |
if (key1->part != key2->part) |
|
5131 |
{
|
|
5132 |
if (key1->part > key2->part) |
|
5133 |
{
|
|
322.2.2
by Mats Kindahl
Hiding THD::proc_info field and providing a setter and getter. |
5134 |
std::swap(key1, key2); |
1
by brian
clean slate |
5135 |
clone_flag=swap_clone_flag(clone_flag); |
5136 |
}
|
|
5137 |
// key1->part < key2->part
|
|
5138 |
key1->use_count--; |
|
5139 |
if (key1->use_count > 0) |
|
5140 |
if (!(key1= key1->clone_tree(param))) |
|
5141 |
return 0; // OOM |
|
5142 |
return and_all_keys(param, key1, key2, clone_flag); |
|
5143 |
}
|
|
5144 |
||
5145 |
if (((clone_flag & CLONE_KEY2_MAYBE) && |
|
5146 |
!(clone_flag & CLONE_KEY1_MAYBE) && |
|
5147 |
key2->type != SEL_ARG::MAYBE_KEY) || |
|
5148 |
key1->type == SEL_ARG::MAYBE_KEY) |
|
5149 |
{ // Put simple key in key2 |
|
322.2.2
by Mats Kindahl
Hiding THD::proc_info field and providing a setter and getter. |
5150 |
std::swap(key1, key2); |
1
by brian
clean slate |
5151 |
clone_flag=swap_clone_flag(clone_flag); |
5152 |
}
|
|
5153 |
||
5154 |
/* If one of the key is MAYBE_KEY then the found region may be smaller */
|
|
5155 |
if (key2->type == SEL_ARG::MAYBE_KEY) |
|
5156 |
{
|
|
5157 |
if (key1->use_count > 1) |
|
5158 |
{
|
|
5159 |
key1->use_count--; |
|
5160 |
if (!(key1=key1->clone_tree(param))) |
|
5161 |
return 0; // OOM |
|
5162 |
key1->use_count++; |
|
5163 |
}
|
|
5164 |
if (key1->type == SEL_ARG::MAYBE_KEY) |
|
5165 |
{ // Both are maybe key |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5166 |
key1->next_key_part=key_and(param, key1->next_key_part, |
1
by brian
clean slate |
5167 |
key2->next_key_part, clone_flag); |
5168 |
if (key1->next_key_part && |
|
5169 |
key1->next_key_part->type == SEL_ARG::IMPOSSIBLE) |
|
5170 |
return key1; |
|
5171 |
}
|
|
5172 |
else
|
|
5173 |
{
|
|
5174 |
key1->maybe_smaller(); |
|
5175 |
if (key2->next_key_part) |
|
5176 |
{
|
|
5177 |
key1->use_count--; // Incremented in and_all_keys |
|
5178 |
return and_all_keys(param, key1, key2, clone_flag); |
|
5179 |
}
|
|
5180 |
key2->use_count--; // Key2 doesn't have a tree |
|
5181 |
}
|
|
5182 |
return key1; |
|
5183 |
}
|
|
5184 |
||
5185 |
key1->use_count--; |
|
5186 |
key2->use_count--; |
|
5187 |
SEL_ARG *e1=key1->first(), *e2=key2->first(), *new_tree=0; |
|
5188 |
||
5189 |
while (e1 && e2) |
|
5190 |
{
|
|
5191 |
int cmp=e1->cmp_min_to_min(e2); |
|
5192 |
if (cmp < 0) |
|
5193 |
{
|
|
5194 |
if (get_range(&e1,&e2,key1)) |
|
5195 |
continue; |
|
5196 |
}
|
|
5197 |
else if (get_range(&e2,&e1,key2)) |
|
5198 |
continue; |
|
5199 |
SEL_ARG *next=key_and(param, e1->next_key_part, e2->next_key_part, |
|
5200 |
clone_flag); |
|
5201 |
e1->increment_use_count(1); |
|
5202 |
e2->increment_use_count(1); |
|
5203 |
if (!next || next->type != SEL_ARG::IMPOSSIBLE) |
|
5204 |
{
|
|
5205 |
SEL_ARG *new_arg= e1->clone_and(e2); |
|
5206 |
if (!new_arg) |
|
5207 |
return &null_element; // End of memory |
|
5208 |
new_arg->next_key_part=next; |
|
5209 |
if (!new_tree) |
|
5210 |
{
|
|
5211 |
new_tree=new_arg; |
|
5212 |
}
|
|
5213 |
else
|
|
5214 |
new_tree=new_tree->insert(new_arg); |
|
5215 |
}
|
|
5216 |
if (e1->cmp_max_to_max(e2) < 0) |
|
5217 |
e1=e1->next; // e1 can't overlapp next e2 |
|
5218 |
else
|
|
5219 |
e2=e2->next; |
|
5220 |
}
|
|
5221 |
key1->free_tree(); |
|
5222 |
key2->free_tree(); |
|
5223 |
if (!new_tree) |
|
5224 |
return &null_element; // Impossible range |
|
5225 |
return new_tree; |
|
5226 |
}
|
|
5227 |
||
5228 |
||
5229 |
static bool |
|
5230 |
get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1) |
|
5231 |
{
|
|
5232 |
(*e1)=root1->find_range(*e2); // first e1->min < e2->min |
|
5233 |
if ((*e1)->cmp_max_to_min(*e2) < 0) |
|
5234 |
{
|
|
5235 |
if (!((*e1)=(*e1)->next)) |
|
5236 |
return 1; |
|
5237 |
if ((*e1)->cmp_min_to_max(*e2) > 0) |
|
5238 |
{
|
|
5239 |
(*e2)=(*e2)->next; |
|
5240 |
return 1; |
|
5241 |
}
|
|
5242 |
}
|
|
5243 |
return 0; |
|
5244 |
}
|
|
5245 |
||
5246 |
||
5247 |
static SEL_ARG * |
|
5248 |
key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) |
|
5249 |
{
|
|
5250 |
if (!key1) |
|
5251 |
{
|
|
5252 |
if (key2) |
|
5253 |
{
|
|
5254 |
key2->use_count--; |
|
5255 |
key2->free_tree(); |
|
5256 |
}
|
|
5257 |
return 0; |
|
5258 |
}
|
|
5259 |
if (!key2) |
|
5260 |
{
|
|
5261 |
key1->use_count--; |
|
5262 |
key1->free_tree(); |
|
5263 |
return 0; |
|
5264 |
}
|
|
5265 |
key1->use_count--; |
|
5266 |
key2->use_count--; |
|
5267 |
||
5268 |
if (key1->part != key2->part) |
|
5269 |
{
|
|
5270 |
key1->free_tree(); |
|
5271 |
key2->free_tree(); |
|
5272 |
return 0; // Can't optimize this |
|
5273 |
}
|
|
5274 |
||
5275 |
// If one of the key is MAYBE_KEY then the found region may be bigger
|
|
5276 |
if (key1->type == SEL_ARG::MAYBE_KEY) |
|
5277 |
{
|
|
5278 |
key2->free_tree(); |
|
5279 |
key1->use_count++; |
|
5280 |
return key1; |
|
5281 |
}
|
|
5282 |
if (key2->type == SEL_ARG::MAYBE_KEY) |
|
5283 |
{
|
|
5284 |
key1->free_tree(); |
|
5285 |
key2->use_count++; |
|
5286 |
return key2; |
|
5287 |
}
|
|
5288 |
||
5289 |
if (key1->use_count > 0) |
|
5290 |
{
|
|
5291 |
if (key2->use_count == 0 || key1->elements > key2->elements) |
|
5292 |
{
|
|
322.2.2
by Mats Kindahl
Hiding THD::proc_info field and providing a setter and getter. |
5293 |
std::swap(key1,key2); |
1
by brian
clean slate |
5294 |
}
|
5295 |
if (key1->use_count > 0 || !(key1=key1->clone_tree(param))) |
|
5296 |
return 0; // OOM |
|
5297 |
}
|
|
5298 |
||
5299 |
// Add tree at key2 to tree at key1
|
|
5300 |
bool key2_shared=key2->use_count != 0; |
|
5301 |
key1->maybe_flag|=key2->maybe_flag; |
|
5302 |
||
5303 |
for (key2=key2->first(); key2; ) |
|
5304 |
{
|
|
5305 |
SEL_ARG *tmp=key1->find_range(key2); // Find key1.min <= key2.min |
|
5306 |
int cmp; |
|
5307 |
||
5308 |
if (!tmp) |
|
5309 |
{
|
|
5310 |
tmp=key1->first(); // tmp.min > key2.min |
|
5311 |
cmp= -1; |
|
5312 |
}
|
|
5313 |
else if ((cmp=tmp->cmp_max_to_min(key2)) < 0) |
|
5314 |
{ // Found tmp.max < key2.min |
|
5315 |
SEL_ARG *next=tmp->next; |
|
5316 |
if (cmp == -2 && eq_tree(tmp->next_key_part,key2->next_key_part)) |
|
5317 |
{
|
|
5318 |
// Join near ranges like tmp.max < 0 and key2.min >= 0
|
|
5319 |
SEL_ARG *key2_next=key2->next; |
|
5320 |
if (key2_shared) |
|
5321 |
{
|
|
5322 |
if (!(key2=new SEL_ARG(*key2))) |
|
5323 |
return 0; // out of memory |
|
5324 |
key2->increment_use_count(key1->use_count+1); |
|
5325 |
key2->next=key2_next; // New copy of key2 |
|
5326 |
}
|
|
5327 |
key2->copy_min(tmp); |
|
5328 |
if (!(key1=key1->tree_delete(tmp))) |
|
5329 |
{ // Only one key in tree |
|
5330 |
key1=key2; |
|
5331 |
key1->make_root(); |
|
5332 |
key2=key2_next; |
|
5333 |
break; |
|
5334 |
}
|
|
5335 |
}
|
|
5336 |
if (!(tmp=next)) // tmp.min > key2.min |
|
5337 |
break; // Copy rest of key2 |
|
5338 |
}
|
|
5339 |
if (cmp < 0) |
|
5340 |
{ // tmp.min > key2.min |
|
5341 |
int tmp_cmp; |
|
5342 |
if ((tmp_cmp=tmp->cmp_min_to_max(key2)) > 0) // if tmp.min > key2.max |
|
5343 |
{
|
|
5344 |
if (tmp_cmp == 2 && eq_tree(tmp->next_key_part,key2->next_key_part)) |
|
5345 |
{ // ranges are connected |
|
5346 |
tmp->copy_min_to_min(key2); |
|
5347 |
key1->merge_flags(key2); |
|
5348 |
if (tmp->min_flag & NO_MIN_RANGE && |
|
5349 |
tmp->max_flag & NO_MAX_RANGE) |
|
5350 |
{
|
|
5351 |
if (key1->maybe_flag) |
|
5352 |
return new SEL_ARG(SEL_ARG::MAYBE_KEY); |
|
5353 |
return 0; |
|
5354 |
}
|
|
5355 |
key2->increment_use_count(-1); // Free not used tree |
|
5356 |
key2=key2->next; |
|
5357 |
continue; |
|
5358 |
}
|
|
5359 |
else
|
|
5360 |
{
|
|
5361 |
SEL_ARG *next=key2->next; // Keys are not overlapping |
|
5362 |
if (key2_shared) |
|
5363 |
{
|
|
5364 |
SEL_ARG *cpy= new SEL_ARG(*key2); // Must make copy |
|
5365 |
if (!cpy) |
|
5366 |
return 0; // OOM |
|
5367 |
key1=key1->insert(cpy); |
|
5368 |
key2->increment_use_count(key1->use_count+1); |
|
5369 |
}
|
|
5370 |
else
|
|
5371 |
key1=key1->insert(key2); // Will destroy key2_root |
|
5372 |
key2=next; |
|
5373 |
continue; |
|
5374 |
}
|
|
5375 |
}
|
|
5376 |
}
|
|
5377 |
||
398.1.4
by Monty Taylor
Renamed max/min. |
5378 |
// tmp.max >= key2.min && tmp.min <= key.cmax(overlapping ranges)
|
1
by brian
clean slate |
5379 |
if (eq_tree(tmp->next_key_part,key2->next_key_part)) |
5380 |
{
|
|
5381 |
if (tmp->is_same(key2)) |
|
5382 |
{
|
|
5383 |
tmp->merge_flags(key2); // Copy maybe flags |
|
5384 |
key2->increment_use_count(-1); // Free not used tree |
|
5385 |
}
|
|
5386 |
else
|
|
5387 |
{
|
|
5388 |
SEL_ARG *last=tmp; |
|
5389 |
while (last->next && last->next->cmp_min_to_max(key2) <= 0 && |
|
5390 |
eq_tree(last->next->next_key_part,key2->next_key_part)) |
|
5391 |
{
|
|
5392 |
SEL_ARG *save=last; |
|
5393 |
last=last->next; |
|
5394 |
key1=key1->tree_delete(save); |
|
5395 |
}
|
|
5396 |
last->copy_min(tmp); |
|
5397 |
if (last->copy_min(key2) || last->copy_max(key2)) |
|
5398 |
{ // Full range |
|
5399 |
key1->free_tree(); |
|
5400 |
for (; key2 ; key2=key2->next) |
|
5401 |
key2->increment_use_count(-1); // Free not used tree |
|
5402 |
if (key1->maybe_flag) |
|
5403 |
return new SEL_ARG(SEL_ARG::MAYBE_KEY); |
|
5404 |
return 0; |
|
5405 |
}
|
|
5406 |
}
|
|
5407 |
key2=key2->next; |
|
5408 |
continue; |
|
5409 |
}
|
|
5410 |
||
5411 |
if (cmp >= 0 && tmp->cmp_min_to_min(key2) < 0) |
|
5412 |
{ // tmp.min <= x < key2.min |
|
5413 |
SEL_ARG *new_arg=tmp->clone_first(key2); |
|
5414 |
if (!new_arg) |
|
5415 |
return 0; // OOM |
|
5416 |
if ((new_arg->next_key_part= key1->next_key_part)) |
|
5417 |
new_arg->increment_use_count(key1->use_count+1); |
|
5418 |
tmp->copy_min_to_min(key2); |
|
5419 |
key1=key1->insert(new_arg); |
|
5420 |
}
|
|
5421 |
||
5422 |
// tmp.min >= key2.min && tmp.min <= key2.max
|
|
5423 |
SEL_ARG key(*key2); // Get copy we can modify |
|
5424 |
for (;;) |
|
5425 |
{
|
|
5426 |
if (tmp->cmp_min_to_min(&key) > 0) |
|
5427 |
{ // key.min <= x < tmp.min |
|
5428 |
SEL_ARG *new_arg=key.clone_first(tmp); |
|
5429 |
if (!new_arg) |
|
5430 |
return 0; // OOM |
|
5431 |
if ((new_arg->next_key_part=key.next_key_part)) |
|
5432 |
new_arg->increment_use_count(key1->use_count+1); |
|
5433 |
key1=key1->insert(new_arg); |
|
5434 |
}
|
|
5435 |
if ((cmp=tmp->cmp_max_to_max(&key)) <= 0) |
|
5436 |
{ // tmp.min. <= x <= tmp.max |
|
5437 |
tmp->maybe_flag|= key.maybe_flag; |
|
5438 |
key.increment_use_count(key1->use_count+1); |
|
5439 |
tmp->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part); |
|
5440 |
if (!cmp) // Key2 is ready |
|
5441 |
break; |
|
5442 |
key.copy_max_to_min(tmp); |
|
5443 |
if (!(tmp=tmp->next)) |
|
5444 |
{
|
|
5445 |
SEL_ARG *tmp2= new SEL_ARG(key); |
|
5446 |
if (!tmp2) |
|
5447 |
return 0; // OOM |
|
5448 |
key1=key1->insert(tmp2); |
|
5449 |
key2=key2->next; |
|
5450 |
goto end; |
|
5451 |
}
|
|
5452 |
if (tmp->cmp_min_to_max(&key) > 0) |
|
5453 |
{
|
|
5454 |
SEL_ARG *tmp2= new SEL_ARG(key); |
|
5455 |
if (!tmp2) |
|
5456 |
return 0; // OOM |
|
5457 |
key1=key1->insert(tmp2); |
|
5458 |
break; |
|
5459 |
}
|
|
5460 |
}
|
|
5461 |
else
|
|
5462 |
{
|
|
5463 |
SEL_ARG *new_arg=tmp->clone_last(&key); // tmp.min <= x <= key.max |
|
5464 |
if (!new_arg) |
|
5465 |
return 0; // OOM |
|
5466 |
tmp->copy_max_to_min(&key); |
|
5467 |
tmp->increment_use_count(key1->use_count+1); |
|
5468 |
/* Increment key count as it may be used for next loop */
|
|
5469 |
key.increment_use_count(1); |
|
5470 |
new_arg->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part); |
|
5471 |
key1=key1->insert(new_arg); |
|
5472 |
break; |
|
5473 |
}
|
|
5474 |
}
|
|
5475 |
key2=key2->next; |
|
5476 |
}
|
|
5477 |
||
5478 |
end: |
|
5479 |
while (key2) |
|
5480 |
{
|
|
5481 |
SEL_ARG *next=key2->next; |
|
5482 |
if (key2_shared) |
|
5483 |
{
|
|
5484 |
SEL_ARG *tmp=new SEL_ARG(*key2); // Must make copy |
|
5485 |
if (!tmp) |
|
5486 |
return 0; |
|
5487 |
key2->increment_use_count(key1->use_count+1); |
|
5488 |
key1=key1->insert(tmp); |
|
5489 |
}
|
|
5490 |
else
|
|
5491 |
key1=key1->insert(key2); // Will destroy key2_root |
|
5492 |
key2=next; |
|
5493 |
}
|
|
5494 |
key1->use_count++; |
|
5495 |
return key1; |
|
5496 |
}
|
|
5497 |
||
5498 |
||
5499 |
/* Compare if two trees are equal */
|
|
5500 |
||
5501 |
static bool eq_tree(SEL_ARG* a,SEL_ARG *b) |
|
5502 |
{
|
|
5503 |
if (a == b) |
|
5504 |
return 1; |
|
5505 |
if (!a || !b || !a->is_same(b)) |
|
5506 |
return 0; |
|
5507 |
if (a->left != &null_element && b->left != &null_element) |
|
5508 |
{
|
|
5509 |
if (!eq_tree(a->left,b->left)) |
|
5510 |
return 0; |
|
5511 |
}
|
|
5512 |
else if (a->left != &null_element || b->left != &null_element) |
|
5513 |
return 0; |
|
5514 |
if (a->right != &null_element && b->right != &null_element) |
|
5515 |
{
|
|
5516 |
if (!eq_tree(a->right,b->right)) |
|
5517 |
return 0; |
|
5518 |
}
|
|
5519 |
else if (a->right != &null_element || b->right != &null_element) |
|
5520 |
return 0; |
|
5521 |
if (a->next_key_part != b->next_key_part) |
|
5522 |
{ // Sub range |
|
5523 |
if (!a->next_key_part != !b->next_key_part || |
|
5524 |
!eq_tree(a->next_key_part, b->next_key_part)) |
|
5525 |
return 0; |
|
5526 |
}
|
|
5527 |
return 1; |
|
5528 |
}
|
|
5529 |
||
5530 |
||
5531 |
SEL_ARG * |
|
5532 |
SEL_ARG::insert(SEL_ARG *key) |
|
5533 |
{
|
|
5534 |
SEL_ARG *element, **par= NULL, *last_element= NULL; |
|
5535 |
||
5536 |
for (element= this; element != &null_element ; ) |
|
5537 |
{
|
|
5538 |
last_element=element; |
|
5539 |
if (key->cmp_min_to_min(element) > 0) |
|
5540 |
{
|
|
5541 |
par= &element->right; element= element->right; |
|
5542 |
}
|
|
5543 |
else
|
|
5544 |
{
|
|
5545 |
par = &element->left; element= element->left; |
|
5546 |
}
|
|
5547 |
}
|
|
5548 |
*par=key; |
|
5549 |
key->parent=last_element; |
|
5550 |
/* Link in list */
|
|
5551 |
if (par == &last_element->left) |
|
5552 |
{
|
|
5553 |
key->next=last_element; |
|
5554 |
if ((key->prev=last_element->prev)) |
|
5555 |
key->prev->next=key; |
|
5556 |
last_element->prev=key; |
|
5557 |
}
|
|
5558 |
else
|
|
5559 |
{
|
|
5560 |
if ((key->next=last_element->next)) |
|
5561 |
key->next->prev=key; |
|
5562 |
key->prev=last_element; |
|
5563 |
last_element->next=key; |
|
5564 |
}
|
|
5565 |
key->left=key->right= &null_element; |
|
5566 |
SEL_ARG *root=rb_insert(key); // rebalance tree |
|
5567 |
root->use_count=this->use_count; // copy root info |
|
5568 |
root->elements= this->elements+1; |
|
5569 |
root->maybe_flag=this->maybe_flag; |
|
5570 |
return root; |
|
5571 |
}
|
|
5572 |
||
5573 |
||
5574 |
/*
|
|
5575 |
** Find best key with min <= given key
|
|
5576 |
** Because the call context this should never return 0 to get_range
|
|
5577 |
*/
|
|
5578 |
||
5579 |
SEL_ARG * |
|
5580 |
SEL_ARG::find_range(SEL_ARG *key) |
|
5581 |
{
|
|
5582 |
SEL_ARG *element=this,*found=0; |
|
5583 |
||
5584 |
for (;;) |
|
5585 |
{
|
|
5586 |
if (element == &null_element) |
|
5587 |
return found; |
|
5588 |
int cmp=element->cmp_min_to_min(key); |
|
5589 |
if (cmp == 0) |
|
5590 |
return element; |
|
5591 |
if (cmp < 0) |
|
5592 |
{
|
|
5593 |
found=element; |
|
5594 |
element=element->right; |
|
5595 |
}
|
|
5596 |
else
|
|
5597 |
element=element->left; |
|
5598 |
}
|
|
5599 |
}
|
|
5600 |
||
5601 |
||
5602 |
/*
|
|
5603 |
Remove a element from the tree
|
|
5604 |
||
5605 |
SYNOPSIS
|
|
5606 |
tree_delete()
|
|
5607 |
key Key that is to be deleted from tree (this)
|
|
5608 |
||
5609 |
NOTE
|
|
5610 |
This also frees all sub trees that is used by the element
|
|
5611 |
||
5612 |
RETURN
|
|
5613 |
root of new tree (with key deleted)
|
|
5614 |
*/
|
|
5615 |
||
5616 |
SEL_ARG * |
|
5617 |
SEL_ARG::tree_delete(SEL_ARG *key) |
|
5618 |
{
|
|
5619 |
enum leaf_color remove_color; |
|
5620 |
SEL_ARG *root,*nod,**par,*fix_par; |
|
5621 |
||
5622 |
root=this; |
|
5623 |
this->parent= 0; |
|
5624 |
||
5625 |
/* Unlink from list */
|
|
5626 |
if (key->prev) |
|
5627 |
key->prev->next=key->next; |
|
5628 |
if (key->next) |
|
5629 |
key->next->prev=key->prev; |
|
5630 |
key->increment_use_count(-1); |
|
5631 |
if (!key->parent) |
|
5632 |
par= &root; |
|
5633 |
else
|
|
5634 |
par=key->parent_ptr(); |
|
5635 |
||
5636 |
if (key->left == &null_element) |
|
5637 |
{
|
|
5638 |
*par=nod=key->right; |
|
5639 |
fix_par=key->parent; |
|
5640 |
if (nod != &null_element) |
|
5641 |
nod->parent=fix_par; |
|
5642 |
remove_color= key->color; |
|
5643 |
}
|
|
5644 |
else if (key->right == &null_element) |
|
5645 |
{
|
|
5646 |
*par= nod=key->left; |
|
5647 |
nod->parent=fix_par=key->parent; |
|
5648 |
remove_color= key->color; |
|
5649 |
}
|
|
5650 |
else
|
|
5651 |
{
|
|
5652 |
SEL_ARG *tmp=key->next; // next bigger key (exist!) |
|
5653 |
nod= *tmp->parent_ptr()= tmp->right; // unlink tmp from tree |
|
5654 |
fix_par=tmp->parent; |
|
5655 |
if (nod != &null_element) |
|
5656 |
nod->parent=fix_par; |
|
5657 |
remove_color= tmp->color; |
|
5658 |
||
5659 |
tmp->parent=key->parent; // Move node in place of key |
|
5660 |
(tmp->left=key->left)->parent=tmp; |
|
5661 |
if ((tmp->right=key->right) != &null_element) |
|
5662 |
tmp->right->parent=tmp; |
|
5663 |
tmp->color=key->color; |
|
5664 |
*par=tmp; |
|
5665 |
if (fix_par == key) // key->right == key->next |
|
5666 |
fix_par=tmp; // new parent of nod |
|
5667 |
}
|
|
5668 |
||
5669 |
if (root == &null_element) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
5670 |
return 0; // Maybe root later |
1
by brian
clean slate |
5671 |
if (remove_color == BLACK) |
5672 |
root=rb_delete_fixup(root,nod,fix_par); |
|
511.2.6
by Monty Taylor
drizzled/ and storage/archive/ are clean. |
5673 |
#ifdef EXTRA_DEBUG
|
1
by brian
clean slate |
5674 |
test_rb_tree(root,root->parent); |
511.2.6
by Monty Taylor
drizzled/ and storage/archive/ are clean. |
5675 |
#endif /* EXTRA_DEBUG */ |
1
by brian
clean slate |
5676 |
|
5677 |
root->use_count=this->use_count; // Fix root counters |
|
5678 |
root->elements=this->elements-1; |
|
5679 |
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. |
5680 |
return(root); |
1
by brian
clean slate |
5681 |
}
|
5682 |
||
5683 |
||
5684 |
/* Functions to fix up the tree after insert and delete */
|
|
5685 |
||
5686 |
static void left_rotate(SEL_ARG **root,SEL_ARG *leaf) |
|
5687 |
{
|
|
5688 |
SEL_ARG *y=leaf->right; |
|
5689 |
leaf->right=y->left; |
|
5690 |
if (y->left != &null_element) |
|
5691 |
y->left->parent=leaf; |
|
5692 |
if (!(y->parent=leaf->parent)) |
|
5693 |
*root=y; |
|
5694 |
else
|
|
5695 |
*leaf->parent_ptr()=y; |
|
5696 |
y->left=leaf; |
|
5697 |
leaf->parent=y; |
|
5698 |
}
|
|
5699 |
||
5700 |
static void right_rotate(SEL_ARG **root,SEL_ARG *leaf) |
|
5701 |
{
|
|
5702 |
SEL_ARG *y=leaf->left; |
|
5703 |
leaf->left=y->right; |
|
5704 |
if (y->right != &null_element) |
|
5705 |
y->right->parent=leaf; |
|
5706 |
if (!(y->parent=leaf->parent)) |
|
5707 |
*root=y; |
|
5708 |
else
|
|
5709 |
*leaf->parent_ptr()=y; |
|
5710 |
y->right=leaf; |
|
5711 |
leaf->parent=y; |
|
5712 |
}
|
|
5713 |
||
5714 |
||
5715 |
SEL_ARG * |
|
5716 |
SEL_ARG::rb_insert(SEL_ARG *leaf) |
|
5717 |
{
|
|
5718 |
SEL_ARG *y,*par,*par2,*root; |
|
5719 |
root= this; root->parent= 0; |
|
5720 |
||
5721 |
leaf->color=RED; |
|
5722 |
while (leaf != root && (par= leaf->parent)->color == RED) |
|
5723 |
{ // This can't be root or 1 level under |
|
5724 |
if (par == (par2= leaf->parent->parent)->left) |
|
5725 |
{
|
|
5726 |
y= par2->right; |
|
5727 |
if (y->color == RED) |
|
5728 |
{
|
|
5729 |
par->color=BLACK; |
|
5730 |
y->color=BLACK; |
|
5731 |
leaf=par2; |
|
5732 |
leaf->color=RED; /* And the loop continues */ |
|
5733 |
}
|
|
5734 |
else
|
|
5735 |
{
|
|
5736 |
if (leaf == par->right) |
|
5737 |
{
|
|
5738 |
left_rotate(&root,leaf->parent); |
|
5739 |
par=leaf; /* leaf is now parent to old leaf */ |
|
5740 |
}
|
|
5741 |
par->color=BLACK; |
|
5742 |
par2->color=RED; |
|
5743 |
right_rotate(&root,par2); |
|
5744 |
break; |
|
5745 |
}
|
|
5746 |
}
|
|
5747 |
else
|
|
5748 |
{
|
|
5749 |
y= par2->left; |
|
5750 |
if (y->color == RED) |
|
5751 |
{
|
|
5752 |
par->color=BLACK; |
|
5753 |
y->color=BLACK; |
|
5754 |
leaf=par2; |
|
5755 |
leaf->color=RED; /* And the loop continues */ |
|
5756 |
}
|
|
5757 |
else
|
|
5758 |
{
|
|
5759 |
if (leaf == par->left) |
|
5760 |
{
|
|
5761 |
right_rotate(&root,par); |
|
5762 |
par=leaf; |
|
5763 |
}
|
|
5764 |
par->color=BLACK; |
|
5765 |
par2->color=RED; |
|
5766 |
left_rotate(&root,par2); |
|
5767 |
break; |
|
5768 |
}
|
|
5769 |
}
|
|
5770 |
}
|
|
5771 |
root->color=BLACK; |
|
511.2.6
by Monty Taylor
drizzled/ and storage/archive/ are clean. |
5772 |
#ifdef EXTRA_DEBUG
|
1
by brian
clean slate |
5773 |
test_rb_tree(root,root->parent); |
511.2.6
by Monty Taylor
drizzled/ and storage/archive/ are clean. |
5774 |
#endif /* EXTRA_DEBUG */ |
5775 |
||
1
by brian
clean slate |
5776 |
return root; |
5777 |
}
|
|
5778 |
||
5779 |
||
5780 |
SEL_ARG *rb_delete_fixup(SEL_ARG *root,SEL_ARG *key,SEL_ARG *par) |
|
5781 |
{
|
|
5782 |
SEL_ARG *x,*w; |
|
5783 |
root->parent=0; |
|
5784 |
||
5785 |
x= key; |
|
5786 |
while (x != root && x->color == SEL_ARG::BLACK) |
|
5787 |
{
|
|
5788 |
if (x == par->left) |
|
5789 |
{
|
|
5790 |
w=par->right; |
|
5791 |
if (w->color == SEL_ARG::RED) |
|
5792 |
{
|
|
5793 |
w->color=SEL_ARG::BLACK; |
|
5794 |
par->color=SEL_ARG::RED; |
|
5795 |
left_rotate(&root,par); |
|
5796 |
w=par->right; |
|
5797 |
}
|
|
5798 |
if (w->left->color == SEL_ARG::BLACK && w->right->color == SEL_ARG::BLACK) |
|
5799 |
{
|
|
5800 |
w->color=SEL_ARG::RED; |
|
5801 |
x=par; |
|
5802 |
}
|
|
5803 |
else
|
|
5804 |
{
|
|
5805 |
if (w->right->color == SEL_ARG::BLACK) |
|
5806 |
{
|
|
5807 |
w->left->color=SEL_ARG::BLACK; |
|
5808 |
w->color=SEL_ARG::RED; |
|
5809 |
right_rotate(&root,w); |
|
5810 |
w=par->right; |
|
5811 |
}
|
|
5812 |
w->color=par->color; |
|
5813 |
par->color=SEL_ARG::BLACK; |
|
5814 |
w->right->color=SEL_ARG::BLACK; |
|
5815 |
left_rotate(&root,par); |
|
5816 |
x=root; |
|
5817 |
break; |
|
5818 |
}
|
|
5819 |
}
|
|
5820 |
else
|
|
5821 |
{
|
|
5822 |
w=par->left; |
|
5823 |
if (w->color == SEL_ARG::RED) |
|
5824 |
{
|
|
5825 |
w->color=SEL_ARG::BLACK; |
|
5826 |
par->color=SEL_ARG::RED; |
|
5827 |
right_rotate(&root,par); |
|
5828 |
w=par->left; |
|
5829 |
}
|
|
5830 |
if (w->right->color == SEL_ARG::BLACK && w->left->color == SEL_ARG::BLACK) |
|
5831 |
{
|
|
5832 |
w->color=SEL_ARG::RED; |
|
5833 |
x=par; |
|
5834 |
}
|
|
5835 |
else
|
|
5836 |
{
|
|
5837 |
if (w->left->color == SEL_ARG::BLACK) |
|
5838 |
{
|
|
5839 |
w->right->color=SEL_ARG::BLACK; |
|
5840 |
w->color=SEL_ARG::RED; |
|
5841 |
left_rotate(&root,w); |
|
5842 |
w=par->left; |
|
5843 |
}
|
|
5844 |
w->color=par->color; |
|
5845 |
par->color=SEL_ARG::BLACK; |
|
5846 |
w->left->color=SEL_ARG::BLACK; |
|
5847 |
right_rotate(&root,par); |
|
5848 |
x=root; |
|
5849 |
break; |
|
5850 |
}
|
|
5851 |
}
|
|
5852 |
par=x->parent; |
|
5853 |
}
|
|
5854 |
x->color=SEL_ARG::BLACK; |
|
5855 |
return root; |
|
5856 |
}
|
|
5857 |
||
5858 |
||
5859 |
/* Test that the properties for a red-black tree hold */
|
|
5860 |
||
5861 |
#ifdef EXTRA_DEBUG
|
|
5862 |
int test_rb_tree(SEL_ARG *element,SEL_ARG *parent) |
|
5863 |
{
|
|
5864 |
int count_l,count_r; |
|
5865 |
||
5866 |
if (element == &null_element) |
|
5867 |
return 0; // Found end of tree |
|
5868 |
if (element->parent != parent) |
|
5869 |
{
|
|
755.2.1
by Mark Atwood
replace sql_print_error etc with errmsg_print |
5870 |
errmsg_printf(ERRMSG_LVL_ERROR, "Wrong tree: Parent doesn't point at parent"); |
1
by brian
clean slate |
5871 |
return -1; |
5872 |
}
|
|
5873 |
if (element->color == SEL_ARG::RED && |
|
5874 |
(element->left->color == SEL_ARG::RED || |
|
5875 |
element->right->color == SEL_ARG::RED)) |
|
5876 |
{
|
|
755.2.1
by Mark Atwood
replace sql_print_error etc with errmsg_print |
5877 |
errmsg_printf(ERRMSG_LVL_ERROR, "Wrong tree: Found two red in a row"); |
1
by brian
clean slate |
5878 |
return -1; |
5879 |
}
|
|
5880 |
if (element->left == element->right && element->left != &null_element) |
|
5881 |
{ // Dummy test |
|
755.2.1
by Mark Atwood
replace sql_print_error etc with errmsg_print |
5882 |
errmsg_printf(ERRMSG_LVL_ERROR, "Wrong tree: Found right == left"); |
1
by brian
clean slate |
5883 |
return -1; |
5884 |
}
|
|
5885 |
count_l=test_rb_tree(element->left,element); |
|
5886 |
count_r=test_rb_tree(element->right,element); |
|
5887 |
if (count_l >= 0 && count_r >= 0) |
|
5888 |
{
|
|
5889 |
if (count_l == count_r) |
|
5890 |
return count_l+(element->color == SEL_ARG::BLACK); |
|
755.2.1
by Mark Atwood
replace sql_print_error etc with errmsg_print |
5891 |
errmsg_printf(ERRMSG_LVL_ERROR, "Wrong tree: Incorrect black-count: %d - %d", |
1
by brian
clean slate |
5892 |
count_l,count_r); |
5893 |
}
|
|
5894 |
return -1; // Error, no more warnings |
|
5895 |
}
|
|
5896 |
||
5897 |
||
5898 |
/*
|
|
5899 |
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: |
5900 |
|
1
by brian
clean slate |
5901 |
SYNOPSIS
|
5902 |
count_key_part_usage()
|
|
5903 |
root An RB-Root node in a SEL_ARG graph.
|
|
5904 |
key Another RB-Root node in that SEL_ARG graph.
|
|
5905 |
||
5906 |
DESCRIPTION
|
|
5907 |
The passed "root" node may refer to "key" node via root->next_key_part,
|
|
5908 |
root->next->n
|
|
5909 |
||
5910 |
This function counts how many times the node "key" is referred (via
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5911 |
SEL_ARG::next_key_part) by
|
5912 |
- intervals of RB-tree pointed by "root",
|
|
5913 |
- intervals of RB-trees that are pointed by SEL_ARG::next_key_part from
|
|
1
by brian
clean slate |
5914 |
intervals of RB-tree pointed by "root",
|
5915 |
- and so on.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5916 |
|
5917 |
Here is an example (horizontal links represent next_key_part pointers,
|
|
5918 |
vertical links - next/prev prev pointers):
|
|
5919 |
||
1
by brian
clean slate |
5920 |
+----+ $
|
5921 |
|root|-----------------+
|
|
5922 |
+----+ $ |
|
|
5923 |
| $ |
|
|
5924 |
| $ |
|
|
5925 |
+----+ +---+ $ | +---+ Here the return value
|
|
5926 |
| |- ... -| |---$-+--+->|key| will be 4.
|
|
5927 |
+----+ +---+ $ | | +---+
|
|
5928 |
| $ | |
|
|
5929 |
... $ | |
|
|
5930 |
| $ | |
|
|
5931 |
+----+ +---+ $ | |
|
|
5932 |
| |---| |---------+ |
|
|
5933 |
+----+ +---+ $ |
|
|
5934 |
| | $ |
|
|
5935 |
... +---+ $ |
|
|
5936 |
| |------------+
|
|
5937 |
+---+ $
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
5938 |
RETURN
|
1
by brian
clean slate |
5939 |
Number of links to "key" from nodes reachable from "root".
|
5940 |
*/
|
|
5941 |
||
5942 |
static ulong count_key_part_usage(SEL_ARG *root, SEL_ARG *key) |
|
5943 |
{
|
|
5944 |
ulong count= 0; |
|
5945 |
for (root=root->first(); root ; root=root->next) |
|
5946 |
{
|
|
5947 |
if (root->next_key_part) |
|
5948 |
{
|
|
5949 |
if (root->next_key_part == key) |
|
5950 |
count++; |
|
5951 |
if (root->next_key_part->part < key->part) |
|
5952 |
count+=count_key_part_usage(root->next_key_part,key); |
|
5953 |
}
|
|
5954 |
}
|
|
5955 |
return count; |
|
5956 |
}
|
|
5957 |
||
5958 |
||
5959 |
/*
|
|
5960 |
Check if SEL_ARG::use_count value is correct
|
|
5961 |
||
5962 |
SYNOPSIS
|
|
5963 |
SEL_ARG::test_use_count()
|
|
5964 |
root The root node of the SEL_ARG graph (an RB-tree root node that
|
|
5965 |
has the least value of sel_arg->part in the entire graph, and
|
|
5966 |
thus is the "origin" of the graph)
|
|
5967 |
||
5968 |
DESCRIPTION
|
|
5969 |
Check if SEL_ARG::use_count value is correct. See the definition of
|
|
5970 |
use_count for what is "correct".
|
|
5971 |
*/
|
|
5972 |
||
5973 |
void SEL_ARG::test_use_count(SEL_ARG *root) |
|
5974 |
{
|
|
482
by Brian Aker
Remove uint. |
5975 |
uint32_t e_count=0; |
1
by brian
clean slate |
5976 |
if (this == root && use_count != 1) |
5977 |
{
|
|
755.2.1
by Mark Atwood
replace sql_print_error etc with errmsg_print |
5978 |
errmsg_printf(ERRMSG_LVL_INFO, "Use_count: Wrong count %lu for root",use_count); |
1
by brian
clean slate |
5979 |
return; |
5980 |
}
|
|
5981 |
if (this->type != SEL_ARG::KEY_RANGE) |
|
5982 |
return; |
|
5983 |
for (SEL_ARG *pos=first(); pos ; pos=pos->next) |
|
5984 |
{
|
|
5985 |
e_count++; |
|
5986 |
if (pos->next_key_part) |
|
5987 |
{
|
|
5988 |
ulong count=count_key_part_usage(root,pos->next_key_part); |
|
5989 |
if (count > pos->next_key_part->use_count) |
|
5990 |
{
|
|
755.2.1
by Mark Atwood
replace sql_print_error etc with errmsg_print |
5991 |
errmsg_printf(ERRMSG_LVL_INFO, "Use_count: Wrong count for key at 0x%lx, %lu " |
1
by brian
clean slate |
5992 |
"should be %lu", (long unsigned int)pos, |
5993 |
pos->next_key_part->use_count, count); |
|
5994 |
return; |
|
5995 |
}
|
|
5996 |
pos->next_key_part->test_use_count(root); |
|
5997 |
}
|
|
5998 |
}
|
|
5999 |
if (e_count != elements) |
|
755.2.1
by Mark Atwood
replace sql_print_error etc with errmsg_print |
6000 |
errmsg_printf(ERRMSG_LVL_WARN, "Wrong use count: %u (should be %u) for tree at 0x%lx", |
1
by brian
clean slate |
6001 |
e_count, elements, (long unsigned int) this); |
6002 |
}
|
|
6003 |
||
6004 |
#endif
|
|
6005 |
||
6006 |
/****************************************************************************
|
|
6007 |
MRR Range Sequence Interface implementation that walks a SEL_ARG* tree.
|
|
6008 |
****************************************************************************/
|
|
6009 |
||
6010 |
/* MRR range sequence, SEL_ARG* implementation: stack entry */
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6011 |
typedef struct st_range_seq_entry |
1
by brian
clean slate |
6012 |
{
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6013 |
/*
|
1
by brian
clean slate |
6014 |
Pointers in min and max keys. They point to right-after-end of key
|
6015 |
images. The 0-th entry has these pointing to key tuple start.
|
|
6016 |
*/
|
|
481
by Brian Aker
Remove all of uchar. |
6017 |
unsigned char *min_key, *max_key; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6018 |
|
6019 |
/*
|
|
1
by brian
clean slate |
6020 |
Flags, for {keypart0, keypart1, ... this_keypart} subtuple.
|
6021 |
min_key_flag may have NULL_RANGE set.
|
|
6022 |
*/
|
|
482
by Brian Aker
Remove uint. |
6023 |
uint32_t min_key_flag, max_key_flag; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6024 |
|
1
by brian
clean slate |
6025 |
/* Number of key parts */
|
482
by Brian Aker
Remove uint. |
6026 |
uint32_t min_key_parts, max_key_parts; |
1
by brian
clean slate |
6027 |
SEL_ARG *key_tree; |
6028 |
} RANGE_SEQ_ENTRY; |
|
6029 |
||
6030 |
||
6031 |
/*
|
|
6032 |
MRR range sequence, SEL_ARG* implementation: SEL_ARG graph traversal context
|
|
6033 |
*/
|
|
6034 |
typedef struct st_sel_arg_range_seq |
|
6035 |
{
|
|
482
by Brian Aker
Remove uint. |
6036 |
uint32_t keyno; /* index of used tree in SEL_TREE structure */ |
6037 |
uint32_t real_keyno; /* Number of the index in tables */ |
|
1
by brian
clean slate |
6038 |
PARAM *param; |
6039 |
SEL_ARG *start; /* Root node of the traversed SEL_ARG* graph */ |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6040 |
|
1
by brian
clean slate |
6041 |
RANGE_SEQ_ENTRY stack[MAX_REF_PARTS]; |
6042 |
int i; /* Index of last used element in the above array */ |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6043 |
|
55
by brian
Update for using real bool types. |
6044 |
bool at_start; /* true <=> The traversal has just started */ |
1
by brian
clean slate |
6045 |
} SEL_ARG_RANGE_SEQ; |
6046 |
||
6047 |
||
6048 |
/*
|
|
6049 |
Range sequence interface, SEL_ARG* implementation: Initialize the traversal
|
|
6050 |
||
6051 |
SYNOPSIS
|
|
6052 |
init()
|
|
6053 |
init_params SEL_ARG tree traversal context
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6054 |
n_ranges [ignored] The number of ranges obtained
|
1
by brian
clean slate |
6055 |
flags [ignored] HA_MRR_SINGLE_POINT, HA_MRR_FIXED_KEY
|
6056 |
||
6057 |
RETURN
|
|
6058 |
Value of init_param
|
|
6059 |
*/
|
|
6060 |
||
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
6061 |
range_seq_t sel_arg_range_seq_init(void *init_param, uint32_t, uint32_t) |
1
by brian
clean slate |
6062 |
{
|
6063 |
SEL_ARG_RANGE_SEQ *seq= (SEL_ARG_RANGE_SEQ*)init_param; |
|
55
by brian
Update for using real bool types. |
6064 |
seq->at_start= true; |
1
by brian
clean slate |
6065 |
seq->stack[0].key_tree= NULL; |
6066 |
seq->stack[0].min_key= seq->param->min_key; |
|
6067 |
seq->stack[0].min_key_flag= 0; |
|
6068 |
seq->stack[0].min_key_parts= 0; |
|
6069 |
||
6070 |
seq->stack[0].max_key= seq->param->max_key; |
|
6071 |
seq->stack[0].max_key_flag= 0; |
|
6072 |
seq->stack[0].max_key_parts= 0; |
|
6073 |
seq->i= 0; |
|
6074 |
return init_param; |
|
6075 |
}
|
|
6076 |
||
6077 |
||
6078 |
static void step_down_to(SEL_ARG_RANGE_SEQ *arg, SEL_ARG *key_tree) |
|
6079 |
{
|
|
6080 |
RANGE_SEQ_ENTRY *cur= &arg->stack[arg->i+1]; |
|
6081 |
RANGE_SEQ_ENTRY *prev= &arg->stack[arg->i]; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6082 |
|
1
by brian
clean slate |
6083 |
cur->key_tree= key_tree; |
6084 |
cur->min_key= prev->min_key; |
|
6085 |
cur->max_key= prev->max_key; |
|
6086 |
cur->min_key_parts= prev->min_key_parts; |
|
6087 |
cur->max_key_parts= prev->max_key_parts; |
|
6088 |
||
206
by Brian Aker
Removed final uint dead types. |
6089 |
uint16_t stor_length= arg->param->key[arg->keyno][key_tree->part].store_length; |
1
by brian
clean slate |
6090 |
cur->min_key_parts += key_tree->store_min(stor_length, &cur->min_key, |
6091 |
prev->min_key_flag); |
|
6092 |
cur->max_key_parts += key_tree->store_max(stor_length, &cur->max_key, |
|
6093 |
prev->max_key_flag); |
|
6094 |
||
6095 |
cur->min_key_flag= prev->min_key_flag | key_tree->min_flag; |
|
6096 |
cur->max_key_flag= prev->max_key_flag | key_tree->max_flag; |
|
6097 |
||
6098 |
if (key_tree->is_null_interval()) |
|
6099 |
cur->min_key_flag |= NULL_RANGE; |
|
6100 |
(arg->i)++; |
|
6101 |
}
|
|
6102 |
||
6103 |
||
6104 |
/*
|
|
6105 |
Range sequence interface, SEL_ARG* implementation: get the next interval
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6106 |
|
1
by brian
clean slate |
6107 |
SYNOPSIS
|
6108 |
sel_arg_range_seq_next()
|
|
6109 |
rseq Value returned from sel_arg_range_seq_init
|
|
6110 |
range OUT Store information about the range here
|
|
6111 |
||
6112 |
DESCRIPTION
|
|
6113 |
This is "get_next" function for Range sequence interface implementation
|
|
6114 |
for SEL_ARG* tree.
|
|
6115 |
||
6116 |
IMPLEMENTATION
|
|
6117 |
The traversal also updates those param members:
|
|
6118 |
- is_ror_scan
|
|
6119 |
- range_count
|
|
6120 |
- max_key_part
|
|
6121 |
||
6122 |
RETURN
|
|
6123 |
0 Ok
|
|
6124 |
1 No more ranges in the sequence
|
|
6125 |
*/
|
|
6126 |
||
6127 |
//psergey-merge-todo: support check_quick_keys:max_keypart
|
|
482
by Brian Aker
Remove uint. |
6128 |
uint32_t sel_arg_range_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range) |
1
by brian
clean slate |
6129 |
{
|
6130 |
SEL_ARG *key_tree; |
|
6131 |
SEL_ARG_RANGE_SEQ *seq= (SEL_ARG_RANGE_SEQ*)rseq; |
|
6132 |
if (seq->at_start) |
|
6133 |
{
|
|
6134 |
key_tree= seq->start; |
|
55
by brian
Update for using real bool types. |
6135 |
seq->at_start= false; |
1
by brian
clean slate |
6136 |
goto walk_up_n_right; |
6137 |
}
|
|
6138 |
||
6139 |
key_tree= seq->stack[seq->i].key_tree; |
|
6140 |
/* Ok, we're at some "full tuple" position in the tree */
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6141 |
|
1
by brian
clean slate |
6142 |
/* Step down if we can */
|
6143 |
if (key_tree->next && key_tree->next != &null_element) |
|
6144 |
{
|
|
6145 |
//step down; (update the tuple, we'll step right and stay there)
|
|
6146 |
seq->i--; |
|
6147 |
step_down_to(seq, key_tree->next); |
|
6148 |
key_tree= key_tree->next; |
|
55
by brian
Update for using real bool types. |
6149 |
seq->param->is_ror_scan= false; |
1
by brian
clean slate |
6150 |
goto walk_right_n_up; |
6151 |
}
|
|
6152 |
||
6153 |
/* Ok, can't step down, walk left until we can step down */
|
|
6154 |
while (1) |
|
6155 |
{
|
|
6156 |
if (seq->i == 1) // can't step left |
|
6157 |
return 1; |
|
6158 |
/* Step left */
|
|
6159 |
seq->i--; |
|
6160 |
key_tree= seq->stack[seq->i].key_tree; |
|
6161 |
||
6162 |
/* Step down if we can */
|
|
6163 |
if (key_tree->next && key_tree->next != &null_element) |
|
6164 |
{
|
|
6165 |
// Step down; update the tuple
|
|
6166 |
seq->i--; |
|
6167 |
step_down_to(seq, key_tree->next); |
|
6168 |
key_tree= key_tree->next; |
|
6169 |
break; |
|
6170 |
}
|
|
6171 |
}
|
|
6172 |
||
6173 |
/*
|
|
6174 |
Ok, we've stepped down from the path to previous tuple.
|
|
6175 |
Walk right-up while we can
|
|
6176 |
*/
|
|
6177 |
walk_right_n_up: |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6178 |
while (key_tree->next_key_part && key_tree->next_key_part != &null_element && |
1
by brian
clean slate |
6179 |
key_tree->next_key_part->part == key_tree->part + 1 && |
6180 |
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) |
|
6181 |
{
|
|
6182 |
{
|
|
6183 |
RANGE_SEQ_ENTRY *cur= &seq->stack[seq->i]; |
|
482
by Brian Aker
Remove uint. |
6184 |
uint32_t min_key_length= cur->min_key - seq->param->min_key; |
6185 |
uint32_t max_key_length= cur->max_key - seq->param->max_key; |
|
6186 |
uint32_t len= cur->min_key - cur[-1].min_key; |
|
1
by brian
clean slate |
6187 |
if (!(min_key_length == max_key_length && |
6188 |
!memcmp(cur[-1].min_key, cur[-1].max_key, len) && |
|
6189 |
!key_tree->min_flag && !key_tree->max_flag)) |
|
6190 |
{
|
|
55
by brian
Update for using real bool types. |
6191 |
seq->param->is_ror_scan= false; |
1
by brian
clean slate |
6192 |
if (!key_tree->min_flag) |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6193 |
cur->min_key_parts += |
1
by brian
clean slate |
6194 |
key_tree->next_key_part->store_min_key(seq->param->key[seq->keyno], |
6195 |
&cur->min_key, |
|
6196 |
&cur->min_key_flag); |
|
6197 |
if (!key_tree->max_flag) |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6198 |
cur->max_key_parts += |
1
by brian
clean slate |
6199 |
key_tree->next_key_part->store_max_key(seq->param->key[seq->keyno], |
6200 |
&cur->max_key, |
|
6201 |
&cur->max_key_flag); |
|
6202 |
break; |
|
6203 |
}
|
|
6204 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6205 |
|
1
by brian
clean slate |
6206 |
/*
|
6207 |
Ok, current atomic interval is in form "t.field=const" and there is
|
|
6208 |
next_key_part interval. Step right, and walk up from there.
|
|
6209 |
*/
|
|
6210 |
key_tree= key_tree->next_key_part; |
|
6211 |
||
6212 |
walk_up_n_right: |
|
6213 |
while (key_tree->prev && key_tree->prev != &null_element) |
|
6214 |
{
|
|
6215 |
/* Step up */
|
|
6216 |
key_tree= key_tree->prev; |
|
6217 |
}
|
|
6218 |
step_down_to(seq, key_tree); |
|
6219 |
}
|
|
6220 |
||
6221 |
/* Ok got a tuple */
|
|
6222 |
RANGE_SEQ_ENTRY *cur= &seq->stack[seq->i]; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6223 |
|
1
by brian
clean slate |
6224 |
range->ptr= (char*)(int)(key_tree->part); |
6225 |
{
|
|
6226 |
range->range_flag= cur->min_key_flag | cur->max_key_flag; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6227 |
|
1
by brian
clean slate |
6228 |
range->start_key.key= seq->param->min_key; |
6229 |
range->start_key.length= cur->min_key - seq->param->min_key; |
|
6230 |
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: |
6231 |
range->start_key.flag= (cur->min_key_flag & NEAR_MIN ? HA_READ_AFTER_KEY : |
1
by brian
clean slate |
6232 |
HA_READ_KEY_EXACT); |
6233 |
||
6234 |
range->end_key.key= seq->param->max_key; |
|
6235 |
range->end_key.length= cur->max_key - seq->param->max_key; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6236 |
range->end_key.flag= (cur->max_key_flag & NEAR_MAX ? HA_READ_BEFORE_KEY : |
1
by brian
clean slate |
6237 |
HA_READ_AFTER_KEY); |
6238 |
range->end_key.keypart_map= make_prev_keypart_map(cur->max_key_parts); |
|
6239 |
||
6240 |
if (!(cur->min_key_flag & ~NULL_RANGE) && !cur->max_key_flag && |
|
895
by Brian Aker
Completion (?) of uint conversion. |
6241 |
(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.) |
6242 |
(seq->param->table->key_info[seq->real_keyno].flags & (HA_NOSAME)) == |
1
by brian
clean slate |
6243 |
HA_NOSAME && |
6244 |
range->start_key.length == range->end_key.length && |
|
6245 |
!memcmp(seq->param->min_key,seq->param->max_key,range->start_key.length)) |
|
6246 |
range->range_flag= UNIQUE_RANGE | (cur->min_key_flag & NULL_RANGE); |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6247 |
|
1
by brian
clean slate |
6248 |
if (seq->param->is_ror_scan) |
6249 |
{
|
|
6250 |
/*
|
|
6251 |
If we get here, the condition on the key was converted to form
|
|
6252 |
"(keyXpart1 = c1) AND ... AND (keyXpart{key_tree->part - 1} = cN) AND
|
|
6253 |
somecond(keyXpart{key_tree->part})"
|
|
6254 |
Check if
|
|
6255 |
somecond is "keyXpart{key_tree->part} = const" and
|
|
6256 |
uncovered "tail" of KeyX parts is either empty or is identical to
|
|
6257 |
first members of clustered primary key.
|
|
6258 |
*/
|
|
6259 |
if (!(!(cur->min_key_flag & ~NULL_RANGE) && !cur->max_key_flag && |
|
6260 |
(range->start_key.length == range->end_key.length) && |
|
6261 |
!memcmp(range->start_key.key, range->end_key.key, range->start_key.length) && |
|
6262 |
is_key_scan_ror(seq->param, seq->real_keyno, key_tree->part + 1))) |
|
55
by brian
Update for using real bool types. |
6263 |
seq->param->is_ror_scan= false; |
1
by brian
clean slate |
6264 |
}
|
6265 |
}
|
|
6266 |
seq->param->range_count++; |
|
895
by Brian Aker
Completion (?) of uint conversion. |
6267 |
seq->param->max_key_part=cmax(seq->param->max_key_part,(uint32_t)key_tree->part); |
1
by brian
clean slate |
6268 |
return 0; |
6269 |
}
|
|
6270 |
||
6271 |
||
6272 |
/*
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6273 |
Calculate cost and E(#rows) for a given index and intervals tree
|
1
by brian
clean slate |
6274 |
|
6275 |
SYNOPSIS
|
|
6276 |
check_quick_select()
|
|
6277 |
param Parameter from test_quick_select
|
|
6278 |
idx Number of index to use in PARAM::key SEL_TREE::key
|
|
55
by brian
Update for using real bool types. |
6279 |
index_only true - assume only index tuples will be accessed
|
6280 |
false - assume full table rows will be read
|
|
1
by brian
clean slate |
6281 |
tree Transformed selection condition, tree->key[idx] holds
|
6282 |
the intervals for the given index.
|
|
55
by brian
Update for using real bool types. |
6283 |
update_tbl_stats true <=> update table->quick_* with information
|
1
by brian
clean slate |
6284 |
about range scan we've evaluated.
|
6285 |
mrr_flags INOUT MRR access flags
|
|
6286 |
cost OUT Scan cost
|
|
6287 |
||
6288 |
NOTES
|
|
6289 |
param->is_ror_scan is set to reflect if the key scan is a ROR (see
|
|
6290 |
is_key_scan_ror function for more info)
|
|
6291 |
param->table->quick_*, param->range_count (and maybe others) are
|
|
6292 |
updated with data of given key scan, see quick_range_seq_next for details.
|
|
6293 |
||
6294 |
RETURN
|
|
6295 |
Estimate # of records to be retrieved.
|
|
6296 |
HA_POS_ERROR if estimate calculation failed due to table handler problems.
|
|
6297 |
*/
|
|
6298 |
||
6299 |
static
|
|
482
by Brian Aker
Remove uint. |
6300 |
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: |
6301 |
SEL_ARG *tree, bool update_tbl_stats, |
482
by Brian Aker
Remove uint. |
6302 |
uint32_t *mrr_flags, uint32_t *bufsize, COST_VECT *cost) |
1
by brian
clean slate |
6303 |
{
|
6304 |
SEL_ARG_RANGE_SEQ seq; |
|
6305 |
RANGE_SEQ_IF seq_if = {sel_arg_range_seq_init, sel_arg_range_seq_next}; |
|
6306 |
handler *file= param->table->file; |
|
6307 |
ha_rows rows; |
|
482
by Brian Aker
Remove uint. |
6308 |
uint32_t keynr= param->real_keynr[idx]; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6309 |
|
1
by brian
clean slate |
6310 |
/* Handle cases when we don't have a valid non-empty list of range */
|
6311 |
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. |
6312 |
return(HA_POS_ERROR); |
1
by brian
clean slate |
6313 |
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. |
6314 |
return(0L); |
1
by brian
clean slate |
6315 |
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. |
6316 |
return(HA_POS_ERROR); |
1
by brian
clean slate |
6317 |
|
6318 |
seq.keyno= idx; |
|
6319 |
seq.real_keyno= keynr; |
|
6320 |
seq.param= param; |
|
6321 |
seq.start= tree; |
|
6322 |
||
6323 |
param->range_count=0; |
|
6324 |
param->max_key_part=0; |
|
6325 |
||
55
by brian
Update for using real bool types. |
6326 |
param->is_ror_scan= true; |
6327 |
if (file->index_flags(keynr, 0, true) & HA_KEY_SCAN_NOT_ROR) |
|
6328 |
param->is_ror_scan= false; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6329 |
|
1
by brian
clean slate |
6330 |
*mrr_flags= param->force_default_mrr? HA_MRR_USE_DEFAULT_IMPL: 0; |
6331 |
*mrr_flags|= HA_MRR_NO_ASSOCIATION; |
|
6332 |
||
6333 |
bool pk_is_clustered= file->primary_key_is_clustered(); |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6334 |
if (index_only && |
1
by brian
clean slate |
6335 |
(file->index_flags(keynr, param->max_key_part, 1) & HA_KEYREAD_ONLY) && |
6336 |
!(pk_is_clustered && keynr == param->table->s->primary_key)) |
|
6337 |
*mrr_flags |= HA_MRR_INDEX_ONLY; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6338 |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
6339 |
if (current_session->lex->sql_command != SQLCOM_SELECT) |
1
by brian
clean slate |
6340 |
*mrr_flags |= HA_MRR_USE_DEFAULT_IMPL; |
6341 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
6342 |
*bufsize= param->session->variables.read_rnd_buff_size; |
1
by brian
clean slate |
6343 |
rows= file->multi_range_read_info_const(keynr, &seq_if, (void*)&seq, 0, |
6344 |
bufsize, mrr_flags, cost); |
|
6345 |
if (rows != HA_POS_ERROR) |
|
6346 |
{
|
|
6347 |
param->table->quick_rows[keynr]=rows; |
|
6348 |
if (update_tbl_stats) |
|
6349 |
{
|
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
6350 |
param->table->quick_keys.set(keynr); |
1
by brian
clean slate |
6351 |
param->table->quick_key_parts[keynr]=param->max_key_part+1; |
6352 |
param->table->quick_n_ranges[keynr]= param->range_count; |
|
6353 |
param->table->quick_condition_rows= |
|
398.1.4
by Monty Taylor
Renamed max/min. |
6354 |
cmin(param->table->quick_condition_rows, rows); |
1
by brian
clean slate |
6355 |
}
|
6356 |
}
|
|
6357 |
/* Figure out if the key scan is ROR (returns rows in ROWID order) or not */
|
|
6358 |
enum ha_key_alg key_alg= param->table->key_info[seq.real_keyno].algorithm; |
|
6359 |
if ((key_alg != HA_KEY_ALG_BTREE) && (key_alg!= HA_KEY_ALG_UNDEF)) |
|
6360 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6361 |
/*
|
1
by brian
clean slate |
6362 |
All scans are non-ROR scans for those index types.
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6363 |
TODO: Don't have this logic here, make table engines return
|
1
by brian
clean slate |
6364 |
appropriate flags instead.
|
6365 |
*/
|
|
55
by brian
Update for using real bool types. |
6366 |
param->is_ror_scan= false; |
1
by brian
clean slate |
6367 |
}
|
6368 |
else
|
|
6369 |
{
|
|
6370 |
/* Clustered PK scan is always a ROR scan (TODO: same as above) */
|
|
6371 |
if (param->table->s->primary_key == keynr && pk_is_clustered) |
|
55
by brian
Update for using real bool types. |
6372 |
param->is_ror_scan= true; |
1
by brian
clean slate |
6373 |
}
|
6374 |
||
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
6375 |
return(rows); //psergey-merge:todo: maintain first_null_comp. |
1
by brian
clean slate |
6376 |
}
|
6377 |
||
6378 |
||
6379 |
/*
|
|
6380 |
Check if key scan on given index with equality conditions on first n key
|
|
6381 |
parts is a ROR scan.
|
|
6382 |
||
6383 |
SYNOPSIS
|
|
6384 |
is_key_scan_ror()
|
|
6385 |
param Parameter from test_quick_select
|
|
6386 |
keynr Number of key in the table. The key must not be a clustered
|
|
6387 |
primary key.
|
|
6388 |
nparts Number of first key parts for which equality conditions
|
|
6389 |
are present.
|
|
6390 |
||
6391 |
NOTES
|
|
6392 |
ROR (Rowid Ordered Retrieval) key scan is a key scan that produces
|
|
6393 |
ordered sequence of rowids (ha_xxx::cmp_ref is the comparison function)
|
|
6394 |
||
6395 |
This function is needed to handle a practically-important special case:
|
|
6396 |
an index scan is a ROR scan if it is done using a condition in form
|
|
6397 |
||
6398 |
"key1_1=c_1 AND ... AND key1_n=c_n"
|
|
6399 |
||
6400 |
where the index is defined on (key1_1, ..., key1_N [,a_1, ..., a_n])
|
|
6401 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6402 |
and the table has a clustered Primary Key defined as
|
6403 |
PRIMARY KEY(a_1, ..., a_n, b1, ..., b_k)
|
|
6404 |
||
6405 |
i.e. the first key parts of it are identical to uncovered parts ot the
|
|
1
by brian
clean slate |
6406 |
key being scanned. This function assumes that the index flags do not
|
6407 |
include HA_KEY_SCAN_NOT_ROR flag (that is checked elsewhere).
|
|
6408 |
||
6409 |
Check (1) is made in quick_range_seq_next()
|
|
6410 |
||
6411 |
RETURN
|
|
55
by brian
Update for using real bool types. |
6412 |
true The scan is ROR-scan
|
6413 |
false Otherwise
|
|
1
by brian
clean slate |
6414 |
*/
|
6415 |
||
482
by Brian Aker
Remove uint. |
6416 |
static bool is_key_scan_ror(PARAM *param, uint32_t keynr, uint8_t nparts) |
1
by brian
clean slate |
6417 |
{
|
6418 |
KEY *table_key= param->table->key_info + keynr; |
|
6419 |
KEY_PART_INFO *key_part= table_key->key_part + nparts; |
|
6420 |
KEY_PART_INFO *key_part_end= (table_key->key_part + |
|
6421 |
table_key->key_parts); |
|
482
by Brian Aker
Remove uint. |
6422 |
uint32_t pk_number; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6423 |
|
1
by brian
clean slate |
6424 |
for (KEY_PART_INFO *kp= table_key->key_part; kp < key_part; kp++) |
6425 |
{
|
|
206
by Brian Aker
Removed final uint dead types. |
6426 |
uint16_t fieldnr= param->table->key_info[keynr]. |
1
by brian
clean slate |
6427 |
key_part[kp - table_key->key_part].fieldnr - 1; |
6428 |
if (param->table->field[fieldnr]->key_length() != kp->length) |
|
55
by brian
Update for using real bool types. |
6429 |
return false; |
1
by brian
clean slate |
6430 |
}
|
6431 |
||
6432 |
if (key_part == key_part_end) |
|
55
by brian
Update for using real bool types. |
6433 |
return true; |
1
by brian
clean slate |
6434 |
|
6435 |
key_part= table_key->key_part + nparts; |
|
6436 |
pk_number= param->table->s->primary_key; |
|
6437 |
if (!param->table->file->primary_key_is_clustered() || pk_number == MAX_KEY) |
|
55
by brian
Update for using real bool types. |
6438 |
return false; |
1
by brian
clean slate |
6439 |
|
6440 |
KEY_PART_INFO *pk_part= param->table->key_info[pk_number].key_part; |
|
6441 |
KEY_PART_INFO *pk_part_end= pk_part + |
|
6442 |
param->table->key_info[pk_number].key_parts; |
|
6443 |
for (;(key_part!=key_part_end) && (pk_part != pk_part_end); |
|
6444 |
++key_part, ++pk_part) |
|
6445 |
{
|
|
6446 |
if ((key_part->field != pk_part->field) || |
|
6447 |
(key_part->length != pk_part->length)) |
|
55
by brian
Update for using real bool types. |
6448 |
return false; |
1
by brian
clean slate |
6449 |
}
|
6450 |
return (key_part == key_part_end); |
|
6451 |
}
|
|
6452 |
||
6453 |
||
6454 |
/*
|
|
6455 |
Create a QUICK_RANGE_SELECT from given key and SEL_ARG tree for that key.
|
|
6456 |
||
6457 |
SYNOPSIS
|
|
6458 |
get_quick_select()
|
|
6459 |
param
|
|
6460 |
idx Index of used key in param->key.
|
|
6461 |
key_tree SEL_ARG tree for the used key
|
|
6462 |
mrr_flags MRR parameter for quick select
|
|
6463 |
mrr_buf_size MRR parameter for quick select
|
|
6464 |
parent_alloc If not NULL, use it to allocate memory for
|
|
6465 |
quick select data. Otherwise use quick->alloc.
|
|
6466 |
NOTES
|
|
6467 |
The caller must call QUICK_SELECT::init for returned quick select.
|
|
6468 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
6469 |
CAUTION! This function may change session->mem_root to a MEM_ROOT which will be
|
1
by brian
clean slate |
6470 |
deallocated when the returned quick select is deleted.
|
6471 |
||
6472 |
RETURN
|
|
6473 |
NULL on error
|
|
6474 |
otherwise created quick select
|
|
6475 |
*/
|
|
6476 |
||
6477 |
QUICK_RANGE_SELECT * |
|
482
by Brian Aker
Remove uint. |
6478 |
get_quick_select(PARAM *param,uint32_t idx,SEL_ARG *key_tree, uint32_t mrr_flags, |
6479 |
uint32_t mrr_buf_size, MEM_ROOT *parent_alloc) |
|
1
by brian
clean slate |
6480 |
{
|
6481 |
QUICK_RANGE_SELECT *quick; |
|
55
by brian
Update for using real bool types. |
6482 |
bool create_err= false; |
1
by brian
clean slate |
6483 |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
6484 |
quick=new QUICK_RANGE_SELECT(param->session, param->table, |
1
by brian
clean slate |
6485 |
param->real_keynr[idx], |
1005.2.3
by Monty Taylor
Further reversion of P. |
6486 |
test(parent_alloc), NULL, &create_err); |
1
by brian
clean slate |
6487 |
|
6488 |
if (quick) |
|
6489 |
{
|
|
6490 |
if (create_err || |
|
6491 |
get_quick_keys(param,quick,param->key[idx],key_tree,param->min_key,0, |
|
6492 |
param->max_key,0)) |
|
6493 |
{
|
|
6494 |
delete quick; |
|
6495 |
quick=0; |
|
6496 |
}
|
|
6497 |
else
|
|
6498 |
{
|
|
6499 |
quick->mrr_flags= mrr_flags; |
|
6500 |
quick->mrr_buf_size= mrr_buf_size; |
|
6501 |
quick->key_parts=(KEY_PART*) |
|
6502 |
memdup_root(parent_alloc? parent_alloc : &quick->alloc, |
|
6503 |
(char*) param->key[idx], |
|
6504 |
sizeof(KEY_PART)* |
|
6505 |
param->table->key_info[param->real_keynr[idx]].key_parts); |
|
6506 |
}
|
|
6507 |
}
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6508 |
return quick; |
1
by brian
clean slate |
6509 |
}
|
6510 |
||
6511 |
||
6512 |
/*
|
|
6513 |
** Fix this to get all possible sub_ranges
|
|
6514 |
*/
|
|
6515 |
bool
|
|
6516 |
get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, |
|
482
by Brian Aker
Remove uint. |
6517 |
SEL_ARG *key_tree, unsigned char *min_key,uint32_t min_key_flag, |
6518 |
unsigned char *max_key, uint32_t max_key_flag) |
|
1
by brian
clean slate |
6519 |
{
|
6520 |
QUICK_RANGE *range; |
|
482
by Brian Aker
Remove uint. |
6521 |
uint32_t flag; |
1
by brian
clean slate |
6522 |
int min_part= key_tree->part-1, // # of keypart values in min_key buffer |
6523 |
max_part= key_tree->part-1; // # of keypart values in max_key buffer |
|
6524 |
||
6525 |
if (key_tree->left != &null_element) |
|
6526 |
{
|
|
6527 |
if (get_quick_keys(param,quick,key,key_tree->left, |
|
6528 |
min_key,min_key_flag, max_key, max_key_flag)) |
|
6529 |
return 1; |
|
6530 |
}
|
|
481
by Brian Aker
Remove all of uchar. |
6531 |
unsigned char *tmp_min_key=min_key,*tmp_max_key=max_key; |
1
by brian
clean slate |
6532 |
min_part+= key_tree->store_min(key[key_tree->part].store_length, |
6533 |
&tmp_min_key,min_key_flag); |
|
6534 |
max_part+= key_tree->store_max(key[key_tree->part].store_length, |
|
6535 |
&tmp_max_key,max_key_flag); |
|
6536 |
||
6537 |
if (key_tree->next_key_part && |
|
6538 |
key_tree->next_key_part->part == key_tree->part+1 && |
|
6539 |
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) |
|
6540 |
{ // const key as prefix |
|
6541 |
if ((tmp_min_key - min_key) == (tmp_max_key - max_key) && |
|
895
by Brian Aker
Completion (?) of uint conversion. |
6542 |
memcmp(min_key, max_key, (uint32_t)(tmp_max_key - max_key))==0 && |
1
by brian
clean slate |
6543 |
key_tree->min_flag==0 && key_tree->max_flag==0) |
6544 |
{
|
|
6545 |
if (get_quick_keys(param,quick,key,key_tree->next_key_part, |
|
6546 |
tmp_min_key, min_key_flag | key_tree->min_flag, |
|
6547 |
tmp_max_key, max_key_flag | key_tree->max_flag)) |
|
6548 |
return 1; |
|
6549 |
goto end; // Ugly, but efficient |
|
6550 |
}
|
|
6551 |
{
|
|
482
by Brian Aker
Remove uint. |
6552 |
uint32_t tmp_min_flag=key_tree->min_flag,tmp_max_flag=key_tree->max_flag; |
1
by brian
clean slate |
6553 |
if (!tmp_min_flag) |
6554 |
min_part+= key_tree->next_key_part->store_min_key(key, &tmp_min_key, |
|
6555 |
&tmp_min_flag); |
|
6556 |
if (!tmp_max_flag) |
|
6557 |
max_part+= key_tree->next_key_part->store_max_key(key, &tmp_max_key, |
|
6558 |
&tmp_max_flag); |
|
6559 |
flag=tmp_min_flag | tmp_max_flag; |
|
6560 |
}
|
|
6561 |
}
|
|
6562 |
else
|
|
6563 |
{
|
|
6564 |
flag= key_tree->min_flag | key_tree->max_flag; |
|
6565 |
}
|
|
6566 |
||
6567 |
/*
|
|
6568 |
Ensure that some part of min_key and max_key are used. If not,
|
|
6569 |
regard this as no lower/upper range
|
|
6570 |
*/
|
|
6571 |
{
|
|
6572 |
if (tmp_min_key != param->min_key) |
|
6573 |
flag&= ~NO_MIN_RANGE; |
|
6574 |
else
|
|
6575 |
flag|= NO_MIN_RANGE; |
|
6576 |
if (tmp_max_key != param->max_key) |
|
6577 |
flag&= ~NO_MAX_RANGE; |
|
6578 |
else
|
|
6579 |
flag|= NO_MAX_RANGE; |
|
6580 |
}
|
|
6581 |
if (flag == 0) |
|
6582 |
{
|
|
895
by Brian Aker
Completion (?) of uint conversion. |
6583 |
uint32_t length= (uint32_t) (tmp_min_key - param->min_key); |
6584 |
if (length == (uint32_t) (tmp_max_key - param->max_key) && |
|
1
by brian
clean slate |
6585 |
!memcmp(param->min_key,param->max_key,length)) |
6586 |
{
|
|
6587 |
KEY *table_key=quick->head->key_info+quick->index; |
|
6588 |
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.) |
6589 |
if ((table_key->flags & (HA_NOSAME)) == HA_NOSAME && |
1
by brian
clean slate |
6590 |
key->part == table_key->key_parts-1) |
6591 |
{
|
|
6592 |
if (!(table_key->flags & HA_NULL_PART_KEY) || |
|
6593 |
!null_part_in_key(key, |
|
6594 |
param->min_key, |
|
895
by Brian Aker
Completion (?) of uint conversion. |
6595 |
(uint32_t) (tmp_min_key - param->min_key))) |
1
by brian
clean slate |
6596 |
flag|= UNIQUE_RANGE; |
6597 |
else
|
|
6598 |
flag|= NULL_RANGE; |
|
6599 |
}
|
|
6600 |
}
|
|
6601 |
}
|
|
6602 |
||
6603 |
/* Get range for retrieving rows in QUICK_SELECT::get_next */
|
|
6604 |
if (!(range= new QUICK_RANGE(param->min_key, |
|
895
by Brian Aker
Completion (?) of uint conversion. |
6605 |
(uint32_t) (tmp_min_key - param->min_key), |
1
by brian
clean slate |
6606 |
min_part >=0 ? make_keypart_map(min_part) : 0, |
6607 |
param->max_key, |
|
895
by Brian Aker
Completion (?) of uint conversion. |
6608 |
(uint32_t) (tmp_max_key - param->max_key), |
1
by brian
clean slate |
6609 |
max_part >=0 ? make_keypart_map(max_part) : 0, |
6610 |
flag))) |
|
6611 |
return 1; // out of memory |
|
6612 |
||
937.2.6
by Stewart Smith
make set_if_bigger typesafe for C and C++. Fix up everywhere. |
6613 |
set_if_bigger(quick->max_used_key_length, (uint32_t)range->min_length); |
6614 |
set_if_bigger(quick->max_used_key_length, (uint32_t)range->max_length); |
|
895
by Brian Aker
Completion (?) of uint conversion. |
6615 |
set_if_bigger(quick->used_key_parts, (uint32_t) key_tree->part+1); |
481
by Brian Aker
Remove all of uchar. |
6616 |
if (insert_dynamic(&quick->ranges, (unsigned char*) &range)) |
1
by brian
clean slate |
6617 |
return 1; |
6618 |
||
6619 |
end: |
|
6620 |
if (key_tree->right != &null_element) |
|
6621 |
return get_quick_keys(param,quick,key,key_tree->right, |
|
6622 |
min_key,min_key_flag, |
|
6623 |
max_key,max_key_flag); |
|
6624 |
return 0; |
|
6625 |
}
|
|
6626 |
||
6627 |
/*
|
|
6628 |
Return 1 if there is only one range and this uses the whole primary key
|
|
6629 |
*/
|
|
6630 |
||
6631 |
bool QUICK_RANGE_SELECT::unique_key_range() |
|
6632 |
{
|
|
6633 |
if (ranges.elements == 1) |
|
6634 |
{
|
|
6635 |
QUICK_RANGE *tmp= *((QUICK_RANGE**)ranges.buffer); |
|
6636 |
if ((tmp->flag & (EQ_RANGE | NULL_RANGE)) == EQ_RANGE) |
|
6637 |
{
|
|
6638 |
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.) |
6639 |
return ((key->flags & (HA_NOSAME)) == HA_NOSAME && |
1
by brian
clean slate |
6640 |
key->key_length == tmp->min_length); |
6641 |
}
|
|
6642 |
}
|
|
6643 |
return 0; |
|
6644 |
}
|
|
6645 |
||
6646 |
||
6647 |
||
6648 |
/*
|
|
55
by brian
Update for using real bool types. |
6649 |
Return true if any part of the key is NULL
|
1
by brian
clean slate |
6650 |
|
6651 |
SYNOPSIS
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6652 |
null_part_in_key()
|
1
by brian
clean slate |
6653 |
key_part Array of key parts (index description)
|
6654 |
key Key values tuple
|
|
6655 |
length Length of key values tuple in bytes.
|
|
6656 |
||
6657 |
RETURN
|
|
55
by brian
Update for using real bool types. |
6658 |
true The tuple has at least one "keypartX is NULL"
|
6659 |
false Otherwise
|
|
1
by brian
clean slate |
6660 |
*/
|
6661 |
||
482
by Brian Aker
Remove uint. |
6662 |
static bool null_part_in_key(KEY_PART *key_part, const unsigned char *key, uint32_t length) |
1
by brian
clean slate |
6663 |
{
|
481
by Brian Aker
Remove all of uchar. |
6664 |
for (const unsigned char *end=key+length ; |
1
by brian
clean slate |
6665 |
key < end; |
6666 |
key+= key_part++->store_length) |
|
6667 |
{
|
|
6668 |
if (key_part->null_bit && *key) |
|
6669 |
return 1; |
|
6670 |
}
|
|
6671 |
return 0; |
|
6672 |
}
|
|
6673 |
||
6674 |
||
1005.2.3
by Monty Taylor
Further reversion of P. |
6675 |
bool QUICK_SELECT_I::is_keys_used(const MY_BITMAP *fields) |
1
by brian
clean slate |
6676 |
{
|
6677 |
return is_key_used(head, index, fields); |
|
6678 |
}
|
|
6679 |
||
1005.2.3
by Monty Taylor
Further reversion of P. |
6680 |
bool QUICK_INDEX_MERGE_SELECT::is_keys_used(const MY_BITMAP *fields) |
6681 |
{
|
|
6682 |
QUICK_RANGE_SELECT *quick; |
|
6683 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
|
6684 |
while ((quick= it++)) |
|
6685 |
{
|
|
6686 |
if (is_key_used(head, quick->index, fields)) |
|
6687 |
return 1; |
|
6688 |
}
|
|
6689 |
return 0; |
|
6690 |
}
|
|
6691 |
||
6692 |
bool QUICK_ROR_INTERSECT_SELECT::is_keys_used(const MY_BITMAP *fields) |
|
6693 |
{
|
|
6694 |
QUICK_RANGE_SELECT *quick; |
|
6695 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
|
6696 |
while ((quick= it++)) |
|
6697 |
{
|
|
6698 |
if (is_key_used(head, quick->index, fields)) |
|
6699 |
return 1; |
|
6700 |
}
|
|
6701 |
return 0; |
|
6702 |
}
|
|
6703 |
||
6704 |
bool QUICK_ROR_UNION_SELECT::is_keys_used(const MY_BITMAP *fields) |
|
1
by brian
clean slate |
6705 |
{
|
6706 |
QUICK_SELECT_I *quick; |
|
6707 |
List_iterator_fast<QUICK_SELECT_I> it(quick_selects); |
|
6708 |
while ((quick= it++)) |
|
6709 |
{
|
|
6710 |
if (quick->is_keys_used(fields)) |
|
6711 |
return 1; |
|
6712 |
}
|
|
6713 |
return 0; |
|
6714 |
}
|
|
6715 |
||
6716 |
||
6717 |
/*
|
|
6718 |
Create quick select from ref/ref_or_null scan.
|
|
6719 |
||
6720 |
SYNOPSIS
|
|
6721 |
get_quick_select_for_ref()
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
6722 |
session Thread handle
|
1
by brian
clean slate |
6723 |
table Table to access
|
6724 |
ref ref[_or_null] scan parameters
|
|
6725 |
records Estimate of number of records (needed only to construct
|
|
6726 |
quick select)
|
|
6727 |
NOTES
|
|
6728 |
This allocates things in a new memory root, as this may be called many
|
|
6729 |
times during a query.
|
|
6730 |
||
6731 |
RETURN
|
|
6732 |
Quick select that retrieves the same rows as passed ref scan
|
|
6733 |
NULL on error.
|
|
6734 |
*/
|
|
6735 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
6736 |
QUICK_RANGE_SELECT *get_quick_select_for_ref(Session *session, Table *table, |
1
by brian
clean slate |
6737 |
TABLE_REF *ref, ha_rows records) |
6738 |
{
|
|
6739 |
MEM_ROOT *old_root, *alloc; |
|
6740 |
QUICK_RANGE_SELECT *quick; |
|
6741 |
KEY *key_info = &table->key_info[ref->key]; |
|
6742 |
KEY_PART *key_part; |
|
6743 |
QUICK_RANGE *range; |
|
482
by Brian Aker
Remove uint. |
6744 |
uint32_t part; |
55
by brian
Update for using real bool types. |
6745 |
bool create_err= false; |
1
by brian
clean slate |
6746 |
COST_VECT cost; |
6747 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
6748 |
old_root= session->mem_root; |
6749 |
/* The following call may change session->mem_root */
|
|
1005.2.3
by Monty Taylor
Further reversion of P. |
6750 |
quick= new QUICK_RANGE_SELECT(session, table, ref->key, 0, 0, &create_err); |
1
by brian
clean slate |
6751 |
/* save mem_root set by QUICK_RANGE_SELECT constructor */
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
6752 |
alloc= session->mem_root; |
1
by brian
clean slate |
6753 |
/*
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
6754 |
return back default mem_root (session->mem_root) changed by
|
1
by brian
clean slate |
6755 |
QUICK_RANGE_SELECT constructor
|
6756 |
*/
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
6757 |
session->mem_root= old_root; |
1
by brian
clean slate |
6758 |
|
6759 |
if (!quick || create_err) |
|
6760 |
return 0; /* no ranges found */ |
|
6761 |
if (quick->init()) |
|
6762 |
goto err; |
|
6763 |
quick->records= records; |
|
6764 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
6765 |
if ((cp_buffer_from_ref(session, ref) && session->is_fatal_error) || |
1
by brian
clean slate |
6766 |
!(range= new(alloc) QUICK_RANGE())) |
6767 |
goto err; // out of memory |
|
6768 |
||
6769 |
range->min_key= range->max_key= ref->key_buff; |
|
6770 |
range->min_length= range->max_length= ref->key_length; |
|
6771 |
range->min_keypart_map= range->max_keypart_map= |
|
6772 |
make_prev_keypart_map(ref->key_parts); |
|
6773 |
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.) |
6774 |
key_info->flags == 0) ? EQ_RANGE : 0); |
1
by brian
clean slate |
6775 |
|
6776 |
if (!(quick->key_parts=key_part=(KEY_PART *) |
|
6777 |
alloc_root(&quick->alloc,sizeof(KEY_PART)*ref->key_parts))) |
|
6778 |
goto err; |
|
6779 |
||
6780 |
for (part=0 ; part < ref->key_parts ;part++,key_part++) |
|
6781 |
{
|
|
6782 |
key_part->part=part; |
|
6783 |
key_part->field= key_info->key_part[part].field; |
|
6784 |
key_part->length= key_info->key_part[part].length; |
|
6785 |
key_part->store_length= key_info->key_part[part].store_length; |
|
6786 |
key_part->null_bit= key_info->key_part[part].null_bit; |
|
206
by Brian Aker
Removed final uint dead types. |
6787 |
key_part->flag= (uint8_t) key_info->key_part[part].key_part_flag; |
1
by brian
clean slate |
6788 |
}
|
481
by Brian Aker
Remove all of uchar. |
6789 |
if (insert_dynamic(&quick->ranges,(unsigned char*)&range)) |
1
by brian
clean slate |
6790 |
goto err; |
6791 |
||
6792 |
/*
|
|
6793 |
Add a NULL range if REF_OR_NULL optimization is used.
|
|
6794 |
For example:
|
|
6795 |
if we have "WHERE A=2 OR A IS NULL" we created the (A=2) range above
|
|
6796 |
and have ref->null_ref_key set. Will create a new NULL range here.
|
|
6797 |
*/
|
|
6798 |
if (ref->null_ref_key) |
|
6799 |
{
|
|
6800 |
QUICK_RANGE *null_range; |
|
6801 |
||
6802 |
*ref->null_ref_key= 1; // Set null byte then create a range |
|
6803 |
if (!(null_range= new (alloc) |
|
6804 |
QUICK_RANGE(ref->key_buff, ref->key_length, |
|
6805 |
make_prev_keypart_map(ref->key_parts), |
|
6806 |
ref->key_buff, ref->key_length, |
|
6807 |
make_prev_keypart_map(ref->key_parts), EQ_RANGE))) |
|
6808 |
goto err; |
|
6809 |
*ref->null_ref_key= 0; // Clear null byte |
|
481
by Brian Aker
Remove all of uchar. |
6810 |
if (insert_dynamic(&quick->ranges,(unsigned char*)&null_range)) |
1
by brian
clean slate |
6811 |
goto err; |
6812 |
}
|
|
6813 |
||
6814 |
/* 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: |
6815 |
quick->mrr_flags= HA_MRR_NO_ASSOCIATION | |
1
by brian
clean slate |
6816 |
(table->key_read ? HA_MRR_INDEX_ONLY : 0); |
520.1.22
by Brian Aker
Second pass of thd cleanup |
6817 |
if (session->lex->sql_command != SQLCOM_SELECT) |
1
by brian
clean slate |
6818 |
quick->mrr_flags |= HA_MRR_USE_DEFAULT_IMPL; |
6819 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
6820 |
quick->mrr_buf_size= session->variables.read_rnd_buff_size; |
895
by Brian Aker
Completion (?) of uint conversion. |
6821 |
if (table->file->multi_range_read_info(quick->index, 1, (uint32_t)records, |
1
by brian
clean slate |
6822 |
&quick->mrr_buf_size, |
6823 |
&quick->mrr_flags, &cost)) |
|
6824 |
goto err; |
|
6825 |
||
6826 |
return quick; |
|
6827 |
err: |
|
6828 |
delete quick; |
|
6829 |
return 0; |
|
6830 |
}
|
|
6831 |
||
6832 |
||
6833 |
/*
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6834 |
Perform key scans for all used indexes (except CPK), get rowids and merge
|
1
by brian
clean slate |
6835 |
them into an ordered non-recurrent sequence of rowids.
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6836 |
|
1
by brian
clean slate |
6837 |
The merge/duplicate removal is performed using Unique class. We put all
|
6838 |
rowids into Unique, get the sorted sequence and destroy the Unique.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6839 |
|
55
by brian
Update for using real bool types. |
6840 |
If table has a clustered primary key that covers all rows (true for bdb
|
1
by brian
clean slate |
6841 |
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: |
6842 |
then rows that will be retrieved by PK scan are not put into Unique and
|
1
by brian
clean slate |
6843 |
primary key scan is not performed here, it is performed later separately.
|
6844 |
||
6845 |
RETURN
|
|
6846 |
0 OK
|
|
6847 |
other error
|
|
6848 |
*/
|
|
6849 |
||
6850 |
int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() |
|
6851 |
{
|
|
6852 |
List_iterator_fast<QUICK_RANGE_SELECT> cur_quick_it(quick_selects); |
|
6853 |
QUICK_RANGE_SELECT* cur_quick; |
|
6854 |
int result; |
|
6855 |
Unique *unique; |
|
6856 |
handler *file= head->file; |
|
6857 |
||
6858 |
file->extra(HA_EXTRA_KEYREAD); |
|
6859 |
head->prepare_for_position(); |
|
6860 |
||
6861 |
cur_quick_it.rewind(); |
|
6862 |
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. |
6863 |
assert(cur_quick != 0); |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6864 |
|
1
by brian
clean slate |
6865 |
/*
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6866 |
We reuse the same instance of handler so we need to call both init and
|
1
by brian
clean slate |
6867 |
reset here.
|
6868 |
*/
|
|
6869 |
if (cur_quick->init() || cur_quick->reset()) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6870 |
return 0; |
1
by brian
clean slate |
6871 |
|
6872 |
unique= new Unique(refpos_order_cmp, (void *)file, |
|
6873 |
file->ref_length, |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
6874 |
session->variables.sortbuff_size); |
1
by brian
clean slate |
6875 |
if (!unique) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6876 |
return 0; |
1
by brian
clean slate |
6877 |
for (;;) |
6878 |
{
|
|
6879 |
while ((result= cur_quick->get_next()) == HA_ERR_END_OF_FILE) |
|
6880 |
{
|
|
6881 |
cur_quick->range_end(); |
|
6882 |
cur_quick= cur_quick_it++; |
|
6883 |
if (!cur_quick) |
|
6884 |
break; |
|
6885 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
6886 |
if (cur_quick->file->inited != handler::NONE) |
1
by brian
clean slate |
6887 |
cur_quick->file->ha_index_end(); |
6888 |
if (cur_quick->init() || cur_quick->reset()) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6889 |
return 0; |
1
by brian
clean slate |
6890 |
}
|
6891 |
||
6892 |
if (result) |
|
6893 |
{
|
|
6894 |
if (result != HA_ERR_END_OF_FILE) |
|
6895 |
{
|
|
6896 |
cur_quick->range_end(); |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6897 |
return result; |
1
by brian
clean slate |
6898 |
}
|
6899 |
break; |
|
6900 |
}
|
|
6901 |
||
520.1.22
by Brian Aker
Second pass of thd cleanup |
6902 |
if (session->killed) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6903 |
return 0; |
1
by brian
clean slate |
6904 |
|
6905 |
/* skip row if it will be retrieved by clustered PK scan */
|
|
6906 |
if (pk_quick_select && pk_quick_select->row_in_ranges()) |
|
6907 |
continue; |
|
6908 |
||
6909 |
cur_quick->file->position(cur_quick->record); |
|
6910 |
result= unique->unique_add((char*)cur_quick->file->ref); |
|
6911 |
if (result) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6912 |
return 0; |
1
by brian
clean slate |
6913 |
|
6914 |
}
|
|
6915 |
||
6916 |
/* ok, all row ids are in Unique */
|
|
6917 |
result= unique->get(head); |
|
6918 |
delete unique; |
|
55
by brian
Update for using real bool types. |
6919 |
doing_pk_scan= false; |
1
by brian
clean slate |
6920 |
/* index_merge currently doesn't support "using index" at all */
|
6921 |
file->extra(HA_EXTRA_NO_KEYREAD); |
|
6922 |
/* start table scan */
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
6923 |
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 |
6924 |
return result; |
1
by brian
clean slate |
6925 |
}
|
6926 |
||
6927 |
||
6928 |
/*
|
|
6929 |
Get next row for index_merge.
|
|
6930 |
NOTES
|
|
6931 |
The rows are read from
|
|
6932 |
1. rowids stored in Unique.
|
|
6933 |
2. QUICK_RANGE_SELECT with clustered primary key (if any).
|
|
6934 |
The sets of rows retrieved in 1) and 2) are guaranteed to be disjoint.
|
|
6935 |
*/
|
|
6936 |
||
6937 |
int QUICK_INDEX_MERGE_SELECT::get_next() |
|
6938 |
{
|
|
6939 |
int result; |
|
6940 |
||
6941 |
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. |
6942 |
return(pk_quick_select->get_next()); |
1
by brian
clean slate |
6943 |
|
6944 |
if ((result= read_record.read_record(&read_record)) == -1) |
|
6945 |
{
|
|
6946 |
result= HA_ERR_END_OF_FILE; |
|
6947 |
end_read_record(&read_record); |
|
6948 |
/* All rows from Unique have been retrieved, do a clustered PK scan */
|
|
6949 |
if (pk_quick_select) |
|
6950 |
{
|
|
55
by brian
Update for using real bool types. |
6951 |
doing_pk_scan= true; |
1
by brian
clean slate |
6952 |
if ((result= pk_quick_select->init()) || |
6953 |
(result= pk_quick_select->reset())) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6954 |
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. |
6955 |
return(pk_quick_select->get_next()); |
1
by brian
clean slate |
6956 |
}
|
6957 |
}
|
|
6958 |
||
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
6959 |
return result; |
1
by brian
clean slate |
6960 |
}
|
6961 |
||
6962 |
||
6963 |
/*
|
|
6964 |
Retrieve next record.
|
|
6965 |
SYNOPSIS
|
|
6966 |
QUICK_ROR_INTERSECT_SELECT::get_next()
|
|
6967 |
||
6968 |
NOTES
|
|
6969 |
Invariant on enter/exit: all intersected selects have retrieved all index
|
|
6970 |
records with rowid <= some_rowid_val and no intersected select has
|
|
6971 |
retrieved any index records with rowid > some_rowid_val.
|
|
6972 |
We start fresh and loop until we have retrieved the same rowid in each of
|
|
6973 |
the key scans or we got an error.
|
|
6974 |
||
6975 |
If a Clustered PK scan is present, it is used only to check if row
|
|
6976 |
satisfies its condition (and never used for row retrieval).
|
|
6977 |
||
6978 |
RETURN
|
|
6979 |
0 - Ok
|
|
6980 |
other - Error code if any error occurred.
|
|
6981 |
*/
|
|
6982 |
||
6983 |
int QUICK_ROR_INTERSECT_SELECT::get_next() |
|
6984 |
{
|
|
6985 |
List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects); |
|
6986 |
QUICK_RANGE_SELECT* quick; |
|
6987 |
int error, cmp; |
|
482
by Brian Aker
Remove uint. |
6988 |
uint32_t last_rowid_count=0; |
1
by brian
clean slate |
6989 |
|
6990 |
do
|
|
6991 |
{
|
|
6992 |
/* Get a rowid for first quick and save it as a 'candidate' */
|
|
6993 |
quick= quick_it++; |
|
6994 |
error= quick->get_next(); |
|
6995 |
if (cpk_quick) |
|
6996 |
{
|
|
6997 |
while (!error && !cpk_quick->row_in_ranges()) |
|
6998 |
error= quick->get_next(); |
|
6999 |
}
|
|
7000 |
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. |
7001 |
return(error); |
1
by brian
clean slate |
7002 |
|
7003 |
quick->file->position(quick->record); |
|
7004 |
memcpy(last_rowid, quick->file->ref, head->file->ref_length); |
|
7005 |
last_rowid_count= 1; |
|
7006 |
||
7007 |
while (last_rowid_count < quick_selects.elements) |
|
7008 |
{
|
|
7009 |
if (!(quick= quick_it++)) |
|
7010 |
{
|
|
7011 |
quick_it.rewind(); |
|
7012 |
quick= quick_it++; |
|
7013 |
}
|
|
7014 |
||
7015 |
do
|
|
7016 |
{
|
|
7017 |
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. |
7018 |
return(error); |
1
by brian
clean slate |
7019 |
quick->file->position(quick->record); |
7020 |
cmp= head->file->cmp_ref(quick->file->ref, last_rowid); |
|
7021 |
} while (cmp < 0); |
|
7022 |
||
7023 |
/* Ok, current select 'caught up' and returned ref >= cur_ref */
|
|
7024 |
if (cmp > 0) |
|
7025 |
{
|
|
7026 |
/* Found a row with ref > cur_ref. Make it a new 'candidate' */
|
|
7027 |
if (cpk_quick) |
|
7028 |
{
|
|
7029 |
while (!cpk_quick->row_in_ranges()) |
|
7030 |
{
|
|
7031 |
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. |
7032 |
return(error); |
1
by brian
clean slate |
7033 |
}
|
7034 |
}
|
|
7035 |
memcpy(last_rowid, quick->file->ref, head->file->ref_length); |
|
7036 |
last_rowid_count= 1; |
|
7037 |
}
|
|
7038 |
else
|
|
7039 |
{
|
|
7040 |
/* current 'candidate' row confirmed by this select */
|
|
7041 |
last_rowid_count++; |
|
7042 |
}
|
|
7043 |
}
|
|
7044 |
||
7045 |
/* We get here if we got the same row ref in all scans. */
|
|
7046 |
if (need_to_fetch_row) |
|
7047 |
error= head->file->rnd_pos(head->record[0], last_rowid); |
|
7048 |
} 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. |
7049 |
return(error); |
1
by brian
clean slate |
7050 |
}
|
7051 |
||
7052 |
||
7053 |
/*
|
|
7054 |
Retrieve next record.
|
|
7055 |
SYNOPSIS
|
|
7056 |
QUICK_ROR_UNION_SELECT::get_next()
|
|
7057 |
||
7058 |
NOTES
|
|
7059 |
Enter/exit invariant:
|
|
7060 |
For each quick select in the queue a {key,rowid} tuple has been
|
|
7061 |
retrieved but the corresponding row hasn't been passed to output.
|
|
7062 |
||
7063 |
RETURN
|
|
7064 |
0 - Ok
|
|
7065 |
other - Error code if any error occurred.
|
|
7066 |
*/
|
|
7067 |
||
7068 |
int QUICK_ROR_UNION_SELECT::get_next() |
|
7069 |
{
|
|
7070 |
int error, dup_row; |
|
7071 |
QUICK_SELECT_I *quick; |
|
481
by Brian Aker
Remove all of uchar. |
7072 |
unsigned char *tmp; |
1
by brian
clean slate |
7073 |
|
7074 |
do
|
|
7075 |
{
|
|
7076 |
do
|
|
7077 |
{
|
|
957.1.6
by Padraig O'Sullivan
Fixed function object to ensure it correctly returns a boolean type since |
7078 |
if (queue->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. |
7079 |
return(HA_ERR_END_OF_FILE); |
1
by brian
clean slate |
7080 |
/* Ok, we have a queue with >= 1 scans */
|
7081 |
||
957.1.6
by Padraig O'Sullivan
Fixed function object to ensure it correctly returns a boolean type since |
7082 |
quick= queue->top(); |
1
by brian
clean slate |
7083 |
memcpy(cur_rowid, quick->last_rowid, rowid_length); |
7084 |
||
7085 |
/* put into queue rowid from the same stream as top element */
|
|
7086 |
if ((error= quick->get_next())) |
|
7087 |
{
|
|
7088 |
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. |
7089 |
return(error); |
957.1.6
by Padraig O'Sullivan
Fixed function object to ensure it correctly returns a boolean type since |
7090 |
queue->pop(); |
1
by brian
clean slate |
7091 |
}
|
7092 |
else
|
|
7093 |
{
|
|
7094 |
quick->save_last_pos(); |
|
957.1.6
by Padraig O'Sullivan
Fixed function object to ensure it correctly returns a boolean type since |
7095 |
queue->pop(); |
7096 |
queue->push(quick); |
|
1
by brian
clean slate |
7097 |
}
|
7098 |
||
7099 |
if (!have_prev_rowid) |
|
7100 |
{
|
|
7101 |
/* No rows have been returned yet */
|
|
55
by brian
Update for using real bool types. |
7102 |
dup_row= false; |
7103 |
have_prev_rowid= true; |
|
1
by brian
clean slate |
7104 |
}
|
7105 |
else
|
|
7106 |
dup_row= !head->file->cmp_ref(cur_rowid, prev_rowid); |
|
7107 |
} while (dup_row); |
|
7108 |
||
7109 |
tmp= cur_rowid; |
|
7110 |
cur_rowid= prev_rowid; |
|
7111 |
prev_rowid= tmp; |
|
7112 |
||
7113 |
error= head->file->rnd_pos(quick->record, prev_rowid); |
|
7114 |
} 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. |
7115 |
return(error); |
1
by brian
clean slate |
7116 |
}
|
7117 |
||
7118 |
||
7119 |
int QUICK_RANGE_SELECT::reset() |
|
7120 |
{
|
|
482
by Brian Aker
Remove uint. |
7121 |
uint32_t buf_size; |
481
by Brian Aker
Remove all of uchar. |
7122 |
unsigned char *mrange_buff; |
1
by brian
clean slate |
7123 |
int error; |
7124 |
HANDLER_BUFFER empty_buf; |
|
7125 |
last_range= NULL; |
|
7126 |
cur_range= (QUICK_RANGE**) ranges.buffer; |
|
7127 |
||
7128 |
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. |
7129 |
return(error); |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7130 |
|
1
by brian
clean slate |
7131 |
/* Allocate buffer if we need one but haven't allocated it yet */
|
7132 |
if (mrr_buf_size && !mrr_buf_desc) |
|
7133 |
{
|
|
7134 |
buf_size= mrr_buf_size; |
|
7135 |
while (buf_size && !my_multi_malloc(MYF(MY_WME), |
|
7136 |
&mrr_buf_desc, sizeof(*mrr_buf_desc), |
|
7137 |
&mrange_buff, buf_size, |
|
461
by Monty Taylor
Removed NullS. bu-bye. |
7138 |
NULL)) |
1
by brian
clean slate |
7139 |
{
|
7140 |
/* Try to shrink the buffers until both are 0. */
|
|
7141 |
buf_size/= 2; |
|
7142 |
}
|
|
7143 |
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. |
7144 |
return(HA_ERR_OUT_OF_MEM); |
1
by brian
clean slate |
7145 |
|
7146 |
/* Initialize the handler buffer. */
|
|
7147 |
mrr_buf_desc->buffer= mrange_buff; |
|
7148 |
mrr_buf_desc->buffer_end= mrange_buff + buf_size; |
|
7149 |
mrr_buf_desc->end_of_used_area= mrange_buff; |
|
7150 |
}
|
|
7151 |
||
7152 |
if (!mrr_buf_desc) |
|
7153 |
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: |
7154 |
|
1
by brian
clean slate |
7155 |
if (sorted) |
7156 |
mrr_flags |= HA_MRR_SORTED; |
|
7157 |
RANGE_SEQ_IF seq_funcs= {quick_range_seq_init, quick_range_seq_next}; |
|
7158 |
error= file->multi_range_read_init(&seq_funcs, (void*)this, ranges.elements, |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7159 |
mrr_flags, mrr_buf_desc? mrr_buf_desc: |
1
by brian
clean slate |
7160 |
&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. |
7161 |
return(error); |
1
by brian
clean slate |
7162 |
}
|
7163 |
||
7164 |
||
7165 |
/*
|
|
7166 |
Range sequence interface implementation for array<QUICK_RANGE>: initialize
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7167 |
|
1
by brian
clean slate |
7168 |
SYNOPSIS
|
7169 |
quick_range_seq_init()
|
|
7170 |
init_param Caller-opaque paramenter: QUICK_RANGE_SELECT* pointer
|
|
7171 |
n_ranges Number of ranges in the sequence (ignored)
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7172 |
flags MRR flags (currently not used)
|
1
by brian
clean slate |
7173 |
|
7174 |
RETURN
|
|
7175 |
Opaque value to be passed to quick_range_seq_next
|
|
7176 |
*/
|
|
7177 |
||
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
7178 |
range_seq_t quick_range_seq_init(void *init_param, uint32_t, uint32_t) |
1
by brian
clean slate |
7179 |
{
|
7180 |
QUICK_RANGE_SELECT *quick= (QUICK_RANGE_SELECT*)init_param; |
|
7181 |
quick->qr_traversal_ctx.first= (QUICK_RANGE**)quick->ranges.buffer; |
|
7182 |
quick->qr_traversal_ctx.cur= (QUICK_RANGE**)quick->ranges.buffer; |
|
77.1.46
by Monty Taylor
Finished the warnings work! |
7183 |
quick->qr_traversal_ctx.last= quick->qr_traversal_ctx.cur + |
1
by brian
clean slate |
7184 |
quick->ranges.elements; |
7185 |
return &quick->qr_traversal_ctx; |
|
7186 |
}
|
|
7187 |
||
7188 |
||
7189 |
/*
|
|
7190 |
Range sequence interface implementation for array<QUICK_RANGE>: get next
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7191 |
|
1
by brian
clean slate |
7192 |
SYNOPSIS
|
7193 |
quick_range_seq_next()
|
|
7194 |
rseq Value returned from quick_range_seq_init
|
|
7195 |
range OUT Store information about the range here
|
|
7196 |
||
7197 |
RETURN
|
|
7198 |
0 Ok
|
|
7199 |
1 No more ranges in the sequence
|
|
7200 |
*/
|
|
7201 |
||
482
by Brian Aker
Remove uint. |
7202 |
uint32_t quick_range_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range) |
1
by brian
clean slate |
7203 |
{
|
7204 |
QUICK_RANGE_SEQ_CTX *ctx= (QUICK_RANGE_SEQ_CTX*)rseq; |
|
7205 |
||
7206 |
if (ctx->cur == ctx->last) |
|
7207 |
return 1; /* no more ranges */ |
|
7208 |
||
7209 |
QUICK_RANGE *cur= *(ctx->cur); |
|
7210 |
key_range *start_key= &range->start_key; |
|
7211 |
key_range *end_key= &range->end_key; |
|
7212 |
||
7213 |
start_key->key= cur->min_key; |
|
7214 |
start_key->length= cur->min_length; |
|
7215 |
start_key->keypart_map= cur->min_keypart_map; |
|
7216 |
start_key->flag= ((cur->flag & NEAR_MIN) ? HA_READ_AFTER_KEY : |
|
7217 |
(cur->flag & EQ_RANGE) ? |
|
7218 |
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT); |
|
7219 |
end_key->key= cur->max_key; |
|
7220 |
end_key->length= cur->max_length; |
|
7221 |
end_key->keypart_map= cur->max_keypart_map; |
|
7222 |
/*
|
|
7223 |
We use HA_READ_AFTER_KEY here because if we are reading on a key
|
|
7224 |
prefix. We want to find all keys with this prefix.
|
|
7225 |
*/
|
|
7226 |
end_key->flag= (cur->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : |
|
7227 |
HA_READ_AFTER_KEY); |
|
7228 |
range->range_flag= cur->flag; |
|
7229 |
ctx->cur++; |
|
7230 |
return 0; |
|
7231 |
}
|
|
7232 |
||
7233 |
||
7234 |
/*
|
|
7235 |
MRR range sequence interface: array<QUICK_RANGE> impl: utility func for NDB
|
|
7236 |
||
7237 |
SYNOPSIS
|
|
7238 |
mrr_persistent_flag_storage()
|
|
7239 |
seq Range sequence being traversed
|
|
7240 |
idx Number of range
|
|
7241 |
||
7242 |
DESCRIPTION
|
|
7243 |
MRR/NDB implementation needs to store some bits for each range. This
|
|
7244 |
function returns a reference to the "range_flag" associated with the
|
|
7245 |
range number idx.
|
|
7246 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7247 |
This function should be removed when we get a proper MRR/NDB
|
1
by brian
clean slate |
7248 |
implementation.
|
7249 |
||
7250 |
RETURN
|
|
7251 |
Reference to range_flag associated with range number #idx
|
|
7252 |
*/
|
|
7253 |
||
482
by Brian Aker
Remove uint. |
7254 |
uint16_t &mrr_persistent_flag_storage(range_seq_t seq, uint32_t idx) |
1
by brian
clean slate |
7255 |
{
|
7256 |
QUICK_RANGE_SEQ_CTX *ctx= (QUICK_RANGE_SEQ_CTX*)seq; |
|
7257 |
return ctx->first[idx]->flag; |
|
7258 |
}
|
|
7259 |
||
7260 |
||
7261 |
/*
|
|
7262 |
MRR range sequence interface: array<QUICK_RANGE> impl: utility func for NDB
|
|
7263 |
||
7264 |
SYNOPSIS
|
|
7265 |
mrr_get_ptr_by_idx()
|
|
7266 |
seq Range sequence bening traversed
|
|
7267 |
idx Number of the range
|
|
7268 |
||
7269 |
DESCRIPTION
|
|
7270 |
An extension of MRR range sequence interface needed by NDB: return the
|
|
7271 |
data associated with the given range.
|
|
7272 |
||
7273 |
A proper MRR interface implementer is supposed to store and return
|
|
7274 |
range-associated data. NDB stores number of the range instead. So this
|
|
7275 |
is a helper function that translates range number to range associated
|
|
7276 |
data.
|
|
7277 |
||
7278 |
This function does nothing, as currrently there is only one user of the
|
|
7279 |
MRR interface - the quick range select code, and this user doesn't need
|
|
7280 |
to use range-associated data.
|
|
7281 |
||
7282 |
RETURN
|
|
7283 |
Reference to range-associated data
|
|
7284 |
*/
|
|
7285 |
||
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
7286 |
char* &mrr_get_ptr_by_idx(range_seq_t, uint32_t) |
1
by brian
clean slate |
7287 |
{
|
7288 |
static char *dummy; |
|
7289 |
return dummy; |
|
7290 |
}
|
|
7291 |
||
7292 |
||
7293 |
/*
|
|
7294 |
Get next possible record using quick-struct.
|
|
7295 |
||
7296 |
SYNOPSIS
|
|
7297 |
QUICK_RANGE_SELECT::get_next()
|
|
7298 |
||
7299 |
NOTES
|
|
7300 |
Record is read into table->record[0]
|
|
7301 |
||
7302 |
RETURN
|
|
7303 |
0 Found row
|
|
7304 |
HA_ERR_END_OF_FILE No (more) rows in range
|
|
7305 |
# Error code
|
|
7306 |
*/
|
|
7307 |
||
7308 |
int QUICK_RANGE_SELECT::get_next() |
|
7309 |
{
|
|
7310 |
char *dummy; |
|
7311 |
if (in_ror_merged_scan) |
|
7312 |
{
|
|
7313 |
/*
|
|
7314 |
We don't need to signal the bitmap change as the bitmap is always the
|
|
7315 |
same for this head->file
|
|
7316 |
*/
|
|
1005.2.10
by Monty Taylor
Got rid of column_bitmap_signal. Unused. |
7317 |
head->column_bitmaps_set(&column_bitmap, &column_bitmap); |
1
by brian
clean slate |
7318 |
}
|
7319 |
||
7320 |
int result= file->multi_range_read_next(&dummy); |
|
7321 |
||
7322 |
if (in_ror_merged_scan) |
|
7323 |
{
|
|
7324 |
/* Restore bitmaps set on entry */
|
|
1005.2.10
by Monty Taylor
Got rid of column_bitmap_signal. Unused. |
7325 |
head->column_bitmaps_set(save_read_set, save_write_set); |
1
by brian
clean slate |
7326 |
}
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7327 |
return result; |
1
by brian
clean slate |
7328 |
}
|
7329 |
||
7330 |
||
7331 |
/*
|
|
7332 |
Get the next record with a different prefix.
|
|
7333 |
||
7334 |
SYNOPSIS
|
|
7335 |
QUICK_RANGE_SELECT::get_next_prefix()
|
|
7336 |
prefix_length length of cur_prefix
|
|
7337 |
cur_prefix prefix of a key to be searched for
|
|
7338 |
||
7339 |
DESCRIPTION
|
|
7340 |
Each subsequent call to the method retrieves the first record that has a
|
|
7341 |
prefix with length prefix_length different from cur_prefix, such that the
|
|
7342 |
record with the new prefix is within the ranges described by
|
|
7343 |
this->ranges. The record found is stored into the buffer pointed by
|
|
7344 |
this->record.
|
|
7345 |
The method is useful for GROUP-BY queries with range conditions to
|
|
7346 |
discover the prefix of the next group that satisfies the range conditions.
|
|
7347 |
||
7348 |
TODO
|
|
7349 |
This method is a modified copy of QUICK_RANGE_SELECT::get_next(), so both
|
|
7350 |
methods should be unified into a more general one to reduce code
|
|
7351 |
duplication.
|
|
7352 |
||
7353 |
RETURN
|
|
7354 |
0 on success
|
|
7355 |
HA_ERR_END_OF_FILE if returned all keys
|
|
7356 |
other if some error occurred
|
|
7357 |
*/
|
|
7358 |
||
482
by Brian Aker
Remove uint. |
7359 |
int QUICK_RANGE_SELECT::get_next_prefix(uint32_t prefix_length, |
1
by brian
clean slate |
7360 |
key_part_map keypart_map, |
481
by Brian Aker
Remove all of uchar. |
7361 |
unsigned char *cur_prefix) |
1
by brian
clean slate |
7362 |
{
|
7363 |
for (;;) |
|
7364 |
{
|
|
7365 |
int result; |
|
7366 |
key_range start_key, end_key; |
|
7367 |
if (last_range) |
|
7368 |
{
|
|
7369 |
/* 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. |
7370 |
assert(cur_prefix != 0); |
1
by brian
clean slate |
7371 |
result= file->index_read_map(record, cur_prefix, keypart_map, |
7372 |
HA_READ_AFTER_KEY); |
|
7373 |
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 |
7374 |
return result; |
1
by brian
clean slate |
7375 |
}
|
7376 |
||
482
by Brian Aker
Remove uint. |
7377 |
uint32_t count= ranges.elements - (cur_range - (QUICK_RANGE**) ranges.buffer); |
1
by brian
clean slate |
7378 |
if (count == 0) |
7379 |
{
|
|
7380 |
/* Ranges have already been used up before. None is left for read. */
|
|
7381 |
last_range= 0; |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7382 |
return HA_ERR_END_OF_FILE; |
1
by brian
clean slate |
7383 |
}
|
7384 |
last_range= *(cur_range++); |
|
7385 |
||
481
by Brian Aker
Remove all of uchar. |
7386 |
start_key.key= (const unsigned char*) last_range->min_key; |
398.1.4
by Monty Taylor
Renamed max/min. |
7387 |
start_key.length= cmin(last_range->min_length, (uint16_t)prefix_length); |
1
by brian
clean slate |
7388 |
start_key.keypart_map= last_range->min_keypart_map & keypart_map; |
7389 |
start_key.flag= ((last_range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY : |
|
7390 |
(last_range->flag & EQ_RANGE) ? |
|
7391 |
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT); |
|
481
by Brian Aker
Remove all of uchar. |
7392 |
end_key.key= (const unsigned char*) last_range->max_key; |
398.1.4
by Monty Taylor
Renamed max/min. |
7393 |
end_key.length= cmin(last_range->max_length, (uint16_t)prefix_length); |
1
by brian
clean slate |
7394 |
end_key.keypart_map= last_range->max_keypart_map & keypart_map; |
7395 |
/*
|
|
7396 |
We use READ_AFTER_KEY here because if we are reading on a key
|
|
7397 |
prefix we want to find all keys with this prefix
|
|
7398 |
*/
|
|
7399 |
end_key.flag= (last_range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : |
|
7400 |
HA_READ_AFTER_KEY); |
|
7401 |
||
7402 |
result= file->read_range_first(last_range->min_keypart_map ? &start_key : 0, |
|
7403 |
last_range->max_keypart_map ? &end_key : 0, |
|
7404 |
test(last_range->flag & EQ_RANGE), |
|
7405 |
sorted); |
|
7406 |
if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE)) |
|
7407 |
last_range= 0; // Stop searching |
|
7408 |
||
7409 |
if (result != HA_ERR_END_OF_FILE) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7410 |
return result; |
1
by brian
clean slate |
7411 |
last_range= 0; // No matching rows; go to next range |
7412 |
}
|
|
7413 |
}
|
|
7414 |
||
7415 |
||
7416 |
/*
|
|
7417 |
Check if current row will be retrieved by this QUICK_RANGE_SELECT
|
|
7418 |
||
7419 |
NOTES
|
|
7420 |
It is assumed that currently a scan is being done on another index
|
|
7421 |
which reads all necessary parts of the index that is scanned by this
|
|
7422 |
quick select.
|
|
7423 |
The implementation does a binary search on sorted array of disjoint
|
|
7424 |
ranges, without taking size of range into account.
|
|
7425 |
||
7426 |
This function is used to filter out clustered PK scan rows in
|
|
7427 |
index_merge quick select.
|
|
7428 |
||
7429 |
RETURN
|
|
55
by brian
Update for using real bool types. |
7430 |
true if current row will be retrieved by this quick select
|
7431 |
false if not
|
|
1
by brian
clean slate |
7432 |
*/
|
7433 |
||
7434 |
bool QUICK_RANGE_SELECT::row_in_ranges() |
|
7435 |
{
|
|
7436 |
QUICK_RANGE *res; |
|
482
by Brian Aker
Remove uint. |
7437 |
uint32_t min= 0; |
7438 |
uint32_t max= ranges.elements - 1; |
|
7439 |
uint32_t mid= (max + min)/2; |
|
1
by brian
clean slate |
7440 |
|
7441 |
while (min != max) |
|
7442 |
{
|
|
7443 |
if (cmp_next(*(QUICK_RANGE**)dynamic_array_ptr(&ranges, mid))) |
|
7444 |
{
|
|
7445 |
/* current row value > mid->max */
|
|
7446 |
min= mid + 1; |
|
7447 |
}
|
|
7448 |
else
|
|
7449 |
max= mid; |
|
7450 |
mid= (min + max) / 2; |
|
7451 |
}
|
|
7452 |
res= *(QUICK_RANGE**)dynamic_array_ptr(&ranges, mid); |
|
7453 |
return (!cmp_next(res) && !cmp_prev(res)); |
|
7454 |
}
|
|
7455 |
||
7456 |
/*
|
|
7457 |
This is a hack: we inherit from QUICK_SELECT so that we can use the
|
|
7458 |
get_next() interface, but we have to hold a pointer to the original
|
|
7459 |
QUICK_SELECT because its data are used all over the place. What
|
|
7460 |
should be done is to factor out the data that is needed into a base
|
|
7461 |
class (QUICK_SELECT), and then have two subclasses (_ASC and _DESC)
|
|
7462 |
which handle the ranges and implement the get_next() function. But
|
|
7463 |
for now, this seems to work right at least.
|
|
7464 |
*/
|
|
7465 |
||
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
7466 |
QUICK_SELECT_DESC::QUICK_SELECT_DESC(QUICK_RANGE_SELECT *q, uint32_t, bool *) |
1
by brian
clean slate |
7467 |
:QUICK_RANGE_SELECT(*q), rev_it(rev_ranges) |
7468 |
{
|
|
7469 |
QUICK_RANGE *r; |
|
7470 |
||
7471 |
QUICK_RANGE **pr= (QUICK_RANGE**)ranges.buffer; |
|
7472 |
QUICK_RANGE **end_range= pr + ranges.elements; |
|
7473 |
for (; pr!=end_range; pr++) |
|
7474 |
rev_ranges.push_front(*pr); |
|
7475 |
||
7476 |
/* Remove EQ_RANGE flag for keys that are not using the full key */
|
|
7477 |
for (r = rev_it++; r; r = rev_it++) |
|
7478 |
{
|
|
7479 |
if ((r->flag & EQ_RANGE) && |
|
7480 |
head->key_info[index].key_length != r->max_length) |
|
7481 |
r->flag&= ~EQ_RANGE; |
|
7482 |
}
|
|
7483 |
rev_it.rewind(); |
|
7484 |
q->dont_free=1; // Don't free shared mem |
|
7485 |
delete q; |
|
7486 |
}
|
|
7487 |
||
7488 |
||
7489 |
int QUICK_SELECT_DESC::get_next() |
|
7490 |
{
|
|
7491 |
/* The max key is handled as follows:
|
|
7492 |
* - if there is NO_MAX_RANGE, start at the end and move backwards
|
|
7493 |
* - if it is an EQ_RANGE, which means that max key covers the entire
|
|
7494 |
* key, go directly to the key and read through it (sorting backwards is
|
|
7495 |
* same as sorting forwards)
|
|
7496 |
* - if it is NEAR_MAX, go to the key or next, step back once, and
|
|
7497 |
* move backwards
|
|
7498 |
* - otherwise (not NEAR_MAX == include the key), go after the key,
|
|
7499 |
* step back once, and move backwards
|
|
7500 |
*/
|
|
7501 |
||
7502 |
for (;;) |
|
7503 |
{
|
|
7504 |
int result; |
|
7505 |
if (last_range) |
|
7506 |
{ // Already read through key |
|
7507 |
result = ((last_range->flag & EQ_RANGE) |
|
7508 |
? file->index_next_same(record, last_range->min_key, |
|
7509 |
last_range->min_length) : |
|
7510 |
file->index_prev(record)); |
|
7511 |
if (!result) |
|
7512 |
{
|
|
7513 |
if (cmp_prev(*rev_it.ref()) == 0) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7514 |
return 0; |
1
by brian
clean slate |
7515 |
}
|
7516 |
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 |
7517 |
return result; |
1
by brian
clean slate |
7518 |
}
|
7519 |
||
7520 |
if (!(last_range= rev_it++)) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7521 |
return HA_ERR_END_OF_FILE; // All ranges used |
1
by brian
clean slate |
7522 |
|
7523 |
if (last_range->flag & NO_MAX_RANGE) // Read last record |
|
7524 |
{
|
|
7525 |
int local_error; |
|
7526 |
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. |
7527 |
return(local_error); // Empty table |
1
by brian
clean slate |
7528 |
if (cmp_prev(last_range) == 0) |
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7529 |
return 0; |
1
by brian
clean slate |
7530 |
last_range= 0; // No match; go to next range |
7531 |
continue; |
|
7532 |
}
|
|
7533 |
||
7534 |
if (last_range->flag & EQ_RANGE) |
|
7535 |
{
|
|
7536 |
result = file->index_read_map(record, last_range->max_key, |
|
7537 |
last_range->max_keypart_map, |
|
7538 |
HA_READ_KEY_EXACT); |
|
7539 |
}
|
|
7540 |
else
|
|
7541 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
7542 |
assert(last_range->flag & NEAR_MAX || |
1
by brian
clean slate |
7543 |
range_reads_after_key(last_range)); |
7544 |
result=file->index_read_map(record, last_range->max_key, |
|
7545 |
last_range->max_keypart_map, |
|
7546 |
((last_range->flag & NEAR_MAX) ? |
|
7547 |
HA_READ_BEFORE_KEY : |
|
7548 |
HA_READ_PREFIX_LAST_OR_PREV)); |
|
7549 |
}
|
|
7550 |
if (result) |
|
7551 |
{
|
|
7552 |
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 |
7553 |
return result; |
1
by brian
clean slate |
7554 |
last_range= 0; // Not found, to next range |
7555 |
continue; |
|
7556 |
}
|
|
7557 |
if (cmp_prev(last_range) == 0) |
|
7558 |
{
|
|
7559 |
if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE)) |
|
7560 |
last_range= 0; // Stop searching |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7561 |
return 0; // Found key is in range |
1
by brian
clean slate |
7562 |
}
|
7563 |
last_range= 0; // To next range |
|
7564 |
}
|
|
7565 |
}
|
|
7566 |
||
7567 |
||
7568 |
/*
|
|
7569 |
Compare if found key is over max-value
|
|
7570 |
Returns 0 if key <= range->max_key
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7571 |
TODO: Figure out why can't this function be as simple as cmp_prev().
|
1
by brian
clean slate |
7572 |
*/
|
7573 |
||
7574 |
int QUICK_RANGE_SELECT::cmp_next(QUICK_RANGE *range_arg) |
|
7575 |
{
|
|
7576 |
if (range_arg->flag & NO_MAX_RANGE) |
|
7577 |
return 0; /* key can't be to large */ |
|
7578 |
||
7579 |
KEY_PART *key_part=key_parts; |
|
482
by Brian Aker
Remove uint. |
7580 |
uint32_t store_length; |
1
by brian
clean slate |
7581 |
|
481
by Brian Aker
Remove all of uchar. |
7582 |
for (unsigned char *key=range_arg->max_key, *end=key+range_arg->max_length; |
1
by brian
clean slate |
7583 |
key < end; |
7584 |
key+= store_length, key_part++) |
|
7585 |
{
|
|
7586 |
int cmp; |
|
7587 |
store_length= key_part->store_length; |
|
7588 |
if (key_part->null_bit) |
|
7589 |
{
|
|
7590 |
if (*key) |
|
7591 |
{
|
|
7592 |
if (!key_part->field->is_null()) |
|
7593 |
return 1; |
|
7594 |
continue; |
|
7595 |
}
|
|
7596 |
else if (key_part->field->is_null()) |
|
7597 |
return 0; |
|
7598 |
key++; // Skip null byte |
|
7599 |
store_length--; |
|
7600 |
}
|
|
7601 |
if ((cmp=key_part->field->key_cmp(key, key_part->length)) < 0) |
|
7602 |
return 0; |
|
7603 |
if (cmp > 0) |
|
7604 |
return 1; |
|
7605 |
}
|
|
7606 |
return (range_arg->flag & NEAR_MAX) ? 1 : 0; // Exact match |
|
7607 |
}
|
|
7608 |
||
7609 |
||
7610 |
/*
|
|
7611 |
Returns 0 if found key is inside range (found key >= range->min_key).
|
|
7612 |
*/
|
|
7613 |
||
7614 |
int QUICK_RANGE_SELECT::cmp_prev(QUICK_RANGE *range_arg) |
|
7615 |
{
|
|
7616 |
int cmp; |
|
7617 |
if (range_arg->flag & NO_MIN_RANGE) |
|
7618 |
return 0; /* key can't be to small */ |
|
7619 |
||
7620 |
cmp= key_cmp(key_part_info, range_arg->min_key, |
|
7621 |
range_arg->min_length); |
|
7622 |
if (cmp > 0 || (cmp == 0 && (range_arg->flag & NEAR_MIN) == false)) |
|
7623 |
return 0; |
|
7624 |
return 1; // outside of range |
|
7625 |
}
|
|
7626 |
||
7627 |
||
7628 |
/*
|
|
55
by brian
Update for using real bool types. |
7629 |
* true if this range will require using HA_READ_AFTER_KEY
|
1
by brian
clean slate |
7630 |
See comment in get_next() about this
|
7631 |
*/
|
|
7632 |
||
7633 |
bool QUICK_SELECT_DESC::range_reads_after_key(QUICK_RANGE *range_arg) |
|
7634 |
{
|
|
7635 |
return ((range_arg->flag & (NO_MAX_RANGE | NEAR_MAX)) || |
|
7636 |
!(range_arg->flag & EQ_RANGE) || |
|
7637 |
head->key_info[index].key_length != range_arg->max_length) ? 1 : 0; |
|
7638 |
}
|
|
7639 |
||
7640 |
||
7641 |
void QUICK_RANGE_SELECT::add_info_string(String *str) |
|
7642 |
{
|
|
7643 |
KEY *key_info= head->key_info + index; |
|
7644 |
str->append(key_info->name); |
|
7645 |
}
|
|
7646 |
||
7647 |
void QUICK_INDEX_MERGE_SELECT::add_info_string(String *str) |
|
7648 |
{
|
|
7649 |
QUICK_RANGE_SELECT *quick; |
|
55
by brian
Update for using real bool types. |
7650 |
bool first= true; |
1
by brian
clean slate |
7651 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
7652 |
str->append(STRING_WITH_LEN("sort_union(")); |
|
7653 |
while ((quick= it++)) |
|
7654 |
{
|
|
7655 |
if (!first) |
|
7656 |
str->append(','); |
|
7657 |
else
|
|
55
by brian
Update for using real bool types. |
7658 |
first= false; |
1
by brian
clean slate |
7659 |
quick->add_info_string(str); |
7660 |
}
|
|
7661 |
if (pk_quick_select) |
|
7662 |
{
|
|
7663 |
str->append(','); |
|
7664 |
pk_quick_select->add_info_string(str); |
|
7665 |
}
|
|
7666 |
str->append(')'); |
|
7667 |
}
|
|
7668 |
||
7669 |
void QUICK_ROR_INTERSECT_SELECT::add_info_string(String *str) |
|
7670 |
{
|
|
55
by brian
Update for using real bool types. |
7671 |
bool first= true; |
1
by brian
clean slate |
7672 |
QUICK_RANGE_SELECT *quick; |
7673 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
|
7674 |
str->append(STRING_WITH_LEN("intersect(")); |
|
7675 |
while ((quick= it++)) |
|
7676 |
{
|
|
7677 |
KEY *key_info= head->key_info + quick->index; |
|
7678 |
if (!first) |
|
7679 |
str->append(','); |
|
7680 |
else
|
|
55
by brian
Update for using real bool types. |
7681 |
first= false; |
1
by brian
clean slate |
7682 |
str->append(key_info->name); |
7683 |
}
|
|
7684 |
if (cpk_quick) |
|
7685 |
{
|
|
7686 |
KEY *key_info= head->key_info + cpk_quick->index; |
|
7687 |
str->append(','); |
|
7688 |
str->append(key_info->name); |
|
7689 |
}
|
|
7690 |
str->append(')'); |
|
7691 |
}
|
|
7692 |
||
7693 |
void QUICK_ROR_UNION_SELECT::add_info_string(String *str) |
|
7694 |
{
|
|
55
by brian
Update for using real bool types. |
7695 |
bool first= true; |
1
by brian
clean slate |
7696 |
QUICK_SELECT_I *quick; |
7697 |
List_iterator_fast<QUICK_SELECT_I> it(quick_selects); |
|
7698 |
str->append(STRING_WITH_LEN("union(")); |
|
7699 |
while ((quick= it++)) |
|
7700 |
{
|
|
7701 |
if (!first) |
|
7702 |
str->append(','); |
|
7703 |
else
|
|
55
by brian
Update for using real bool types. |
7704 |
first= false; |
1
by brian
clean slate |
7705 |
quick->add_info_string(str); |
7706 |
}
|
|
7707 |
str->append(')'); |
|
7708 |
}
|
|
7709 |
||
7710 |
||
7711 |
void QUICK_RANGE_SELECT::add_keys_and_lengths(String *key_names, |
|
7712 |
String *used_lengths) |
|
7713 |
{
|
|
7714 |
char buf[64]; |
|
482
by Brian Aker
Remove uint. |
7715 |
uint32_t length; |
1
by brian
clean slate |
7716 |
KEY *key_info= head->key_info + index; |
7717 |
key_names->append(key_info->name); |
|
152
by Brian Aker
longlong replacement |
7718 |
length= int64_t2str(max_used_key_length, buf, 10) - buf; |
1
by brian
clean slate |
7719 |
used_lengths->append(buf, length); |
7720 |
}
|
|
7721 |
||
7722 |
void QUICK_INDEX_MERGE_SELECT::add_keys_and_lengths(String *key_names, |
|
7723 |
String *used_lengths) |
|
7724 |
{
|
|
7725 |
char buf[64]; |
|
482
by Brian Aker
Remove uint. |
7726 |
uint32_t length; |
55
by brian
Update for using real bool types. |
7727 |
bool first= true; |
1
by brian
clean slate |
7728 |
QUICK_RANGE_SELECT *quick; |
7729 |
||
7730 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
|
7731 |
while ((quick= it++)) |
|
7732 |
{
|
|
7733 |
if (first) |
|
55
by brian
Update for using real bool types. |
7734 |
first= false; |
1
by brian
clean slate |
7735 |
else
|
7736 |
{
|
|
7737 |
key_names->append(','); |
|
7738 |
used_lengths->append(','); |
|
7739 |
}
|
|
7740 |
||
7741 |
KEY *key_info= head->key_info + quick->index; |
|
7742 |
key_names->append(key_info->name); |
|
152
by Brian Aker
longlong replacement |
7743 |
length= int64_t2str(quick->max_used_key_length, buf, 10) - buf; |
1
by brian
clean slate |
7744 |
used_lengths->append(buf, length); |
7745 |
}
|
|
7746 |
if (pk_quick_select) |
|
7747 |
{
|
|
7748 |
KEY *key_info= head->key_info + pk_quick_select->index; |
|
7749 |
key_names->append(','); |
|
7750 |
key_names->append(key_info->name); |
|
152
by Brian Aker
longlong replacement |
7751 |
length= int64_t2str(pk_quick_select->max_used_key_length, buf, 10) - buf; |
1
by brian
clean slate |
7752 |
used_lengths->append(','); |
7753 |
used_lengths->append(buf, length); |
|
7754 |
}
|
|
7755 |
}
|
|
7756 |
||
7757 |
void QUICK_ROR_INTERSECT_SELECT::add_keys_and_lengths(String *key_names, |
|
7758 |
String *used_lengths) |
|
7759 |
{
|
|
7760 |
char buf[64]; |
|
482
by Brian Aker
Remove uint. |
7761 |
uint32_t length; |
55
by brian
Update for using real bool types. |
7762 |
bool first= true; |
1
by brian
clean slate |
7763 |
QUICK_RANGE_SELECT *quick; |
7764 |
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); |
|
7765 |
while ((quick= it++)) |
|
7766 |
{
|
|
7767 |
KEY *key_info= head->key_info + quick->index; |
|
7768 |
if (first) |
|
55
by brian
Update for using real bool types. |
7769 |
first= false; |
1
by brian
clean slate |
7770 |
else
|
7771 |
{
|
|
7772 |
key_names->append(','); |
|
7773 |
used_lengths->append(','); |
|
7774 |
}
|
|
7775 |
key_names->append(key_info->name); |
|
152
by Brian Aker
longlong replacement |
7776 |
length= int64_t2str(quick->max_used_key_length, buf, 10) - buf; |
1
by brian
clean slate |
7777 |
used_lengths->append(buf, length); |
7778 |
}
|
|
7779 |
||
7780 |
if (cpk_quick) |
|
7781 |
{
|
|
7782 |
KEY *key_info= head->key_info + cpk_quick->index; |
|
7783 |
key_names->append(','); |
|
7784 |
key_names->append(key_info->name); |
|
152
by Brian Aker
longlong replacement |
7785 |
length= int64_t2str(cpk_quick->max_used_key_length, buf, 10) - buf; |
1
by brian
clean slate |
7786 |
used_lengths->append(','); |
7787 |
used_lengths->append(buf, length); |
|
7788 |
}
|
|
7789 |
}
|
|
7790 |
||
7791 |
void QUICK_ROR_UNION_SELECT::add_keys_and_lengths(String *key_names, |
|
7792 |
String *used_lengths) |
|
7793 |
{
|
|
55
by brian
Update for using real bool types. |
7794 |
bool first= true; |
1
by brian
clean slate |
7795 |
QUICK_SELECT_I *quick; |
7796 |
List_iterator_fast<QUICK_SELECT_I> it(quick_selects); |
|
7797 |
while ((quick= it++)) |
|
7798 |
{
|
|
7799 |
if (first) |
|
55
by brian
Update for using real bool types. |
7800 |
first= false; |
1
by brian
clean slate |
7801 |
else
|
7802 |
{
|
|
7803 |
used_lengths->append(','); |
|
7804 |
key_names->append(','); |
|
7805 |
}
|
|
7806 |
quick->add_keys_and_lengths(key_names, used_lengths); |
|
7807 |
}
|
|
7808 |
}
|
|
7809 |
||
7810 |
||
7811 |
/*******************************************************************************
|
|
7812 |
* Implementation of QUICK_GROUP_MIN_MAX_SELECT
|
|
7813 |
*******************************************************************************/
|
|
7814 |
||
482
by Brian Aker
Remove uint. |
7815 |
static inline uint32_t get_field_keypart(KEY *index, Field *field); |
7816 |
static inline SEL_ARG * get_index_range_tree(uint32_t index, SEL_TREE* range_tree, |
|
7817 |
PARAM *param, uint32_t *param_idx); |
|
1
by brian
clean slate |
7818 |
static bool get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree, |
7819 |
KEY_PART_INFO *first_non_group_part, |
|
7820 |
KEY_PART_INFO *min_max_arg_part, |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
7821 |
KEY_PART_INFO *last_part, Session *session, |
482
by Brian Aker
Remove uint. |
7822 |
unsigned char *key_infix, uint32_t *key_infix_len, |
1
by brian
clean slate |
7823 |
KEY_PART_INFO **first_non_infix_part); |
7824 |
static bool |
|
7825 |
check_group_min_max_predicates(COND *cond, Item_field *min_max_arg_item, |
|
7826 |
Field::imagetype image_type); |
|
7827 |
||
7828 |
static void |
|
482
by Brian Aker
Remove uint. |
7829 |
cost_group_min_max(Table* table, KEY *index_info, uint32_t used_key_parts, |
7830 |
uint32_t group_key_parts, SEL_TREE *range_tree, |
|
1
by brian
clean slate |
7831 |
SEL_ARG *index_tree, ha_rows quick_prefix_records, |
7832 |
bool have_min, bool have_max, |
|
7833 |
double *read_cost, ha_rows *records); |
|
7834 |
||
7835 |
||
7836 |
/*
|
|
7837 |
Test if this access method is applicable to a GROUP query with MIN/MAX
|
|
7838 |
functions, and if so, construct a new TRP object.
|
|
7839 |
||
7840 |
SYNOPSIS
|
|
7841 |
get_best_group_min_max()
|
|
7842 |
param Parameter from test_quick_select
|
|
7843 |
sel_tree Range tree generated by get_mm_tree
|
|
7844 |
||
7845 |
DESCRIPTION
|
|
7846 |
Test whether a query can be computed via a QUICK_GROUP_MIN_MAX_SELECT.
|
|
7847 |
Queries computable via a QUICK_GROUP_MIN_MAX_SELECT must satisfy the
|
|
7848 |
following conditions:
|
|
7849 |
A) Table T has at least one compound index I of the form:
|
|
7850 |
I = <A_1, ...,A_k, [B_1,..., B_m], C, [D_1,...,D_n]>
|
|
7851 |
B) Query conditions:
|
|
7852 |
B0. Q is over a single table T.
|
|
7853 |
B1. The attributes referenced by Q are a subset of the attributes of I.
|
|
7854 |
B2. All attributes QA in Q can be divided into 3 overlapping groups:
|
|
7855 |
- SA = {S_1, ..., S_l, [C]} - from the SELECT clause, where C is
|
|
7856 |
referenced by any number of MIN and/or MAX functions if present.
|
|
7857 |
- WA = {W_1, ..., W_p} - from the WHERE clause
|
|
7858 |
- GA = <G_1, ..., G_k> - from the GROUP BY clause (if any)
|
|
7859 |
= SA - if Q is a DISTINCT query (based on the
|
|
7860 |
equivalence of DISTINCT and GROUP queries.
|
|
7861 |
- NGA = QA - (GA union C) = {NG_1, ..., NG_m} - the ones not in
|
|
7862 |
GROUP BY and not referenced by MIN/MAX functions.
|
|
7863 |
with the following properties specified below.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
7864 |
B3. If Q has a GROUP BY WITH ROLLUP clause the access method is not
|
1
by brian
clean slate |
7865 |
applicable.
|
7866 |
||
7867 |
SA1. There is at most one attribute in SA referenced by any number of
|
|
7868 |
MIN and/or MAX functions which, which if present, is denoted as C.
|
|
7869 |
SA2. The position of the C attribute in the index is after the last A_k.
|
|
7870 |
SA3. The attribute C can be referenced in the WHERE clause only in
|
|
7871 |
predicates of the forms:
|
|
7872 |
- (C {< | <= | > | >= | =} const)
|
|
7873 |
- (const {< | <= | > | >= | =} C)
|
|
7874 |
- (C between const_i and const_j)
|
|
7875 |
- C IS NULL
|
|
7876 |
- C IS NOT NULL
|
|
7877 |
- C != const
|
|
7878 |
SA4. If Q has a GROUP BY clause, there are no other aggregate functions
|
|
7879 |
except MIN and MAX. For queries with DISTINCT, aggregate functions
|
|
7880 |
are allowed.
|
|
7881 |
SA5. The select list in DISTINCT queries should not contain expressions.
|
|
7882 |
GA1. If Q has a GROUP BY clause, then GA is a prefix of I. That is, if
|
|
7883 |
G_i = A_j => i = j.
|
|
7884 |
GA2. If Q has a DISTINCT clause, then there is a permutation of SA that
|
|
7885 |
forms a prefix of I. This permutation is used as the GROUP clause
|
|
7886 |
when the DISTINCT query is converted to a GROUP query.
|
|
7887 |
GA3. The attributes in GA may participate in arbitrary predicates, divided
|
|
7888 |
into two groups:
|
|
7889 |
- RNG(G_1,...,G_q ; where q <= k) is a range condition over the
|
|
7890 |
attributes of a prefix of GA
|
|
7891 |
- PA(G_i1,...G_iq) is an arbitrary predicate over an arbitrary subset
|
|
7892 |
of GA. Since P is applied to only GROUP attributes it filters some
|
|
7893 |
groups, and thus can be applied after the grouping.
|
|
7894 |
GA4. There are no expressions among G_i, just direct column references.
|
|
7895 |
NGA1.If in the index I there is a gap between the last GROUP attribute G_k,
|
|
7896 |
and the MIN/MAX attribute C, then NGA must consist of exactly the
|
|
7897 |
index attributes that constitute the gap. As a result there is a
|
|
7898 |
permutation of NGA that coincides with the gap in the index
|
|
7899 |
<B_1, ..., B_m>.
|
|
7900 |
NGA2.If BA <> {}, then the WHERE clause must contain a conjunction EQ of
|
|
7901 |
equality conditions for all NG_i of the form (NG_i = const) or
|
|
7902 |
(const = NG_i), such that each NG_i is referenced in exactly one
|
|
7903 |
conjunct. Informally, the predicates provide constants to fill the
|
|
7904 |
gap in the index.
|
|
7905 |
WA1. There are no other attributes in the WHERE clause except the ones
|
|
7906 |
referenced in predicates RNG, PA, PC, EQ defined above. Therefore
|
|
7907 |
WA is subset of (GA union NGA union C) for GA,NGA,C that pass the
|
|
7908 |
above tests. By transitivity then it also follows that each WA_i
|
|
7909 |
participates in the index I (if this was already tested for GA, NGA
|
|
7910 |
and C).
|
|
7911 |
||
7912 |
C) Overall query form:
|
|
7913 |
SELECT EXPR([A_1,...,A_k], [B_1,...,B_m], [MIN(C)], [MAX(C)])
|
|
7914 |
FROM T
|
|
7915 |
WHERE [RNG(A_1,...,A_p ; where p <= k)]
|
|
7916 |
[AND EQ(B_1,...,B_m)]
|
|
7917 |
[AND PC(C)]
|
|
7918 |
[AND PA(A_i1,...,A_iq)]
|
|
7919 |
GROUP BY A_1,...,A_k
|
|
7920 |
[HAVING PH(A_1, ..., B_1,..., C)]
|
|
7921 |
where EXPR(...) is an arbitrary expression over some or all SELECT fields,
|
|
7922 |
or:
|
|
7923 |
SELECT DISTINCT A_i1,...,A_ik
|
|
7924 |
FROM T
|
|
7925 |
WHERE [RNG(A_1,...,A_p ; where p <= k)]
|
|
7926 |
[AND PA(A_i1,...,A_iq)];
|
|
7927 |
||
7928 |
NOTES
|
|
7929 |
If the current query satisfies the conditions above, and if
|
|
7930 |
(mem_root! = NULL), then the function constructs and returns a new TRP
|
|
7931 |
object, that is later used to construct a new QUICK_GROUP_MIN_MAX_SELECT.
|
|
7932 |
If (mem_root == NULL), then the function only tests whether the current
|
|
7933 |
query satisfies the conditions above, and, if so, sets
|
|
55
by brian
Update for using real bool types. |
7934 |
is_applicable = true.
|
1
by brian
clean slate |
7935 |
|
7936 |
Queries with DISTINCT for which index access can be used are transformed
|
|
7937 |
into equivalent group-by queries of the form:
|
|
7938 |
||
7939 |
SELECT A_1,...,A_k FROM T
|
|
7940 |
WHERE [RNG(A_1,...,A_p ; where p <= k)]
|
|
7941 |
[AND PA(A_i1,...,A_iq)]
|
|
7942 |
GROUP BY A_1,...,A_k;
|
|
7943 |
||
7944 |
The group-by list is a permutation of the select attributes, according
|
|
7945 |
to their order in the index.
|
|
7946 |
||
7947 |
TODO
|
|
7948 |
- What happens if the query groups by the MIN/MAX field, and there is no
|
|
7949 |
other field as in: "select min(a) from t1 group by a" ?
|
|
7950 |
- We assume that the general correctness of the GROUP-BY query was checked
|
|
7951 |
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: |
7952 |
- Lift the limitation in condition (B3), that is, make this access method
|
1
by brian
clean slate |
7953 |
applicable to ROLLUP queries.
|
7954 |
||
7955 |
RETURN
|
|
7956 |
If mem_root != NULL
|
|
7957 |
- valid TRP_GROUP_MIN_MAX object if this QUICK class can be used for
|
|
7958 |
the query
|
|
7959 |
- NULL o/w.
|
|
7960 |
If mem_root == NULL
|
|
7961 |
- NULL
|
|
7962 |
*/
|
|
7963 |
||
7964 |
static TRP_GROUP_MIN_MAX * |
|
7965 |
get_best_group_min_max(PARAM *param, SEL_TREE *tree) |
|
7966 |
{
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
7967 |
Session *session= param->session; |
7968 |
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 |
7969 |
Table *table= param->table; |
55
by brian
Update for using real bool types. |
7970 |
bool have_min= false; /* true if there is a MIN function. */ |
7971 |
bool have_max= false; /* true if there is a MAX function. */ |
|
1
by brian
clean slate |
7972 |
Item_field *min_max_arg_item= NULL; // The argument of all MIN/MAX functions |
7973 |
KEY_PART_INFO *min_max_arg_part= NULL; /* The corresponding keypart. */ |
|
482
by Brian Aker
Remove uint. |
7974 |
uint32_t group_prefix_len= 0; /* Length (in bytes) of the key prefix. */ |
1
by brian
clean slate |
7975 |
KEY *index_info= NULL; /* The index chosen for data access. */ |
482
by Brian Aker
Remove uint. |
7976 |
uint32_t index= 0; /* The id of the chosen index. */ |
7977 |
uint32_t group_key_parts= 0; // Number of index key parts in the group prefix. |
|
7978 |
uint32_t used_key_parts= 0; /* Number of index key parts used for access. */ |
|
481
by Brian Aker
Remove all of uchar. |
7979 |
unsigned char key_infix[MAX_KEY_LENGTH]; /* Constants from equality predicates.*/ |
482
by Brian Aker
Remove uint. |
7980 |
uint32_t key_infix_len= 0; /* Length of key_infix. */ |
1
by brian
clean slate |
7981 |
TRP_GROUP_MIN_MAX *read_plan= NULL; /* The eventually constructed TRP. */ |
482
by Brian Aker
Remove uint. |
7982 |
uint32_t key_part_nr; |
327.2.3
by Brian Aker
Refactoring of class Table |
7983 |
order_st *tmp_group; |
1
by brian
clean slate |
7984 |
Item *item; |
7985 |
Item_field *item_field; |
|
7986 |
||
7987 |
/* Perform few 'cheap' tests whether this access method is applicable. */
|
|
7988 |
if (!join) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
7989 |
return NULL; /* This is not a select statement. */ |
1
by brian
clean slate |
7990 |
if ((join->tables != 1) || /* The query must reference one table. */ |
7991 |
((!join->group_list) && /* Neither GROUP BY nor a DISTINCT query. */ |
|
7992 |
(!join->select_distinct)) || |
|
7993 |
(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 |
7994 |
return NULL; |
1
by brian
clean slate |
7995 |
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 |
7996 |
return NULL; |
1
by brian
clean slate |
7997 |
|
7998 |
/* Analyze the query in more detail. */
|
|
7999 |
List_iterator<Item> select_items_it(join->fields_list); |
|
8000 |
||
8001 |
/* Check (SA1,SA4) and store the only MIN/MAX argument - the C attribute.*/
|
|
8002 |
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 |
8003 |
return NULL; |
1
by brian
clean slate |
8004 |
if (join->sum_funcs[0]) |
8005 |
{
|
|
8006 |
Item_sum *min_max_item; |
|
8007 |
Item_sum **func_ptr= join->sum_funcs; |
|
8008 |
while ((min_max_item= *(func_ptr++))) |
|
8009 |
{
|
|
8010 |
if (min_max_item->sum_func() == Item_sum::MIN_FUNC) |
|
55
by brian
Update for using real bool types. |
8011 |
have_min= true; |
1
by brian
clean slate |
8012 |
else if (min_max_item->sum_func() == Item_sum::MAX_FUNC) |
55
by brian
Update for using real bool types. |
8013 |
have_max= true; |
1
by brian
clean slate |
8014 |
else
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8015 |
return NULL; |
1
by brian
clean slate |
8016 |
|
8017 |
/* The argument of MIN/MAX. */
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
8018 |
Item *expr= min_max_item->args[0]->real_item(); |
1
by brian
clean slate |
8019 |
if (expr->type() == Item::FIELD_ITEM) /* Is it an attribute? */ |
8020 |
{
|
|
8021 |
if (! min_max_arg_item) |
|
8022 |
min_max_arg_item= (Item_field*) expr; |
|
8023 |
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 |
8024 |
return NULL; |
1
by brian
clean slate |
8025 |
}
|
8026 |
else
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8027 |
return NULL; |
1
by brian
clean slate |
8028 |
}
|
8029 |
}
|
|
8030 |
||
8031 |
/* Check (SA5). */
|
|
8032 |
if (join->select_distinct) |
|
8033 |
{
|
|
8034 |
while ((item= select_items_it++)) |
|
8035 |
{
|
|
8036 |
if (item->type() != Item::FIELD_ITEM) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8037 |
return NULL; |
1
by brian
clean slate |
8038 |
}
|
8039 |
}
|
|
8040 |
||
8041 |
/* Check (GA4) - that there are no expressions among the group attributes. */
|
|
8042 |
for (tmp_group= join->group_list; tmp_group; tmp_group= tmp_group->next) |
|
8043 |
{
|
|
8044 |
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 |
8045 |
return NULL; |
1
by brian
clean slate |
8046 |
}
|
8047 |
||
8048 |
/*
|
|
8049 |
Check that table has at least one compound index such that the conditions
|
|
55
by brian
Update for using real bool types. |
8050 |
(GA1,GA2) are all true. If there is more than one such index, select the
|
1
by brian
clean slate |
8051 |
first one. Here we set the variables: group_prefix_len and index_info.
|
8052 |
*/
|
|
8053 |
KEY *cur_index_info= table->key_info; |
|
8054 |
KEY *cur_index_info_end= cur_index_info + table->s->keys; |
|
8055 |
KEY_PART_INFO *cur_part= NULL; |
|
8056 |
KEY_PART_INFO *end_part; /* Last part for loops. */ |
|
8057 |
/* Last index part. */
|
|
8058 |
KEY_PART_INFO *last_part= NULL; |
|
8059 |
KEY_PART_INFO *first_non_group_part= NULL; |
|
8060 |
KEY_PART_INFO *first_non_infix_part= NULL; |
|
482
by Brian Aker
Remove uint. |
8061 |
uint32_t key_infix_parts= 0; |
8062 |
uint32_t cur_group_key_parts= 0; |
|
8063 |
uint32_t cur_group_prefix_len= 0; |
|
1
by brian
clean slate |
8064 |
/* Cost-related variables for the best index so far. */
|
8065 |
double best_read_cost= DBL_MAX; |
|
8066 |
ha_rows best_records= 0; |
|
8067 |
SEL_ARG *best_index_tree= NULL; |
|
8068 |
ha_rows best_quick_prefix_records= 0; |
|
482
by Brian Aker
Remove uint. |
8069 |
uint32_t best_param_idx= 0; |
1
by brian
clean slate |
8070 |
double cur_read_cost= DBL_MAX; |
8071 |
ha_rows cur_records; |
|
8072 |
SEL_ARG *cur_index_tree= NULL; |
|
8073 |
ha_rows cur_quick_prefix_records= 0; |
|
482
by Brian Aker
Remove uint. |
8074 |
uint32_t cur_param_idx=MAX_KEY; |
1
by brian
clean slate |
8075 |
key_map cur_used_key_parts; |
482
by Brian Aker
Remove uint. |
8076 |
uint32_t pk= param->table->s->primary_key; |
1
by brian
clean slate |
8077 |
|
482
by Brian Aker
Remove uint. |
8078 |
for (uint32_t cur_index= 0 ; cur_index_info != cur_index_info_end ; |
1
by brian
clean slate |
8079 |
cur_index_info++, cur_index++) |
8080 |
{
|
|
8081 |
/* Check (B1) - if current index is covering. */
|
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
8082 |
if (!table->covering_keys.test(cur_index)) |
1
by brian
clean slate |
8083 |
goto next_index; |
8084 |
||
8085 |
/*
|
|
8086 |
If the current storage manager is such that it appends the primary key to
|
|
8087 |
each index, then the above condition is insufficient to check if the
|
|
8088 |
index is covering. In such cases it may happen that some fields are
|
|
8089 |
covered by the PK index, but not by the current index. Since we can't
|
|
8090 |
use the concatenation of both indexes for index lookup, such an index
|
|
8091 |
does not qualify as covering in our case. If this is the case, below
|
|
8092 |
we check that all query fields are indeed covered by 'cur_index'.
|
|
8093 |
*/
|
|
8094 |
if (pk < MAX_KEY && cur_index != pk && |
|
8095 |
(table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX)) |
|
8096 |
{
|
|
8097 |
/* For each table field */
|
|
482
by Brian Aker
Remove uint. |
8098 |
for (uint32_t i= 0; i < table->s->fields; i++) |
1
by brian
clean slate |
8099 |
{
|
8100 |
Field *cur_field= table->field[i]; |
|
8101 |
/*
|
|
8102 |
If the field is used in the current query ensure that it's
|
|
8103 |
part of 'cur_index'
|
|
8104 |
*/
|
|
1003.1.12
by Brian Aker
Begin of abstract out the bitmap from direct reference. |
8105 |
if ((cur_field->isReadSet()) && |
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
8106 |
!cur_field->part_of_key_not_clustered.test(cur_index)) |
1
by brian
clean slate |
8107 |
goto next_index; // Field was not part of key |
8108 |
}
|
|
8109 |
}
|
|
8110 |
||
8111 |
/*
|
|
8112 |
Check (GA1) for GROUP BY queries.
|
|
8113 |
*/
|
|
8114 |
if (join->group_list) |
|
8115 |
{
|
|
8116 |
cur_part= cur_index_info->key_part; |
|
8117 |
end_part= cur_part + cur_index_info->key_parts; |
|
8118 |
/* Iterate in parallel over the GROUP list and the index parts. */
|
|
8119 |
for (tmp_group= join->group_list; tmp_group && (cur_part != end_part); |
|
8120 |
tmp_group= tmp_group->next, cur_part++) |
|
8121 |
{
|
|
8122 |
/*
|
|
8123 |
TODO:
|
|
8124 |
tmp_group::item is an array of Item, is it OK to consider only the
|
|
8125 |
first Item? If so, then why? What is the array for?
|
|
8126 |
*/
|
|
8127 |
/* 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. |
8128 |
assert((*tmp_group->item)->type() == Item::FIELD_ITEM); |
1
by brian
clean slate |
8129 |
Item_field *group_field= (Item_field *) (*tmp_group->item); |
8130 |
if (group_field->field->eq(cur_part->field)) |
|
8131 |
{
|
|
8132 |
cur_group_prefix_len+= cur_part->store_length; |
|
8133 |
++cur_group_key_parts; |
|
8134 |
}
|
|
8135 |
else
|
|
8136 |
goto next_index; |
|
8137 |
}
|
|
8138 |
}
|
|
8139 |
/*
|
|
8140 |
Check (GA2) if this is a DISTINCT query.
|
|
327.2.3
by Brian Aker
Refactoring of class Table |
8141 |
If GA2, then Store a new order_st object in group_fields_array at the
|
8142 |
position of the key part of item_field->field. Thus we get the order_st
|
|
1
by brian
clean slate |
8143 |
objects for each field ordered as the corresponding key parts.
|
327.2.3
by Brian Aker
Refactoring of class Table |
8144 |
Later group_fields_array of order_st objects is used to convert the query
|
1
by brian
clean slate |
8145 |
to a GROUP query.
|
8146 |
*/
|
|
8147 |
else if (join->select_distinct) |
|
8148 |
{
|
|
8149 |
select_items_it.rewind(); |
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
8150 |
cur_used_key_parts.reset(); |
482
by Brian Aker
Remove uint. |
8151 |
uint32_t max_key_part= 0; |
1
by brian
clean slate |
8152 |
while ((item= select_items_it++)) |
8153 |
{
|
|
8154 |
item_field= (Item_field*) item; /* (SA5) already checked above. */ |
|
8155 |
/* Find the order of the key part in the index. */
|
|
8156 |
key_part_nr= get_field_keypart(cur_index_info, item_field->field); |
|
8157 |
/*
|
|
8158 |
Check if this attribute was already present in the select list.
|
|
8159 |
If it was present, then its corresponding key part was alredy used.
|
|
8160 |
*/
|
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
8161 |
if (cur_used_key_parts.test(key_part_nr)) |
1
by brian
clean slate |
8162 |
continue; |
8163 |
if (key_part_nr < 1 || key_part_nr > join->fields_list.elements) |
|
8164 |
goto next_index; |
|
8165 |
cur_part= cur_index_info->key_part + key_part_nr - 1; |
|
8166 |
cur_group_prefix_len+= cur_part->store_length; |
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
8167 |
cur_used_key_parts.set(key_part_nr); |
1
by brian
clean slate |
8168 |
++cur_group_key_parts; |
398.1.4
by Monty Taylor
Renamed max/min. |
8169 |
max_key_part= cmax(max_key_part,key_part_nr); |
1
by brian
clean slate |
8170 |
}
|
8171 |
/*
|
|
8172 |
Check that used key parts forms a prefix of the index.
|
|
8173 |
To check this we compare bits in all_parts and cur_parts.
|
|
8174 |
all_parts have all bits set from 0 to (max_key_part-1).
|
|
8175 |
cur_parts have bits set for only used keyparts.
|
|
8176 |
*/
|
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
8177 |
key_map all_parts, cur_parts; |
8178 |
for (uint32_t pos= 0; pos < max_key_part; pos++) |
|
8179 |
all_parts.set(pos); |
|
8180 |
cur_parts= cur_used_key_parts >> 1; |
|
1
by brian
clean slate |
8181 |
if (all_parts != cur_parts) |
8182 |
goto next_index; |
|
8183 |
}
|
|
8184 |
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. |
8185 |
assert(false); |
1
by brian
clean slate |
8186 |
|
8187 |
/* Check (SA2). */
|
|
8188 |
if (min_max_arg_item) |
|
8189 |
{
|
|
8190 |
key_part_nr= get_field_keypart(cur_index_info, min_max_arg_item->field); |
|
8191 |
if (key_part_nr <= cur_group_key_parts) |
|
8192 |
goto next_index; |
|
8193 |
min_max_arg_part= cur_index_info->key_part + key_part_nr - 1; |
|
8194 |
}
|
|
8195 |
||
8196 |
/*
|
|
8197 |
Check (NGA1, NGA2) and extract a sequence of constants to be used as part
|
|
8198 |
of all search keys.
|
|
8199 |
*/
|
|
8200 |
||
8201 |
/*
|
|
8202 |
If there is MIN/MAX, each keypart between the last group part and the
|
|
8203 |
MIN/MAX part must participate in one equality with constants, and all
|
|
8204 |
keyparts after the MIN/MAX part must not be referenced in the query.
|
|
8205 |
||
8206 |
If there is no MIN/MAX, the keyparts after the last group part can be
|
|
8207 |
referenced only in equalities with constants, and the referenced keyparts
|
|
8208 |
must form a sequence without any gaps that starts immediately after the
|
|
8209 |
last group keypart.
|
|
8210 |
*/
|
|
8211 |
last_part= cur_index_info->key_part + cur_index_info->key_parts; |
|
8212 |
first_non_group_part= (cur_group_key_parts < cur_index_info->key_parts) ? |
|
8213 |
cur_index_info->key_part + cur_group_key_parts : |
|
8214 |
NULL; |
|
8215 |
first_non_infix_part= min_max_arg_part ? |
|
8216 |
(min_max_arg_part < last_part) ? |
|
8217 |
min_max_arg_part : |
|
8218 |
NULL : |
|
8219 |
NULL; |
|
8220 |
if (first_non_group_part && |
|
8221 |
(!min_max_arg_part || (min_max_arg_part - first_non_group_part > 0))) |
|
8222 |
{
|
|
8223 |
if (tree) |
|
8224 |
{
|
|
482
by Brian Aker
Remove uint. |
8225 |
uint32_t dummy; |
1
by brian
clean slate |
8226 |
SEL_ARG *index_range_tree= get_index_range_tree(cur_index, tree, param, |
8227 |
&dummy); |
|
8228 |
if (!get_constant_key_infix(cur_index_info, index_range_tree, |
|
8229 |
first_non_group_part, min_max_arg_part, |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
8230 |
last_part, session, key_infix, &key_infix_len, |
1
by brian
clean slate |
8231 |
&first_non_infix_part)) |
8232 |
goto next_index; |
|
8233 |
}
|
|
8234 |
else if (min_max_arg_part && |
|
8235 |
(min_max_arg_part - first_non_group_part > 0)) |
|
8236 |
{
|
|
8237 |
/*
|
|
8238 |
There is a gap but no range tree, thus no predicates at all for the
|
|
8239 |
non-group keyparts.
|
|
8240 |
*/
|
|
8241 |
goto next_index; |
|
8242 |
}
|
|
8243 |
else if (first_non_group_part && join->conds) |
|
8244 |
{
|
|
8245 |
/*
|
|
8246 |
If there is no MIN/MAX function in the query, but some index
|
|
8247 |
key part is referenced in the WHERE clause, then this index
|
|
8248 |
cannot be used because the WHERE condition over the keypart's
|
|
8249 |
field cannot be 'pushed' to the index (because there is no
|
|
8250 |
range 'tree'), and the WHERE clause must be evaluated before
|
|
8251 |
GROUP BY/DISTINCT.
|
|
8252 |
*/
|
|
8253 |
/*
|
|
8254 |
Store the first and last keyparts that need to be analyzed
|
|
8255 |
into one array that can be passed as parameter.
|
|
8256 |
*/
|
|
8257 |
KEY_PART_INFO *key_part_range[2]; |
|
8258 |
key_part_range[0]= first_non_group_part; |
|
8259 |
key_part_range[1]= last_part; |
|
8260 |
||
8261 |
/* Check if cur_part is referenced in the WHERE clause. */
|
|
8262 |
if (join->conds->walk(&Item::find_item_in_field_list_processor, 0, |
|
481
by Brian Aker
Remove all of uchar. |
8263 |
(unsigned char*) key_part_range)) |
1
by brian
clean slate |
8264 |
goto next_index; |
8265 |
}
|
|
8266 |
}
|
|
8267 |
||
8268 |
/*
|
|
8269 |
Test (WA1) partially - that no other keypart after the last infix part is
|
|
8270 |
referenced in the query.
|
|
8271 |
*/
|
|
8272 |
if (first_non_infix_part) |
|
8273 |
{
|
|
8274 |
cur_part= first_non_infix_part + |
|
8275 |
(min_max_arg_part && (min_max_arg_part < last_part)); |
|
8276 |
for (; cur_part != last_part; cur_part++) |
|
8277 |
{
|
|
1003.1.12
by Brian Aker
Begin of abstract out the bitmap from direct reference. |
8278 |
if (cur_part->field->isReadSet()) |
1
by brian
clean slate |
8279 |
goto next_index; |
8280 |
}
|
|
8281 |
}
|
|
8282 |
||
8283 |
/* If we got to this point, cur_index_info passes the test. */
|
|
8284 |
key_infix_parts= key_infix_len ? |
|
8285 |
(first_non_infix_part - first_non_group_part) : 0; |
|
8286 |
used_key_parts= cur_group_key_parts + key_infix_parts; |
|
8287 |
||
8288 |
/* Compute the cost of using this index. */
|
|
8289 |
if (tree) |
|
8290 |
{
|
|
8291 |
/* Find the SEL_ARG sub-tree that corresponds to the chosen index. */
|
|
8292 |
cur_index_tree= get_index_range_tree(cur_index, tree, param, |
|
8293 |
&cur_param_idx); |
|
8294 |
/* Check if this range tree can be used for prefix retrieval. */
|
|
8295 |
COST_VECT dummy_cost; |
|
482
by Brian Aker
Remove uint. |
8296 |
uint32_t mrr_flags= HA_MRR_USE_DEFAULT_IMPL; |
8297 |
uint32_t mrr_bufsize=0; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
8298 |
cur_quick_prefix_records= check_quick_select(param, cur_param_idx, |
8299 |
false /*don't care*/, |
|
55
by brian
Update for using real bool types. |
8300 |
cur_index_tree, true, |
1
by brian
clean slate |
8301 |
&mrr_flags, &mrr_bufsize, |
8302 |
&dummy_cost); |
|
8303 |
}
|
|
8304 |
cost_group_min_max(table, cur_index_info, used_key_parts, |
|
8305 |
cur_group_key_parts, tree, cur_index_tree, |
|
8306 |
cur_quick_prefix_records, have_min, have_max, |
|
8307 |
&cur_read_cost, &cur_records); |
|
8308 |
/*
|
|
8309 |
If cur_read_cost is lower than best_read_cost use cur_index.
|
|
8310 |
Do not compare doubles directly because they may have different
|
|
8311 |
representations (64 vs. 80 bits).
|
|
8312 |
*/
|
|
8313 |
if (cur_read_cost < best_read_cost - (DBL_EPSILON * cur_read_cost)) |
|
8314 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8315 |
assert(tree != 0 || cur_param_idx == MAX_KEY); |
1
by brian
clean slate |
8316 |
index_info= cur_index_info; |
8317 |
index= cur_index; |
|
8318 |
best_read_cost= cur_read_cost; |
|
8319 |
best_records= cur_records; |
|
8320 |
best_index_tree= cur_index_tree; |
|
8321 |
best_quick_prefix_records= cur_quick_prefix_records; |
|
8322 |
best_param_idx= cur_param_idx; |
|
8323 |
group_key_parts= cur_group_key_parts; |
|
8324 |
group_prefix_len= cur_group_prefix_len; |
|
8325 |
}
|
|
8326 |
||
8327 |
next_index: |
|
8328 |
cur_group_key_parts= 0; |
|
8329 |
cur_group_prefix_len= 0; |
|
8330 |
}
|
|
8331 |
if (!index_info) /* No usable index found. */ |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8332 |
return NULL; |
1
by brian
clean slate |
8333 |
|
8334 |
/* Check (SA3) for the where clause. */
|
|
8335 |
if (join->conds && min_max_arg_item && |
|
248
by Brian Aker
Random cleanup in base.h |
8336 |
!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 |
8337 |
return NULL; |
1
by brian
clean slate |
8338 |
|
8339 |
/* The query passes all tests, so construct a new TRP object. */
|
|
8340 |
read_plan= new (param->mem_root) |
|
8341 |
TRP_GROUP_MIN_MAX(have_min, have_max, min_max_arg_part, |
|
8342 |
group_prefix_len, used_key_parts, |
|
8343 |
group_key_parts, index_info, index, |
|
8344 |
key_infix_len, |
|
8345 |
(key_infix_len > 0) ? key_infix : NULL, |
|
8346 |
tree, best_index_tree, best_param_idx, |
|
8347 |
best_quick_prefix_records); |
|
8348 |
if (read_plan) |
|
8349 |
{
|
|
8350 |
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 |
8351 |
return NULL; |
1
by brian
clean slate |
8352 |
|
8353 |
read_plan->read_cost= best_read_cost; |
|
8354 |
read_plan->records= best_records; |
|
8355 |
}
|
|
8356 |
||
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8357 |
return read_plan; |
1
by brian
clean slate |
8358 |
}
|
8359 |
||
8360 |
||
8361 |
/*
|
|
8362 |
Check that the MIN/MAX attribute participates only in range predicates
|
|
8363 |
with constants.
|
|
8364 |
||
8365 |
SYNOPSIS
|
|
8366 |
check_group_min_max_predicates()
|
|
8367 |
cond tree (or subtree) describing all or part of the WHERE
|
|
8368 |
clause being analyzed
|
|
8369 |
min_max_arg_item the field referenced by the MIN/MAX function(s)
|
|
8370 |
min_max_arg_part the keypart of the MIN/MAX argument if any
|
|
8371 |
||
8372 |
DESCRIPTION
|
|
8373 |
The function walks recursively over the cond tree representing a WHERE
|
|
8374 |
clause, and checks condition (SA3) - if a field is referenced by a MIN/MAX
|
|
8375 |
aggregate function, it is referenced only by one of the following
|
|
8376 |
predicates: {=, !=, <, <=, >, >=, between, is null, is not null}.
|
|
8377 |
||
8378 |
RETURN
|
|
55
by brian
Update for using real bool types. |
8379 |
true if cond passes the test
|
8380 |
false o/w
|
|
1
by brian
clean slate |
8381 |
*/
|
8382 |
||
8383 |
static bool |
|
8384 |
check_group_min_max_predicates(COND *cond, Item_field *min_max_arg_item, |
|
8385 |
Field::imagetype image_type) |
|
8386 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8387 |
assert(cond && min_max_arg_item); |
1
by brian
clean slate |
8388 |
|
8389 |
cond= cond->real_item(); |
|
8390 |
Item::Type cond_type= cond->type(); |
|
8391 |
if (cond_type == Item::COND_ITEM) /* 'AND' or 'OR' */ |
|
8392 |
{
|
|
8393 |
List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list()); |
|
8394 |
Item *and_or_arg; |
|
8395 |
while ((and_or_arg= li++)) |
|
8396 |
{
|
|
8397 |
if (!check_group_min_max_predicates(and_or_arg, min_max_arg_item, |
|
8398 |
image_type)) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8399 |
return false; |
1
by brian
clean slate |
8400 |
}
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8401 |
return true; |
1
by brian
clean slate |
8402 |
}
|
8403 |
||
8404 |
/*
|
|
8405 |
TODO:
|
|
8406 |
This is a very crude fix to handle sub-selects in the WHERE clause
|
|
8407 |
(Item_subselect objects). With the test below we rule out from the
|
|
8408 |
optimization all queries with subselects in the WHERE clause. What has to
|
|
8409 |
be done, is that here we should analyze whether the subselect references
|
|
8410 |
the MIN/MAX argument field, and disallow the optimization only if this is
|
|
8411 |
so.
|
|
8412 |
*/
|
|
8413 |
if (cond_type == Item::SUBSELECT_ITEM) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8414 |
return false; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
8415 |
|
1
by brian
clean slate |
8416 |
/* 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. |
8417 |
assert(cond_type == Item::FUNC_ITEM); |
1
by brian
clean slate |
8418 |
|
8419 |
/* Test if cond references only group-by or non-group fields. */
|
|
8420 |
Item_func *pred= (Item_func*) cond; |
|
8421 |
Item **arguments= pred->arguments(); |
|
8422 |
Item *cur_arg; |
|
482
by Brian Aker
Remove uint. |
8423 |
for (uint32_t arg_idx= 0; arg_idx < pred->argument_count (); arg_idx++) |
1
by brian
clean slate |
8424 |
{
|
8425 |
cur_arg= arguments[arg_idx]->real_item(); |
|
8426 |
if (cur_arg->type() == Item::FIELD_ITEM) |
|
8427 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
8428 |
if (min_max_arg_item->eq(cur_arg, 1)) |
1
by brian
clean slate |
8429 |
{
|
8430 |
/*
|
|
8431 |
If pred references the MIN/MAX argument, check whether pred is a range
|
|
8432 |
condition that compares the MIN/MAX argument with a constant.
|
|
8433 |
*/
|
|
8434 |
Item_func::Functype pred_type= pred->functype(); |
|
8435 |
if (pred_type != Item_func::EQUAL_FUNC && |
|
8436 |
pred_type != Item_func::LT_FUNC && |
|
8437 |
pred_type != Item_func::LE_FUNC && |
|
8438 |
pred_type != Item_func::GT_FUNC && |
|
8439 |
pred_type != Item_func::GE_FUNC && |
|
8440 |
pred_type != Item_func::BETWEEN && |
|
8441 |
pred_type != Item_func::ISNULL_FUNC && |
|
8442 |
pred_type != Item_func::ISNOTNULL_FUNC && |
|
8443 |
pred_type != Item_func::EQ_FUNC && |
|
8444 |
pred_type != Item_func::NE_FUNC) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8445 |
return false; |
1
by brian
clean slate |
8446 |
|
8447 |
/* Check that pred compares min_max_arg_item with a constant. */
|
|
8448 |
Item *args[3]; |
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
8449 |
memset(args, 0, 3 * sizeof(Item*)); |
1
by brian
clean slate |
8450 |
bool inv; |
8451 |
/* Test if this is a comparison of a field and a constant. */
|
|
8452 |
if (!simple_pred(pred, args, &inv)) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8453 |
return false; |
1
by brian
clean slate |
8454 |
|
8455 |
/* Check for compatible string comparisons - similar to get_mm_leaf. */
|
|
8456 |
if (args[0] && args[1] && !args[2] && // this is a binary function |
|
8457 |
min_max_arg_item->result_type() == STRING_RESULT && |
|
8458 |
/*
|
|
8459 |
Don't use an index when comparing strings of different collations.
|
|
8460 |
*/
|
|
8461 |
((args[1]->result_type() == STRING_RESULT && |
|
8462 |
image_type == Field::itRAW && |
|
8463 |
((Field_str*) min_max_arg_item->field)->charset() != |
|
8464 |
pred->compare_collation()) |
|
8465 |
||
|
|
8466 |
/*
|
|
8467 |
We can't always use indexes when comparing a string index to a
|
|
8468 |
number.
|
|
8469 |
*/
|
|
8470 |
(args[1]->result_type() != STRING_RESULT && |
|
8471 |
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 |
8472 |
return false; |
1
by brian
clean slate |
8473 |
}
|
8474 |
}
|
|
8475 |
else if (cur_arg->type() == Item::FUNC_ITEM) |
|
8476 |
{
|
|
8477 |
if (!check_group_min_max_predicates(cur_arg, min_max_arg_item, |
|
8478 |
image_type)) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8479 |
return false; |
1
by brian
clean slate |
8480 |
}
|
8481 |
else if (cur_arg->const_item()) |
|
8482 |
{
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8483 |
return true; |
1
by brian
clean slate |
8484 |
}
|
8485 |
else
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8486 |
return false; |
1
by brian
clean slate |
8487 |
}
|
8488 |
||
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8489 |
return true; |
1
by brian
clean slate |
8490 |
}
|
8491 |
||
8492 |
||
8493 |
/*
|
|
8494 |
Extract a sequence of constants from a conjunction of equality predicates.
|
|
8495 |
||
8496 |
SYNOPSIS
|
|
8497 |
get_constant_key_infix()
|
|
8498 |
index_info [in] Descriptor of the chosen index.
|
|
8499 |
index_range_tree [in] Range tree for the chosen index
|
|
8500 |
first_non_group_part [in] First index part after group attribute parts
|
|
8501 |
min_max_arg_part [in] The keypart of the MIN/MAX argument if any
|
|
8502 |
last_part [in] Last keypart of the index
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
8503 |
session [in] Current thread
|
1
by brian
clean slate |
8504 |
key_infix [out] Infix of constants to be used for index lookup
|
8505 |
key_infix_len [out] Lenghth of the infix
|
|
8506 |
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: |
8507 |
|
1
by brian
clean slate |
8508 |
DESCRIPTION
|
8509 |
Test conditions (NGA1, NGA2) from get_best_group_min_max(). Namely,
|
|
8510 |
for each keypart field NGF_i not in GROUP-BY, check that there is a
|
|
8511 |
constant equality predicate among conds with the form (NGF_i = const_ci) or
|
|
8512 |
(const_ci = NGF_i).
|
|
8513 |
Thus all the NGF_i attributes must fill the 'gap' between the last group-by
|
|
8514 |
attribute and the MIN/MAX attribute in the index (if present). If these
|
|
8515 |
conditions hold, copy each constant from its corresponding predicate into
|
|
8516 |
key_infix, in the order its NG_i attribute appears in the index, and update
|
|
8517 |
key_infix_len with the total length of the key parts in key_infix.
|
|
8518 |
||
8519 |
RETURN
|
|
55
by brian
Update for using real bool types. |
8520 |
true if the index passes the test
|
8521 |
false o/w
|
|
1
by brian
clean slate |
8522 |
*/
|
8523 |
||
8524 |
static bool |
|
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
8525 |
get_constant_key_infix(KEY *, SEL_ARG *index_range_tree, |
1
by brian
clean slate |
8526 |
KEY_PART_INFO *first_non_group_part, |
8527 |
KEY_PART_INFO *min_max_arg_part, |
|
77.1.46
by Monty Taylor
Finished the warnings work! |
8528 |
KEY_PART_INFO *last_part, |
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
8529 |
Session *, unsigned char *key_infix, uint32_t *key_infix_len, |
1
by brian
clean slate |
8530 |
KEY_PART_INFO **first_non_infix_part) |
8531 |
{
|
|
8532 |
SEL_ARG *cur_range; |
|
8533 |
KEY_PART_INFO *cur_part; |
|
8534 |
/* End part for the first loop below. */
|
|
8535 |
KEY_PART_INFO *end_part= min_max_arg_part ? min_max_arg_part : last_part; |
|
8536 |
||
8537 |
*key_infix_len= 0; |
|
481
by Brian Aker
Remove all of uchar. |
8538 |
unsigned char *key_ptr= key_infix; |
1
by brian
clean slate |
8539 |
for (cur_part= first_non_group_part; cur_part != end_part; cur_part++) |
8540 |
{
|
|
8541 |
/*
|
|
8542 |
Find the range tree for the current keypart. We assume that
|
|
8543 |
index_range_tree points to the leftmost keypart in the index.
|
|
8544 |
*/
|
|
8545 |
for (cur_range= index_range_tree; cur_range; |
|
8546 |
cur_range= cur_range->next_key_part) |
|
8547 |
{
|
|
8548 |
if (cur_range->field->eq(cur_part->field)) |
|
8549 |
break; |
|
8550 |
}
|
|
8551 |
if (!cur_range) |
|
8552 |
{
|
|
8553 |
if (min_max_arg_part) |
|
55
by brian
Update for using real bool types. |
8554 |
return false; /* The current keypart has no range predicates at all. */ |
1
by brian
clean slate |
8555 |
else
|
8556 |
{
|
|
8557 |
*first_non_infix_part= cur_part; |
|
55
by brian
Update for using real bool types. |
8558 |
return true; |
1
by brian
clean slate |
8559 |
}
|
8560 |
}
|
|
8561 |
||
8562 |
/* Check that the current range tree is a single point interval. */
|
|
8563 |
if (cur_range->prev || cur_range->next) |
|
55
by brian
Update for using real bool types. |
8564 |
return false; /* This is not the only range predicate for the field. */ |
1
by brian
clean slate |
8565 |
if ((cur_range->min_flag & NO_MIN_RANGE) || |
8566 |
(cur_range->max_flag & NO_MAX_RANGE) || |
|
8567 |
(cur_range->min_flag & NEAR_MIN) || (cur_range->max_flag & NEAR_MAX)) |
|
55
by brian
Update for using real bool types. |
8568 |
return false; |
1
by brian
clean slate |
8569 |
|
482
by Brian Aker
Remove uint. |
8570 |
uint32_t field_length= cur_part->store_length; |
1
by brian
clean slate |
8571 |
if ((cur_range->maybe_null && |
8572 |
cur_range->min_value[0] && cur_range->max_value[0]) || |
|
8573 |
!memcmp(cur_range->min_value, cur_range->max_value, field_length)) |
|
8574 |
{
|
|
8575 |
/* cur_range specifies 'IS NULL' or an equality condition. */
|
|
8576 |
memcpy(key_ptr, cur_range->min_value, field_length); |
|
8577 |
key_ptr+= field_length; |
|
8578 |
*key_infix_len+= field_length; |
|
8579 |
}
|
|
8580 |
else
|
|
55
by brian
Update for using real bool types. |
8581 |
return false; |
1
by brian
clean slate |
8582 |
}
|
8583 |
||
8584 |
if (!min_max_arg_part && (cur_part == last_part)) |
|
8585 |
*first_non_infix_part= last_part; |
|
8586 |
||
55
by brian
Update for using real bool types. |
8587 |
return true; |
1
by brian
clean slate |
8588 |
}
|
8589 |
||
8590 |
||
8591 |
/*
|
|
8592 |
Find the key part referenced by a field.
|
|
8593 |
||
8594 |
SYNOPSIS
|
|
8595 |
get_field_keypart()
|
|
8596 |
index descriptor of an index
|
|
8597 |
field field that possibly references some key part in index
|
|
8598 |
||
8599 |
NOTES
|
|
8600 |
The return value can be used to get a KEY_PART_INFO pointer by
|
|
8601 |
part= index->key_part + get_field_keypart(...) - 1;
|
|
8602 |
||
8603 |
RETURN
|
|
8604 |
Positive number which is the consecutive number of the key part, or
|
|
8605 |
0 if field does not reference any index field.
|
|
8606 |
*/
|
|
8607 |
||
8608 |
static inline uint |
|
8609 |
get_field_keypart(KEY *index, Field *field) |
|
8610 |
{
|
|
8611 |
KEY_PART_INFO *part, *end; |
|
8612 |
||
8613 |
for (part= index->key_part, end= part + index->key_parts; part < end; part++) |
|
8614 |
{
|
|
8615 |
if (field->eq(part->field)) |
|
8616 |
return part - index->key_part + 1; |
|
8617 |
}
|
|
8618 |
return 0; |
|
8619 |
}
|
|
8620 |
||
8621 |
||
8622 |
/*
|
|
8623 |
Find the SEL_ARG sub-tree that corresponds to the chosen index.
|
|
8624 |
||
8625 |
SYNOPSIS
|
|
8626 |
get_index_range_tree()
|
|
8627 |
index [in] The ID of the index being looked for
|
|
8628 |
range_tree[in] Tree of ranges being searched
|
|
8629 |
param [in] PARAM from SQL_SELECT::test_quick_select
|
|
8630 |
param_idx [out] Index in the array PARAM::key that corresponds to 'index'
|
|
8631 |
||
8632 |
DESCRIPTION
|
|
8633 |
||
8634 |
A SEL_TREE contains range trees for all usable indexes. This procedure
|
|
8635 |
finds the SEL_ARG sub-tree for 'index'. The members of a SEL_TREE are
|
|
8636 |
ordered in the same way as the members of PARAM::key, thus we first find
|
|
8637 |
the corresponding index in the array PARAM::key. This index is returned
|
|
8638 |
through the variable param_idx, to be used later as argument of
|
|
8639 |
check_quick_select().
|
|
8640 |
||
8641 |
RETURN
|
|
8642 |
Pointer to the SEL_ARG subtree that corresponds to index.
|
|
8643 |
*/
|
|
8644 |
||
482
by Brian Aker
Remove uint. |
8645 |
SEL_ARG * get_index_range_tree(uint32_t index, SEL_TREE* range_tree, PARAM *param, |
8646 |
uint32_t *param_idx) |
|
1
by brian
clean slate |
8647 |
{
|
482
by Brian Aker
Remove uint. |
8648 |
uint32_t idx= 0; /* Index nr in param->key_parts */ |
1
by brian
clean slate |
8649 |
while (idx < param->keys) |
8650 |
{
|
|
8651 |
if (index == param->real_keynr[idx]) |
|
8652 |
break; |
|
8653 |
idx++; |
|
8654 |
}
|
|
8655 |
*param_idx= idx; |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8656 |
return range_tree->keys[idx]; |
1
by brian
clean slate |
8657 |
}
|
8658 |
||
8659 |
||
8660 |
/*
|
|
8661 |
Compute the cost of a quick_group_min_max_select for a particular index.
|
|
8662 |
||
8663 |
SYNOPSIS
|
|
8664 |
cost_group_min_max()
|
|
8665 |
table [in] The table being accessed
|
|
8666 |
index_info [in] The index used to access the table
|
|
8667 |
used_key_parts [in] Number of key parts used to access the index
|
|
8668 |
group_key_parts [in] Number of index key parts in the group prefix
|
|
8669 |
range_tree [in] Tree of ranges for all indexes
|
|
8670 |
index_tree [in] The range tree for the current index
|
|
8671 |
quick_prefix_records [in] Number of records retrieved by the internally
|
|
8672 |
used quick range select if any
|
|
8673 |
have_min [in] True if there is a MIN function
|
|
8674 |
have_max [in] True if there is a MAX function
|
|
8675 |
read_cost [out] The cost to retrieve rows via this quick select
|
|
8676 |
records [out] The number of rows retrieved
|
|
8677 |
||
8678 |
DESCRIPTION
|
|
8679 |
This method computes the access cost of a TRP_GROUP_MIN_MAX instance and
|
|
8680 |
the number of rows returned. It updates this->read_cost and this->records.
|
|
8681 |
||
8682 |
NOTES
|
|
8683 |
The cost computation distinguishes several cases:
|
|
8684 |
1) No equality predicates over non-group attributes (thus no key_infix).
|
|
8685 |
If groups are bigger than blocks on the average, then we assume that it
|
|
8686 |
is very unlikely that block ends are aligned with group ends, thus even
|
|
8687 |
if we look for both MIN and MAX keys, all pairs of neighbor MIN/MAX
|
|
8688 |
keys, except for the first MIN and the last MAX keys, will be in the
|
|
8689 |
same block. If groups are smaller than blocks, then we are going to
|
|
8690 |
read all blocks.
|
|
8691 |
2) There are equality predicates over non-group attributes.
|
|
8692 |
In this case the group prefix is extended by additional constants, and
|
|
8693 |
as a result the min/max values are inside sub-groups of the original
|
|
8694 |
groups. The number of blocks that will be read depends on whether the
|
|
8695 |
ends of these sub-groups will be contained in the same or in different
|
|
8696 |
blocks. We compute the probability for the two ends of a subgroup to be
|
|
8697 |
in two different blocks as the ratio of:
|
|
8698 |
- the number of positions of the left-end of a subgroup inside a group,
|
|
8699 |
such that the right end of the subgroup is past the end of the buffer
|
|
8700 |
containing the left-end, and
|
|
8701 |
- the total number of possible positions for the left-end of the
|
|
8702 |
subgroup, which is the number of keys in the containing group.
|
|
8703 |
We assume it is very unlikely that two ends of subsequent subgroups are
|
|
8704 |
in the same block.
|
|
8705 |
3) The are range predicates over the group attributes.
|
|
8706 |
Then some groups may be filtered by the range predicates. We use the
|
|
8707 |
selectivity of the range predicates to decide how many groups will be
|
|
8708 |
filtered.
|
|
8709 |
||
8710 |
TODO
|
|
8711 |
- Take into account the optional range predicates over the MIN/MAX
|
|
8712 |
argument.
|
|
8713 |
- Check if we have a PK index and we use all cols - then each key is a
|
|
8714 |
group, and it will be better to use an index scan.
|
|
8715 |
||
8716 |
RETURN
|
|
8717 |
None
|
|
8718 |
*/
|
|
8719 |
||
482
by Brian Aker
Remove uint. |
8720 |
void cost_group_min_max(Table* table, KEY *index_info, uint32_t used_key_parts, |
8721 |
uint32_t group_key_parts, SEL_TREE *range_tree, |
|
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
8722 |
SEL_ARG *, ha_rows quick_prefix_records, |
1
by brian
clean slate |
8723 |
bool have_min, bool have_max, |
8724 |
double *read_cost, ha_rows *records) |
|
8725 |
{
|
|
8726 |
ha_rows table_records; |
|
482
by Brian Aker
Remove uint. |
8727 |
uint32_t num_groups; |
8728 |
uint32_t num_blocks; |
|
8729 |
uint32_t keys_per_block; |
|
8730 |
uint32_t keys_per_group; |
|
8731 |
uint32_t keys_per_subgroup; /* Average number of keys in sub-groups */ |
|
1
by brian
clean slate |
8732 |
/* formed by a key infix. */
|
8733 |
double p_overlap; /* Probability that a sub-group overlaps two blocks. */ |
|
8734 |
double quick_prefix_selectivity; |
|
8735 |
double io_cost; |
|
8736 |
double cpu_cost= 0; /* TODO: CPU cost of index_read calls? */ |
|
8737 |
||
8738 |
table_records= table->file->stats.records; |
|
8739 |
keys_per_block= (table->file->stats.block_size / 2 / |
|
8740 |
(index_info->key_length + table->file->ref_length) |
|
8741 |
+ 1); |
|
895
by Brian Aker
Completion (?) of uint conversion. |
8742 |
num_blocks= (uint32_t)(table_records / keys_per_block) + 1; |
1
by brian
clean slate |
8743 |
|
8744 |
/* Compute the number of keys in a group. */
|
|
8745 |
keys_per_group= index_info->rec_per_key[group_key_parts - 1]; |
|
8746 |
if (keys_per_group == 0) /* If there is no statistics try to guess */ |
|
8747 |
/* each group contains 10% of all records */
|
|
895
by Brian Aker
Completion (?) of uint conversion. |
8748 |
keys_per_group= (uint32_t)(table_records / 10) + 1; |
8749 |
num_groups= (uint32_t)(table_records / keys_per_group) + 1; |
|
1
by brian
clean slate |
8750 |
|
8751 |
/* Apply the selectivity of the quick select for group prefixes. */
|
|
8752 |
if (range_tree && (quick_prefix_records != HA_POS_ERROR)) |
|
8753 |
{
|
|
8754 |
quick_prefix_selectivity= (double) quick_prefix_records / |
|
8755 |
(double) table_records; |
|
895
by Brian Aker
Completion (?) of uint conversion. |
8756 |
num_groups= (uint32_t) rint(num_groups * quick_prefix_selectivity); |
937.2.6
by Stewart Smith
make set_if_bigger typesafe for C and C++. Fix up everywhere. |
8757 |
set_if_bigger(num_groups, 1U); |
1
by brian
clean slate |
8758 |
}
|
8759 |
||
8760 |
if (used_key_parts > group_key_parts) |
|
8761 |
{ /* |
|
8762 |
Compute the probability that two ends of a subgroup are inside
|
|
8763 |
different blocks.
|
|
8764 |
*/
|
|
8765 |
keys_per_subgroup= index_info->rec_per_key[used_key_parts - 1]; |
|
8766 |
if (keys_per_subgroup >= keys_per_block) /* If a subgroup is bigger than */ |
|
8767 |
p_overlap= 1.0; /* a block, it will overlap at least two blocks. */ |
|
8768 |
else
|
|
8769 |
{
|
|
8770 |
double blocks_per_group= (double) num_blocks / (double) num_groups; |
|
8771 |
p_overlap= (blocks_per_group * (keys_per_subgroup - 1)) / keys_per_group; |
|
398.1.4
by Monty Taylor
Renamed max/min. |
8772 |
p_overlap= cmin(p_overlap, 1.0); |
1
by brian
clean slate |
8773 |
}
|
398.1.4
by Monty Taylor
Renamed max/min. |
8774 |
io_cost= (double) cmin(num_groups * (1 + p_overlap), (double)num_blocks); |
1
by brian
clean slate |
8775 |
}
|
8776 |
else
|
|
8777 |
io_cost= (keys_per_group > keys_per_block) ? |
|
8778 |
(have_min && have_max) ? (double) (num_groups + 1) : |
|
8779 |
(double) num_groups : |
|
8780 |
(double) num_blocks; |
|
8781 |
||
8782 |
/*
|
|
8783 |
TODO: If there is no WHERE clause and no other expressions, there should be
|
|
8784 |
no CPU cost. We leave it here to make this cost comparable to that of index
|
|
8785 |
scan as computed in SQL_SELECT::test_quick_select().
|
|
8786 |
*/
|
|
8787 |
cpu_cost= (double) num_groups / TIME_FOR_COMPARE; |
|
8788 |
||
8789 |
*read_cost= io_cost + cpu_cost; |
|
8790 |
*records= num_groups; |
|
8791 |
}
|
|
8792 |
||
8793 |
||
8794 |
/*
|
|
8795 |
Construct a new quick select object for queries with group by with min/max.
|
|
8796 |
||
8797 |
SYNOPSIS
|
|
8798 |
TRP_GROUP_MIN_MAX::make_quick()
|
|
8799 |
param Parameter from test_quick_select
|
|
8800 |
retrieve_full_rows ignored
|
|
8801 |
parent_alloc Memory pool to use, if any.
|
|
8802 |
||
8803 |
NOTES
|
|
8804 |
Make_quick ignores the retrieve_full_rows parameter because
|
|
8805 |
QUICK_GROUP_MIN_MAX_SELECT always performs 'index only' scans.
|
|
8806 |
The other parameter are ignored as well because all necessary
|
|
8807 |
data to create the QUICK object is computed at this TRP creation
|
|
8808 |
time.
|
|
8809 |
||
8810 |
RETURN
|
|
8811 |
New QUICK_GROUP_MIN_MAX_SELECT object if successfully created,
|
|
8812 |
NULL otherwise.
|
|
8813 |
*/
|
|
8814 |
||
8815 |
QUICK_SELECT_I * |
|
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
8816 |
TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool, MEM_ROOT *parent_alloc) |
1
by brian
clean slate |
8817 |
{
|
8818 |
QUICK_GROUP_MIN_MAX_SELECT *quick; |
|
8819 |
||
8820 |
quick= new QUICK_GROUP_MIN_MAX_SELECT(param->table, |
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
8821 |
param->session->lex->current_select->join, |
1
by brian
clean slate |
8822 |
have_min, have_max, min_max_arg_part, |
8823 |
group_prefix_len, group_key_parts, |
|
8824 |
used_key_parts, index_info, index, |
|
8825 |
read_cost, records, key_infix_len, |
|
8826 |
key_infix, parent_alloc); |
|
8827 |
if (!quick) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8828 |
return NULL; |
1
by brian
clean slate |
8829 |
|
8830 |
if (quick->init()) |
|
8831 |
{
|
|
8832 |
delete quick; |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8833 |
return NULL; |
1
by brian
clean slate |
8834 |
}
|
8835 |
||
8836 |
if (range_tree) |
|
8837 |
{
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8838 |
assert(quick_prefix_records > 0); |
1
by brian
clean slate |
8839 |
if (quick_prefix_records == HA_POS_ERROR) |
8840 |
quick->quick_prefix_select= NULL; /* Can't construct a quick select. */ |
|
8841 |
else
|
|
8842 |
/* Make a QUICK_RANGE_SELECT to be used for group prefix retrieval. */
|
|
8843 |
quick->quick_prefix_select= get_quick_select(param, param_idx, |
|
8844 |
index_tree, |
|
8845 |
HA_MRR_USE_DEFAULT_IMPL, 0, |
|
8846 |
&quick->alloc); |
|
8847 |
||
8848 |
/*
|
|
8849 |
Extract the SEL_ARG subtree that contains only ranges for the MIN/MAX
|
|
8850 |
attribute, and create an array of QUICK_RANGES to be used by the
|
|
8851 |
new quick select.
|
|
8852 |
*/
|
|
8853 |
if (min_max_arg_part) |
|
8854 |
{
|
|
8855 |
SEL_ARG *min_max_range= index_tree; |
|
8856 |
while (min_max_range) /* Find the tree for the MIN/MAX key part. */ |
|
8857 |
{
|
|
8858 |
if (min_max_range->field->eq(min_max_arg_part->field)) |
|
8859 |
break; |
|
8860 |
min_max_range= min_max_range->next_key_part; |
|
8861 |
}
|
|
8862 |
/* Scroll to the leftmost interval for the MIN/MAX argument. */
|
|
8863 |
while (min_max_range && min_max_range->prev) |
|
8864 |
min_max_range= min_max_range->prev; |
|
8865 |
/* Create an array of QUICK_RANGEs for the MIN/MAX argument. */
|
|
8866 |
while (min_max_range) |
|
8867 |
{
|
|
8868 |
if (quick->add_range(min_max_range)) |
|
8869 |
{
|
|
8870 |
delete quick; |
|
8871 |
quick= NULL; |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8872 |
return NULL; |
1
by brian
clean slate |
8873 |
}
|
8874 |
min_max_range= min_max_range->next; |
|
8875 |
}
|
|
8876 |
}
|
|
8877 |
}
|
|
8878 |
else
|
|
8879 |
quick->quick_prefix_select= NULL; |
|
8880 |
||
8881 |
quick->update_key_stat(); |
|
8882 |
quick->adjust_prefix_ranges(); |
|
8883 |
||
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
8884 |
return quick; |
1
by brian
clean slate |
8885 |
}
|
8886 |
||
8887 |
||
8888 |
/*
|
|
8889 |
Construct new quick select for group queries with min/max.
|
|
8890 |
||
8891 |
SYNOPSIS
|
|
8892 |
QUICK_GROUP_MIN_MAX_SELECT::QUICK_GROUP_MIN_MAX_SELECT()
|
|
8893 |
table The table being accessed
|
|
8894 |
join Descriptor of the current query
|
|
55
by brian
Update for using real bool types. |
8895 |
have_min true if the query selects a MIN function
|
8896 |
have_max true if the query selects a MAX function
|
|
1
by brian
clean slate |
8897 |
min_max_arg_part The only argument field of all MIN/MAX functions
|
8898 |
group_prefix_len Length of all key parts in the group prefix
|
|
8899 |
prefix_key_parts All key parts in the group prefix
|
|
8900 |
index_info The index chosen for data access
|
|
8901 |
use_index The id of index_info
|
|
8902 |
read_cost Cost of this access method
|
|
8903 |
records Number of records returned
|
|
8904 |
key_infix_len Length of the key infix appended to the group prefix
|
|
8905 |
key_infix Infix of constants from equality predicates
|
|
8906 |
parent_alloc Memory pool for this and quick_prefix_select data
|
|
8907 |
||
8908 |
RETURN
|
|
8909 |
None
|
|
8910 |
*/
|
|
8911 |
||
8912 |
QUICK_GROUP_MIN_MAX_SELECT:: |
|
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
8913 |
QUICK_GROUP_MIN_MAX_SELECT(Table *table, JOIN *join_arg, bool have_min_arg, |
1
by brian
clean slate |
8914 |
bool have_max_arg, |
8915 |
KEY_PART_INFO *min_max_arg_part_arg, |
|
482
by Brian Aker
Remove uint. |
8916 |
uint32_t group_prefix_len_arg, uint32_t group_key_parts_arg, |
8917 |
uint32_t used_key_parts_arg, KEY *index_info_arg, |
|
8918 |
uint32_t use_index, double read_cost_arg, |
|
8919 |
ha_rows records_arg, uint32_t key_infix_len_arg, |
|
481
by Brian Aker
Remove all of uchar. |
8920 |
unsigned char *key_infix_arg, MEM_ROOT *parent_alloc) |
1
by brian
clean slate |
8921 |
:join(join_arg), index_info(index_info_arg), |
8922 |
group_prefix_len(group_prefix_len_arg), |
|
8923 |
group_key_parts(group_key_parts_arg), have_min(have_min_arg), |
|
55
by brian
Update for using real bool types. |
8924 |
have_max(have_max_arg), seen_first_key(false), |
1
by brian
clean slate |
8925 |
min_max_arg_part(min_max_arg_part_arg), key_infix(key_infix_arg), |
8926 |
key_infix_len(key_infix_len_arg), min_functions_it(NULL), |
|
8927 |
max_functions_it(NULL) |
|
8928 |
{
|
|
8929 |
head= table; |
|
8930 |
file= head->file; |
|
8931 |
index= use_index; |
|
8932 |
record= head->record[0]; |
|
8933 |
tmp_record= head->record[1]; |
|
8934 |
read_time= read_cost_arg; |
|
8935 |
records= records_arg; |
|
8936 |
used_key_parts= used_key_parts_arg; |
|
8937 |
real_key_parts= used_key_parts_arg; |
|
8938 |
real_prefix_len= group_prefix_len + key_infix_len; |
|
8939 |
group_prefix= NULL; |
|
8940 |
min_max_arg_len= min_max_arg_part ? min_max_arg_part->store_length : 0; |
|
8941 |
||
8942 |
/*
|
|
8943 |
We can't have parent_alloc set as the init function can't handle this case
|
|
8944 |
yet.
|
|
8945 |
*/
|
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
8946 |
assert(!parent_alloc); |
1
by brian
clean slate |
8947 |
if (!parent_alloc) |
8948 |
{
|
|
520.1.22
by Brian Aker
Second pass of thd cleanup |
8949 |
init_sql_alloc(&alloc, join->session->variables.range_alloc_block_size, 0); |
8950 |
join->session->mem_root= &alloc; |
|
1
by brian
clean slate |
8951 |
}
|
8952 |
else
|
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
8953 |
memset(&alloc, 0, sizeof(MEM_ROOT)); // ensure that it's not used |
1
by brian
clean slate |
8954 |
}
|
8955 |
||
8956 |
||
8957 |
/*
|
|
8958 |
Do post-constructor initialization.
|
|
8959 |
||
8960 |
SYNOPSIS
|
|
8961 |
QUICK_GROUP_MIN_MAX_SELECT::init()
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
8962 |
|
1
by brian
clean slate |
8963 |
DESCRIPTION
|
8964 |
The method performs initialization that cannot be done in the constructor
|
|
8965 |
such as memory allocations that may fail. It allocates memory for the
|
|
8966 |
group prefix and inifix buffers, and for the lists of MIN/MAX item to be
|
|
8967 |
updated during execution.
|
|
8968 |
||
8969 |
RETURN
|
|
8970 |
0 OK
|
|
8971 |
other Error code
|
|
8972 |
*/
|
|
8973 |
||
8974 |
int QUICK_GROUP_MIN_MAX_SELECT::init() |
|
8975 |
{
|
|
8976 |
if (group_prefix) /* Already initialized. */ |
|
8977 |
return 0; |
|
8978 |
||
481
by Brian Aker
Remove all of uchar. |
8979 |
if (!(last_prefix= (unsigned char*) alloc_root(&alloc, group_prefix_len))) |
1
by brian
clean slate |
8980 |
return 1; |
8981 |
/*
|
|
8982 |
We may use group_prefix to store keys with all select fields, so allocate
|
|
8983 |
enough space for it.
|
|
8984 |
*/
|
|
481
by Brian Aker
Remove all of uchar. |
8985 |
if (!(group_prefix= (unsigned char*) alloc_root(&alloc, |
1
by brian
clean slate |
8986 |
real_prefix_len + min_max_arg_len))) |
8987 |
return 1; |
|
8988 |
||
8989 |
if (key_infix_len > 0) |
|
8990 |
{
|
|
8991 |
/*
|
|
8992 |
The memory location pointed to by key_infix will be deleted soon, so
|
|
8993 |
allocate a new buffer and copy the key_infix into it.
|
|
8994 |
*/
|
|
481
by Brian Aker
Remove all of uchar. |
8995 |
unsigned char *tmp_key_infix= (unsigned char*) alloc_root(&alloc, key_infix_len); |
1
by brian
clean slate |
8996 |
if (!tmp_key_infix) |
8997 |
return 1; |
|
8998 |
memcpy(tmp_key_infix, this->key_infix, key_infix_len); |
|
8999 |
this->key_infix= tmp_key_infix; |
|
9000 |
}
|
|
9001 |
||
9002 |
if (min_max_arg_part) |
|
9003 |
{
|
|
9004 |
if (my_init_dynamic_array(&min_max_ranges, sizeof(QUICK_RANGE*), 16, 16)) |
|
9005 |
return 1; |
|
9006 |
||
9007 |
if (have_min) |
|
9008 |
{
|
|
9009 |
if (!(min_functions= new List<Item_sum>)) |
|
9010 |
return 1; |
|
9011 |
}
|
|
9012 |
else
|
|
9013 |
min_functions= NULL; |
|
9014 |
if (have_max) |
|
9015 |
{
|
|
9016 |
if (!(max_functions= new List<Item_sum>)) |
|
9017 |
return 1; |
|
9018 |
}
|
|
9019 |
else
|
|
9020 |
max_functions= NULL; |
|
9021 |
||
9022 |
Item_sum *min_max_item; |
|
9023 |
Item_sum **func_ptr= join->sum_funcs; |
|
9024 |
while ((min_max_item= *(func_ptr++))) |
|
9025 |
{
|
|
9026 |
if (have_min && (min_max_item->sum_func() == Item_sum::MIN_FUNC)) |
|
9027 |
min_functions->push_back(min_max_item); |
|
9028 |
else if (have_max && (min_max_item->sum_func() == Item_sum::MAX_FUNC)) |
|
9029 |
max_functions->push_back(min_max_item); |
|
9030 |
}
|
|
9031 |
||
9032 |
if (have_min) |
|
9033 |
{
|
|
9034 |
if (!(min_functions_it= new List_iterator<Item_sum>(*min_functions))) |
|
9035 |
return 1; |
|
9036 |
}
|
|
9037 |
||
9038 |
if (have_max) |
|
9039 |
{
|
|
9040 |
if (!(max_functions_it= new List_iterator<Item_sum>(*max_functions))) |
|
9041 |
return 1; |
|
9042 |
}
|
|
9043 |
}
|
|
9044 |
else
|
|
9045 |
min_max_ranges.elements= 0; |
|
9046 |
||
9047 |
return 0; |
|
9048 |
}
|
|
9049 |
||
9050 |
||
9051 |
QUICK_GROUP_MIN_MAX_SELECT::~QUICK_GROUP_MIN_MAX_SELECT() |
|
9052 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
9053 |
if (file->inited != handler::NONE) |
1
by brian
clean slate |
9054 |
file->ha_index_end(); |
9055 |
if (min_max_arg_part) |
|
9056 |
delete_dynamic(&min_max_ranges); |
|
9057 |
free_root(&alloc,MYF(0)); |
|
9058 |
delete min_functions_it; |
|
9059 |
delete max_functions_it; |
|
9060 |
delete quick_prefix_select; |
|
9061 |
}
|
|
9062 |
||
9063 |
||
9064 |
/*
|
|
9065 |
Eventually create and add a new quick range object.
|
|
9066 |
||
9067 |
SYNOPSIS
|
|
9068 |
QUICK_GROUP_MIN_MAX_SELECT::add_range()
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
9069 |
sel_range Range object from which a
|
1
by brian
clean slate |
9070 |
|
9071 |
NOTES
|
|
9072 |
Construct a new QUICK_RANGE object from a SEL_ARG object, and
|
|
9073 |
add it to the array min_max_ranges. If sel_arg is an infinite
|
|
9074 |
range, e.g. (x < 5 or x > 4), then skip it and do not construct
|
|
9075 |
a quick range.
|
|
9076 |
||
9077 |
RETURN
|
|
55
by brian
Update for using real bool types. |
9078 |
false on success
|
9079 |
true otherwise
|
|
1
by brian
clean slate |
9080 |
*/
|
9081 |
||
9082 |
bool QUICK_GROUP_MIN_MAX_SELECT::add_range(SEL_ARG *sel_range) |
|
9083 |
{
|
|
9084 |
QUICK_RANGE *range; |
|
482
by Brian Aker
Remove uint. |
9085 |
uint32_t range_flag= sel_range->min_flag | sel_range->max_flag; |
1
by brian
clean slate |
9086 |
|
9087 |
/* Skip (-inf,+inf) ranges, e.g. (x < 5 or x > 4). */
|
|
9088 |
if ((range_flag & NO_MIN_RANGE) && (range_flag & NO_MAX_RANGE)) |
|
55
by brian
Update for using real bool types. |
9089 |
return false; |
1
by brian
clean slate |
9090 |
|
9091 |
if (!(sel_range->min_flag & NO_MIN_RANGE) && |
|
9092 |
!(sel_range->max_flag & NO_MAX_RANGE)) |
|
9093 |
{
|
|
9094 |
if (sel_range->maybe_null && |
|
9095 |
sel_range->min_value[0] && sel_range->max_value[0]) |
|
9096 |
range_flag|= NULL_RANGE; /* IS NULL condition */ |
|
9097 |
else if (memcmp(sel_range->min_value, sel_range->max_value, |
|
9098 |
min_max_arg_len) == 0) |
|
9099 |
range_flag|= EQ_RANGE; /* equality condition */ |
|
9100 |
}
|
|
9101 |
range= new QUICK_RANGE(sel_range->min_value, min_max_arg_len, |
|
9102 |
make_keypart_map(sel_range->part), |
|
9103 |
sel_range->max_value, min_max_arg_len, |
|
9104 |
make_keypart_map(sel_range->part), |
|
9105 |
range_flag); |
|
9106 |
if (!range) |
|
55
by brian
Update for using real bool types. |
9107 |
return true; |
481
by Brian Aker
Remove all of uchar. |
9108 |
if (insert_dynamic(&min_max_ranges, (unsigned char*)&range)) |
55
by brian
Update for using real bool types. |
9109 |
return true; |
9110 |
return false; |
|
1
by brian
clean slate |
9111 |
}
|
9112 |
||
9113 |
||
9114 |
/*
|
|
9115 |
Opens the ranges if there are more conditions in quick_prefix_select than
|
|
9116 |
the ones used for jumping through the prefixes.
|
|
9117 |
||
9118 |
SYNOPSIS
|
|
9119 |
QUICK_GROUP_MIN_MAX_SELECT::adjust_prefix_ranges()
|
|
9120 |
||
9121 |
NOTES
|
|
9122 |
quick_prefix_select is made over the conditions on the whole key.
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
9123 |
It defines a number of ranges of length x.
|
9124 |
However when jumping through the prefixes we use only the the first
|
|
1
by brian
clean slate |
9125 |
few most significant keyparts in the range key. However if there
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
9126 |
are more keyparts to follow the ones we are using we must make the
|
9127 |
condition on the key inclusive (because x < "ab" means
|
|
1
by brian
clean slate |
9128 |
x[0] < 'a' OR (x[0] == 'a' AND x[1] < 'b').
|
9129 |
To achive the above we must turn off the NEAR_MIN/NEAR_MAX
|
|
9130 |
*/
|
|
9131 |
void QUICK_GROUP_MIN_MAX_SELECT::adjust_prefix_ranges () |
|
9132 |
{
|
|
9133 |
if (quick_prefix_select && |
|
9134 |
group_prefix_len < quick_prefix_select->max_used_key_length) |
|
9135 |
{
|
|
9136 |
DYNAMIC_ARRAY *arr; |
|
482
by Brian Aker
Remove uint. |
9137 |
uint32_t inx; |
1
by brian
clean slate |
9138 |
|
9139 |
for (inx= 0, arr= &quick_prefix_select->ranges; inx < arr->elements; inx++) |
|
9140 |
{
|
|
9141 |
QUICK_RANGE *range; |
|
9142 |
||
481
by Brian Aker
Remove all of uchar. |
9143 |
get_dynamic(arr, (unsigned char*)&range, inx); |
1
by brian
clean slate |
9144 |
range->flag &= ~(NEAR_MIN | NEAR_MAX); |
9145 |
}
|
|
9146 |
}
|
|
9147 |
}
|
|
9148 |
||
9149 |
||
9150 |
/*
|
|
9151 |
Determine the total number and length of the keys that will be used for
|
|
9152 |
index lookup.
|
|
9153 |
||
9154 |
SYNOPSIS
|
|
9155 |
QUICK_GROUP_MIN_MAX_SELECT::update_key_stat()
|
|
9156 |
||
9157 |
DESCRIPTION
|
|
9158 |
The total length of the keys used for index lookup depends on whether
|
|
9159 |
there are any predicates referencing the min/max argument, and/or if
|
|
9160 |
the min/max argument field can be NULL.
|
|
9161 |
This function does an optimistic analysis whether the search key might
|
|
9162 |
be extended by a constant for the min/max keypart. It is 'optimistic'
|
|
9163 |
because during actual execution it may happen that a particular range
|
|
9164 |
is skipped, and then a shorter key will be used. However this is data
|
|
9165 |
dependent and can't be easily estimated here.
|
|
9166 |
||
9167 |
RETURN
|
|
9168 |
None
|
|
9169 |
*/
|
|
9170 |
||
9171 |
void QUICK_GROUP_MIN_MAX_SELECT::update_key_stat() |
|
9172 |
{
|
|
9173 |
max_used_key_length= real_prefix_len; |
|
9174 |
if (min_max_ranges.elements > 0) |
|
9175 |
{
|
|
9176 |
QUICK_RANGE *cur_range; |
|
9177 |
if (have_min) |
|
9178 |
{ /* Check if the right-most range has a lower boundary. */ |
|
481
by Brian Aker
Remove all of uchar. |
9179 |
get_dynamic(&min_max_ranges, (unsigned char*)&cur_range, |
1
by brian
clean slate |
9180 |
min_max_ranges.elements - 1); |
9181 |
if (!(cur_range->flag & NO_MIN_RANGE)) |
|
9182 |
{
|
|
9183 |
max_used_key_length+= min_max_arg_len; |
|
9184 |
used_key_parts++; |
|
9185 |
return; |
|
9186 |
}
|
|
9187 |
}
|
|
9188 |
if (have_max) |
|
9189 |
{ /* Check if the left-most range has an upper boundary. */ |
|
481
by Brian Aker
Remove all of uchar. |
9190 |
get_dynamic(&min_max_ranges, (unsigned char*)&cur_range, 0); |
1
by brian
clean slate |
9191 |
if (!(cur_range->flag & NO_MAX_RANGE)) |
9192 |
{
|
|
9193 |
max_used_key_length+= min_max_arg_len; |
|
9194 |
used_key_parts++; |
|
9195 |
return; |
|
9196 |
}
|
|
9197 |
}
|
|
9198 |
}
|
|
9199 |
else if (have_min && min_max_arg_part && |
|
9200 |
min_max_arg_part->field->real_maybe_null()) |
|
9201 |
{
|
|
9202 |
/*
|
|
9203 |
If a MIN/MAX argument value is NULL, we can quickly determine
|
|
9204 |
that we're in the beginning of the next group, because NULLs
|
|
9205 |
are always < any other value. This allows us to quickly
|
|
9206 |
determine the end of the current group and jump to the next
|
|
9207 |
group (see next_min()) and thus effectively increases the
|
|
9208 |
usable key length.
|
|
9209 |
*/
|
|
9210 |
max_used_key_length+= min_max_arg_len; |
|
9211 |
used_key_parts++; |
|
9212 |
}
|
|
9213 |
}
|
|
9214 |
||
9215 |
||
9216 |
/*
|
|
9217 |
Initialize a quick group min/max select for key retrieval.
|
|
9218 |
||
9219 |
SYNOPSIS
|
|
9220 |
QUICK_GROUP_MIN_MAX_SELECT::reset()
|
|
9221 |
||
9222 |
DESCRIPTION
|
|
9223 |
Initialize the index chosen for access and find and store the prefix
|
|
9224 |
of the last group. The method is expensive since it performs disk access.
|
|
9225 |
||
9226 |
RETURN
|
|
9227 |
0 OK
|
|
9228 |
other Error code
|
|
9229 |
*/
|
|
9230 |
||
9231 |
int QUICK_GROUP_MIN_MAX_SELECT::reset(void) |
|
9232 |
{
|
|
9233 |
int result; |
|
9234 |
||
9235 |
file->extra(HA_EXTRA_KEYREAD); /* We need only the key attributes */ |
|
9236 |
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 |
9237 |
return result; |
1
by brian
clean slate |
9238 |
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 |
9239 |
return 0; |
1
by brian
clean slate |
9240 |
result= file->index_last(record); |
9241 |
if (result == HA_ERR_END_OF_FILE) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9242 |
return 0; |
1
by brian
clean slate |
9243 |
/* Save the prefix of the last group. */
|
9244 |
key_copy(last_prefix, record, index_info, group_prefix_len); |
|
9245 |
||
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9246 |
return 0; |
1
by brian
clean slate |
9247 |
}
|
9248 |
||
9249 |
||
9250 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
9251 |
/*
|
1
by brian
clean slate |
9252 |
Get the next key containing the MIN and/or MAX key for the next group.
|
9253 |
||
9254 |
SYNOPSIS
|
|
9255 |
QUICK_GROUP_MIN_MAX_SELECT::get_next()
|
|
9256 |
||
9257 |
DESCRIPTION
|
|
9258 |
The method finds the next subsequent group of records that satisfies the
|
|
9259 |
query conditions and finds the keys that contain the MIN/MAX values for
|
|
9260 |
the key part referenced by the MIN/MAX function(s). Once a group and its
|
|
9261 |
MIN/MAX values are found, store these values in the Item_sum objects for
|
|
9262 |
the MIN/MAX functions. The rest of the values in the result row are stored
|
|
9263 |
in the Item_field::result_field of each select field. If the query does
|
|
9264 |
not contain MIN and/or MAX functions, then the function only finds the
|
|
9265 |
group prefix, which is a query answer itself.
|
|
9266 |
||
9267 |
NOTES
|
|
9268 |
If both MIN and MAX are computed, then we use the fact that if there is
|
|
9269 |
no MIN key, there can't be a MAX key as well, so we can skip looking
|
|
9270 |
for a MAX key in this case.
|
|
9271 |
||
9272 |
RETURN
|
|
9273 |
0 on success
|
|
9274 |
HA_ERR_END_OF_FILE if returned all keys
|
|
9275 |
other if some error occurred
|
|
9276 |
*/
|
|
9277 |
||
9278 |
int QUICK_GROUP_MIN_MAX_SELECT::get_next() |
|
9279 |
{
|
|
9280 |
int min_res= 0; |
|
9281 |
int max_res= 0; |
|
9282 |
int result; |
|
9283 |
int is_last_prefix= 0; |
|
9284 |
||
9285 |
/*
|
|
9286 |
Loop until a group is found that satisfies all query conditions or the last
|
|
9287 |
group is reached.
|
|
9288 |
*/
|
|
9289 |
do
|
|
9290 |
{
|
|
9291 |
result= next_prefix(); |
|
9292 |
/*
|
|
9293 |
Check if this is the last group prefix. Notice that at this point
|
|
9294 |
this->record contains the current prefix in record format.
|
|
9295 |
*/
|
|
9296 |
if (!result) |
|
9297 |
{
|
|
9298 |
is_last_prefix= key_cmp(index_info->key_part, last_prefix, |
|
9299 |
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. |
9300 |
assert(is_last_prefix <= 0); |
1
by brian
clean slate |
9301 |
}
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
9302 |
else
|
1
by brian
clean slate |
9303 |
{
|
9304 |
if (result == HA_ERR_KEY_NOT_FOUND) |
|
9305 |
continue; |
|
9306 |
break; |
|
9307 |
}
|
|
9308 |
||
9309 |
if (have_min) |
|
9310 |
{
|
|
9311 |
min_res= next_min(); |
|
9312 |
if (min_res == 0) |
|
9313 |
update_min_result(); |
|
9314 |
}
|
|
9315 |
/* If there is no MIN in the group, there is no MAX either. */
|
|
9316 |
if ((have_max && !have_min) || |
|
9317 |
(have_max && have_min && (min_res == 0))) |
|
9318 |
{
|
|
9319 |
max_res= next_max(); |
|
9320 |
if (max_res == 0) |
|
9321 |
update_max_result(); |
|
9322 |
/* 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 |
9323 |
assert(((have_max && !have_min) || |
9324 |
(have_max && have_min && (max_res == 0)))); |
|
1
by brian
clean slate |
9325 |
}
|
9326 |
/*
|
|
9327 |
If this is just a GROUP BY or DISTINCT without MIN or MAX and there
|
|
9328 |
are equality predicates for the key parts after the group, find the
|
|
9329 |
first sub-group with the extended prefix.
|
|
9330 |
*/
|
|
9331 |
if (!have_min && !have_max && key_infix_len > 0) |
|
9332 |
result= file->index_read_map(record, group_prefix, |
|
9333 |
make_prev_keypart_map(real_key_parts), |
|
9334 |
HA_READ_KEY_EXACT); |
|
9335 |
||
9336 |
result= have_min ? min_res : have_max ? max_res : result; |
|
9337 |
} while ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) && |
|
9338 |
is_last_prefix != 0); |
|
9339 |
||
9340 |
if (result == 0) |
|
9341 |
{
|
|
9342 |
/*
|
|
9343 |
Partially mimic the behavior of end_select_send. Copy the
|
|
9344 |
field data from Item_field::field into Item_field::result_field
|
|
9345 |
of each non-aggregated field (the group fields, and optionally
|
|
9346 |
other fields in non-ANSI SQL mode).
|
|
9347 |
*/
|
|
9348 |
copy_fields(&join->tmp_table_param); |
|
9349 |
}
|
|
9350 |
else if (result == HA_ERR_KEY_NOT_FOUND) |
|
9351 |
result= HA_ERR_END_OF_FILE; |
|
9352 |
||
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9353 |
return result; |
1
by brian
clean slate |
9354 |
}
|
9355 |
||
9356 |
||
9357 |
/*
|
|
9358 |
Retrieve the minimal key in the next group.
|
|
9359 |
||
9360 |
SYNOPSIS
|
|
9361 |
QUICK_GROUP_MIN_MAX_SELECT::next_min()
|
|
9362 |
||
9363 |
DESCRIPTION
|
|
9364 |
Find the minimal key within this group such that the key satisfies the query
|
|
9365 |
conditions and NULL semantics. The found key is loaded into this->record.
|
|
9366 |
||
9367 |
IMPLEMENTATION
|
|
9368 |
Depending on the values of min_max_ranges.elements, key_infix_len, and
|
|
9369 |
whether there is a NULL in the MIN field, this function may directly
|
|
9370 |
return without any data access. In this case we use the key loaded into
|
|
9371 |
this->record by the call to this->next_prefix() just before this call.
|
|
9372 |
||
9373 |
RETURN
|
|
9374 |
0 on success
|
|
9375 |
HA_ERR_KEY_NOT_FOUND if no MIN key was found that fulfills all conditions.
|
|
9376 |
HA_ERR_END_OF_FILE - "" -
|
|
9377 |
other if some error occurred
|
|
9378 |
*/
|
|
9379 |
||
9380 |
int QUICK_GROUP_MIN_MAX_SELECT::next_min() |
|
9381 |
{
|
|
9382 |
int result= 0; |
|
9383 |
||
9384 |
/* Find the MIN key using the eventually extended group prefix. */
|
|
9385 |
if (min_max_ranges.elements > 0) |
|
9386 |
{
|
|
9387 |
if ((result= next_min_in_range())) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9388 |
return result; |
1
by brian
clean slate |
9389 |
}
|
9390 |
else
|
|
9391 |
{
|
|
9392 |
/* Apply the constant equality conditions to the non-group select fields */
|
|
9393 |
if (key_infix_len > 0) |
|
9394 |
{
|
|
9395 |
if ((result= file->index_read_map(record, group_prefix, |
|
9396 |
make_prev_keypart_map(real_key_parts), |
|
9397 |
HA_READ_KEY_EXACT))) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9398 |
return result; |
1
by brian
clean slate |
9399 |
}
|
9400 |
||
9401 |
/*
|
|
9402 |
If the min/max argument field is NULL, skip subsequent rows in the same
|
|
9403 |
group with NULL in it. Notice that:
|
|
9404 |
- if the first row in a group doesn't have a NULL in the field, no row
|
|
9405 |
in the same group has (because NULL < any other value),
|
|
9406 |
- min_max_arg_part->field->ptr points to some place in 'record'.
|
|
9407 |
*/
|
|
9408 |
if (min_max_arg_part && min_max_arg_part->field->is_null()) |
|
9409 |
{
|
|
9410 |
/* Find the first subsequent record without NULL in the MIN/MAX field. */
|
|
9411 |
key_copy(tmp_record, record, index_info, 0); |
|
9412 |
result= file->index_read_map(record, tmp_record, |
|
9413 |
make_keypart_map(real_key_parts), |
|
9414 |
HA_READ_AFTER_KEY); |
|
9415 |
/*
|
|
9416 |
Check if the new record belongs to the current group by comparing its
|
|
9417 |
prefix with the group's prefix. If it is from the next group, then the
|
|
9418 |
whole group has NULLs in the MIN/MAX field, so use the first record in
|
|
9419 |
the group as a result.
|
|
9420 |
TODO:
|
|
9421 |
It is possible to reuse this new record as the result candidate for the
|
|
9422 |
next call to next_min(), and to save one lookup in the next call. For
|
|
9423 |
this add a new member 'this->next_group_prefix'.
|
|
9424 |
*/
|
|
9425 |
if (!result) |
|
9426 |
{
|
|
9427 |
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len)) |
|
9428 |
key_restore(record, tmp_record, index_info, 0); |
|
9429 |
}
|
|
9430 |
else if (result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) |
|
9431 |
result= 0; /* There is a result in any case. */ |
|
9432 |
}
|
|
9433 |
}
|
|
9434 |
||
9435 |
/*
|
|
9436 |
If the MIN attribute is non-nullable, this->record already contains the
|
|
9437 |
MIN key in the group, so just return.
|
|
9438 |
*/
|
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9439 |
return result; |
1
by brian
clean slate |
9440 |
}
|
9441 |
||
9442 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
9443 |
/*
|
1
by brian
clean slate |
9444 |
Retrieve the maximal key in the next group.
|
9445 |
||
9446 |
SYNOPSIS
|
|
9447 |
QUICK_GROUP_MIN_MAX_SELECT::next_max()
|
|
9448 |
||
9449 |
DESCRIPTION
|
|
9450 |
Lookup the maximal key of the group, and store it into this->record.
|
|
9451 |
||
9452 |
RETURN
|
|
9453 |
0 on success
|
|
9454 |
HA_ERR_KEY_NOT_FOUND if no MAX key was found that fulfills all conditions.
|
|
9455 |
HA_ERR_END_OF_FILE - "" -
|
|
9456 |
other if some error occurred
|
|
9457 |
*/
|
|
9458 |
||
9459 |
int QUICK_GROUP_MIN_MAX_SELECT::next_max() |
|
9460 |
{
|
|
9461 |
int result; |
|
9462 |
||
9463 |
/* Get the last key in the (possibly extended) group. */
|
|
9464 |
if (min_max_ranges.elements > 0) |
|
9465 |
result= next_max_in_range(); |
|
9466 |
else
|
|
9467 |
result= file->index_read_map(record, group_prefix, |
|
9468 |
make_prev_keypart_map(real_key_parts), |
|
9469 |
HA_READ_PREFIX_LAST); |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9470 |
return result; |
1
by brian
clean slate |
9471 |
}
|
9472 |
||
9473 |
||
9474 |
/*
|
|
9475 |
Determine the prefix of the next group.
|
|
9476 |
||
9477 |
SYNOPSIS
|
|
9478 |
QUICK_GROUP_MIN_MAX_SELECT::next_prefix()
|
|
9479 |
||
9480 |
DESCRIPTION
|
|
9481 |
Determine the prefix of the next group that satisfies the query conditions.
|
|
9482 |
If there is a range condition referencing the group attributes, use a
|
|
9483 |
QUICK_RANGE_SELECT object to retrieve the *first* key that satisfies the
|
|
9484 |
condition. If there is a key infix of constants, append this infix
|
|
9485 |
immediately after the group attributes. The possibly extended prefix is
|
|
9486 |
stored in this->group_prefix. The first key of the found group is stored in
|
|
9487 |
this->record, on which relies this->next_min().
|
|
9488 |
||
9489 |
RETURN
|
|
9490 |
0 on success
|
|
9491 |
HA_ERR_KEY_NOT_FOUND if there is no key with the formed prefix
|
|
9492 |
HA_ERR_END_OF_FILE if there are no more keys
|
|
9493 |
other if some error occurred
|
|
9494 |
*/
|
|
9495 |
int QUICK_GROUP_MIN_MAX_SELECT::next_prefix() |
|
9496 |
{
|
|
9497 |
int result; |
|
9498 |
||
9499 |
if (quick_prefix_select) |
|
9500 |
{
|
|
481
by Brian Aker
Remove all of uchar. |
9501 |
unsigned char *cur_prefix= seen_first_key ? group_prefix : NULL; |
1
by brian
clean slate |
9502 |
if ((result= quick_prefix_select->get_next_prefix(group_prefix_len, |
9503 |
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 |
9504 |
return result; |
55
by brian
Update for using real bool types. |
9505 |
seen_first_key= true; |
1
by brian
clean slate |
9506 |
}
|
9507 |
else
|
|
9508 |
{
|
|
9509 |
if (!seen_first_key) |
|
9510 |
{
|
|
9511 |
result= file->index_first(record); |
|
9512 |
if (result) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9513 |
return result; |
55
by brian
Update for using real bool types. |
9514 |
seen_first_key= true; |
1
by brian
clean slate |
9515 |
}
|
9516 |
else
|
|
9517 |
{
|
|
9518 |
/* Load the first key in this group into record. */
|
|
9519 |
result= file->index_read_map(record, group_prefix, |
|
9520 |
make_prev_keypart_map(group_key_parts), |
|
9521 |
HA_READ_AFTER_KEY); |
|
9522 |
if (result) |
|
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9523 |
return result; |
1
by brian
clean slate |
9524 |
}
|
9525 |
}
|
|
9526 |
||
9527 |
/* Save the prefix of this group for subsequent calls. */
|
|
9528 |
key_copy(group_prefix, record, index_info, group_prefix_len); |
|
9529 |
/* Append key_infix to group_prefix. */
|
|
9530 |
if (key_infix_len > 0) |
|
9531 |
memcpy(group_prefix + group_prefix_len, |
|
9532 |
key_infix, key_infix_len); |
|
9533 |
||
723
by Brian Aker
Fix for group_min_max test (aka... use MyISAM... need to further test |
9534 |
return 0; |
1
by brian
clean slate |
9535 |
}
|
9536 |
||
9537 |
||
9538 |
/*
|
|
9539 |
Find the minimal key in a group that satisfies some range conditions for the
|
|
9540 |
min/max argument field.
|
|
9541 |
||
9542 |
SYNOPSIS
|
|
9543 |
QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range()
|
|
9544 |
||
9545 |
DESCRIPTION
|
|
9546 |
Given the sequence of ranges min_max_ranges, find the minimal key that is
|
|
9547 |
in the left-most possible range. If there is no such key, then the current
|
|
9548 |
group does not have a MIN key that satisfies the WHERE clause. If a key is
|
|
9549 |
found, its value is stored in this->record.
|
|
9550 |
||
9551 |
RETURN
|
|
9552 |
0 on success
|
|
9553 |
HA_ERR_KEY_NOT_FOUND if there is no key with the given prefix in any of
|
|
9554 |
the ranges
|
|
9555 |
HA_ERR_END_OF_FILE - "" -
|
|
9556 |
other if some error
|
|
9557 |
*/
|
|
9558 |
||
9559 |
int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range() |
|
9560 |
{
|
|
9561 |
ha_rkey_function find_flag; |
|
9562 |
key_part_map keypart_map; |
|
9563 |
QUICK_RANGE *cur_range; |
|
55
by brian
Update for using real bool types. |
9564 |
bool found_null= false; |
1
by brian
clean slate |
9565 |
int result= HA_ERR_KEY_NOT_FOUND; |
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
9566 |
basic_string<unsigned char> max_key; |
660.1.6
by Eric Herman
trailing whitespace fixup |
9567 |
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
9568 |
max_key.reserve(real_prefix_len + min_max_arg_len); |
1
by brian
clean slate |
9569 |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9570 |
assert(min_max_ranges.elements > 0); |
1
by brian
clean slate |
9571 |
|
482
by Brian Aker
Remove uint. |
9572 |
for (uint32_t range_idx= 0; range_idx < min_max_ranges.elements; range_idx++) |
1
by brian
clean slate |
9573 |
{ /* Search from the left-most range to the right. */ |
481
by Brian Aker
Remove all of uchar. |
9574 |
get_dynamic(&min_max_ranges, (unsigned char*)&cur_range, range_idx); |
1
by brian
clean slate |
9575 |
|
9576 |
/*
|
|
9577 |
If the current value for the min/max argument is bigger than the right
|
|
9578 |
boundary of cur_range, there is no need to check this range.
|
|
9579 |
*/
|
|
9580 |
if (range_idx != 0 && !(cur_range->flag & NO_MAX_RANGE) && |
|
481
by Brian Aker
Remove all of uchar. |
9581 |
(key_cmp(min_max_arg_part, (const unsigned char*) cur_range->max_key, |
1
by brian
clean slate |
9582 |
min_max_arg_len) == 1)) |
9583 |
continue; |
|
9584 |
||
9585 |
if (cur_range->flag & NO_MIN_RANGE) |
|
9586 |
{
|
|
9587 |
keypart_map= make_prev_keypart_map(real_key_parts); |
|
9588 |
find_flag= HA_READ_KEY_EXACT; |
|
9589 |
}
|
|
9590 |
else
|
|
9591 |
{
|
|
9592 |
/* Extend the search key with the lower boundary for this range. */
|
|
9593 |
memcpy(group_prefix + real_prefix_len, cur_range->min_key, |
|
9594 |
cur_range->min_length); |
|
9595 |
keypart_map= make_keypart_map(real_key_parts); |
|
9596 |
find_flag= (cur_range->flag & (EQ_RANGE | NULL_RANGE)) ? |
|
9597 |
HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MIN) ? |
|
9598 |
HA_READ_AFTER_KEY : HA_READ_KEY_OR_NEXT; |
|
9599 |
}
|
|
9600 |
||
9601 |
result= file->index_read_map(record, group_prefix, keypart_map, find_flag); |
|
9602 |
if (result) |
|
9603 |
{
|
|
9604 |
if ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) && |
|
9605 |
(cur_range->flag & (EQ_RANGE | NULL_RANGE))) |
|
9606 |
continue; /* Check the next range. */ |
|
9607 |
||
9608 |
/*
|
|
9609 |
In all other cases (HA_ERR_*, HA_READ_KEY_EXACT with NO_MIN_RANGE,
|
|
9610 |
HA_READ_AFTER_KEY, HA_READ_KEY_OR_NEXT) if the lookup failed for this
|
|
9611 |
range, it can't succeed for any other subsequent range.
|
|
9612 |
*/
|
|
9613 |
break; |
|
9614 |
}
|
|
9615 |
||
9616 |
/* A key was found. */
|
|
9617 |
if (cur_range->flag & EQ_RANGE) |
|
9618 |
break; /* No need to perform the checks below for equal keys. */ |
|
9619 |
||
9620 |
if (cur_range->flag & NULL_RANGE) |
|
9621 |
{
|
|
9622 |
/*
|
|
9623 |
Remember this key, and continue looking for a non-NULL key that
|
|
9624 |
satisfies some other condition.
|
|
9625 |
*/
|
|
9626 |
memcpy(tmp_record, record, head->s->rec_buff_length); |
|
55
by brian
Update for using real bool types. |
9627 |
found_null= true; |
1
by brian
clean slate |
9628 |
continue; |
9629 |
}
|
|
9630 |
||
9631 |
/* Check if record belongs to the current group. */
|
|
9632 |
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len)) |
|
9633 |
{
|
|
9634 |
result= HA_ERR_KEY_NOT_FOUND; |
|
9635 |
continue; |
|
9636 |
}
|
|
9637 |
||
9638 |
/* If there is an upper limit, check if the found key is in the range. */
|
|
9639 |
if ( !(cur_range->flag & NO_MAX_RANGE) ) |
|
9640 |
{
|
|
9641 |
/* Compose the MAX key for the range. */
|
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
9642 |
max_key.clear(); |
9643 |
max_key.append(group_prefix, real_prefix_len); |
|
9644 |
max_key.append(cur_range->max_key, cur_range->max_length); |
|
1
by brian
clean slate |
9645 |
/* Compare the found key with max_key. */
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
9646 |
int cmp_res= key_cmp(index_info->key_part, |
9647 |
max_key.data(), |
|
1
by brian
clean slate |
9648 |
real_prefix_len + min_max_arg_len); |
9649 |
if ((!((cur_range->flag & NEAR_MAX) && (cmp_res == -1)) || (cmp_res <= 0))) |
|
9650 |
{
|
|
9651 |
result= HA_ERR_KEY_NOT_FOUND; |
|
9652 |
continue; |
|
9653 |
}
|
|
9654 |
}
|
|
9655 |
/* 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. |
9656 |
assert(result == 0); |
1
by brian
clean slate |
9657 |
break; |
9658 |
}
|
|
9659 |
/*
|
|
9660 |
If there was a key with NULL in the MIN/MAX field, and there was no other
|
|
9661 |
key without NULL from the same group that satisfies some other condition,
|
|
9662 |
then use the key with the NULL.
|
|
9663 |
*/
|
|
9664 |
if (found_null && result) |
|
9665 |
{
|
|
9666 |
memcpy(record, tmp_record, head->s->rec_buff_length); |
|
9667 |
result= 0; |
|
9668 |
}
|
|
9669 |
return result; |
|
9670 |
}
|
|
9671 |
||
9672 |
||
9673 |
/*
|
|
9674 |
Find the maximal key in a group that satisfies some range conditions for the
|
|
9675 |
min/max argument field.
|
|
9676 |
||
9677 |
SYNOPSIS
|
|
9678 |
QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range()
|
|
9679 |
||
9680 |
DESCRIPTION
|
|
9681 |
Given the sequence of ranges min_max_ranges, find the maximal key that is
|
|
9682 |
in the right-most possible range. If there is no such key, then the current
|
|
9683 |
group does not have a MAX key that satisfies the WHERE clause. If a key is
|
|
9684 |
found, its value is stored in this->record.
|
|
9685 |
||
9686 |
RETURN
|
|
9687 |
0 on success
|
|
9688 |
HA_ERR_KEY_NOT_FOUND if there is no key with the given prefix in any of
|
|
9689 |
the ranges
|
|
9690 |
HA_ERR_END_OF_FILE - "" -
|
|
9691 |
other if some error
|
|
9692 |
*/
|
|
9693 |
||
9694 |
int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range() |
|
9695 |
{
|
|
9696 |
ha_rkey_function find_flag; |
|
9697 |
key_part_map keypart_map; |
|
9698 |
QUICK_RANGE *cur_range; |
|
9699 |
int result; |
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
9700 |
basic_string<unsigned char> min_key; |
9701 |
min_key.reserve(real_prefix_len + min_max_arg_len); |
|
1
by brian
clean slate |
9702 |
|
51.1.11
by Jay Pipes
Removed/replaced all DBUG_XXX statements, all conditional compilation directives for DBUG_OFF, but kept in the optimizer's custom debugging print code for now. |
9703 |
assert(min_max_ranges.elements > 0); |
1
by brian
clean slate |
9704 |
|
482
by Brian Aker
Remove uint. |
9705 |
for (uint32_t range_idx= min_max_ranges.elements; range_idx > 0; range_idx--) |
1
by brian
clean slate |
9706 |
{ /* Search from the right-most range to the left. */ |
481
by Brian Aker
Remove all of uchar. |
9707 |
get_dynamic(&min_max_ranges, (unsigned char*)&cur_range, range_idx - 1); |
1
by brian
clean slate |
9708 |
|
9709 |
/*
|
|
9710 |
If the current value for the min/max argument is smaller than the left
|
|
9711 |
boundary of cur_range, there is no need to check this range.
|
|
9712 |
*/
|
|
9713 |
if (range_idx != min_max_ranges.elements && |
|
9714 |
!(cur_range->flag & NO_MIN_RANGE) && |
|
481
by Brian Aker
Remove all of uchar. |
9715 |
(key_cmp(min_max_arg_part, (const unsigned char*) cur_range->min_key, |
1
by brian
clean slate |
9716 |
min_max_arg_len) == -1)) |
9717 |
continue; |
|
9718 |
||
9719 |
if (cur_range->flag & NO_MAX_RANGE) |
|
9720 |
{
|
|
9721 |
keypart_map= make_prev_keypart_map(real_key_parts); |
|
9722 |
find_flag= HA_READ_PREFIX_LAST; |
|
9723 |
}
|
|
9724 |
else
|
|
9725 |
{
|
|
9726 |
/* Extend the search key with the upper boundary for this range. */
|
|
9727 |
memcpy(group_prefix + real_prefix_len, cur_range->max_key, |
|
9728 |
cur_range->max_length); |
|
9729 |
keypart_map= make_keypart_map(real_key_parts); |
|
9730 |
find_flag= (cur_range->flag & EQ_RANGE) ? |
|
9731 |
HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MAX) ? |
|
9732 |
HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV; |
|
9733 |
}
|
|
9734 |
||
9735 |
result= file->index_read_map(record, group_prefix, keypart_map, find_flag); |
|
9736 |
||
9737 |
if (result) |
|
9738 |
{
|
|
9739 |
if ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) && |
|
9740 |
(cur_range->flag & EQ_RANGE)) |
|
9741 |
continue; /* Check the next range. */ |
|
9742 |
||
9743 |
/*
|
|
9744 |
In no key was found with this upper bound, there certainly are no keys
|
|
9745 |
in the ranges to the left.
|
|
9746 |
*/
|
|
9747 |
return result; |
|
9748 |
}
|
|
9749 |
/* A key was found. */
|
|
9750 |
if (cur_range->flag & EQ_RANGE) |
|
9751 |
return 0; /* No need to perform the checks below for equal keys. */ |
|
9752 |
||
9753 |
/* Check if record belongs to the current group. */
|
|
9754 |
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len)) |
|
9755 |
continue; // Row not found |
|
9756 |
||
9757 |
/* If there is a lower limit, check if the found key is in the range. */
|
|
9758 |
if ( !(cur_range->flag & NO_MIN_RANGE) ) |
|
9759 |
{
|
|
9760 |
/* Compose the MIN key for the range. */
|
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
9761 |
min_key.clear(); |
9762 |
min_key.append(group_prefix, real_prefix_len); |
|
9763 |
min_key.append(cur_range->min_key, cur_range->min_length); |
|
9764 |
||
1
by brian
clean slate |
9765 |
/* Compare the found key with min_key. */
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
9766 |
int cmp_res= key_cmp(index_info->key_part, |
9767 |
min_key.data(), |
|
1
by brian
clean slate |
9768 |
real_prefix_len + min_max_arg_len); |
9769 |
if ((!((cur_range->flag & NEAR_MIN) && (cmp_res == 1)) || |
|
9770 |
(cmp_res >= 0))) |
|
9771 |
continue; |
|
9772 |
}
|
|
9773 |
/* If we got to this point, the current key qualifies as MAX. */
|
|
9774 |
return result; |
|
9775 |
}
|
|
9776 |
return HA_ERR_KEY_NOT_FOUND; |
|
9777 |
}
|
|
9778 |
||
9779 |
||
9780 |
/*
|
|
9781 |
Update all MIN function results with the newly found value.
|
|
9782 |
||
9783 |
SYNOPSIS
|
|
9784 |
QUICK_GROUP_MIN_MAX_SELECT::update_min_result()
|
|
9785 |
||
9786 |
DESCRIPTION
|
|
9787 |
The method iterates through all MIN functions and updates the result value
|
|
9788 |
of each function by calling Item_sum::reset(), which in turn picks the new
|
|
9789 |
result value from this->head->record[0], previously updated by
|
|
9790 |
next_min(). The updated value is stored in a member variable of each of the
|
|
9791 |
Item_sum objects, depending on the value type.
|
|
9792 |
||
9793 |
IMPLEMENTATION
|
|
9794 |
The update must be done separately for MIN and MAX, immediately after
|
|
9795 |
next_min() was called and before next_max() is called, because both MIN and
|
|
9796 |
MAX take their result value from the same buffer this->head->record[0]
|
|
9797 |
(i.e. this->record).
|
|
9798 |
||
9799 |
RETURN
|
|
9800 |
None
|
|
9801 |
*/
|
|
9802 |
||
9803 |
void QUICK_GROUP_MIN_MAX_SELECT::update_min_result() |
|
9804 |
{
|
|
9805 |
Item_sum *min_func; |
|
9806 |
||
9807 |
min_functions_it->rewind(); |
|
9808 |
while ((min_func= (*min_functions_it)++)) |
|
9809 |
min_func->reset(); |
|
9810 |
}
|
|
9811 |
||
9812 |
||
9813 |
/*
|
|
9814 |
Update all MAX function results with the newly found value.
|
|
9815 |
||
9816 |
SYNOPSIS
|
|
9817 |
QUICK_GROUP_MIN_MAX_SELECT::update_max_result()
|
|
9818 |
||
9819 |
DESCRIPTION
|
|
9820 |
The method iterates through all MAX functions and updates the result value
|
|
9821 |
of each function by calling Item_sum::reset(), which in turn picks the new
|
|
9822 |
result value from this->head->record[0], previously updated by
|
|
9823 |
next_max(). The updated value is stored in a member variable of each of the
|
|
9824 |
Item_sum objects, depending on the value type.
|
|
9825 |
||
9826 |
IMPLEMENTATION
|
|
9827 |
The update must be done separately for MIN and MAX, immediately after
|
|
9828 |
next_max() was called, because both MIN and MAX take their result value
|
|
9829 |
from the same buffer this->head->record[0] (i.e. this->record).
|
|
9830 |
||
9831 |
RETURN
|
|
9832 |
None
|
|
9833 |
*/
|
|
9834 |
||
9835 |
void QUICK_GROUP_MIN_MAX_SELECT::update_max_result() |
|
9836 |
{
|
|
9837 |
Item_sum *max_func; |
|
9838 |
||
9839 |
max_functions_it->rewind(); |
|
9840 |
while ((max_func= (*max_functions_it)++)) |
|
9841 |
max_func->reset(); |
|
9842 |
}
|
|
9843 |
||
9844 |
||
9845 |
/*
|
|
9846 |
Append comma-separated list of keys this quick select uses to key_names;
|
|
9847 |
append comma-separated list of corresponding used lengths to used_lengths.
|
|
9848 |
||
9849 |
SYNOPSIS
|
|
9850 |
QUICK_GROUP_MIN_MAX_SELECT::add_keys_and_lengths()
|
|
9851 |
key_names [out] Names of used indexes
|
|
9852 |
used_lengths [out] Corresponding lengths of the index names
|
|
9853 |
||
9854 |
DESCRIPTION
|
|
9855 |
This method is used by select_describe to extract the names of the
|
|
9856 |
indexes used by a quick select.
|
|
9857 |
||
9858 |
*/
|
|
9859 |
||
9860 |
void QUICK_GROUP_MIN_MAX_SELECT::add_keys_and_lengths(String *key_names, |
|
9861 |
String *used_lengths) |
|
9862 |
{
|
|
9863 |
char buf[64]; |
|
482
by Brian Aker
Remove uint. |
9864 |
uint32_t length; |
1
by brian
clean slate |
9865 |
key_names->append(index_info->name); |
152
by Brian Aker
longlong replacement |
9866 |
length= int64_t2str(max_used_key_length, buf, 10) - buf; |
1
by brian
clean slate |
9867 |
used_lengths->append(buf, length); |
9868 |
}
|
|
9869 |
||
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
9870 |
static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map, const char *) |
1
by brian
clean slate |
9871 |
{
|
9872 |
SEL_ARG **key,**end; |
|
9873 |
int idx; |
|
9874 |
char buff[1024]; |
|
9875 |
||
9876 |
String tmp(buff,sizeof(buff),&my_charset_bin); |
|
9877 |
tmp.length(0); |
|
9878 |
for (idx= 0,key=tree->keys, end=key+param->keys ; |
|
9879 |
key != end ; |
|
9880 |
key++,idx++) |
|
9881 |
{
|
|
1005.2.6
by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<> |
9882 |
if (tree_map->test(idx)) |
1
by brian
clean slate |
9883 |
{
|
482
by Brian Aker
Remove uint. |
9884 |
uint32_t keynr= param->real_keynr[idx]; |
1
by brian
clean slate |
9885 |
if (tmp.length()) |
9886 |
tmp.append(','); |
|
9887 |
tmp.append(param->table->key_info[keynr].name); |
|
9888 |
}
|
|
9889 |
}
|
|
9890 |
if (!tmp.length()) |
|
9891 |
tmp.append(STRING_WITH_LEN("(empty)")); |
|
9892 |
}
|
|
9893 |
||
9894 |
||
327.1.5
by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h |
9895 |
static void print_ror_scans_arr(Table *table, |
655
by Brian Aker
Yet more unused.... damn annoying... (also tossed some prototypes that were |
9896 |
const char *, struct st_ror_scan_info **start, |
1
by brian
clean slate |
9897 |
struct st_ror_scan_info **end) |
9898 |
{
|
|
9899 |
char buff[1024]; |
|
9900 |
String tmp(buff,sizeof(buff),&my_charset_bin); |
|
9901 |
tmp.length(0); |
|
9902 |
for (;start != end; start++) |
|
9903 |
{
|
|
9904 |
if (tmp.length()) |
|
9905 |
tmp.append(','); |
|
9906 |
tmp.append(table->key_info[(*start)->keynr].name); |
|
9907 |
}
|
|
9908 |
if (!tmp.length()) |
|
9909 |
tmp.append(STRING_WITH_LEN("(empty)")); |
|
9910 |
}
|
|
9911 |
||
9912 |
/*****************************************************************************
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
9913 |
** Instantiate templates
|
1
by brian
clean slate |
9914 |
*****************************************************************************/
|
9915 |
||
9916 |
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
|
|
9917 |
template class List<QUICK_RANGE>; |
|
9918 |
template class List_iterator<QUICK_RANGE>; |
|
9919 |
#endif
|