From fbe17c2a36dcaa99c5a6570f7096745126113301 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 10 Mar 2006 15:03:04 +0100 Subject: [PATCH] Bug#14980 - COUNT(*) incorrect on MyISAM table with certain INDEX For "count(*) while index_column = value" an index read is done. It consists of an index scan and retrieval of each key. For efficiency reasons the index scan stores the key in the special buffer 'lastkey2' once only. At the first iteration it notes this fact with the flag HA_STATE_RNEXT_SAME in 'info->update'. For efficiency reasons, the key retrieval for blobs does not allocate a new buffer, but uses 'lastkey2'... Now I clear the HA_STATE_RNEXT_SAME flag whenever the buffer has been polluted. In this case, the index scan copies the key value again (and sets the flag again). include/my_base.h: Bug#14980 - COUNT(*) incorrect on MyISAM table with certain INDEX Changed the comment for HA_STATE_RNEXT_SAME as a warning for future uses. myisam/mi_delete.c: Bug#14980 - COUNT(*) incorrect on MyISAM table with certain INDEX Removing the flag HA_STATE_RNEXT_SAME from info->update if info->lastkey2 was reused for another purpose than index scanning. myisam/mi_key.c: Bug#14980 - COUNT(*) incorrect on MyISAM table with certain INDEX Removing the flag HA_STATE_RNEXT_SAME from info->update if info->lastkey2 was reused for another purpose than index scanning. myisam/mi_rnext_same.c: Bug#14980 - COUNT(*) incorrect on MyISAM table with certain INDEX Removed trailing space and fixed a comment. myisam/mi_unique.c: Bug#14980 - COUNT(*) incorrect on MyISAM table with certain INDEX Removing the flag HA_STATE_RNEXT_SAME from info->update if info->lastkey2 was reused for another purpose than index scanning. myisam/mi_update.c: Bug#14980 - COUNT(*) incorrect on MyISAM table with certain INDEX Removing the flag HA_STATE_RNEXT_SAME from info->update if info->lastkey2 was reused for another purpose than index scanning. myisam/mi_write.c: Bug#14980 - COUNT(*) incorrect on MyISAM table with certain INDEX Removing the flag HA_STATE_RNEXT_SAME from info->update if info->lastkey2 was reused for another purpose than index scanning. mysql-test/r/myisam.result: Bug#14980 - COUNT(*) incorrect on MyISAM table with certain INDEX Added test result. mysql-test/t/myisam.test: Bug#14980 - COUNT(*) incorrect on MyISAM table with certain INDEX Added test. --- include/my_base.h | 2 +- myisam/mi_delete.c | 2 ++ myisam/mi_key.c | 4 ++++ myisam/mi_rnext_same.c | 4 ++-- myisam/mi_unique.c | 3 +++ myisam/mi_update.c | 4 ++++ myisam/mi_write.c | 4 ++++ mysql-test/r/myisam.result | 18 ++++++++++++++++++ mysql-test/t/myisam.test | 19 +++++++++++++++++++ 9 files changed, 57 insertions(+), 3 deletions(-) diff --git a/include/my_base.h b/include/my_base.h index 271e7cd23ba..1261a95175f 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -340,7 +340,7 @@ enum ha_base_keytype { #define HA_STATE_BUFF_SAVED 512 /* If current keybuff is info->buff */ #define HA_STATE_ROW_CHANGED 1024 /* To invalide ROW cache */ #define HA_STATE_EXTEND_BLOCK 2048 -#define HA_STATE_RNEXT_SAME 4096 /* rnext_same was called */ +#define HA_STATE_RNEXT_SAME 4096 /* rnext_same occupied lastkey2 */ enum en_fieldtype { FIELD_LAST=-1,FIELD_NORMAL,FIELD_SKIP_ENDSPACE,FIELD_SKIP_PRESPACE, diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c index 6c302aecea1..00699e8b089 100644 --- a/myisam/mi_delete.c +++ b/myisam/mi_delete.c @@ -82,6 +82,8 @@ int mi_delete(MI_INFO *info,const byte *record) _mi_make_key(info,i,old_key,record,info->lastpos))) goto err; } + /* The above changed info->lastkey2. Inform mi_rnext_same(). */ + info->update&= ~HA_STATE_RNEXT_SAME; } } diff --git a/myisam/mi_key.c b/myisam/mi_key.c index f4b92f969db..cb85febd869 100644 --- a/myisam/mi_key.c +++ b/myisam/mi_key.c @@ -393,6 +393,10 @@ static int _mi_put_key_in_record(register MI_INFO *info, uint keynr, (char*) &blob_ptr,sizeof(char*)); memcpy(blob_ptr,key,length); blob_ptr+=length; + + /* The above changed info->lastkey2. Inform mi_rnext_same(). */ + info->update&= ~HA_STATE_RNEXT_SAME; + _my_store_blob_length(record+keyseg->start, (uint) keyseg->bit_start,length); key+=length; diff --git a/myisam/mi_rnext_same.c b/myisam/mi_rnext_same.c index 92692d0517f..64d8d9b0baa 100644 --- a/myisam/mi_rnext_same.c +++ b/myisam/mi_rnext_same.c @@ -40,7 +40,7 @@ int mi_rnext_same(MI_INFO *info, byte *buf) if (info->s->concurrent_insert) rw_rdlock(&info->s->key_root_lock[inx]); - + switch (keyinfo->key_alg) { #ifdef HAVE_RTREE_KEYS @@ -102,4 +102,4 @@ int mi_rnext_same(MI_INFO *info, byte *buf) DBUG_RETURN(0); } DBUG_RETURN(my_errno); -} /* mi_rnext */ +} /* mi_rnext_same */ diff --git a/myisam/mi_unique.c b/myisam/mi_unique.c index ad685f4cbdc..b5baa448609 100644 --- a/myisam/mi_unique.c +++ b/myisam/mi_unique.c @@ -30,6 +30,9 @@ my_bool mi_check_unique(MI_INFO *info, MI_UNIQUEDEF *def, byte *record, mi_unique_store(record+key->seg->start, unique_hash); _mi_make_key(info,def->key,key_buff,record,0); + /* The above changed info->lastkey2. Inform mi_rnext_same(). */ + info->update&= ~HA_STATE_RNEXT_SAME; + if (_mi_search(info,info->s->keyinfo+def->key,key_buff,MI_UNIQUE_HASH_LENGTH, SEARCH_FIND,info->s->state.key_root[def->key])) { diff --git a/myisam/mi_update.c b/myisam/mi_update.c index f62be133ed9..672c8407353 100644 --- a/myisam/mi_update.c +++ b/myisam/mi_update.c @@ -108,6 +108,10 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec) { uint new_length=_mi_make_key(info,i,new_key,newrec,pos); uint old_length=_mi_make_key(info,i,old_key,oldrec,pos); + + /* The above changed info->lastkey2. Inform mi_rnext_same(). */ + info->update&= ~HA_STATE_RNEXT_SAME; + if (new_length != old_length || memcmp((byte*) old_key,(byte*) new_key,new_length)) { diff --git a/myisam/mi_write.c b/myisam/mi_write.c index 52455320515..720c96b2d38 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -128,6 +128,10 @@ int mi_write(MI_INFO *info, byte *record) goto err; } } + + /* The above changed info->lastkey2. Inform mi_rnext_same(). */ + info->update&= ~HA_STATE_RNEXT_SAME; + if (local_lock_tree) rw_unlock(&share->key_root_lock[i]); } diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index c269cbadca3..3b4519e5444 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -730,3 +730,21 @@ select * from t1 where bob is null and cip=1; cip time score bob 1 00:01:00 0 NULL drop table t1; +create table t1 ( +id1 int not null auto_increment, +id2 int not null default '0', +t text not null, +primary key (id1), +key x (id2, t(32)) +) engine=myisam; +insert into t1 (id2, t) values +(10, 'abc'), (10, 'abc'), (10, 'abc'), +(20, 'abc'), (20, 'abc'), (20, 'def'), +(10, 'abc'), (10, 'abc'); +select count(*) from t1 where id2 = 10; +count(*) +5 +select count(id1) from t1 where id2 = 10; +count(id1) +5 +drop table t1; diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index ce40cae3266..7e4cc324b12 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -686,4 +686,23 @@ select * from t1 where bob is null and cip=1; create index bug on t1 (bob(22), cip, time); select * from t1 where bob is null and cip=1; drop table t1; + +# +# Bug#14980 - COUNT(*) incorrect on MyISAM table with certain INDEX +# +create table t1 ( + id1 int not null auto_increment, + id2 int not null default '0', + t text not null, + primary key (id1), + key x (id2, t(32)) +) engine=myisam; +insert into t1 (id2, t) values +(10, 'abc'), (10, 'abc'), (10, 'abc'), +(20, 'abc'), (20, 'abc'), (20, 'def'), +(10, 'abc'), (10, 'abc'); +select count(*) from t1 where id2 = 10; +select count(id1) from t1 where id2 = 10; +drop table t1; + # End of 4.1 tests