From 702b5ad4d66e9f9430d2b3b172239e14c32135c3 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Mon, 15 Sep 2003 15:16:13 +0300 Subject: [PATCH 01/49] fixed server crash on moving query block with pointers to same table in it (BUG#988) removed server options --- mysql-test/r/query_cache.result | 43 +++++++++++++++++++++- mysql-test/t/query_cache-master.opt | 1 - mysql-test/t/query_cache.test | 55 ++++++++++++++++++++++++++++- sql/sql_cache.cc | 26 ++++++++++++-- 4 files changed, 120 insertions(+), 5 deletions(-) delete mode 100644 mysql-test/t/query_cache-master.opt diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 0b86c79afbf..83d2e439fbc 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -1,8 +1,9 @@ +set GLOBAL query_cache_size=1355776; flush query cache; flush query cache; reset query cache; flush status; -drop table if exists t1,t2,t3; +drop table if exists t1,t2,t3,t4,t11,t21; drop database if exists mysqltest; create table t1 (a int not null); insert into t1 values (1),(2),(3); @@ -640,3 +641,43 @@ Variable_name Value Qcache_queries_in_cache 2 SET OPTION SQL_SELECT_LIMIT=DEFAULT; drop table t1; +flush query cache; +reset query cache; +flush status; +set GLOBAL query_cache_size=1048576; +create table t1 (a int not null); +insert into t1 values (1),(2),(3); +create table t2 (a text not null); +create table t3 (a text not null); +insert into t3 values("1111111111111111111111111111111111111111111111111111"); +insert into t2 select * from t3; +insert into t3 select * from t2; +insert into t2 select * from t3; +insert into t3 select * from t2; +insert into t2 select * from t3; +insert into t3 select * from t2; +insert into t2 select * from t3; +insert into t3 select * from t2; +insert into t2 select * from t3; +insert into t3 select * from t2; +drop table t2; +create table t2 (a int not null); +insert into t2 values (1),(2),(3); +create table t4 (a int not null); +insert into t4 values (1),(2),(3); +select * from t4; +select * from t2; +select * from t1 as tt, t1 as ttt where tt.a=1 and ttt.a=2; +select * from t2; +select * from t4; +select * from t1 as tt, t1 as ttt where tt.a=1 and ttt.a=2; +select * from t2; +select * from t4; +select * from t1 as tt, t1 as ttt where tt.a=1 and ttt.a=2; +delete from t2 where a=1; +flush query cache; +select * from t3; +delete from t4 where a=1; +flush query cache; +drop table t1,t2,t3,t4; +set GLOBAL query_cache_size=0; diff --git a/mysql-test/t/query_cache-master.opt b/mysql-test/t/query_cache-master.opt deleted file mode 100644 index cfdce628e74..00000000000 --- a/mysql-test/t/query_cache-master.opt +++ /dev/null @@ -1 +0,0 @@ ---set-variable=query_cache_size=1355776 diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 9e1c22ac642..2ab5504f84b 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -3,6 +3,7 @@ # # Tests with query cache # +set GLOBAL query_cache_size=1355776; # Reset query cache variables. @@ -10,7 +11,7 @@ flush query cache; # This crashed in some versions flush query cache; # This crashed in some versions reset query cache; flush status; -drop table if exists t1,t2,t3; +drop table if exists t1,t2,t3,t4,t11,t21; drop database if exists mysqltest; # @@ -450,3 +451,55 @@ select * from t1; show status like "Qcache_queries_in_cache"; SET OPTION SQL_SELECT_LIMIT=DEFAULT; drop table t1; + + +# +# query cache crash on using same table twice in one query test +# +flush query cache; +reset query cache; +flush status; +set GLOBAL query_cache_size=1048576; + + +create table t1 (a int not null); +insert into t1 values (1),(2),(3); +create table t2 (a text not null); +create table t3 (a text not null); +insert into t3 values("1111111111111111111111111111111111111111111111111111"); +insert into t2 select * from t3; +insert into t3 select * from t2; +insert into t2 select * from t3; +insert into t3 select * from t2; +insert into t2 select * from t3; +insert into t3 select * from t2; +insert into t2 select * from t3; +insert into t3 select * from t2; +insert into t2 select * from t3; +insert into t3 select * from t2; +drop table t2; +create table t2 (a int not null); +insert into t2 values (1),(2),(3); +create table t4 (a int not null); +insert into t4 values (1),(2),(3); + +disable_result_log; +select * from t4; +select * from t2; +select * from t1 as tt, t1 as ttt where tt.a=1 and ttt.a=2; +select * from t2; +select * from t4; +select * from t1 as tt, t1 as ttt where tt.a=1 and ttt.a=2; +select * from t2; +select * from t4; +select * from t1 as tt, t1 as ttt where tt.a=1 and ttt.a=2; + +delete from t2 where a=1; +flush query cache; +select * from t3; +enable_result_log; +delete from t4 where a=1; +flush query cache; + +drop table t1,t2,t3,t4; +set GLOBAL query_cache_size=0; diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 97ec6033ad6..5d525c7be4e 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -2666,11 +2666,33 @@ my_bool Query_cache::move_by_type(byte **border, relink(block, new_block, next, prev, pnext, pprev); if (queries_blocks == block) queries_blocks = new_block; + Query_cache_block_table *beg_of_table_table= block->table(0), + *end_of_table_table= block->table(n_tables); + byte *beg_of_new_table_table= (byte*) new_block->table(0); + for (TABLE_COUNTER_TYPE j=0; j < n_tables; j++) { Query_cache_block_table *block_table = new_block->table(j); - block_table->next->prev = block_table; - block_table->prev->next = block_table; + + // use aligment from begining of table if 'next' is in same block + if ((beg_of_table_table <= block_table->next) && + (block_table->next < end_of_table_table)) + ((Query_cache_block_table *)(beg_of_new_table_table + + (((byte*)block_table->next) - + ((byte*)beg_of_table_table))))->prev= + block_table; + else + block_table->next->prev= block_table; + + // use aligment from begining of table if 'prev' is in same block + if ((beg_of_table_table <= block_table->prev) && + (block_table->prev < end_of_table_table)) + ((Query_cache_block_table *)(beg_of_new_table_table + + (((byte*)block_table->prev) - + ((byte*)beg_of_table_table))))->next= + block_table; + else + block_table->prev->next = block_table; } DBUG_PRINT("qcache", ("after circle tt")); *border += len; From bf5be93a133c5c55f8ae4533d5df53e01ffd0f36 Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Sat, 27 Sep 2003 17:16:19 +0200 Subject: [PATCH 02/49] backport of a fix made in 4.0 to make replication work in 64-bit binaries. The 4.0 changeset was: ChangeSet@1.1579.3.1, 2003-09-26 23:43:22+02:00, guilhem@mysql.com Fix for 64-bit machines. I am almost sure this is the cause for BUG#1381 [Opn]: Bug in replication on HP-UX 64 bit binaries? BUG#1256 [CRp]: Replication slave fails to connect to master in 64-bit version (Solaris) The reason why I think it's wrong is that the normal client code has uint32 ip_addr. (of course on 32-bit machines it does not matter, but on 64-bit it does). --- sql/mini_client.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/mini_client.cc b/sql/mini_client.cc index 2c74eb96bf9..c7beeea37b8 100644 --- a/sql/mini_client.cc +++ b/sql/mini_client.cc @@ -496,7 +496,7 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user, { char buff[100],*end,*host_info; my_socket sock; - ulong ip_addr; + uint32 ip_addr; struct sockaddr_in sock_addr; uint pkt_length; NET *net= &mysql->net; From 293f27df35a2bddf3226b2854a163db910699275 Mon Sep 17 00:00:00 2001 From: "vva@eagle.mysql.r18.ru" <> Date: Mon, 29 Sep 2003 15:42:33 -0400 Subject: [PATCH 03/49] fixed processing of COM_BINLOG_DUMP to use in mysqlbinlog --- sql/sql_parse.cc | 3 ++- sql/sql_repl.cc | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 81233c038a1..3f6fa8d24ad 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -929,7 +929,8 @@ bool do_command(THD *thd) pos = uint4korr(packet + 1); flags = uint2korr(packet + 5); pthread_mutex_lock(&LOCK_server_id); - kill_zombie_dump_threads(slave_server_id = uint4korr(packet+7)); + if ((slave_server_id = uint4korr(packet+7))) + kill_zombie_dump_threads(slave_server_id); thd->server_id = slave_server_id; pthread_mutex_unlock(&LOCK_server_id); mysql_binlog_send(thd, thd->strdup(packet + 11), pos, flags); diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 1940ff360c2..ec5d45bca90 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -442,6 +442,11 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) break; case LOG_READ_EOF: DBUG_PRINT("wait",("waiting for data on binary log")); + if (thd->server_id==0) + { + pthread_mutex_unlock(log_lock); + goto end; + } if (!thd->killed) pthread_cond_wait(&COND_binlog_update, log_lock); break; @@ -523,6 +528,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) } } +end: end_io_cache(&log); (void)my_close(file, MYF(MY_WME)); @@ -532,7 +538,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) thd->current_linfo = 0; pthread_mutex_unlock(&LOCK_thread_count); DBUG_VOID_RETURN; - err: +err: thd->proc_info = "waiting to finalize termination"; end_io_cache(&log); pthread_mutex_lock(&LOCK_thread_count); From 498e1c6d959ebc57968637b4b90624751ad6b875 Mon Sep 17 00:00:00 2001 From: "monty@mishka.mysql.fi" <> Date: Wed, 8 Oct 2003 21:02:53 +0300 Subject: [PATCH 04/49] Fixed memory leak in send_file --- BitKeeper/etc/logging_ok | 1 + mysql-test/t/myisam.test | 3 +-- sql/sql_repl.cc | 9 +-------- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 8238e85a5be..777c590ce62 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -22,6 +22,7 @@ monty@bitch.mysql.fi monty@donna.mysql.fi monty@hundin.mysql.fi monty@mashka.mysql.fi +monty@mishka.mysql.fi monty@narttu. monty@narttu.mysql.fi monty@tik. diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index c9cb77d2a3a..e6772c4c0ac 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -284,5 +284,4 @@ insert into t1 values (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, "Sergei"); -drop table if exists t1; - +drop table t1; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 1940ff360c2..49e13f0e415 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -66,10 +66,10 @@ static int send_file(THD *thd) NET* net = &thd->net; int fd = -1,bytes, error = 1; char fname[FN_REFLEN+1]; - char *buf; const char *errmsg = 0; int old_timeout; uint packet_len; + char buf[IO_SIZE]; // It's safe to alloc this DBUG_ENTER("send_file"); // the client might be slow loading the data, give him wait_timeout to do @@ -77,13 +77,6 @@ static int send_file(THD *thd) old_timeout = thd->net.timeout; thd->net.timeout = thd->inactive_timeout; - // spare the stack - if(!(buf = alloc_root(&thd->mem_root,IO_SIZE))) - { - errmsg = "Out of memory"; - goto err; - } - // we need net_flush here because the client will not know it needs to send // us the file name until it has processed the load event entry if (net_flush(net) || (packet_len = my_net_read(net)) == packet_error) From 9f7b30f5f877170fd343e1bcd66f6a1e7f682da3 Mon Sep 17 00:00:00 2001 From: "greg@mysql.com" <> Date: Wed, 15 Oct 2003 19:50:47 -0400 Subject: [PATCH 05/49] Created small scripts to manage in-tree diffs for NetWare platform, so changes are visible in the tree but cannot affect other platforms. --- netware/BUILD/apply-patch | 41 ++++++++++++++++++++++++++++ netware/BUILD/save-patch | 56 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100755 netware/BUILD/apply-patch create mode 100755 netware/BUILD/save-patch diff --git a/netware/BUILD/apply-patch b/netware/BUILD/apply-patch new file mode 100755 index 00000000000..3fe5a077f9a --- /dev/null +++ b/netware/BUILD/apply-patch @@ -0,0 +1,41 @@ +#! /bin/sh + +# debug +#set -x + +# stop on errors +set -e + +# repository directory +repo_dir=`pwd` + +# show usage +show_usage() +{ + cat << EOF + +usage: apply-patch + +Imports netware/current-changes.patch so that current changes +for the platform are present on the local repository. + +Use from the root directory of the repository, with BitKeeper +installed. + +EOF + exit 0; +} + +if test $1 || test -z $BK_USER +then + show_usage +fi + +echo "starting patch..." + +echo "user: $BK_USER" + +# import patch +# Note: In future this should be changed to check whether +# the repo already has this patch +bk import -tpatch $repo_dir/netware/current-changes.patch $repo_dir diff --git a/netware/BUILD/save-patch b/netware/BUILD/save-patch new file mode 100755 index 00000000000..9f9979ace5b --- /dev/null +++ b/netware/BUILD/save-patch @@ -0,0 +1,56 @@ +#! /bin/sh + +# debug +#set -x + +# stop on errors +set -e + +# repository directory +repo_dir=`pwd` + +# show usage +show_usage() +{ + cat << EOF + +usage: save-patch + +Creates a patch file between the latest revision of the current tree +and the latest revision not created by \$BK_USER and places it in +the tree as netware/current-changes.patch + +EOF + exit 0; +} + +if test $1 || test -z $BK_USER +then + show_usage +fi + +echo "starting patch..." + +echo "user: $BK_USER" + +# check for bk and repo_dir +bk help > /dev/null +repo_dir=`bk root $repo_dir` +cd $repo_dir + +# determine version +version=`grep -e "AM_INIT_AUTOMAKE(mysql, .*)" < configure.in | sed -e "s/AM_INIT_AUTOMAKE(mysql, \(.*\))/\1/"` +echo "version: $version" + +# user revision +user_rev=`bk changes -e -n -d':REV:' | head -1` +echo "latest revision: $user_rev" + +# tree revision +tree_rev=`bk changes -e -n -d':REV:' -U$BK_USER | head -1` +echo "latest non-$BK_USER revision: $tree_rev" + +# create patch +patch="$repo_dir/netware/current-changes.patch" +echo "creating \"$patch\"..." +bk export -tpatch -r$tree_rev..$user_rev -xnetware/current-changes.patch > $patch From c7d8977f43752afcab306f04c3de27eede259ab4 Mon Sep 17 00:00:00 2001 From: "kostja@oak.local" <> Date: Thu, 16 Oct 2003 17:00:09 +0400 Subject: [PATCH 06/49] fix for one of the bugs spotted by #1274 --- sql/sql_select.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 353a4623962..f1ab998c0fa 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -968,10 +968,20 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, } } } + /* + Here we sort rows for ORDER BY/GROUP BY clause, if the optimiser + chose FILESORT to be faster than INDEX SCAN or there is no + suitable index present. + Note, that create_sort_index calls test_if_skip_sort_order and may + finally replace sorting with index scan if there is a LIMIT clause in + the query. XXX: it's never shown in EXPLAIN! + OPTION_FOUND_ROWS supersedes LIMIT and is taken into account. + */ if (create_sort_index(&join.join_tab[join.const_tables], group ? group : order, select_limit, - thd->select_limit)) + join.select_options & OPTION_FOUND_ROWS ? + HA_POS_ERROR : thd->select_limit)) goto err; } join.having=having; // Actually a parameter From b1dba93cdb75d52d5754a55521d429e2005a6d49 Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Thu, 16 Oct 2003 20:55:15 +0300 Subject: [PATCH 07/49] Safety fix to detect multiple calls to my_thread_end() Portability fix (For Mac OS X) --- configure.in | 2 +- include/my_pthread.h | 1 + libmysqld/lib_sql.cc | 5 ---- mysys/charset.c | 66 +++++++++++++++++++++++++++++--------------- mysys/my_thr_init.c | 9 ++++-- sql/sql_test.cc | 4 +++ 6 files changed, 56 insertions(+), 31 deletions(-) diff --git a/configure.in b/configure.in index f085d365ed2..8ce3a9aea67 100644 --- a/configure.in +++ b/configure.in @@ -733,7 +733,7 @@ AC_CHECK_HEADERS(fcntl.h float.h floatingpoint.h ieeefp.h limits.h \ strings.h string.h synch.h sys/mman.h sys/socket.h netinet/in.h arpa/inet.h \ sys/timeb.h sys/types.h sys/un.h sys/vadvise.h sys/wait.h term.h \ unistd.h utime.h sys/utime.h termio.h termios.h sched.h crypt.h alloca.h \ - sys/ioctl.h) + sys/ioctl.h malloc.h sys/malloc.h) #-------------------------------------------------------------------- # Check for system libraries. Adds the library to $LIBS diff --git a/include/my_pthread.h b/include/my_pthread.h index 4247b951d82..16a14ac5038 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -637,6 +637,7 @@ struct st_my_thread_var long id; int cmp_length; int volatile abort; + my_bool init; #ifndef DBUG_OFF gptr dbug; char name[THREAD_NAME_SIZE+1]; diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 52ff08b8787..d33f384f81e 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -621,11 +621,6 @@ void STDCALL mysql_server_end() my_free((char*) copy_arguments_ptr, MYF(MY_ALLOW_ZERO_PTR)); copy_arguments_ptr=0; clean_up(0); -#ifdef THREAD - /* Don't call my_thread_end() if the application is using MY_INIT() */ - if (!org_my_init_done) - my_thread_end(); -#endif /* If library called my_init(), free memory allocated by it */ if (!org_my_init_done) my_end(0); diff --git a/mysys/charset.c b/mysys/charset.c index 6a64730571c..ba6733185e0 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -453,20 +453,37 @@ static my_bool charset_in_string(const char *name, DYNAMIC_STRING *s) static void charset_append(DYNAMIC_STRING *s, const char *name) { - if (!charset_in_string(name, s)) { + if (!charset_in_string(name, s)) + { dynstr_append(s, name); dynstr_append(s, " "); } } -/* Returns a dynamically-allocated string listing the character sets - requested. The caller is responsible for freeing the memory. */ +/* + Returns a dynamically-allocated string listing the character sets + requested. + + SYNOPSIS + list_charsets() + want_flags Flags for which character sets to return: + MY_COMPILED_SETS: Return incompiled charsets + MY_INDEX_SETS: + MY_LOADED_SETS: + + NOTES + The caller is responsible for freeing the memory. + + + RETURN + A string with available character sets separated by space +*/ char * list_charsets(myf want_flags) { DYNAMIC_STRING s; - char *p; + char *result; (void)init_available_charsets(MYF(0)); init_dynamic_string(&s, NullS, 256, 1024); @@ -483,42 +500,45 @@ char * list_charsets(myf want_flags) if (want_flags & MY_CONFIG_SETS) { - CS_ID **c; + CS_ID **charset; char buf[FN_REFLEN]; MY_STAT status; - if((c=available_charsets)) - for (; *c; ++c) - { - if (charset_in_string((*c)->name, &s)) - continue; - get_charset_conf_name((*c)->number, buf); - if (!my_stat(buf, &status, MYF(0))) - continue; /* conf file doesn't exist */ - dynstr_append(&s, (*c)->name); - dynstr_append(&s, " "); - } + if ((charset=available_charsets)) + { + for (; *charset; charset++) + { + if (charset_in_string((*charset)->name, &s)) + continue; + get_charset_conf_name((*charset)->number, buf); + if (!my_stat(buf, &status, MYF(0))) + continue; /* conf file doesn't exist */ + dynstr_append(&s, (*charset)->name); + dynstr_append(&s, " "); + } + } } if (want_flags & MY_INDEX_SETS) { - CS_ID **c; - for (c = available_charsets; *c; ++c) - charset_append(&s, (*c)->name); + CS_ID **charset; + for (charset = available_charsets; *charset; charset++) + charset_append(&s, (*charset)->name); } if (want_flags & MY_LOADED_SETS) { uint i; for (i = 0; i < cs_info_table.elements; i++) - charset_append(&s, + charset_append(&s, dynamic_element(&cs_info_table, i, CHARSET_INFO *)->name); } - s.str[s.length - 1] = '\0'; /* chop trailing space */ - p = my_strdup(s.str, MYF(MY_WME)); + if (s.length) + s.length--; /* Remove end space */ + result= my_strdup_with_length(s.str, s.length, MYF(MY_WME)); dynstr_free(&s); - return p; + return result; } /**************************************************************************** diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index 59466083b28..9f64e9dcb60 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -159,6 +159,7 @@ my_bool my_thread_init(void) tmp->id= ++thread_id; pthread_mutex_init(&tmp->mutex,MY_MUTEX_INIT_FAST); pthread_cond_init(&tmp->suspend, NULL); + tmp->init= 1; end: #if !defined(__WIN__) || defined(USE_TLS) || ! defined(SAFE_MUTEX) @@ -170,12 +171,14 @@ end: void my_thread_end(void) { - struct st_my_thread_var *tmp=my_thread_var; + struct st_my_thread_var *tmp; + tmp= my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys); + #ifdef EXTRA_DEBUG_THREADS fprintf(stderr,"my_thread_end(): tmp=%p,thread_id=%ld\n", tmp,pthread_self()); #endif - if (tmp) + if (tmp && tmp->init) { #if !defined(DBUG_OFF) /* tmp->dbug is allocated inside DBUG library */ @@ -191,6 +194,8 @@ void my_thread_end(void) pthread_mutex_destroy(&tmp->mutex); #if (!defined(__WIN__) && !defined(OS2)) || defined(USE_TLS) free(tmp); +#else + tmp->init= 0; #endif } /* The following free has to be done, even if my_thread_var() is 0 */ diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 6498a52cc09..a217d40246f 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -22,7 +22,11 @@ #include "sql_select.h" #include #include +#if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_H) #include +#elif defined(HAVE_MALLINFO) && defined(HAVE_SYS_MALLOC_H) +#include +#endif /* Intern key cache variables */ extern "C" pthread_mutex_t THR_LOCK_keycache; From 83f5c4dbf856d5deaecddd41bbd6bfedebbcbc03 Mon Sep 17 00:00:00 2001 From: "lenz@mysql.com" <> Date: Thu, 16 Oct 2003 22:15:36 +0200 Subject: [PATCH 08/49] - fixed small typo to resolve "test: argument expected" error on Solaris and Tru64 when running "mysql_install_db" --- scripts/mysql_install_db.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index 5a6b11fb19b..ba95ff3b5b9 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -136,7 +136,7 @@ then fi fi -if test "$ip_only" ="1" +if test "$ip_only" = "1" then ip=`echo "$resolved" | awk '/ /{print $6}'` hostname=$ip From ce6d7367148e13abf75432cc8151c878e692d105 Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Fri, 17 Oct 2003 00:00:25 +0200 Subject: [PATCH 09/49] A fix for a random test failure rpl_trunc_binlog: don't RESET MASTER while the slave is connected. --- mysql-test/t/rpl_trunc_binlog.test | 2 -- sql/slave.cc | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/mysql-test/t/rpl_trunc_binlog.test b/mysql-test/t/rpl_trunc_binlog.test index 11ec0026560..2c34b7a442f 100644 --- a/mysql-test/t/rpl_trunc_binlog.test +++ b/mysql-test/t/rpl_trunc_binlog.test @@ -22,5 +22,3 @@ start slave; sleep 3; --replace_result $MASTER_MYPORT MASTER_PORT show slave status; -connection master; -reset master; diff --git a/sql/slave.cc b/sql/slave.cc index 9c380408291..b679ac2f6b8 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1337,7 +1337,7 @@ file '%s', errno %d)", fname, my_errno); if (init_relay_log_pos(rli,NullS,BIN_LOG_HEADER_SIZE,0 /* no data lock */, &msg)) { - sql_print_error("Failed to open the relay log 'FIRST' (relay_log_pos 4"); + sql_print_error("Failed to open the relay log 'FIRST' (relay_log_pos 4)"); goto err; } rli->master_log_name[0]= 0; From 095db2746ed7ad5310b08880f7b81a1915da47f0 Mon Sep 17 00:00:00 2001 From: "lenz@mysql.com" <> Date: Fri, 17 Oct 2003 02:32:09 +0200 Subject: [PATCH 10/49] - Updated rpl_trunc_binlog test result after last change --- mysql-test/r/rpl_trunc_binlog.result | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/r/rpl_trunc_binlog.result b/mysql-test/r/rpl_trunc_binlog.result index a006437207a..eb5dcf7c593 100644 --- a/mysql-test/r/rpl_trunc_binlog.result +++ b/mysql-test/r/rpl_trunc_binlog.result @@ -11,4 +11,3 @@ start slave; show slave status; Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space 127.0.0.1 root MASTER_PORT 1 master-bin.002 4 slave-relay-bin.002 161 master-bin.001 Yes No 0 Rolling back unfinished transaction (no COMMIT or ROLLBACK) from relay log. Probably cause is that the master died while writing the transaction to it's binary log. 0 79 317 -reset master; From ecce9f23ae1c569191a02734be80239f4bf62ed3 Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Fri, 17 Oct 2003 09:15:30 +0200 Subject: [PATCH 11/49] test update: what we want to detect in this test is if the slave stopped. --- mysql-test/r/rpl_trunc_binlog.result | 4 ---- mysql-test/t/rpl_trunc_binlog.test | 3 +-- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/mysql-test/r/rpl_trunc_binlog.result b/mysql-test/r/rpl_trunc_binlog.result index a006437207a..19d5e30addb 100644 --- a/mysql-test/r/rpl_trunc_binlog.result +++ b/mysql-test/r/rpl_trunc_binlog.result @@ -8,7 +8,3 @@ stop slave; flush logs; reset slave; start slave; -show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.002 4 slave-relay-bin.002 161 master-bin.001 Yes No 0 Rolling back unfinished transaction (no COMMIT or ROLLBACK) from relay log. Probably cause is that the master died while writing the transaction to it's binary log. 0 79 317 -reset master; diff --git a/mysql-test/t/rpl_trunc_binlog.test b/mysql-test/t/rpl_trunc_binlog.test index 2c34b7a442f..59d8aed288c 100644 --- a/mysql-test/t/rpl_trunc_binlog.test +++ b/mysql-test/t/rpl_trunc_binlog.test @@ -20,5 +20,4 @@ reset slave; start slave; # can't sync_with_master so we must sleep sleep 3; ---replace_result $MASTER_MYPORT MASTER_PORT -show slave status; +wait_for_slave_to_stop; From fad448bddd3a149aa9318af8b9a80486143e6e6a Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Fri, 17 Oct 2003 09:26:38 +0200 Subject: [PATCH 12/49] cancelling a previous change I made in rpl_trunc_binlog.test (which I did not push), to enable SHOW SLAVE STATUS again. --- mysql-test/r/rpl_trunc_binlog.result | 3 +++ mysql-test/t/rpl_trunc_binlog.test | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/rpl_trunc_binlog.result b/mysql-test/r/rpl_trunc_binlog.result index 19d5e30addb..eb5dcf7c593 100644 --- a/mysql-test/r/rpl_trunc_binlog.result +++ b/mysql-test/r/rpl_trunc_binlog.result @@ -8,3 +8,6 @@ stop slave; flush logs; reset slave; start slave; +show slave status; +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +127.0.0.1 root MASTER_PORT 1 master-bin.002 4 slave-relay-bin.002 161 master-bin.001 Yes No 0 Rolling back unfinished transaction (no COMMIT or ROLLBACK) from relay log. Probably cause is that the master died while writing the transaction to it's binary log. 0 79 317 diff --git a/mysql-test/t/rpl_trunc_binlog.test b/mysql-test/t/rpl_trunc_binlog.test index 59d8aed288c..2c34b7a442f 100644 --- a/mysql-test/t/rpl_trunc_binlog.test +++ b/mysql-test/t/rpl_trunc_binlog.test @@ -20,4 +20,5 @@ reset slave; start slave; # can't sync_with_master so we must sleep sleep 3; -wait_for_slave_to_stop; +--replace_result $MASTER_MYPORT MASTER_PORT +show slave status; From 91f5c5e3379869c82b1477a37cefe54be084f261 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Fri, 17 Oct 2003 23:44:34 +0300 Subject: [PATCH 13/49] thr0loc.c, srv0start.c, srv0srv.c, srv0srv.h, os0thread.h, ha_innodb.cc: Backport from 4.1: reduce InnoDB memory consumption if buf pool < 8 MB --- innobase/include/os0thread.h | 11 +++-------- innobase/include/srv0srv.h | 2 ++ innobase/srv/srv0srv.c | 14 +++++++++++--- innobase/srv/srv0start.c | 22 ++++++++++++++++++++++ innobase/thr/thr0loc.c | 1 + sql/ha_innodb.cc | 5 ----- 6 files changed, 39 insertions(+), 16 deletions(-) diff --git a/innobase/include/os0thread.h b/innobase/include/os0thread.h index 491d8866af4..554ca0563e4 100644 --- a/innobase/include/os0thread.h +++ b/innobase/include/os0thread.h @@ -15,14 +15,9 @@ Created 9/8/1995 Heikki Tuuri /* Maximum number of threads which can be created in the program; this is also the size of the wait slot array for MySQL threads which can wait inside InnoDB */ -#if defined(__WIN__) || defined(__NETWARE__) -/* Create less event semaphores because Win 98/ME had difficult creating -40000 event semaphores */ -/* TODO: these just take a lot of memory on NetWare. should netware move up? */ -#define OS_THREAD_MAX_N 1000 -#else -#define OS_THREAD_MAX_N 10000 -#endif + +#define OS_THREAD_MAX_N srv_max_n_threads + /* Possible fixed priorities for threads */ #define OS_THREAD_PRIORITY_NONE 100 diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h index f4255fc9a98..87df3904f19 100644 --- a/innobase/include/srv0srv.h +++ b/innobase/include/srv0srv.h @@ -80,6 +80,8 @@ extern ulint srv_max_dirty_pages_pct; extern ulint srv_force_recovery; extern ulint srv_thread_concurrency; +extern ulint srv_max_n_threads; + extern lint srv_conc_n_threads; extern ibool srv_fast_shutdown; diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index f31d275eff0..8aba1b4f414 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -142,7 +142,7 @@ byte srv_latin1_ordering[256] /* The sort order table of the latin1 ulint srv_pool_size = ULINT_MAX; /* size in database pages; MySQL originally sets this - value in megabytes */ + value in bytes */ ulint srv_mem_pool_size = ULINT_MAX; /* size in bytes */ ulint srv_lock_table_size = ULINT_MAX; @@ -169,6 +169,12 @@ the user from forgetting the innodb_force_recovery keyword to my.cnf */ ulint srv_force_recovery = 0; /*-----------------------*/ +/* We are prepared for a situation that we have this many threads waiting for +a semaphore inside InnoDB. innobase_start_or_create_for_mysql() sets the +value. */ + +ulint srv_max_n_threads = 0; + /* The following controls how many threads we let inside InnoDB concurrently: threads waiting for locks are not counted into the number because otherwise we could get a deadlock. MySQL creates a thread for each user session, and @@ -208,7 +214,7 @@ struct srv_conc_slot_struct{ UT_LIST_BASE_NODE_T(srv_conc_slot_t) srv_conc_queue; /* queue of threads waiting to get in */ -srv_conc_slot_t srv_conc_slots[OS_THREAD_MAX_N]; /* array of wait +srv_conc_slot_t* srv_conc_slots; /* array of wait slots */ /* Number of times a thread is allowed to enter InnoDB within the same @@ -1693,6 +1699,8 @@ srv_init(void) os_fast_mutex_init(&srv_conc_mutex); UT_LIST_INIT(srv_conc_queue); + + srv_conc_slots = mem_alloc(OS_THREAD_MAX_N * sizeof(srv_conc_slot_t)); for (i = 0; i < OS_THREAD_MAX_N; i++) { conc_slot = srv_conc_slots + i; @@ -1740,7 +1748,7 @@ srv_conc_enter_innodb( thread */ { ibool has_slept = FALSE; - srv_conc_slot_t* slot; + srv_conc_slot_t* slot = NULL; ulint i; char err_buf[1000]; diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index a85c3615c1b..af4ca71d443 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -1087,6 +1087,28 @@ innobase_start_or_create_for_mysql(void) return(DB_ERROR); } + /* Set the maximum number of threads which can wait for a semaphore + inside InnoDB */ +#if defined(__WIN__) || defined(__NETWARE__) + +/* Create less event semaphores because Win 98/ME had difficulty creating +40000 event semaphores. +Comment from Novell, Inc.: also, these just take a lot of memory on +NetWare. */ + srv_max_n_threads = 1000; +#else + if (srv_pool_size >= 8 * 1024 * 1024) { + /* Here we still have srv_pool_size counted + in bytes, srv_boot converts the value to + pages; if buffer pool is less than 8 MB, + assume fewer threads. */ + srv_max_n_threads = 10000; + } else { + srv_max_n_threads = 1000; /* saves several MB of memory, + especially in 64-bit + computers */ + } +#endif err = srv_boot(); if (err != DB_SUCCESS) { diff --git a/innobase/thr/thr0loc.c b/innobase/thr/thr0loc.c index fbf3e3a1dad..839cb024f25 100644 --- a/innobase/thr/thr0loc.c +++ b/innobase/thr/thr0loc.c @@ -14,6 +14,7 @@ Created 10/5/1995 Heikki Tuuri #include "sync0sync.h" #include "hash0hash.h" #include "mem0mem.h" +#include "srv0srv.h" /* IMPLEMENTATION OF THREAD LOCAL STORAGE diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 3619fefdd1b..47c49b79d77 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -17,11 +17,6 @@ /* This file defines the InnoDB handler: the interface between MySQL and InnoDB */ -/* TODO list for the InnoDB handler: - - Ask Monty if strings of different languages can exist in the same - database. Answer: in 4.1 yes. -*/ - #ifdef __GNUC__ #pragma implementation // gcc: Class implementation #endif From 18995bb1c6986235a3f911dbe10799b2074fcece Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Sun, 19 Oct 2003 20:28:03 +0300 Subject: [PATCH 14/49] os0file.c: Check that writes to data files always happen in to addresses divisible by 16 kB, and the chunk size is also divisible by 16 kB; a user reported 2 corrupt pages from Linux-2.4.20 where an index page seemed displaced --- innobase/os/os0file.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 311937f2145..24bc0f1bdf9 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -2676,7 +2676,11 @@ consecutive_loop: /* Do the i/o with ordinary, synchronous i/o functions: */ if (slot->type == OS_FILE_WRITE) { if (array == os_aio_write_array) { - + if ((total_len % UNIV_PAGE_SIZE != 0) + || (slot->offset % UNIV_PAGE_SIZE != 0)) { + ut_a(0); + } + /* Do a 'last millisecond' check that the page end is sensible; reported page checksum errors from Linux seem to wipe over the page end */ From e52a2f1ace9c52d012fb0f9a0f89e811e709db85 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Sun, 19 Oct 2003 20:31:32 +0300 Subject: [PATCH 15/49] os0file.c: Check that writes to data files always happen in to addresses divisible by 16 kB, and the chunk size is also divisible by 16 kB; a user reported 2 corrupt pages from Linux-2.4.20 where an index page seemed displaced --- innobase/os/os0file.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 24bc0f1bdf9..55d0ade1bf7 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -2678,6 +2678,10 @@ consecutive_loop: if (array == os_aio_write_array) { if ((total_len % UNIV_PAGE_SIZE != 0) || (slot->offset % UNIV_PAGE_SIZE != 0)) { + fprintf(stderr, +"InnoDB: Error: trying a displaced write to %s %lu %lu, len %lu\n", + slot->name, slot->offset_high, + slot->offset, total_len); ut_a(0); } From d0a21a0aeb883602345484a2015d6a4ad80d7f68 Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Mon, 20 Oct 2003 15:35:03 +0200 Subject: [PATCH 16/49] Fix for Bug #1595 "mysqlbinlog can't read a password from the console". Make mysqlbinlog prompt for the password if mysqlbinlog -p instead of printing the usage(). This makes mysqlbinlog behave like other clients, which is the reason why we fix this in 3.23. This new code was almost copied from mysqldump. Note that before, one could use mysqlbinlog -p pass and now one must use mysqlbinlog -ppass (putting a space will ask for the password). --- client/mysqlbinlog.cc | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 6d1e711fa98..e0cee438f1b 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -54,7 +54,7 @@ static struct option long_options[] = {"help", no_argument, 0, '?'}, {"host", required_argument, 0, 'h'}, {"offset", required_argument, 0, 'o'}, - {"password", required_argument, 0, 'p'}, + {"password", optional_argument, 0, 'p'}, {"port", required_argument, 0, 'P'}, {"position", required_argument, 0, 'j'}, {"result-file", required_argument, 0, 'r'}, @@ -71,7 +71,7 @@ static ulonglong offset = 0; static const char* host = "localhost"; static int port = MYSQL_PORT; static const char* user = "test"; -static const char* pass = ""; +static char* pass = 0; static ulonglong position = 0; static bool use_remote = 0; static short binlog_flags = 0; @@ -84,6 +84,7 @@ static void dump_log_entries(const char* logname); static void dump_remote_file(NET* net, const char* fname); static void dump_remote_table(NET* net, const char* db, const char* table); static void die(const char* fmt, ...); +static void cleanup(); static MYSQL* safe_connect(); @@ -97,6 +98,11 @@ void sql_print_error(const char *format,...) va_end(args); } +static void cleanup() +{ + my_free(pass,MYF(MY_ALLOW_ZERO_PTR)); +} + static void die(const char* fmt, ...) { va_list args; @@ -105,6 +111,7 @@ static void die(const char* fmt, ...) vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); va_end(args); + cleanup(); exit(1); } @@ -177,9 +184,10 @@ static void dump_remote_file(NET* net, const char* fname) static int parse_args(int *argc, char*** argv) { int c, opt_index = 0; + bool tty_password= 0; result_file = stdout; - while((c = getopt_long(*argc, *argv, "so:#::h:j:u:p:P:r:t:?V", long_options, + while((c = getopt_long(*argc, *argv, "so:#::h:j:u:p::P:r:t:?V", long_options, &opt_index)) != EOF) { switch(c) @@ -213,7 +221,17 @@ static int parse_args(int *argc, char*** argv) case 'p': use_remote = 1; - pass = my_strdup(optarg, MYF(0)); + if (optarg) + { + char *start=optarg; + my_free(pass,MYF(MY_ALLOW_ZERO_PTR)); + pass= my_strdup(optarg,MYF(MY_FAE)); + while (*optarg) *optarg++= 'x'; /* Destroy argument */ + if (*start) + start[1]=0; /* Cut length of argument */ + } + else + tty_password=1; break; case 'r': @@ -244,6 +262,8 @@ static int parse_args(int *argc, char*** argv) (*argc)-=optind; (*argv)+=optind; + if (tty_password) + pass= get_tty_password(NullS); return 0; } @@ -457,6 +477,7 @@ int main(int argc, char** argv) my_fclose(result_file, MYF(0)); if (use_remote) mysql_close(mysql); + cleanup(); return 0; } From f602be8d3f860d2c59399a5fd7e601871859ad7e Mon Sep 17 00:00:00 2001 From: "gluh@gluh.mysql.r18.ru" <> Date: Tue, 21 Oct 2003 15:14:06 +0500 Subject: [PATCH 17/49] Fix for bug #1271: Undefined variable in PASSWORD() function is not handled correctly --- mysql-test/r/func_crypt.result | 10 ++++++++++ mysql-test/t/func_crypt.test | 9 +++++++++ sql/item_func.cc | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_crypt.result b/mysql-test/r/func_crypt.result index 742de833bf7..96bbaa6cae7 100644 --- a/mysql-test/r/func_crypt.result +++ b/mysql-test/r/func_crypt.result @@ -7,3 +7,13 @@ old_password('test') password('test') select length(encrypt('test')), encrypt('test','aa'); length(encrypt('test')) encrypt('test','aa') 13 aaqPiZY5xR5l. +drop table if exists t1; +create table t1 (name varchar(50), pw varchar(16)); +insert into t1 values ('tom', password('my_pass')); +set @pass='my_pass'; +select name from t1 where name='tom' and pw=password(@pass); +name +tom +select name from t1 where name='tom' and pw=password(@undefined); +name +drop table t1; diff --git a/mysql-test/t/func_crypt.test b/mysql-test/t/func_crypt.test index f403d96e885..e612405c5e9 100644 --- a/mysql-test/t/func_crypt.test +++ b/mysql-test/t/func_crypt.test @@ -4,3 +4,12 @@ select length(encrypt('foo', 'ff')) <> 0; --replace_result $1$aa$4OSUA5cjdx0RUQ08opV27/ aaqPiZY5xR5l. select old_password('test'), password('test'); select length(encrypt('test')), encrypt('test','aa'); + +drop table if exists t1; +create table t1 (name varchar(50), pw varchar(16)); +insert into t1 values ('tom', password('my_pass')); +set @pass='my_pass'; +select name from t1 where name='tom' and pw=password(@pass); +select name from t1 where name='tom' and pw=password(@undefined); +drop table t1; + diff --git a/sql/item_func.cc b/sql/item_func.cc index fd6d17d0cf2..8d7ee637d73 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2087,7 +2087,7 @@ void Item_func_get_user_var::fix_length_and_dec() bool Item_func_get_user_var::const_item() const { - return var_entry && current_thd->query_id != var_entry->update_query_id; + return (!var_entry || current_thd->query_id != var_entry->update_query_id); } From c93f69e9dd41b73e8dd76adba367bb86277ff688 Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Tue, 21 Oct 2003 12:22:24 +0200 Subject: [PATCH 18/49] Fix for Bug #1595 "mysqlbinlog can't read a password from the console". ** I already fixed it in 3.23; I fix it in 4.0 separately because the code is a bit different (so the changeset 1.1422 of 3.23 should not be merged here) ** Make mysqlbinlog prompt for the password if mysqlbinlog -p instead of printing the usage(). This makes mysqlbinlog behave like other clients. This new code was almost copied from mysqldump. Note that before, one could use mysqlbinlog -p pass and now one must use mysqlbinlog -ppass (putting a space will ask for the password). --- client/mysqlbinlog.cc | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 298521b5aa7..34b7ae11f74 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -52,7 +52,7 @@ static const char* host = 0; static int port = MYSQL_PORT; static const char* sock= 0; static const char* user = 0; -static const char* pass = ""; +static char* pass = 0; static ulonglong position = 0; static short binlog_flags = 0; static MYSQL* mysql = NULL; @@ -227,7 +227,7 @@ static struct my_option my_long_options[] = {"offset", 'o', "Skip the first N entries.", (gptr*) &offset, (gptr*) &offset, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"password", 'p', "Password to connect to remote server.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Use port to connect to the remote server.", (gptr*) &port, (gptr*) &port, 0, GET_INT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0}, @@ -267,6 +267,11 @@ void sql_print_error(const char *format,...) va_end(args); } +static void cleanup() +{ + my_free(pass,MYF(MY_ALLOW_ZERO_PTR)); +} + static void die(const char* fmt, ...) { va_list args; @@ -275,6 +280,7 @@ static void die(const char* fmt, ...) vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); va_end(args); + cleanup(); exit(1); } @@ -334,6 +340,7 @@ extern "C" my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) { + bool tty_password=0; switch (optid) { #ifndef DBUG_OFF case '#': @@ -344,7 +351,17 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), one_database = 1; break; case 'p': - pass = my_strdup(argument, MYF(0)); + if (argument) + { + my_free(pass,MYF(MY_ALLOW_ZERO_PTR)); + char *start=argument; + pass= my_strdup(argument,MYF(MY_FAE)); + while (*argument) *argument++= 'x'; /* Destroy argument */ + if (*start) + start[1]=0; /* Cut length of argument */ + } + else + tty_password=1; break; case 'r': if (!(result_file = my_fopen(argument, O_WRONLY | O_BINARY, MYF(MY_WME)))) @@ -360,6 +377,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), usage(); exit(0); } + if (tty_password) + pass= get_tty_password(NullS); + return 0; } @@ -778,6 +798,7 @@ int main(int argc, char** argv) my_fclose(result_file, MYF(0)); if (remote_opt) mysql_close(mysql); + cleanup(); free_defaults(defaults_argv); my_end(0); return 0; From b93c83ee2a9a25e8ccd4f16064d27774ea097d6b Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Tue, 21 Oct 2003 17:34:40 +0200 Subject: [PATCH 19/49] Bug#1271 - RAND_TABLE_BIT in expression and only const_tables in join --- sql/sql_select.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f1ab998c0fa..55813378b9c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2600,6 +2600,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) table_map used_tables; if (join->tables > 1) cond->update_used_tables(); // Tablenr may have changed + if (join->const_tables == join->tables) + join->const_table_map|=RAND_TABLE_BIT; { // Check const tables COND *const_cond= make_cond_for_table(cond,join->const_table_map,(table_map) 0); From f393024fef2965c08ec99a4f0b5810228f4e88df Mon Sep 17 00:00:00 2001 From: "lenz@mysql.com" <> Date: Tue, 21 Oct 2003 18:41:19 +0200 Subject: [PATCH 20/49] - bumped up version number in configure.in to to 4.0.17 now that 4.0.16 has been tagged and released - tagged ChangeSet 1.1576.1.5 as "mysql-4.0.16" --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 8ce3a9aea67..02825ce1424 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.16) +AM_INIT_AUTOMAKE(mysql, 4.0.17) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 From 07c9d4575bba8ac3c6b5d364f3a63890f46e6953 Mon Sep 17 00:00:00 2001 From: "jani@rhols221.adsl.netsonic.fi" <> Date: Wed, 22 Oct 2003 16:02:27 +0300 Subject: [PATCH 21/49] Applied a patch from Travis Wheeler to mysqlhotcopy that allows using regexp with tablenames together with databasenames. --- scripts/mysqlhotcopy.sh | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh index f23955da06a..3e53af32653 100644 --- a/scripts/mysqlhotcopy.sh +++ b/scripts/mysqlhotcopy.sh @@ -37,7 +37,7 @@ WARNING: THIS PROGRAM IS STILL IN BETA. Comments/patches welcome. # Documentation continued at end of file -my $VERSION = "1.19"; +my $VERSION = "1.20"; my $opt_tmpdir = $ENV{TMPDIR} || "/tmp"; @@ -235,10 +235,15 @@ else # --- resolve database names from regexp --- if ( defined $opt{regexp} ) { + my $t_regex = '.*'; + if ( $opt{regexp} =~ s{^/(.+)/\./(.+)/$}{$1} ) { + $t_regex = $2; + } + my $sth_dbs = $dbh->prepare("show databases"); $sth_dbs->execute; while ( my ($db_name) = $sth_dbs->fetchrow_array ) { - push @db_desc, { 'src' => $db_name } if ( $db_name =~ m/$opt{regexp}/o ); + push @db_desc, { 'src' => $db_name, 't_regex' => $t_regex } if ( $db_name =~ m/$opt{regexp}/o ); } } @@ -938,6 +943,14 @@ server in a mutual replication setup. Copy all databases with names matching the pattern +=item --regexp /pattern1/./pattern2/ + +Copy all tables with names matching pattern2 from all databases with +names matching pattern1. For example, to select all tables which +names begin with 'bar' from all databases which names end with 'foo': + + mysqlhotcopy --indices --method=cp --regexp /foo$/./^bar/ + =item db_name./pattern/ Copy only tables matching pattern. Shell metacharacters ( (, ), |, !, From 94cce644165e0009f9a057b8e21712e9b3f370ea Mon Sep 17 00:00:00 2001 From: "jani@rhols221.adsl.netsonic.fi" <> Date: Wed, 22 Oct 2003 18:19:59 +0300 Subject: [PATCH 22/49] Fixed bug #954 mysqlhotcopy permission problem. The database directory owner ship was not honored. --- scripts/mysqlhotcopy.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh index 3e53af32653..654e5466e12 100644 --- a/scripts/mysqlhotcopy.sh +++ b/scripts/mysqlhotcopy.sh @@ -418,6 +418,8 @@ foreach my $rdb ( @db_desc ) { else { mkdir($tgt_dirpath, 0750) or die "Can't create '$tgt_dirpath': $!\n" unless -d $tgt_dirpath; + my @f_info= stat "$datadir/$rdb->{src}"; + chown $f_info[4], $f_info[5], $tgt_dirpath; } } } From e69447933dce4c4bbd681e6b7eea15a1d23bb415 Mon Sep 17 00:00:00 2001 From: "jani@rhols221.adsl.netsonic.fi" <> Date: Wed, 22 Oct 2003 18:40:37 +0300 Subject: [PATCH 23/49] Fixed a bug in mysqlhotcopy, which made special table names to cause program to abort. Such table name could have been one with a semicolon (:) in the middle. --- scripts/mysqlhotcopy.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh index 654e5466e12..160a2611374 100644 --- a/scripts/mysqlhotcopy.sh +++ b/scripts/mysqlhotcopy.sh @@ -453,13 +453,13 @@ if ( $opt{dryrun} ) { } else { my $start = time; - $dbh->do("LOCK TABLES $hc_locks"); + $dbh->do('LOCK TABLES $hc_locks'); printf "Locked $num_tables tables in %d seconds.\n", time-$start unless $opt{quiet}; $hc_started = time; # count from time lock is granted # flush tables to make on-disk copy uptodate $start = time; - $dbh->do("FLUSH TABLES /*!32323 $hc_tables */"); + $dbh->do('FLUSH TABLES /*!32323 $hc_tables */'); printf "Flushed tables ($hc_tables) in %d seconds.\n", time-$start unless $opt{quiet}; $dbh->do( "FLUSH LOGS" ) if ( $opt{flushlog} ); $dbh->do( "RESET MASTER" ) if ( $opt{resetmaster} ); @@ -467,7 +467,7 @@ else { if ( $opt{record_log_pos} ) { record_log_pos( $dbh, $opt{record_log_pos} ); - $dbh->do("FLUSH TABLES /*!32323 $hc_tables */"); + $dbh->do('FLUSH TABLES /*!32323 $hc_tables */'); } } From 7b3c89f1f6aec2658a51c39be53ae32a2869d6db Mon Sep 17 00:00:00 2001 From: "jani@rhols221.adsl.netsonic.fi" <> Date: Wed, 22 Oct 2003 19:24:19 +0300 Subject: [PATCH 24/49] Reverted a wrong patch from mysqlhotcopy. This is a real bug in MySQL server... --- scripts/mysqlhotcopy.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh index 160a2611374..654e5466e12 100644 --- a/scripts/mysqlhotcopy.sh +++ b/scripts/mysqlhotcopy.sh @@ -453,13 +453,13 @@ if ( $opt{dryrun} ) { } else { my $start = time; - $dbh->do('LOCK TABLES $hc_locks'); + $dbh->do("LOCK TABLES $hc_locks"); printf "Locked $num_tables tables in %d seconds.\n", time-$start unless $opt{quiet}; $hc_started = time; # count from time lock is granted # flush tables to make on-disk copy uptodate $start = time; - $dbh->do('FLUSH TABLES /*!32323 $hc_tables */'); + $dbh->do("FLUSH TABLES /*!32323 $hc_tables */"); printf "Flushed tables ($hc_tables) in %d seconds.\n", time-$start unless $opt{quiet}; $dbh->do( "FLUSH LOGS" ) if ( $opt{flushlog} ); $dbh->do( "RESET MASTER" ) if ( $opt{resetmaster} ); @@ -467,7 +467,7 @@ else { if ( $opt{record_log_pos} ) { record_log_pos( $dbh, $opt{record_log_pos} ); - $dbh->do('FLUSH TABLES /*!32323 $hc_tables */'); + $dbh->do("FLUSH TABLES /*!32323 $hc_tables */"); } } From eaf9f35db82afabf2ad2854102a2c9d9dcad661d Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Thu, 23 Oct 2003 14:04:06 +0300 Subject: [PATCH 25/49] Fix results after merge --- mysql-test/r/myisam.result | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 3052af3499d..e113a48f4da 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -83,7 +83,6 @@ OPTIMIZE TABLE t1; Table Op Msg_type Msg_text test.t1 optimize status OK DROP TABLE t1; -drop table if exists t1; create table t1 ( t1 char(255), key(t1(250))); insert t1 values ('137513751375137513751375137513751375137569516951695169516951695169516951695169'); insert t1 values ('178417841784178417841784178417841784178403420342034203420342034203420342034203'); From fb548cbc6d8ce20032d48c2e5ec177ff6ce416ed Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Thu, 23 Oct 2003 15:24:48 +0200 Subject: [PATCH 26/49] Put username in the Subject line as well (with the changeset number). --- BitKeeper/triggers/post-commit | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BitKeeper/triggers/post-commit b/BitKeeper/triggers/post-commit index 636e4262693..7f803732d5b 100755 --- a/BitKeeper/triggers/post-commit +++ b/BitKeeper/triggers/post-commit @@ -19,7 +19,8 @@ BK_STATUS=$BK_STATUS$BK_COMMIT if [ "$BK_STATUS" = OK ] then -CHANGESET=`bk -R prs -r+ -h -d':I:' ChangeSet` +USRN=`echo $FROM | sed 's/\(..*\)@.*/\1/'` +CHANGESET=${USRN}:`bk -R prs -r+ -h -d':I:' ChangeSet` #++ # dev-public@ From 37ee1b8e439044a13bbd4f6c87909a4cfd278bbe Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Fri, 24 Oct 2003 14:22:54 +0300 Subject: [PATCH 27/49] Move the pid file testing after arguments are parsed (previous patch was not correct) --- support-files/mysql.server.sh | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index 89d45e0f26d..36eb5c4dff6 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -108,19 +108,6 @@ else test -z "$print_defaults" && print_defaults="my_print_defaults" fi -# -# Set pid file if not given -# -if test -z "$pid_file" -then - pid_file=$datadir/`@HOSTNAME@`.pid -else - case "$pid_file" in - /* ) ;; - * ) pid_file="$datadir/$pid_file" ;; - esac -fi - # # Test if someone changed datadir; In this case we should also read the # default arguments from this directory @@ -134,6 +121,19 @@ fi parse_arguments `$print_defaults $extra_args mysqld mysql_server mysql.server` +# +# Set pid file if not given +# +if test -z "$pid_file" +then + pid_file=$datadir/`@HOSTNAME@`.pid +else + case "$pid_file" in + /* ) ;; + * ) pid_file="$datadir/$pid_file" ;; + esac +fi + # Safeguard (relative paths, core dumps..) cd $basedir From dcc36e671c3a458b77dba4ffc409b4dc8b24d9ef Mon Sep 17 00:00:00 2001 From: "vva@eagle.mysql.r18.ru" <> Date: Fri, 24 Oct 2003 15:20:46 -0400 Subject: [PATCH 28/49] added to mysql_secure_installation changing root password on all hosts (bug 1228) --- scripts/mysql_secure_installation.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/mysql_secure_installation.sh b/scripts/mysql_secure_installation.sh index d6392c57731..1c7ca34ad59 100644 --- a/scripts/mysql_secure_installation.sh +++ b/scripts/mysql_secure_installation.sh @@ -85,9 +85,13 @@ set_root_password() { return 1 fi - do_query "SET PASSWORD FOR root=PASSWORD('$password1');" + do_query "UPDATE mysql.user SET Password=PASSWORD('$password1') WHERE User='root';" if [ $? -eq 0 ]; then echo "Password updated successfully!" + echo "Reloading privilege tables.." + if ! reload_privilege_tables; then + exit 1 + fi echo rootpass=$password1 make_config @@ -144,11 +148,11 @@ reload_privilege_tables() { do_query "FLUSH PRIVILEGES;" if [ $? -eq 0 ]; then echo " ... Success!" + return 0 else echo " ... Failed!" + return 1 fi - - return 0 } interrupt() { From a6d788d115969d933b8aac44db5113c9c53f5111 Mon Sep 17 00:00:00 2001 From: "vva@eagle.mysql.r18.ru" <> Date: Fri, 24 Oct 2003 17:26:26 -0400 Subject: [PATCH 29/49] added quotas for database names (fixed bug #1348) --- client/mysqldump.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index b28373ccd4a..40f88021c89 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -1271,10 +1271,13 @@ static int init_dumping(char *database) { if (opt_databases || opt_alldbs) { + /* length of table name * 2 (if name contain quotas), 2 quotas and 0 */ + char quoted_database_buf[64*2+3]; + char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted); fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", database); if (!opt_create_db) fprintf(md_result_file,"\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n", - database); + qdatabase); fprintf(md_result_file,"\nUSE %s;\n", database); } } From 72d00ef0c28047f82f80a35bf95b3d04a34bf931 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Sat, 25 Oct 2003 22:43:19 +0200 Subject: [PATCH 30/49] cleanup --- BitKeeper/triggers/post-commit | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/BitKeeper/triggers/post-commit b/BitKeeper/triggers/post-commit index 7f803732d5b..2dfefb5deb3 100755 --- a/BitKeeper/triggers/post-commit +++ b/BitKeeper/triggers/post-commit @@ -19,8 +19,7 @@ BK_STATUS=$BK_STATUS$BK_COMMIT if [ "$BK_STATUS" = OK ] then -USRN=`echo $FROM | sed 's/\(..*\)@.*/\1/'` -CHANGESET=${USRN}:`bk -R prs -r+ -h -d':I:' ChangeSet` +CHANGESET=`bk -R prs -r+ -h -d':P:::I:' ChangeSet` #++ # dev-public@ From 52c353de9439bbf1ae0c4ccd73c2b030d8ae43a3 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Mon, 27 Oct 2003 11:18:44 +0100 Subject: [PATCH 31/49] correct casting in ulonglong2double --- include/config-win.h | 4 ++-- include/my_global.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/config-win.h b/include/config-win.h index 9f903b3bcd2..53dff5d63af 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -173,8 +173,8 @@ inline double rint(double nr) } #ifdef _WIN64 -#define ulonglong2double(A) ((double) (A)) -#define my_off_t2double(A) ((double) (A)) +#define ulonglong2double(A) ((double) (ulonglong) (A)) +#define my_off_t2double(A) ((double) (my_off_t) (A)) #else inline double ulonglong2double(ulonglong value) diff --git a/include/my_global.h b/include/my_global.h index 59e0c43f18d..349ac8ac82e 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -571,8 +571,8 @@ extern double my_atof(const char*); #define closesocket(A) close(A) #endif #ifndef ulonglong2double -#define ulonglong2double(A) ((double) (A)) -#define my_off_t2double(A) ((double) (A)) +#define ulonglong2double(A) ((double) (ulonglong) (A)) +#define my_off_t2double(A) ((double) (my_off_t) (A)) #endif #endif From 75454930dc81d5e872055747eddb491ec6c47baa Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Mon, 27 Oct 2003 15:14:03 +0100 Subject: [PATCH 32/49] fixes for max_user_connections (connections are now counted even if max_user_connections is not set - that is no limit - so that when max_user_connections is set (with SET) old connections are also taken into account mutexes are added where appropriate --- sql/sql_parse.cc | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e068c309e21..ebcfc2bdec1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -156,7 +156,7 @@ static int get_or_create_user_conn(THD *thd, const char *user, uc->user_len= user_len; uc->host=uc->user + uc->user_len + 1; uc->len = temp_len; - uc->connections = 1; + uc->connections = 0; uc->questions=uc->updates=uc->conn_per_hour=0; uc->user_resources=*mqh; if (max_user_connections && mqh->connections > max_user_connections) @@ -171,6 +171,7 @@ static int get_or_create_user_conn(THD *thd, const char *user, } } thd->user_connect=uc; + uc->connections++; end: (void) pthread_mutex_unlock(&LOCK_user_conn); return return_val; @@ -255,8 +256,8 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, if ((ur.questions || ur.updates || ur.connections || max_user_connections) && get_or_create_user_conn(thd,user,thd->host_or_ip,&ur)) return -1; - if (thd->user_connect && ((thd->user_connect->user_resources.connections) || - max_user_connections) && + if (thd->user_connect && (thd->user_connect->user_resources.connections || + max_user_connections) && check_for_max_user_connections(thd->user_connect)) return -1; if (db && db[0]) @@ -303,16 +304,17 @@ static int check_for_max_user_connections(USER_CONN *uc) int error=0; DBUG_ENTER("check_for_max_user_connections"); + (void) pthread_mutex_lock(&LOCK_user_conn); if (max_user_connections && - (max_user_connections < (uint) uc->connections)) + max_user_connections <= uc->connections) { net_printf(&(current_thd->net),ER_TOO_MANY_USER_CONNECTIONS, uc->user); error=1; + uc->connections--; goto end; } - uc->connections++; if (uc->user_resources.connections && - uc->conn_per_hour++ >= uc->user_resources.connections) + uc->user_resources.connections <= uc->conn_per_hour) { net_printf(¤t_thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_connections", @@ -320,7 +322,9 @@ static int check_for_max_user_connections(USER_CONN *uc) error=1; goto end; } + uc->conn_per_hour++; end: + (void) pthread_mutex_unlock(&LOCK_user_conn); DBUG_RETURN(error); } @@ -328,13 +332,14 @@ end: static void decrease_user_connections(USER_CONN *uc) { DBUG_ENTER("decrease_user_connections"); - if ((uc->connections && !--uc->connections) && !mqh_used) + (void) pthread_mutex_lock(&LOCK_user_conn); + DBUG_ASSERT(uc->connections); + if (!--uc->connections && !mqh_used) { /* Last connection for user; Delete it */ - (void) pthread_mutex_lock(&LOCK_user_conn); (void) hash_delete(&hash_user_connections,(byte*) uc); - (void) pthread_mutex_unlock(&LOCK_user_conn); } + (void) pthread_mutex_unlock(&LOCK_user_conn); DBUG_VOID_RETURN; } @@ -1026,7 +1031,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->priv_user=save_priv_user; break; } - if (max_connections && save_uc) + if (save_uc) decrease_user_connections(save_uc); x_free((gptr) save_db); x_free((gptr) save_user); From de6cc5f0189d21f624e5d9be4e9a871da183e28c Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Tue, 28 Oct 2003 15:55:18 +0200 Subject: [PATCH 33/49] row0sel.c: If innodb_force_recovery >= 5, do not try to fetch an old version of a clustered index record: this reduces crashes when dumping tables from a corrupt database --- innobase/row/row0sel.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 482f82b02ba..f02fbeeb8fd 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -3222,8 +3222,14 @@ rec_loop: latest version of the record */ } else if (index == clust_index) { - - if (!lock_clust_rec_cons_read_sees(rec, index, + + /* Fetch a previous version of the row if the current + one is not visible in the snapshot; if we have a very + high force recovery level set, we try to avoid crashes + by skipping this lookup */ + + if (srv_force_recovery < 5 + && !lock_clust_rec_cons_read_sees(rec, index, trx->read_view)) { err = row_sel_build_prev_vers_for_mysql( From d1572484bb8f5961dd1fa13920b60aa4dd98417a Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Tue, 28 Oct 2003 18:36:41 +0200 Subject: [PATCH 34/49] Fix for problem of installing MySQL as a service with mysql --install mysql --defualts-file=path-to-file (Bug #1643) --- include/mysql_com.h | 2 +- sql/mysqld.cc | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/include/mysql_com.h b/include/mysql_com.h index 6daf26bc2ac..27307b690b9 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -31,7 +31,7 @@ #if defined(__WIN__) && !defined( _CUSTOMCONFIG_) #define MYSQL_NAMEDPIPE "MySQL" -#define MYSQL_SERVICENAME "MySql" +#define MYSQL_SERVICENAME "mysqld" #endif /* __WIN__ */ enum enum_server_command { diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 811984e50b4..5073f8e1c40 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1958,7 +1958,7 @@ extern "C" pthread_handler_decl(handle_shutdown,arg) #endif -const char *load_default_groups[]= { "mysqld","server",MYSQL_BASE_VERSION,0 }; +const char *load_default_groups[]= { "mysqld","server",MYSQL_BASE_VERSION,0,0}; bool open_log(MYSQL_LOG *log, const char *hostname, const char *opt_name, const char *extension, @@ -2561,7 +2561,7 @@ default_service_handling(char **argv, const char *extra_opt) { char path_and_service[FN_REFLEN+FN_REFLEN+32], *pos, *end; - end= path_and_service + sizeof(path_and_service)-1; + end= path_and_service + sizeof(path_and_service)-3; /* We have to quote filename if it contains spaces */ pos= add_quoted_string(path_and_service, file_path, end); @@ -2571,7 +2571,9 @@ default_service_handling(char **argv, *pos++= ' '; pos= add_quoted_string(pos, extra_opt, end); } - *pos= 0; // Ensure end null + /* We must have servicename last */ + *pos++= ' '; + strmake(pos, servicename, (uint) (end+2 - pos)); if (Service.got_service_option(argv, "install")) { @@ -2616,7 +2618,7 @@ int main(int argc, char **argv) if (Service.IsService(argv[1])) { /* start an optional service */ - load_default_groups[0]= argv[1]; + load_default_groups[3]= argv[1]; start_mode= 1; Service.Init(argv[1], mysql_service); return 0; @@ -2624,8 +2626,7 @@ int main(int argc, char **argv) } else if (argc == 3) /* install or remove any optional service */ { - if (!default_service_handling(argv, argv[2], argv[2], file_path, - argv[2])) + if (!default_service_handling(argv, argv[2], argv[2], file_path, "")) return 0; if (Service.IsService(argv[2])) { @@ -2637,6 +2638,7 @@ int main(int argc, char **argv) opt_argc= 2; // Skip service-name opt_argv=argv; start_mode= 1; + load_default_groups[3]= argv[2]; Service.Init(argv[2], mysql_service); return 0; } From 1d617f18887c86183027c802945ef27060b71a0a Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Wed, 29 Oct 2003 08:33:31 +0100 Subject: [PATCH 35/49] followup to max_user_connections fix, keep the count more accurate --- sql/sql_parse.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ebcfc2bdec1..e63e85e99c6 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -303,14 +303,13 @@ static int check_for_max_user_connections(USER_CONN *uc) { int error=0; DBUG_ENTER("check_for_max_user_connections"); - + (void) pthread_mutex_lock(&LOCK_user_conn); if (max_user_connections && - max_user_connections <= uc->connections) + max_user_connections < uc->connections) { net_printf(&(current_thd->net),ER_TOO_MANY_USER_CONNECTIONS, uc->user); error=1; - uc->connections--; goto end; } if (uc->user_resources.connections && @@ -324,6 +323,8 @@ static int check_for_max_user_connections(USER_CONN *uc) } uc->conn_per_hour++; end: + if (error) + uc->connections--; // no need for decrease_user_connections() here (void) pthread_mutex_unlock(&LOCK_user_conn); DBUG_RETURN(error); } From 59d0872aa05e8b02e78db16b1afbe2837af333cf Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Wed, 29 Oct 2003 14:23:35 +0100 Subject: [PATCH 36/49] Fix for BUG#1686 "If 2 master threads with same-name temp table, slave makes bad binlog" and (two birds with one stone) for BUG#1240 "slave of slave breaks when STOP SLAVE was issud on parent slave and temp tables". Here is the design change: in a slave running with --log-slave-updates, events are now logged with the thread id they had on the master. So no more id conflicts between master threads, but introduces id conflicts between one master thread and one normal client thread connected to the slave. This is solved by storing the server id in the temp table's name. New test which requires mysql-test-run to be run with --manager, otherwise it will be skipped. Undoing a Monty's change (hum, a chill runs down my spine ;) which was "Cleanup temporary tables when slave ends" in ChangeSet 1.1572.1.1. --- mysql-test/mysql-test-run.sh | 2 +- mysql-test/r/rpl_chain_temp_table.result | 30 ++++++++ mysql-test/t/rpl_chain_temp_table.test | 89 ++++++++++++++++++++++++ sql/log_event.cc | 56 ++++++++++++--- sql/log_event.h | 8 +++ sql/slave.cc | 2 - sql/sql_base.cc | 25 +++++-- sql/unireg.h | 2 +- 8 files changed, 197 insertions(+), 17 deletions(-) create mode 100644 mysql-test/r/rpl_chain_temp_table.result create mode 100644 mysql-test/t/rpl_chain_temp_table.test diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 6cba5eecddd..d155c02c652 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -1161,7 +1161,7 @@ run_testcase () echo $tname > $CURRENT_TEST SKIP_SLAVE=`$EXPR \( $tname : rpl \) = 0` if [ $USE_MANAGER = 1 ] ; then - many_slaves=`$EXPR \( $tname : rpl_failsafe \) != 0` + many_slaves=`$EXPR \( \( $tname : rpl_failsafe \) != 0 \) \| \( \( $tname : rpl_chain_temp_table \) != 0 \)` fi if [ -n "$SKIP_TEST" ] ; then diff --git a/mysql-test/r/rpl_chain_temp_table.result b/mysql-test/r/rpl_chain_temp_table.result new file mode 100644 index 00000000000..5ece80565c7 --- /dev/null +++ b/mysql-test/r/rpl_chain_temp_table.result @@ -0,0 +1,30 @@ +slave stop; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +slave start; +reset master; +change master to master_host='127.0.0.1',master_port=9307, master_user='root'; +start slave; +create temporary table t1 (a int); +create temporary table t1 (a int); +show status like 'slave_open_temp_tables'; +Variable_name Value +Slave_open_temp_tables 2 +create temporary table t1 (a int); +create temporary table t1 (a int); +show status like 'slave_open_temp_tables'; +Variable_name Value +Slave_open_temp_tables 4 +stop slave; +insert into t1 values(1); +create table t2 as select * from t1; +start slave; +show status like 'slave_open_temp_tables'; +Variable_name Value +Slave_open_temp_tables 4 +select * from t2; +a +1 +drop table t2; diff --git a/mysql-test/t/rpl_chain_temp_table.test b/mysql-test/t/rpl_chain_temp_table.test new file mode 100644 index 00000000000..65701d8a078 --- /dev/null +++ b/mysql-test/t/rpl_chain_temp_table.test @@ -0,0 +1,89 @@ + # This test makes some assumptions about values of thread ids, which should be +# true if the servers have been restarted for this test. So we want to +# stop/restart servers. Note that if assumptions are wrong, the test will not +# fail; it will just fail to test the error-prone scenario. +# Using the manager is the only way to have more than one slave server. + +require_manager; +server_stop master; +server_start master; +server_stop slave; +server_start slave; +# no need for slave_sec (no assumptions on thread ids for this server). + +source include/master-slave.inc; +connect (slave_sec,localhost,root,,test,0,slave.sock-1); +connection master; +save_master_pos; +connection slave; +sync_with_master; +reset master; +save_master_pos; +connection slave_sec; +eval change master to master_host='127.0.0.1',master_port=$SLAVE_MYPORT, master_user='root'; +start slave; +sync_with_master; + +# :P now we have a chain ready-to-test. + +connection master; +create temporary table t1 (a int); +save_master_pos; +connection slave; +sync_with_master; +connection master1; +create temporary table t1 (a int); +save_master_pos; +connection slave; +sync_with_master; +save_master_pos; + +# First test: + +connection slave_sec; +# Before BUG#1686 ("If 2 master threads with same-name temp table, slave makes +# bad binlog") was fixed, sync_with_master failed +sync_with_master; +show status like 'slave_open_temp_tables'; + +# 'master' and 'master1' usually have thread id 2-3 or 3-4. +# 'slave' and 'slave1' usually have thread id 2-3. +connection slave; +create temporary table t1 (a int); +connection slave1; +create temporary table t1 (a int); +# So it's likely that in the binlog of slave we get +# server_id=of_master thread_id=3 create temp... +# server_id=of_slave thread_id=3 create temp... +# which would confuse slave-sec unless slave-sec uses server id to distinguish +# between temp tables (here thread id is obviously not enough to distinguish). + +save_master_pos; + +# Second test: + +connection slave_sec; +# If we did not use the server id to distinguish between temp tables, +# sync_with_master would fail +sync_with_master; +show status like 'slave_open_temp_tables'; + +# Third test (BUG#1240 "slave of slave breaks when STOP SLAVE was issud on +# parent slave and temp tables"). +stop slave; +connection slave; +insert into t1 values(1); +create table t2 as select * from t1; +save_master_pos; +connection slave_sec; +start slave; +sync_with_master; +show status like 'slave_open_temp_tables'; +select * from t2; + +# clean up +connection slave; +drop table t2; +save_master_pos; +connection slave_sec; +sync_with_master; diff --git a/sql/log_event.cc b/sql/log_event.cc index 699d1ff866d..36d2d33ade6 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -834,8 +834,11 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length, bool using_trans) :Log_event(thd_arg, 0, using_trans), data_buf(0), query(query_arg), db(thd_arg->db), q_len((uint32) query_length), - error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno), - thread_id(thd_arg->thread_id) + error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno), + thread_id(thd_arg->thread_id), + /* save the original thread id; we already know the server id */ + slave_proxy_id(thd_arg->slave_proxy_id) + { time_t end_time; time(&end_time); @@ -918,7 +921,42 @@ int Query_log_event::write_data(IO_CACHE* file) return -1; char buf[QUERY_HEADER_LEN]; - int4store(buf + Q_THREAD_ID_OFFSET, thread_id); + /* + We want to store the thread id: + (- as an information for the user when he reads the binlog) + - if the query uses temporary table: for the slave SQL thread to know to + which master connection the temp table belongs. + Now imagine we (write_data()) are called by the slave SQL thread (we are + logging a query executed by this thread; the slave runs with + --log-slave-updates). Then this query will be logged with + thread_id=the_thread_id_of_the_SQL_thread. Imagine that 2 temp tables of the + same name were created simultaneously on the master (in the master binlog + you have + CREATE TEMPORARY TABLE t; (thread 1) + CREATE TEMPORARY TABLE t; (thread 2) + ...) + then in the slave's binlog there will be + CREATE TEMPORARY TABLE t; (thread_id_of_the_slave_SQL_thread) + CREATE TEMPORARY TABLE t; (thread_id_of_the_slave_SQL_thread) + which is bad (same thread id!). + To avoid this, we log the thread's thread id EXCEPT for the SQL slave thread + for which we log the original (master's) thread id. + Now this moves the bug: what happens if the thread id on the master was 10 + and when the slave replicates the query, a connection number 10 is opened by + a normal client on the slave, and updates a temp table of the same name? We + get a problem again. To avoid this, in the handling of temp tables + (sql_base.cc) we use thread_id AND server_id. + TODO when this is merged into 4.1: in 4.1, slave_proxy_id has been renamed + to pseudo_thread_id and is a session variable: that's to make mysqlbinlog + work with temp tables. We probably need to introduce + SET PSEUDO_SERVER_ID + for mysqlbinlog in 4.1. mysqlbinlog would print: + SET PSEUDO_SERVER_ID= + SET PSEUDO_THREAD_ID= + for each query using temp tables. + */ + int4store(buf + Q_THREAD_ID_OFFSET, (slave_proxy_id ? slave_proxy_id : + thread_id)); int4store(buf + Q_EXEC_TIME_OFFSET, exec_time); buf[Q_DB_LEN_OFFSET] = (char) db_len; int2store(buf + Q_ERR_CODE_OFFSET, error_code); @@ -1019,7 +1057,8 @@ void Rand_log_event::print(FILE* file, bool short_form, char* last_db) int Load_log_event::write_data_header(IO_CACHE* file) { char buf[LOAD_HEADER_LEN]; - int4store(buf + L_THREAD_ID_OFFSET, thread_id); + int4store(buf + L_THREAD_ID_OFFSET, (slave_proxy_id ? slave_proxy_id : + thread_id)); int4store(buf + L_EXEC_TIME_OFFSET, exec_time); int4store(buf + L_SKIP_LINES_OFFSET, skip_lines); buf[L_TBL_LEN_OFFSET] = (char)table_name_len; @@ -1143,10 +1182,11 @@ Load_log_event::Load_log_event(THD* thd_arg, sql_exchange* ex, enum enum_duplicates handle_dup, bool using_trans) :Log_event(thd_arg, 0, using_trans),thread_id(thd_arg->thread_id), - num_fields(0),fields(0), - field_lens(0),field_block_len(0), - table_name(table_name_arg ? table_name_arg : ""), - db(db_arg), fname(ex->file_name) + slave_proxy_id(thd_arg->slave_proxy_id), + num_fields(0),fields(0), + field_lens(0),field_block_len(0), + table_name(table_name_arg ? table_name_arg : ""), + db(db_arg), fname(ex->file_name) { time_t end_time; time(&end_time); diff --git a/sql/log_event.h b/sql/log_event.h index 227c0243b9c..2e6b7373dc2 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -320,6 +320,13 @@ public: uint32 db_len; uint16 error_code; ulong thread_id; + /* + For events created by Query_log_event::exec_event (and + Load_log_event::exec_event()) we need the *original* thread id, to be able + to log the event with the original (=master's) thread id (fix for + BUG#1686). + */ + ulong slave_proxy_id; #ifndef MYSQL_CLIENT Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length, @@ -390,6 +397,7 @@ protected: public: ulong thread_id; + ulong slave_proxy_id; uint32 table_name_len; uint32 db_len; uint32 fname_len; diff --git a/sql/slave.cc b/sql/slave.cc index b679ac2f6b8..90b0cc74fd8 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2719,8 +2719,6 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ RPL_LOG_NAME, llstr(rli->master_log_pos,llbuff)); err: - /* Free temporary tables etc */ - thd->cleanup(); VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query = thd->db = 0; // extra safety VOID(pthread_mutex_unlock(&LOCK_thread_count)); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 1010378825f..47529b90b67 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -589,6 +589,8 @@ TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name) uint key_length= (uint) (strmov(strmov(key,db)+1,table_name)-key)+1; TABLE *table,**prev; + int4store(key+key_length,thd->server_id); + key_length += 4; int4store(key+key_length,thd->slave_proxy_id); key_length += 4; @@ -617,18 +619,27 @@ bool close_temporary_table(THD *thd, const char *db, const char *table_name) return 0; } +/* + Used by ALTER TABLE when the table is a temporary one. It changes something + only if the ALTER contained a RENAME clause (otherwise, table_name is the old + name). + Prepares a table cache key, which is the concatenation of db, table_name and + thd->slave_proxy_id, separated by '\0'. +*/ bool rename_temporary_table(THD* thd, TABLE *table, const char *db, const char *table_name) { char *key; if (!(key=(char*) alloc_root(&table->mem_root, (uint) strlen(db)+ - (uint) strlen(table_name)+6))) + (uint) strlen(table_name)+6+4))) return 1; /* purecov: inspected */ table->key_length=(uint) (strmov((table->real_name=strmov(table->table_cache_key=key, db)+1), table_name) - table->table_cache_key)+1; + int4store(key+table->key_length,thd->server_id); + table->key_length += 4; int4store(key+table->key_length,thd->slave_proxy_id); table->key_length += 4; return 0; @@ -783,12 +794,13 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, if (thd->killed) DBUG_RETURN(0); key_length= (uint) (strmov(strmov(key,db)+1,table_name)-key)+1; - int4store(key + key_length, thd->slave_proxy_id); + int4store(key + key_length, thd->server_id); + int4store(key + key_length + 4, thd->slave_proxy_id); for (table=thd->temporary_tables; table ; table=table->next) { - if (table->key_length == key_length+4 && - !memcmp(table->table_cache_key,key,key_length+4)) + if (table->key_length == key_length+8 && + !memcmp(table->table_cache_key,key,key_length+8)) { if (table->query_id == thd->query_id) { @@ -1596,7 +1608,7 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db, total of 6 extra bytes in my_malloc in addition to table/db stuff */ if (!(tmp_table=(TABLE*) my_malloc(sizeof(*tmp_table)+(uint) strlen(db)+ - (uint) strlen(table_name)+6, + (uint) strlen(table_name)+6+4, MYF(MY_WME)))) DBUG_RETURN(0); /* purecov: inspected */ @@ -1618,6 +1630,9 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db, strmov(tmp_table->table_cache_key,db) +1), table_name) - tmp_table->table_cache_key)+1; + int4store(tmp_table->table_cache_key + tmp_table->key_length, + thd->server_id); + tmp_table->key_length += 4; int4store(tmp_table->table_cache_key + tmp_table->key_length, thd->slave_proxy_id); tmp_table->key_length += 4; diff --git a/sql/unireg.h b/sql/unireg.h index f2cace51fa7..37157311e15 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -43,7 +43,7 @@ #define ERRMAPP 1 /* Errormap f|r my_error */ #define LIBLEN FN_REFLEN-FN_LEN /* Max l{ngd p} dev */ -#define MAX_DBKEY_LENGTH (FN_LEN*2+6) /* extra 4 bytes for slave tmp +#define MAX_DBKEY_LENGTH (FN_LEN*2+1+1+4+4) /* extra 4+4 bytes for slave tmp * tables */ #define MAX_FIELD_NAME 34 /* Max colum name length +2 */ #define MAX_SYS_VAR_LENGTH 32 From bc00893d165a8881160011169a25754f10cdb06d Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Thu, 30 Oct 2003 01:01:53 +0200 Subject: [PATCH 37/49] Change back service name to MySQL Don't add service name to read config file segments if it's "MySQL" Fixed possible memory leak when CHANGE USER failed. --- include/mysql_com.h | 2 +- myisam/myisamchk.c | 6 ++++-- sql/mysqld.cc | 12 +++++++++--- sql/sql_parse.cc | 12 ++++++++---- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/include/mysql_com.h b/include/mysql_com.h index 27307b690b9..a874034ba46 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -31,7 +31,7 @@ #if defined(__WIN__) && !defined( _CUSTOMCONFIG_) #define MYSQL_NAMEDPIPE "MySQL" -#define MYSQL_SERVICENAME "mysqld" +#define MYSQL_SERVICENAME "MySQL" #endif /* __WIN__ */ enum enum_server_command { diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index b7627fc59fd..f1deda41f8b 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -401,7 +401,9 @@ static void usage(void) Change the character set used by the index\n\ -q, --quick Faster repair by not modifying the data file.\n\ One can give a second '-q' to force myisamchk to\n\ - modify the original datafile in case of duplicate keys\n\ + modify the original datafile in case of duplicate keys.\n\ + NOTE: Tables where the data file is currupted can't be\n\ + fixed with this option.\n\ -u, --unpack Unpack file packed with myisampack.\n\ "); @@ -1094,7 +1096,7 @@ end2: filename)); if (param->testflag & T_REP_ANY) VOID(fprintf(stderr, - "Try fixing it by using the --safe-recover (-o) or the --force (-f) option\n")); + "Try fixing it by using the --safe-recover (-o), the --force (-f) option or by not using the --quick (-q) flag\n")); } else if (!(param->error_printed & 2) && !(param->testflag & T_FORCE_CREATE)) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 5073f8e1c40..cdcf13ca7bf 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2615,10 +2615,16 @@ int main(int argc, char **argv) if (!default_service_handling(argv, MYSQL_SERVICENAME, MYSQL_SERVICENAME, file_path, "")) return 0; - if (Service.IsService(argv[1])) + if (Service.IsService(argv[1])) /* Start an optional service */ { - /* start an optional service */ - load_default_groups[3]= argv[1]; + /* + Only add the service name to the groups read from the config file + if it's not "MySQL". (The default service name should be 'mysqld' + but we started a bad tradition by calling it MySQL from the start + and we are now stuck with it. + */ + if (my_strcasecmp(argv[1],"mysql")) + load_default_groups[3]= argv[1]; start_mode= 1; Service.Init(argv[1], mysql_service); return 0; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e63e85e99c6..0789a1768d1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1013,14 +1013,17 @@ bool dispatch_command(enum enum_server_command command, THD *thd, char *save_user= thd->user; char *save_priv_user= thd->priv_user; char *save_db= thd->db; - thd->user=0; - USER_CONN *save_uc= thd->user_connect; + USER_CONN *save_user_connect= thd->user_connect; if ((uint) ((uchar*) db - net->read_pos) > packet_length) { // Check if protocol is ok send_error(net, ER_UNKNOWN_COM_ERROR); break; } + + /* Clear variables that are allocated */ + thd->user= 0; + thd->user_connect= 0; if (check_user(thd, COM_CHANGE_USER, user, passwd, db, 0)) { // Restore old user x_free(thd->user); @@ -1030,10 +1033,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->db_length=save_db_length; thd->user=save_user; thd->priv_user=save_priv_user; + thd->user_connect= save_user_connect; break; } - if (save_uc) - decrease_user_connections(save_uc); + if (save_user_connect) + decrease_user_connections(save_user_connect); x_free((gptr) save_db); x_free((gptr) save_user); break; From a4fff85de574664f54cf2d1be190d65faa5b220a Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Thu, 30 Oct 2003 01:20:38 +0200 Subject: [PATCH 38/49] Safety fix for adding service name to search config groups --- sql/mysqld.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index cdcf13ca7bf..e5ddbfe7a33 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2644,7 +2644,8 @@ int main(int argc, char **argv) opt_argc= 2; // Skip service-name opt_argv=argv; start_mode= 1; - load_default_groups[3]= argv[2]; + if (my_strcasecmp(argv[2],"mysql")) + load_default_groups[3]= argv[2]; Service.Init(argv[2], mysql_service); return 0; } From af02e27e3f0d9b3a84d9773864675716b0e8c23a Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Thu, 30 Oct 2003 12:25:15 +0300 Subject: [PATCH 39/49] fix for bug #1634 '"operator new" in my_new wastes memory' --- BitKeeper/etc/logging_ok | 1 + mysys/my_new.cc | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 4c1777f1434..afb9c5cff5c 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -48,6 +48,7 @@ jcole@sarvik.tfr.cafe.ee jcole@tetra.spaceapes.com jorge@linux.jorge.mysql.com kaj@work.mysql.com +konstantin@mysql.com kostja@oak.local lenz@kallisto.mysql.com lenz@mysql.com diff --git a/mysys/my_new.cc b/mysys/my_new.cc index 5cc291af9aa..5f2da90bbd1 100644 --- a/mysys/my_new.cc +++ b/mysys/my_new.cc @@ -25,12 +25,12 @@ void *operator new (size_t sz) { - return (void *) malloc (sz ? sz+1 : sz); + return (void *) malloc (sz ? sz : 1); } void *operator new[] (size_t sz) { - return (void *) malloc (sz ? sz+1 : sz); + return (void *) malloc (sz ? sz : 1); } void operator delete (void *ptr) From 80793657b41c9b01052de8f967e8b15804837b05 Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Thu, 30 Oct 2003 16:12:21 +0100 Subject: [PATCH 40/49] Fix to be able to run mysql-test-run --manager --valgrind (without this fix, the manager fails to start mysqld and the tests hang). --- mysql-test/mysql-test-run.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index d155c02c652..cd409e1ace5 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -336,7 +336,13 @@ while test $# -gt 0; do EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --gdb" ;; --valgrind) - VALGRIND="valgrind --alignment=8 --leak-check=yes --num-callers=16" + VALGRIND=`which valgrind` # this will print an error if not found + # Give good warning to the user and stop + if [ -z "$VALGRIND" ] ; then + $ECHO "You need to have the 'valgrind' program in your PATH to run mysql-test-run with option --valgrind. Valgrind's home page is http://developer.kde.org/~sewardj ." + exit 1 + fi + VALGRIND="$VALGRIND --alignment=8 --leak-check=yes --num-callers=16" EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-safemalloc --skip-bdb" EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-safemalloc --skip-bdb" SLEEP_TIME_AFTER_RESTART=10 From ca34cf30bdef0a54af4c3c61e4cd93543d86762f Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Thu, 30 Oct 2003 21:30:20 +0300 Subject: [PATCH 41/49] comments about designation of thd->where and thd->proc_info added --- sql/sql_class.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sql/sql_class.h b/sql/sql_class.h index 27258c025d8..58543a3d230 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -379,7 +379,11 @@ public: char priv_host[MAX_HOSTNAME]; /* remote (peer) port */ uint16 peer_port; - /* Points to info-string that will show in SHOW PROCESSLIST */ + /* + Points to info-string that we show in SHOW PROCESSLIST + You are supposed to update thd->proc_info only if you have coded + a time-consuming piece that MySQL can get stuck in for a long time. + */ const char *proc_info; /* points to host if host is available, otherwise points to ip */ const char *host_or_ip; @@ -408,6 +412,11 @@ public: enum enum_server_command command; uint32 server_id; uint32 file_id; // for LOAD DATA INFILE + /* + Used in error messages to tell user in what part of MySQL we found an + error. E. g. when where= "having clause", if fix_fields() fails, user + will know that the error was in having clause. + */ const char *where; time_t start_time,time_after_lock,user_time; time_t connect_time,thr_create_time; // track down slow pthread_create From f9015d5ac80a0e5cb70b810efc1009834ae72324 Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Fri, 31 Oct 2003 17:03:08 +0300 Subject: [PATCH 42/49] thd->query assignment moved out of lock scope --- sql/log_event.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index 36d2d33ade6..4f241c6b992 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1826,8 +1826,8 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) thd->set_time((time_t)when); thd->current_tablenr = 0; thd->query_length= q_len; + thd->query= (char *) query; VOID(pthread_mutex_lock(&LOCK_thread_count)); - thd->query = (char*)query; thd->query_id = query_id++; VOID(pthread_mutex_unlock(&LOCK_thread_count)); thd->query_error = 0; // clear error From 975177fdb2406cd3191a1e60f25a2ba5a1fb7324 Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Fri, 31 Oct 2003 17:13:42 +0300 Subject: [PATCH 43/49] minor fix in rm --- libmysqld/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index d831d2a7a5a..54bfd6503d4 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -89,10 +89,10 @@ libmysqld.a: libmysqld_int.a $(INC_LIB) ar x $$file; \ for obj in *.o ; do mv $$obj $${bfile}_$$obj ; done ; \ ar q ../libmysqld_int2.a *.o ; \ - rm *.o ; \ + rm -f *.o ; \ done mv libmysqld_int2.a libmysqld.a - rm tmp/* + rm -f tmp/* $(RANLIB) libmysqld.a ## XXX: any time the client interface changes, we'll need to bump From c1f7f3396005d40470a4ae069c57aa48ad645ac3 Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Fri, 31 Oct 2003 23:20:23 +0100 Subject: [PATCH 44/49] 4 small items in this: - when we don't have in_addr_t, use uint32. - a forgotten initialization of slave_proxy_id in sql/log_event.cc (was not really "forgot", was "we needn't init it there", but there was one case where we needed...). - made slave_proxy_id always meaningful in THD and Log_event, so we can rely more on it (no need to test if it's meaningful). THD::slave_proxy_id is equal to THD::thread_id except for the slave SQL thread. - clean up the slave's temporary table (i.e. free their memory) when slave server shuts down. --- extra/resolveip.c | 4 ---- include/my_net.h | 9 +++++++++ libmysql/libmysql.c | 2 +- libmysql/manager.c | 2 +- mysql-test/t/rpl_chain_temp_table.test | 10 ++++++++++ sql/log_event.cc | 10 ++++------ sql/mini_client.cc | 2 +- sql/slave.cc | 21 +++++++++++++++++++++ sql/slave.h | 1 + sql/sql_class.cc | 5 +++++ 10 files changed, 53 insertions(+), 13 deletions(-) diff --git a/extra/resolveip.c b/extra/resolveip.c index 6d05152e20b..d3caa9e1d45 100644 --- a/extra/resolveip.c +++ b/extra/resolveip.c @@ -36,10 +36,6 @@ extern int h_errno; #endif -#ifndef HAVE_IN_ADDR_T -#define in_addr_t ulong -#endif - static my_bool silent; static struct my_option my_long_options[] = diff --git a/include/my_net.h b/include/my_net.h index 28d862d8528..7b42afa1f3a 100644 --- a/include/my_net.h +++ b/include/my_net.h @@ -63,6 +63,15 @@ C_MODE_START #define O_NONBLOCK 1 /* For emulation of fcntl() */ #endif +/* + On OSes which don't have the in_addr_t, we guess that using uint32 is the best + possible choice. We guess this from the fact that on HP-UX64bit & FreeBSD64bit + & Solaris64bit, in_addr_t is equivalent to uint32. And on Linux32bit too. +*/ +#ifndef HAVE_IN_ADDR_T +#define in_addr_t uint32 +#endif + /* Thread safe or portable version of some functions */ void my_inet_ntoa(struct in_addr in, char *buf); diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index d8966b30fb9..5d809adf36a 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1623,7 +1623,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, char buff[NAME_LEN+USERNAME_LENGTH+100],charset_name_buff[16]; char *end,*host_info,*charset_name; my_socket sock; - uint32 ip_addr; + in_addr_t ip_addr; struct sockaddr_in sock_addr; ulong pkt_length; NET *net= &mysql->net; diff --git a/libmysql/manager.c b/libmysql/manager.c index d4bd8d5520b..1a4ac718ef9 100644 --- a/libmysql/manager.c +++ b/libmysql/manager.c @@ -90,7 +90,7 @@ MYSQL_MANAGER* STDCALL mysql_manager_connect(MYSQL_MANAGER* con, { my_socket sock; struct sockaddr_in sock_addr; - uint32 ip_addr; + in_addr_t ip_addr; char msg_buf[MAX_MYSQL_MANAGER_MSG]; int msg_len; Vio* vio; diff --git a/mysql-test/t/rpl_chain_temp_table.test b/mysql-test/t/rpl_chain_temp_table.test index 65701d8a078..007b018e9d8 100644 --- a/mysql-test/t/rpl_chain_temp_table.test +++ b/mysql-test/t/rpl_chain_temp_table.test @@ -3,6 +3,7 @@ # stop/restart servers. Note that if assumptions are wrong, the test will not # fail; it will just fail to test the error-prone scenario. # Using the manager is the only way to have more than one slave server. +# So you must run this test with --manager. require_manager; server_stop master; @@ -87,3 +88,12 @@ drop table t2; save_master_pos; connection slave_sec; sync_with_master; + +# On purpose, we don't delete the temporary tables explicitely. +# So temp tables remain on slave (remember they are not deleted when the slave +# SQL thread terminates). If you run this test with +# --valgrind --valgrind-options=--show-reachable=yes +# you will see if they get cleaned up at slave's shutdown (that is, if the +# memory they use is freed (it should) by mysqld before it terminates). +# If they wouldn't be cleaned up, you would see some "still reachable" blocks in +# Valgrind. diff --git a/sql/log_event.cc b/sql/log_event.cc index 4f241c6b992..d17c94a2b44 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -874,7 +874,7 @@ Query_log_event::Query_log_event(const char* buf, int event_len, return; memcpy(data_buf, buf + Q_DATA_OFFSET, data_len); - thread_id = uint4korr(buf + Q_THREAD_ID_OFFSET); + slave_proxy_id= thread_id= uint4korr(buf + Q_THREAD_ID_OFFSET); db = data_buf; db_len = (uint)buf[Q_DB_LEN_OFFSET]; query=data_buf + db_len + 1; @@ -955,8 +955,7 @@ int Query_log_event::write_data(IO_CACHE* file) SET PSEUDO_THREAD_ID= for each query using temp tables. */ - int4store(buf + Q_THREAD_ID_OFFSET, (slave_proxy_id ? slave_proxy_id : - thread_id)); + int4store(buf + Q_THREAD_ID_OFFSET, slave_proxy_id); int4store(buf + Q_EXEC_TIME_OFFSET, exec_time); buf[Q_DB_LEN_OFFSET] = (char) db_len; int2store(buf + Q_ERR_CODE_OFFSET, error_code); @@ -1057,8 +1056,7 @@ void Rand_log_event::print(FILE* file, bool short_form, char* last_db) int Load_log_event::write_data_header(IO_CACHE* file) { char buf[LOAD_HEADER_LEN]; - int4store(buf + L_THREAD_ID_OFFSET, (slave_proxy_id ? slave_proxy_id : - thread_id)); + int4store(buf + L_THREAD_ID_OFFSET, slave_proxy_id); int4store(buf + L_EXEC_TIME_OFFSET, exec_time); int4store(buf + L_SKIP_LINES_OFFSET, skip_lines); buf[L_TBL_LEN_OFFSET] = (char)table_name_len; @@ -1276,7 +1274,7 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len, char* buf_end = (char*)buf + event_len; uint header_len= old_format ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN; const char* data_head = buf + header_len; - thread_id = uint4korr(data_head + L_THREAD_ID_OFFSET); + slave_proxy_id= thread_id= uint4korr(data_head + L_THREAD_ID_OFFSET); exec_time = uint4korr(data_head + L_EXEC_TIME_OFFSET); skip_lines = uint4korr(data_head + L_SKIP_LINES_OFFSET); table_name_len = (uint)data_head[L_TBL_LEN_OFFSET]; diff --git a/sql/mini_client.cc b/sql/mini_client.cc index f204c38c18c..2de5227a953 100644 --- a/sql/mini_client.cc +++ b/sql/mini_client.cc @@ -547,7 +547,7 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user, { char buff[NAME_LEN+USERNAME_LENGTH+100],*end,*host_info; my_socket sock; - uint32 ip_addr; + in_addr_t ip_addr; struct sockaddr_in sock_addr; ulong pkt_length; NET *net= &mysql->net; diff --git a/sql/slave.cc b/sql/slave.cc index 90b0cc74fd8..da63ca71951 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -324,6 +324,20 @@ void init_slave_skip_errors(const char* arg) } } +void st_relay_log_info::close_temporary_tables() +{ + TABLE *table,*next; + + for (table=save_temporary_tables ; table ; table=next) + { + next=table->next; + /* + Don't ask for disk deletion. For now, anyway they will be deleted when + slave restarts, but it is a better intention to not delete them. + */ + close_temporary(table, 0); + } +} /* We assume we have a run lock on rli and that both slave thread @@ -790,6 +804,7 @@ static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/) void end_slave() { + /* This is called when the server terminates, in close_connections(). */ if (active_mi) { /* @@ -3092,6 +3107,12 @@ void end_relay_log_info(RELAY_LOG_INFO* rli) } rli->inited = 0; rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT); + /* + Delete the slave's temporary tables from memory. + In the future there will be other actions than this, to ensure persistance + of slave's temp tables after shutdown. + */ + rli->close_temporary_tables(); DBUG_VOID_RETURN; } diff --git a/sql/slave.h b/sql/slave.h index 778ddf2ec72..8f7d96b23dd 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -239,6 +239,7 @@ typedef struct st_relay_log_info int wait_for_pos(THD* thd, String* log_name, longlong log_pos, longlong timeout); + void st_relay_log_info::close_temporary_tables(); } RELAY_LOG_INFO; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 132e0d7745f..3ea61da28fc 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -323,6 +323,11 @@ bool THD::store_globals() return 1; mysys_var=my_thread_var; dbug_thread_id=my_thread_id(); + /* + By default 'slave_proxy_id' is 'thread_id'. They may later become different + if this is the slave SQL thread. + */ + slave_proxy_id= thread_id; return 0; } From 4668b54837f3cd0a4ee71b16841c41a6bdc44c06 Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Sun, 2 Nov 2003 15:55:02 +0200 Subject: [PATCH 45/49] Call my_sync() after all data is written to .frm file Added my_sync() to mysys which will do fsync/fdatasync/_commit() on a file. --- BitKeeper/etc/logging_ok | 1 + VC++Files/mysys/mysys.dsp | 4 +++ configure.in | 2 +- include/my_sys.h | 1 + include/mysys_err.h | 3 +- isam/extra.c | 10 +++--- myisam/mi_extra.c | 20 +++--------- myisam/mi_locking.c | 20 +++--------- mysql-test/mysql-test-run.sh | 3 ++ mysys/Makefile.am | 2 +- mysys/errors.c | 8 +++-- mysys/my_symlink.c | 3 +- mysys/my_sync.c | 60 ++++++++++++++++++++++++++++++++++++ mysys/thr_alarm.c | 7 +++++ sql/unireg.cc | 9 ++++-- 15 files changed, 105 insertions(+), 48 deletions(-) create mode 100644 mysys/my_sync.c diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index afb9c5cff5c..f642821747f 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -66,6 +66,7 @@ monty@hundin.mysql.fi monty@mashka.(none) monty@mashka.mysql.fi monty@mishka.mysql.fi +monty@mysql.com monty@narttu. monty@narttu.mysql.fi monty@rescue. diff --git a/VC++Files/mysys/mysys.dsp b/VC++Files/mysys/mysys.dsp index 695e2cb2638..b410d0a7465 100644 --- a/VC++Files/mysys/mysys.dsp +++ b/VC++Files/mysys/mysys.dsp @@ -426,6 +426,10 @@ SOURCE=.\my_symlink2.c # End Source File # Begin Source File +SOURCE=.\my_sync.c +# End Source File +# Begin Source File + SOURCE=.\my_tempnam.c # End Source File # Begin Source File diff --git a/configure.in b/configure.in index 02825ce1424..a4fe75ce896 100644 --- a/configure.in +++ b/configure.in @@ -1817,7 +1817,7 @@ AC_CHECK_FUNCS(alarm bmove \ pthread_attr_create pthread_getsequence_np pthread_attr_setstacksize \ pthread_attr_getstacksize \ pthread_condattr_create rwlock_init pthread_rwlock_rdlock \ - fchmod getpass getpassphrase initgroups mlockall) + fsync fdatasync fchmod getpass getpassphrase initgroups mlockall) CFLAGS="$ORG_CFLAGS" diff --git a/include/my_sys.h b/include/my_sys.h index 7a3d22f3304..df8b9759e5d 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -566,6 +566,7 @@ extern FILE *my_fopen(const char *FileName,int Flags,myf MyFlags); extern FILE *my_fdopen(File Filedes,const char *name, int Flags,myf MyFlags); extern int my_fclose(FILE *fd,myf MyFlags); extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags); +extern int my_sync(File fd, myf my_flags); extern int my_error _VARARGS((int nr,myf MyFlags, ...)); extern int my_printf_error _VARARGS((uint my_err, const char *format, myf MyFlags, ...) diff --git a/include/mysys_err.h b/include/mysys_err.h index a86765c74fd..0ee89e91ee4 100644 --- a/include/mysys_err.h +++ b/include/mysys_err.h @@ -21,7 +21,7 @@ extern "C" { #endif #define GLOB 0 /* Error maps */ -#define GLOBERRS 27 /* Max number of error messages in map's */ +#define GLOBERRS 28 /* Max number of error messages in map's */ #define EE(X) globerrs[ X ] /* Defines to add error to right map */ extern const char * NEAR globerrs[]; /* my_error_messages is here */ @@ -53,6 +53,7 @@ extern const char * NEAR globerrs[]; /* my_error_messages is here */ #define EE_CANT_READLINK 24 #define EE_CANT_SYMLINK 25 #define EE_REALPATH 26 +#define EE_SYNC 27 /* exit codes for all MySQL programs */ diff --git a/isam/extra.c b/isam/extra.c index e2f13532ddf..3bf1dd012ed 100644 --- a/isam/extra.c +++ b/isam/extra.c @@ -250,17 +250,15 @@ int nisam_extra(N_INFO *info, enum ha_extra_function function) pthread_mutex_unlock(&THR_LOCK_isam); break; case HA_EXTRA_FLUSH: -#ifdef __WIN__ if (info->s->not_flushed) { info->s->not_flushed=0; - if (_commit(info->s->kfile)) - error=errno; - if (_commit(info->dfile)) - error=errno; + if (my_sync(info->s->kfile, MYF(0))) + error= my_errno; + if (my_sync(info->dfile, MYF(0))) + error= my_errno; } break; -#endif case HA_EXTRA_NORMAL: /* Theese isn't in use */ case HA_EXTRA_QUICK: case HA_EXTRA_KEY_CACHE: diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c index ef82a6ef61f..1d45fd300e7 100644 --- a/myisam/mi_extra.c +++ b/myisam/mi_extra.c @@ -336,22 +336,10 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) if (share->not_flushed) { share->not_flushed=0; -#if defined(__WIN__) - if (_commit(share->kfile)) - error=errno; - if (_commit(info->dfile)) - error=errno; -#elif defined(HAVE_FDATASYNC) - if (fdatasync(share->kfile)) - error=errno; - if (fdatasync(share->dfile)) - error=errno; -#elif defined(HAVE_FSYNC) - if ( fsync(share->kfile)) - error=errno; - if (fsync(share->dfile)) - error=errno; -#endif + if (my_sync(share->kfile, MYF(0))) + error= my_errno; + if (my_sync(info->dfile, MYF(0))) + error= my_errno; if (error) { share->changed=1; diff --git a/myisam/mi_locking.c b/myisam/mi_locking.c index a707eb294a9..f3bfa8deb90 100644 --- a/myisam/mi_locking.c +++ b/myisam/mi_locking.c @@ -88,22 +88,10 @@ int mi_lock_database(MI_INFO *info, int lock_type) share->changed=0; if (myisam_flush) { -#if defined(__WIN__) - if (_commit(share->kfile)) - error=errno; - if (_commit(info->dfile)) - error=errno; -#elif defined(HAVE_FDATASYNC) - if (fdatasync(share->kfile)) - error=errno; - if (fdatasync(share->dfile)) - error=errno; -#elif defined(HAVE_FSYNC) - if (fsync(share->kfile)) - error=errno; - if (fsync(share->dfile)) - error=errno; -#endif + if (my_sync(share->kfile, MYF(0))) + error= my_errno; + if (my_sync(info->dfile, MYF(0))) + error= my_errno; } else share->not_flushed=1; diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index cd409e1ace5..a298701dc7f 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -353,6 +353,9 @@ while test $# -gt 0; do TMP=`$ECHO "$1" | $SED -e "s;--valgrind-options=;;"` VALGRIND="$VALGRIND $TMP" ;; + --valgrind-all) + VALGRIND="$VALGRIND -v --show-reachable=yes" + ;; --skip-*) EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT $1" EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT $1" diff --git a/mysys/Makefile.am b/mysys/Makefile.am index a927fa5e3a0..5dc54817fd7 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -47,7 +47,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\ my_delete.c my_rename.c my_redel.c my_tempnam.c \ my_chsize.c my_lread.c my_lwrite.c my_clock.c \ my_quick.c my_lockmem.c my_static.c \ - my_getopt.c my_mkdir.c \ + my_sync.c my_getopt.c my_mkdir.c \ default.c my_compress.c checksum.c raid.cc \ my_net.c my_semaphore.c my_port.c my_sleep.c \ my_vsnprintf.c charset.c my_bitmap.c my_bit.c md5.c \ diff --git a/mysys/errors.c b/mysys/errors.c index 8a120e0e869..7d755718b16 100644 --- a/mysys/errors.c +++ b/mysys/errors.c @@ -48,6 +48,7 @@ const char * NEAR globerrs[GLOBERRS]= "Can't read value for symlink '%s' (Error %d)", "Can't create symlink '%s' pointing at '%s' (Error %d)", "Error on realpath() on '%s' (Error %d)", + "Can't sync file '%s' to disk (Errcode: %d)", }; void init_glob_errs(void) @@ -84,8 +85,9 @@ void init_glob_errs() EE(EE_CANT_MKDIR) ="Can't create directory '%s' (Errcode: %d)"; EE(EE_UNKNOWN_CHARSET)= "Character set is not a compiled character set and is not specified in the %s file"; EE(EE_OUT_OF_FILERESOURCES)="Out of resources when opening file '%s' (Errcode: %d)"; - EE(EE_CANT_READLINK)="Can't read value for symlink '%s' (Error %d)"; - EE(EE_CANT_SYMLINK)="Can't create symlink '%s' pointing at '%s' (Error %d)"; - EE(EE_REALPATH)="Error on realpath() on '%s' (Error %d)"; + EE(EE_CANT_READLINK)= "Can't read value for symlink '%s' (Error %d)"; + EE(EE_CANT_SYMLINK)= "Can't create symlink '%s' pointing at '%s' (Error %d)"; + EE(EE_REALPATH)= "Error on realpath() on '%s' (Error %d)"; + EE(EE_SYNC)= "Can't sync file '%s' to disk (Errcode: %d)"; } #endif diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c index e287930ff06..abef0096e28 100644 --- a/mysys/my_symlink.c +++ b/mysys/my_symlink.c @@ -103,7 +103,8 @@ int my_symlink(const char *content, const char *linkname, myf MyFlags) #define BUFF_LEN FN_LEN #endif -int my_realpath(char *to, const char *filename, myf MyFlags) +int my_realpath(char *to, const char *filename, + myf MyFlags __attribute__((unused))) { #if defined(HAVE_REALPATH) && !defined(HAVE_purify) && !defined(HAVE_BROKEN_REALPATH) int result=0; diff --git a/mysys/my_sync.c b/mysys/my_sync.c new file mode 100644 index 00000000000..317ca039346 --- /dev/null +++ b/mysys/my_sync.c @@ -0,0 +1,60 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "mysys_priv.h" +#include "mysys_err.h" +#include + +/* + Sync data in file to disk + + SYNOPSIS + my_sync() + fd File descritor to sync + my_flags Flags (now only MY_WME is supported) + + NOTE + If file system supports its, only file data is synced, not inode date + + RETURN + 0 ok + -1 error +*/ + +int my_sync(File fd, myf my_flags) +{ + int res; + DBUG_ENTER("my_sync"); + DBUG_PRINT("my",("Fd: %d my_flags: %d", fd, my_flags)); + +#if defined(HAVE_FDATASYNC) + res= fdatasync(fd); +#elif defined(HAVE_FSYNC) + res=fsync(fd); +#elif defined(__WIN__) + res= _commit(fd); +#else + res= 0; /* No sync (strange OS) */ +#endif + if (res) + { + if (!(my_errno= errno)) + my_errno= -1; /* Unknown error */ + if (my_flags & MY_WME) + my_error(EE_SYNC, MYF(ME_BELL+ME_WAITTANG), my_filename(fd), my_errno); + } + DBUG_RETURN(res); +} /* my_read */ diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index 36bbac16fef..bf40ffc5b4d 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -714,6 +714,9 @@ void thr_alarm_info(ALARM_INFO *info) bzero((char*) info, sizeof(*info)); } +void resize_thr_alarm(uint max_alarms) +{ +} /***************************************************************************** thr_alarm for win95 @@ -793,6 +796,10 @@ void thr_alarm_info(ALARM_INFO *info) bzero((char*) info, sizeof(*info)); } +void resize_thr_alarm(uint max_alarms) +{ +} + #endif /* __WIN__ */ #endif /* THREAD */ diff --git a/sql/unireg.cc b/sql/unireg.cc index 5183f471fa2..ff42bfae0f0 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -150,16 +150,19 @@ int rea_create_table(my_string file_name, my_free((gptr) screen_buff,MYF(0)); my_afree((gptr) keybuff); - VOID(my_close(file,MYF(MY_WME))); - if (ha_create_table(file_name,create_info,0)) + if (my_sync(file, MYF(MY_WME))) goto err2; + if (my_close(file,MYF(MY_WME)) || + ha_create_table(file_name,create_info,0)) + goto err3; DBUG_RETURN(0); err: my_free((gptr) screen_buff,MYF(0)); my_afree((gptr) keybuff); +err2: VOID(my_close(file,MYF(MY_WME))); - err2: +err3: my_delete(file_name,MYF(0)); DBUG_RETURN(1); } /* rea_create_table */ From 3ebe794733b973d4254716075b0d53486329b839 Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Sun, 2 Nov 2003 16:38:27 +0200 Subject: [PATCH 46/49] Portability fix --- sql/slave.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/slave.h b/sql/slave.h index 8f7d96b23dd..ed34c12985a 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -239,7 +239,7 @@ typedef struct st_relay_log_info int wait_for_pos(THD* thd, String* log_name, longlong log_pos, longlong timeout); - void st_relay_log_info::close_temporary_tables(); + void close_temporary_tables(); } RELAY_LOG_INFO; From 0143e4856801ada413ca93f58e80e1590414c505 Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Mon, 3 Nov 2003 19:56:01 +0300 Subject: [PATCH 47/49] fix for bug #1724 'WHERE ... IN() optimizer behaviour has changed since 4.0.14' We need to calculate cost of RANGE scan if it is present instead of cost of FULL scan. --- mysql-test/r/order_by.result | 6 ++-- mysql-test/r/range.result | 17 ++++++++++ mysql-test/r/select.result | 4 +-- mysql-test/t/range.test | 23 +++++++++++++ sql/sql_select.cc | 65 +++++++++++++++++++++++------------- 5 files changed, 87 insertions(+), 28 deletions(-) diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 58f4972d08f..076c80035b2 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -307,17 +307,17 @@ table type possible_keys key key_len ref rows Extra t1 range a a 9 NULL 8 Using where; Using index explain select * from t1 where a = 2 and b >0 order by a desc,b desc; table type possible_keys key key_len ref rows Extra -t1 range a a 9 NULL 5 Using where; Using index +t1 range a a 9 NULL 4 Using where; Using index explain select * from t1 where a = 2 and b is null order by a desc,b desc; table type possible_keys key key_len ref rows Extra t1 ref a a 9 const,const 1 Using where; Using index; Using filesort explain select * from t1 where a = 2 and (b is null or b > 0) order by a desc,b desc; table type possible_keys key key_len ref rows Extra -t1 range a a 9 NULL 6 Using where; Using index +t1 range a a 9 NULL 5 Using where; Using index explain select * from t1 where a = 2 and b > 0 order by a desc,b desc; table type possible_keys key key_len ref rows Extra -t1 range a a 9 NULL 5 Using where; Using index +t1 range a a 9 NULL 4 Using where; Using index explain select * from t1 where a = 2 and b < 2 order by a desc,b desc; table type possible_keys key key_len ref rows Extra t1 range a a 9 NULL 2 Using where; Using index diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 2bd80cbfba3..68987009598 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -273,3 +273,20 @@ table type possible_keys key key_len ref rows Extra t2 ref j1 j1 4 const 1 Using where; Using index t1 ALL i2 NULL NULL NULL 4 Range checked for each record (index map: 2) DROP TABLE t1,t2; +CREATE TABLE t1 ( +a int(11) default NULL, +b int(11) default NULL, +KEY a (a), +KEY b (b) +) TYPE=MyISAM; +INSERT INTO t1 VALUES +(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,2),(10,2), +(13,2),(14,2),(15,2),(16,2),(17,3),(17,3),(16,3),(17,3),(19,3),(20,3), +(21,4),(22,5),(23,5),(24,5),(25,5),(26,5),(30,5),(31,5),(32,5),(33,5), +(33,5),(33,5),(33,5),(33,5),(34,5),(35,5); +EXPLAIN SELECT * FROM t1 WHERE a IN(1,2) AND b=5; +table type possible_keys key key_len ref rows Extra +t1 range a,b a 5 NULL 2 Using where +SELECT * FROM t1 WHERE a IN(1,2) AND b=5; +a b +DROP TABLE t1; diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 09a4ffdb88b..9cc5ad76ff0 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2136,10 +2136,10 @@ a a a select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 on t1.a>1; a a a 1 1 2 -2 2 2 -3 3 2 1 1 3 +2 2 2 2 2 3 +3 3 2 3 3 3 select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; a a a diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index 75ca0fff5f2..a8b7679457b 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -214,3 +214,26 @@ explain select * from t1, t2 where (t1.key1 table->force_index && best_key)) { // Check full join ha_rows rnd_records= s->found_records; - /* Estimate cost of reading table. */ - tmp= s->table->file->scan_time(); /* If there is a restriction on the table, assume that 25% of the rows can be skipped on next part. @@ -2156,36 +2154,57 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, if (found_constraint) rnd_records-= rnd_records/4; - if (s->on_expr) // Can't use join cache + /* + Range optimizer never proposes a RANGE if it isn't better + than FULL: so if RANGE is present, it's always preferred to FULL. + Here we estimate its cost. + */ + if (s->quick) { + /* + For each record we: + - read record range through 'quick' + - skip rows which does not satisfy WHERE constraints + */ tmp= record_count * - /* We have to read the whole table for each record */ - (tmp + - /* - And we have to skip rows which does not satisfy join - condition for each record. - */ - (s->records - rnd_records)/(double) TIME_FOR_COMPARE); + (s->quick->read_time + + (s->found_records - rnd_records)/(double) TIME_FOR_COMPARE); } else { - /* We read the table as many times as join buffer becomes full. */ - tmp*= (1.0 + floor((double) cache_record_length(join,idx) * - record_count / - (double) thd->variables.join_buff_size)); - /* - We don't make full cartesian product between rows in the scanned - table and existing records because we skip all rows from the - scanned table, which does not satisfy join condition when - we read the table (see flush_cached_records for details). Here we - take into account cost to read and skip these records. - */ - tmp+= (s->records - rnd_records)/(double) TIME_FOR_COMPARE; + /* Estimate cost of reading table. */ + tmp= s->table->file->scan_time(); + if (s->on_expr) // Can't use join cache + { + /* + For each record we have to: + - read the whole table record + - skip rows which does not satisfy join condition + */ + tmp= record_count * + (tmp + + (s->records - rnd_records)/(double) TIME_FOR_COMPARE); + } + else + { + /* We read the table as many times as join buffer becomes full. */ + tmp*= (1.0 + floor((double) cache_record_length(join,idx) * + record_count / + (double) thd->variables.join_buff_size)); + /* + We don't make full cartesian product between rows in the scanned + table and existing records because we skip all rows from the + scanned table, which does not satisfy join condition when + we read the table (see flush_cached_records for details). Here we + take into account cost to read and skip these records. + */ + tmp+= (s->records - rnd_records)/(double) TIME_FOR_COMPARE; + } } /* We estimate the cost of evaluating WHERE clause for found records - as record_count * rnd_records + TIME_FOR_COMPARE. This cost plus + as record_count * rnd_records / TIME_FOR_COMPARE. This cost plus tmp give us total cost of using TABLE SCAN */ if (best == DBL_MAX || From fbc54c139d26602f8b2d418413476c49a814c2b3 Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Mon, 3 Nov 2003 18:24:01 +0100 Subject: [PATCH 48/49] When we delete the slave's temp tables from memory, we reset rli->save_temporary_tables and slave_open_temp_tables (in old 4.0 you could make "SHOW STATUS LIKE 'slave_open_temp_tables'" grow indefinitely by doing RESET SLAVE and replicating always the same CREATE TEMPORARY TABLE). It's critical to reset save_temporary_tables to 0 (otherwise you may later read memory which has been freed) so this changeset should go into 4.1. --- mysql-test/r/rpl_reset_slave.result | 10 ++++++++++ mysql-test/t/rpl_reset_slave.test | 18 ++++++++++++++++++ sql/slave.cc | 2 ++ 3 files changed, 30 insertions(+) diff --git a/mysql-test/r/rpl_reset_slave.result b/mysql-test/r/rpl_reset_slave.result index c1bc1e8e483..fb931064720 100644 --- a/mysql-test/r/rpl_reset_slave.result +++ b/mysql-test/r/rpl_reset_slave.result @@ -20,3 +20,13 @@ start slave; show slave status; Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space 127.0.0.1 root MASTER_PORT 1 master-bin.001 79 slave-relay-bin.002 120 master-bin.001 Yes Yes 0 0 79 120 +stop slave; +reset slave; +start slave; +create temporary table t1 (a int); +stop slave; +reset slave; +start slave; +show status like 'slave_open_temp_tables'; +Variable_name Value +Slave_open_temp_tables 1 diff --git a/mysql-test/t/rpl_reset_slave.test b/mysql-test/t/rpl_reset_slave.test index 9c58ac0c787..083492c3fc0 100644 --- a/mysql-test/t/rpl_reset_slave.test +++ b/mysql-test/t/rpl_reset_slave.test @@ -2,6 +2,8 @@ # --master-* options from mysqld, as this is what is going to be used next time # slave threads will be started). In bug 985, it displayed old values (of before # RESET SLAVE). +# See if slave crashes when doing a CREATE TEMPORARY TABLE twice, separated by +# RESET SLAVE. source include/master-slave.inc; connection master; @@ -24,3 +26,19 @@ start slave; sync_with_master; --replace_result $MASTER_MYPORT MASTER_PORT show slave status; + +# test of crash with temp tables & RESET SLAVE +# (test to see if RESET SLAVE clears temp tables in memory and disk) +stop slave; +reset slave; +start slave; +connection master; +create temporary table t1 (a int); +save_master_pos; +connection slave; +sync_with_master; +stop slave; +reset slave; +start slave; +sync_with_master; +show status like 'slave_open_temp_tables'; diff --git a/sql/slave.cc b/sql/slave.cc index da63ca71951..6816d968007 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -337,6 +337,8 @@ void st_relay_log_info::close_temporary_tables() */ close_temporary(table, 0); } + save_temporary_tables= 0; + slave_open_temp_tables= 0; } /* From 5505abe1026b674a46c998eb6b21a4280a542203 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Mon, 3 Nov 2003 23:18:55 +0100 Subject: [PATCH 49/49] fixed a bug in boolean fts where a word queue was created based on min_word_len, while with trunc* operator one could get shorter words --- myisam/ft_boolean_search.c | 2 +- mysql-test/r/fulltext.result | 2 ++ mysql-test/t/fulltext.test | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 6a7b7531d4d..72c54bd0c5b 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -308,7 +308,7 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, Hack: instead of init_queue, we'll use reinit queue to be able to alloc queue with alloc_root() */ - res=ftb->queue.max_elements=1+query_len/(ft_min_word_len+1); + res=ftb->queue.max_elements=1+query_len/(min(ft_min_word_len,2)+1); ftb->queue.root=(byte **)alloc_root(&ftb->mem_root, (res+1)*sizeof(void*)); reinit_queue(& ftb->queue, res, 0, 0, (int (*)(void*,byte*,byte*))FTB_WORD_cmp, 0); diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index 737390865f1..df277a18615 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -266,4 +266,6 @@ insert into t2 values (3, 1, 'xxbuz'); select * from t1 join t2 using(`t1_id`) where match (t1.name, t2.name) against('xxfoo' in boolean mode); t1_id name t2_id t1_id name 1 data1 1 1 xxfoo +select * from t2 where match name against ('a* b* c* d* e* f*' in boolean mode); +t2_id t1_id name drop table t1,t2; diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index 387a36f1f52..69c69794f4f 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -213,5 +213,11 @@ insert into t2 values (1, 1, 'xxfoo'); insert into t2 values (2, 1, 'xxbar'); insert into t2 values (3, 1, 'xxbuz'); select * from t1 join t2 using(`t1_id`) where match (t1.name, t2.name) against('xxfoo' in boolean mode); + +# +# bug with many short (< ft_min_word_len) words in boolean search +# +select * from t2 where match name against ('a* b* c* d* e* f*' in boolean mode); + drop table t1,t2;