Commit 1c33fbc4 authored by ingo@mysql.com's avatar ingo@mysql.com

Bug#10178 - failure to find a row in heap table by concurrent UPDATEs

Bug#10568 - Function 'LAST_DAY(date)' does not return NULL for invalid argument.
Manual merge.
parents 182c0ca5 2dcf451b
...@@ -295,10 +295,8 @@ C_MODE_END ...@@ -295,10 +295,8 @@ C_MODE_END
#include <alloca.h> #include <alloca.h>
#endif #endif
#ifdef HAVE_ATOMIC_ADD #ifdef HAVE_ATOMIC_ADD
#if defined(__ia64__)
#define new my_arg_new #define new my_arg_new
#define need_to_restore_new 1 #define need_to_restore_new 1
#endif
C_MODE_START C_MODE_START
#include <asm/atomic.h> #include <asm/atomic.h>
C_MODE_END C_MODE_END
......
...@@ -231,18 +231,19 @@ explain select * from t1 where a='aaad'; ...@@ -231,18 +231,19 @@ explain select * from t1 where a='aaad';
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where 1 SIMPLE t1 ref a a 8 const 1 Using where
insert into t1 select * from t1; insert into t1 select * from t1;
flush tables;
explain select * from t1 where a='aaaa'; explain select * from t1 where a='aaaa';
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where 1 SIMPLE t1 ref a a 8 const 2 Using where
explain select * from t1 where a='aaab'; explain select * from t1 where a='aaab';
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where 1 SIMPLE t1 ref a a 8 const 2 Using where
explain select * from t1 where a='aaac'; explain select * from t1 where a='aaac';
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where 1 SIMPLE t1 ref a a 8 const 2 Using where
explain select * from t1 where a='aaad'; explain select * from t1 where a='aaad';
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where 1 SIMPLE t1 ref a a 8 const 2 Using where
flush tables; flush tables;
explain select * from t1 where a='aaaa'; explain select * from t1 where a='aaaa';
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
...@@ -261,16 +262,16 @@ delete from t1; ...@@ -261,16 +262,16 @@ delete from t1;
insert into t1 select * from t2; insert into t1 select * from t2;
explain select * from t1 where a='aaaa'; explain select * from t1 where a='aaaa';
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where 1 SIMPLE t1 ref a a 8 const 2 Using where
explain select * from t1 where a='aaab'; explain select * from t1 where a='aaab';
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where 1 SIMPLE t1 ref a a 8 const 2 Using where
explain select * from t1 where a='aaac'; explain select * from t1 where a='aaac';
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where 1 SIMPLE t1 ref a a 8 const 2 Using where
explain select * from t1 where a='aaad'; explain select * from t1 where a='aaad';
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where 1 SIMPLE t1 ref a a 8 const 2 Using where
drop table t1, t2; drop table t1, t2;
create table t1 ( create table t1 (
id int unsigned not null primary key auto_increment, id int unsigned not null primary key auto_increment,
...@@ -345,14 +346,14 @@ insert into t3 select name, name from t1; ...@@ -345,14 +346,14 @@ insert into t3 select name, name from t1;
show index from t3; show index from t3;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t3 1 a 1 a NULL NULL NULL NULL HASH t3 1 a 1 a NULL NULL NULL NULL HASH
t3 1 a 2 b NULL 15 NULL NULL HASH t3 1 a 2 b NULL 13 NULL NULL HASH
show index from t3; show index from t3;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t3 1 a 1 a NULL NULL NULL NULL HASH t3 1 a 1 a NULL NULL NULL NULL HASH
t3 1 a 2 b NULL 15 NULL NULL HASH t3 1 a 2 b NULL 13 NULL NULL HASH
explain select * from t1 ignore key(btree_idx), t3 where t1.name='matt' and t3.a = concat('',t1.name) and t3.b=t1.name; explain select * from t1 ignore key(btree_idx), t3 where t1.name='matt' and t3.a = concat('',t1.name) and t3.b=t1.name;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t3 ref a a 44 const,const 6 Using where 1 SIMPLE t3 ref a a 44 const,const 7 Using where
1 SIMPLE t1 ref heap_idx heap_idx 22 const 7 Using where 1 SIMPLE t1 ref heap_idx heap_idx 22 const 7 Using where
drop table t1, t2, t3; drop table t1, t2, t3;
create temporary table t1 ( a int, index (a) ) engine=memory; create temporary table t1 ( a int, index (a) ) engine=memory;
......
...@@ -169,6 +169,8 @@ explain select * from t1 where a='aaac'; ...@@ -169,6 +169,8 @@ explain select * from t1 where a='aaac';
explain select * from t1 where a='aaad'; explain select * from t1 where a='aaad';
insert into t1 select * from t1; insert into t1 select * from t1;
# avoid statistics differences between normal and ps-protocol tests
flush tables;
explain select * from t1 where a='aaaa'; explain select * from t1 where a='aaaa';
explain select * from t1 where a='aaab'; explain select * from t1 where a='aaab';
explain select * from t1 where a='aaac'; explain select * from t1 where a='aaac';
......
...@@ -65,7 +65,15 @@ int ha_heap::open(const char *name, int mode, uint test_if_locked) ...@@ -65,7 +65,15 @@ int ha_heap::open(const char *name, int mode, uint test_if_locked)
{ {
/* Initialize variables for the opened table */ /* Initialize variables for the opened table */
set_keys_for_scanning(); set_keys_for_scanning();
update_key_stats(); /*
We cannot run update_key_stats() here because we do not have a
lock on the table. The 'records' count might just be changed
temporarily at this moment and we might get wrong statistics (Bug
#10178). Instead we request for update. This will be done in
ha_heap::info(), which is always called before key statistics are
used.
*/
key_stats_ok= FALSE;
} }
return (file ? 0 : 1); return (file ? 0 : 1);
} }
...@@ -118,6 +126,8 @@ void ha_heap::update_key_stats() ...@@ -118,6 +126,8 @@ void ha_heap::update_key_stats()
} }
} }
records_changed= 0; records_changed= 0;
/* At the end of update_key_stats() we can proudly claim they are OK. */
key_stats_ok= TRUE;
} }
...@@ -132,7 +142,7 @@ int ha_heap::write_row(byte * buf) ...@@ -132,7 +142,7 @@ int ha_heap::write_row(byte * buf)
res= heap_write(file,buf); res= heap_write(file,buf);
if (!res && (++records_changed*HEAP_STATS_UPDATE_THRESHOLD > if (!res && (++records_changed*HEAP_STATS_UPDATE_THRESHOLD >
file->s->records)) file->s->records))
update_key_stats(); key_stats_ok= FALSE;
return res; return res;
} }
...@@ -145,7 +155,7 @@ int ha_heap::update_row(const byte * old_data, byte * new_data) ...@@ -145,7 +155,7 @@ int ha_heap::update_row(const byte * old_data, byte * new_data)
res= heap_update(file,old_data,new_data); res= heap_update(file,old_data,new_data);
if (!res && ++records_changed*HEAP_STATS_UPDATE_THRESHOLD > if (!res && ++records_changed*HEAP_STATS_UPDATE_THRESHOLD >
file->s->records) file->s->records)
update_key_stats(); key_stats_ok= FALSE;
return res; return res;
} }
...@@ -156,7 +166,7 @@ int ha_heap::delete_row(const byte * buf) ...@@ -156,7 +166,7 @@ int ha_heap::delete_row(const byte * buf)
res= heap_delete(file,buf); res= heap_delete(file,buf);
if (!res && table->s->tmp_table == NO_TMP_TABLE && if (!res && table->s->tmp_table == NO_TMP_TABLE &&
++records_changed*HEAP_STATS_UPDATE_THRESHOLD > file->s->records) ++records_changed*HEAP_STATS_UPDATE_THRESHOLD > file->s->records)
update_key_stats(); key_stats_ok= FALSE;
return res; return res;
} }
...@@ -278,6 +288,13 @@ void ha_heap::info(uint flag) ...@@ -278,6 +288,13 @@ void ha_heap::info(uint flag)
delete_length= info.deleted * info.reclength; delete_length= info.deleted * info.reclength;
if (flag & HA_STATUS_AUTO) if (flag & HA_STATUS_AUTO)
auto_increment_value= info.auto_increment; auto_increment_value= info.auto_increment;
/*
If info() is called for the first time after open(), we will still
have to update the key statistics. Hoping that a table lock is now
in place.
*/
if (! key_stats_ok)
update_key_stats();
} }
int ha_heap::extra(enum ha_extra_function operation) int ha_heap::extra(enum ha_extra_function operation)
...@@ -289,7 +306,7 @@ int ha_heap::delete_all_rows() ...@@ -289,7 +306,7 @@ int ha_heap::delete_all_rows()
{ {
heap_clear(file); heap_clear(file);
if (table->s->tmp_table == NO_TMP_TABLE) if (table->s->tmp_table == NO_TMP_TABLE)
update_key_stats(); key_stats_ok= FALSE;
return 0; return 0;
} }
...@@ -448,6 +465,9 @@ ha_rows ha_heap::records_in_range(uint inx, key_range *min_key, ...@@ -448,6 +465,9 @@ ha_rows ha_heap::records_in_range(uint inx, key_range *min_key,
min_key->flag != HA_READ_KEY_EXACT || min_key->flag != HA_READ_KEY_EXACT ||
max_key->flag != HA_READ_AFTER_KEY) max_key->flag != HA_READ_AFTER_KEY)
return HA_POS_ERROR; // Can only use exact keys return HA_POS_ERROR; // Can only use exact keys
/* Assert that info() did run. We need current statistics here. */
DBUG_ASSERT(key_stats_ok);
return key->rec_per_key[key->key_parts-1]; return key->rec_per_key[key->key_parts-1];
} }
......
...@@ -29,8 +29,10 @@ class ha_heap: public handler ...@@ -29,8 +29,10 @@ class ha_heap: public handler
key_map btree_keys; key_map btree_keys;
/* number of records changed since last statistics update */ /* number of records changed since last statistics update */
uint records_changed; uint records_changed;
bool key_stats_ok;
public: public:
ha_heap(TABLE *table): handler(table), file(0), records_changed(0) {} ha_heap(TABLE *table): handler(table), file(0), records_changed(0),
key_stats_ok(0) {}
~ha_heap() {} ~ha_heap() {}
const char *table_type() const const char *table_type() const
{ {
......
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