00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <config.h>
00021
00022 #include <drizzled/session.h>
00023 #include <drizzled/optimizer/quick_range.h>
00024 #include <drizzled/optimizer/quick_range_select.h>
00025 #include <drizzled/internal/m_string.h>
00026 #include <drizzled/current_session.h>
00027 #include <drizzled/key.h>
00028 #include <drizzled/table.h>
00029 #include <drizzled/util/test.h>
00030 #include <drizzled/system_variables.h>
00031
00032 #include <fcntl.h>
00033
00034 using namespace std;
00035
00036 namespace drizzled {
00037
00038
00039 optimizer::QuickRangeSelect::QuickRangeSelect(Session *session,
00040 Table *table,
00041 uint32_t key_nr,
00042 bool no_alloc,
00043 memory::Root *parent_alloc)
00044 :
00045 cursor(NULL),
00046 ranges(),
00047 in_ror_merged_scan(false),
00048 column_bitmap(NULL),
00049 save_read_set(NULL),
00050 save_write_set(NULL),
00051 free_file(false),
00052 cur_range(NULL),
00053 last_range(NULL),
00054 qr_traversal_ctx(),
00055 mrr_buf_size(0),
00056 key_parts(NULL),
00057 dont_free(false),
00058 mrr_flags(0),
00059 alloc()
00060 {
00061 sorted= 0;
00062 index= key_nr;
00063 head= table;
00064 key_part_info= head->key_info[index].key_part;
00065 ranges.init(sizeof(optimizer::QuickRange*), 16, 16);
00066
00067
00068 mrr_buf_size= session->variables.read_rnd_buff_size;
00069
00070 if (! no_alloc && ! parent_alloc)
00071 {
00072
00073 alloc.init(session->variables.range_alloc_block_size);
00074 session->mem_root= &alloc;
00075 }
00076 else
00077 {
00078 memset(&alloc, 0, sizeof(alloc));
00079 }
00080
00081 cursor= head->cursor;
00082 record= head->record[0];
00083 save_read_set= head->read_set;
00084 save_write_set= head->write_set;
00085 column_bitmap= new boost::dynamic_bitset<>(table->getShare()->sizeFields());
00086 }
00087
00088
00089 int optimizer::QuickRangeSelect::init()
00090 {
00091 if (cursor->inited != Cursor::NONE)
00092 cursor->ha_index_or_rnd_end();
00093 return (cursor->startIndexScan(index, 1));
00094 }
00095
00096
00097 void optimizer::QuickRangeSelect::range_end()
00098 {
00099 if (cursor->inited != Cursor::NONE)
00100 cursor->ha_index_or_rnd_end();
00101 }
00102
00103
00104 optimizer::QuickRangeSelect::~QuickRangeSelect()
00105 {
00106 if (! dont_free)
00107 {
00108
00109 if (cursor)
00110 {
00111 range_end();
00112 if (head->key_read)
00113 {
00114 head->key_read= 0;
00115 cursor->extra(HA_EXTRA_NO_KEYREAD);
00116 }
00117 if (free_file)
00118 {
00119 cursor->ha_external_lock(current_session, F_UNLCK);
00120 cursor->close();
00121 delete cursor;
00122 }
00123 }
00124 ranges.free();
00125 delete column_bitmap;
00126 alloc.free_root(MYF(0));
00127 }
00128 head->column_bitmaps_set(*save_read_set, *save_write_set);
00129 }
00130
00131
00132 int optimizer::QuickRangeSelect::init_ror_merged_scan(bool reuse_handler)
00133 {
00134 Cursor* org_file;
00135 Cursor* save_file= cursor;
00136 Session* session;
00137
00138 in_ror_merged_scan= 1;
00139 if (reuse_handler)
00140 {
00141 if (init() || reset())
00142 {
00143 return 0;
00144 }
00145 head->column_bitmaps_set(*column_bitmap, *column_bitmap);
00146 goto end;
00147 }
00148
00149
00150 if (free_file)
00151 {
00152
00153 return 0;
00154 }
00155
00156 session= head->in_use;
00157 if (not (cursor= head->cursor->clone(session->mem_root)))
00158 {
00159
00160
00161
00162
00163
00164
00165
00166 my_error(ER_OUT_OF_RESOURCES, MYF(0));
00167
00168 goto failure;
00169 }
00170
00171 head->column_bitmaps_set(*column_bitmap, *column_bitmap);
00172
00173 if (cursor->ha_external_lock(session, F_RDLCK))
00174 goto failure;
00175
00176 if (init() || reset())
00177 {
00178 cursor->ha_external_lock(session, F_UNLCK);
00179 cursor->close();
00180 goto failure;
00181 }
00182 free_file= true;
00183 last_rowid= cursor->ref;
00184
00185 end:
00186
00187
00188
00189
00190
00191
00192 org_file= head->cursor;
00193 head->cursor= cursor;
00194
00195 if (not head->no_keyread)
00196 {
00197 head->key_read= 1;
00198 head->mark_columns_used_by_index(index);
00199 }
00200 head->prepare_for_position();
00201 head->cursor= org_file;
00202 *column_bitmap|= *head->read_set;
00203 head->column_bitmaps_set(*column_bitmap, *column_bitmap);
00204
00205 return 0;
00206
00207 failure:
00208 head->column_bitmaps_set(*save_read_set, *save_write_set);
00209 delete cursor;
00210 cursor= save_file;
00211 return 0;
00212 }
00213
00214
00215 void optimizer::QuickRangeSelect::save_last_pos()
00216 {
00217 cursor->position(record);
00218 }
00219
00220
00221 bool optimizer::QuickRangeSelect::unique_key_range() const
00222 {
00223 if (ranges.size() == 1)
00224 {
00225 optimizer::QuickRange *tmp= *((optimizer::QuickRange**)ranges.buffer);
00226 if ((tmp->flag & (EQ_RANGE | NULL_RANGE)) == EQ_RANGE)
00227 {
00228 KeyInfo *key=head->key_info+index;
00229 return ((key->flags & (HA_NOSAME)) == HA_NOSAME &&
00230 key->key_length == tmp->min_length);
00231 }
00232 }
00233 return false;
00234 }
00235
00236
00237 int optimizer::QuickRangeSelect::reset()
00238 {
00239 int error= 0;
00240 last_range= NULL;
00241 cur_range= (optimizer::QuickRange**) ranges.buffer;
00242
00243 if (cursor->inited == Cursor::NONE && (error= cursor->startIndexScan(index, 1)))
00244 {
00245 return error;
00246 }
00247
00248
00249
00250
00251
00252
00253 assert(not (mrr_buf_size));
00254
00255 if (sorted)
00256 {
00257 mrr_flags|= HA_MRR_SORTED;
00258 }
00259 RANGE_SEQ_IF seq_funcs= {
00260 optimizer::quick_range_seq_init,
00261 optimizer::quick_range_seq_next
00262 };
00263 error= cursor->multi_range_read_init(&seq_funcs,
00264 (void*) this,
00265 ranges.size(),
00266 mrr_flags);
00267 return error;
00268 }
00269
00270
00271 int optimizer::QuickRangeSelect::get_next()
00272 {
00273 char *dummy= NULL;
00274 if (in_ror_merged_scan)
00275 {
00276
00277
00278
00279
00280 head->column_bitmaps_set(*column_bitmap, *column_bitmap);
00281 }
00282
00283 int result= cursor->multi_range_read_next(&dummy);
00284
00285 if (in_ror_merged_scan)
00286 {
00287
00288 head->column_bitmaps_set(*save_read_set, *save_write_set);
00289 }
00290 return result;
00291 }
00292
00293
00294 int optimizer::QuickRangeSelect::get_next_prefix(uint32_t prefix_length,
00295 key_part_map keypart_map,
00296 unsigned char *cur_prefix)
00297 {
00298 for (;;)
00299 {
00300 int result;
00301 key_range start_key, end_key;
00302 if (last_range)
00303 {
00304
00305 assert(cur_prefix != 0);
00306 result= cursor->index_read_map(record,
00307 cur_prefix,
00308 keypart_map,
00309 HA_READ_AFTER_KEY);
00310 if (result || (cursor->compare_key(cursor->end_range) <= 0))
00311 return result;
00312 }
00313
00314 uint32_t count= ranges.size() - (cur_range - (optimizer::QuickRange**) ranges.buffer);
00315 if (count == 0)
00316 {
00317
00318 last_range= 0;
00319 return HA_ERR_END_OF_FILE;
00320 }
00321 last_range= *(cur_range++);
00322
00323 start_key.key= (const unsigned char*) last_range->min_key;
00324 start_key.length= min(last_range->min_length, (uint16_t)prefix_length);
00325 start_key.keypart_map= last_range->min_keypart_map & keypart_map;
00326 start_key.flag= ((last_range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
00327 (last_range->flag & EQ_RANGE) ?
00328 HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
00329 end_key.key= (const unsigned char*) last_range->max_key;
00330 end_key.length= min(last_range->max_length, (uint16_t)prefix_length);
00331 end_key.keypart_map= last_range->max_keypart_map & keypart_map;
00332
00333
00334
00335
00336 end_key.flag= (last_range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
00337 HA_READ_AFTER_KEY);
00338
00339 result= cursor->read_range_first(last_range->min_keypart_map ? &start_key : 0,
00340 last_range->max_keypart_map ? &end_key : 0,
00341 test(last_range->flag & EQ_RANGE),
00342 sorted);
00343 if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE))
00344 last_range= 0;
00345
00346 if (result != HA_ERR_END_OF_FILE)
00347 return result;
00348 last_range= 0;
00349 }
00350 }
00351
00352
00353 bool optimizer::QuickRangeSelect::row_in_ranges()
00354 {
00355 optimizer::QuickRange *res= NULL;
00356 uint32_t min= 0;
00357 uint32_t max= ranges.size() - 1;
00358 uint32_t mid= (max + min) / 2;
00359
00360 while (min != max)
00361 {
00362 if (cmp_next(reinterpret_cast<optimizer::QuickRange**>(ranges.buffer)[mid]))
00363 {
00364
00365 min= mid + 1;
00366 }
00367 else
00368 max= mid;
00369 mid= (min + max) / 2;
00370 }
00371 res= reinterpret_cast<optimizer::QuickRange**>(ranges.buffer)[mid];
00372 return not cmp_next(res) && not cmp_prev(res);
00373 }
00374
00375
00376 int optimizer::QuickRangeSelect::cmp_next(optimizer::QuickRange *range_arg)
00377 {
00378 if (range_arg->flag & NO_MAX_RANGE)
00379 return 0;
00380
00381 KEY_PART *key_part= key_parts;
00382 uint32_t store_length;
00383
00384 for (unsigned char *key=range_arg->max_key, *end=key+range_arg->max_length;
00385 key < end;
00386 key+= store_length, key_part++)
00387 {
00388 int cmp;
00389 store_length= key_part->store_length;
00390 if (key_part->null_bit)
00391 {
00392 if (*key)
00393 {
00394 if (! key_part->field->is_null())
00395 return 1;
00396 continue;
00397 }
00398 else if (key_part->field->is_null())
00399 return 0;
00400 key++;
00401 store_length--;
00402 }
00403 if ((cmp= key_part->field->key_cmp(key, key_part->length)) < 0)
00404 return 0;
00405 if (cmp > 0)
00406 return 1;
00407 }
00408 return (range_arg->flag & NEAR_MAX) ? 1 : 0;
00409 }
00410
00411
00412 int optimizer::QuickRangeSelect::cmp_prev(optimizer::QuickRange *range_arg)
00413 {
00414 if (range_arg->flag & NO_MIN_RANGE)
00415 return 0;
00416
00417 int cmp= key_cmp(key_part_info,
00418 range_arg->min_key,
00419 range_arg->min_length);
00420 if (cmp > 0 || (cmp == 0 && (range_arg->flag & NEAR_MIN) == false))
00421 return 0;
00422 return 1;
00423 }
00424
00425
00426 void optimizer::QuickRangeSelect::add_info_string(string *str)
00427 {
00428 KeyInfo *key_info= head->key_info + index;
00429 str->append(key_info->name);
00430 }
00431
00432
00433 void optimizer::QuickRangeSelect::add_keys_and_lengths(string *key_names,
00434 string *used_lengths)
00435 {
00436 char buf[64];
00437 uint32_t length;
00438 KeyInfo *key_info= head->key_info + index;
00439 key_names->append(key_info->name);
00440 length= internal::int64_t2str(max_used_key_length, buf, 10) - buf;
00441 used_lengths->append(buf, length);
00442 }
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454 optimizer::QuickSelectDescending::QuickSelectDescending(optimizer::QuickRangeSelect *q, uint32_t, bool *)
00455 :
00456 optimizer::QuickRangeSelect(*q)
00457 {
00458 optimizer::QuickRange **pr= (optimizer::QuickRange**) ranges.buffer;
00459 optimizer::QuickRange **end_range= pr + ranges.size();
00460 for (; pr != end_range; pr++)
00461 {
00462 rev_ranges.push_back(*pr);
00463 }
00464 rev_it= rev_ranges.begin();
00465
00466
00467 BOOST_FOREACH(QuickRange* it, rev_ranges)
00468 {
00469 if ((it->flag & EQ_RANGE) && head->key_info[index].key_length != it->max_length)
00470 {
00471 it->flag&= ~EQ_RANGE;
00472 }
00473 }
00474 q->dont_free= 1;
00475 delete q;
00476 }
00477
00478
00479 int optimizer::QuickSelectDescending::get_next()
00480 {
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491 for (;;)
00492 {
00493 int result;
00494 if (last_range)
00495 {
00496 result= ((last_range->flag & EQ_RANGE) ?
00497 cursor->index_next_same(record, last_range->min_key,
00498 last_range->min_length) :
00499 cursor->index_prev(record));
00500 if (! result)
00501 {
00502 if (cmp_prev(*(rev_it - 1)) == 0)
00503 return 0;
00504 }
00505 else if (result != HA_ERR_END_OF_FILE)
00506 return result;
00507 }
00508
00509 if (rev_it == rev_ranges.end())
00510 {
00511 return HA_ERR_END_OF_FILE;
00512 }
00513 last_range= *rev_it;
00514 ++rev_it;
00515
00516 if (last_range->flag & NO_MAX_RANGE)
00517 {
00518 int local_error;
00519 if ((local_error= cursor->index_last(record)))
00520 return local_error;
00521 if (cmp_prev(last_range) == 0)
00522 return 0;
00523 last_range= 0;
00524 continue;
00525 }
00526
00527 if (last_range->flag & EQ_RANGE)
00528 {
00529 result = cursor->index_read_map(record,
00530 last_range->max_key,
00531 last_range->max_keypart_map,
00532 HA_READ_KEY_EXACT);
00533 }
00534 else
00535 {
00536 assert(last_range->flag & NEAR_MAX ||
00537 range_reads_after_key(last_range));
00538 result= cursor->index_read_map(record,
00539 last_range->max_key,
00540 last_range->max_keypart_map,
00541 ((last_range->flag & NEAR_MAX) ?
00542 HA_READ_BEFORE_KEY :
00543 HA_READ_PREFIX_LAST_OR_PREV));
00544 }
00545 if (result)
00546 {
00547 if (result != HA_ERR_KEY_NOT_FOUND && result != HA_ERR_END_OF_FILE)
00548 return result;
00549 last_range= 0;
00550 continue;
00551 }
00552 if (cmp_prev(last_range) == 0)
00553 {
00554 if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE))
00555 last_range= 0;
00556 return 0;
00557 }
00558 last_range= 0;
00559 }
00560 }
00561
00562
00563
00564
00565
00566
00567 bool optimizer::QuickSelectDescending::range_reads_after_key(optimizer::QuickRange *range_arg)
00568 {
00569 return ((range_arg->flag & (NO_MAX_RANGE | NEAR_MAX)) ||
00570 ! (range_arg->flag & EQ_RANGE) ||
00571 head->key_info[index].key_length != range_arg->max_length) ? 1 : 0;
00572 }
00573
00574
00575 }