~drizzle-trunk/drizzle/development

1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
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
 */
19
1241.9.36 by Monty Taylor
ZOMG. I deleted drizzled/server_includes.h.
20
#include "config.h"
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
21
#include "drizzled/session.h"
22
#include "drizzled/optimizer/quick_range.h"
23
#include "drizzled/optimizer/quick_range_select.h"
1241.9.54 by Monty Taylor
Moved bitmap into drizzled.
24
#include "drizzled/sql_bitmap.h"
1241.9.64 by Monty Taylor
Moved remaining non-public portions of mysys and mystrings to drizzled/internal.
25
#include "drizzled/internal/m_string.h"
1241.9.1 by Monty Taylor
Removed global.h. Fixed all the headers.
26
#include <fcntl.h>
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
27
#include "drizzled/memory/multi_malloc.h"
28
29
using namespace std;
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
30
31
namespace drizzled
32
{
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
33
34
1240.3.1 by Brian Aker
Merge Padraig.
35
optimizer::QuickRangeSelect::QuickRangeSelect(Session *session,
36
                                              Table *table,
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
37
                                              uint32_t key_nr,
1240.3.1 by Brian Aker
Merge Padraig.
38
                                              bool no_alloc,
1253.1.3 by Monty Taylor
MEM_ROOT == memory::Root
39
                                              memory::Root *parent_alloc,
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
40
                                              bool *create_error)
41
  :
1237.13.36 by Padraig O'Sullivan
Corrected an order of initialization in a few optimizer classes
42
    mrr_flags(0),
43
    alloc(),
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
44
    cursor(NULL),
45
    ranges(),
46
    in_ror_merged_scan(false),
47
    column_bitmap(),
48
    save_read_set(NULL),
49
    save_write_set(NULL),
50
    free_file(false),
51
    cur_range(NULL),
52
    last_range(NULL),
53
    qr_traversal_ctx(),
54
    mrr_buf_size(0),
55
    mrr_buf_desc(NULL),
56
    key_parts(NULL),
1237.13.36 by Padraig O'Sullivan
Corrected an order of initialization in a few optimizer classes
57
    dont_free(false)
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
58
{
59
  my_bitmap_map *bitmap= NULL;
60
61
  sorted= 0;
62
  index= key_nr;
63
  head= table;
64
  key_part_info= head->key_info[index].key_part;
65
  my_init_dynamic_array(&ranges, sizeof(optimizer::QuickRange*), 16, 16);
66
67
  /* 'session' is not accessible in QuickRangeSelect::reset(). */
68
  mrr_buf_size= session->variables.read_rnd_buff_size;
69
  mrr_buf_desc= NULL;
70
71
  if (! no_alloc && ! parent_alloc)
72
  {
73
    // Allocates everything through the internal memroot
1253.1.6 by Monty Taylor
Moved mem_root functions into drizzled::memory:: namespace.
74
    memory::init_sql_alloc(&alloc, session->variables.range_alloc_block_size, 0);
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
75
    session->mem_root= &alloc;
76
  }
77
  else
78
  {
79
    memset(&alloc, 0, sizeof(alloc));
80
  }
81
82
  cursor= head->cursor;
83
  record= head->record[0];
84
  save_read_set= head->read_set;
85
  save_write_set= head->write_set;
86
1253.1.6 by Monty Taylor
Moved mem_root functions into drizzled::memory:: namespace.
87
  /* Allocate a bitmap for used columns. Using memory::sql_alloc instead of malloc
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
88
     simply as a "fix" to the MySQL 6.0 code that also free()s it at the
89
     same time we destroy the mem_root.
90
   */
91
1253.1.6 by Monty Taylor
Moved mem_root functions into drizzled::memory:: namespace.
92
  bitmap= reinterpret_cast<my_bitmap_map*>(memory::sql_alloc(head->s->column_bitmap_size));
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
93
  if (! bitmap)
94
  {
95
    column_bitmap.setBitmap(NULL);
96
    *create_error= 1;
97
  }
98
  else
99
  {
100
    column_bitmap.init(bitmap, head->s->fields);
101
  }
102
}
103
104
105
int optimizer::QuickRangeSelect::init()
106
{
107
  if (cursor->inited != Cursor::NONE)
108
    cursor->ha_index_or_rnd_end();
109
  return (cursor->ha_index_init(index, 1));
110
}
111
112
113
void optimizer::QuickRangeSelect::range_end()
114
{
115
  if (cursor->inited != Cursor::NONE)
116
    cursor->ha_index_or_rnd_end();
117
}
118
119
120
optimizer::QuickRangeSelect::~QuickRangeSelect()
121
{
122
  if (! dont_free)
123
  {
124
    /* cursor is NULL for CPK scan on covering ROR-intersection */
125
    if (cursor)
126
    {
127
      range_end();
128
      if (head->key_read)
129
      {
130
        head->key_read= 0;
131
        cursor->extra(HA_EXTRA_NO_KEYREAD);
132
      }
133
      if (free_file)
134
      {
135
        cursor->ha_external_lock(current_session, F_UNLCK);
136
        cursor->close();
137
        delete cursor;
138
      }
139
    }
140
    delete_dynamic(&ranges); /* ranges are allocated in alloc */
141
    free_root(&alloc,MYF(0));
142
  }
143
  head->column_bitmaps_set(save_read_set, save_write_set);
144
  assert(mrr_buf_desc == NULL);
145
  if (mrr_buf_desc)
146
  {
147
    free(mrr_buf_desc);
148
  }
149
}
150
151
152
int optimizer::QuickRangeSelect::init_ror_merged_scan(bool reuse_handler)
153
{
154
  Cursor *save_file= cursor, *org_file;
155
  Session *session;
156
157
  in_ror_merged_scan= 1;
158
  if (reuse_handler)
159
  {
160
    if (init() || reset())
161
    {
162
      return 0;
163
    }
164
    head->column_bitmaps_set(&column_bitmap, &column_bitmap);
165
    goto end;
166
  }
167
168
  /* Create a separate Cursor object for this quick select */
169
  if (free_file)
170
  {
171
    /* already have own 'Cursor' object. */
172
    return 0;
173
  }
174
175
  session= head->in_use;
176
  if (! (cursor= head->cursor->clone(session->mem_root)))
177
  {
178
    /*
179
      Manually set the error flag. Note: there seems to be quite a few
180
      places where a failure could cause the server to "hang" the client by
181
      sending no response to a query. ATM those are not real errors because
182
      the storage engine calls in question happen to never fail with the
183
      existing storage engines.
184
    */
185
    my_error(ER_OUT_OF_RESOURCES, MYF(0));
186
    /* Caller will free the memory */
187
    goto failure;
188
  }
189
190
  head->column_bitmaps_set(&column_bitmap, &column_bitmap);
191
192
  if (cursor->ha_external_lock(session, F_RDLCK))
193
    goto failure;
194
195
  if (init() || reset())
196
  {
197
    cursor->ha_external_lock(session, F_UNLCK);
198
    cursor->close();
199
    goto failure;
200
  }
201
  free_file= true;
202
  last_rowid= cursor->ref;
203
204
end:
205
  /*
206
    We are only going to read key fields and call position() on 'cursor'
207
    The following sets head->tmp_set to only use this key and then updates
208
    head->read_set and head->write_set to use this bitmap.
209
    The now bitmap is stored in 'column_bitmap' which is used in ::get_next()
210
  */
211
  org_file= head->cursor;
212
  head->cursor= cursor;
213
  /* We don't have to set 'head->keyread' here as the 'cursor' is unique */
214
  if (! head->no_keyread)
215
  {
216
    head->key_read= 1;
217
    head->mark_columns_used_by_index(index);
218
  }
219
  head->prepare_for_position();
220
  head->cursor= org_file;
221
  column_bitmap= *head->read_set;
222
  head->column_bitmaps_set(&column_bitmap, &column_bitmap);
223
224
  return 0;
225
226
failure:
227
  head->column_bitmaps_set(save_read_set, save_write_set);
228
  delete cursor;
229
  cursor= save_file;
230
  return 0;
231
}
232
233
234
void optimizer::QuickRangeSelect::save_last_pos()
235
{
236
  cursor->position(record);
237
}
238
239
1237.13.11 by Padraig O'Sullivan
Split the QUICK_ROR_INTERSECT_SELECT class out into its own header and implementation files.
240
bool optimizer::QuickRangeSelect::unique_key_range() const
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
241
{
242
  if (ranges.elements == 1)
243
  {
244
    optimizer::QuickRange *tmp= *((optimizer::QuickRange**)ranges.buffer);
245
    if ((tmp->flag & (EQ_RANGE | NULL_RANGE)) == EQ_RANGE)
246
    {
247
      KEY *key=head->key_info+index;
248
      return ((key->flags & (HA_NOSAME)) == HA_NOSAME &&
249
	      key->key_length == tmp->min_length);
250
    }
251
  }
252
  return false;
253
}
254
255
256
int optimizer::QuickRangeSelect::reset()
257
{
258
  uint32_t buf_size= 0;
259
  unsigned char *mrange_buff= NULL;
260
  int error= 0;
261
  HANDLER_BUFFER empty_buf;
262
  last_range= NULL;
263
  cur_range= (optimizer::QuickRange**) ranges.buffer;
264
265
  if (cursor->inited == Cursor::NONE && (error= cursor->ha_index_init(index, 1)))
266
  {
267
    return error;
268
  }
269
270
  /* Allocate buffer if we need one but haven't allocated it yet */
271
  if (mrr_buf_size && ! mrr_buf_desc)
272
  {
273
    buf_size= mrr_buf_size;
274
    while (buf_size && ! memory::multi_malloc(false,
1240.3.1 by Brian Aker
Merge Padraig.
275
                                              &mrr_buf_desc,
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
276
                                              sizeof(*mrr_buf_desc),
1240.3.1 by Brian Aker
Merge Padraig.
277
                                              &mrange_buff,
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
278
                                              buf_size,
279
                                              NULL))
280
    {
281
      /* Try to shrink the buffers until both are 0. */
282
      buf_size/= 2;
283
    }
284
    if (! mrr_buf_desc)
285
    {
286
      return HA_ERR_OUT_OF_MEM;
287
    }
288
289
    /* Initialize the Cursor buffer. */
290
    mrr_buf_desc->buffer= mrange_buff;
291
    mrr_buf_desc->buffer_end= mrange_buff + buf_size;
292
    mrr_buf_desc->end_of_used_area= mrange_buff;
293
  }
294
295
  if (! mrr_buf_desc)
296
  {
297
    empty_buf.buffer= NULL;
298
    empty_buf.buffer_end= NULL;
299
    empty_buf.end_of_used_area= NULL;
300
  }
301
302
  if (sorted)
303
  {
304
     mrr_flags|= HA_MRR_SORTED;
305
  }
306
  RANGE_SEQ_IF seq_funcs= {
1240.3.1 by Brian Aker
Merge Padraig.
307
    optimizer::quick_range_seq_init,
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
308
    optimizer::quick_range_seq_next
309
  };
1240.3.1 by Brian Aker
Merge Padraig.
310
  error= cursor->multi_range_read_init(&seq_funcs,
311
                                       (void*) this,
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
312
                                       ranges.elements,
1240.3.1 by Brian Aker
Merge Padraig.
313
                                       mrr_flags,
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
314
                                       mrr_buf_desc ? mrr_buf_desc : &empty_buf);
315
  return error;
316
}
317
318
319
int optimizer::QuickRangeSelect::get_next()
320
{
321
  char *dummy= NULL;
322
  if (in_ror_merged_scan)
323
  {
324
    /*
325
      We don't need to signal the bitmap change as the bitmap is always the
326
      same for this head->cursor
327
    */
328
    head->column_bitmaps_set(&column_bitmap, &column_bitmap);
329
  }
330
331
  int result= cursor->multi_range_read_next(&dummy);
332
333
  if (in_ror_merged_scan)
334
  {
335
    /* Restore bitmaps set on entry */
336
    head->column_bitmaps_set(save_read_set, save_write_set);
337
  }
338
  return result;
339
}
340
341
342
int optimizer::QuickRangeSelect::get_next_prefix(uint32_t prefix_length,
343
                                                 key_part_map keypart_map,
344
                                                 unsigned char *cur_prefix)
345
{
346
  for (;;)
347
  {
348
    int result;
349
    key_range start_key, end_key;
350
    if (last_range)
351
    {
352
      /* Read the next record in the same range with prefix after cur_prefix. */
353
      assert(cur_prefix != 0);
1240.3.1 by Brian Aker
Merge Padraig.
354
      result= cursor->index_read_map(record,
355
                                     cur_prefix,
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
356
                                     keypart_map,
357
                                     HA_READ_AFTER_KEY);
358
      if (result || (cursor->compare_key(cursor->end_range) <= 0))
359
        return result;
360
    }
361
362
    uint32_t count= ranges.elements - (cur_range - (optimizer::QuickRange**) ranges.buffer);
363
    if (count == 0)
364
    {
365
      /* Ranges have already been used up before. None is left for read. */
366
      last_range= 0;
367
      return HA_ERR_END_OF_FILE;
368
    }
369
    last_range= *(cur_range++);
370
371
    start_key.key= (const unsigned char*) last_range->min_key;
372
    start_key.length= min(last_range->min_length, (uint16_t)prefix_length);
373
    start_key.keypart_map= last_range->min_keypart_map & keypart_map;
374
    start_key.flag= ((last_range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
375
		                                                (last_range->flag & EQ_RANGE) ?
376
		                                                HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
377
    end_key.key= (const unsigned char*) last_range->max_key;
378
    end_key.length= min(last_range->max_length, (uint16_t)prefix_length);
379
    end_key.keypart_map= last_range->max_keypart_map & keypart_map;
380
    /*
381
      We use READ_AFTER_KEY here because if we are reading on a key
382
      prefix we want to find all keys with this prefix
383
    */
384
    end_key.flag= (last_range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
385
		                                             HA_READ_AFTER_KEY);
386
387
    result= cursor->read_range_first(last_range->min_keypart_map ? &start_key : 0,
388
				                             last_range->max_keypart_map ? &end_key : 0,
389
                                     test(last_range->flag & EQ_RANGE),
390
				                             sorted);
391
    if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE))
392
      last_range= 0; // Stop searching
393
394
    if (result != HA_ERR_END_OF_FILE)
395
      return result;
396
    last_range= 0; // No matching rows; go to next range
397
  }
398
}
399
400
401
bool optimizer::QuickRangeSelect::row_in_ranges()
402
{
403
  optimizer::QuickRange *res= NULL;
404
  uint32_t min= 0;
405
  uint32_t max= ranges.elements - 1;
406
  uint32_t mid= (max + min) / 2;
407
408
  while (min != max)
409
  {
410
    if (cmp_next(*(optimizer::QuickRange**)dynamic_array_ptr(&ranges, mid)))
411
    {
412
      /* current row value > mid->max */
413
      min= mid + 1;
414
    }
415
    else
416
      max= mid;
417
    mid= (min + max) / 2;
418
  }
419
  res= *(optimizer::QuickRange**)dynamic_array_ptr(&ranges, mid);
420
  return (! cmp_next(res) && ! cmp_prev(res));
421
}
422
423
424
int optimizer::QuickRangeSelect::cmp_next(optimizer::QuickRange *range_arg)
425
{
426
  if (range_arg->flag & NO_MAX_RANGE)
427
    return 0;                                   /* key can't be to large */
428
429
  KEY_PART *key_part= key_parts;
430
  uint32_t store_length;
431
432
  for (unsigned char *key=range_arg->max_key, *end=key+range_arg->max_length;
433
       key < end;
434
       key+= store_length, key_part++)
435
  {
436
    int cmp;
437
    store_length= key_part->store_length;
438
    if (key_part->null_bit)
439
    {
440
      if (*key)
441
      {
442
        if (! key_part->field->is_null())
443
          return 1;
444
        continue;
445
      }
446
      else if (key_part->field->is_null())
447
        return 0;
448
      key++;					// Skip null byte
449
      store_length--;
450
    }
451
    if ((cmp= key_part->field->key_cmp(key, key_part->length)) < 0)
452
      return 0;
453
    if (cmp > 0)
454
      return 1;
455
  }
456
  return (range_arg->flag & NEAR_MAX) ? 1 : 0;          // Exact match
457
}
458
459
460
int optimizer::QuickRangeSelect::cmp_prev(optimizer::QuickRange *range_arg)
461
{
462
  if (range_arg->flag & NO_MIN_RANGE)
1237.13.25 by Padraig O'Sullivan
Replaced an instance of List with std::vector in the range optimizer.
463
    return 0; /* key can't be to small */
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
464
1237.13.25 by Padraig O'Sullivan
Replaced an instance of List with std::vector in the range optimizer.
465
  int cmp= key_cmp(key_part_info,
466
                   range_arg->min_key,
467
                   range_arg->min_length);
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
468
  if (cmp > 0 || (cmp == 0 && (range_arg->flag & NEAR_MIN) == false))
469
    return 0;
1237.13.25 by Padraig O'Sullivan
Replaced an instance of List with std::vector in the range optimizer.
470
  return 1; // outside of range
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
471
}
472
473
474
void optimizer::QuickRangeSelect::add_info_string(String *str)
475
{
476
  KEY *key_info= head->key_info + index;
477
  str->append(key_info->name);
478
}
479
480
481
void optimizer::QuickRangeSelect::add_keys_and_lengths(String *key_names,
482
                                                       String *used_lengths)
483
{
484
  char buf[64];
485
  uint32_t length;
486
  KEY *key_info= head->key_info + index;
487
  key_names->append(key_info->name);
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
488
  length= internal::int64_t2str(max_used_key_length, buf, 10) - buf;
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
489
  used_lengths->append(buf, length);
490
}
491
492
493
/*
494
  This is a hack: we inherit from QUICK_SELECT so that we can use the
495
  get_next() interface, but we have to hold a pointer to the original
496
  QUICK_SELECT because its data are used all over the place.  What
497
  should be done is to factor out the data that is needed into a base
498
  class (QUICK_SELECT), and then have two subclasses (_ASC and _DESC)
499
  which handle the ranges and implement the get_next() function.  But
500
  for now, this seems to work right at least.
501
 */
502
optimizer::QuickSelectDescending::QuickSelectDescending(optimizer::QuickRangeSelect *q, uint32_t, bool *)
503
  :
1237.13.25 by Padraig O'Sullivan
Replaced an instance of List with std::vector in the range optimizer.
504
    optimizer::QuickRangeSelect(*q)
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
505
{
1237.13.16 by Padraig O'Sullivan
Replaced List with std::vector in the QuickRorIntersectSelect class.
506
  optimizer::QuickRange **pr= (optimizer::QuickRange**) ranges.buffer;
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
507
  optimizer::QuickRange **end_range= pr + ranges.elements;
508
  for (; pr != end_range; pr++)
1237.13.25 by Padraig O'Sullivan
Replaced an instance of List with std::vector in the range optimizer.
509
  {
510
    rev_ranges.push_back(*pr);
511
  }
512
  rev_it= rev_ranges.begin();
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
513
514
  /* Remove EQ_RANGE flag for keys that are not using the full key */
1237.13.25 by Padraig O'Sullivan
Replaced an instance of List with std::vector in the range optimizer.
515
  for (vector<optimizer::QuickRange *>::iterator it= rev_ranges.begin();
516
       it != rev_ranges.end();
517
       ++it)
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
518
  {
1237.13.25 by Padraig O'Sullivan
Replaced an instance of List with std::vector in the range optimizer.
519
    optimizer::QuickRange *r= *it;
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
520
    if ((r->flag & EQ_RANGE) &&
521
        head->key_info[index].key_length != r->max_length)
1237.13.25 by Padraig O'Sullivan
Replaced an instance of List with std::vector in the range optimizer.
522
    {
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
523
      r->flag&= ~EQ_RANGE;
1237.13.25 by Padraig O'Sullivan
Replaced an instance of List with std::vector in the range optimizer.
524
    }
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
525
  }
1237.13.25 by Padraig O'Sullivan
Replaced an instance of List with std::vector in the range optimizer.
526
  q->dont_free= 1; // Don't free shared mem
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
527
  delete q;
528
}
529
530
531
int optimizer::QuickSelectDescending::get_next()
532
{
533
  /* The max key is handled as follows:
534
   *   - if there is NO_MAX_RANGE, start at the end and move backwards
535
   *   - if it is an EQ_RANGE, which means that max key covers the entire
536
   *     key, go directly to the key and read through it (sorting backwards is
537
   *     same as sorting forwards)
538
   *   - if it is NEAR_MAX, go to the key or next, step back once, and
539
   *     move backwards
540
   *   - otherwise (not NEAR_MAX == include the key), go after the key,
541
   *     step back once, and move backwards
542
   */
543
  for (;;)
544
  {
545
    int result;
546
    if (last_range)
547
    {						// Already read through key
548
      result= ((last_range->flag & EQ_RANGE) ?
549
		           cursor->index_next_same(record, last_range->min_key,
550
					                             last_range->min_length) :
551
		           cursor->index_prev(record));
552
      if (! result)
553
      {
1237.13.25 by Padraig O'Sullivan
Replaced an instance of List with std::vector in the range optimizer.
554
          if (cmp_prev(*(rev_it - 1)) == 0)
555
            return 0;
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
556
      }
557
      else if (result != HA_ERR_END_OF_FILE)
558
        return result;
559
    }
560
1237.13.25 by Padraig O'Sullivan
Replaced an instance of List with std::vector in the range optimizer.
561
    if (rev_it == rev_ranges.end())
562
    {
563
      return HA_ERR_END_OF_FILE; // All ranges used
564
    }
565
    last_range= *rev_it;
566
    ++rev_it;
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
567
568
    if (last_range->flag & NO_MAX_RANGE)        // Read last record
569
    {
570
      int local_error;
571
      if ((local_error= cursor->index_last(record)))
572
        return local_error;	// Empty table
573
      if (cmp_prev(last_range) == 0)
574
        return 0;
575
      last_range= 0; // No match; go to next range
576
      continue;
577
    }
578
579
    if (last_range->flag & EQ_RANGE)
580
    {
1240.3.1 by Brian Aker
Merge Padraig.
581
      result = cursor->index_read_map(record,
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
582
                                      last_range->max_key,
583
                                      last_range->max_keypart_map,
584
                                      HA_READ_KEY_EXACT);
585
    }
586
    else
587
    {
588
      assert(last_range->flag & NEAR_MAX ||
589
             range_reads_after_key(last_range));
1240.3.1 by Brian Aker
Merge Padraig.
590
      result= cursor->index_read_map(record,
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
591
                                     last_range->max_key,
592
                                     last_range->max_keypart_map,
593
                                     ((last_range->flag & NEAR_MAX) ?
594
                                      HA_READ_BEFORE_KEY :
595
                                      HA_READ_PREFIX_LAST_OR_PREV));
596
    }
597
    if (result)
598
    {
599
      if (result != HA_ERR_KEY_NOT_FOUND && result != HA_ERR_END_OF_FILE)
600
        return result;
601
      last_range= 0;                            // Not found, to next range
602
      continue;
603
    }
604
    if (cmp_prev(last_range) == 0)
605
    {
606
      if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE))
607
        last_range= 0;				// Stop searching
608
      return 0;				// Found key is in range
609
    }
610
    last_range= 0;                              // To next range
611
  }
612
}
613
614
615
/*
616
 * true if this range will require using HA_READ_AFTER_KEY
617
   See comment in get_next() about this
618
 */
619
bool optimizer::QuickSelectDescending::range_reads_after_key(optimizer::QuickRange *range_arg)
620
{
621
  return ((range_arg->flag & (NO_MAX_RANGE | NEAR_MAX)) ||
622
	        ! (range_arg->flag & EQ_RANGE) ||
623
	        head->key_info[index].key_length != range_arg->max_length) ? 1 : 0;
624
}
625
626
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
627
} /* namespace drizzled */