From ba0697c6584d20f730148ec8c5171c2aca48086f Mon Sep 17 00:00:00 2001 From: "ingo@mysql.com" <> Date: Thu, 6 May 2004 16:15:46 +0200 Subject: [PATCH 01/22] Fix a forgotten skip of space at line begin for the 'system' command. --- BitKeeper/etc/logging_ok | 1 + client/mysql.cc | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index b805749821c..a51078f675f 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -39,6 +39,7 @@ hf@deer.mysql.r18.ru hf@genie.(none) igor@hundin.mysql.fi igor@rurik.mysql.com +ingo@mysql.com jani@dsl-jkl1657.dial.inet.fi jani@hynda.(none) jani@hynda.mysql.fi diff --git a/client/mysql.cc b/client/mysql.cc index 695cb1f28be..46ade3aef26 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -2042,6 +2042,10 @@ static int com_shell(String *buffer, char *line __attribute__((unused))) { char *shell_cmd; + + /* Skip space from line begin */ + while (isspace(*line)) + line++; if (!(shell_cmd = strchr(line, ' '))) { put_info("Usage: \\! shell-command", INFO_ERROR); From 7d575447edcf65db4515dd4c17598c26462e2920 Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Thu, 6 May 2004 22:55:30 +0200 Subject: [PATCH 02/22] A DBUG_RETURN to match a DBUG_ENTER --- myisam/mi_dynrec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/myisam/mi_dynrec.c b/myisam/mi_dynrec.c index 2a3f4aec0a8..0ffab05b6bc 100644 --- a/myisam/mi_dynrec.c +++ b/myisam/mi_dynrec.c @@ -311,7 +311,7 @@ static int update_backward_delete_link(MI_INFO *info, my_off_t delete_block, DBUG_RETURN(1); /* Wrong delete link */ } } - return 0; + DBUG_RETURN(0); } /* Delete datarecord from database */ From 6bc03b14d9198a83a8dc668330f053240d1d98f4 Mon Sep 17 00:00:00 2001 From: "jani@a80-186-24-72.elisa-laajakaista.fi" <> Date: Fri, 7 May 2004 01:02:57 +0300 Subject: [PATCH 03/22] Fixed a problem with option --where, which earlier was not dynamic. One was not able to use long query strings with it. Bug#3633 --- BitKeeper/etc/logging_ok | 1 + client/mysqldump.c | 63 ++++++++++++++++++++++++++++++---------- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index b805749821c..ef879971e38 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -39,6 +39,7 @@ hf@deer.mysql.r18.ru hf@genie.(none) igor@hundin.mysql.fi igor@rurik.mysql.com +jani@a80-186-24-72.elisa-laajakaista.fi jani@dsl-jkl1657.dial.inet.fi jani@hynda.(none) jani@hynda.mysql.fi diff --git a/client/mysqldump.c b/client/mysqldump.c index 42b094d2902..f264b9b61c6 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -36,7 +36,7 @@ ** Added --single-transaction option 06/06/2002 by Peter Zaitsev */ -#define DUMP_VERSION "9.10" +#define DUMP_VERSION "9.11" #include #include @@ -938,18 +938,32 @@ static char *field_escape(char *to,const char *from,uint length) } /* field_escape */ +static char *alloc_query_str(ulong size) +{ + char *query; + + if (!(query= (char*) my_malloc(size, MYF(MY_WME)))) + { + ignore_errors= 0; /* Fatal error */ + safe_exit(EX_MYSQLERR); /* Force exit */ + } + return query; +} + /* ** dumpTable saves database contents as a series of INSERT statements. */ static void dumpTable(uint numFields, char *table) { - char query[QUERY_LENGTH], *end, buff[256],table_buff[NAME_LEN+3]; + char query_buf[QUERY_LENGTH], *end, buff[256],table_buff[NAME_LEN+3]; char *result_table, table_buff2[NAME_LEN*2+3], *opt_quoted_table; + char *query= query_buf; MYSQL_RES *res; MYSQL_FIELD *field; MYSQL_ROW row; ulong rownr, row_break, total_length, init_length; const char *table_type; + int error= 0; result_table= quote_name(table,table_buff, 1); opt_quoted_table= quote_name(table, table_buff2, 0); @@ -995,8 +1009,11 @@ static void dumpTable(uint numFields, char *table) sprintf(buff," FROM %s", result_table); end= strmov(end,buff); if (where) - end= strxmov(end, " WHERE ",where,NullS); - if (mysql_query(sock, query)) + { + query= alloc_query_str((ulong) (strlen(where) + (end - query) + 10)); + end= strxmov(query, query_buf, " WHERE ", where, NullS); + } + if (mysql_real_query(sock, query, (uint) (end - query))) { DBerror(sock, "when executing 'SELECT INTO OUTFILE'"); return; @@ -1013,14 +1030,16 @@ static void dumpTable(uint numFields, char *table) { if (!opt_xml && opt_comments) fprintf(md_result_file,"-- WHERE: %s\n",where); - strxmov(strend(query), " WHERE ",where,NullS); + query= alloc_query_str((ulong) (strlen(where) + strlen(query) + 10)); + strxmov(query, query_buf, " WHERE ", where, NullS); } if (!opt_xml) fputs("\n", md_result_file); if (mysql_query(sock, query)) { DBerror(sock, "when retrieving data from server"); - return; + error= EX_CONSCHECK; + goto err; } if (quick) res=mysql_use_result(sock); @@ -1029,7 +1048,8 @@ static void dumpTable(uint numFields, char *table) if (!res) { DBerror(sock, "when retrieving data from server"); - return; + error= EX_CONSCHECK; + goto err; } if (verbose) fprintf(stderr, "-- Retrieving rows...\n"); @@ -1037,8 +1057,8 @@ static void dumpTable(uint numFields, char *table) { fprintf(stderr,"%s: Error in field count for table: %s ! Aborting.\n", my_progname, result_table); - safe_exit(EX_CONSCHECK); - return; + error= EX_CONSCHECK; + goto err; } if (opt_disable_keys) @@ -1076,8 +1096,8 @@ static void dumpTable(uint numFields, char *table) sprintf(query,"%s: Not enough fields from table %s! Aborting.\n", my_progname, result_table); fputs(query,stderr); - safe_exit(EX_CONSCHECK); - return; + error= EX_CONSCHECK; + goto err; } if (extended_insert) { @@ -1096,7 +1116,8 @@ static void dumpTable(uint numFields, char *table) if (dynstr_realloc(&extended_row,length * 2+2)) { fputs("Aborting dump (out of memory)",stderr); - safe_exit(EX_EOM); + error= EX_EOM; + goto err; } dynstr_append(&extended_row,"\'"); extended_row.length += @@ -1131,7 +1152,8 @@ static void dumpTable(uint numFields, char *table) else if (dynstr_append(&extended_row,"NULL")) { fputs("Aborting dump (out of memory)",stderr); - safe_exit(EX_EOM); + error= EX_EOM; + goto err; } } else @@ -1229,8 +1251,8 @@ static void dumpTable(uint numFields, char *table) result_table, rownr); fputs(query,stderr); - safe_exit(EX_CONSCHECK); - return; + error= EX_CONSCHECK; + goto err; } if (opt_lock) fputs("UNLOCK TABLES;\n", md_result_file); @@ -1240,7 +1262,16 @@ static void dumpTable(uint numFields, char *table) if (opt_autocommit) fprintf(md_result_file, "commit;\n"); mysql_free_result(res); - } + if (query != query_buf) + my_free(query, MYF(MY_ALLOW_ZERO_PTR)); + } + return; + +err: + if (query != query_buf) + my_free(query, MYF(MY_ALLOW_ZERO_PTR)); + safe_exit(error); + return; } /* dumpTable */ From c066b3022e9ce6606f6ccc214bbdc3b85a83dfcb Mon Sep 17 00:00:00 2001 From: "marko@hundin.mysql.fi" <> Date: Fri, 7 May 2004 12:13:45 +0300 Subject: [PATCH 04/22] Fix auto_inc locking bug introduced in ChangeSet@1.1794.1.1 --- innobase/row/row0mysql.c | 2 +- mysql-test/r/innodb.result | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index f53a8de2080..bdc47ca0e8e 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -696,7 +696,7 @@ run_again: trx_start_if_not_started(trx); - err = lock_table(0, prebuilt->table, prebuilt->select_lock_type, thr); + err = lock_table(0, prebuilt->table, LOCK_AUTO_INC, thr); trx->error_state = err; diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 1a92946bfcd..6a67bbc6f8b 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -431,7 +431,7 @@ Duplicate entry 'test2' for key 2 select * from t1; id ggid email passwd 1 this will work -4 test2 this will work +3 test2 this will work select * from t1 where id=1; id ggid email passwd 1 this will work From 309c7412f6a7b2c84a576a0d49695a6b8b0b9b30 Mon Sep 17 00:00:00 2001 From: "ingo@mysql.com" <> Date: Mon, 10 May 2004 12:15:40 +0200 Subject: [PATCH 05/22] Fix replace_result of $MASTER_MYPORT instead of literal numbers. --- mysql-test/t/rpl000015.test | 2 +- mysql-test/t/rpl_error_ignored_table.test | 2 +- mysql-test/t/rpl_log.test | 6 +++--- mysql-test/t/rpl_log_pos.test | 8 ++++---- mysql-test/t/rpl_max_relay_size.test | 12 ++++++------ mysql-test/t/rpl_rotate_logs.test | 10 +++++----- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/mysql-test/t/rpl000015.test b/mysql-test/t/rpl000015.test index 26d32ea3e11..7c5a8bf3743 100644 --- a/mysql-test/t/rpl000015.test +++ b/mysql-test/t/rpl000015.test @@ -11,7 +11,7 @@ show slave status; change master to master_host='127.0.0.1'; # The following needs to be cleaned up when change master is fixed ---replace_result $MASTER_MYPORT MASTER_PORT 3306 MASTER_PORT 3334 MASTER_PORT +--replace_result $MASTER_MYPORT MASTER_PORT 3306 MASTER_PORT show slave status; --replace_result $MASTER_MYPORT MASTER_PORT eval change master to master_host='127.0.0.1',master_user='root', diff --git a/mysql-test/t/rpl_error_ignored_table.test b/mysql-test/t/rpl_error_ignored_table.test index 4f15f9de0a2..a0b0f1fd599 100644 --- a/mysql-test/t/rpl_error_ignored_table.test +++ b/mysql-test/t/rpl_error_ignored_table.test @@ -14,7 +14,7 @@ connection slave; sync_with_master; # The port number is different when doing the release build with # Do-compile, hence we have to replace the port number here accordingly ---replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT +--replace_result $MASTER_MYPORT MASTER_PORT show slave status; # check that the table has been ignored, because otherwise the test is nonsense show tables like 't1'; diff --git a/mysql-test/t/rpl_log.test b/mysql-test/t/rpl_log.test index e01b3e4e09c..df2b9ecd0cb 100644 --- a/mysql-test/t/rpl_log.test +++ b/mysql-test/t/rpl_log.test @@ -79,11 +79,11 @@ connection slave; slave start; sync_with_master; show master logs; ---replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT $VERSION VERSION +--replace_result $MASTER_MYPORT MASTER_PORT $VERSION VERSION show binlog events in 'slave-bin.001' from 4; ---replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT $VERSION VERSION +--replace_result $MASTER_MYPORT MASTER_PORT $VERSION VERSION show binlog events in 'slave-bin.002' from 4; ---replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT +--replace_result $MASTER_MYPORT MASTER_PORT show slave status; # Need to recode the following diff --git a/mysql-test/t/rpl_log_pos.test b/mysql-test/t/rpl_log_pos.test index 859180d4e25..1a9a5bc3448 100644 --- a/mysql-test/t/rpl_log_pos.test +++ b/mysql-test/t/rpl_log_pos.test @@ -6,7 +6,7 @@ show master status; save_master_pos; connection slave; sync_with_master; ---replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT +--replace_result $MASTER_MYPORT MASTER_PORT show slave status; slave stop; change master to master_log_pos=73; @@ -15,17 +15,17 @@ sleep 5; slave stop; change master to master_log_pos=73; ---replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT +--replace_result $MASTER_MYPORT MASTER_PORT show slave status; slave start; sleep 5; ---replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT +--replace_result $MASTER_MYPORT MASTER_PORT show slave status; slave stop; change master to master_log_pos=173; slave start; sleep 2; ---replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT +--replace_result $MASTER_MYPORT MASTER_PORT show slave status; connection master; show master status; diff --git a/mysql-test/t/rpl_max_relay_size.test b/mysql-test/t/rpl_max_relay_size.test index 7e9a8a1872e..d2278b6d6df 100644 --- a/mysql-test/t/rpl_max_relay_size.test +++ b/mysql-test/t/rpl_max_relay_size.test @@ -28,7 +28,7 @@ set global max_relay_log_size=8192-1; # mapped to 4096 select @@global.max_relay_log_size; start slave; sync_with_master; ---replace_result $MASTER_MYPORT MASTER_PORT 3306 MASTER_PORT 3334 MASTER_PORT +--replace_result $MASTER_MYPORT MASTER_PORT show slave status; stop slave; reset slave; @@ -36,7 +36,7 @@ set global max_relay_log_size=(5*4096); select @@global.max_relay_log_size; start slave; sync_with_master; ---replace_result $MASTER_MYPORT MASTER_PORT 3306 MASTER_PORT 3334 MASTER_PORT +--replace_result $MASTER_MYPORT MASTER_PORT --replace_column 18 # show slave status; stop slave; @@ -45,7 +45,7 @@ set global max_relay_log_size=0; select @@global.max_relay_log_size; start slave; sync_with_master; ---replace_result $MASTER_MYPORT MASTER_PORT 3306 MASTER_PORT 3334 MASTER_PORT +--replace_result $MASTER_MYPORT MASTER_PORT show slave status; # Tests below are mainly to ensure that we have not coded with wrong assumptions @@ -55,7 +55,7 @@ reset slave; # test of relay log rotation when the slave is stopped # (to make sure it does not crash). flush logs; ---replace_result $MASTER_MYPORT MASTER_PORT 3306 MASTER_PORT 3334 MASTER_PORT +--replace_result $MASTER_MYPORT MASTER_PORT show slave status; reset slave; @@ -70,7 +70,7 @@ create table t1 (a int); save_master_pos; connection slave; sync_with_master; ---replace_result $MASTER_MYPORT MASTER_PORT 3306 MASTER_PORT 3334 MASTER_PORT +--replace_result $MASTER_MYPORT MASTER_PORT show slave status; # one more rotation, to be sure Relay_log_space is correctly updated flush logs; @@ -79,7 +79,7 @@ drop table t1; save_master_pos; connection slave; sync_with_master; ---replace_result $MASTER_MYPORT MASTER_PORT 3306 MASTER_PORT 3334 MASTER_PORT +--replace_result $MASTER_MYPORT MASTER_PORT show slave status; connection master; diff --git a/mysql-test/t/rpl_rotate_logs.test b/mysql-test/t/rpl_rotate_logs.test index 70366fc1749..76a06d01fa9 100644 --- a/mysql-test/t/rpl_rotate_logs.test +++ b/mysql-test/t/rpl_rotate_logs.test @@ -25,13 +25,13 @@ system chmod 600 var/slave-data/master.info; # init_strvar_from_file() in init_master_info()). --error 1201 slave start; ---replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT +--replace_result $MASTER_MYPORT MASTER_PORT # CHANGE MASTER will fail because it first parses master.info before changing it # (so when master.info is bad, people have to use RESET SLAVE first). --error 1201 eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root'; reset slave; ---replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT +--replace_result $MASTER_MYPORT MASTER_PORT eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root'; connection master; reset master; @@ -49,7 +49,7 @@ insert into t1 values('Could not break slave'),('Tried hard'); save_master_pos; connection slave; sync_with_master; ---replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT +--replace_result $MASTER_MYPORT MASTER_PORT --replace_column 18 # show slave status; select * from t1; @@ -101,7 +101,7 @@ insert into t2 values (65); save_master_pos; connection slave; sync_with_master; ---replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT +--replace_result $MASTER_MYPORT MASTER_PORT --replace_column 18 # show slave status; select * from t2; @@ -133,7 +133,7 @@ connection slave; sync_with_master; select * from t4; ---replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT +--replace_result $MASTER_MYPORT MASTER_PORT --replace_column 18 # show slave status; # because of concurrent insert, the table may not be up to date From 2cbc4e71fcec35820a85998e602fccb8ad1609a2 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Mon, 10 May 2004 12:39:01 +0200 Subject: [PATCH 06/22] backport from 4.1: "phrase search" should not match partial words (it should not match 'paraphrase searches') --- myisam/ft_boolean_search.c | 29 +++++++++++++++++++---------- myisam/ft_parser.c | 9 --------- myisam/ftdefs.h | 5 +++-- mysql-test/r/fulltext.result | 3 ++- mysql-test/t/fulltext.test | 1 + 5 files changed, 25 insertions(+), 22 deletions(-) diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index d728c379ea5..61381f80783 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -360,25 +360,34 @@ err: } -/* returns 1 if str0 contain str1 */ +/* returns 1 if str0 ~= /\/ */ static int _ftb_strstr(const byte *s0, const byte *e0, const byte *s1, const byte *e1, CHARSET_INFO *cs) { - const byte *p; + const byte *p0, *p1; + my_bool s_after, e_before; - while (s0 < e0) + s_after=true_word_char(s1[0]); + e_before=true_word_char(e1[-1]); + p0=s0; + + while (p0 < e0) { - while (s0 < e0 && cs->to_upper[(uint) (uchar) *s0++] != + while (p0 < e0 && cs->to_upper[(uint) (uchar) *p0++] != cs->to_upper[(uint) (uchar) *s1]) /* no-op */; - if (s0 >= e0) + if (p0 >= e0) return 0; - p=s1+1; - while (s0 < e0 && p < e1 && cs->to_upper[(uint) (uchar) *s0] == - cs->to_upper[(uint) (uchar) *p]) - s0++, p++; - if (p >= e1) + + if (s_after && p0-1 > s0 && true_word_char(p0[-2])) + continue; + + p1=s1+1; + while (p0 < e0 && p1 < e1 && cs->to_upper[(uint) (uchar) *p0] == + cs->to_upper[(uint) (uchar) *p1]) + p0++, p1++; + if (p1 == e1 && (!e_before || p0 == e0 || !true_word_char(p0[0]))) return 1; } return 0; diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c index c25ed6022a0..f397660af6b 100644 --- a/myisam/ft_parser.c +++ b/myisam/ft_parser.c @@ -105,15 +105,6 @@ FT_WORD * ft_linearize(TREE *wtree) DBUG_RETURN(wlist); } -#define true_word_char(X) (isalnum(X) || (X)=='_') -#ifdef HYPHEN_IS_DELIM -#define misc_word_char(X) ((X)=='\'') -#else -#define misc_word_char(X) ((X)=='\'' || (X)=='-') -#endif -#define word_char(X) (true_word_char(X) || misc_word_char(X)) - - /* returns: * 0 - eof * 1 - word found diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h index 62fa4362e19..46acf60d796 100644 --- a/myisam/ftdefs.h +++ b/myisam/ftdefs.h @@ -22,8 +22,9 @@ #include #include -#define HYPHEN_IS_DELIM -#define HYPHEN_IS_CONCAT /* not used for now */ +#define true_word_char(X) (isalnum(X) || (X)=='_') +#define misc_word_char(X) ((X)=='\'') +#define word_char(X) (true_word_char(X) || misc_word_char(X)) #define COMPILE_STOPWORDS_IN diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index 738941f63c7..baa3a834f6f 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -116,7 +116,8 @@ a b MySQL has now support for full-text search select * from t1 where MATCH a,b AGAINST ('"text i"' IN BOOLEAN MODE); a b -Full-text indexes are called collections +select * from t1 where MATCH a,b AGAINST ('"xt indexes"' IN BOOLEAN MODE); +a b select * from t1 where MATCH a,b AGAINST ('+(support collections) +foobar*' IN BOOLEAN MODE); a b select * from t1 where MATCH a,b AGAINST ('+(+(support collections)) +foobar*' IN BOOLEAN MODE); diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index 774a3b42619..86d2cde370a 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -52,6 +52,7 @@ select * from t1 where MATCH a,b AGAINST ('"text search" "now support"' IN BOOL select * from t1 where MATCH a,b AGAINST ('"text search" -"now support"' IN BOOLEAN MODE); select * from t1 where MATCH a,b AGAINST ('"text search" +"now support"' IN BOOLEAN MODE); select * from t1 where MATCH a,b AGAINST ('"text i"' IN BOOLEAN MODE); +select * from t1 where MATCH a,b AGAINST ('"xt indexes"' IN BOOLEAN MODE); select * from t1 where MATCH a,b AGAINST ('+(support collections) +foobar*' IN BOOLEAN MODE); select * from t1 where MATCH a,b AGAINST ('+(+(support collections)) +foobar*' IN BOOLEAN MODE); From d48d5681c8733a1f6d75eb13f51654513e93a097 Mon Sep 17 00:00:00 2001 From: "marko@hundin.mysql.fi" <> Date: Mon, 10 May 2004 17:15:29 +0300 Subject: [PATCH 07/22] InnoDB: Fix assertion failure for orphaned tables in DROP DATABASE --- innobase/row/row0mysql.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index bdc47ca0e8e..228f19c865f 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -2208,10 +2208,11 @@ row_drop_database_for_mysql( dict_table_t* table; char* table_name; int err = DB_SUCCESS; + ulint namelen = strlen(name); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_a(name != NULL); - ut_a(name[strlen(name) - 1] == '/'); + ut_a(name[namelen - 1] == '/'); trx->op_info = (char *) "dropping database"; @@ -2220,7 +2221,7 @@ loop: row_mysql_lock_data_dictionary(trx); while ((table_name = dict_get_first_table_name_in_db(name))) { - ut_a(strcmp(table_name, name) == 0); + ut_a(memcmp(table_name, name, namelen) == 0); table = dict_table_get_low(table_name); From 981f6ef9792b51000411a1dc35512adabb609aaf Mon Sep 17 00:00:00 2001 From: "marko@hundin.mysql.fi" <> Date: Tue, 11 May 2004 11:05:02 +0300 Subject: [PATCH 08/22] InnoDB: Changed bug reporting address to http://bugs.mysql.com --- innobase/btr/btr0btr.c | 2 +- innobase/dict/dict0load.c | 2 +- innobase/ibuf/ibuf0ibuf.c | 7 +++---- innobase/lock/lock0lock.c | 6 ++++-- innobase/row/row0ins.c | 3 +-- innobase/row/row0sel.c | 3 +-- innobase/row/row0umod.c | 3 +-- innobase/row/row0upd.c | 3 +-- innobase/trx/trx0rec.c | 22 +++++++++------------- innobase/ut/ut0dbg.c | 2 +- 10 files changed, 23 insertions(+), 30 deletions(-) diff --git a/innobase/btr/btr0btr.c b/innobase/btr/btr0btr.c index 70bcd1eea1f..0b4c0dbfa94 100644 --- a/innobase/btr/btr0btr.c +++ b/innobase/btr/btr0btr.c @@ -882,7 +882,7 @@ btr_page_reorganize_low( fprintf(stderr, "InnoDB: Error: page old data size %lu new data size %lu\n" "InnoDB: Error: page old max ins size %lu new max ins size %lu\n" -"InnoDB: Make a detailed bug report and send it to mysql@lists.mysql.com\n", +"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", data_size1, data_size2, max_ins_size1, max_ins_size2); } diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c index 884ef95e183..6a4d4c86824 100644 --- a/innobase/dict/dict0load.c +++ b/innobase/dict/dict0load.c @@ -721,7 +721,7 @@ dict_load_table( "InnoDB: the foreign key table or the referenced table!\n" "InnoDB: The data dictionary of InnoDB is corrupt. You may need to drop\n" "InnoDB: and recreate the foreign key table or the referenced table.\n" -"InnoDB: Send a detailed bug report to mysql@lists.mysql.com\n" +"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n" "InnoDB: Latest foreign key error printout:\n%s\n", dict_foreign_err_buf); mutex_exit(&dict_foreign_err_mutex); diff --git a/innobase/ibuf/ibuf0ibuf.c b/innobase/ibuf/ibuf0ibuf.c index 83bb23b036f..4525cf7afef 100644 --- a/innobase/ibuf/ibuf0ibuf.c +++ b/innobase/ibuf/ibuf0ibuf.c @@ -2385,7 +2385,7 @@ ibuf_insert_to_index_page( fprintf(stderr, "Bitmap bits %lu\n", old_bits); fputs( -"InnoDB: Send a detailed bug report to mysql@lists.mysql.com!\n", stderr); +"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr); } } @@ -2443,7 +2443,7 @@ ibuf_delete_rec( if (!success) { fprintf(stderr, - "InnoDB: ERROR: Send the output to mysql@lists.mysql.com\n" + "InnoDB: ERROR: Submit the output to http://bugs.mysql.com\n" "InnoDB: ibuf cursor restoration fails!\n" "InnoDB: ibuf record inserted to page %lu\n", page_no); fflush(stderr); @@ -2597,8 +2597,7 @@ ibuf_merge_or_delete_for_page( "InnoDB: We try to resolve the problem by skipping the insert buffer\n" "InnoDB: merge for this page. Please run CHECK TABLE on your tables\n" "InnoDB: to determine if they are corrupt after this.\n\n" -"InnoDB: Please make a detailed bug report and send it to\n" -"InnoDB: mysql@lists.mysql.com\n\n", +"InnoDB: Please submit a detailed bug report to http://bugs.mysql.com\n\n", page_no, fil_page_get_type(page)); } } diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index 6534387c22c..4343496f6e1 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -1629,7 +1629,8 @@ lock_rec_enqueue_waiting( " InnoDB: Error: a record lock wait happens in a dictionary operation!\n" "InnoDB: Table name ", stderr); ut_print_name(stderr, index->table_name); - fputs(". Send a bug report to mysql@lists.mysql.com\n", + fputs(".\n" +"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr); } @@ -3269,7 +3270,8 @@ lock_table_enqueue_waiting( " InnoDB: Error: a table lock wait happens in a dictionary operation!\n" "InnoDB: Table name ", stderr); ut_print_name(stderr, table->name); - fputs(". Send a bug report to mysql@lists.mysql.com\n", + fputs(".\n" +"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr); } diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index 8bc6c9697c1..8f1c1370f25 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -803,8 +803,7 @@ row_ins_foreign_check_on_constraint( "InnoDB: clustered record ", stderr); rec_print(stderr, clust_rec); fputs("\n" - "InnoDB: Make a detailed bug report and send it\n" - "InnoDB: to mysql@lists.mysql.com\n", stderr); +"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr); err = DB_SUCCESS; diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 6f8ce120764..e0bf4684214 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -2358,8 +2358,7 @@ row_sel_get_clust_rec_for_mysql( trx_print(stderr, thr_get_trx(thr)); fputs("\n" - "InnoDB: Make a detailed bug report and send it\n" - "InnoDB: to mysql@lists.mysql.com\n", stderr); +"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr); } clust_rec = NULL; diff --git a/innobase/row/row0umod.c b/innobase/row/row0umod.c index 5975bb164b9..1f74cfb52be 100644 --- a/innobase/row/row0umod.c +++ b/innobase/row/row0umod.c @@ -441,8 +441,7 @@ row_undo_mod_del_unmark_sec_and_undo_update( putc('\n', stderr); trx_print(stderr, thr_get_trx(thr)); fputs("\n" - "InnoDB: Make a detailed bug report and send it\n" - "InnoDB: to mysql@lists.mysql.com\n", stderr); +"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr); } else { btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur); diff --git a/innobase/row/row0upd.c b/innobase/row/row0upd.c index 02fe245ce8b..e7894e543bc 100644 --- a/innobase/row/row0upd.c +++ b/innobase/row/row0upd.c @@ -1236,8 +1236,7 @@ row_upd_sec_index_entry( trx_print(stderr, thr_get_trx(thr)); fputs("\n" - "InnoDB: Make a detailed bug report and send it\n" - "InnoDB: to mysql@lists.mysql.com\n", stderr); +"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr); } else { /* Delete mark the old index record; it can already be delete marked if we return after a lock wait in diff --git a/innobase/trx/trx0rec.c b/innobase/trx/trx0rec.c index 4926c776ae9..79fad312e8e 100644 --- a/innobase/trx/trx0rec.c +++ b/innobase/trx/trx0rec.c @@ -823,17 +823,16 @@ trx_undo_update_rec_get_update( if (field_no >= dict_index_get_n_fields(index)) { fprintf(stderr, - "InnoDB: Error: trying to access" - " update undo rec field %lu in ", field_no); +"InnoDB: Error: trying to access update undo rec field %lu in ", field_no); dict_index_name_print(stderr, index); fprintf(stderr, "\n" - "InnoDB: but index has only %lu fields\n" - "InnoDB: Send a detailed bug report to mysql@lists.mysql.com\n" - "InnoDB: Run also CHECK TABLE ", +"InnoDB: but index has only %lu fields\n" +"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n" +"InnoDB: Run also CHECK TABLE ", dict_index_get_n_fields(index)); ut_print_name(stderr, index->table_name); fprintf(stderr, "\n" - "InnoDB: n_fields = %lu, i = %lu, ptr %p\n", +"InnoDB: n_fields = %lu, i = %lu, ptr %p\n", n_fields, i, ptr); return(NULL); } @@ -1271,8 +1270,7 @@ trx_undo_prev_version_build( " update undo rec for non-clustered ", stderr); dict_index_name_print(stderr, index); fputs("\n" - "InnoDB: Send a detailed bug report to" - " mysql@lists.mysql.com\n" +"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n" "InnoDB: index record ", stderr); rec_print(stderr, index_rec); fputs("\n" @@ -1320,11 +1318,9 @@ trx_undo_prev_version_build( " update undo rec for table ", stderr); ut_print_name(stderr, index->table_name); fputs("\n" - "InnoDB: but the table id in the" - " undo record is wrong\n" - "InnoDB: Send a detailed bug report to " - "mysql@lists.mysql.com\n" - "InnoDB: Run also CHECK TABLE ", stderr); +"InnoDB: but the table id in the undo record is wrong\n" +"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n" +"InnoDB: Run also CHECK TABLE ", stderr); ut_print_name(stderr, index->table_name); putc('\n', stderr); } diff --git a/innobase/ut/ut0dbg.c b/innobase/ut/ut0dbg.c index 3697e31050f..65703ec1c86 100644 --- a/innobase/ut/ut0dbg.c +++ b/innobase/ut/ut0dbg.c @@ -23,7 +23,7 @@ const char* ut_dbg_msg_assert_fail = "InnoDB: Assertion failure in thread %lu in file %s line %lu\n"; const char* ut_dbg_msg_trap = "InnoDB: We intentionally generate a memory trap.\n" -"InnoDB: Send a detailed bug report to mysql@lists.mysql.com.\n" +"InnoDB: Submit a detailed bug report to http://bugs.mysql.com.\n" "InnoDB: If you get repeated assertion failures or crashes, even\n" "InnoDB: immediately after the mysqld startup, there may be\n" "InnoDB: corruption in the InnoDB tablespace. See section 6.1 of\n" From 8a03c1b86909ef8c3be811c794b2da85b5a7204a Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Tue, 11 May 2004 12:19:37 +0200 Subject: [PATCH 09/22] bug#3612 - Item_func_div set decimals incorrectly --- mysql-test/r/type_float.result | 15 +++++++++++++++ mysql-test/t/type_float.test | 8 ++++++++ sql/item_func.cc | 1 + 3 files changed, 24 insertions(+) diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result index e85bced353a..c9996e9c9f3 100644 --- a/mysql-test/r/type_float.result +++ b/mysql-test/r/type_float.result @@ -67,6 +67,21 @@ select min(a) from t1; min(a) -0.010 drop table t1; +create table t1 (c1 double, c2 varchar(20)); +insert t1 values (121,"16"); +select c1 + c1 * (c2 / 100) as col from t1; +col +140.36 +create table t2 select c1 + c1 * (c2 / 100) as col from t1; +select * from t2; +col +140.36 +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `col` double default NULL +) TYPE=MyISAM +drop table t1,t2; create table t1 (f float, f2 float(24), f3 float(6,2), d double, d2 float(53), d3 double(10,3), de decimal, de2 decimal(6), de3 decimal(5,2), n numeric, n2 numeric(8), n3 numeric(5,6)); show full columns from t1; Field Type Null Key Default Extra Privileges diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test index 23941ad2913..65d594387b9 100644 --- a/mysql-test/t/type_float.test +++ b/mysql-test/t/type_float.test @@ -28,6 +28,14 @@ select a from t1 order by a; select min(a) from t1; drop table t1; +create table t1 (c1 double, c2 varchar(20)); +insert t1 values (121,"16"); +select c1 + c1 * (c2 / 100) as col from t1; +create table t2 select c1 + c1 * (c2 / 100) as col from t1; +select * from t2; +show create table t2; +drop table t1,t2; + # # FLOAT/DOUBLE/DECIMAL handling # diff --git a/sql/item_func.cc b/sql/item_func.cc index 9d1f784fc25..368c14cc8df 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -402,6 +402,7 @@ longlong Item_func_div::val_int() void Item_func_div::fix_length_and_dec() { decimals=max(args[0]->decimals,args[1]->decimals)+2; + set_if_smaller(decimals, NOT_FIXED_DEC); max_length=args[0]->max_length - args[0]->decimals + decimals; uint tmp=float_length(decimals); set_if_smaller(max_length,tmp); From 593a10178e7e44a3ba45b36e60669b18f749463d Mon Sep 17 00:00:00 2001 From: "lenz@mysql.com" <> Date: Wed, 12 May 2004 01:23:27 +0200 Subject: [PATCH 10/22] - Bumped up version number from 4.0.19 -> 4.0.20 - Tagged ChangeSet@1.1800.1.1 as "mysql-4.0.19" --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index a50d89c8655..b8d279d2f27 100644 --- a/configure.in +++ b/configure.in @@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! -AM_INIT_AUTOMAKE(mysql, 4.0.19) +AM_INIT_AUTOMAKE(mysql, 4.0.20) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 From ecdac0a326d16ae03f033627ffed37bc093b1469 Mon Sep 17 00:00:00 2001 From: "marko@hundin.mysql.fi" <> Date: Wed, 12 May 2004 10:40:04 +0300 Subject: [PATCH 11/22] eval0eval.c: Backport suppression of MSVC++ warning from 4.1 --- innobase/eval/eval0eval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/innobase/eval/eval0eval.c b/innobase/eval/eval0eval.c index 053a10b3c23..a3cd60b86ae 100644 --- a/innobase/eval/eval0eval.c +++ b/innobase/eval/eval0eval.c @@ -725,7 +725,7 @@ eval_predefined( uint_val = (ulint) int_val; } for (tmp = int_len; uint_val > 0; uint_val /= 10) { - data[--tmp] = '0' + (uint_val % 10); + data[--tmp] = '0' + (byte)(uint_val % 10); } } From 17d5da7e33c44057345d984d15d0270e3316d666 Mon Sep 17 00:00:00 2001 From: "marko@hundin.mysql.fi" <> Date: Wed, 12 May 2004 16:44:53 +0300 Subject: [PATCH 12/22] InnoDB: avoid some data races in innobase_mysql_print_thd() (Bug #3596) --- sql/ha_innodb.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index ac7ccf5c11a..8651125e331 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -323,9 +323,10 @@ innobase_mysql_print_thd( FILE* f, /* in: output stream */ void* input_thd)/* in: pointer to a MySQL THD object */ { - THD* thd; + const THD* thd; + const char* s; - thd = (THD*) input_thd; + thd = (const THD*) input_thd; fprintf(f, "MySQL thread id %lu, query id %lu", thd->thread_id, thd->query_id); @@ -344,14 +345,14 @@ innobase_mysql_print_thd( fputs(thd->user, f); } - if (thd->proc_info) { + if ((s = thd->proc_info)) { putc(' ', f); - fputs(thd->proc_info, f); + fputs(s, f); } - if (thd->query) { + if ((s = thd->query)) { putc(' ', f); - fputs(thd->query, f); + fputs(s, f); } putc('\n', f); From c838192066f5e6b593fac803c58d45176e587b0c Mon Sep 17 00:00:00 2001 From: "marko@hundin.mysql.fi" <> Date: Thu, 13 May 2004 15:28:56 +0300 Subject: [PATCH 13/22] InnoDB: Remove os_file_lock() from the 4.0 tree (unfix Bug #3608) --- innobase/os/os0file.c | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 833703e38dd..81566337218 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -358,32 +358,6 @@ os_file_handle_error( return(FALSE); } -#if !defined(__WIN__) && !defined(UNIV_HOTBACKUP) -/******************************************************************** -Obtain an exclusive lock on a file. */ -static -int -os_file_lock( -/*=========*/ - /* out: 0 on success */ - int fd, /* in: file descriptor */ - const char* name) /* in: file name */ -{ - struct flock lk; - lk.l_type = F_WRLCK; - lk.l_whence = SEEK_SET; - lk.l_start = lk.l_len = 0; - if (fcntl(fd, F_SETLK, &lk) == -1) { - fprintf(stderr, - "InnoDB: Unable to lock %s", name); - perror (": fcntl"); - close(fd); - return(-1); - } - return 0; -} -#endif /* !defined(__WIN__) && !defined(UNIV_HOTBACKUP) */ - /******************************************************************** Creates the seek mutexes used in positioned reads and writes. */ @@ -504,11 +478,6 @@ try_again: if (retry) { goto try_again; } -#ifndef UNIV_HOTBACKUP - } else if (os_file_lock(file, name)) { - *success = FALSE; - file = -1; -#endif } else { *success = TRUE; } @@ -603,11 +572,6 @@ os_file_create_simple_no_error_handling( if (file == -1) { *success = FALSE; -#ifndef UNIV_HOTBACKUP - } else if (os_file_lock(file, name)) { - *success = FALSE; - file = -1; -#endif } else { *success = TRUE; } @@ -808,11 +772,6 @@ try_again: if (retry) { goto try_again; } -#ifndef UNIV_HOTBACKUP - } else if (os_file_lock(file, name)) { - *success = FALSE; - file = -1; -#endif } else { *success = TRUE; } From bd8901fd735433838219c064bbfbc2e525e4cfd3 Mon Sep 17 00:00:00 2001 From: "marko@hundin.mysql.fi" <> Date: Thu, 13 May 2004 15:51:02 +0300 Subject: [PATCH 14/22] InnoDB: fixed bug in dict0dict.c: dict_index_name_print() --- innobase/dict/dict0dict.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index fa80532a32d..51e92a9900f 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -4195,5 +4195,5 @@ dict_index_name_print( fputs("index ", file); ut_print_name(file, index->name); fputs(" of table ", file); - ut_print_name(stderr, index->table_name); + ut_print_name(file, index->table_name); } From 077f0812fc40427e0186067ac2faaa8d77b4b845 Mon Sep 17 00:00:00 2001 From: "marko@hundin.mysql.fi" <> Date: Thu, 13 May 2004 16:18:39 +0300 Subject: [PATCH 15/22] ha_innodb.cc: innobase_mysql_print_thd(): protect thd with LOCK_thread_count (Bug #3596) --- sql/ha_innodb.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 8651125e331..d5bbeb874ad 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -328,6 +328,8 @@ innobase_mysql_print_thd( thd = (const THD*) input_thd; + VOID(pthread_mutex_lock(&LOCK_thread_count)); + fprintf(f, "MySQL thread id %lu, query id %lu", thd->thread_id, thd->query_id); if (thd->host) { @@ -351,11 +353,16 @@ innobase_mysql_print_thd( } if ((s = thd->query)) { - putc(' ', f); - fputs(s, f); + /* determine the length of the query string */ + uint32 i, len = thd->query_length; + for (i = 0; i < len && s[i]; i++); + putc('\n', f); + fwrite(s, 1, i, f); } putc('\n', f); + + VOID(pthread_mutex_unlock(&LOCK_thread_count)); } /************************************************************************* From b1f2932fff656fecc020283dee9bf7ecbb4bace6 Mon Sep 17 00:00:00 2001 From: "lenz@mysql.com" <> Date: Thu, 13 May 2004 18:50:09 +0200 Subject: [PATCH 16/22] - make sure the binaries are executable before calling them during make_binary_distribution (bug#2857) --- scripts/make_binary_distribution.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh index c7945e31eda..730086bbb62 100644 --- a/scripts/make_binary_distribution.sh +++ b/scripts/make_binary_distribution.sh @@ -221,6 +221,7 @@ $CP mysql-test/t/*test mysql-test/t/*.opt mysql-test/t/*.slave-mi mysql-test/t/* $CP mysql-test/r/*result mysql-test/r/*.require $BASE/mysql-test/r if [ $BASE_SYSTEM != "netware" ] ; then + chmod a+x $BASE/bin/* $CP scripts/* $BASE/bin $BASE/bin/replace \@localstatedir\@ ./data \@bindir\@ ./bin \@scriptdir\@ ./bin \@libexecdir\@ ./bin \@sbindir\@ ./bin \@prefix\@ . \@HOSTNAME\@ @HOSTNAME@ < $SOURCE/scripts/mysql_install_db.sh > $BASE/scripts/mysql_install_db $BASE/bin/replace \@prefix\@ /usr/local/mysql \@bindir\@ ./bin \@MYSQLD_USER\@ root \@localstatedir\@ /usr/local/mysql/data \@HOSTNAME\@ @HOSTNAME@ < $SOURCE/support-files/mysql.server.sh > $BASE/support-files/mysql.server From cafad010a608e8abe98187f16fcc274451a71b97 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Thu, 13 May 2004 20:02:05 +0300 Subject: [PATCH 17/22] ha_innodb.cc: A flawed fix of the thd->query race in SHOW INNODB STATUS; see the comments in code about how to fix this properly; we cannot use LOCK_thread_count to protect thd->query, because that will cause a deadlock of threads --- sql/ha_innodb.cc | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index d5bbeb874ad..e330a0b532f 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -325,10 +325,18 @@ innobase_mysql_print_thd( { const THD* thd; const char* s; + char buf[301]; thd = (const THD*) input_thd; - VOID(pthread_mutex_lock(&LOCK_thread_count)); +/* We cannot use LOCK_thread_count to protect this operation because we own +the InnoDB kernel_mutex when we enter this function, but in freeing of a +THD object, MySQL first reserves LOCK_thread_count and AFTER THAT InnoDB +reserves kernel_mutex when freeing the trx object => a deadlock can occur. +The solution is for MySQL to use a separate mutex to protect thd->query and +thd->query_len. Someone should do that! This bug has been here for 3 years! + + VOID(pthread_mutex_lock(&LOCK_thread_count)); */ fprintf(f, "MySQL thread id %lu, query id %lu", thd->thread_id, thd->query_id); @@ -354,15 +362,29 @@ innobase_mysql_print_thd( if ((s = thd->query)) { /* determine the length of the query string */ - uint32 i, len = thd->query_length; + uint32 i, len; + + len = thd->query_length; + + if (len > 300) { + len = 300; /* A TEMPORARY SOLUTION: print at most + 300 chars to reduce the probability of + a seg fault in a race */ + } + for (i = 0; i < len && s[i]; i++); + + memcpy(buf, s, i); /* use memcpy to reduce the timeframe + for a race, compared to fwrite() */ + buf[300] = '\0'; + putc('\n', f); - fwrite(s, 1, i, f); + fwrite(buf, 1, i, f); } putc('\n', f); - VOID(pthread_mutex_unlock(&LOCK_thread_count)); +/* VOID(pthread_mutex_unlock(&LOCK_thread_count)); */ } /************************************************************************* From d2649c110a3779196d0873378024a3c26d1a17f4 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Thu, 13 May 2004 22:07:51 +0300 Subject: [PATCH 18/22] ha_innodb.cc, trx0trx.h, lock0lock.c, trx0trx.c: Reserve the MySQL LOCK_thread_count mutex when printing thd->query of an arbitrary transaction; if we are printing thd->query of a transaction that we know is currently executing inside InnoDB, then we know that MySQL cannot meanwhile change thd->query, and no need to reserve the MySQL mutex; note that this patch still leaves open the possibility of races in MySQL's thd->query_len --- innobase/include/trx0trx.h | 6 +++-- innobase/lock/lock0lock.c | 34 +++++++++++++++++++++++++++ innobase/trx/trx0trx.c | 4 +++- sql/ha_innodb.cc | 48 +++++++++++++++++++++++++++----------- 4 files changed, 75 insertions(+), 17 deletions(-) diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index 71269cb1e4e..07d5e5a8215 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -275,13 +275,15 @@ trx_commit_step( que_thr_t* thr); /* in: query thread */ /************************************************************************** Prints info about a transaction to the standard output. The caller must -own the kernel mutex. */ +own the kernel mutex and must have called +innobase_mysql_prepare_print_arbitrary_thd(), unless he knows that MySQL or +InnoDB cannot meanwhile change the info printed here. */ void trx_print( /*======*/ FILE* f, /* in: output stream */ - trx_t* trx); /* in: transaction */ + trx_t* trx); /* in: transaction */ /* Signal to a transaction */ diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index 4343496f6e1..791b81366b2 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -17,6 +17,32 @@ Created 5/7/1996 Heikki Tuuri #include "dict0mem.h" #include "trx0sys.h" + +/* 2 function prototypes copied from ha_innodb.cc: */ + +/***************************************************************** +If you want to print a thd that is not associated with the current thread, +you must call this function before reserving the InnoDB kernel_mutex, to +protect MySQL from setting thd->query NULL. If you print a thd of the current +thread, we know that MySQL cannot modify thd->query, and it is not necessary +to call this. Call innobase_mysql_end_print_arbitrary_thd() after you release +the kernel_mutex. +NOTE that /mysql/innobase/lock/lock0lock.c must contain the prototype for this +function! */ + +void +innobase_mysql_prepare_print_arbitrary_thd(void); +/*============================================*/ + +/***************************************************************** +Relases the mutex reserved by innobase_mysql_prepare_print_arbitrary_thd(). +NOTE that /mysql/innobase/lock/lock0lock.c must contain the prototype for this +function! */ + +void +innobase_mysql_end_print_arbitrary_thd(void); +/*========================================*/ + /* Restricts the length of search we will do in the waits-for graph of transactions */ #define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000 @@ -3974,6 +4000,11 @@ lock_print_info( ulint i; mtr_t mtr; + /* We must protect the MySQL thd->query field with a MySQL mutex, and + because the MySQL mutex must be reserved before the kernel_mutex of + InnoDB, we call innobase_mysql_prepare_print_arbitrary_thd() here. */ + + innobase_mysql_prepare_print_arbitrary_thd(); lock_mutex_enter_kernel(); if (lock_deadlock_found) { @@ -4037,6 +4068,7 @@ loop: if (trx == NULL) { lock_mutex_exit_kernel(); + innobase_mysql_end_print_arbitrary_thd(); ut_ad(lock_validate()); @@ -4101,6 +4133,7 @@ loop: if (load_page_first) { lock_mutex_exit_kernel(); + innobase_mysql_end_print_arbitrary_thd(); mtr_start(&mtr); @@ -4110,6 +4143,7 @@ loop: load_page_first = FALSE; + innobase_mysql_prepare_print_arbitrary_thd(); lock_mutex_enter_kernel(); goto loop; diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index 69cd6c7b22d..335e1f69228 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -1562,7 +1562,9 @@ trx_mark_sql_stat_end( /************************************************************************** Prints info about a transaction to the standard output. The caller must -own the kernel mutex. */ +own the kernel mutex and must have called +innobase_mysql_prepare_print_arbitrary_thd(), unless he knows that MySQL or +InnoDB cannot meanwhile change the info printed here. */ void trx_print( diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index e330a0b532f..194c8b558f0 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -312,6 +312,35 @@ convert_error_code_to_mysql( } } +/***************************************************************** +If you want to print a thd that is not associated with the current thread, +you must call this function before reserving the InnoDB kernel_mutex, to +protect MySQL from setting thd->query NULL. If you print a thd of the current +thread, we know that MySQL cannot modify thd->query, and it is not necessary +to call this. Call innobase_mysql_end_print_arbitrary_thd() after you release +the kernel_mutex. +NOTE that /mysql/innobase/lock/lock0lock.c must contain the prototype for this +function! */ +extern "C" +void +innobase_mysql_prepare_print_arbitrary_thd(void) +/*============================================*/ +{ + VOID(pthread_mutex_lock(&LOCK_thread_count)); +} + +/***************************************************************** +Relases the mutex reserved by innobase_mysql_prepare_print_arbitrary_thd(). +NOTE that /mysql/innobase/lock/lock0lock.c must contain the prototype for this +function! */ +extern "C" +void +innobase_mysql_end_print_arbitrary_thd(void) +/*========================================*/ +{ + VOID(pthread_mutex_unlock(&LOCK_thread_count)); +} + /***************************************************************** Prints info of a THD object (== user session thread) to the standard output. NOTE that /mysql/innobase/trx/trx0trx.c must contain @@ -329,15 +358,6 @@ innobase_mysql_print_thd( thd = (const THD*) input_thd; -/* We cannot use LOCK_thread_count to protect this operation because we own -the InnoDB kernel_mutex when we enter this function, but in freeing of a -THD object, MySQL first reserves LOCK_thread_count and AFTER THAT InnoDB -reserves kernel_mutex when freeing the trx object => a deadlock can occur. -The solution is for MySQL to use a separate mutex to protect thd->query and -thd->query_len. Someone should do that! This bug has been here for 3 years! - - VOID(pthread_mutex_lock(&LOCK_thread_count)); */ - fprintf(f, "MySQL thread id %lu, query id %lu", thd->thread_id, thd->query_id); if (thd->host) { @@ -367,14 +387,16 @@ thd->query_len. Someone should do that! This bug has been here for 3 years! len = thd->query_length; if (len > 300) { - len = 300; /* A TEMPORARY SOLUTION: print at most + len = 300; /* ADDITIONAL SAFETY: print at most 300 chars to reduce the probability of - a seg fault in a race */ + a seg fault if there is a race in + thd->query_len in MySQL; on May 13, + 2004 we do not know */ } for (i = 0; i < len && s[i]; i++); - memcpy(buf, s, i); /* use memcpy to reduce the timeframe + memcpy(buf, s, i); /* Use memcpy to reduce the timeframe for a race, compared to fwrite() */ buf[300] = '\0'; @@ -383,8 +405,6 @@ thd->query_len. Someone should do that! This bug has been here for 3 years! } putc('\n', f); - -/* VOID(pthread_mutex_unlock(&LOCK_thread_count)); */ } /************************************************************************* From b4ae2577f03888995cb5a78a4bd532d0272349f6 Mon Sep 17 00:00:00 2001 From: "marko@hundin.mysql.fi" <> Date: Fri, 14 May 2004 12:26:12 +0300 Subject: [PATCH 19/22] InnoDB: Remove unused function ut_str_catenate() --- innobase/include/ut0mem.h | 11 ----------- innobase/ut/ut0mem.c | 26 -------------------------- 2 files changed, 37 deletions(-) diff --git a/innobase/include/ut0mem.h b/innobase/include/ut0mem.h index bfda5ded40c..e83b2e6f60c 100644 --- a/innobase/include/ut0mem.h +++ b/innobase/include/ut0mem.h @@ -108,17 +108,6 @@ ut_memcpyq( const char* src, /* in: string to be quoted */ ulint len); /* in: length of src */ -/************************************************************************** -Catenates two strings into newly allocated memory. The memory must be freed -using mem_free. */ - -char* -ut_str_catenate( -/*============*/ - /* out, own: catenated null-terminated string */ - char* str1, /* in: null-terminated string */ - char* str2); /* in: null-terminated string */ - #ifndef UNIV_NONINL #include "ut0mem.ic" #endif diff --git a/innobase/ut/ut0mem.c b/innobase/ut/ut0mem.c index 1fcaf9febbe..13846630818 100644 --- a/innobase/ut/ut0mem.c +++ b/innobase/ut/ut0mem.c @@ -236,29 +236,3 @@ ut_memcpyq( return(dest); } - -/************************************************************************** -Catenates two strings into newly allocated memory. The memory must be freed -using mem_free. */ - -char* -ut_str_catenate( -/*============*/ - /* out, own: catenated null-terminated string */ - char* str1, /* in: null-terminated string */ - char* str2) /* in: null-terminated string */ -{ - ulint len1; - ulint len2; - char* str; - - len1 = ut_strlen(str1); - len2 = ut_strlen(str2); - - str = mem_alloc(len1 + len2 + 1); - - ut_memcpy(str, str1, len1); - ut_memcpy(str + len1, str2, len2 + 1); - - return(str); -} From 02f51ccf2d16bd3525e1446553ab74c00af695f1 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Fri, 14 May 2004 16:48:56 +0300 Subject: [PATCH 20/22] Many files: Fix remaining cases of Bug #3596: fix possible races caused by an obsolete value of thd->query_length in SHOW PROCESSLIST and SHOW INNODB STATUS; this fix depends on the fact that thd->query is always set to NULL before setting it to point to a new query --- sql/ha_innodb.cc | 7 ++++--- sql/log_event.cc | 1 + sql/slave.cc | 2 ++ sql/sql_class.h | 19 ++++++++++++++++++- sql/sql_db.cc | 2 ++ sql/sql_parse.cc | 1 + sql/sql_show.cc | 6 +++++- 7 files changed, 33 insertions(+), 5 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 194c8b558f0..4835f794a1d 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -390,15 +390,16 @@ innobase_mysql_print_thd( len = 300; /* ADDITIONAL SAFETY: print at most 300 chars to reduce the probability of a seg fault if there is a race in - thd->query_len in MySQL; on May 13, - 2004 we do not know */ + thd->query_length in MySQL; after + May 14, 2004 probably no race any more, + but better be safe */ } for (i = 0; i < len && s[i]; i++); memcpy(buf, s, i); /* Use memcpy to reduce the timeframe for a race, compared to fwrite() */ - buf[300] = '\0'; + buf[300] = '\0'; /* not needed, just extra safety */ putc('\n', f); fwrite(buf, 1, i, f); diff --git a/sql/log_event.cc b/sql/log_event.cc index 7817ccff3d7..f84c8d1f579 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1929,6 +1929,7 @@ end: VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->db= 0; // prevent db from being freed thd->query= 0; // just to be sure + thd->query_length= 0; VOID(pthread_mutex_unlock(&LOCK_thread_count)); // assume no convert for next query unless set explictly thd->variables.convert_set = 0; diff --git a/sql/slave.cc b/sql/slave.cc index d6d0a5b5425..c7a7dac141a 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2691,6 +2691,7 @@ err: IO_RPL_LOG_NAME, llstr(mi->master_log_pos,llbuff)); VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query = thd->db = 0; // extra safety + thd->query_length = 0; VOID(pthread_mutex_unlock(&LOCK_thread_count)); if (mysql) { @@ -2839,6 +2840,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ err: VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query = thd->db = 0; // extra safety + thd->query_length = 0; VOID(pthread_mutex_unlock(&LOCK_thread_count)); thd->proc_info = "Waiting for slave mutex on exit"; pthread_mutex_lock(&rli->run_lock); diff --git a/sql/sql_class.h b/sql/sql_class.h index ad1eed5448f..83dc75e2b84 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -360,7 +360,24 @@ public: struct rand_struct rand; // used for authentication struct system_variables variables; // Changeable local variables pthread_mutex_t LOCK_delete; // Locked before thd is deleted - + /* + Note that (A) if we set query = NULL, we must at the same time set + query_length = 0, and protect the whole operation with the + LOCK_thread_count mutex. And (B) we are ONLY allowed to set query to a + non-NULL value if its previous value is NULL. We do not need to protect + operation (B) with any mutex. To avoid crashes in races, if we do not + know that thd->query cannot change at the moment, one should print + thd->query like this: + (1) reserve the LOCK_thread_count mutex; + (2) check if thd->query is NULL; + (3) if not NULL, then print at most thd->query_length characters from + it. We will see the query_length field as either 0, or the right value + for it. + Assuming that the write and read of an n-bit memory field in an n-bit + computer is atomic, we can avoid races in the above way. + This printing is needed at least in SHOW PROCESSLIST and SHOW INNODB + STATUS. + */ char *query; // Points to the current query, /* A pointer to the stack frame of handle_one_connection(), diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 7dd458a3b5d..865b2e1328f 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -95,6 +95,7 @@ int mysql_create_db(THD *thd, char *db, uint create_options, bool silent) { VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query= 0; + thd->query_length= 0; VOID(pthread_mutex_unlock(&LOCK_thread_count)); } send_ok(&thd->net, result); @@ -202,6 +203,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) { VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query= 0; + thd->query_length= 0; VOID(pthread_mutex_unlock(&LOCK_thread_count)); } send_ok(&thd->net,(ulong) deleted); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index be2d81fa372..77032bef698 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1312,6 +1312,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->proc_info=0; thd->command=COM_SLEEP; thd->query=0; + thd->query_length=0; thread_running--; VOID(pthread_mutex_unlock(&LOCK_thread_count)); thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 63f3afab128..7f52e52c849 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1141,7 +1141,11 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) thd_info->query=0; if (tmp->query) { - /* query_length is always set before tmp->query */ + /* + query_length is always set to 0 when we set query = NULL; see + the comment in sql_class.h why this prevents crashes in possible + races with query_length + */ uint length= min(max_query_length, tmp->query_length); thd_info->query=(char*) thd->memdup(tmp->query,length+1); thd_info->query[length]=0; From a039062ef372c6e0f68fbeb3c579f96fa591f5c8 Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Fri, 14 May 2004 23:08:03 +0200 Subject: [PATCH 21/22] Replication testsuite: making the master-slave synchronization less likely to fail, by adding sleep-and-retries (max 4 times) if MASTER_POS_WAIT() returns NULL in sync_with_master and sync_slave_with_master. The problem showed up only today, in MySQL 5.0 in rpl_server_id2.test, but may affect 4.x as well, so fixing it here. Note that I am also fixing 5.0 too, with the same exact patch, because I don't want to leave 5.0 broken until the next 4.0->4.1->5.0 merge. --- client/mysqltest.c | 21 ++++++++++++++++++--- mysql-test/r/rpl_server_id2.result | 1 - mysql-test/t/rpl_server_id2.test | 1 - 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 32fb44d178e..7dae99efde3 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -1081,7 +1081,7 @@ int do_sync_with_master2(const char* p) MYSQL_ROW row; MYSQL* mysql = &cur_con->mysql; char query_buf[FN_REFLEN+128]; - int offset = 0; + int offset= 0, tries= 0; int rpl_parse; if (!master_pos.file[0]) @@ -1096,6 +1096,9 @@ int do_sync_with_master2(const char* p) sprintf(query_buf, "select master_pos_wait('%s', %ld)", master_pos.file, master_pos.pos + offset); + +wait_for_position: + if (mysql_query(mysql, query_buf)) die("line %u: failed in %s: %d: %s", start_lineno, query_buf, mysql_errno(mysql), mysql_error(mysql)); @@ -1106,8 +1109,20 @@ int do_sync_with_master2(const char* p) if (!(row = mysql_fetch_row(res))) die("line %u: empty result in %s", start_lineno, query_buf); if (!row[0]) - die("line %u: could not sync with master ('%s' returned NULL)", - start_lineno, query_buf); + { + /* + It may be that the slave SQL thread has not started yet, though START + SLAVE has been issued ? + */ + if (tries++ == 3) + { + die("line %u: could not sync with master ('%s' returned NULL)", + start_lineno, query_buf); + } + sleep(1); /* So at most we will wait 3 seconds and make 4 tries */ + mysql_free_result(res); + goto wait_for_position; + } mysql_free_result(res); last_result=0; if (rpl_parse) diff --git a/mysql-test/r/rpl_server_id2.result b/mysql-test/r/rpl_server_id2.result index d665bb25dbb..1b5d946998c 100644 --- a/mysql-test/r/rpl_server_id2.result +++ b/mysql-test/r/rpl_server_id2.result @@ -4,7 +4,6 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; slave start; -drop table if exists t1; create table t1 (n int); reset master; stop slave; diff --git a/mysql-test/t/rpl_server_id2.test b/mysql-test/t/rpl_server_id2.test index dc8f733b7ed..7bbac358ada 100644 --- a/mysql-test/t/rpl_server_id2.test +++ b/mysql-test/t/rpl_server_id2.test @@ -3,7 +3,6 @@ source include/master-slave.inc; connection slave; -drop table if exists t1; create table t1 (n int); reset master; # replicate ourselves From 1e860400f3a260c01a00bada514df7f34ec462c0 Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Sat, 15 May 2004 09:08:03 +0300 Subject: [PATCH 22/22] Extra safety fixes (probably not needed, but can't hurt) --- sql/ha_innodb.cc | 9 +++------ sql/sql_parse.cc | 3 ++- sql/sql_show.cc | 3 +-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 4835f794a1d..4a50e2d8ccf 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -395,12 +395,9 @@ innobase_mysql_print_thd( but better be safe */ } - for (i = 0; i < len && s[i]; i++); - - memcpy(buf, s, i); /* Use memcpy to reduce the timeframe - for a race, compared to fwrite() */ - buf[300] = '\0'; /* not needed, just extra safety */ - + /* Use strmake to reduce the timeframe + for a race, compared to fwrite() */ + i= (uint) (strmake(buf, s, len) - buf); putc('\n', f); fwrite(buf, 1, i, f); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 77032bef698..7e68db0dcd2 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1067,6 +1067,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, packet_length--; } /* We must allocate some extra memory for query cache */ + thd->query_length= 0; // Extra safety: Avoid races if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet), packet_length, thd->db_length+2+ @@ -2982,8 +2983,8 @@ void mysql_parse(THD *thd, char *inBuf, uint length) { DBUG_ENTER("mysql_parse"); - mysql_init_query(thd); thd->query_length = length; + mysql_init_query(thd); if (query_cache_send_result_to_client(thd, inBuf, length) <= 0) { LEX *lex=lex_start(thd, (uchar*) inBuf, length); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 7f52e52c849..a4ef735c715 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1147,8 +1147,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) races with query_length */ uint length= min(max_query_length, tmp->query_length); - thd_info->query=(char*) thd->memdup(tmp->query,length+1); - thd_info->query[length]=0; + thd_info->query=(char*) thd->strmake(tmp->query,length); } thread_infos.append(thd_info); }