1237.13.20
by Padraig O'Sullivan
Forgot to include a copyright header in one of the new files I created. |
1 |
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
|
2 |
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
|
|
3 |
*
|
|
4 |
* Copyright (C) 2008-2009 Sun Microsystems
|
|
5 |
*
|
|
6 |
* This program is free software; you can redistribute it and/or modify
|
|
7 |
* it under the terms of the GNU General Public License as published by
|
|
8 |
* the Free Software Foundation; version 2 of the License.
|
|
9 |
*
|
|
10 |
* This program is distributed in the hope that it will be useful,
|
|
11 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13 |
* GNU General Public License for more details.
|
|
14 |
*
|
|
15 |
* You should have received a copy of the GNU General Public License
|
|
16 |
* along with this program; if not, write to the Free Software
|
|
17 |
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
18 |
*/
|
|
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
19 |
|
1241.9.36
by Monty Taylor
ZOMG. I deleted drizzled/server_includes.h. |
20 |
#include "config.h" |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
21 |
#include "drizzled/session.h" |
22 |
#include "drizzled/sql_select.h" |
|
23 |
#include "drizzled/join.h" |
|
24 |
#include "drizzled/optimizer/range.h" |
|
25 |
#include "drizzled/optimizer/quick_group_min_max_select.h" |
|
26 |
#include "drizzled/optimizer/quick_range.h" |
|
27 |
#include "drizzled/optimizer/quick_range_select.h" |
|
28 |
#include "drizzled/optimizer/sel_arg.h" |
|
1241.9.64
by Monty Taylor
Moved remaining non-public portions of mysys and mystrings to drizzled/internal. |
29 |
#include "drizzled/internal/m_string.h" |
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
30 |
#include "drizzled/util/functors.h" |
31 |
||
32 |
#include <vector> |
|
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
33 |
|
34 |
using namespace std; |
|
35 |
||
1280.1.10
by Monty Taylor
Put everything in drizzled into drizzled namespace. |
36 |
namespace drizzled |
37 |
{
|
|
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
38 |
|
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
39 |
optimizer::QuickGroupMinMaxSelect:: |
40 |
QuickGroupMinMaxSelect(Table *table, |
|
41 |
JOIN *join_arg, |
|
42 |
bool have_min_arg, |
|
43 |
bool have_max_arg, |
|
44 |
KEY_PART_INFO *min_max_arg_part_arg, |
|
45 |
uint32_t group_prefix_len_arg, |
|
46 |
uint32_t group_key_parts_arg, |
|
47 |
uint32_t used_key_parts_arg, |
|
48 |
KEY *index_info_arg, |
|
49 |
uint32_t use_index, |
|
50 |
double read_cost_arg, |
|
51 |
ha_rows records_arg, |
|
52 |
uint32_t key_infix_len_arg, |
|
53 |
unsigned char *key_infix_arg, |
|
1253.1.3
by Monty Taylor
MEM_ROOT == memory::Root |
54 |
memory::Root *parent_alloc) |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
55 |
:
|
56 |
join(join_arg), |
|
57 |
index_info(index_info_arg), |
|
58 |
group_prefix_len(group_prefix_len_arg), |
|
59 |
group_key_parts(group_key_parts_arg), |
|
60 |
have_min(have_min_arg), |
|
61 |
have_max(have_max_arg), |
|
62 |
seen_first_key(false), |
|
63 |
min_max_arg_part(min_max_arg_part_arg), |
|
64 |
key_infix(key_infix_arg), |
|
65 |
key_infix_len(key_infix_len_arg), |
|
66 |
min_functions_it(NULL), |
|
67 |
max_functions_it(NULL) |
|
68 |
{
|
|
69 |
head= table; |
|
70 |
cursor= head->cursor; |
|
71 |
index= use_index; |
|
72 |
record= head->record[0]; |
|
73 |
tmp_record= head->record[1]; |
|
74 |
read_time= read_cost_arg; |
|
75 |
records= records_arg; |
|
76 |
used_key_parts= used_key_parts_arg; |
|
77 |
real_key_parts= used_key_parts_arg; |
|
78 |
real_prefix_len= group_prefix_len + key_infix_len; |
|
79 |
group_prefix= NULL; |
|
80 |
min_max_arg_len= min_max_arg_part ? min_max_arg_part->store_length : 0; |
|
81 |
||
82 |
/*
|
|
83 |
We can't have parent_alloc set as the init function can't handle this case
|
|
84 |
yet.
|
|
85 |
*/
|
|
86 |
assert(! parent_alloc); |
|
87 |
if (! parent_alloc) |
|
88 |
{
|
|
1253.1.6
by Monty Taylor
Moved mem_root functions into drizzled::memory:: namespace. |
89 |
memory::init_sql_alloc(&alloc, join->session->variables.range_alloc_block_size, 0); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
90 |
join->session->mem_root= &alloc; |
91 |
}
|
|
92 |
else
|
|
1253.1.3
by Monty Taylor
MEM_ROOT == memory::Root |
93 |
memset(&alloc, 0, sizeof(memory::Root)); // ensure that it's not used |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
94 |
}
|
95 |
||
96 |
||
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
97 |
int optimizer::QuickGroupMinMaxSelect::init() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
98 |
{
|
99 |
if (group_prefix) /* Already initialized. */ |
|
100 |
return 0; |
|
101 |
||
102 |
if (! (last_prefix= (unsigned char*) alloc_root(&alloc, group_prefix_len))) |
|
103 |
return 1; |
|
104 |
/*
|
|
105 |
We may use group_prefix to store keys with all select fields, so allocate
|
|
106 |
enough space for it.
|
|
107 |
*/
|
|
108 |
if (! (group_prefix= (unsigned char*) alloc_root(&alloc, |
|
109 |
real_prefix_len + min_max_arg_len))) |
|
110 |
return 1; |
|
111 |
||
112 |
if (key_infix_len > 0) |
|
113 |
{
|
|
114 |
/*
|
|
115 |
The memory location pointed to by key_infix will be deleted soon, so
|
|
116 |
allocate a new buffer and copy the key_infix into it.
|
|
117 |
*/
|
|
118 |
unsigned char *tmp_key_infix= (unsigned char*) alloc_root(&alloc, key_infix_len); |
|
119 |
if (! tmp_key_infix) |
|
120 |
return 1; |
|
121 |
memcpy(tmp_key_infix, this->key_infix, key_infix_len); |
|
122 |
this->key_infix= tmp_key_infix; |
|
123 |
}
|
|
124 |
||
125 |
if (min_max_arg_part) |
|
126 |
{
|
|
127 |
if (have_min) |
|
128 |
{
|
|
129 |
if (! (min_functions= new List<Item_sum>)) |
|
130 |
return 1; |
|
131 |
}
|
|
132 |
else
|
|
133 |
min_functions= NULL; |
|
134 |
if (have_max) |
|
135 |
{
|
|
136 |
if (! (max_functions= new List<Item_sum>)) |
|
137 |
return 1; |
|
138 |
}
|
|
139 |
else
|
|
140 |
max_functions= NULL; |
|
141 |
||
142 |
Item_sum *min_max_item= NULL; |
|
143 |
Item_sum **func_ptr= join->sum_funcs; |
|
144 |
while ((min_max_item= *(func_ptr++))) |
|
145 |
{
|
|
146 |
if (have_min && (min_max_item->sum_func() == Item_sum::MIN_FUNC)) |
|
147 |
min_functions->push_back(min_max_item); |
|
148 |
else if (have_max && (min_max_item->sum_func() == Item_sum::MAX_FUNC)) |
|
149 |
max_functions->push_back(min_max_item); |
|
150 |
}
|
|
151 |
||
152 |
if (have_min) |
|
153 |
{
|
|
154 |
if (! (min_functions_it= new List_iterator<Item_sum>(*min_functions))) |
|
155 |
return 1; |
|
156 |
}
|
|
157 |
||
158 |
if (have_max) |
|
159 |
{
|
|
160 |
if (! (max_functions_it= new List_iterator<Item_sum>(*max_functions))) |
|
161 |
return 1; |
|
162 |
}
|
|
163 |
}
|
|
164 |
||
165 |
return 0; |
|
166 |
}
|
|
167 |
||
168 |
||
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
169 |
optimizer::QuickGroupMinMaxSelect::~QuickGroupMinMaxSelect() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
170 |
{
|
171 |
if (cursor->inited != Cursor::NONE) |
|
172 |
{
|
|
173 |
cursor->ha_index_end(); |
|
174 |
}
|
|
175 |
if (min_max_arg_part) |
|
176 |
{
|
|
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
177 |
for_each(min_max_ranges.begin(), |
178 |
min_max_ranges.end(), |
|
179 |
DeletePtr()); |
|
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
180 |
}
|
1237.13.31
by Padraig O'Sullivan
Minor revisions based on review comments from Jay. Thanks Jay! |
181 |
min_max_ranges.clear(); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
182 |
free_root(&alloc,MYF(0)); |
183 |
delete min_functions_it; |
|
184 |
delete max_functions_it; |
|
185 |
delete quick_prefix_select; |
|
186 |
}
|
|
187 |
||
188 |
||
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
189 |
bool optimizer::QuickGroupMinMaxSelect::add_range(optimizer::SEL_ARG *sel_range) |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
190 |
{
|
191 |
optimizer::QuickRange *range= NULL; |
|
192 |
uint32_t range_flag= sel_range->min_flag | sel_range->max_flag; |
|
193 |
||
194 |
/* Skip (-inf,+inf) ranges, e.g. (x < 5 or x > 4). */
|
|
195 |
if ((range_flag & NO_MIN_RANGE) && (range_flag & NO_MAX_RANGE)) |
|
196 |
return false; |
|
197 |
||
198 |
if (! (sel_range->min_flag & NO_MIN_RANGE) && |
|
199 |
! (sel_range->max_flag & NO_MAX_RANGE)) |
|
200 |
{
|
|
201 |
if (sel_range->maybe_null && |
|
202 |
sel_range->min_value[0] && sel_range->max_value[0]) |
|
203 |
range_flag|= NULL_RANGE; /* IS NULL condition */ |
|
204 |
else if (memcmp(sel_range->min_value, sel_range->max_value, |
|
205 |
min_max_arg_len) == 0) |
|
206 |
range_flag|= EQ_RANGE; /* equality condition */ |
|
207 |
}
|
|
208 |
range= new optimizer::QuickRange(sel_range->min_value, |
|
209 |
min_max_arg_len, |
|
210 |
make_keypart_map(sel_range->part), |
|
211 |
sel_range->max_value, |
|
212 |
min_max_arg_len, |
|
213 |
make_keypart_map(sel_range->part), |
|
214 |
range_flag); |
|
215 |
if (! range) |
|
216 |
return true; |
|
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
217 |
min_max_ranges.push_back(range); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
218 |
return false; |
219 |
}
|
|
220 |
||
221 |
||
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
222 |
void optimizer::QuickGroupMinMaxSelect::adjust_prefix_ranges() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
223 |
{
|
224 |
if (quick_prefix_select && |
|
225 |
group_prefix_len < quick_prefix_select->max_used_key_length) |
|
226 |
{
|
|
227 |
DYNAMIC_ARRAY *arr= NULL; |
|
228 |
uint32_t inx; |
|
229 |
||
230 |
for (inx= 0, arr= &quick_prefix_select->ranges; inx < arr->elements; inx++) |
|
231 |
{
|
|
232 |
optimizer::QuickRange *range= NULL; |
|
233 |
||
234 |
get_dynamic(arr, (unsigned char*)&range, inx); |
|
235 |
range->flag &= ~(NEAR_MIN | NEAR_MAX); |
|
236 |
}
|
|
237 |
}
|
|
238 |
}
|
|
239 |
||
240 |
||
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
241 |
void optimizer::QuickGroupMinMaxSelect::update_key_stat() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
242 |
{
|
243 |
max_used_key_length= real_prefix_len; |
|
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
244 |
if (! min_max_ranges.empty()) |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
245 |
{
|
246 |
optimizer::QuickRange *cur_range= NULL; |
|
247 |
if (have_min) |
|
248 |
{ /* Check if the right-most range has a lower boundary. */ |
|
1237.13.31
by Padraig O'Sullivan
Minor revisions based on review comments from Jay. Thanks Jay! |
249 |
cur_range= min_max_ranges.back(); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
250 |
if (! (cur_range->flag & NO_MIN_RANGE)) |
251 |
{
|
|
252 |
max_used_key_length+= min_max_arg_len; |
|
253 |
used_key_parts++; |
|
254 |
return; |
|
255 |
}
|
|
256 |
}
|
|
257 |
if (have_max) |
|
258 |
{ /* Check if the left-most range has an upper boundary. */ |
|
1237.13.31
by Padraig O'Sullivan
Minor revisions based on review comments from Jay. Thanks Jay! |
259 |
cur_range= min_max_ranges.front(); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
260 |
if (! (cur_range->flag & NO_MAX_RANGE)) |
261 |
{
|
|
262 |
max_used_key_length+= min_max_arg_len; |
|
263 |
used_key_parts++; |
|
264 |
return; |
|
265 |
}
|
|
266 |
}
|
|
267 |
}
|
|
268 |
else if (have_min && min_max_arg_part && |
|
269 |
min_max_arg_part->field->real_maybe_null()) |
|
270 |
{
|
|
271 |
/*
|
|
272 |
If a MIN/MAX argument value is NULL, we can quickly determine
|
|
273 |
that we're in the beginning of the next group, because NULLs
|
|
274 |
are always < any other value. This allows us to quickly
|
|
275 |
determine the end of the current group and jump to the next
|
|
276 |
group (see next_min()) and thus effectively increases the
|
|
277 |
usable key length.
|
|
278 |
*/
|
|
279 |
max_used_key_length+= min_max_arg_len; |
|
280 |
used_key_parts++; |
|
281 |
}
|
|
282 |
}
|
|
283 |
||
284 |
||
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
285 |
int optimizer::QuickGroupMinMaxSelect::reset(void) |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
286 |
{
|
287 |
int result; |
|
288 |
||
289 |
cursor->extra(HA_EXTRA_KEYREAD); /* We need only the key attributes */ |
|
290 |
if ((result= cursor->ha_index_init(index,1))) |
|
291 |
return result; |
|
292 |
if (quick_prefix_select && quick_prefix_select->reset()) |
|
293 |
return 0; |
|
294 |
result= cursor->index_last(record); |
|
295 |
if (result == HA_ERR_END_OF_FILE) |
|
296 |
return 0; |
|
297 |
/* Save the prefix of the last group. */
|
|
298 |
key_copy(last_prefix, record, index_info, group_prefix_len); |
|
299 |
||
300 |
return 0; |
|
301 |
}
|
|
302 |
||
303 |
||
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
304 |
int optimizer::QuickGroupMinMaxSelect::get_next() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
305 |
{
|
306 |
int min_res= 0; |
|
307 |
int max_res= 0; |
|
308 |
int result= 0; |
|
309 |
int is_last_prefix= 0; |
|
310 |
||
311 |
/*
|
|
312 |
Loop until a group is found that satisfies all query conditions or the last
|
|
313 |
group is reached.
|
|
314 |
*/
|
|
315 |
do
|
|
316 |
{
|
|
317 |
result= next_prefix(); |
|
318 |
/*
|
|
319 |
Check if this is the last group prefix. Notice that at this point
|
|
320 |
this->record contains the current prefix in record format.
|
|
321 |
*/
|
|
322 |
if (! result) |
|
323 |
{
|
|
324 |
is_last_prefix= key_cmp(index_info->key_part, last_prefix, |
|
325 |
group_prefix_len); |
|
326 |
assert(is_last_prefix <= 0); |
|
327 |
}
|
|
328 |
else
|
|
329 |
{
|
|
330 |
if (result == HA_ERR_KEY_NOT_FOUND) |
|
331 |
continue; |
|
332 |
break; |
|
333 |
}
|
|
334 |
||
335 |
if (have_min) |
|
336 |
{
|
|
337 |
min_res= next_min(); |
|
338 |
if (min_res == 0) |
|
339 |
update_min_result(); |
|
340 |
}
|
|
341 |
/* If there is no MIN in the group, there is no MAX either. */
|
|
342 |
if ((have_max && !have_min) || |
|
343 |
(have_max && have_min && (min_res == 0))) |
|
344 |
{
|
|
345 |
max_res= next_max(); |
|
346 |
if (max_res == 0) |
|
347 |
update_max_result(); |
|
348 |
/* If a MIN was found, a MAX must have been found as well. */
|
|
349 |
assert(((have_max && !have_min) || |
|
350 |
(have_max && have_min && (max_res == 0)))); |
|
351 |
}
|
|
352 |
/*
|
|
353 |
If this is just a GROUP BY or DISTINCT without MIN or MAX and there
|
|
354 |
are equality predicates for the key parts after the group, find the
|
|
355 |
first sub-group with the extended prefix.
|
|
356 |
*/
|
|
357 |
if (! have_min && ! have_max && key_infix_len > 0) |
|
358 |
result= cursor->index_read_map(record, |
|
359 |
group_prefix, |
|
360 |
make_prev_keypart_map(real_key_parts), |
|
361 |
HA_READ_KEY_EXACT); |
|
362 |
||
363 |
result= have_min ? min_res : have_max ? max_res : result; |
|
364 |
} while ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) && |
|
365 |
is_last_prefix != 0); |
|
366 |
||
367 |
if (result == 0) |
|
368 |
{
|
|
369 |
/*
|
|
370 |
Partially mimic the behavior of end_select_send. Copy the
|
|
371 |
field data from Item_field::field into Item_field::result_field
|
|
372 |
of each non-aggregated field (the group fields, and optionally
|
|
373 |
other fields in non-ANSI SQL mode).
|
|
374 |
*/
|
|
375 |
copy_fields(&join->tmp_table_param); |
|
376 |
}
|
|
377 |
else if (result == HA_ERR_KEY_NOT_FOUND) |
|
378 |
result= HA_ERR_END_OF_FILE; |
|
379 |
||
380 |
return result; |
|
381 |
}
|
|
382 |
||
383 |
||
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
384 |
int optimizer::QuickGroupMinMaxSelect::next_min() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
385 |
{
|
386 |
int result= 0; |
|
387 |
||
388 |
/* Find the MIN key using the eventually extended group prefix. */
|
|
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
389 |
if (! min_max_ranges.empty()) |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
390 |
{
|
391 |
if ((result= next_min_in_range())) |
|
392 |
return result; |
|
393 |
}
|
|
394 |
else
|
|
395 |
{
|
|
396 |
/* Apply the constant equality conditions to the non-group select fields */
|
|
397 |
if (key_infix_len > 0) |
|
398 |
{
|
|
399 |
if ((result= cursor->index_read_map(record, |
|
400 |
group_prefix, |
|
401 |
make_prev_keypart_map(real_key_parts), |
|
402 |
HA_READ_KEY_EXACT))) |
|
403 |
return result; |
|
404 |
}
|
|
405 |
||
406 |
/*
|
|
407 |
If the min/max argument field is NULL, skip subsequent rows in the same
|
|
408 |
group with NULL in it. Notice that:
|
|
409 |
- if the first row in a group doesn't have a NULL in the field, no row
|
|
410 |
in the same group has (because NULL < any other value),
|
|
411 |
- min_max_arg_part->field->ptr points to some place in 'record'.
|
|
412 |
*/
|
|
413 |
if (min_max_arg_part && min_max_arg_part->field->is_null()) |
|
414 |
{
|
|
415 |
/* Find the first subsequent record without NULL in the MIN/MAX field. */
|
|
416 |
key_copy(tmp_record, record, index_info, 0); |
|
417 |
result= cursor->index_read_map(record, |
|
418 |
tmp_record, |
|
419 |
make_keypart_map(real_key_parts), |
|
420 |
HA_READ_AFTER_KEY); |
|
421 |
/*
|
|
422 |
Check if the new record belongs to the current group by comparing its
|
|
423 |
prefix with the group's prefix. If it is from the next group, then the
|
|
424 |
whole group has NULLs in the MIN/MAX field, so use the first record in
|
|
425 |
the group as a result.
|
|
426 |
TODO:
|
|
427 |
It is possible to reuse this new record as the result candidate for the
|
|
428 |
next call to next_min(), and to save one lookup in the next call. For
|
|
429 |
this add a new member 'this->next_group_prefix'.
|
|
430 |
*/
|
|
431 |
if (! result) |
|
432 |
{
|
|
433 |
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len)) |
|
434 |
key_restore(record, tmp_record, index_info, 0); |
|
435 |
}
|
|
436 |
else if (result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) |
|
437 |
result= 0; /* There is a result in any case. */ |
|
438 |
}
|
|
439 |
}
|
|
440 |
||
441 |
/*
|
|
442 |
If the MIN attribute is non-nullable, this->record already contains the
|
|
443 |
MIN key in the group, so just return.
|
|
444 |
*/
|
|
445 |
return result; |
|
446 |
}
|
|
447 |
||
448 |
||
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
449 |
int optimizer::QuickGroupMinMaxSelect::next_max() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
450 |
{
|
451 |
int result= 0; |
|
452 |
||
453 |
/* Get the last key in the (possibly extended) group. */
|
|
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
454 |
if (! min_max_ranges.empty()) |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
455 |
result= next_max_in_range(); |
456 |
else
|
|
457 |
result= cursor->index_read_map(record, |
|
458 |
group_prefix, |
|
459 |
make_prev_keypart_map(real_key_parts), |
|
460 |
HA_READ_PREFIX_LAST); |
|
461 |
return result; |
|
462 |
}
|
|
463 |
||
464 |
||
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
465 |
int optimizer::QuickGroupMinMaxSelect::next_prefix() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
466 |
{
|
467 |
int result= 0; |
|
468 |
||
469 |
if (quick_prefix_select) |
|
470 |
{
|
|
471 |
unsigned char *cur_prefix= seen_first_key ? group_prefix : NULL; |
|
472 |
if ((result= quick_prefix_select->get_next_prefix(group_prefix_len, |
|
473 |
make_prev_keypart_map(group_key_parts), |
|
474 |
cur_prefix))) |
|
475 |
return result; |
|
476 |
seen_first_key= true; |
|
477 |
}
|
|
478 |
else
|
|
479 |
{
|
|
480 |
if (! seen_first_key) |
|
481 |
{
|
|
482 |
result= cursor->index_first(record); |
|
483 |
if (result) |
|
484 |
return result; |
|
485 |
seen_first_key= true; |
|
486 |
}
|
|
487 |
else
|
|
488 |
{
|
|
489 |
/* Load the first key in this group into record. */
|
|
490 |
result= cursor->index_read_map(record, |
|
491 |
group_prefix, |
|
492 |
make_prev_keypart_map(group_key_parts), |
|
493 |
HA_READ_AFTER_KEY); |
|
494 |
if (result) |
|
495 |
return result; |
|
496 |
}
|
|
497 |
}
|
|
498 |
||
499 |
/* Save the prefix of this group for subsequent calls. */
|
|
500 |
key_copy(group_prefix, record, index_info, group_prefix_len); |
|
501 |
/* Append key_infix to group_prefix. */
|
|
502 |
if (key_infix_len > 0) |
|
503 |
memcpy(group_prefix + group_prefix_len, |
|
504 |
key_infix, |
|
505 |
key_infix_len); |
|
506 |
||
507 |
return 0; |
|
508 |
}
|
|
509 |
||
510 |
||
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
511 |
int optimizer::QuickGroupMinMaxSelect::next_min_in_range() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
512 |
{
|
513 |
ha_rkey_function find_flag; |
|
514 |
key_part_map keypart_map; |
|
515 |
optimizer::QuickRange *cur_range= NULL; |
|
516 |
bool found_null= false; |
|
517 |
int result= HA_ERR_KEY_NOT_FOUND; |
|
518 |
basic_string<unsigned char> max_key; |
|
519 |
||
520 |
max_key.reserve(real_prefix_len + min_max_arg_len); |
|
521 |
||
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
522 |
assert(! min_max_ranges.empty()); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
523 |
|
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
524 |
for (vector<optimizer::QuickRange *>::iterator it= min_max_ranges.begin(); |
525 |
it != min_max_ranges.end(); |
|
526 |
++it) |
|
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
527 |
{ /* Search from the left-most range to the right. */ |
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
528 |
cur_range= *it; |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
529 |
|
530 |
/*
|
|
531 |
If the current value for the min/max argument is bigger than the right
|
|
532 |
boundary of cur_range, there is no need to check this range.
|
|
533 |
*/
|
|
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
534 |
if (it != min_max_ranges.begin() && |
535 |
! (cur_range->flag & NO_MAX_RANGE) && |
|
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
536 |
(key_cmp(min_max_arg_part, |
537 |
(const unsigned char*) cur_range->max_key, |
|
538 |
min_max_arg_len) == 1)) |
|
539 |
continue; |
|
540 |
||
541 |
if (cur_range->flag & NO_MIN_RANGE) |
|
542 |
{
|
|
543 |
keypart_map= make_prev_keypart_map(real_key_parts); |
|
544 |
find_flag= HA_READ_KEY_EXACT; |
|
545 |
}
|
|
546 |
else
|
|
547 |
{
|
|
548 |
/* Extend the search key with the lower boundary for this range. */
|
|
549 |
memcpy(group_prefix + real_prefix_len, |
|
550 |
cur_range->min_key, |
|
551 |
cur_range->min_length); |
|
552 |
keypart_map= make_keypart_map(real_key_parts); |
|
553 |
find_flag= (cur_range->flag & (EQ_RANGE | NULL_RANGE)) ? |
|
554 |
HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MIN) ? |
|
555 |
HA_READ_AFTER_KEY : HA_READ_KEY_OR_NEXT; |
|
556 |
}
|
|
557 |
||
558 |
result= cursor->index_read_map(record, group_prefix, keypart_map, find_flag); |
|
559 |
if (result) |
|
560 |
{
|
|
561 |
if ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) && |
|
562 |
(cur_range->flag & (EQ_RANGE | NULL_RANGE))) |
|
563 |
continue; /* Check the next range. */ |
|
564 |
||
565 |
/*
|
|
566 |
In all other cases (HA_ERR_*, HA_READ_KEY_EXACT with NO_MIN_RANGE,
|
|
567 |
HA_READ_AFTER_KEY, HA_READ_KEY_OR_NEXT) if the lookup failed for this
|
|
568 |
range, it can't succeed for any other subsequent range.
|
|
569 |
*/
|
|
570 |
break; |
|
571 |
}
|
|
572 |
||
573 |
/* A key was found. */
|
|
574 |
if (cur_range->flag & EQ_RANGE) |
|
575 |
break; /* No need to perform the checks below for equal keys. */ |
|
576 |
||
577 |
if (cur_range->flag & NULL_RANGE) |
|
578 |
{
|
|
579 |
/*
|
|
580 |
Remember this key, and continue looking for a non-NULL key that
|
|
581 |
satisfies some other condition.
|
|
582 |
*/
|
|
583 |
memcpy(tmp_record, record, head->s->rec_buff_length); |
|
584 |
found_null= true; |
|
585 |
continue; |
|
586 |
}
|
|
587 |
||
588 |
/* Check if record belongs to the current group. */
|
|
589 |
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len)) |
|
590 |
{
|
|
591 |
result= HA_ERR_KEY_NOT_FOUND; |
|
592 |
continue; |
|
593 |
}
|
|
594 |
||
595 |
/* If there is an upper limit, check if the found key is in the range. */
|
|
596 |
if (! (cur_range->flag & NO_MAX_RANGE) ) |
|
597 |
{
|
|
598 |
/* Compose the MAX key for the range. */
|
|
599 |
max_key.clear(); |
|
600 |
max_key.append(group_prefix, real_prefix_len); |
|
601 |
max_key.append(cur_range->max_key, cur_range->max_length); |
|
602 |
/* Compare the found key with max_key. */
|
|
603 |
int cmp_res= key_cmp(index_info->key_part, |
|
604 |
max_key.data(), |
|
605 |
real_prefix_len + min_max_arg_len); |
|
606 |
if (! (((cur_range->flag & NEAR_MAX) && (cmp_res == -1)) || |
|
607 |
(cmp_res <= 0))) |
|
608 |
{
|
|
609 |
result= HA_ERR_KEY_NOT_FOUND; |
|
610 |
continue; |
|
611 |
}
|
|
612 |
}
|
|
613 |
/* If we got to this point, the current key qualifies as MIN. */
|
|
614 |
assert(result == 0); |
|
615 |
break; |
|
616 |
}
|
|
617 |
/*
|
|
618 |
If there was a key with NULL in the MIN/MAX field, and there was no other
|
|
619 |
key without NULL from the same group that satisfies some other condition,
|
|
620 |
then use the key with the NULL.
|
|
621 |
*/
|
|
622 |
if (found_null && result) |
|
623 |
{
|
|
624 |
memcpy(record, tmp_record, head->s->rec_buff_length); |
|
625 |
result= 0; |
|
626 |
}
|
|
627 |
return result; |
|
628 |
}
|
|
629 |
||
630 |
||
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
631 |
int optimizer::QuickGroupMinMaxSelect::next_max_in_range() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
632 |
{
|
633 |
ha_rkey_function find_flag; |
|
634 |
key_part_map keypart_map; |
|
635 |
optimizer::QuickRange *cur_range= NULL; |
|
636 |
int result= 0; |
|
637 |
basic_string<unsigned char> min_key; |
|
638 |
min_key.reserve(real_prefix_len + min_max_arg_len); |
|
639 |
||
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
640 |
assert(! min_max_ranges.empty()); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
641 |
|
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
642 |
for (vector<optimizer::QuickRange *>::reverse_iterator rit= min_max_ranges.rbegin(); |
643 |
rit != min_max_ranges.rend(); |
|
644 |
++rit) |
|
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
645 |
{ /* Search from the right-most range to the left. */ |
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
646 |
cur_range= *rit; |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
647 |
|
648 |
/*
|
|
649 |
If the current value for the min/max argument is smaller than the left
|
|
650 |
boundary of cur_range, there is no need to check this range.
|
|
651 |
*/
|
|
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
652 |
if (rit != min_max_ranges.rbegin() && |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
653 |
! (cur_range->flag & NO_MIN_RANGE) && |
654 |
(key_cmp(min_max_arg_part, |
|
655 |
(const unsigned char*) cur_range->min_key, |
|
656 |
min_max_arg_len) == -1)) |
|
657 |
continue; |
|
658 |
||
659 |
if (cur_range->flag & NO_MAX_RANGE) |
|
660 |
{
|
|
661 |
keypart_map= make_prev_keypart_map(real_key_parts); |
|
662 |
find_flag= HA_READ_PREFIX_LAST; |
|
663 |
}
|
|
664 |
else
|
|
665 |
{
|
|
666 |
/* Extend the search key with the upper boundary for this range. */
|
|
667 |
memcpy(group_prefix + real_prefix_len, |
|
668 |
cur_range->max_key, |
|
669 |
cur_range->max_length); |
|
670 |
keypart_map= make_keypart_map(real_key_parts); |
|
671 |
find_flag= (cur_range->flag & EQ_RANGE) ? |
|
672 |
HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MAX) ? |
|
673 |
HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV; |
|
674 |
}
|
|
675 |
||
676 |
result= cursor->index_read_map(record, group_prefix, keypart_map, find_flag); |
|
677 |
||
678 |
if (result) |
|
679 |
{
|
|
680 |
if ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) && |
|
681 |
(cur_range->flag & EQ_RANGE)) |
|
682 |
continue; /* Check the next range. */ |
|
683 |
||
684 |
/*
|
|
685 |
In no key was found with this upper bound, there certainly are no keys
|
|
686 |
in the ranges to the left.
|
|
687 |
*/
|
|
688 |
return result; |
|
689 |
}
|
|
690 |
/* A key was found. */
|
|
691 |
if (cur_range->flag & EQ_RANGE) |
|
692 |
return 0; /* No need to perform the checks below for equal keys. */ |
|
693 |
||
694 |
/* Check if record belongs to the current group. */
|
|
695 |
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len)) |
|
696 |
continue; // Row not found |
|
697 |
||
698 |
/* If there is a lower limit, check if the found key is in the range. */
|
|
699 |
if (! (cur_range->flag & NO_MIN_RANGE) ) |
|
700 |
{
|
|
701 |
/* Compose the MIN key for the range. */
|
|
702 |
min_key.clear(); |
|
703 |
min_key.append(group_prefix, real_prefix_len); |
|
704 |
min_key.append(cur_range->min_key, cur_range->min_length); |
|
705 |
||
706 |
/* Compare the found key with min_key. */
|
|
707 |
int cmp_res= key_cmp(index_info->key_part, |
|
708 |
min_key.data(), |
|
709 |
real_prefix_len + min_max_arg_len); |
|
710 |
if (! (((cur_range->flag & NEAR_MIN) && (cmp_res == 1)) || |
|
711 |
(cmp_res >= 0))) |
|
712 |
continue; |
|
713 |
}
|
|
714 |
/* If we got to this point, the current key qualifies as MAX. */
|
|
715 |
return result; |
|
716 |
}
|
|
717 |
return HA_ERR_KEY_NOT_FOUND; |
|
718 |
}
|
|
719 |
||
720 |
||
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
721 |
void optimizer::QuickGroupMinMaxSelect::update_min_result() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
722 |
{
|
723 |
Item_sum *min_func= NULL; |
|
724 |
||
725 |
min_functions_it->rewind(); |
|
726 |
while ((min_func= (*min_functions_it)++)) |
|
727 |
min_func->reset(); |
|
728 |
}
|
|
729 |
||
730 |
||
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
731 |
void optimizer::QuickGroupMinMaxSelect::update_max_result() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
732 |
{
|
733 |
Item_sum *max_func= NULL; |
|
734 |
||
735 |
max_functions_it->rewind(); |
|
736 |
while ((max_func= (*max_functions_it)++)) |
|
737 |
max_func->reset(); |
|
738 |
}
|
|
739 |
||
740 |
||
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
741 |
void optimizer::QuickGroupMinMaxSelect::add_keys_and_lengths(String *key_names, |
742 |
String *used_lengths) |
|
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
743 |
{
|
744 |
char buf[64]; |
|
745 |
key_names->append(index_info->name); |
|
1280.1.10
by Monty Taylor
Put everything in drizzled into drizzled namespace. |
746 |
uint32_t length= internal::int64_t2str(max_used_key_length, buf, 10) - buf; |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
747 |
used_lengths->append(buf, length); |
748 |
}
|
|
749 |
||
1280.1.10
by Monty Taylor
Put everything in drizzled into drizzled namespace. |
750 |
} /* namespace drizzled */ |