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
|
LEFT JOIN
|
||||||
(t1,t2)
|
(t1,t2)
|
||||||
ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b;
|
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
|
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||||
FROM (t3,t4)
|
FROM (t3,t4)
|
||||||
LEFT JOIN
|
LEFT JOIN
|
||||||
|
@ -586,6 +586,7 @@ if (`select @@join_cache_level=6`)
|
|||||||
--echo # Not anymore:
|
--echo # Not anymore:
|
||||||
--echo # The following query gives wrong result due to Bug#49129
|
--echo # The following query gives wrong result due to Bug#49129
|
||||||
}
|
}
|
||||||
|
select sin(0);
|
||||||
select * from t0 where t0.a in
|
select * from t0 where t0.a in
|
||||||
(select t1.a from t1, t2 where t2.a=t0.a and t1.b=t2.b);
|
(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. */
|
/* Give all space to forward key buffer. */
|
||||||
key_buffer= &forward_key_buf;
|
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);
|
key_buffer->set_buffer_space(full_buf, full_buf_end);
|
||||||
|
|
||||||
/* Just in case, tell rowid buffer that it has zero size: */
|
/* 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_end= full_buf + bytes_for_rowids;
|
||||||
rowid_buffer.set_buffer_space(full_buf, rowid_buffer_end);
|
rowid_buffer.set_buffer_space(full_buf, rowid_buffer_end);
|
||||||
key_buffer= &backward_key_buf;
|
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->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);
|
rowid_buffer.set_buffer_space(full_buf, rowid_buffer_end);
|
||||||
key_buffer= &backward_key_buf;
|
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->set_buffer_space(rowid_buffer_end, full_buf_end);
|
||||||
}
|
}
|
||||||
key_buffer->reset();
|
key_buffer->reset();
|
||||||
@ -815,9 +815,12 @@ void DsMrr_impl::dsmrr_fill_key_buffer()
|
|||||||
is_mrr_assoc? (uchar**)&cur_range_info: NULL,
|
is_mrr_assoc? (uchar**)&cur_range_info: NULL,
|
||||||
sizeof(void*));
|
sizeof(void*));
|
||||||
|
|
||||||
last_identical_key_ptr= NULL;
|
//last_identical_key_ptr= NULL;
|
||||||
//in_identical_keys_range= FALSE;
|
//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;
|
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.
|
bool Key_value_records_iterator::init(DsMrr_impl *dsmrr_arg)
|
||||||
*/
|
{
|
||||||
|
int res;
|
||||||
|
dsmrr= dsmrr_arg;
|
||||||
|
handler *file= dsmrr->do_rndpos_scan? dsmrr->h2 : dsmrr->h;
|
||||||
|
|
||||||
void DsMrr_impl::read_out_identical_ranges()
|
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())
|
||||||
{
|
{
|
||||||
if (last_identical_key_ptr)
|
if (DsMrr_impl::key_tuple_cmp(dsmrr, key_in_buf, dsmrr->cur_index_tuple))
|
||||||
{
|
break;
|
||||||
/* key_buffer.read() reads to (cur_index_tuple, cur_range_info) */
|
last_identical_key_ptr= dsmrr->cur_index_tuple;
|
||||||
while (!key_buffer->read() && (cur_index_tuple != last_identical_key_ptr)) {}
|
|
||||||
last_identical_key_ptr= NULL;
|
|
||||||
}
|
}
|
||||||
|
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
|
DS-MRR/CPK: multi_range_read_next() function
|
||||||
@ -871,131 +940,34 @@ void DsMrr_impl::read_out_identical_ranges()
|
|||||||
@retval HA_ERR_END_OF_FILE End of records
|
@retval HA_ERR_END_OF_FILE End of records
|
||||||
@retval Other Some other error
|
@retval Other Some other error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int DsMrr_impl::dsmrr_next_from_index(char **range_info_arg)
|
int DsMrr_impl::dsmrr_next_from_index(char **range_info_arg)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("DsMrr_impl::dsmrr_next_from_index");
|
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)
|
while (1)
|
||||||
{
|
{
|
||||||
bool have_record= FALSE;
|
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 */
|
kv_it.close();
|
||||||
|
scanning_key_val_iter= FALSE;
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
have_record= TRUE;
|
have_record= TRUE;
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GET_NEXT_RECORD:
|
|
||||||
{
|
|
||||||
/* 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
|
else
|
||||||
{
|
{
|
||||||
index_scan_state= index_ranges_unique? GET_NEXT_RANGE : GET_NEXT_RECORD;
|
while (kv_it.init(this))
|
||||||
have_record= TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res)
|
|
||||||
{
|
{
|
||||||
read_out_identical_ranges();
|
/* Failed to initialize iterator */
|
||||||
index_scan_state= GET_NEXT_RANGE;
|
if (key_buffer->is_empty())
|
||||||
have_record= FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case REFILL_KEY_BUFFER:
|
|
||||||
{
|
{
|
||||||
if (dsmrr_eof)
|
if (dsmrr_eof)
|
||||||
{
|
{
|
||||||
index_scan_state= SCAN_FINISHED;
|
index_scan_eof= TRUE;
|
||||||
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1008,15 +980,13 @@ int DsMrr_impl::dsmrr_next_from_index(char **range_info_arg)
|
|||||||
|
|
||||||
if (key_buffer->is_empty())
|
if (key_buffer->is_empty())
|
||||||
{
|
{
|
||||||
index_scan_state= SCAN_FINISHED;
|
index_scan_eof= TRUE;
|
||||||
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
index_scan_state= GET_NEXT_RANGE;
|
|
||||||
}
|
}
|
||||||
default:
|
}
|
||||||
DBUG_ASSERT(0);
|
/* if we got here, it means iterator was successfully initialized */
|
||||||
break;
|
scanning_key_val_iter= TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (have_record &&
|
if (have_record &&
|
||||||
@ -1035,151 +1005,6 @@ int DsMrr_impl::dsmrr_next_from_index(char **range_info_arg)
|
|||||||
DBUG_RETURN(0);
|
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.
|
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 (do_sort_keys)
|
||||||
{
|
{
|
||||||
if (index_scan_state != SCAN_FINISHED)
|
if (index_scan_eof)
|
||||||
{
|
{
|
||||||
/* There are some sorted keys left. Use them to get rowids */
|
/* There are some sorted keys left. Use them to get rowids */
|
||||||
if ((res= dsmrr_fill_rowid_buffer()))
|
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]
|
Note: this implies that SQL layer doesn't touch table->record[0]
|
||||||
between calls.
|
between calls.
|
||||||
*/
|
*/
|
||||||
Forward_iterator it;
|
Lifo_buffer_iterator it;
|
||||||
it.init(&rowid_buffer);
|
it.init(&rowid_buffer);
|
||||||
while (!it.read_next()) // reads to (rowid, ...)
|
while (!it.read()) // reads to (rowid, ...)
|
||||||
{
|
{
|
||||||
if (h2->cmp_ref(rowid, cur_rowid))
|
if (h2->cmp_ref(rowid, cur_rowid))
|
||||||
break;
|
break;
|
||||||
|
@ -48,6 +48,37 @@
|
|||||||
|
|
||||||
#include "sql_lifo_buffer.h"
|
#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
|
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
|
each ha_{myisam/innobase/etc} object. That object will be further referred to
|
||||||
@ -197,17 +228,6 @@ private:
|
|||||||
|
|
||||||
/** Index scaning and key buffer-related members **/
|
/** 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 */
|
/* TRUE <=> We can get at most one index tuple for a lookup key */
|
||||||
bool index_ranges_unique;
|
bool index_ranges_unique;
|
||||||
|
|
||||||
@ -220,25 +240,26 @@ private:
|
|||||||
buffers.
|
buffers.
|
||||||
*/
|
*/
|
||||||
Forward_lifo_buffer forward_key_buf;
|
Forward_lifo_buffer forward_key_buf;
|
||||||
Forward_iterator forward_key_it;
|
|
||||||
Backward_lifo_buffer backward_key_buf;
|
Backward_lifo_buffer backward_key_buf;
|
||||||
Backward_iterator backward_key_it;
|
|
||||||
|
|
||||||
/* Buffer to store (key, range_id) pairs */
|
/* Buffer to store (key, range_id) pairs */
|
||||||
Lifo_buffer *key_buffer;
|
Lifo_buffer *key_buffer;
|
||||||
|
|
||||||
/* key_buffer.read() reads */
|
/* Index scan state */
|
||||||
uchar *cur_index_tuple;
|
bool scanning_key_val_iter;
|
||||||
|
|
||||||
/* if in_index_range==TRUE: range_id of the range we're enumerating */
|
|
||||||
char *cur_range_info;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TRUE <=> we've got index tuples/rowids for all keys (need this flag because
|
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
|
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)
|
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 */
|
/* Initially FALSE, becomes TRUE when we've set key_tuple_xxx members */
|
||||||
bool know_key_tuple_params;
|
bool know_key_tuple_params;
|
||||||
@ -255,28 +276,6 @@ private:
|
|||||||
/* = key_size_in_keybuf [ + sizeof(range_assoc_info) ] */
|
/* = key_size_in_keybuf [ + sizeof(range_assoc_info) ] */
|
||||||
uint key_buff_elem_size;
|
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 **/
|
/** rnd_pos() scan and rowid buffer-related members **/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -289,11 +288,6 @@ private:
|
|||||||
uchar *rowid;
|
uchar *rowid;
|
||||||
uchar *rowids_range_id;
|
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;
|
uchar *last_identical_rowid;
|
||||||
|
|
||||||
bool dsmrr_eof; /* TRUE <=> We have reached EOF when reading index tuples */
|
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 setup_buffer_sizes(key_range *sample_key);
|
||||||
void reallocate_buffer_space();
|
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 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);
|
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 void reset() = 0;
|
||||||
virtual uchar *end_of_space() = 0;
|
virtual uchar *end_of_space() = 0;
|
||||||
protected:
|
protected:
|
||||||
bool have_data(size_t bytes)
|
|
||||||
{
|
|
||||||
return (used_size() >= bytes);
|
|
||||||
}
|
|
||||||
virtual bool have_space_for(size_t bytes) = 0;
|
virtual bool have_space_for(size_t bytes) = 0;
|
||||||
virtual size_t used_size() = 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:
|
public:
|
||||||
|
|
||||||
virtual void remove_unused_space(uchar **unused_start, uchar **unused_end)=0;
|
virtual void remove_unused_space(uchar **unused_start, uchar **unused_end)=0;
|
||||||
virtual uchar *used_area() = 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 ~Lifo_buffer() {};
|
virtual ~Lifo_buffer() {};
|
||||||
|
|
||||||
friend class Forward_iterator;
|
|
||||||
friend class Backward_iterator;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -196,19 +173,24 @@ public:
|
|||||||
memcpy(pos, data, bytes);
|
memcpy(pos, data, bytes);
|
||||||
pos += bytes;
|
pos += bytes;
|
||||||
}
|
}
|
||||||
uchar *read_bytes(size_t bytes)
|
bool have_data(uchar *position, size_t bytes)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(have_data(bytes));
|
return ((position - start) >= (ptrdiff_t)bytes);
|
||||||
pos= pos - bytes;
|
|
||||||
return pos;
|
|
||||||
}
|
}
|
||||||
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;
|
return TRUE;
|
||||||
if (read_ptr2)
|
if (read_ptr2)
|
||||||
*read_ptr2= read_bytes(size2);
|
*read_ptr2= read_bytes(position, size2);
|
||||||
*read_ptr1= read_bytes(size1);
|
*read_ptr1= read_bytes(position, size1);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
void remove_unused_space(uchar **unused_start, uchar **unused_end)
|
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 */
|
/* Return pointer to start of the memory area that is occupied by the data */
|
||||||
uchar *used_area() { return start; }
|
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
|
Backward LIFO buffer
|
||||||
@ -332,18 +267,26 @@ public:
|
|||||||
}
|
}
|
||||||
bool read()
|
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;
|
return TRUE;
|
||||||
*read_ptr1= read_bytes(size1);
|
*read_ptr1= read_bytes(position, size1);
|
||||||
if (read_ptr2)
|
if (read_ptr2)
|
||||||
*read_ptr2= read_bytes(size2);
|
*read_ptr2= read_bytes(position, size2);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
uchar *read_bytes(size_t bytes)
|
bool have_data(uchar *position, size_t bytes)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(have_data(bytes));
|
return ((end - position) >= (ptrdiff_t)bytes);
|
||||||
uchar *ret= pos;
|
}
|
||||||
pos= pos + bytes;
|
uchar *read_bytes(uchar **position, size_t bytes)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(have_data(*position, bytes));
|
||||||
|
uchar *ret= *position;
|
||||||
|
*position= *position + bytes;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -363,50 +306,34 @@ public:
|
|||||||
}
|
}
|
||||||
/* Return pointer to start of the memory area that is occupied by the data */
|
/* Return pointer to start of the memory area that is occupied by the data */
|
||||||
uchar *used_area() { return pos; }
|
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;
|
uchar *pos;
|
||||||
/* Return pointer to next chunk of nbytes bytes and advance over it */
|
Lifo_buffer *buf;
|
||||||
uchar *get_next(size_t nbytes)
|
|
||||||
{
|
|
||||||
if (pos + nbytes > ((Backward_lifo_buffer*)buf)->end)
|
|
||||||
return NULL;
|
|
||||||
uchar *res= pos;
|
|
||||||
pos += nbytes;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
public:
|
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)
|
void init(Lifo_buffer *buf_arg)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(buf_arg->type() == Lifo_buffer::BACKWARD);
|
|
||||||
buf= buf_arg;
|
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