1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2008-2009 Sun Microsystems
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.
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.
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
20
#include "drizzled/server_includes.h"
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"
31
using namespace drizzled;
34
optimizer::QuickGroupMinMaxSelect::
35
QuickGroupMinMaxSelect(Table *table,
39
KEY_PART_INFO *min_max_arg_part_arg,
40
uint32_t group_prefix_len_arg,
41
uint32_t group_key_parts_arg,
42
uint32_t used_key_parts_arg,
47
uint32_t key_infix_len_arg,
48
unsigned char *key_infix_arg,
49
MEM_ROOT *parent_alloc)
52
index_info(index_info_arg),
53
group_prefix_len(group_prefix_len_arg),
54
group_key_parts(group_key_parts_arg),
55
have_min(have_min_arg),
56
have_max(have_max_arg),
57
seen_first_key(false),
58
min_max_arg_part(min_max_arg_part_arg),
59
key_infix(key_infix_arg),
60
key_infix_len(key_infix_len_arg),
61
min_functions_it(NULL),
62
max_functions_it(NULL)
67
record= head->record[0];
68
tmp_record= head->record[1];
69
read_time= read_cost_arg;
71
used_key_parts= used_key_parts_arg;
72
real_key_parts= used_key_parts_arg;
73
real_prefix_len= group_prefix_len + key_infix_len;
75
min_max_arg_len= min_max_arg_part ? min_max_arg_part->store_length : 0;
78
We can't have parent_alloc set as the init function can't handle this case
81
assert(! parent_alloc);
84
init_sql_alloc(&alloc, join->session->variables.range_alloc_block_size, 0);
85
join->session->mem_root= &alloc;
88
memset(&alloc, 0, sizeof(MEM_ROOT)); // ensure that it's not used
92
int optimizer::QuickGroupMinMaxSelect::init()
94
if (group_prefix) /* Already initialized. */
97
if (! (last_prefix= (unsigned char*) alloc_root(&alloc, group_prefix_len)))
100
We may use group_prefix to store keys with all select fields, so allocate
103
if (! (group_prefix= (unsigned char*) alloc_root(&alloc,
104
real_prefix_len + min_max_arg_len)))
107
if (key_infix_len > 0)
110
The memory location pointed to by key_infix will be deleted soon, so
111
allocate a new buffer and copy the key_infix into it.
113
unsigned char *tmp_key_infix= (unsigned char*) alloc_root(&alloc, key_infix_len);
116
memcpy(tmp_key_infix, this->key_infix, key_infix_len);
117
this->key_infix= tmp_key_infix;
120
if (min_max_arg_part)
122
if (my_init_dynamic_array(&min_max_ranges, sizeof(optimizer::QuickRange*), 16, 16))
127
if (! (min_functions= new List<Item_sum>))
134
if (! (max_functions= new List<Item_sum>))
140
Item_sum *min_max_item= NULL;
141
Item_sum **func_ptr= join->sum_funcs;
142
while ((min_max_item= *(func_ptr++)))
144
if (have_min && (min_max_item->sum_func() == Item_sum::MIN_FUNC))
145
min_functions->push_back(min_max_item);
146
else if (have_max && (min_max_item->sum_func() == Item_sum::MAX_FUNC))
147
max_functions->push_back(min_max_item);
152
if (! (min_functions_it= new List_iterator<Item_sum>(*min_functions)))
158
if (! (max_functions_it= new List_iterator<Item_sum>(*max_functions)))
163
min_max_ranges.elements= 0;
169
optimizer::QuickGroupMinMaxSelect::~QuickGroupMinMaxSelect()
171
if (cursor->inited != Cursor::NONE)
173
cursor->ha_index_end();
175
if (min_max_arg_part)
177
delete_dynamic(&min_max_ranges);
179
free_root(&alloc,MYF(0));
180
delete min_functions_it;
181
delete max_functions_it;
182
delete quick_prefix_select;
186
bool optimizer::QuickGroupMinMaxSelect::add_range(optimizer::SEL_ARG *sel_range)
188
optimizer::QuickRange *range= NULL;
189
uint32_t range_flag= sel_range->min_flag | sel_range->max_flag;
191
/* Skip (-inf,+inf) ranges, e.g. (x < 5 or x > 4). */
192
if ((range_flag & NO_MIN_RANGE) && (range_flag & NO_MAX_RANGE))
195
if (! (sel_range->min_flag & NO_MIN_RANGE) &&
196
! (sel_range->max_flag & NO_MAX_RANGE))
198
if (sel_range->maybe_null &&
199
sel_range->min_value[0] && sel_range->max_value[0])
200
range_flag|= NULL_RANGE; /* IS NULL condition */
201
else if (memcmp(sel_range->min_value, sel_range->max_value,
202
min_max_arg_len) == 0)
203
range_flag|= EQ_RANGE; /* equality condition */
205
range= new optimizer::QuickRange(sel_range->min_value,
207
make_keypart_map(sel_range->part),
208
sel_range->max_value,
210
make_keypart_map(sel_range->part),
214
if (insert_dynamic(&min_max_ranges, (unsigned char*)&range))
220
void optimizer::QuickGroupMinMaxSelect::adjust_prefix_ranges()
222
if (quick_prefix_select &&
223
group_prefix_len < quick_prefix_select->max_used_key_length)
225
DYNAMIC_ARRAY *arr= NULL;
228
for (inx= 0, arr= &quick_prefix_select->ranges; inx < arr->elements; inx++)
230
optimizer::QuickRange *range= NULL;
232
get_dynamic(arr, (unsigned char*)&range, inx);
233
range->flag &= ~(NEAR_MIN | NEAR_MAX);
239
void optimizer::QuickGroupMinMaxSelect::update_key_stat()
241
max_used_key_length= real_prefix_len;
242
if (min_max_ranges.elements > 0)
244
optimizer::QuickRange *cur_range= NULL;
246
{ /* Check if the right-most range has a lower boundary. */
247
get_dynamic(&min_max_ranges,
248
(unsigned char*) &cur_range,
249
min_max_ranges.elements - 1);
250
if (! (cur_range->flag & NO_MIN_RANGE))
252
max_used_key_length+= min_max_arg_len;
258
{ /* Check if the left-most range has an upper boundary. */
259
get_dynamic(&min_max_ranges, (unsigned char*)&cur_range, 0);
260
if (! (cur_range->flag & NO_MAX_RANGE))
262
max_used_key_length+= min_max_arg_len;
268
else if (have_min && min_max_arg_part &&
269
min_max_arg_part->field->real_maybe_null())
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
279
max_used_key_length+= min_max_arg_len;
285
int optimizer::QuickGroupMinMaxSelect::reset(void)
289
cursor->extra(HA_EXTRA_KEYREAD); /* We need only the key attributes */
290
if ((result= cursor->ha_index_init(index,1)))
292
if (quick_prefix_select && quick_prefix_select->reset())
294
result= cursor->index_last(record);
295
if (result == HA_ERR_END_OF_FILE)
297
/* Save the prefix of the last group. */
298
key_copy(last_prefix, record, index_info, group_prefix_len);
304
int optimizer::QuickGroupMinMaxSelect::get_next()
309
int is_last_prefix= 0;
312
Loop until a group is found that satisfies all query conditions or the last
317
result= next_prefix();
319
Check if this is the last group prefix. Notice that at this point
320
this->record contains the current prefix in record format.
324
is_last_prefix= key_cmp(index_info->key_part, last_prefix,
326
assert(is_last_prefix <= 0);
330
if (result == HA_ERR_KEY_NOT_FOUND)
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)))
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))));
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.
357
if (! have_min && ! have_max && key_infix_len > 0)
358
result= cursor->index_read_map(record,
360
make_prev_keypart_map(real_key_parts),
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);
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).
375
copy_fields(&join->tmp_table_param);
377
else if (result == HA_ERR_KEY_NOT_FOUND)
378
result= HA_ERR_END_OF_FILE;
384
int optimizer::QuickGroupMinMaxSelect::next_min()
388
/* Find the MIN key using the eventually extended group prefix. */
389
if (min_max_ranges.elements > 0)
391
if ((result= next_min_in_range()))
396
/* Apply the constant equality conditions to the non-group select fields */
397
if (key_infix_len > 0)
399
if ((result= cursor->index_read_map(record,
401
make_prev_keypart_map(real_key_parts),
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'.
413
if (min_max_arg_part && min_max_arg_part->field->is_null())
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,
419
make_keypart_map(real_key_parts),
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.
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'.
433
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len))
434
key_restore(record, tmp_record, index_info, 0);
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. */
442
If the MIN attribute is non-nullable, this->record already contains the
443
MIN key in the group, so just return.
449
int optimizer::QuickGroupMinMaxSelect::next_max()
453
/* Get the last key in the (possibly extended) group. */
454
if (min_max_ranges.elements > 0)
455
result= next_max_in_range();
457
result= cursor->index_read_map(record,
459
make_prev_keypart_map(real_key_parts),
460
HA_READ_PREFIX_LAST);
465
int optimizer::QuickGroupMinMaxSelect::next_prefix()
469
if (quick_prefix_select)
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),
476
seen_first_key= true;
480
if (! seen_first_key)
482
result= cursor->index_first(record);
485
seen_first_key= true;
489
/* Load the first key in this group into record. */
490
result= cursor->index_read_map(record,
492
make_prev_keypart_map(group_key_parts),
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,
511
int optimizer::QuickGroupMinMaxSelect::next_min_in_range()
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;
520
max_key.reserve(real_prefix_len + min_max_arg_len);
522
assert(min_max_ranges.elements > 0);
524
for (uint32_t range_idx= 0; range_idx < min_max_ranges.elements; range_idx++)
525
{ /* Search from the left-most range to the right. */
526
get_dynamic(&min_max_ranges, (unsigned char*)&cur_range, range_idx);
529
If the current value for the min/max argument is bigger than the right
530
boundary of cur_range, there is no need to check this range.
532
if (range_idx != 0 && !(cur_range->flag & NO_MAX_RANGE) &&
533
(key_cmp(min_max_arg_part,
534
(const unsigned char*) cur_range->max_key,
535
min_max_arg_len) == 1))
538
if (cur_range->flag & NO_MIN_RANGE)
540
keypart_map= make_prev_keypart_map(real_key_parts);
541
find_flag= HA_READ_KEY_EXACT;
545
/* Extend the search key with the lower boundary for this range. */
546
memcpy(group_prefix + real_prefix_len,
548
cur_range->min_length);
549
keypart_map= make_keypart_map(real_key_parts);
550
find_flag= (cur_range->flag & (EQ_RANGE | NULL_RANGE)) ?
551
HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MIN) ?
552
HA_READ_AFTER_KEY : HA_READ_KEY_OR_NEXT;
555
result= cursor->index_read_map(record, group_prefix, keypart_map, find_flag);
558
if ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) &&
559
(cur_range->flag & (EQ_RANGE | NULL_RANGE)))
560
continue; /* Check the next range. */
563
In all other cases (HA_ERR_*, HA_READ_KEY_EXACT with NO_MIN_RANGE,
564
HA_READ_AFTER_KEY, HA_READ_KEY_OR_NEXT) if the lookup failed for this
565
range, it can't succeed for any other subsequent range.
570
/* A key was found. */
571
if (cur_range->flag & EQ_RANGE)
572
break; /* No need to perform the checks below for equal keys. */
574
if (cur_range->flag & NULL_RANGE)
577
Remember this key, and continue looking for a non-NULL key that
578
satisfies some other condition.
580
memcpy(tmp_record, record, head->s->rec_buff_length);
585
/* Check if record belongs to the current group. */
586
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len))
588
result= HA_ERR_KEY_NOT_FOUND;
592
/* If there is an upper limit, check if the found key is in the range. */
593
if (! (cur_range->flag & NO_MAX_RANGE) )
595
/* Compose the MAX key for the range. */
597
max_key.append(group_prefix, real_prefix_len);
598
max_key.append(cur_range->max_key, cur_range->max_length);
599
/* Compare the found key with max_key. */
600
int cmp_res= key_cmp(index_info->key_part,
602
real_prefix_len + min_max_arg_len);
603
if (! (((cur_range->flag & NEAR_MAX) && (cmp_res == -1)) ||
606
result= HA_ERR_KEY_NOT_FOUND;
610
/* If we got to this point, the current key qualifies as MIN. */
615
If there was a key with NULL in the MIN/MAX field, and there was no other
616
key without NULL from the same group that satisfies some other condition,
617
then use the key with the NULL.
619
if (found_null && result)
621
memcpy(record, tmp_record, head->s->rec_buff_length);
628
int optimizer::QuickGroupMinMaxSelect::next_max_in_range()
630
ha_rkey_function find_flag;
631
key_part_map keypart_map;
632
optimizer::QuickRange *cur_range= NULL;
634
basic_string<unsigned char> min_key;
635
min_key.reserve(real_prefix_len + min_max_arg_len);
637
assert(min_max_ranges.elements > 0);
639
for (uint32_t range_idx= min_max_ranges.elements; range_idx > 0; range_idx--)
640
{ /* Search from the right-most range to the left. */
641
get_dynamic(&min_max_ranges, (unsigned char*)&cur_range, range_idx - 1);
644
If the current value for the min/max argument is smaller than the left
645
boundary of cur_range, there is no need to check this range.
647
if (range_idx != min_max_ranges.elements &&
648
! (cur_range->flag & NO_MIN_RANGE) &&
649
(key_cmp(min_max_arg_part,
650
(const unsigned char*) cur_range->min_key,
651
min_max_arg_len) == -1))
654
if (cur_range->flag & NO_MAX_RANGE)
656
keypart_map= make_prev_keypart_map(real_key_parts);
657
find_flag= HA_READ_PREFIX_LAST;
661
/* Extend the search key with the upper boundary for this range. */
662
memcpy(group_prefix + real_prefix_len,
664
cur_range->max_length);
665
keypart_map= make_keypart_map(real_key_parts);
666
find_flag= (cur_range->flag & EQ_RANGE) ?
667
HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MAX) ?
668
HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV;
671
result= cursor->index_read_map(record, group_prefix, keypart_map, find_flag);
675
if ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) &&
676
(cur_range->flag & EQ_RANGE))
677
continue; /* Check the next range. */
680
In no key was found with this upper bound, there certainly are no keys
681
in the ranges to the left.
685
/* A key was found. */
686
if (cur_range->flag & EQ_RANGE)
687
return 0; /* No need to perform the checks below for equal keys. */
689
/* Check if record belongs to the current group. */
690
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len))
691
continue; // Row not found
693
/* If there is a lower limit, check if the found key is in the range. */
694
if (! (cur_range->flag & NO_MIN_RANGE) )
696
/* Compose the MIN key for the range. */
698
min_key.append(group_prefix, real_prefix_len);
699
min_key.append(cur_range->min_key, cur_range->min_length);
701
/* Compare the found key with min_key. */
702
int cmp_res= key_cmp(index_info->key_part,
704
real_prefix_len + min_max_arg_len);
705
if (! (((cur_range->flag & NEAR_MIN) && (cmp_res == 1)) ||
709
/* If we got to this point, the current key qualifies as MAX. */
712
return HA_ERR_KEY_NOT_FOUND;
716
void optimizer::QuickGroupMinMaxSelect::update_min_result()
718
Item_sum *min_func= NULL;
720
min_functions_it->rewind();
721
while ((min_func= (*min_functions_it)++))
726
void optimizer::QuickGroupMinMaxSelect::update_max_result()
728
Item_sum *max_func= NULL;
730
max_functions_it->rewind();
731
while ((max_func= (*max_functions_it)++))
736
void optimizer::QuickGroupMinMaxSelect::add_keys_and_lengths(String *key_names,
737
String *used_lengths)
740
key_names->append(index_info->name);
741
uint32_t length= int64_t2str(max_used_key_length, buf, 10) - buf;
742
used_lengths->append(buf, length);