From 3add511de79f8d3f3856cdcb9770037705c3d88e Mon Sep 17 00:00:00 2001 From: "ingo@mysql.com" <> Date: Fri, 8 Apr 2005 14:13:02 +0200 Subject: [PATCH 1/3] 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 | 51 ++++++++++++++++++++++++++++++++------ myisam/mi_write.c | 26 +++++++++++++++++-- mysql-test/r/myisam.result | 8 ++++++ mysql-test/t/myisam.test | 10 ++++++++ 4 files changed, 85 insertions(+), 10 deletions(-) diff --git a/myisam/mi_search.c b/myisam/mi_search.c index bc8be9c2732..390e32b679d 100644 --- a/myisam/mi_search.c +++ b/myisam/mi_search.c @@ -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; diff --git a/myisam/mi_write.c b/myisam/mi_write.c index 7d053ddfd22..cd9e73fba22 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -414,8 +414,30 @@ err: } /* 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, diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index eaed7c620e3..5b69ce68a79 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -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; diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 0babd1f9401..46a6499adad 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -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; + From 533e0551f20afb356936c2ecd966721c911d688e Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Thu, 14 Apr 2005 18:14:54 +0200 Subject: [PATCH 2/3] TRUNCATE is always a transaction on itself. pretent we're in auto-commit mode bug#8151 --- mysql-test/r/innodb.result | 1 + mysql-test/t/innodb.test | 1 + sql/sql_delete.cc | 8 ++++++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index c282ec68c78..f00679801f8 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -821,6 +821,7 @@ truncate table t1; Can't execute the given command because you have active locked tables or an active transaction commit; truncate table t1; +truncate table t1; select * from t1; a insert into t1 values(1),(2); diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 34eabcc22df..2c8002ea841 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -528,6 +528,7 @@ insert into t1 values(1),(2); truncate table t1; commit; truncate table t1; +truncate table t1; select * from t1; insert into t1 values(1),(2); delete from t1; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 475df34dc4f..166a0e130e3 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -590,8 +590,12 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) { /* Probably InnoDB table */ table_list->lock_type= TL_WRITE; - DBUG_RETURN(mysql_delete(thd, table_list, (COND*) 0, (ORDER*) 0, - HA_POS_ERROR, 0)); + ulong save_options= thd->options; + thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT); + int res= mysql_delete(thd, table_list, (COND*) 0, (ORDER*) 0, + HA_POS_ERROR, 0); + thd->options= save_options; + DBUG_RETURN(res); } if (lock_and_wait_for_table_name(thd, table_list)) DBUG_RETURN(-1); From 08ae28f4b8569f7e2cc1238e8b4bd9853bddcd12 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Fri, 15 Apr 2005 19:20:15 +0200 Subject: [PATCH 3/3] BUG#9922 - INSERT SELECT with UNIONs allows concurrent INSERTs don't set lex->lock_option=TL_READ in the parser for SELECT --- sql/sql_lex.cc | 1 + sql/sql_yacc.yy | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index d62edf83c11..20aacf42be0 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -147,6 +147,7 @@ LEX *lex_start(THD *thd, uchar *buf,uint length) lex->select->in_sum_expr=0; lex->select->expr_list.empty(); lex->select->ftfunc_list.empty(); + lex->lock_option=TL_READ; lex->convert_set=(lex->thd=thd)->variables.convert_set; lex->yacc_yyss=lex->yacc_yyvs=0; lex->ignore_space=test(thd->sql_mode & MODE_IGNORE_SPACE); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 39b57061507..8c5c4d61d1d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1531,7 +1531,6 @@ select_init: select_part2: { LEX *lex=Lex; - lex->lock_option=TL_READ; mysql_init_select(lex); } select_options select_item_list select_into select_lock_type;