From be0b4042669d2d960294cfb823d61b833678beed Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Fri, 26 Sep 2008 11:16:35 +0300 Subject: [PATCH] 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. --- mysql-test/r/maria.result | 32 ++++++++++++++++++++++++++++++++ mysql-test/t/maria.test | 17 +++++++++++++++++ storage/maria/ma_search.c | 21 ++++++++++++++++++--- 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/maria.result b/mysql-test/r/maria.result index 55651a99e95..031cb894daa 100644 --- a/mysql-test/r/maria.result +++ b/mysql-test/r/maria.result @@ -2243,3 +2243,35 @@ lock table t1 write concurrent; delete from t1; ERROR 42000: The storage engine for the table doesn't support DELETE in WRITE CONCURRENT 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; diff --git a/mysql-test/t/maria.test b/mysql-test/t/maria.test index 66a8b906eef..0ad4c4d29e1 100644 --- a/mysql-test/t/maria.test +++ b/mysql-test/t/maria.test @@ -1542,3 +1542,20 @@ eval set global storage_engine=$default_engine, maria_page_checksum=$default_che --enable_result_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; diff --git a/storage/maria/ma_search.c b/storage/maria/ma_search.c index cf7ec5f9724..470011cb247 100644 --- a/storage/maria/ma_search.c +++ b/storage/maria/ma_search.c @@ -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 - @fn _ma_skip_pack_key() + @fn _ma_skip_static_key() @param key Keyinfo and buffer that can be used @param nod_flag If nod: Length of node pointer, else zero. @param key Points at key @@ -1049,6 +1049,7 @@ uint _ma_get_pack_key(MARIA_KEY *int_key, uint page_flag, } else { + /* Key that is not packed against previous key */ if (keyseg->flag & HA_NULL_PART) { if (!length--) /* Null part */ @@ -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 key Points at key + @note + This is in principle a simpler version of _ma_get_pack_key() + @retval pointer to next key */ @@ -1150,6 +1154,14 @@ uchar *_ma_skip_pack_key(MARIA_KEY *key, uint page_flag, page+= length; 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; } else @@ -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 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 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