Commit 3add511d authored by ingo@mysql.com's avatar ingo@mysql.com

Bug#9188 - Corruption Can't open file: 'table.MYI' (errno: 145)

Since 4.1 keys are compared with trailing spaces. 
Thus, a "x " key can be inserted between a couple of "x" keys.
The existing code did not take this into account. Though the
comments in the code claimed it did.
parent da53d7bc
...@@ -210,9 +210,31 @@ int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, ...@@ -210,9 +210,31 @@ int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
} /* _mi_bin_search */ } /* _mi_bin_search */
/* Used instead of _mi_bin_search() when key is packed */ /*
/* Puts smaller or identical key in buff */ Locate a packed key in a key page.
/* Key is searched sequentially */
SYNOPSIS
_mi_seq_search()
info Open table information.
keyinfo Key definition information.
page Key page (beginning).
key Search key.
key_len Length to use from search key or USE_WHOLE_KEY
comp_flag Search flags like SEARCH_SAME etc.
ret_pos RETURN Position in key page behind this key.
buff RETURN Copy of previous or identical unpacked key.
last_key RETURN If key is last in page.
DESCRIPTION
Used instead of _mi_bin_search() when key is packed.
Puts smaller or identical key in buff.
Key is searched sequentially.
RETURN
> 0 Key in 'buff' is smaller than search key.
0 Key in 'buff' is identical to search key.
< 0 Not found.
*/
int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
uchar *key, uint key_len, uint comp_flag, uchar **ret_pos, uchar *key, uint key_len, uint comp_flag, uchar **ret_pos,
...@@ -718,7 +740,19 @@ uint _mi_get_static_key(register MI_KEYDEF *keyinfo, uint nod_flag, ...@@ -718,7 +740,19 @@ uint _mi_get_static_key(register MI_KEYDEF *keyinfo, uint nod_flag,
} /* _mi_get_static_key */ } /* _mi_get_static_key */
/* Key with is packed against previous key or key with a NULL column */ /*
get key witch is packed against previous key or key with a NULL column.
SYNOPSIS
_mi_get_pack_key()
keyinfo key definition information.
nod_flag If nod: Length of node pointer, else zero.
page_pos RETURN position in key page behind this key.
key IN/OUT in: prev key, out: unpacked key.
RETURN
key_length + length of data pointer
*/
uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
register uchar **page_pos, register uchar *key) register uchar **page_pos, register uchar *key)
...@@ -1339,12 +1373,12 @@ _mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag, ...@@ -1339,12 +1373,12 @@ _mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
Keys are compressed the following way: Keys are compressed the following way:
If the max length of first key segment <= 127 characters the prefix is If the max length of first key segment <= 127 bytes the prefix is
1 byte else it's 2 byte 1 byte else it's 2 byte
prefix byte The high bit is set if this is a prefix for the prev key 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 Packed length if the previous was a prefix byte
[length] Length character of data [length] data bytes ('length' bytes)
next-key-seg Next key segments next-key-seg Next key segments
If the first segment can have NULL: If the first segment can have NULL:
...@@ -1537,7 +1571,8 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, ...@@ -1537,7 +1571,8 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
s_temp->part_of_prev_key= new_ref_length; s_temp->part_of_prev_key= new_ref_length;
s_temp->prev_length= org_key_length - s_temp->prev_length= org_key_length -
(new_ref_length-pack_marker); (new_ref_length-pack_marker);
s_temp->n_ref_length= s_temp->n_length= s_temp->prev_length; s_temp->n_ref_length= s_temp->part_of_prev_key;
s_temp->n_length= s_temp->prev_length;
n_length= get_pack_length(s_temp->prev_length); n_length= get_pack_length(s_temp->prev_length);
s_temp->prev_key+= (new_ref_length - pack_marker); s_temp->prev_key+= (new_ref_length - pack_marker);
length+= s_temp->prev_length + n_length; length+= s_temp->prev_length + n_length;
......
...@@ -414,8 +414,30 @@ err: ...@@ -414,8 +414,30 @@ err:
} /* w_search */ } /* w_search */
/* Insert new key at right of key_pos */ /*
/* Returns 2 if key contains key to upper level */ Insert new key.
SYNOPSIS
_mi_insert()
info Open table information.
keyinfo Key definition information.
key New key.
anc_buff Key page (beginning).
key_pos Position in key page where to insert.
key_buff Copy of previous key.
father_buff parent key page for balancing.
father_key_pos position in parent key page for balancing.
father_page position of parent key page in file.
insert_last If to append at end of page.
DESCRIPTION
Insert new key at right of key_pos.
RETURN
2 if key contains key to upper level.
0 OK.
< 0 Error.
*/
int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo, int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo,
uchar *key, uchar *anc_buff, uchar *key_pos, uchar *key_buff, uchar *key, uchar *anc_buff, uchar *key_pos, uchar *key_buff,
......
...@@ -573,3 +573,11 @@ truncate table t1; ...@@ -573,3 +573,11 @@ truncate table t1;
ERROR HY000: MyISAM table 't1' is in use (most likely by a MERGE table). Try FLUSH TABLES. ERROR HY000: MyISAM table 't1' is in use (most likely by a MERGE table). Try FLUSH TABLES.
insert into t1 values (1); insert into t1 values (1);
drop table t1,t2; drop table t1,t2;
create table t1 (c1 int, c2 varchar(4) not null default '',
key(c2(3))) default charset=utf8;
insert into t1 values (1,'A'), (2, 'B'), (3, 'A');
update t1 set c2='A B' where c1=2;
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
...@@ -550,3 +550,13 @@ truncate table t1; ...@@ -550,3 +550,13 @@ truncate table t1;
insert into t1 values (1); insert into t1 values (1);
drop table t1,t2; drop table t1,t2;
#
# bug9188 - Corruption Can't open file: 'table.MYI' (errno: 145)
#
create table t1 (c1 int, c2 varchar(4) not null default '',
key(c2(3))) default charset=utf8;
insert into t1 values (1,'A'), (2, 'B'), (3, 'A');
update t1 set c2='A B' where c1=2;
check table t1;
drop table t1;
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