Commit 99ad23ec authored by ingo@mysql.com's avatar ingo@mysql.com

Bug#14400 - Query joins wrong rows from table which is subject of "concurrent insert"

It was possible that fetching a record by an exact key value 
(including the record pointer) could return a record with a 
different key value. This happened only if a concurrent insert 
added a record with the searched key value after the fetching 
statement locked the table for read.

The search succeded on the key value, but the record was
rejected as it was past the file length that was remembered
at start of the fetching statement. With other words it was 
rejected as being a concurrently inserted record.

The action to recover from this problem was to fetch the 
record that is pointed at by the next key of the index. 
This was repeated until a record below the file length was 
found.

I do now avoid this loop if an exact match was searched. 
If this match is beyond the file length, it is now treated 
as "key not found". There cannot be another key with the 
same record pointer.
parent e09910f9
......@@ -66,6 +66,7 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len,
if (fast_mi_readinfo(info))
goto err;
if (share->concurrent_insert)
rw_rdlock(&share->key_root_lock[inx]);
......@@ -77,14 +78,24 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len,
if (!_mi_search(info,keyinfo, key_buff, use_key_length,
myisam_read_vec[search_flag], info->s->state.key_root[inx]))
{
while (info->lastpos >= info->state->data_file_length)
/*
If we are searching for an exact key (including the data pointer)
and this was added by an concurrent insert,
then the result is "key not found".
*/
if ((search_flag == HA_READ_KEY_EXACT) &&
(info->lastpos >= info->state->data_file_length))
{
my_errno= HA_ERR_KEY_NOT_FOUND;
info->lastpos= HA_OFFSET_ERROR;
}
else while (info->lastpos >= info->state->data_file_length)
{
/*
Skip rows that are inserted by other threads since we got a lock
Note that this can only happen if we are not searching after an
exact key, because the keys are sorted according to position
*/
if (_mi_search_next(info, keyinfo, info->lastkey,
info->lastkey_length,
myisam_readnext_vec[search_flag],
......@@ -92,6 +103,7 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len,
break;
}
}
if (share->concurrent_insert)
rw_unlock(&share->key_root_lock[inx]);
......
......@@ -477,7 +477,7 @@ bool select_send::send_data(List<Item> &items)
{
List_iterator_fast<Item> li(items);
String *packet= &thd->packet;
DBUG_ENTER("send_data");
DBUG_ENTER("select_send::send_data");
#ifdef HAVE_INNOBASE_DB
/* We may be passing the control from mysqld to the client: release the
......@@ -611,7 +611,7 @@ select_export::prepare(List<Item> &list)
bool select_export::send_data(List<Item> &items)
{
DBUG_ENTER("send_data");
DBUG_ENTER("select_export::send_data");
char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH];
bool space_inited=0;
String tmp(buff,sizeof(buff)),*res;
......@@ -828,7 +828,7 @@ bool select_dump::send_data(List<Item> &items)
String tmp(buff,sizeof(buff)),*res;
tmp.length(0);
Item *item;
DBUG_ENTER("send_data");
DBUG_ENTER("select_dump::send_data");
if (thd->offset_limit)
{ // using limit offset,count
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment