Commit 7ff8fc73 authored by unknown's avatar unknown
Browse files

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.


myisam/mi_search.c:
  Bug#9188 - Corruption Can't open file: 'table.MYI' (errno: 145)
  Fixed some function comments.
  In the case when we insert a different key between two identical keys,
  the difference must be additional spaces. In this case the prefix is 
  the same as that of the new key instead of the (zero) remaining length.
myisam/mi_write.c:
  Bug#9188 - Corruption Can't open file: 'table.MYI' (errno: 145)
  Fixed a function comment.
mysql-test/r/myisam.result:
  Bug#9188 - Corruption Can't open file: 'table.MYI' (errno: 145)
  The test result.
mysql-test/t/myisam.test:
  Bug#9188 - Corruption Can't open file: 'table.MYI' (errno: 145)
  The test case.
parent 98e615ba
Loading
Loading
Loading
Loading
+43 −8
Original line number Diff line number Diff line
@@ -210,9 +210,31 @@ int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
} /* _mi_bin_search */


        /* Used instead of _mi_bin_search() when key is packed */
        /* Puts smaller or identical key in buff */
        /* Key is searched sequentially */
/*
  Locate a packed key in a key page.

  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,
                   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,
} /* _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,
                      register uchar **page_pos, register uchar *key)
@@ -1339,12 +1373,12 @@ _mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag,

  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

  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]       Length character of data
  [length]       data bytes ('length' bytes)
  next-key-seg   Next key segments

  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,
            s_temp->part_of_prev_key= new_ref_length;
            s_temp->prev_length=          org_key_length -
              (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);
            s_temp->prev_key+=    (new_ref_length - pack_marker);
            length+=              s_temp->prev_length + n_length;
+24 −2
Original line number Diff line number Diff line
@@ -414,8 +414,30 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
} /* 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,
	       uchar *key, uchar *anc_buff, uchar *key_pos, uchar *key_buff,
+8 −0
Original line number Diff line number Diff line
@@ -573,3 +573,11 @@ truncate table t1;
ERROR HY000: MyISAM table 't1' is in use (most likely by a MERGE table). Try FLUSH TABLES.
insert into t1 values (1);
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;
+10 −0
Original line number Diff line number Diff line
@@ -550,3 +550,13 @@ truncate table t1;
insert into t1 values (1);
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;