~drizzle-trunk/drizzle/development

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 */