Address review feedback
- One iterator class - Switch back from state automaton into two-nested-iterators approach..
This commit is contained in:
parent
22d5323fac
commit
5156457506
@ -462,7 +462,6 @@ SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||
LEFT JOIN
|
||||
(t1,t2)
|
||||
ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b;
|
||||
|
||||
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||
FROM (t3,t4)
|
||||
LEFT JOIN
|
||||
|
@ -586,6 +586,7 @@ if (`select @@join_cache_level=6`)
|
||||
--echo # Not anymore:
|
||||
--echo # The following query gives wrong result due to Bug#49129
|
||||
}
|
||||
select sin(0);
|
||||
select * from t0 where t0.a in
|
||||
(select t1.a from t1, t2 where t2.a=t0.a and t1.b=t2.b);
|
||||
|
||||
|
@ -682,7 +682,7 @@ void DsMrr_impl::setup_buffer_sizes(key_range *sample_key)
|
||||
{
|
||||
/* Give all space to forward key buffer. */
|
||||
key_buffer= &forward_key_buf;
|
||||
identical_key_it= &forward_key_it;
|
||||
//identical_key_it= &forward_key_it;
|
||||
key_buffer->set_buffer_space(full_buf, full_buf_end);
|
||||
|
||||
/* Just in case, tell rowid buffer that it has zero size: */
|
||||
@ -731,7 +731,7 @@ void DsMrr_impl::setup_buffer_sizes(key_range *sample_key)
|
||||
rowid_buffer_end= full_buf + bytes_for_rowids;
|
||||
rowid_buffer.set_buffer_space(full_buf, rowid_buffer_end);
|
||||
key_buffer= &backward_key_buf;
|
||||
identical_key_it= &backward_key_it;
|
||||
//identical_key_it= &backward_key_it;
|
||||
key_buffer->set_buffer_space(rowid_buffer_end, full_buf_end);
|
||||
}
|
||||
|
||||
@ -771,7 +771,7 @@ void DsMrr_impl::dsmrr_fill_key_buffer()
|
||||
*/
|
||||
rowid_buffer.set_buffer_space(full_buf, rowid_buffer_end);
|
||||
key_buffer= &backward_key_buf;
|
||||
identical_key_it= &backward_key_it;
|
||||
//identical_key_it= &backward_key_it;
|
||||
key_buffer->set_buffer_space(rowid_buffer_end, full_buf_end);
|
||||
}
|
||||
key_buffer->reset();
|
||||
@ -815,9 +815,12 @@ void DsMrr_impl::dsmrr_fill_key_buffer()
|
||||
is_mrr_assoc? (uchar**)&cur_range_info: NULL,
|
||||
sizeof(void*));
|
||||
|
||||
last_identical_key_ptr= NULL;
|
||||
//last_identical_key_ptr= NULL;
|
||||
//in_identical_keys_range= FALSE;
|
||||
index_scan_state= GET_NEXT_RANGE;
|
||||
//index_scan_state= GET_NEXT_RANGE;
|
||||
scanning_key_val_iter= FALSE;
|
||||
index_scan_eof= FALSE;
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -834,22 +837,88 @@ void DsMrr_impl::reallocate_buffer_space()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Read out ranges from the buffer until we've reached the range with
|
||||
last_identical_key_ptr.
|
||||
*/
|
||||
|
||||
void DsMrr_impl::read_out_identical_ranges()
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
bool Key_value_records_iterator::init(DsMrr_impl *dsmrr_arg)
|
||||
{
|
||||
if (last_identical_key_ptr)
|
||||
int res;
|
||||
dsmrr= dsmrr_arg;
|
||||
handler *file= dsmrr->do_rndpos_scan? dsmrr->h2 : dsmrr->h;
|
||||
|
||||
identical_key_it.init(dsmrr->key_buffer);
|
||||
/* Get the first pair into (cur_index_tuple, cur_range_info) */
|
||||
if (identical_key_it.read())
|
||||
return TRUE;
|
||||
|
||||
uchar *key_in_buf= dsmrr->cur_index_tuple;
|
||||
|
||||
if (dsmrr->use_key_pointers)
|
||||
dsmrr->cur_index_tuple= *((uchar**)dsmrr->cur_index_tuple);
|
||||
|
||||
/* Check out how many more identical keys are following */
|
||||
//char *save_cur_range_info= cur_range_info;
|
||||
uchar *save_cur_index_tuple= dsmrr->cur_index_tuple;
|
||||
last_identical_key_ptr= dsmrr->cur_index_tuple;
|
||||
while (!identical_key_it.read())
|
||||
{
|
||||
/* key_buffer.read() reads to (cur_index_tuple, cur_range_info) */
|
||||
while (!key_buffer->read() && (cur_index_tuple != last_identical_key_ptr)) {}
|
||||
last_identical_key_ptr= NULL;
|
||||
if (DsMrr_impl::key_tuple_cmp(dsmrr, key_in_buf, dsmrr->cur_index_tuple))
|
||||
break;
|
||||
last_identical_key_ptr= dsmrr->cur_index_tuple;
|
||||
}
|
||||
identical_key_it.init(dsmrr->key_buffer);
|
||||
dsmrr->cur_index_tuple= save_cur_index_tuple;
|
||||
//cur_range_info= save_cur_range_info;
|
||||
res= file->ha_index_read_map(dsmrr->table->record[0],
|
||||
dsmrr->cur_index_tuple,
|
||||
dsmrr->key_tuple_map,
|
||||
HA_READ_KEY_EXACT);
|
||||
|
||||
if (res)
|
||||
{
|
||||
close();
|
||||
return res; /* Fatal error */
|
||||
}
|
||||
get_next_row= FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Key_value_records_iterator::get_next()
|
||||
{
|
||||
handler *file= dsmrr->do_rndpos_scan? dsmrr->h2 : dsmrr->h;
|
||||
int res;
|
||||
|
||||
if (get_next_row)
|
||||
{
|
||||
if (dsmrr->index_ranges_unique)
|
||||
return HA_ERR_END_OF_FILE; /* Max one match */
|
||||
|
||||
if ((res= file->ha_index_next_same(dsmrr->table->record[0],
|
||||
dsmrr->cur_index_tuple,
|
||||
dsmrr->key_tuple_length)))
|
||||
{
|
||||
/* EOF is EOF for iterator, also, any error means EOF on the iterator */
|
||||
return res;
|
||||
}
|
||||
identical_key_it.init(dsmrr->key_buffer);
|
||||
}
|
||||
|
||||
identical_key_it.read(); // This gets us next range_id.
|
||||
if (!last_identical_key_ptr || (dsmrr->cur_index_tuple == last_identical_key_ptr))
|
||||
{
|
||||
get_next_row= TRUE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Key_value_records_iterator::close()
|
||||
{
|
||||
while (!dsmrr->key_buffer->read() &&
|
||||
(dsmrr->cur_index_tuple != last_identical_key_ptr)) {}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
DS-MRR/CPK: multi_range_read_next() function
|
||||
@ -871,154 +940,55 @@ void DsMrr_impl::read_out_identical_ranges()
|
||||
@retval HA_ERR_END_OF_FILE End of records
|
||||
@retval Other Some other error
|
||||
*/
|
||||
|
||||
int DsMrr_impl::dsmrr_next_from_index(char **range_info_arg)
|
||||
{
|
||||
DBUG_ENTER("DsMrr_impl::dsmrr_next_from_index");
|
||||
int res;
|
||||
handler *file= do_rndpos_scan? h2: h;
|
||||
|
||||
//handler *file= do_rndpos_scan? h2: h;
|
||||
|
||||
while (1)
|
||||
{
|
||||
bool have_record= FALSE;
|
||||
switch (index_scan_state)
|
||||
if (scanning_key_val_iter)
|
||||
{
|
||||
case GET_NEXT_IDENTICAL_KEY:
|
||||
if (kv_it.get_next())
|
||||
{
|
||||
/* Get the next range_id for the current record */
|
||||
|
||||
/* read to (cur_index_tuple, cur_range_info) */
|
||||
bool bres= identical_key_it->read_next();
|
||||
DBUG_ASSERT(!bres);
|
||||
|
||||
if (cur_index_tuple == last_identical_key_ptr)
|
||||
{
|
||||
/*
|
||||
We've just got to the last of identical ranges. Next step is to
|
||||
go next record
|
||||
*/
|
||||
index_scan_state= index_ranges_unique? GET_NEXT_RANGE : GET_NEXT_RECORD;
|
||||
}
|
||||
kv_it.close();
|
||||
scanning_key_val_iter= FALSE;
|
||||
}
|
||||
else
|
||||
have_record= TRUE;
|
||||
break;
|
||||
}
|
||||
case GET_NEXT_RECORD:
|
||||
}
|
||||
else
|
||||
{
|
||||
while (kv_it.init(this))
|
||||
{
|
||||
/* Get the next record from the range */
|
||||
res= file->ha_index_next_same(table->record[0], cur_index_tuple,
|
||||
key_tuple_length);
|
||||
if (res)
|
||||
{
|
||||
if (res != HA_ERR_END_OF_FILE && res != HA_ERR_KEY_NOT_FOUND)
|
||||
DBUG_RETURN(res); /* Fatal error */
|
||||
|
||||
/* Got EOF for this range, go get the next range */
|
||||
index_scan_state= GET_NEXT_RANGE;
|
||||
break;
|
||||
}
|
||||
|
||||
have_record= TRUE;
|
||||
if (last_identical_key_ptr)
|
||||
{
|
||||
/*
|
||||
If the range we're scanning is one of the set of identical ranges,
|
||||
return this record with range_id of each range
|
||||
*/
|
||||
index_scan_state= GET_NEXT_IDENTICAL_KEY;
|
||||
identical_key_it->init(key_buffer);
|
||||
cur_range_info= first_identical_range_info;
|
||||
have_record= FALSE; //psergey4
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GET_NEXT_RANGE:
|
||||
{
|
||||
read_out_identical_ranges();
|
||||
if (do_rndpos_scan)
|
||||
reallocate_buffer_space();
|
||||
|
||||
/* Get the next range to scan */
|
||||
if (key_buffer->read()) /* read to (cur_index_tuple,cur_range_info) */
|
||||
{
|
||||
index_scan_state= REFILL_KEY_BUFFER;
|
||||
break;
|
||||
}
|
||||
uchar *key_in_buf= cur_index_tuple;
|
||||
|
||||
if (use_key_pointers)
|
||||
cur_index_tuple= *((uchar**)cur_index_tuple);
|
||||
|
||||
res= file->ha_index_read_map(table->record[0], cur_index_tuple,
|
||||
key_tuple_map, HA_READ_KEY_EXACT);
|
||||
|
||||
if (res && res != HA_ERR_END_OF_FILE && res != HA_ERR_KEY_NOT_FOUND)
|
||||
DBUG_RETURN(res); /* Fatal error */
|
||||
|
||||
/*
|
||||
Check if subsequent elements in the key buffer are the same as this
|
||||
one
|
||||
*/
|
||||
char *save_cur_range_info= cur_range_info;
|
||||
identical_key_it->init(key_buffer);
|
||||
last_identical_key_ptr= NULL;
|
||||
while (!identical_key_it->read_next())
|
||||
{
|
||||
if (key_tuple_cmp(this, key_in_buf, cur_index_tuple))
|
||||
break;
|
||||
last_identical_key_ptr= cur_index_tuple;
|
||||
}
|
||||
cur_range_info= save_cur_range_info;
|
||||
|
||||
if (last_identical_key_ptr)
|
||||
{
|
||||
index_scan_state= GET_NEXT_IDENTICAL_KEY;
|
||||
identical_key_it->init(key_buffer);
|
||||
first_identical_range_info= cur_range_info;
|
||||
have_record= FALSE; //psergey4
|
||||
}
|
||||
else
|
||||
{
|
||||
index_scan_state= index_ranges_unique? GET_NEXT_RANGE : GET_NEXT_RECORD;
|
||||
have_record= TRUE;
|
||||
}
|
||||
|
||||
if (res)
|
||||
{
|
||||
read_out_identical_ranges();
|
||||
index_scan_state= GET_NEXT_RANGE;
|
||||
have_record= FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case REFILL_KEY_BUFFER:
|
||||
{
|
||||
if (dsmrr_eof)
|
||||
{
|
||||
index_scan_state= SCAN_FINISHED;
|
||||
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
||||
}
|
||||
|
||||
/*
|
||||
When rowid fetching is used, it controls all buffer refills. When we're
|
||||
on our own, try refilling our buffer.
|
||||
*/
|
||||
if (!do_rndpos_scan)
|
||||
dsmrr_fill_key_buffer();
|
||||
|
||||
/* Failed to initialize iterator */
|
||||
if (key_buffer->is_empty())
|
||||
{
|
||||
index_scan_state= SCAN_FINISHED;
|
||||
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
||||
}
|
||||
if (dsmrr_eof)
|
||||
{
|
||||
index_scan_eof= TRUE;
|
||||
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
||||
}
|
||||
|
||||
index_scan_state= GET_NEXT_RANGE;
|
||||
/*
|
||||
When rowid fetching is used, it controls all buffer refills. When we're
|
||||
on our own, try refilling our buffer.
|
||||
*/
|
||||
if (!do_rndpos_scan)
|
||||
dsmrr_fill_key_buffer();
|
||||
|
||||
if (key_buffer->is_empty())
|
||||
{
|
||||
index_scan_eof= TRUE;
|
||||
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
break;
|
||||
/* if we got here, it means iterator was successfully initialized */
|
||||
scanning_key_val_iter= TRUE;
|
||||
}
|
||||
|
||||
|
||||
if (have_record &&
|
||||
(!h->mrr_funcs.skip_index_tuple ||
|
||||
!h->mrr_funcs.skip_index_tuple(h->mrr_iter, *(char**)cur_range_info))
|
||||
@ -1030,156 +1000,11 @@ int DsMrr_impl::dsmrr_next_from_index(char **range_info_arg)
|
||||
}
|
||||
/* Go get another (record, range_id) combination */
|
||||
} /* while */
|
||||
|
||||
|
||||
memcpy(range_info_arg, cur_range_info, sizeof(void*));
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
int DsMrr_impl::dsmrr_next_from_index(char **range_info_arg)
|
||||
{
|
||||
int res;
|
||||
uchar *key_in_buf;
|
||||
handler *file= do_rndpos_scan? h2: h;
|
||||
bool res2;
|
||||
|
||||
while (in_identical_keys_range)
|
||||
{
|
||||
/* This will read to (cur_index_tuple, cur_range_info): */
|
||||
res2= identical_key_it->read_next();
|
||||
DBUG_ASSERT(!res2);
|
||||
|
||||
if (cur_index_tuple == last_identical_key_ptr)
|
||||
{
|
||||
/* We're looking at the last of the identical keys */
|
||||
in_identical_keys_range= FALSE;
|
||||
}
|
||||
check_record:
|
||||
if ((h->mrr_funcs.skip_index_tuple &&
|
||||
h->mrr_funcs.skip_index_tuple(h->mrr_iter, *(char**)cur_range_info)) ||
|
||||
(h->mrr_funcs.skip_record &&
|
||||
h->mrr_funcs.skip_record(h->mrr_iter, *(char**)cur_range_info, NULL)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
memcpy(range_info_arg, cur_range_info, sizeof(void*));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try returrning next record from the current range */
|
||||
while (in_index_range)
|
||||
{
|
||||
res= file->ha_index_next_same(table->record[0], cur_index_tuple,
|
||||
key_tuple_length);
|
||||
|
||||
if (res)
|
||||
{
|
||||
if (res != HA_ERR_END_OF_FILE && res != HA_ERR_KEY_NOT_FOUND)
|
||||
return res; /* Fatal error */
|
||||
|
||||
in_index_range= FALSE; /* no more records here */
|
||||
break;
|
||||
}
|
||||
|
||||
if (last_identical_key_ptr)
|
||||
{
|
||||
in_identical_keys_range= TRUE;
|
||||
identical_key_it->init(key_buffer);
|
||||
cur_range_info= first_identical_range_info;
|
||||
}
|
||||
|
||||
goto check_record;
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
DBUG_ASSERT(!in_identical_keys_range && !in_index_range);
|
||||
|
||||
/* Jump over the keys that were handled by identical key processing */
|
||||
if (last_identical_key_ptr)
|
||||
{
|
||||
/* key_buffer.read() reads to (cur_index_tuple, cur_range_info) */
|
||||
while (!key_buffer->read() && (cur_index_tuple != last_identical_key_ptr)) {}
|
||||
last_identical_key_ptr= NULL;
|
||||
}
|
||||
|
||||
/* First, make sure we have a range at start of the buffer */
|
||||
if (key_buffer->is_empty())
|
||||
{
|
||||
if (dsmrr_eof)
|
||||
{
|
||||
res= HA_ERR_END_OF_FILE;
|
||||
goto end;
|
||||
}
|
||||
/*
|
||||
When rowid fetching is used, it controls all buffer refills. When we're
|
||||
on our own, try refilling our buffer.
|
||||
*/
|
||||
if (!do_rndpos_scan)
|
||||
dsmrr_fill_key_buffer();
|
||||
|
||||
if (key_buffer->is_empty())
|
||||
{
|
||||
res= HA_ERR_END_OF_FILE;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
At this point we're not using anything what we've read from key
|
||||
buffer. Cut off unused key buffer space and give it to the rowid
|
||||
buffer.
|
||||
*/
|
||||
if (do_rndpos_scan)
|
||||
reallocate_buffer_space();
|
||||
|
||||
/* Get the next range to scan */
|
||||
key_buffer->read(); // reads to (cur_index_tuple, cur_range_info)
|
||||
key_in_buf= cur_index_tuple;
|
||||
|
||||
if (use_key_pointers)
|
||||
cur_index_tuple= *((uchar**)cur_index_tuple);
|
||||
|
||||
/* Do index lookup */
|
||||
if ((res= file->ha_index_read_map(table->record[0], cur_index_tuple,
|
||||
key_tuple_map, HA_READ_KEY_EXACT)))
|
||||
{
|
||||
if (res != HA_ERR_END_OF_FILE && res != HA_ERR_KEY_NOT_FOUND)
|
||||
return res;
|
||||
continue; /* to next key and make another lookup */
|
||||
}
|
||||
|
||||
/* Check if subsequent keys in the key buffer are the same as this one */
|
||||
{
|
||||
char *save_cur_range_info= cur_range_info;
|
||||
identical_key_it->init(key_buffer);
|
||||
last_identical_key_ptr= NULL;
|
||||
while (!identical_key_it->read_next())
|
||||
{
|
||||
if (key_tuple_cmp(this, key_in_buf, cur_index_tuple))
|
||||
break;
|
||||
|
||||
last_identical_key_ptr= cur_index_tuple;
|
||||
}
|
||||
cur_range_info= save_cur_range_info;
|
||||
if (last_identical_key_ptr)
|
||||
{
|
||||
in_identical_keys_range= TRUE;
|
||||
identical_key_it->init(key_buffer);
|
||||
first_identical_range_info= cur_range_info;
|
||||
}
|
||||
}
|
||||
|
||||
in_index_range= !index_ranges_unique;
|
||||
goto check_record;
|
||||
}
|
||||
|
||||
end:
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
DS-MRR implementation: multi_range_read_next() function.
|
||||
|
||||
@ -1227,7 +1052,7 @@ int DsMrr_impl::dsmrr_next(char **range_info)
|
||||
{
|
||||
if (do_sort_keys)
|
||||
{
|
||||
if (index_scan_state != SCAN_FINISHED)
|
||||
if (index_scan_eof)
|
||||
{
|
||||
/* There are some sorted keys left. Use them to get rowids */
|
||||
if ((res= dsmrr_fill_rowid_buffer()))
|
||||
@ -1288,9 +1113,9 @@ int DsMrr_impl::dsmrr_next(char **range_info)
|
||||
Note: this implies that SQL layer doesn't touch table->record[0]
|
||||
between calls.
|
||||
*/
|
||||
Forward_iterator it;
|
||||
Lifo_buffer_iterator it;
|
||||
it.init(&rowid_buffer);
|
||||
while (!it.read_next()) // reads to (rowid, ...)
|
||||
while (!it.read()) // reads to (rowid, ...)
|
||||
{
|
||||
if (h2->cmp_ref(rowid, cur_rowid))
|
||||
break;
|
||||
|
@ -48,6 +48,37 @@
|
||||
|
||||
#include "sql_lifo_buffer.h"
|
||||
|
||||
class DsMrr_impl;
|
||||
|
||||
/**
|
||||
Iterator over (record, range_id) pairs that match given key value.
|
||||
|
||||
We may need to scan multiple (key_val, range_id) pairs with the same
|
||||
key value. A key value may have multiple matching records, so we'll need to
|
||||
produce a cross-product of sets of matching records and range_id-s.
|
||||
*/
|
||||
|
||||
class Key_value_records_iterator
|
||||
{
|
||||
/* Scan parameters */
|
||||
DsMrr_impl *dsmrr;
|
||||
Lifo_buffer_iterator identical_key_it;
|
||||
uchar *last_identical_key_ptr;
|
||||
bool get_next_row;
|
||||
public:
|
||||
/*
|
||||
*/
|
||||
bool init(DsMrr_impl *dsmrr);
|
||||
|
||||
/*
|
||||
Get next (key_val, range_id) pair.
|
||||
*/
|
||||
int get_next();
|
||||
|
||||
void close();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
DS-MRR implementation for one table. Create/use one object of this class for
|
||||
each ha_{myisam/innobase/etc} object. That object will be further referred to
|
||||
@ -196,17 +227,6 @@ private:
|
||||
uchar *rowid_buffer_end;
|
||||
|
||||
/** Index scaning and key buffer-related members **/
|
||||
|
||||
|
||||
enum enum_index_scan_state {
|
||||
REFILL_KEY_BUFFER,
|
||||
GET_NEXT_RANGE,
|
||||
GET_NEXT_RECORD,
|
||||
GET_NEXT_IDENTICAL_KEY,
|
||||
SCAN_FINISHED
|
||||
};
|
||||
|
||||
enum enum_index_scan_state index_scan_state;
|
||||
|
||||
/* TRUE <=> We can get at most one index tuple for a lookup key */
|
||||
bool index_ranges_unique;
|
||||
@ -220,25 +240,26 @@ private:
|
||||
buffers.
|
||||
*/
|
||||
Forward_lifo_buffer forward_key_buf;
|
||||
Forward_iterator forward_key_it;
|
||||
Backward_lifo_buffer backward_key_buf;
|
||||
Backward_iterator backward_key_it;
|
||||
|
||||
/* Buffer to store (key, range_id) pairs */
|
||||
Lifo_buffer *key_buffer;
|
||||
|
||||
/* key_buffer.read() reads */
|
||||
uchar *cur_index_tuple;
|
||||
|
||||
/* if in_index_range==TRUE: range_id of the range we're enumerating */
|
||||
char *cur_range_info;
|
||||
|
||||
|
||||
/* Index scan state */
|
||||
bool scanning_key_val_iter;
|
||||
/*
|
||||
TRUE <=> we've got index tuples/rowids for all keys (need this flag because
|
||||
we may have a situation where we've read everything from the key buffer but
|
||||
haven't finished with getting index tuples for the last key)
|
||||
*/
|
||||
//bool key_eof;
|
||||
bool index_scan_eof;
|
||||
Key_value_records_iterator kv_it;
|
||||
|
||||
/* key_buffer.read() reads to here */
|
||||
uchar *cur_index_tuple;
|
||||
|
||||
/* if in_index_range==TRUE: range_id of the range we're enumerating */
|
||||
char *cur_range_info;
|
||||
|
||||
/* Initially FALSE, becomes TRUE when we've set key_tuple_xxx members */
|
||||
bool know_key_tuple_params;
|
||||
@ -255,28 +276,6 @@ private:
|
||||
/* = key_size_in_keybuf [ + sizeof(range_assoc_info) ] */
|
||||
uint key_buff_elem_size;
|
||||
|
||||
/*
|
||||
TRUE <=> we're doing key-ordered index scan and right now several
|
||||
subsequent key values are the same as the one we've already retrieved and
|
||||
returned index tuple for.
|
||||
*/
|
||||
//bool in_identical_keys_range;
|
||||
|
||||
/* range_id of the first of the identical keys */
|
||||
char *first_identical_range_info;
|
||||
|
||||
/* Pointer to the last of the identical key values */
|
||||
uchar *last_identical_key_ptr;
|
||||
|
||||
/*
|
||||
key_buffer iterator for walking the identical key range (we need to
|
||||
enumerate the set of (identical_key, range_id) pairs multiple times,
|
||||
and do that by walking from current buffer read position until we get
|
||||
last_identical_key_ptr.
|
||||
*/
|
||||
Lifo_buffer::Iterator *identical_key_it;
|
||||
|
||||
|
||||
/** rnd_pos() scan and rowid buffer-related members **/
|
||||
|
||||
/*
|
||||
@ -288,12 +287,7 @@ private:
|
||||
/* rowid_buffer.read() will set the following: */
|
||||
uchar *rowid;
|
||||
uchar *rowids_range_id;
|
||||
|
||||
/*
|
||||
not-NULL: we're traversing a group of (rowid, range_id) pairs with
|
||||
identical rowid values, and this is the pointer to the last one.
|
||||
NULL: we're not in the group of indentical rowids.
|
||||
*/
|
||||
|
||||
uchar *last_identical_rowid;
|
||||
|
||||
bool dsmrr_eof; /* TRUE <=> We have reached EOF when reading index tuples */
|
||||
@ -315,10 +309,9 @@ private:
|
||||
void setup_buffer_sizes(key_range *sample_key);
|
||||
void reallocate_buffer_space();
|
||||
|
||||
void read_out_identical_ranges();
|
||||
|
||||
static range_seq_t key_buf_seq_init(void *init_param, uint n_ranges, uint flags);
|
||||
static uint key_buf_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range);
|
||||
friend class Key_value_records_iterator;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -112,40 +112,17 @@ public:
|
||||
virtual void reset() = 0;
|
||||
virtual uchar *end_of_space() = 0;
|
||||
protected:
|
||||
bool have_data(size_t bytes)
|
||||
{
|
||||
return (used_size() >= bytes);
|
||||
}
|
||||
virtual bool have_space_for(size_t bytes) = 0;
|
||||
virtual size_t used_size() = 0;
|
||||
|
||||
|
||||
/* To be used only by iterator class: */
|
||||
virtual uchar *get_pos()= 0;
|
||||
virtual bool read(uchar **position)= 0;
|
||||
friend class Lifo_buffer_iterator;
|
||||
public:
|
||||
|
||||
virtual void remove_unused_space(uchar **unused_start, uchar **unused_end)=0;
|
||||
virtual uchar *used_area() = 0;
|
||||
|
||||
/** Iterator to walk over contents of the buffer without reading it. */
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
virtual void init(Lifo_buffer *buf) = 0;
|
||||
/*
|
||||
Read the next value. The calling convention is the same as buf->read()
|
||||
has.
|
||||
|
||||
@retval FALSE - ok
|
||||
@retval TRUE - EOF, reached the end of the buffer
|
||||
*/
|
||||
virtual bool read_next()= 0;
|
||||
virtual ~Iterator() {}
|
||||
protected:
|
||||
Lifo_buffer *buf;
|
||||
virtual uchar *get_next(size_t nbytes)=0;
|
||||
};
|
||||
virtual uchar *used_area() = 0;
|
||||
virtual ~Lifo_buffer() {};
|
||||
|
||||
friend class Forward_iterator;
|
||||
friend class Backward_iterator;
|
||||
};
|
||||
|
||||
|
||||
@ -196,19 +173,24 @@ public:
|
||||
memcpy(pos, data, bytes);
|
||||
pos += bytes;
|
||||
}
|
||||
uchar *read_bytes(size_t bytes)
|
||||
bool have_data(uchar *position, size_t bytes)
|
||||
{
|
||||
DBUG_ASSERT(have_data(bytes));
|
||||
pos= pos - bytes;
|
||||
return pos;
|
||||
return ((position - start) >= (ptrdiff_t)bytes);
|
||||
}
|
||||
bool read()
|
||||
uchar *read_bytes(uchar **position, size_t bytes)
|
||||
{
|
||||
if (!have_data(size1 + (read_ptr2 ? size2 : 0)))
|
||||
DBUG_ASSERT(have_data(*position, bytes));
|
||||
*position= (*position) - bytes;
|
||||
return *position;
|
||||
}
|
||||
bool read() { return read(&pos); }
|
||||
bool read(uchar **position)
|
||||
{
|
||||
if (!have_data(*position, size1 + (read_ptr2 ? size2 : 0)))
|
||||
return TRUE;
|
||||
if (read_ptr2)
|
||||
*read_ptr2= read_bytes(size2);
|
||||
*read_ptr1= read_bytes(size1);
|
||||
*read_ptr2= read_bytes(position, size2);
|
||||
*read_ptr1= read_bytes(position, size1);
|
||||
return FALSE;
|
||||
}
|
||||
void remove_unused_space(uchar **unused_start, uchar **unused_end)
|
||||
@ -231,58 +213,11 @@ public:
|
||||
}
|
||||
/* Return pointer to start of the memory area that is occupied by the data */
|
||||
uchar *used_area() { return start; }
|
||||
friend class Forward_iterator;
|
||||
friend class Lifo_buffer_iterator;
|
||||
uchar *get_pos() { return pos; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Iterator for Forward_lifo_buffer
|
||||
*/
|
||||
|
||||
class Forward_iterator : public Lifo_buffer::Iterator
|
||||
{
|
||||
uchar *pos;
|
||||
|
||||
/** Return pointer to next chunk of nbytes bytes and avance over it */
|
||||
uchar *get_next(size_t nbytes)
|
||||
{
|
||||
if (pos - nbytes < ((Forward_lifo_buffer*)buf)->start)
|
||||
return NULL;
|
||||
pos -= nbytes;
|
||||
return pos;
|
||||
}
|
||||
public:
|
||||
bool read_next()
|
||||
{
|
||||
uchar *res;
|
||||
if (buf->read_ptr2)
|
||||
{
|
||||
if ((res= get_next(buf->size2)))
|
||||
{
|
||||
*(buf->read_ptr2)= res;
|
||||
*buf->read_ptr1= get_next(buf->size1);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((res= get_next(buf->size1)))
|
||||
{
|
||||
*(buf->read_ptr1)= res;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE; /* EOF */
|
||||
}
|
||||
|
||||
void init(Lifo_buffer *buf_arg)
|
||||
{
|
||||
DBUG_ASSERT(buf_arg->type() == Lifo_buffer::FORWARD);
|
||||
buf= buf_arg;
|
||||
pos= ((Forward_lifo_buffer*)buf)->pos;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Backward LIFO buffer
|
||||
@ -332,18 +267,26 @@ public:
|
||||
}
|
||||
bool read()
|
||||
{
|
||||
if (!have_data(size1 + (read_ptr2 ? size2 : 0)))
|
||||
return read(&pos);
|
||||
}
|
||||
bool read(uchar **position)
|
||||
{
|
||||
if (!have_data(*position, size1 + (read_ptr2 ? size2 : 0)))
|
||||
return TRUE;
|
||||
*read_ptr1= read_bytes(size1);
|
||||
*read_ptr1= read_bytes(position, size1);
|
||||
if (read_ptr2)
|
||||
*read_ptr2= read_bytes(size2);
|
||||
*read_ptr2= read_bytes(position, size2);
|
||||
return FALSE;
|
||||
}
|
||||
uchar *read_bytes(size_t bytes)
|
||||
bool have_data(uchar *position, size_t bytes)
|
||||
{
|
||||
DBUG_ASSERT(have_data(bytes));
|
||||
uchar *ret= pos;
|
||||
pos= pos + bytes;
|
||||
return ((end - position) >= (ptrdiff_t)bytes);
|
||||
}
|
||||
uchar *read_bytes(uchar **position, size_t bytes)
|
||||
{
|
||||
DBUG_ASSERT(have_data(*position, bytes));
|
||||
uchar *ret= *position;
|
||||
*position= *position + bytes;
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
@ -363,50 +306,34 @@ public:
|
||||
}
|
||||
/* Return pointer to start of the memory area that is occupied by the data */
|
||||
uchar *used_area() { return pos; }
|
||||
friend class Backward_iterator;
|
||||
friend class Lifo_buffer_iterator;
|
||||
uchar *get_pos() { return pos; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Iterator for Backward_lifo_buffer
|
||||
*/
|
||||
|
||||
class Backward_iterator : public Lifo_buffer::Iterator
|
||||
/** Iterator to walk over contents of the buffer without reading it. */
|
||||
class Lifo_buffer_iterator
|
||||
{
|
||||
uchar *pos;
|
||||
/* Return pointer to next chunk of nbytes bytes and advance over it */
|
||||
uchar *get_next(size_t nbytes)
|
||||
{
|
||||
if (pos + nbytes > ((Backward_lifo_buffer*)buf)->end)
|
||||
return NULL;
|
||||
uchar *res= pos;
|
||||
pos += nbytes;
|
||||
return res;
|
||||
}
|
||||
Lifo_buffer *buf;
|
||||
public:
|
||||
bool read_next()
|
||||
{
|
||||
/*
|
||||
Always read the first component first (if the buffer is backwards, we
|
||||
have written the second component first).
|
||||
*/
|
||||
uchar *res;
|
||||
if ((res= get_next(buf->size1)))
|
||||
{
|
||||
*(buf->read_ptr1)= res;
|
||||
if (buf->read_ptr2)
|
||||
*buf->read_ptr2= get_next(buf->size2);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE; /* EOF */
|
||||
}
|
||||
void init(Lifo_buffer *buf_arg)
|
||||
{
|
||||
DBUG_ASSERT(buf_arg->type() == Lifo_buffer::BACKWARD);
|
||||
buf= buf_arg;
|
||||
pos= ((Backward_lifo_buffer*)buf)->pos;
|
||||
pos= buf->get_pos();
|
||||
}
|
||||
/*
|
||||
Read the next value. The calling convention is the same as buf->read()
|
||||
has.
|
||||
|
||||
@retval FALSE - ok
|
||||
@retval TRUE - EOF, reached the end of the buffer
|
||||
*/
|
||||
bool read()
|
||||
{
|
||||
return buf->read(&pos);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user