Commit be0b4042 authored by Michael Widenius's avatar Michael Widenius

Fix for Bug #39243 SELECT WHERE does not find row

Symptom was that records_in_range() found 0 matching keys which confused the optimizer to belive that there was no matching rows for the query

mysql-test/r/maria.result:
  New testcase
mysql-test/t/maria.test:
  New testcase
storage/maria/ma_search.c:
  Fix bug in skip_key for keys that starts with a CHAR/VARCHAR NULL key.
parent 7f960da4
...@@ -2243,3 +2243,35 @@ lock table t1 write concurrent; ...@@ -2243,3 +2243,35 @@ lock table t1 write concurrent;
delete from t1; delete from t1;
ERROR 42000: The storage engine for the table doesn't support DELETE in WRITE CONCURRENT ERROR 42000: The storage engine for the table doesn't support DELETE in WRITE CONCURRENT
drop table t1; drop table t1;
create table t1 (p int primary key, i int, a char(10), key k1(i), key k2(a))
engine maria;
insert into t1 values (1, 1, 'qqqq'), (2, 1, 'pppp'),
(3, 1, 'yyyy'), (4, 3, 'zzzz');
insert into t1 values (5, 3, 'yyyy'), (6, 3, 'yyyy'), (7, 0, NULL),
(8, 0, NULL);
select * from t1 where a='zzzz';
p i a
4 3 zzzz
select * from t1 where a='yyyy';
p i a
3 1 yyyy
5 3 yyyy
6 3 yyyy
select * from t1 where a is NULL;
p i a
7 0 NULL
8 0 NULL
select * from t1;
p i a
1 1 qqqq
2 1 pppp
3 1 yyyy
4 3 zzzz
5 3 yyyy
6 3 yyyy
7 0 NULL
8 0 NULL
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
...@@ -1542,3 +1542,20 @@ eval set global storage_engine=$default_engine, maria_page_checksum=$default_che ...@@ -1542,3 +1542,20 @@ eval set global storage_engine=$default_engine, maria_page_checksum=$default_che
--enable_result_log --enable_result_log
--enable_query_log --enable_query_log
#
# Bug#39243 SELECT WHERE does not find row
# (Problem with skip_row)
#
create table t1 (p int primary key, i int, a char(10), key k1(i), key k2(a))
engine maria;
insert into t1 values (1, 1, 'qqqq'), (2, 1, 'pppp'),
(3, 1, 'yyyy'), (4, 3, 'zzzz');
insert into t1 values (5, 3, 'yyyy'), (6, 3, 'yyyy'), (7, 0, NULL),
(8, 0, NULL);
select * from t1 where a='zzzz';
select * from t1 where a='yyyy';
select * from t1 where a is NULL;
select * from t1;
check table t1;
drop table t1;
...@@ -931,7 +931,7 @@ uint _ma_get_static_key(MARIA_KEY *key, uint page_flag, uint nod_flag, ...@@ -931,7 +931,7 @@ uint _ma_get_static_key(MARIA_KEY *key, uint page_flag, uint nod_flag,
/** /**
Skip over static length key from key-block Skip over static length key from key-block
@fn _ma_skip_pack_key() @fn _ma_skip_static_key()
@param key Keyinfo and buffer that can be used @param key Keyinfo and buffer that can be used
@param nod_flag If nod: Length of node pointer, else zero. @param nod_flag If nod: Length of node pointer, else zero.
@param key Points at key @param key Points at key
...@@ -1049,6 +1049,7 @@ uint _ma_get_pack_key(MARIA_KEY *int_key, uint page_flag, ...@@ -1049,6 +1049,7 @@ uint _ma_get_pack_key(MARIA_KEY *int_key, uint page_flag,
} }
else else
{ {
/* Key that is not packed against previous key */
if (keyseg->flag & HA_NULL_PART) if (keyseg->flag & HA_NULL_PART)
{ {
if (!length--) /* Null part */ if (!length--) /* Null part */
...@@ -1121,6 +1122,9 @@ uint _ma_get_pack_key(MARIA_KEY *int_key, uint page_flag, ...@@ -1121,6 +1122,9 @@ uint _ma_get_pack_key(MARIA_KEY *int_key, uint page_flag,
@param nod_flag If nod: Length of node pointer, else zero. @param nod_flag If nod: Length of node pointer, else zero.
@param key Points at key @param key Points at key
@note
This is in principle a simpler version of _ma_get_pack_key()
@retval pointer to next key @retval pointer to next key
*/ */
...@@ -1150,6 +1154,14 @@ uchar *_ma_skip_pack_key(MARIA_KEY *key, uint page_flag, ...@@ -1150,6 +1154,14 @@ uchar *_ma_skip_pack_key(MARIA_KEY *key, uint page_flag,
page+= length; page+= length;
continue; continue;
} }
if ((keyseg->flag & HA_NULL_PART) && length)
{
/*
Keys that can have null use length+1 as the length for date as the
number 0 is reserved for keys that have a NULL value
*/
length--;
}
page+= length; page+= length;
} }
else else
...@@ -1846,11 +1858,14 @@ _ma_calc_var_key_length(const MARIA_KEY *key, uint nod_flag, ...@@ -1846,11 +1858,14 @@ _ma_calc_var_key_length(const MARIA_KEY *key, uint nod_flag,
prefix byte(s) The high bit is set if this is a prefix for the prev key prefix byte(s) The high bit is set if this is a prefix for the prev key
length Packed length if the previous was a prefix byte length Packed length if the previous was a prefix byte
[length] data bytes ('length' bytes) [data_length] data bytes ('length' bytes)
next-key-seg Next key segments next-key-seg Next key segments
If the first segment can have NULL: If the first segment can have NULL:
The length is 0 for NULLS and 1+length for not null columns. If key was packed
data_length is length of rest of key
If key was not packed
The data_length is 0 for NULLS and 1+data_length for not null columns
*/ */
int int
......
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