mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
Fixed rare bug in MYISAM introduced in 4.0.3 where the index file header was not updated directly after an UPDATE of split dynamic rows.
myisam/mi_locking.c: Added DBUG info myisam/mi_open.c: Added DBUG info myisam/mi_update.c: More comments Fixed rare bug in MYISAM introduced in 4.0.3 where the index file header was not updated directly after an UPDATE of split dynamic rows. mysql-test/r/myisam.result: Added test case for MyISAM UPDATE bug mysql-test/t/myisam.test: Added test case for MyISAM UPDATE bug
This commit is contained in:
@ -76,6 +76,8 @@ int mi_lock_database(MI_INFO *info, int lock_type)
|
||||
}
|
||||
if (!count)
|
||||
{
|
||||
DBUG_PRINT("info",("changed: %u w_locks: %u",
|
||||
(uint) share->changed, share->w_locks));
|
||||
if (share->changed && !share->w_locks)
|
||||
{
|
||||
share->state.process= share->last_process=share->this_process;
|
||||
@ -352,6 +354,8 @@ int _mi_writeinfo(register MI_INFO *info, uint operation)
|
||||
int error,olderror;
|
||||
MYISAM_SHARE *share=info->s;
|
||||
DBUG_ENTER("_mi_writeinfo");
|
||||
DBUG_PRINT("info",("operation: %u tot_locks: %u", operation,
|
||||
share->tot_locks));
|
||||
|
||||
error=0;
|
||||
if (share->tot_locks == 0)
|
||||
@ -379,9 +383,7 @@ int _mi_writeinfo(register MI_INFO *info, uint operation)
|
||||
my_errno=olderror;
|
||||
}
|
||||
else if (operation)
|
||||
{
|
||||
share->changed= 1; /* Mark keyfile changed */
|
||||
}
|
||||
DBUG_RETURN(error);
|
||||
} /* _mi_writeinfo */
|
||||
|
||||
|
@ -730,6 +730,7 @@ uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite)
|
||||
uchar *ptr=buff;
|
||||
uint i, keys= (uint) state->header.keys,
|
||||
key_blocks=state->header.max_block_size;
|
||||
DBUG_ENTER("mi_state_info_write");
|
||||
|
||||
memcpy_fixed(ptr,&state->header,sizeof(state->header));
|
||||
ptr+=sizeof(state->header);
|
||||
@ -780,10 +781,10 @@ uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite)
|
||||
}
|
||||
|
||||
if (pWrite & 1)
|
||||
return my_pwrite(file,(char*) buff, (uint) (ptr-buff), 0L,
|
||||
MYF(MY_NABP | MY_THREADSAFE));
|
||||
else
|
||||
return my_write(file, (char*) buff, (uint) (ptr-buff), MYF(MY_NABP));
|
||||
DBUG_RETURN(my_pwrite(file,(char*) buff, (uint) (ptr-buff), 0L,
|
||||
MYF(MY_NABP | MY_THREADSAFE)));
|
||||
DBUG_RETURN(my_write(file, (char*) buff, (uint) (ptr-buff),
|
||||
MYF(MY_NABP)));
|
||||
}
|
||||
|
||||
|
||||
|
@ -94,7 +94,14 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec)
|
||||
if (_mi_ft_cmp(info,i,oldrec, newrec))
|
||||
{
|
||||
if ((int) i == info->lastinx)
|
||||
{
|
||||
/*
|
||||
We are changeing the index we are reading on. Mark that
|
||||
the index data has changed and we need to do a full search
|
||||
when doing read-next
|
||||
*/
|
||||
key_changed|=HA_STATE_WRITTEN;
|
||||
}
|
||||
changed|=((ulonglong) 1 << i);
|
||||
if (_mi_ft_update(info,i,(char*) old_key,oldrec,newrec,pos))
|
||||
goto err;
|
||||
@ -121,25 +128,36 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec)
|
||||
}
|
||||
/*
|
||||
If we are running with external locking, we must update the index file
|
||||
that something has changed
|
||||
that something has changed.
|
||||
*/
|
||||
if (changed || !my_disable_locking)
|
||||
key_changed|= HA_STATE_KEY_CHANGED;
|
||||
key_changed|= HA_STATE_CHANGED;
|
||||
|
||||
if (share->calc_checksum)
|
||||
{
|
||||
info->checksum=(*share->calc_checksum)(info,newrec);
|
||||
key_changed|= HA_STATE_KEY_CHANGED; /* Must update index file */
|
||||
/* Store new checksum in index file header */
|
||||
key_changed|= HA_STATE_CHANGED;
|
||||
}
|
||||
{
|
||||
/* Don't update index file if data file is not extended */
|
||||
/*
|
||||
Don't update index file if data file is not extended and no status
|
||||
information changed
|
||||
*/
|
||||
MI_STATUS_INFO state;
|
||||
ha_rows org_split;
|
||||
my_off_t org_delete_link;
|
||||
|
||||
memcpy((char*) &state, (char*) info->state, sizeof(state));
|
||||
org_split= share->state.split;
|
||||
org_delete_link= share->state.dellink;
|
||||
if ((*share->update_record)(info,pos,newrec))
|
||||
goto err;
|
||||
if (!key_changed &&
|
||||
memcmp((char*) &state, (char*) info->state, sizeof(state)))
|
||||
key_changed|= HA_STATE_KEY_CHANGED; /* Must update index file */
|
||||
(memcmp((char*) &state, (char*) info->state, sizeof(state)) ||
|
||||
org_split != share->state.split ||
|
||||
org_delete_link != share->state.dellink))
|
||||
key_changed|= HA_STATE_CHANGED; /* Must update index file */
|
||||
}
|
||||
if (auto_key_changed)
|
||||
update_auto_increment(info,newrec);
|
||||
@ -163,7 +181,7 @@ err:
|
||||
DBUG_PRINT("error",("key: %d errno: %d",i,my_errno));
|
||||
save_errno=my_errno;
|
||||
if (changed)
|
||||
key_changed|= HA_STATE_KEY_CHANGED;
|
||||
key_changed|= HA_STATE_CHANGED;
|
||||
if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_RECORD_FILE_FULL)
|
||||
{
|
||||
info->errkey= (int) i;
|
||||
|
@ -364,3 +364,25 @@ explain select * from t1 force index (a) where a=0 or a=2;
|
||||
table type possible_keys key key_len ref rows Extra
|
||||
t1 range a a 4 NULL 4 Using where
|
||||
drop table t1,t2;
|
||||
create table t1 (a int not null auto_increment primary key, b varchar(255));
|
||||
insert into t1 (b) values (repeat('a',100)),(repeat('b',100)),(repeat('c',100));
|
||||
update t1 set b=repeat(left(b,1),200) where a=1;
|
||||
delete from t1 where (a & 1)= 0;
|
||||
update t1 set b=repeat('e',200) where a=1;
|
||||
flush tables;
|
||||
check table t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
update t1 set b=repeat(left(b,1),255) where a between 1 and 5;
|
||||
update t1 set b=repeat(left(b,1),10) where a between 32 and 43;
|
||||
update t1 set b=repeat(left(b,1),2) where a between 64 and 66;
|
||||
update t1 set b=repeat(left(b,1),65) where a between 67 and 70;
|
||||
check table t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
insert into t1 (b) values (repeat('z',100));
|
||||
update t1 set b="test" where left(b,1) > 'n';
|
||||
check table t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
drop table t1;
|
||||
|
@ -352,3 +352,37 @@ explain select * from t1,t2 force index(c) where t1.a=t2.a;
|
||||
explain select * from t1 where a=0 or a=2;
|
||||
explain select * from t1 force index (a) where a=0 or a=2;
|
||||
drop table t1,t2;
|
||||
|
||||
#
|
||||
# Test bug when updating a split dynamic row where keys are not changed
|
||||
#
|
||||
|
||||
create table t1 (a int not null auto_increment primary key, b varchar(255));
|
||||
insert into t1 (b) values (repeat('a',100)),(repeat('b',100)),(repeat('c',100));
|
||||
update t1 set b=repeat(left(b,1),200) where a=1;
|
||||
delete from t1 where (a & 1)= 0;
|
||||
update t1 set b=repeat('e',200) where a=1;
|
||||
flush tables;
|
||||
check table t1;
|
||||
|
||||
#
|
||||
# check updating with keys
|
||||
#
|
||||
|
||||
disable_query_log;
|
||||
let $1 = 100;
|
||||
while ($1)
|
||||
{
|
||||
eval insert into t1 (b) values (repeat(char(($1 & 32)+65), $1));
|
||||
dec $1;
|
||||
}
|
||||
enable_query_log;
|
||||
update t1 set b=repeat(left(b,1),255) where a between 1 and 5;
|
||||
update t1 set b=repeat(left(b,1),10) where a between 32 and 43;
|
||||
update t1 set b=repeat(left(b,1),2) where a between 64 and 66;
|
||||
update t1 set b=repeat(left(b,1),65) where a between 67 and 70;
|
||||
check table t1;
|
||||
insert into t1 (b) values (repeat('z',100));
|
||||
update t1 set b="test" where left(b,1) > 'n';
|
||||
check table t1;
|
||||
drop table t1;
|
||||
|
Reference in New Issue
Block a user