summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/include/mrr_tests.inc3
-rw-r--r--mysql-test/r/innodb_mrr.result1
-rw-r--r--mysql-test/r/maria_mrr.result1
-rw-r--r--mysql-test/r/myisam_mrr.result5
-rw-r--r--mysql-test/t/myisam_mrr.test2
-rw-r--r--sql/handler.h17
-rw-r--r--sql/multi_range_read.cc258
-rw-r--r--sql/multi_range_read.h63
-rw-r--r--sql/opt_range.cc4
-rw-r--r--sql/sql_join_cache.cc16
10 files changed, 206 insertions, 164 deletions
diff --git a/mysql-test/include/mrr_tests.inc b/mysql-test/include/mrr_tests.inc
index 21c419aa1a0..ad7dff61477 100644
--- a/mysql-test/include/mrr_tests.inc
+++ b/mysql-test/include/mrr_tests.inc
@@ -71,6 +71,9 @@ select b,filler from t3 where (b>='c-1011=w' and b<= 'c-1018=w') or
#
# Now try different keypart types and special values
#
+--disable_warnings
+drop table if exists t4;
+--enable_warnings
create table t4 (a varchar(10), b int, c char(10), filler char(200),
key idx1 (a, b, c));
diff --git a/mysql-test/r/innodb_mrr.result b/mysql-test/r/innodb_mrr.result
index 1e50a8b84ed..8949aec266a 100644
--- a/mysql-test/r/innodb_mrr.result
+++ b/mysql-test/r/innodb_mrr.result
@@ -168,6 +168,7 @@ c-1020=w filler
c-1021=w filler
c-1022=w filler
c-1023=w filler
+drop table if exists t4;
create table t4 (a varchar(10), b int, c char(10), filler char(200),
key idx1 (a, b, c));
insert into t4 (filler) select concat('NULL-', 15-a) from t2 order by a limit 15;
diff --git a/mysql-test/r/maria_mrr.result b/mysql-test/r/maria_mrr.result
index 9153d795a17..bf1173e0bed 100644
--- a/mysql-test/r/maria_mrr.result
+++ b/mysql-test/r/maria_mrr.result
@@ -169,6 +169,7 @@ c-1020=w filler
c-1021=w filler
c-1022=w filler
c-1023=w filler
+drop table if exists t4;
create table t4 (a varchar(10), b int, c char(10), filler char(200),
key idx1 (a, b, c));
insert into t4 (filler) select concat('NULL-', 15-a) from t2 order by a limit 15;
diff --git a/mysql-test/r/myisam_mrr.result b/mysql-test/r/myisam_mrr.result
index 8befb17e5ac..306b8cc4f51 100644
--- a/mysql-test/r/myisam_mrr.result
+++ b/mysql-test/r/myisam_mrr.result
@@ -1,4 +1,4 @@
-drop table if exists t1, t2, t3;
+drop table if exists t0, t1, t2, t3;
set @mrr_buffer_size_save= @@mrr_buffer_size;
set mrr_buffer_size=79;
Warnings:
@@ -170,6 +170,7 @@ c-1020=w filler
c-1021=w filler
c-1022=w filler
c-1023=w filler
+drop table if exists t4;
create table t4 (a varchar(10), b int, c char(10), filler char(200),
key idx1 (a, b, c));
insert into t4 (filler) select concat('NULL-', 15-a) from t2 order by a limit 15;
@@ -432,8 +433,8 @@ a a b
1 1 1
2 2 2
NULL NULL 1234
-NULL NULL 1234
NULL NULL 5678
+NULL NULL 1234
NULL NULL 5678
set @@join_cache_level=@save_join_cache_level;
drop table t0, t1;
diff --git a/mysql-test/t/myisam_mrr.test b/mysql-test/t/myisam_mrr.test
index 156528d3d29..82457ee4366 100644
--- a/mysql-test/t/myisam_mrr.test
+++ b/mysql-test/t/myisam_mrr.test
@@ -3,7 +3,7 @@
#
--disable_warnings
-drop table if exists t1, t2, t3;
+drop table if exists t0, t1, t2, t3;
--enable_warnings
set @mrr_buffer_size_save= @@mrr_buffer_size;
diff --git a/sql/handler.h b/sql/handler.h
index bf49698939c..c60f28afa42 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -1155,6 +1155,23 @@ typedef void *range_seq_t;
typedef struct st_range_seq_if
{
/*
+ Get key information
+
+ SYNOPSIS
+ get_key_info()
+ init_params The seq_init_param parameter
+ length OUT length of the keys in this range sequence
+ map OUT key_part_map of the keys in this range sequence
+
+ DESCRIPTION
+ This function is set only when using HA_MRR_FIXED_KEY mode. In that mode,
+ all ranges are single-point equality ranges that use the same set of key
+ parts. This function allows the MRR implementation to get the length of
+ a key, and which keyparts it uses.
+ */
+ void (*get_key_info)(void *init_params, uint *length, key_part_map *map);
+
+ /*
Initialize the traversal of range sequence
SYNOPSIS
diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc
index e92c6405057..01ddfef9c51 100644
--- a/sql/multi_range_read.cc
+++ b/sql/multi_range_read.cc
@@ -288,7 +288,9 @@ scan_it_again:
int Mrr_simple_index_reader::init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
void *seq_init_param, uint n_ranges,
- uint mode, Buffer_manager *buf_manager_arg)
+ uint mode, Key_parameters *key_par_arg,
+ Lifo_buffer *key_buffer_arg,
+ Buffer_manager *buf_manager_arg)
{
HANDLER_BUFFER no_buffer = {NULL, NULL, NULL};
h= h_arg;
@@ -332,42 +334,29 @@ int Mrr_ordered_index_reader::get_next(char **range_info)
int res;
DBUG_ENTER("Mrr_ordered_index_reader::get_next");
- if (!know_key_tuple_params)
- {
- //psergey-todo: this will be removed
- /*
- We're at the very start, haven't filled the buffer or even know what
- will be there. Force the caller to call refill_buffer():
- */
- DBUG_RETURN(HA_ERR_END_OF_FILE);
- }
-
for(;;)
{
- if (scanning_key_val_iter)
- {
- if ((res= kv_it.get_next()))
- {
- scanning_key_val_iter= FALSE;
- if ((res != HA_ERR_KEY_NOT_FOUND && res != HA_ERR_END_OF_FILE))
- DBUG_RETURN(res);
- kv_it.move_to_next_key_value();
- continue;
- }
- }
- else
+ if (!scanning_key_val_iter)
{
while ((res= kv_it.init(this)))
{
if ((res != HA_ERR_KEY_NOT_FOUND && res != HA_ERR_END_OF_FILE))
DBUG_RETURN(res); /* Some fatal error */
- if (key_buffer->is_empty()) //psergey-todo: the problem is here?
+ if (key_buffer->is_empty())
{
DBUG_RETURN(HA_ERR_END_OF_FILE);
}
}
scanning_key_val_iter= TRUE;
+ }
+
+ if ((res= kv_it.get_next()))
+ {
+ scanning_key_val_iter= FALSE;
+ if ((res != HA_ERR_KEY_NOT_FOUND && res != HA_ERR_END_OF_FILE))
+ DBUG_RETURN(res);
+ kv_it.move_to_next_key_value();
continue;
}
@@ -386,14 +375,6 @@ int Mrr_ordered_index_reader::get_next(char **range_info)
/**
Fill the buffer with (lookup_tuple, range_id) pairs and sort
-
- @note
- We don't know lookup_tuple before we get the first key from
- mrr_funcs.get_next(). Not knowing tuple length means we can't setup the
- key buffer (in particular, which part of the buffer space it should occupy
- when we have both key and rowid buffers). This problem is solved by having
- know_key_tuple_params variabe, and buf_manager, which we ask to set/reset
- buffers for us.
*/
int Mrr_ordered_index_reader::refill_buffer(bool initial)
@@ -403,45 +384,25 @@ int Mrr_ordered_index_reader::refill_buffer(bool initial)
uchar *key_ptr;
DBUG_ENTER("Mrr_ordered_index_reader::refill_buffer");
- DBUG_ASSERT(!know_key_tuple_params || key_buffer->is_empty());
+ DBUG_ASSERT(key_buffer->is_empty());
if (source_exhausted)
DBUG_RETURN(HA_ERR_END_OF_FILE);
- if (know_key_tuple_params)
+ //if (know_key_tuple_params)
{
- buf_manager->reset_buffer_sizes();
+ buf_manager->reset_buffer_sizes(buf_manager->arg);
key_buffer->reset();
key_buffer->setup_writing(&key_ptr, keypar.key_size_in_keybuf,
is_mrr_assoc? (uchar**)&range_info_ptr : NULL,
sizeof(uchar*));
}
- while ((!know_key_tuple_params || key_buffer->can_write()) &&
+ while (key_buffer->can_write() &&
!(source_exhausted= (bool)mrr_funcs.next(mrr_iter, &cur_range)))
{
DBUG_ASSERT(cur_range.range_flag & EQ_RANGE);
- if (!know_key_tuple_params)
- {
- /* This only happens when we've just started filling the buffer */
- key_range *sample_key= &cur_range.start_key;
- know_key_tuple_params= TRUE;
- keypar.key_tuple_length= sample_key->length;
- keypar.key_tuple_map= sample_key->keypart_map;
- keypar.key_size_in_keybuf= keypar.use_key_pointers ? sizeof(char*) : keypar.key_tuple_length;
- KEY *key_info= &h->get_table()->key_info[h->active_index];
- keypar.index_ranges_unique= test(key_info->flags & HA_NOSAME &&
- key_info->key_parts ==
- my_count_bits(sample_key->keypart_map));
- buf_manager->setup_buffer_sizes(keypar.key_size_in_keybuf, keypar.key_tuple_map);
- key_buffer= buf_manager->get_key_buffer();
- key_buffer->setup_writing(&key_ptr, keypar.key_size_in_keybuf,
- is_mrr_assoc? (uchar**)&range_info_ptr : NULL,
- sizeof(uchar*));
- DBUG_ASSERT(key_buffer->can_write());
- }
-
/* Put key, or {key, range_id} pair into the buffer */
key_ptr= (keypar.use_key_pointers)? (uchar*)&cur_range.start_key.key :
(uchar*)cur_range.start_key.key;
@@ -452,7 +413,7 @@ int Mrr_ordered_index_reader::refill_buffer(bool initial)
/* Force get_next() to start with kv_it.init() call: */
scanning_key_val_iter= FALSE;
- if (source_exhausted && (!know_key_tuple_params || key_buffer->is_empty()))
+ if (source_exhausted && key_buffer->is_empty())
DBUG_RETURN(HA_ERR_END_OF_FILE);
key_buffer->sort((key_buffer->type() == Lifo_buffer::FORWARD)?
@@ -465,16 +426,24 @@ int Mrr_ordered_index_reader::refill_buffer(bool initial)
int Mrr_ordered_index_reader::init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
void *seq_init_param, uint n_ranges,
- uint mode, Buffer_manager *buf_manager_arg)
+ uint mode, Key_parameters *key_par_arg,
+ Lifo_buffer *key_buffer_arg,
+ Buffer_manager *buf_manager_arg)
{
h= h_arg;
+ key_buffer= key_buffer_arg;
+ buf_manager= buf_manager_arg;
+ keypar= *key_par_arg;
+
+ KEY *key_info= &h->get_table()->key_info[h->active_index];
+ keypar.index_ranges_unique= test(key_info->flags & HA_NOSAME &&
+ key_info->key_parts ==
+ my_count_bits(keypar.key_tuple_map));
+
mrr_iter= seq_funcs->init(seq_init_param, n_ranges, mode);
- keypar.use_key_pointers= test(mode & HA_MRR_MATERIALIZED_KEYS);
is_mrr_assoc= !test(mode & HA_MRR_NO_ASSOCIATION);
mrr_funcs= *seq_funcs;
- know_key_tuple_params= FALSE;
source_exhausted= FALSE;
- buf_manager= buf_manager_arg;
/*
Short: don't do identical key handling when we have a pushed index
condition.
@@ -546,9 +515,6 @@ int Mrr_ordered_rndpos_reader::init(handler *h_arg,
When this function returns, either rowid buffer is not empty, or the source
of lookup keys (i.e. ranges) is exhaused.
- dsmrr_eof is set to indicate whether we've exhausted the list of ranges we're
- scanning. This function never returns HA_ERR_END_OF_FILE.
-
@retval 0 OK, the next portion of rowids is in the buffer,
properly ordered
@retval other Error
@@ -751,6 +717,11 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
{
THD *thd= current_thd;
int res;
+ Key_parameters keypar;
+ uint key_buff_elem_size;
+ handler *h_idx;
+ Mrr_ordered_rndpos_reader *disk_strategy= NULL;
+ bool do_sort_keys= FALSE;
DBUG_ENTER("DsMrr_impl::dsmrr_init");
/*
@@ -761,16 +732,14 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
is_mrr_assoc= !test(mode & HA_MRR_NO_ASSOCIATION);
strategy_exhausted= FALSE;
+
+ /* By default, have do-nothing buffer manager */
+ buf_manager.arg= this;
+ buf_manager.reset_buffer_sizes= do_nothing;
+ buf_manager.redistribute_buffer_space= do_nothing;
if (mode & (HA_MRR_USE_DEFAULT_IMPL | HA_MRR_SORTED))
- {
- DBUG_ASSERT(h->inited == handler::INDEX);
- /* Call correct init function and assign to top level object */
- Mrr_simple_index_reader *s= &reader_factory.simple_index_reader;
- res= s->init(h, seq_funcs, seq_init_param, n_ranges, mode, this);
- strategy= s;
- DBUG_RETURN(res);
- }
+ goto use_default_impl;
/*
Determine whether we'll need to do key sorting and/or rnd_pos() scan
@@ -779,6 +748,7 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
if ((mode & HA_MRR_SINGLE_POINT) &&
optimizer_flag(thd, OPTIMIZER_SWITCH_MRR_SORT_KEYS))
{
+ do_sort_keys= TRUE;
index_strategy= &reader_factory.ordered_index_reader;
}
else
@@ -794,10 +764,9 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
(h->inited == handler::RND && h2 &&
h2->inited == handler::INDEX));
- handler *h_idx= (h->inited == handler::INDEX)? h: h2;
+ h_idx= (h->inited == handler::INDEX)? h: h2;
keyno= h_idx->active_index;
- Mrr_ordered_rndpos_reader *disk_strategy= NULL;
if (!(keyno == table->s->primary_key && h_idx->primary_key_is_clustered()))
{
strategy= disk_strategy= &reader_factory.ordered_rndpos_reader;
@@ -808,29 +777,64 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
full_buf= buf->buffer;
full_buf_end= buf->buffer_end;
-
+
+ if (do_sort_keys)
+ {
+ /* Pre-calculate some parameters of key sorting */
+ keypar.use_key_pointers= test(mode & HA_MRR_MATERIALIZED_KEYS);
+ seq_funcs->get_key_info(seq_init_param, &keypar.key_tuple_length,
+ &keypar.key_tuple_map);
+ keypar.key_size_in_keybuf= keypar.use_key_pointers?
+ sizeof(char*) : keypar.key_tuple_length;
+ key_buff_elem_size= keypar.key_size_in_keybuf + (int)is_mrr_assoc * sizeof(void*);
+ }
+
if (strategy == index_strategy)
{
- /* Index strategy serves it all. We don't need two handlers, etc */
- /* Give the buffer to index strategy */
+ /*
+ Index strategy alone handles the record retrieval. Give all buffer space
+ to it. Key buffer should have forward orientation so we can return the
+ end of it.
+ */
+ key_buffer= &forward_key_buf;
+ key_buffer->set_buffer_space(full_buf, full_buf_end);
+
+ /* Safety: specify that rowid buffer has zero size: */
+ rowid_buffer.set_buffer_space(full_buf_end, full_buf_end);
+
+ if (do_sort_keys && !key_buffer->have_space_for(key_buff_elem_size))
+ goto use_default_impl;
+
if ((res= index_strategy->init(h, seq_funcs, seq_init_param, n_ranges,
- mode, this)))
+ mode, &keypar, key_buffer, &buf_manager)))
goto error;
}
else
{
- /*
- If we got here the request is served by both index and rndpos strategies
- working together.
+ /* We'll have both index and rndpos strategies working together */
+ if (do_sort_keys)
+ {
+ /* Both strategies will need buffer space, share the buffer */
+ if (setup_buffer_sharing(keypar.key_size_in_keybuf, keypar.key_tuple_map))
+ goto use_default_impl;
- */
- rowid_buffer.set_buffer_space(buf->buffer, buf->buffer_end);
+ buf_manager.reset_buffer_sizes= reset_buffer_sizes;
+ buf_manager.redistribute_buffer_space= redistribute_buffer_space;
+ }
+ else
+ {
+ /* index strategy doesn't need buffer, give all space to rowids*/
+ rowid_buffer.set_buffer_space(full_buf, full_buf_end);
+ if (!rowid_buffer.have_space_for(h->ref_length +
+ (int)is_mrr_assoc * sizeof(char*)))
+ goto use_default_impl;
+ }
if ((res= setup_two_handlers()))
goto error;
if ((res= index_strategy->init(h2, seq_funcs, seq_init_param, n_ranges,
- mode, this)) ||
+ mode, &keypar, key_buffer, &buf_manager)) ||
(res= disk_strategy->init(h, index_strategy, mode, &rowid_buffer)))
{
goto error;
@@ -859,6 +863,14 @@ error:
/* Safety, not really needed but: */
strategy= NULL;
DBUG_RETURN(1);
+
+use_default_impl:
+ DBUG_ASSERT(h->inited == handler::INDEX);
+ /* Call correct init function and assign to top level object */
+ Mrr_simple_index_reader *s= &reader_factory.simple_index_reader;
+ res= s->init(h, seq_funcs, seq_init_param, n_ranges, mode, NULL, NULL, NULL);
+ strategy= s;
+ DBUG_RETURN(res);
}
@@ -1010,34 +1022,23 @@ int Mrr_ordered_index_reader::compare_keys_reverse(void* arg, uchar* key1,
/**
- Setup key/rowid buffer sizes based on sample_key and its length.
-
- @param
- sample_key A lookup key to use as a sample. It is assumed that
- all other keys will have the same length/etc.
- @note
- This function must be called when all buffers are empty
+ Set the buffer space to be shared between rowid and key buffer
+
+ @return FALSE ok
+ @return TRUE There is so little buffer space that we won't be able to use
+ the strategy.
+ This happens when we don't have enough space for one rowid
+ element and one key element so this is mainly targeted at
+ testing.
*/
-void DsMrr_impl::setup_buffer_sizes(uint key_size_in_keybuf,
- key_part_map key_tuple_map)
+bool DsMrr_impl::setup_buffer_sharing(uint key_size_in_keybuf,
+ key_part_map key_tuple_map)
{
uint key_buff_elem_size= key_size_in_keybuf +
(int)is_mrr_assoc * sizeof(void*);
KEY *key_info= &h->get_table()->key_info[keyno];
- if (strategy == index_strategy)
- {
- /* Give all space to the key buffer, key buffer must be forward */
- key_buffer= &forward_key_buf;
- key_buffer->set_buffer_space(full_buf, full_buf_end);
- DBUG_ASSERT(key_buffer->have_space_for(key_buff_elem_size));
-
- /* Just in case, tell rowid buffer that it has zero size: */
- rowid_buffer.set_buffer_space(full_buf_end, full_buf_end);
- return;
- }
-
/*
Ok if we got here we need to allocate one part of the buffer
for keys and another part for rowids.
@@ -1048,7 +1049,6 @@ void DsMrr_impl::setup_buffer_sizes(uint key_size_in_keybuf,
/*
Use rec_per_key statistics as a basis to find out how many rowids
we'll get for each key value.
- TODO: are we guaranteed to get r_p_c==1 for unique keys?
TODO: what should be the default value to use when there is no
statistics?
*/
@@ -1065,45 +1065,48 @@ void DsMrr_impl::setup_buffer_sizes(uint key_size_in_keybuf,
size_t bytes_for_rowids=
round(fraction_for_rowids * (full_buf_end - full_buf));
- uint bytes_for_keys= (full_buf_end - full_buf) - bytes_for_rowids;
+ long bytes_for_keys= (full_buf_end - full_buf) - bytes_for_rowids;
if (bytes_for_keys < key_buff_elem_size + 1)
{
- ulong add= key_buff_elem_size + 1 - bytes_for_keys;
+ long add= key_buff_elem_size + 1 - bytes_for_keys;
bytes_for_keys= key_buff_elem_size + 1;
bytes_for_rowids -= add;
- DBUG_ASSERT(bytes_for_rowids >= rowid_buf_elem_size + 1);
}
if (bytes_for_rowids < rowid_buf_elem_size + 1)
{
- ulong add= rowid_buf_elem_size + 1 - bytes_for_rowids;
+ long add= rowid_buf_elem_size + 1 - bytes_for_rowids;
bytes_for_rowids= rowid_buf_elem_size + 1;
bytes_for_keys -= add;
- DBUG_ASSERT(bytes_for_keys >= key_buff_elem_size + 1);
}
rowid_buffer_end= full_buf + bytes_for_rowids;
rowid_buffer.set_buffer_space(full_buf, rowid_buffer_end);
key_buffer= &backward_key_buf;
key_buffer->set_buffer_space(rowid_buffer_end, full_buf_end);
- DBUG_ASSERT(key_buffer->have_space_for(key_buff_elem_size));
- DBUG_ASSERT(rowid_buffer.have_space_for(rowid_buf_elem_size));
+
+ if (!key_buffer->have_space_for(key_buff_elem_size) ||
+ !rowid_buffer.have_space_for(rowid_buf_elem_size))
+ return TRUE; /* Failed to provide minimum space for one of the buffers */
+
+ return FALSE;
}
-void DsMrr_impl::reset_buffer_sizes()
+void DsMrr_impl::do_nothing(void *dsmrr_arg)
{
- if (strategy != index_strategy)
- {
- /*
- Ok we have both ordered index reader and there is a disk rearder.
- Redistribute the buffer space.
- */
- rowid_buffer.set_buffer_space(full_buf, rowid_buffer_end);
- key_buffer= &backward_key_buf;
- key_buffer->set_buffer_space(rowid_buffer_end, full_buf_end);
- }
+ /* Do nothing */
+}
+
+
+void DsMrr_impl::reset_buffer_sizes(void *dsmrr_arg)
+{
+ DsMrr_impl *dsmrr= (DsMrr_impl*)dsmrr_arg;
+ dsmrr->rowid_buffer.set_buffer_space(dsmrr->full_buf,
+ dsmrr->rowid_buffer_end);
+ dsmrr->key_buffer->set_buffer_space(dsmrr->rowid_buffer_end,
+ dsmrr->full_buf_end);
}
@@ -1111,11 +1114,12 @@ void DsMrr_impl::reset_buffer_sizes()
Take unused space from the key buffer and give it to the rowid buffer
*/
-void DsMrr_impl::redistribute_buffer_space()
+void DsMrr_impl::redistribute_buffer_space(void *dsmrr_arg)
{
+ DsMrr_impl *dsmrr= (DsMrr_impl*)dsmrr_arg;
uchar *unused_start, *unused_end;
- key_buffer->remove_unused_space(&unused_start, &unused_end);
- rowid_buffer.grow(unused_start, unused_end);
+ dsmrr->key_buffer->remove_unused_space(&unused_start, &unused_end);
+ dsmrr->rowid_buffer.grow(unused_start, unused_end);
}
diff --git a/sql/multi_range_read.h b/sql/multi_range_read.h
index 13baac0a0dc..2b168869d9d 100644
--- a/sql/multi_range_read.h
+++ b/sql/multi_range_read.h
@@ -56,9 +56,6 @@ class Mrr_ordered_index_reader;
class Key_parameters
{
public:
- /* TRUE <=> We can get at most one index tuple for a lookup key */
- bool index_ranges_unique;
-
uint key_tuple_length; /* Length of index lookup tuple, in bytes */
key_part_map key_tuple_map; /* keyparts used in index lookup tuples */
@@ -71,6 +68,9 @@ public:
/* TRUE <=> don't copy key values, use pointers to them instead. */
bool use_key_pointers;
+
+ /* TRUE <=> We can get at most one index tuple for a lookup key */
+ bool index_ranges_unique;
};
@@ -145,28 +145,27 @@ public:
Buffer manager interface. Mrr_reader objects use it to inqure DsMrr_impl
to manage buffer space for them.
*/
-class Buffer_manager
+typedef struct st_buffer_manager
{
public:
- /*
- Index-based reader calls this when it gets the first key, so we get to know
- key length and
+ /* Opaque value to be passed as the first argument to all member functions */
+ void *arg;
+
+ /*
+ This is called when we've freed more space from the rowid buffer. The
+ callee will get the unused space from the rowid buffer and give it to the
+ key buffer.
*/
- virtual void setup_buffer_sizes(uint key_size_in_keybuf,
- key_part_map key_tuple_map) = 0;
+ void (*redistribute_buffer_space)(void *arg);
- virtual void redistribute_buffer_space() = 0;
/*
This is called when both key and rowid buffers are empty, and so it's time
to reset them to their original size (They've lost their original size,
because we were dynamically growing rowid buffer and shrinking key buffer).
*/
- virtual void reset_buffer_sizes() = 0;
+ void (*reset_buffer_sizes)(void *arg);
- virtual Lifo_buffer* get_key_buffer() = 0;
-
- virtual ~Buffer_manager(){} /* Shut up the compiler */
-};
+} Buffer_manager;
/*
@@ -205,7 +204,9 @@ protected:
public:
virtual int init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
void *seq_init_param, uint n_ranges,
- uint mode, Buffer_manager *buf_manager_arg) = 0;
+ uint mode, Key_parameters *key_par,
+ Lifo_buffer *key_buffer,
+ Buffer_manager *buf_manager_arg) = 0;
/* Get pointer to place where every get_next() call will put rowid */
virtual uchar *get_rowid_ptr() = 0;
@@ -224,9 +225,11 @@ public:
class Mrr_simple_index_reader : public Mrr_index_reader
{
public:
- int init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
+ int init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
void *seq_init_param, uint n_ranges,
- uint mode, Buffer_manager *buf_manager_arg);
+ uint mode, Key_parameters *key_par,
+ Lifo_buffer *key_buffer,
+ Buffer_manager *buf_manager_arg);
int get_next(char **range_info);
int refill_buffer(bool initial) { return initial? 0: HA_ERR_END_OF_FILE; }
uchar *get_rowid_ptr() { return h->ref; }
@@ -247,7 +250,9 @@ class Mrr_ordered_index_reader : public Mrr_index_reader
public:
int init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
void *seq_init_param, uint n_ranges,
- uint mode, Buffer_manager *buf_manager_arg);
+ uint mode, Key_parameters *key_par,
+ Lifo_buffer *key_buffer,
+ Buffer_manager *buf_manager_arg);
int get_next(char **range_info);
int refill_buffer(bool initial);
uchar *get_rowid_ptr() { return h->ref; }
@@ -278,12 +283,6 @@ private:
/* This manages key buffer allocation and sizing for us */
Buffer_manager *buf_manager;
- /*
- Initially FALSE, becomes TRUE when we saw the first lookup key and set
- keypar's member.
- */
- bool know_key_tuple_params;
-
Key_parameters keypar; /* index scan and lookup tuple parameters */
/* TRUE <=> need range association, buffers hold {rowid, range_id} pairs */
@@ -498,7 +497,7 @@ public:
*/
-class DsMrr_impl : public Buffer_manager
+class DsMrr_impl
{
public:
typedef void (handler::*range_check_toggle_func_t)(bool on);
@@ -582,10 +581,14 @@ private:
uint *buffer_size, COST_VECT *cost);
bool check_cpk_scan(THD *thd, uint keyno, uint mrr_flags);
- /* Buffer_manager implementation */
- void setup_buffer_sizes(uint key_size_in_keybuf, key_part_map key_tuple_map);
- void redistribute_buffer_space();
- void reset_buffer_sizes();
+ bool setup_buffer_sharing(uint key_size_in_keybuf, key_part_map key_tuple_map);
+
+ /* Buffer_manager and its member functions */
+ Buffer_manager buf_manager;
+ static void redistribute_buffer_space(void *dsmrr_arg);
+ static void reset_buffer_sizes(void *dsmrr_arg);
+ static void do_nothing(void *dsmrr_arg);
+
Lifo_buffer* get_key_buffer() { return key_buffer; }
friend class Key_value_records_iterator;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index b39d96f6474..2b3bc1528b3 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -7449,7 +7449,7 @@ ha_rows check_quick_select(PARAM *param, uint idx, bool index_only,
uint *mrr_flags, uint *bufsize, COST_VECT *cost)
{
SEL_ARG_RANGE_SEQ seq;
- RANGE_SEQ_IF seq_if = {sel_arg_range_seq_init, sel_arg_range_seq_next, 0, 0};
+ RANGE_SEQ_IF seq_if = {NULL, sel_arg_range_seq_init, sel_arg_range_seq_next, 0, 0};
handler *file= param->table->file;
ha_rows rows;
uint keynr= param->real_keynr[idx];
@@ -8377,7 +8377,7 @@ int QUICK_RANGE_SELECT::reset()
if (!mrr_buf_desc)
empty_buf.buffer= empty_buf.buffer_end= empty_buf.end_of_used_area= NULL;
- RANGE_SEQ_IF seq_funcs= {quick_range_seq_init, quick_range_seq_next, 0, 0};
+ RANGE_SEQ_IF seq_funcs= {NULL, quick_range_seq_init, quick_range_seq_next, 0, 0};
error= file->multi_range_read_init(&seq_funcs, (void*)this, ranges.elements,
mrr_flags, mrr_buf_desc? mrr_buf_desc:
&empty_buf);
diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc
index 88f95142686..9a32a1a6598 100644
--- a/sql/sql_join_cache.cc
+++ b/sql/sql_join_cache.cc
@@ -3597,6 +3597,16 @@ int JOIN_TAB_SCAN_MRR::next()
}
+static
+void bka_range_seq_key_info(void *init_params, uint *length,
+ key_part_map *map)
+{
+ TABLE_REF *ref= &(((JOIN_CACHE*)init_params)->join_tab->ref);
+ *length= ref->key_length;
+ *map= (key_part_map(1) << ref->key_parts) - 1;
+}
+
+
/*
Initialize retrieval of range sequence for BKA join algorithm
@@ -3876,7 +3886,8 @@ int JOIN_CACHE_BKA::init()
int res;
bool check_only_first_match= join_tab->check_only_first_match();
- RANGE_SEQ_IF rs_funcs= { bka_range_seq_init,
+ RANGE_SEQ_IF rs_funcs= { bka_range_seq_key_info,
+ bka_range_seq_init,
bka_range_seq_next,
check_only_first_match ?
bka_range_seq_skip_record : 0,
@@ -4265,7 +4276,8 @@ int JOIN_CACHE_BKAH::init()
no_association= test(mrr_mode & HA_MRR_NO_ASSOCIATION);
- RANGE_SEQ_IF rs_funcs= { bkah_range_seq_init,
+ RANGE_SEQ_IF rs_funcs= { bka_range_seq_key_info,
+ bkah_range_seq_init,
bkah_range_seq_next,
check_only_first_match && !no_association ?
bkah_range_seq_skip_record : 0,