diff options
Diffstat (limited to 'sql/opt_range.cc')
-rw-r--r-- | sql/opt_range.cc | 100 |
1 files changed, 78 insertions, 22 deletions
diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 72eb8460496..2205d2fcab4 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -117,6 +117,7 @@ #include "records.h" // init_read_record, end_read_record #include <m_ctype.h> #include "sql_select.h" +#include "filesort.h" // filesort_free_buffers #ifndef EXTRA_DEBUG #define test_rb_tree(A,B) {} @@ -1772,7 +1773,8 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr, index= key_nr; head= table; key_part_info= head->key_info[index].key_part; - my_init_dynamic_array(&ranges, sizeof(QUICK_RANGE*), 16, 16); + my_init_dynamic_array(&ranges, sizeof(QUICK_RANGE*), 16, 16, + MYF(MY_THREAD_SPECIFIC)); /* 'thd' is not accessible in QUICK_RANGE_SELECT::reset(). */ mrr_buf_size= thd->variables.mrr_buff_size; @@ -1781,7 +1783,8 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr, if (!no_alloc && !parent_alloc) { // Allocates everything through the internal memroot - init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0); + init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0, + MYF(MY_THREAD_SPECIFIC)); thd->mem_root= &alloc; } else @@ -1791,7 +1794,7 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr, /* Allocate a bitmap for used columns (Q: why not on MEM_ROOT?) */ if (!(bitmap= (my_bitmap_map*) my_malloc(head->s->column_bitmap_size, - MYF(MY_WME)))) + MYF(MY_WME | MY_THREAD_SPECIFIC)))) { column_bitmap.bitmap= 0; *create_error= 1; @@ -1876,7 +1879,8 @@ QUICK_INDEX_SORT_SELECT::QUICK_INDEX_SORT_SELECT(THD *thd_param, index= MAX_KEY; head= table; bzero(&read_record, sizeof(read_record)); - init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0); + init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0, + MYF(MY_THREAD_SPECIFIC)); DBUG_VOID_RETURN; } @@ -1889,7 +1893,8 @@ int QUICK_INDEX_SORT_SELECT::init() int QUICK_INDEX_SORT_SELECT::reset() { DBUG_ENTER("QUICK_INDEX_SORT_SELECT::reset"); - DBUG_RETURN(read_keys_and_merge()); + const int retval= read_keys_and_merge(); + DBUG_RETURN(retval); } bool @@ -1946,7 +1951,8 @@ QUICK_ROR_INTERSECT_SELECT::QUICK_ROR_INTERSECT_SELECT(THD *thd_param, head= table; record= head->record[0]; if (!parent_alloc) - init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0); + init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0, + MYF(MY_THREAD_SPECIFIC)); else bzero(&alloc, sizeof(MEM_ROOT)); last_rowid= (uchar*) alloc_root(parent_alloc? parent_alloc : &alloc, @@ -2140,8 +2146,9 @@ int QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan(bool reuse_handler) There is no use of this->file. Use it for the first of merged range selects. */ - if (quick->init_ror_merged_scan(TRUE)) - DBUG_RETURN(1); + int error= quick->init_ror_merged_scan(TRUE); + if (error) + DBUG_RETURN(error); quick->file->extra(HA_EXTRA_KEYREAD_PRESERVE_FIELDS); } while ((cur= quick_it++)) @@ -2244,7 +2251,8 @@ QUICK_ROR_UNION_SELECT::QUICK_ROR_UNION_SELECT(THD *thd_param, head= table; rowid_length= table->file->ref_length; record= head->record[0]; - init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0); + init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0, + MYF(MY_THREAD_SPECIFIC)); thd_param->mem_root= &alloc; } @@ -2334,8 +2342,8 @@ int QUICK_ROR_UNION_SELECT::reset() List_iterator_fast<QUICK_SELECT_I> it(quick_selects); while ((quick= it++)) { - if (quick->reset()) - DBUG_RETURN(1); + if ((error= quick->reset())) + DBUG_RETURN(error); if ((error= quick->get_next())) { if (error == HA_ERR_END_OF_FILE) @@ -2346,10 +2354,10 @@ int QUICK_ROR_UNION_SELECT::reset() queue_insert(&queue, (uchar*)quick); } - if (head->file->ha_rnd_init_with_error(1)) + if ((error= head->file->ha_rnd_init(1))) { DBUG_PRINT("error", ("ROR index_merge rnd_init call failed")); - DBUG_RETURN(1); + DBUG_RETURN(error); } DBUG_RETURN(0); @@ -2978,7 +2986,8 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, param.force_default_mrr= ordered_output; thd->no_errors=1; // Don't warn about NULL - init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0); + init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0, + MYF(MY_THREAD_SPECIFIC)); if (!(param.key_parts= (KEY_PART*) alloc_root(&alloc, sizeof(KEY_PART) * @@ -3423,7 +3432,8 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond) my_bitmap_map *old_sets[2]; prune_param.part_info= part_info; - init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0); + init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0, + MYF(MY_THREAD_SPECIFIC)); range_par->mem_root= &alloc; range_par->old_root= thd->mem_root; @@ -10615,7 +10625,10 @@ int read_keys_and_merge_scans(THD *thd, *unique_ptr= unique; } else + { unique->reset(); + filesort_free_buffers(head, false); + } DBUG_ASSERT(file->ref_length == unique->get_size()); DBUG_ASSERT(thd->variables.sortbuff_size == unique->get_max_in_memory_size()); @@ -10774,6 +10787,13 @@ int QUICK_INDEX_INTERSECT_SELECT::get_next() If a Clustered PK scan is present, it is used only to check if row satisfies its condition (and never used for row retrieval). + Locking: to ensure that exclusive locks are only set on records that + are included in the final result we must release the lock + on all rows we read but do not include in the final result. This + must be done on each index that reads the record and the lock + must be released using the same handler (the same quick object) as + used when reading the record. + RETURN 0 - Ok other - Error code if any error occurred. @@ -10784,6 +10804,12 @@ int QUICK_ROR_INTERSECT_SELECT::get_next() List_iterator_fast<QUICK_SELECT_WITH_RECORD> quick_it(quick_selects); QUICK_SELECT_WITH_RECORD *qr; QUICK_RANGE_SELECT* quick; + + /* quick that reads the given rowid first. This is needed in order + to be able to unlock the row using the same handler object that locked + it */ + QUICK_RANGE_SELECT* quick_with_last_rowid; + int error, cmp; uint last_rowid_count=0; DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::get_next"); @@ -10797,7 +10823,10 @@ int QUICK_ROR_INTERSECT_SELECT::get_next() if (cpk_quick) { while (!error && !cpk_quick->row_in_ranges()) + { + quick->file->unlock_row(); /* row not in range; unlock */ error= quick->get_next(); + } } if (error) DBUG_RETURN(error); @@ -10809,6 +10838,7 @@ int QUICK_ROR_INTERSECT_SELECT::get_next() quick->file->position(quick->record); memcpy(last_rowid, quick->file->ref, head->file->ref_length); last_rowid_count= 1; + quick_with_last_rowid= quick; while (last_rowid_count < quick_selects.elements) { @@ -10822,9 +10852,17 @@ int QUICK_ROR_INTERSECT_SELECT::get_next() do { if ((error= quick->get_next())) + { + quick_with_last_rowid->file->unlock_row(); DBUG_RETURN(error); + } quick->file->position(quick->record); cmp= head->file->cmp_ref(quick->file->ref, last_rowid); + if (cmp < 0) + { + /* This row is being skipped. Release lock on it. */ + quick->file->unlock_row(); + } } while (cmp < 0); key_copy(qr->key_tuple, record, head->key_info + quick->index, @@ -10838,13 +10876,19 @@ int QUICK_ROR_INTERSECT_SELECT::get_next() { while (!cpk_quick->row_in_ranges()) { + quick->file->unlock_row(); /* row not in range; unlock */ if ((error= quick->get_next())) + { + quick_with_last_rowid->file->unlock_row(); DBUG_RETURN(error); + } } quick->file->position(quick->record); } memcpy(last_rowid, quick->file->ref, head->file->ref_length); + quick_with_last_rowid->file->unlock_row(); last_rowid_count= 1; + quick_with_last_rowid= quick; //save the fields here key_copy(qr->key_tuple, record, head->key_info + quick->index, @@ -10971,8 +11015,13 @@ int QUICK_RANGE_SELECT::reset() if (file->inited == handler::NONE) { + DBUG_EXECUTE_IF("bug14365043_2", + DBUG_SET("+d,ha_index_init_fail");); if ((error= file->ha_index_init(index,1))) - goto err; + { + file->print_error(error, MYF(0)); + goto err; + } } /* Allocate buffer if we need one but haven't allocated it yet */ @@ -11014,7 +11063,7 @@ err: /* Restore bitmaps set on entry */ if (in_ror_merged_scan) head->column_bitmaps_set_no_signal(save_read_set, save_write_set); - + DBUG_RETURN(error); } @@ -12882,7 +12931,8 @@ QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg, DBUG_ASSERT(!parent_alloc); if (!parent_alloc) { - init_sql_alloc(&alloc, join->thd->variables.range_alloc_block_size, 0); + init_sql_alloc(&alloc, join->thd->variables.range_alloc_block_size, 0, + MYF(MY_THREAD_SPECIFIC)); join->thd->mem_root= &alloc; } else @@ -12937,7 +12987,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::init() if (min_max_arg_part) { - if (my_init_dynamic_array(&min_max_ranges, sizeof(QUICK_RANGE*), 16, 16)) + if (my_init_dynamic_array(&min_max_ranges, sizeof(QUICK_RANGE*), 16, 16, + MYF(MY_THREAD_SPECIFIC))) return 1; if (have_min) @@ -13183,7 +13234,10 @@ int QUICK_GROUP_MIN_MAX_SELECT::reset(void) head->enable_keyread(); /* We need only the key attributes */ } if ((result= file->ha_index_init(index,1))) + { + head->file->print_error(result, MYF(0)); DBUG_RETURN(result); + } if (quick_prefix_select && quick_prefix_select->reset()) DBUG_RETURN(1); result= file->ha_index_last(record); @@ -13358,9 +13412,10 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min() */ if (min_max_arg_part && min_max_arg_part->field->is_null()) { + uchar *tmp_key_buff= (uchar*)my_alloca(max_used_key_length); /* Find the first subsequent record without NULL in the MIN/MAX field. */ - key_copy(tmp_record, record, index_info, max_used_key_length); - result= file->ha_index_read_map(record, tmp_record, + key_copy(tmp_key_buff, record, index_info, max_used_key_length); + result= file->ha_index_read_map(record, tmp_key_buff, make_keypart_map(real_key_parts), HA_READ_AFTER_KEY); /* @@ -13376,10 +13431,11 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min() if (!result) { if (key_cmp(index_info->key_part, group_prefix, real_prefix_len)) - key_restore(record, tmp_record, index_info, 0); + key_restore(record, tmp_key_buff, index_info, 0); } else if (result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) result= 0; /* There is a result in any case. */ + my_afree(tmp_key_buff); } } |