~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
 *
1999.6.1 by kalebral at gmail
update Copyright strings to a more common format to help with creating the master debian copyright file
4
 *  Copyright (C) 2008-2009 Sun Microsystems, Inc.
1237.13.20 by Padraig O'Sullivan
Forgot to include a copyright header in one of the new files I created.
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
2173.2.1 by Monty Taylor
Fixes incorrect usage of include
20
#include <config.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>
29
#include <drizzled/internal/m_string.h>
30
#include <drizzled/util/functors.h>
1237.13.29 by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer.
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,
1541.1.1 by Brian Aker
JOIN -> Join rename
41
                       Join *join_arg,
1237.13.21 by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class.
42
                       bool have_min_arg,
43
                       bool have_max_arg,
1534 by Brian Aker
Remove of KeyPartInfo
44
                       KeyPartInfo *min_max_arg_part_arg,
1237.13.21 by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class.
45
                       uint32_t group_prefix_len_arg,
46
                       uint32_t group_key_parts_arg,
47
                       uint32_t used_key_parts_arg,
1535 by Brian Aker
Rename of KEY to KeyInfo
48
                       KeyInfo *index_info_arg,
1237.13.21 by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class.
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];
1672.3.6 by Brian Aker
First pass in encapsulating row
73
  tmp_record= head->getUpdateRecord();
1237.13.18 by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files.
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
1485 by Brian Aker
Updates to confine memroot
102
  if (! (last_prefix= (unsigned char*) alloc.alloc_root(group_prefix_len)))
1237.13.18 by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files.
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
  */
1485 by Brian Aker
Updates to confine memroot
108
  if (! (group_prefix= (unsigned char*) alloc.alloc_root(real_prefix_len + min_max_arg_len)))
1237.13.18 by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files.
109
    return 1;
110
111
  if (key_infix_len > 0)
112
  {
113
    /*
114
      The memory location pointed to by key_infix will be deleted soon, so
115
      allocate a new buffer and copy the key_infix into it.
116
    */
1485 by Brian Aker
Updates to confine memroot
117
    unsigned char *tmp_key_infix= (unsigned char*) alloc.alloc_root(key_infix_len);
1237.13.18 by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files.
118
    if (! tmp_key_infix)
119
      return 1;
120
    memcpy(tmp_key_infix, this->key_infix, key_infix_len);
121
    this->key_infix= tmp_key_infix;
122
  }
123
124
  if (min_max_arg_part)
125
  {
126
    if (have_min)
127
    {
128
      if (! (min_functions= new List<Item_sum>))
129
        return 1;
130
    }
131
    else
132
      min_functions= NULL;
133
    if (have_max)
134
    {
135
      if (! (max_functions= new List<Item_sum>))
136
        return 1;
137
    }
138
    else
139
      max_functions= NULL;
140
141
    Item_sum *min_max_item= NULL;
142
    Item_sum **func_ptr= join->sum_funcs;
143
    while ((min_max_item= *(func_ptr++)))
144
    {
145
      if (have_min && (min_max_item->sum_func() == Item_sum::MIN_FUNC))
146
        min_functions->push_back(min_max_item);
147
      else if (have_max && (min_max_item->sum_func() == Item_sum::MAX_FUNC))
148
        max_functions->push_back(min_max_item);
149
    }
150
151
    if (have_min)
152
    {
2179.1.3 by Olaf van der Spek
x
153
      if (! (min_functions_it= new List<Item_sum>::iterator(*min_functions)))
1237.13.18 by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files.
154
        return 1;
155
    }
156
157
    if (have_max)
158
    {
2179.1.3 by Olaf van der Spek
x
159
      if (! (max_functions_it= new List<Item_sum>::iterator(*max_functions)))
1237.13.18 by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files.
160
        return 1;
161
    }
162
  }
163
164
  return 0;
165
}
166
167
1237.13.21 by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class.
168
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.
169
{
170
  if (cursor->inited != Cursor::NONE)
171
  {
1491.1.6 by Jay Pipes
Cursor::ha_index_init() -> Cursor::startIndexScan(). Cursor::ha_index_end() -> Cursor::endIndexScan()
172
    cursor->endIndexScan();
1237.13.18 by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files.
173
  }
174
  if (min_max_arg_part)
175
  {
1237.13.29 by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer.
176
    for_each(min_max_ranges.begin(),
177
             min_max_ranges.end(),
178
             DeletePtr());
1237.13.18 by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files.
179
  }
1237.13.31 by Padraig O'Sullivan
Minor revisions based on review comments from Jay. Thanks Jay!
180
  min_max_ranges.clear();
1487 by Brian Aker
More updates for memory::Root
181
  alloc.free_root(MYF(0));
1237.13.18 by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files.
182
  delete min_functions_it;
183
  delete max_functions_it;
184
  delete quick_prefix_select;
185
}
186
187
1237.13.21 by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class.
188
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.
189
{
190
  optimizer::QuickRange *range= NULL;
191
  uint32_t range_flag= sel_range->min_flag | sel_range->max_flag;
192
193
  /* Skip (-inf,+inf) ranges, e.g. (x < 5 or x > 4). */
194
  if ((range_flag & NO_MIN_RANGE) && (range_flag & NO_MAX_RANGE))
195
    return false;
196
197
  if (! (sel_range->min_flag & NO_MIN_RANGE) &&
198
      ! (sel_range->max_flag & NO_MAX_RANGE))
199
  {
200
    if (sel_range->maybe_null &&
201
        sel_range->min_value[0] && sel_range->max_value[0])
202
      range_flag|= NULL_RANGE; /* IS NULL condition */
203
    else if (memcmp(sel_range->min_value, sel_range->max_value,
204
                    min_max_arg_len) == 0)
205
      range_flag|= EQ_RANGE;  /* equality condition */
206
  }
207
  range= new optimizer::QuickRange(sel_range->min_value,
208
                                   min_max_arg_len,
209
                                   make_keypart_map(sel_range->part),
210
                                   sel_range->max_value,
211
                                   min_max_arg_len,
212
                                   make_keypart_map(sel_range->part),
213
                                   range_flag);
214
  if (! range)
215
    return true;
1237.13.29 by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer.
216
  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.
217
  return false;
218
}
219
220
1237.13.21 by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class.
221
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.
222
{
223
  if (quick_prefix_select &&
224
      group_prefix_len < quick_prefix_select->max_used_key_length)
225
  {
226
    DYNAMIC_ARRAY *arr= NULL;
227
    uint32_t inx;
228
229
    for (inx= 0, arr= &quick_prefix_select->ranges; inx < arr->elements; inx++)
230
    {
231
      optimizer::QuickRange *range= NULL;
232
233
      get_dynamic(arr, (unsigned char*)&range, inx);
234
      range->flag &= ~(NEAR_MIN | NEAR_MAX);
235
    }
236
  }
237
}
238
239
1237.13.21 by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class.
240
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.
241
{
242
  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.
243
  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.
244
  {
245
    optimizer::QuickRange *cur_range= NULL;
246
    if (have_min)
247
    { /* 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!
248
      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.
249
      if (! (cur_range->flag & NO_MIN_RANGE))
250
      {
251
        max_used_key_length+= min_max_arg_len;
252
        used_key_parts++;
253
        return;
254
      }
255
    }
256
    if (have_max)
257
    { /* 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!
258
      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.
259
      if (! (cur_range->flag & NO_MAX_RANGE))
260
      {
261
        max_used_key_length+= min_max_arg_len;
262
        used_key_parts++;
263
        return;
264
      }
265
    }
266
  }
267
  else if (have_min && min_max_arg_part &&
268
           min_max_arg_part->field->real_maybe_null())
269
  {
270
    /*
271
      If a MIN/MAX argument value is NULL, we can quickly determine
272
      that we're in the beginning of the next group, because NULLs
273
      are always < any other value. This allows us to quickly
274
      determine the end of the current group and jump to the next
275
      group (see next_min()) and thus effectively increases the
276
      usable key length.
277
    */
278
    max_used_key_length+= min_max_arg_len;
279
    used_key_parts++;
280
  }
281
}
282
283
1237.13.21 by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class.
284
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.
285
{
286
  int result;
287
288
  cursor->extra(HA_EXTRA_KEYREAD); /* We need only the key attributes */
1491.1.6 by Jay Pipes
Cursor::ha_index_init() -> Cursor::startIndexScan(). Cursor::ha_index_end() -> Cursor::endIndexScan()
289
  if ((result= cursor->startIndexScan(index,1)))
1237.13.18 by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files.
290
    return result;
291
  if (quick_prefix_select && quick_prefix_select->reset())
292
    return 0;
293
  result= cursor->index_last(record);
294
  if (result == HA_ERR_END_OF_FILE)
295
    return 0;
296
  /* Save the prefix of the last group. */
297
  key_copy(last_prefix, record, index_info, group_prefix_len);
298
299
  return 0;
300
}
301
302
1237.13.21 by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class.
303
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.
304
{
305
  int min_res= 0;
306
  int max_res= 0;
307
  int result= 0;
308
  int is_last_prefix= 0;
309
310
  /*
311
    Loop until a group is found that satisfies all query conditions or the last
312
    group is reached.
313
  */
314
  do
315
  {
316
    result= next_prefix();
317
    /*
318
      Check if this is the last group prefix. Notice that at this point
319
      this->record contains the current prefix in record format.
320
    */
321
    if (! result)
322
    {
323
      is_last_prefix= key_cmp(index_info->key_part, last_prefix,
324
                              group_prefix_len);
325
      assert(is_last_prefix <= 0);
326
    }
327
    else
328
    {
329
      if (result == HA_ERR_KEY_NOT_FOUND)
330
        continue;
331
      break;
332
    }
333
334
    if (have_min)
335
    {
336
      min_res= next_min();
337
      if (min_res == 0)
338
        update_min_result();
339
    }
340
    /* If there is no MIN in the group, there is no MAX either. */
341
    if ((have_max && !have_min) ||
342
        (have_max && have_min && (min_res == 0)))
343
    {
344
      max_res= next_max();
345
      if (max_res == 0)
346
        update_max_result();
347
      /* If a MIN was found, a MAX must have been found as well. */
348
      assert(((have_max && !have_min) ||
349
                  (have_max && have_min && (max_res == 0))));
350
    }
351
    /*
352
      If this is just a GROUP BY or DISTINCT without MIN or MAX and there
353
      are equality predicates for the key parts after the group, find the
354
      first sub-group with the extended prefix.
355
    */
356
    if (! have_min && ! have_max && key_infix_len > 0)
357
      result= cursor->index_read_map(record,
358
                                     group_prefix,
359
                                     make_prev_keypart_map(real_key_parts),
360
                                     HA_READ_KEY_EXACT);
361
362
    result= have_min ? min_res : have_max ? max_res : result;
363
  } while ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) &&
364
           is_last_prefix != 0);
365
366
  if (result == 0)
367
  {
368
    /*
369
      Partially mimic the behavior of end_select_send. Copy the
370
      field data from Item_field::field into Item_field::result_field
371
      of each non-aggregated field (the group fields, and optionally
372
      other fields in non-ANSI SQL mode).
373
    */
374
    copy_fields(&join->tmp_table_param);
375
  }
376
  else if (result == HA_ERR_KEY_NOT_FOUND)
377
    result= HA_ERR_END_OF_FILE;
378
379
  return result;
380
}
381
382
1237.13.21 by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class.
383
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.
384
{
385
  int result= 0;
386
387
  /* 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.
388
  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.
389
  {
390
    if ((result= next_min_in_range()))
391
      return result;
392
  }
393
  else
394
  {
395
    /* Apply the constant equality conditions to the non-group select fields */
396
    if (key_infix_len > 0)
397
    {
398
      if ((result= cursor->index_read_map(record,
399
                                          group_prefix,
400
                                          make_prev_keypart_map(real_key_parts),
401
                                          HA_READ_KEY_EXACT)))
402
        return result;
403
    }
404
405
    /*
406
      If the min/max argument field is NULL, skip subsequent rows in the same
407
      group with NULL in it. Notice that:
408
      - if the first row in a group doesn't have a NULL in the field, no row
409
      in the same group has (because NULL < any other value),
410
      - min_max_arg_part->field->ptr points to some place in 'record'.
411
    */
412
    if (min_max_arg_part && min_max_arg_part->field->is_null())
413
    {
414
      /* Find the first subsequent record without NULL in the MIN/MAX field. */
415
      key_copy(tmp_record, record, index_info, 0);
416
      result= cursor->index_read_map(record,
417
                                     tmp_record,
418
                                     make_keypart_map(real_key_parts),
419
                                     HA_READ_AFTER_KEY);
420
      /*
421
        Check if the new record belongs to the current group by comparing its
422
        prefix with the group's prefix. If it is from the next group, then the
423
        whole group has NULLs in the MIN/MAX field, so use the first record in
424
        the group as a result.
425
        TODO:
426
        It is possible to reuse this new record as the result candidate for the
427
        next call to next_min(), and to save one lookup in the next call. For
428
        this add a new member 'this->next_group_prefix'.
429
      */
430
      if (! result)
431
      {
432
        if (key_cmp(index_info->key_part, group_prefix, real_prefix_len))
433
          key_restore(record, tmp_record, index_info, 0);
434
      }
435
      else if (result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE)
436
        result= 0; /* There is a result in any case. */
437
    }
438
  }
439
440
  /*
441
    If the MIN attribute is non-nullable, this->record already contains the
442
    MIN key in the group, so just return.
443
  */
444
  return result;
445
}
446
447
1237.13.21 by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class.
448
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.
449
{
450
  int result= 0;
451
452
  /* 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.
453
  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.
454
    result= next_max_in_range();
455
  else
456
    result= cursor->index_read_map(record,
457
                                   group_prefix,
458
                                   make_prev_keypart_map(real_key_parts),
459
                                   HA_READ_PREFIX_LAST);
460
  return result;
461
}
462
463
1237.13.21 by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class.
464
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.
465
{
466
  int result= 0;
467
468
  if (quick_prefix_select)
469
  {
470
    unsigned char *cur_prefix= seen_first_key ? group_prefix : NULL;
471
    if ((result= quick_prefix_select->get_next_prefix(group_prefix_len,
472
                                                      make_prev_keypart_map(group_key_parts),
473
                                                      cur_prefix)))
474
      return result;
475
    seen_first_key= true;
476
  }
477
  else
478
  {
479
    if (! seen_first_key)
480
    {
481
      result= cursor->index_first(record);
482
      if (result)
483
        return result;
484
      seen_first_key= true;
485
    }
486
    else
487
    {
488
      /* Load the first key in this group into record. */
489
      result= cursor->index_read_map(record,
490
                                     group_prefix,
491
                                     make_prev_keypart_map(group_key_parts),
492
                                     HA_READ_AFTER_KEY);
493
      if (result)
494
        return result;
495
    }
496
  }
497
498
  /* Save the prefix of this group for subsequent calls. */
499
  key_copy(group_prefix, record, index_info, group_prefix_len);
500
  /* Append key_infix to group_prefix. */
501
  if (key_infix_len > 0)
502
    memcpy(group_prefix + group_prefix_len,
503
           key_infix,
504
           key_infix_len);
505
506
  return 0;
507
}
508
509
1237.13.21 by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class.
510
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.
511
{
512
  ha_rkey_function find_flag;
513
  key_part_map keypart_map;
514
  optimizer::QuickRange *cur_range= NULL;
515
  bool found_null= false;
516
  int result= HA_ERR_KEY_NOT_FOUND;
517
  basic_string<unsigned char> max_key;
518
519
  max_key.reserve(real_prefix_len + min_max_arg_len);
520
1237.13.29 by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer.
521
  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.
522
1237.13.29 by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer.
523
  for (vector<optimizer::QuickRange *>::iterator it= min_max_ranges.begin();
524
       it != min_max_ranges.end();
525
       ++it)
1237.13.18 by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files.
526
  { /* 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.
527
    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.
528
529
    /*
530
      If the current value for the min/max argument is bigger than the right
531
      boundary of cur_range, there is no need to check this range.
532
    */
1237.13.29 by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer.
533
    if (it != min_max_ranges.begin() && 
534
        ! (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.
535
        (key_cmp(min_max_arg_part,
536
                 (const unsigned char*) cur_range->max_key,
537
                 min_max_arg_len) == 1))
538
      continue;
539
540
    if (cur_range->flag & NO_MIN_RANGE)
541
    {
542
      keypart_map= make_prev_keypart_map(real_key_parts);
543
      find_flag= HA_READ_KEY_EXACT;
544
    }
545
    else
546
    {
547
      /* Extend the search key with the lower boundary for this range. */
548
      memcpy(group_prefix + real_prefix_len,
549
             cur_range->min_key,
550
             cur_range->min_length);
551
      keypart_map= make_keypart_map(real_key_parts);
552
      find_flag= (cur_range->flag & (EQ_RANGE | NULL_RANGE)) ?
553
                 HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MIN) ?
554
                 HA_READ_AFTER_KEY : HA_READ_KEY_OR_NEXT;
555
    }
556
557
    result= cursor->index_read_map(record, group_prefix, keypart_map, find_flag);
558
    if (result)
559
    {
560
      if ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) &&
561
          (cur_range->flag & (EQ_RANGE | NULL_RANGE)))
562
        continue; /* Check the next range. */
563
564
      /*
565
        In all other cases (HA_ERR_*, HA_READ_KEY_EXACT with NO_MIN_RANGE,
566
        HA_READ_AFTER_KEY, HA_READ_KEY_OR_NEXT) if the lookup failed for this
567
        range, it can't succeed for any other subsequent range.
568
      */
569
      break;
570
    }
571
572
    /* A key was found. */
573
    if (cur_range->flag & EQ_RANGE)
574
      break; /* No need to perform the checks below for equal keys. */
575
576
    if (cur_range->flag & NULL_RANGE)
577
    {
578
      /*
579
        Remember this key, and continue looking for a non-NULL key that
580
        satisfies some other condition.
581
      */
1532.1.15 by Brian Aker
Partial encapsulation of TableShare from Table.
582
      memcpy(tmp_record, record, head->getShare()->rec_buff_length);
1237.13.18 by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files.
583
      found_null= true;
584
      continue;
585
    }
586
587
    /* Check if record belongs to the current group. */
588
    if (key_cmp(index_info->key_part, group_prefix, real_prefix_len))
589
    {
590
      result= HA_ERR_KEY_NOT_FOUND;
591
      continue;
592
    }
593
594
    /* If there is an upper limit, check if the found key is in the range. */
595
    if (! (cur_range->flag & NO_MAX_RANGE) )
596
    {
597
      /* Compose the MAX key for the range. */
598
      max_key.clear();
599
      max_key.append(group_prefix, real_prefix_len);
600
      max_key.append(cur_range->max_key, cur_range->max_length);
601
      /* Compare the found key with max_key. */
602
      int cmp_res= key_cmp(index_info->key_part,
603
                           max_key.data(),
604
                           real_prefix_len + min_max_arg_len);
605
      if (! (((cur_range->flag & NEAR_MAX) && (cmp_res == -1)) ||
606
          (cmp_res <= 0)))
607
      {
608
        result= HA_ERR_KEY_NOT_FOUND;
609
        continue;
610
      }
611
    }
612
    /* If we got to this point, the current key qualifies as MIN. */
613
    assert(result == 0);
614
    break;
615
  }
616
  /*
617
    If there was a key with NULL in the MIN/MAX field, and there was no other
618
    key without NULL from the same group that satisfies some other condition,
619
    then use the key with the NULL.
620
  */
621
  if (found_null && result)
622
  {
1532.1.15 by Brian Aker
Partial encapsulation of TableShare from Table.
623
    memcpy(record, tmp_record, head->getShare()->rec_buff_length);
1237.13.18 by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files.
624
    result= 0;
625
  }
626
  return result;
627
}
628
629
1237.13.21 by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class.
630
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.
631
{
632
  ha_rkey_function find_flag;
633
  key_part_map keypart_map;
634
  optimizer::QuickRange *cur_range= NULL;
635
  int result= 0;
636
  basic_string<unsigned char> min_key;
637
  min_key.reserve(real_prefix_len + min_max_arg_len);
638
1237.13.29 by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer.
639
  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.
640
1237.13.29 by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer.
641
  for (vector<optimizer::QuickRange *>::reverse_iterator rit= min_max_ranges.rbegin();
642
       rit != min_max_ranges.rend();
643
       ++rit)
1237.13.18 by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files.
644
  { /* 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.
645
    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.
646
647
    /*
648
      If the current value for the min/max argument is smaller than the left
649
      boundary of cur_range, there is no need to check this range.
650
    */
1237.13.29 by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer.
651
    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.
652
        ! (cur_range->flag & NO_MIN_RANGE) &&
653
        (key_cmp(min_max_arg_part,
654
                 (const unsigned char*) cur_range->min_key,
655
                 min_max_arg_len) == -1))
656
      continue;
657
658
    if (cur_range->flag & NO_MAX_RANGE)
659
    {
660
      keypart_map= make_prev_keypart_map(real_key_parts);
661
      find_flag= HA_READ_PREFIX_LAST;
662
    }
663
    else
664
    {
665
      /* Extend the search key with the upper boundary for this range. */
666
      memcpy(group_prefix + real_prefix_len,
667
             cur_range->max_key,
668
             cur_range->max_length);
669
      keypart_map= make_keypart_map(real_key_parts);
670
      find_flag= (cur_range->flag & EQ_RANGE) ?
671
                 HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MAX) ?
672
                 HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV;
673
    }
674
675
    result= cursor->index_read_map(record, group_prefix, keypart_map, find_flag);
676
677
    if (result)
678
    {
679
      if ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) &&
680
          (cur_range->flag & EQ_RANGE))
681
        continue; /* Check the next range. */
682
683
      /*
684
        In no key was found with this upper bound, there certainly are no keys
685
        in the ranges to the left.
686
      */
687
      return result;
688
    }
689
    /* A key was found. */
690
    if (cur_range->flag & EQ_RANGE)
691
      return 0; /* No need to perform the checks below for equal keys. */
692
693
    /* Check if record belongs to the current group. */
694
    if (key_cmp(index_info->key_part, group_prefix, real_prefix_len))
695
      continue;                                 // Row not found
696
697
    /* If there is a lower limit, check if the found key is in the range. */
698
    if (! (cur_range->flag & NO_MIN_RANGE) )
699
    {
700
      /* Compose the MIN key for the range. */
701
      min_key.clear();
702
      min_key.append(group_prefix, real_prefix_len);
703
      min_key.append(cur_range->min_key, cur_range->min_length);
704
705
      /* Compare the found key with min_key. */
706
      int cmp_res= key_cmp(index_info->key_part,
707
                           min_key.data(),
708
                           real_prefix_len + min_max_arg_len);
709
      if (! (((cur_range->flag & NEAR_MIN) && (cmp_res == 1)) ||
710
          (cmp_res >= 0)))
711
        continue;
712
    }
713
    /* If we got to this point, the current key qualifies as MAX. */
714
    return result;
715
  }
716
  return HA_ERR_KEY_NOT_FOUND;
717
}
718
719
1237.13.21 by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class.
720
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.
721
{
2183.2.1 by Olaf van der Spek
x
722
  *min_functions_it= min_functions->begin();
2179.1.11 by Olaf van der Spek
x
723
  for (Item_sum *min_func; (min_func= (*min_functions_it)++); )
1237.13.18 by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files.
724
    min_func->reset();
725
}
726
727
1237.13.21 by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class.
728
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.
729
{
2183.2.1 by Olaf van der Spek
x
730
  *max_functions_it= max_functions->begin();
2179.1.11 by Olaf van der Spek
x
731
  for (Item_sum *max_func; (max_func= (*max_functions_it)++); )
1237.13.18 by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files.
732
    max_func->reset();
733
}
734
735
2170.4.3 by Stewart Smith
convert tmp2 in explain_plan to std::string instead of char[] buf and String, consequently also convert add_keys_and_length to deal with std::string for key_names parameter
736
void optimizer::QuickGroupMinMaxSelect::add_keys_and_lengths(string *key_names,
2170.4.4 by Stewart Smith
tmp3 String to std::string in explain_plan (and used_lengths parameter to add_keys_and_lengths
737
                                                             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.
738
{
739
  char buf[64];
740
  key_names->append(index_info->name);
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
741
  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.
742
  used_lengths->append(buf, length);
743
}
744
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
745
} /* namespace drizzled */