Commit 38cbef8b authored by Monty's avatar Monty

MDEV-22935 Erroneous Aria Index / Optimizer behaviour

The problem was in the Aria part of the range optimizer,
maria_records_in_range(), which wrong concluded that there was no rows
in the range.

This error would happen in the unlikely case when searching for a range
on a partial key and there was a match for the first key part in the
upper part of the b-tree (node) and also a match in the underlying
node page.

In other words, for this bug to happen one have to use Aria, have a multi
part key with a lot of identical values for the first key part and do a
range search on the second part of the key.

Fixed by ensuring that we do not stop searching for partial keys found
on node.

Other things:
- Added some comments
- Changed a variable name to more clearly explain it's purpose.
- Fixed wrong cast in _ma_record_pos() that could cause problems on 32 bit
  systems.
parent c6d36c3e
#
# MDEV-22935 Erroneous Aria Index / Optimizer behaviour
#
create table t1 (a char(255), b datetime, primary key(a,b)) engine=aria transactional=0 pack_keys=0;
insert into t1 select concat("hello world hello world", truncate(seq/100,0)),from_unixtime(seq+1) from seq_1_to_20000;
drop table t1;
--source include/have_sequence.inc
--echo #
--echo # MDEV-22935 Erroneous Aria Index / Optimizer behaviour
--echo #
create table t1 (a char(255), b datetime, primary key(a,b)) engine=aria transactional=0 pack_keys=0;
insert into t1 select concat("hello world hello world", truncate(seq/100,0)),from_unixtime(seq+1) from seq_1_to_20000;
let $i= 200;
--disable_query_log
while ($i)
{
let $tmp= `select count(*) from t1 where a="hello world hello world$i" and b <= from_unixtime($i*100+1)`;
if (`SELECT $tmp != 1`)
{
--echo "Found $tmp rows, expected 1, for value $i"
}
dec $i;
}
--enable_query_log
drop table t1;
...@@ -191,8 +191,8 @@ static ha_rows _ma_record_pos(MARIA_HA *info, const uchar *key_data, ...@@ -191,8 +191,8 @@ static ha_rows _ma_record_pos(MARIA_HA *info, const uchar *key_data,
info->s->state.key_root[inx], final_page); info->s->state.key_root[inx], final_page);
if (pos >= 0.0) if (pos >= 0.0)
{ {
DBUG_PRINT("exit",("pos: %ld",(ulong) (pos*info->state->records))); DBUG_PRINT("exit",("pos: %lld",(longlong) (pos*info->state->records)));
DBUG_RETURN((ulong) (pos*info->state->records+0.5)); DBUG_RETURN((ha_rows) (pos*info->state->records+0.5));
} }
DBUG_RETURN(HA_POS_ERROR); DBUG_RETURN(HA_POS_ERROR);
} }
...@@ -214,7 +214,7 @@ static double _ma_search_pos(MARIA_HA *info, MARIA_KEY *key, ...@@ -214,7 +214,7 @@ static double _ma_search_pos(MARIA_HA *info, MARIA_KEY *key,
{ {
int flag; int flag;
uint keynr, UNINIT_VAR(max_keynr); uint keynr, UNINIT_VAR(max_keynr);
my_bool after_key; my_bool last_key_on_page;
uchar *keypos; uchar *keypos;
double offset; double offset;
MARIA_KEYDEF *keyinfo= key->keyinfo; MARIA_KEYDEF *keyinfo= key->keyinfo;
...@@ -230,7 +230,7 @@ static double _ma_search_pos(MARIA_HA *info, MARIA_KEY *key, ...@@ -230,7 +230,7 @@ static double _ma_search_pos(MARIA_HA *info, MARIA_KEY *key,
goto err; goto err;
*final_page= pos; *final_page= pos;
flag= (*keyinfo->bin_search)(key, &page, nextflag, &keypos, flag= (*keyinfo->bin_search)(key, &page, nextflag, &keypos,
info->lastkey_buff, &after_key); info->lastkey_buff, &last_key_on_page);
keynr= _ma_keynr(&page, keypos, &max_keynr); keynr= _ma_keynr(&page, keypos, &max_keynr);
if (flag) if (flag)
...@@ -274,7 +274,7 @@ static double _ma_search_pos(MARIA_HA *info, MARIA_KEY *key, ...@@ -274,7 +274,7 @@ static double _ma_search_pos(MARIA_HA *info, MARIA_KEY *key,
There may be identical keys in the tree. Try to match on of those. There may be identical keys in the tree. Try to match on of those.
Matches keynr + [0-1] Matches keynr + [0-1]
*/ */
if ((offset= _ma_search_pos(info, key, SEARCH_FIND, if ((offset= _ma_search_pos(info, key, nextflag,
_ma_kpos(page.node,keypos), _ma_kpos(page.node,keypos),
final_page)) < 0) final_page)) < 0)
DBUG_RETURN(offset); /* Read error */ DBUG_RETURN(offset); /* Read error */
...@@ -290,9 +290,10 @@ static double _ma_search_pos(MARIA_HA *info, MARIA_KEY *key, ...@@ -290,9 +290,10 @@ static double _ma_search_pos(MARIA_HA *info, MARIA_KEY *key,
/* /*
Get keynummer of current key and max number of keys in nod Get keynumber of current key and max number of keys in nod
keynr >= 0 && key_nr <= max_key @return key position on page (0 - (ret_max_key - 1))
ret_max_key contains how many keys there was on the page
*/ */
static uint _ma_keynr(MARIA_PAGE *page, uchar *keypos, uint *ret_max_key) static uint _ma_keynr(MARIA_PAGE *page, uchar *keypos, uint *ret_max_key)
......
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