Commit 18dc64ec authored by Igor Babaev's avatar Igor Babaev

Fixed LP bug #694443.

One of the hash functions employed by the BNLH join algorithm
calculates the the value of hash index for key value utilizing
every byte of the key buffer. To make this calculation valid
one has to ensure that for any key value unused bytes of the 
buffer are filled with with a certain filler. We choose 0 as
a filler for these bytes.

Added an optional boolean parameter with_zerofill to the function
key_copy. If the value of the parameter is TRUE all unused bytes
of the key buffer is filled with 0. 
parent 1eb21dc4
...@@ -6122,4 +6122,50 @@ f1 f3 f3 f2 f4 ...@@ -6122,4 +6122,50 @@ f1 f3 f3 f2 f4
SET SESSION join_cache_level = DEFAULT; SET SESSION join_cache_level = DEFAULT;
SET SESSION optimizer_switch = DEFAULT; SET SESSION optimizer_switch = DEFAULT;
DROP TABLE t1,t2; DROP TABLE t1,t2;
#
# Bug #694443: hash join using IS NULL the an equi-join condition
#
CREATE TABLE t1 (a int PRIMARY KEY);
INSERT INTO t1 VALUES
(7), (4), (9), (1), (3), (8), (2);
CREATE TABLE t2 (a int, b int, INDEX idx (a));
INSERT INTO t2 VALUES
(NULL,10), (4,80), (7,70), (6,11), (7,90), (NULL,40),
(4,77), (4,50), (NULL,41), (7,99), (7,88), (8,12),
(1,21), (4,90), (7,91), (8,22), (6,92), (NULL,42),
(2,78), (2,51), (1,43), (5,97), (5,89);
SET SESSION join_cache_level = 1;
EXPLAIN
SELECT * FROM t1,t2 WHERE t1.a < 3 and t2.a IS NULL;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 Using where; Using index
1 SIMPLE t2 ref idx idx 5 const 4 Using index condition
SELECT * FROM t1,t2 WHERE t1.a < 3 and t2.a IS NULL;
a a b
1 NULL 10
1 NULL 40
1 NULL 41
1 NULL 42
2 NULL 10
2 NULL 40
2 NULL 41
2 NULL 42
SET SESSION join_cache_level = 4;
EXPLAIN
SELECT * FROM t1,t2 WHERE t1.a < 3 and t2.a IS NULL;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 Using where; Using index
1 SIMPLE t2 ref idx idx 5 const 4 Using where; Using join buffer (flat, BNLH join)
SELECT * FROM t1,t2 WHERE t1.a < 3 and t2.a IS NULL;
a a b
1 NULL 10
2 NULL 10
1 NULL 40
2 NULL 40
1 NULL 41
2 NULL 41
1 NULL 42
2 NULL 42
SET SESSION join_cache_level = DEFAULT;
DROP TABLE t1,t2;
set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch=@save_optimizer_switch;
...@@ -2759,5 +2759,36 @@ SET SESSION optimizer_switch = DEFAULT; ...@@ -2759,5 +2759,36 @@ SET SESSION optimizer_switch = DEFAULT;
DROP TABLE t1,t2; DROP TABLE t1,t2;
--echo #
--echo # Bug #694443: hash join using IS NULL the an equi-join condition
--echo #
CREATE TABLE t1 (a int PRIMARY KEY);
INSERT INTO t1 VALUES
(7), (4), (9), (1), (3), (8), (2);
CREATE TABLE t2 (a int, b int, INDEX idx (a));
INSERT INTO t2 VALUES
(NULL,10), (4,80), (7,70), (6,11), (7,90), (NULL,40),
(4,77), (4,50), (NULL,41), (7,99), (7,88), (8,12),
(1,21), (4,90), (7,91), (8,22), (6,92), (NULL,42),
(2,78), (2,51), (1,43), (5,97), (5,89);
SET SESSION join_cache_level = 1;
EXPLAIN
SELECT * FROM t1,t2 WHERE t1.a < 3 and t2.a IS NULL;
SELECT * FROM t1,t2 WHERE t1.a < 3 and t2.a IS NULL;
SET SESSION join_cache_level = 4;
EXPLAIN
SELECT * FROM t1,t2 WHERE t1.a < 3 and t2.a IS NULL;
SELECT * FROM t1,t2 WHERE t1.a < 3 and t2.a IS NULL;
SET SESSION join_cache_level = DEFAULT;
DROP TABLE t1,t2;
# this must be the last command in the file # this must be the last command in the file
set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch=@save_optimizer_switch;
...@@ -103,10 +103,11 @@ int find_ref_key(KEY *key, uint key_count, uchar *record, Field *field, ...@@ -103,10 +103,11 @@ int find_ref_key(KEY *key, uint key_count, uchar *record, Field *field,
@param from_record full record to be copied from @param from_record full record to be copied from
@param key_info descriptor of the index @param key_info descriptor of the index
@param key_length specifies length of all keyparts that will be copied @param key_length specifies length of all keyparts that will be copied
@param with_zerofill skipped bytes in the key buffer to be filled with 0
*/ */
void key_copy(uchar *to_key, uchar *from_record, KEY *key_info, void key_copy(uchar *to_key, uchar *from_record, KEY *key_info,
uint key_length) uint key_length, bool with_zerofill)
{ {
uint length; uint length;
KEY_PART_INFO *key_part; KEY_PART_INFO *key_part;
...@@ -129,6 +130,8 @@ void key_copy(uchar *to_key, uchar *from_record, KEY *key_info, ...@@ -129,6 +130,8 @@ void key_copy(uchar *to_key, uchar *from_record, KEY *key_info,
The -1 below is to subtract the null byte which is already handled The -1 below is to subtract the null byte which is already handled
*/ */
length= min(key_length, (uint) key_part->store_length-1); length= min(key_length, (uint) key_part->store_length-1);
if (with_zerofill)
bzero((char*) to_key, length);
continue; continue;
} }
} }
...@@ -137,7 +140,9 @@ void key_copy(uchar *to_key, uchar *from_record, KEY *key_info, ...@@ -137,7 +140,9 @@ void key_copy(uchar *to_key, uchar *from_record, KEY *key_info,
{ {
key_length-= HA_KEY_BLOB_LENGTH; key_length-= HA_KEY_BLOB_LENGTH;
length= min(key_length, key_part->length); length= min(key_length, key_part->length);
key_part->field->get_key_image(to_key, length, Field::itRAW); uint bytes= key_part->field->get_key_image(to_key, length, Field::itRAW);
if (with_zerofill && bytes < length)
bzero((char*) to_key + bytes, length - bytes);
to_key+= HA_KEY_BLOB_LENGTH; to_key+= HA_KEY_BLOB_LENGTH;
} }
else else
......
...@@ -1876,7 +1876,8 @@ void mysql_print_status(); ...@@ -1876,7 +1876,8 @@ void mysql_print_status();
/* key.cc */ /* key.cc */
int find_ref_key(KEY *key, uint key_count, uchar *record, Field *field, int find_ref_key(KEY *key, uint key_count, uchar *record, Field *field,
uint *key_length, uint *keypart); uint *key_length, uint *keypart);
void key_copy(uchar *to_key, uchar *from_record, KEY *key_info, uint key_length); void key_copy(uchar *to_key, uchar *from_record, KEY *key_info, uint key_length,
bool with_zerofill= FALSE);
void key_restore(uchar *to_record, uchar *from_key, KEY *key_info, void key_restore(uchar *to_record, uchar *from_key, KEY *key_info,
uint key_length); uint key_length);
bool key_cmp_if_same(TABLE *form,const uchar *key,uint index,uint key_length); bool key_cmp_if_same(TABLE *form,const uchar *key,uint index,uint key_length);
......
...@@ -3429,7 +3429,7 @@ uchar *JOIN_CACHE_BNLH::get_matching_chain_by_join_key() ...@@ -3429,7 +3429,7 @@ uchar *JOIN_CACHE_BNLH::get_matching_chain_by_join_key()
TABLE_REF *ref= &join_tab->ref; TABLE_REF *ref= &join_tab->ref;
KEY *keyinfo= table->key_info+ref->key; KEY *keyinfo= table->key_info+ref->key;
/* Build the join key value out of the record in the record buffer */ /* Build the join key value out of the record in the record buffer */
key_copy(key_buff, table->record[0], keyinfo, key_length); key_copy(key_buff, table->record[0], keyinfo, key_length, TRUE);
/* Look for this key in the join buffer */ /* Look for this key in the join buffer */
if (!key_search(key_buff, key_length, &key_ref_ptr)) if (!key_search(key_buff, key_length, &key_ref_ptr))
return 0; return 0;
......
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