diff options
67 files changed, 882 insertions, 199 deletions
diff --git a/BitKeeper/triggers/post-commit b/BitKeeper/triggers/post-commit index a2a0ecb2701..b0d70c85661 100755 --- a/BitKeeper/triggers/post-commit +++ b/BitKeeper/triggers/post-commit @@ -19,7 +19,7 @@ BK_STATUS=$BK_STATUS$BK_COMMIT if [ "$BK_STATUS" = OK ] then -CHANGESET=`bk -R prs -r+ -h -d':I:' ChangeSet` +CHANGESET=`bk -R prs -r+ -h -d':P:::I:' ChangeSet` #++ # dev-public@ diff --git a/VC++Files/mysys/mysys.dsp b/VC++Files/mysys/mysys.dsp index 9f7a6bbf2e9..533d4212e2b 100644 --- a/VC++Files/mysys/mysys.dsp +++ b/VC++Files/mysys/mysys.dsp @@ -430,6 +430,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/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 68b7da78bbf..f870c92cb6d 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; @@ -226,7 +226,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}, @@ -266,6 +266,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; @@ -274,6 +279,7 @@ static void die(const char* fmt, ...) vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); va_end(args); + cleanup(); exit(1); } @@ -333,6 +339,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 '#': @@ -343,7 +350,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)))) @@ -359,6 +376,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; } @@ -707,6 +727,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; diff --git a/client/mysqldump.c b/client/mysqldump.c index 5e83e7bd043..31305c93e6c 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -632,6 +632,7 @@ static my_bool test_if_special_chars(const char *str) } /* test_if_special_chars */ + static char *quote_name(const char *name, char *buff, my_bool force) { char *to= buff; @@ -789,7 +790,8 @@ static uint getTableStructure(char *table, char* db) if (verbose) fprintf(stderr, "-- Retrieving table structure for table %s...\n", table); - sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d", (opt_quoted || opt_keywords)); + sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d", + (opt_quoted || opt_keywords)); result_table= quote_name(table, table_buff, 1); opt_quoted_table= quote_name(table, table_buff2, 0); if (!opt_xml && !mysql_query(sock,insert_pat)) @@ -1041,7 +1043,8 @@ static uint getTableStructure(char *table, char* db) else if (keynr == primary_key) fputs(",\n PRIMARY KEY (",sql_file); /* First UNIQUE is primary */ else - fprintf(sql_file, ",\n UNIQUE %s (",quote_name(row[2],name_buff,0)); + fprintf(sql_file, ",\n UNIQUE %s (",quote_name(row[2],name_buff, + 0)); } else putc(',', sql_file); @@ -1520,23 +1523,28 @@ static int init_dumping(char *database) { if (opt_databases || opt_alldbs) { - fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", database); + /* + 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", qdatabase); if (!opt_create_db) { - char qbuf[128]; + char qbuf[256]; MYSQL_ROW row; MYSQL_RES *dbinfo; - sprintf(qbuf,"SHOW CREATE DATABASE WITH IF NOT EXISTS %s",database); + sprintf(qbuf,"SHOW CREATE DATABASE WITH IF NOT EXISTS %s", + qdatabase); if (mysql_query(sock, qbuf) || !(dbinfo = mysql_store_result(sock))) { /* Old server version, dump generic CREATE DATABASE */ fprintf(md_result_file, - "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s%s%s;\n", - (opt_quoted ? "`" : ""), - database, - (opt_quoted ? "`" : "")); + "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n", + qdatabase); } else { @@ -1547,18 +1555,16 @@ static int init_dumping(char *database) } } } - fprintf(md_result_file,"\nUSE %s%s%s;\n", (opt_quoted ? "`" : ""), - database, - (opt_quoted ? "`" : "")); + fprintf(md_result_file,"\nUSE %s;\n", qdatabase); } } - if (extended_insert) - if (init_dynamic_string(&extended_row, "", 1024, 1024)) - exit(EX_EOM); + if (extended_insert && init_dynamic_string(&extended_row, "", 1024, 1024)) + exit(EX_EOM); return 0; } /* init_dumping */ + static int dump_all_tables_in_db(char *database) { char *table; diff --git a/configure.in b/configure.in index 207404a89c5..4b930b45f04 100644 --- a/configure.in +++ b/configure.in @@ -731,7 +731,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 @@ -1832,7 +1832,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/extra/resolveip.c b/extra/resolveip.c index 12e6977c2ba..f8cff2a976c 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/config-win.h b/include/config-win.h index 884b2edfb63..4fdbfbbd02f 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -183,8 +183,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 73287a2ba2a..43cacf8fa65 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -594,8 +594,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 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/include/my_pthread.h b/include/my_pthread.h index 82a2bb1accc..a4ea88b20f0 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -645,6 +645,7 @@ struct st_my_thread_var long id; int cmp_length; int volatile abort; + my_bool init; struct st_my_thread_var *next,**prev; void *opt_info; #ifndef DBUG_OFF diff --git a/include/my_sys.h b/include/my_sys.h index c404e54c2a9..6082b988822 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -614,6 +614,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/mysql_com.h b/include/mysql_com.h index be8db185737..f4b6114c8d4 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -33,7 +33,7 @@ #if defined(__WIN__) && !defined( _CUSTOMCONFIG_) #define MYSQL_NAMEDPIPE "MySQL" -#define MYSQL_SERVICENAME "MySql" +#define MYSQL_SERVICENAME "MySQL" #endif /* __WIN__ */ enum enum_server_command 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/innobase/os/os0file.c b/innobase/os/os0file.c index 37f64efb27f..b6d4eba9f9b 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -3095,7 +3095,15 @@ 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)) { + 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); + } + /* Do a 'last millisecond' check that the page end is sensible; reported page checksum errors from Linux seem to wipe over the page end */ diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 0effdf20766..f41574b2855 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -3287,14 +3287,14 @@ rec_loop: latest version of the record */ } else if (index == clust_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, + && !lock_clust_rec_cons_read_sees(rec, index, trx->read_view)) { err = row_sel_build_prev_vers_for_mysql( diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index fa836fb6083..9987804f03e 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -1717,7 +1717,7 @@ 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++) { diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 59143e81049..067aec36627 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -1164,6 +1164,28 @@ NetWare. */ /* Note that the call srv_boot() also changes the values of srv_pool_size etc. to the units used by InnoDB internally */ + /* 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/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/libmysql/manager.c b/libmysql/manager.c index 1354b98d1c9..ddf9b6c1010 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/libmysqld/Makefile.am b/libmysqld/Makefile.am index 7e04f53e9ff..95cbd4ec826 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -92,10 +92,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 diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 95d0149c67d..f3b593f7341 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -362,7 +362,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/myisam/mi_extra.c b/myisam/mi_extra.c index 1d57e0c0e18..8c7515550e7 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 785979235ce..6f996ab5abd 100644 --- a/myisam/mi_locking.c +++ b/myisam/mi_locking.c @@ -98,22 +98,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/myisam/myisamchk.c b/myisam/myisamchk.c index 5a3768c9932..59cc26b198b 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -411,6 +411,8 @@ static void usage(void) -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\ + 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\ "); @@ -1109,7 +1111,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/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index eda2f3b2a34..8af3a3ac3ec 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -338,7 +338,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 @@ -349,6 +355,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" @@ -1163,7 +1172,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/fulltext.result b/mysql-test/r/fulltext.result index da3b3d0b8da..56f95ff0c90 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -297,6 +297,8 @@ 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; SET NAMES latin1; CREATE TABLE t1 (t text character set utf8 not null, fulltext(t)); diff --git a/mysql-test/r/func_crypt.result b/mysql-test/r/func_crypt.result index 5ee0f0f3e93..6b63002fd39 100644 --- a/mysql-test/r/func_crypt.result +++ b/mysql-test/r/func_crypt.result @@ -1,6 +1,16 @@ +drop table if exists t1; select length(encrypt('foo', 'ff')) <> 0; length(encrypt('foo', 'ff')) <> 0 1 +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; select password('abc'); password('abc') *0D3CED9BEC10A777AEC23CCC353A8C08A633045E diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index db747e3a7eb..f4878664076 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -306,17 +306,17 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE 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; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range a a 9 NULL 5 Using where; Using index +1 SIMPLE 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; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE 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; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range a a 9 NULL 6 Using where; Using index +1 SIMPLE 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; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range a a 9 NULL 5 Using where; Using index +1 SIMPLE 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; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range a a 9 NULL 2 Using where; Using index diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index b446d30c83f..45e195e89f7 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); @@ -722,6 +723,46 @@ 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; SET NAMES koi8r; CREATE TABLE t1 (a char(1) character set koi8r); INSERT INTO t1 VALUES (_koi8r'á'),(_koi8r'Á'); diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 38d3d9b2b7d..324eb37b334 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -262,6 +262,23 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ref j1 j1 4 const 1 Using where; Using index 1 SIMPLE t1 ALL i2 NULL NULL NULL 4 Range checked for each record (index map: 0x2) 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; create table t1 (id int(10) primary key); insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9); select id from t1 where id in (2,5,9) ; 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/r/rpl_reset_slave.result b/mysql-test/r/rpl_reset_slave.result index 8887462389d..e1fbf12786d 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; Slave_IO_State 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 Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_condition Until_Log_File Until_Log_pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_behind_master # 127.0.0.1 root MASTER_PORT 1 master-bin.000001 79 slave-relay-bin.000002 123 master-bin.000001 Yes Yes 0 0 79 123 None 0 No # +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/r/rpl_trunc_binlog.result b/mysql-test/r/rpl_trunc_binlog.result index 1cd9cdf08a0..bc5e401287d 100644 --- a/mysql-test/r/rpl_trunc_binlog.result +++ b/mysql-test/r/rpl_trunc_binlog.result @@ -8,7 +8,8 @@ stop slave; flush logs; reset slave; start slave; -show slave status; Slave_IO_State 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 Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_condition Until_Log_File Until_Log_pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_behind_master # 127.0.0.1 root MASTER_PORT 1 master-bin.000002 4 slave-relay-bin.000002 123 master-bin.000001 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 326 None 0 No # -reset master; +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/r/select.result b/mysql-test/r/select.result index b9218942a5e..8edd0182dec 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2150,10 +2150,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/fulltext.test b/mysql-test/t/fulltext.test index 9c48f84161a..467d1aa6f07 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -228,6 +228,12 @@ 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; # diff --git a/mysql-test/t/func_crypt.test b/mysql-test/t/func_crypt.test index c1c7090cab3..3cf1e15e3ef 100644 --- a/mysql-test/t/func_crypt.test +++ b/mysql-test/t/func_crypt.test @@ -1,9 +1,21 @@ -- source include/have_crypt.inc +--disable_warnings +drop table if exists t1; +--enable_warnings + select length(encrypt('foo', 'ff')) <> 0; --replace_result $1$aa$4OSUA5cjdx0RUQ08opV27/ aaqPiZY5xR5l. +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; + # Test new and old password handling functions + select password('abc'); select password(''); select old_password('abc'); 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 0ec6e5ecb73..14cbf4c906d 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. @@ -11,7 +12,7 @@ flush query cache; # This crashed in some versions reset query cache; flush status; --disable_warnings -drop table if exists t1,t2,t3; +drop table if exists t1,t2,t3,t4,t11,t21; drop database if exists mysqltest; --enable_warnings @@ -490,6 +491,55 @@ 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; + +# # Test character set related variables: # character_set_result # character_set_client @@ -535,3 +585,4 @@ show status like "Qcache_queries_in_cache"; # Keep things tidy # DROP TABLE t1; +SET GLOBAL query_cache_size=0; diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index 40ae49f8005..0b39f20e346 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -306,3 +306,28 @@ select * from t1, t2 where t1.uid=t2.uid AND t1.uid > 0; select * from t1, t2 where t1.uid=t2.uid AND t1.uid != 0; drop table t1,t2; + +# +# bug #1724: use RANGE on more selective column instead of REF on less +# selective + +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; +SELECT * FROM t1 WHERE a IN(1,2) AND b=5; + +DROP TABLE t1; + +# we expect that optimizer will choose key on A 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..007b018e9d8 --- /dev/null +++ b/mysql-test/t/rpl_chain_temp_table.test @@ -0,0 +1,99 @@ + # 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. +# So you must run this test with --manager. + +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; + +# 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/mysql-test/t/rpl_reset_slave.test b/mysql-test/t/rpl_reset_slave.test index e03916ec73a..d58e9c711d1 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; @@ -28,3 +30,19 @@ sync_with_master; --replace_result $MASTER_MYPORT MASTER_PORT --replace_column 1 # 33 # 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/mysql-test/t/rpl_trunc_binlog.test b/mysql-test/t/rpl_trunc_binlog.test index 4c14ec72b5c..32052af9184 100644 --- a/mysql-test/t/rpl_trunc_binlog.test +++ b/mysql-test/t/rpl_trunc_binlog.test @@ -23,5 +23,3 @@ sleep 3; --replace_result $MASTER_MYPORT MASTER_PORT --replace_column 1 # 33 # show slave status; -connection master; -reset master; diff --git a/mysys/Makefile.am b/mysys/Makefile.am index 5ff682fbc80..37c79e28395 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 \ charset.c charset-def.c my_bitmap.c my_bit.c md5.c \ diff --git a/mysys/errors.c b/mysys/errors.c index a2226fc12c5..255b6893c73 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 '%s' 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_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) 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 <errno.h> + +/* + 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/my_thr_init.c b/mysys/my_thr_init.c index 32bc8ea3724..9ee7371b639 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/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/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index adaac0f3102..acf0f8aa2c8 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -167,7 +167,7 @@ then fi fi -if test "$ip_only" ="1" +if test "$ip_only" = "1" then ip=`echo "$resolved" | awk '/ /{print $6}'` hostname=$ip 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() { diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh index f23955da06a..654e5466e12 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 ); } } @@ -413,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; } } } @@ -938,6 +945,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 ( (, ), |, !, diff --git a/sql/item_func.cc b/sql/item_func.cc index e6120f2e93c..3ed0396e373 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2571,7 +2571,7 @@ err: 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); } diff --git a/sql/log_event.cc b/sql/log_event.cc index 62dc56e7fd2..c0fd781cede 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -768,11 +768,49 @@ int Query_log_event::write(IO_CACHE* file) int Query_log_event::write_data(IO_CACHE* file) { + char buf[QUERY_HEADER_LEN]; + if (!query) 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); int4store(buf + Q_EXEC_TIME_OFFSET, exec_time); buf[Q_DB_LEN_OFFSET] = (char) db_len; int2store(buf + Q_ERR_CODE_OFFSET, error_code); @@ -790,12 +828,14 @@ int Query_log_event::write_data(IO_CACHE* file) #ifndef MYSQL_CLIENT Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length, bool using_trans) - :Log_event(thd_arg, !thd_arg->tmp_table_used ? - 0 : LOG_EVENT_THREAD_SPECIFIC_F, using_trans), + :Log_event(thd_arg, !thd_arg->tmp_table_used ? + 0 : LOG_EVENT_THREAD_SPECIFIC_F, 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); @@ -836,7 +876,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; @@ -907,8 +947,8 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) { thd->set_time((time_t)when); thd->query_length= q_len; - VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query = (char*)query; + VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query_id = query_id++; VOID(pthread_mutex_unlock(&LOCK_thread_count)); thd->query_error= 0; // clear error @@ -1276,7 +1316,7 @@ void Load_log_event::pack_info(Protocol *protocol) 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); 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; @@ -1317,7 +1357,9 @@ 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), + 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) { @@ -1422,7 +1464,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/log_event.h b/sql/log_event.h index 8ba5d0379a0..6cc8a7ca06d 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -455,6 +455,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, @@ -543,6 +550,7 @@ protected: public: ulong thread_id; + ulong slave_proxy_id; uint32 table_name_len; uint32 db_len; uint32 fname_len; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1052eeaf11b..7c432a05786 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1985,7 +1985,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, @@ -2733,7 +2733,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); @@ -2743,7 +2743,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")) { @@ -2786,10 +2788,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[0]= 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; @@ -2797,8 +2805,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])) { @@ -2810,6 +2817,8 @@ int main(int argc, char **argv) opt_argc= 2; // Skip service-name opt_argv=argv; start_mode= 1; + if (my_strcasecmp(argv[2],"mysql")) + load_default_groups[3]= argv[2]; Service.Init(argv[2], mysql_service); return 0; } diff --git a/sql/slave.cc b/sql/slave.cc index 415969a2955..561b32b668c 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -355,6 +355,22 @@ 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); + } + save_temporary_tables= 0; + slave_open_temp_tables= 0; +} /* purge_relay_logs() @@ -847,6 +863,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) { /* @@ -1428,7 +1445,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->group_master_log_name[0]= 0; @@ -3166,8 +3183,6 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ RPL_LOG_NAME, llstr(rli->group_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)); @@ -3585,6 +3600,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 618b04311b9..f8093826f58 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -320,10 +320,10 @@ typedef struct st_relay_log_info int wait_for_pos(THD* thd, String* log_name, longlong log_pos, longlong timeout); + void close_temporary_tables(); /* Check if UNTIL condition is satisfied. See slave.cc for more. */ bool is_until_satisfied(); - } RELAY_LOG_INFO; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 88a1d21354b..3976ebd81f4 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -575,6 +575,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->variables.pseudo_thread_id); key_length += 4; @@ -603,18 +605,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->variables.pseudo_thread_id); table->key_length += 4; return 0; @@ -771,12 +782,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->variables.pseudo_thread_id); + int4store(key + key_length, thd->server_id); + int4store(key + key_length + 4, thd->variables.pseudo_thread_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) { @@ -1671,7 +1683,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 */ @@ -1694,6 +1706,9 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *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->variables.pseudo_thread_id); tmp_table->key_length += 4; diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 0bae41da002..a4ae8fd5946 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -2761,11 +2761,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; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ed01e1bb038..6b43c2f796e 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -396,6 +396,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; } diff --git a/sql/sql_class.h b/sql/sql_class.h index c66ebb77020..7a8dc067256 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -481,7 +481,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; @@ -510,6 +514,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 diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d6f8e2f66c7..b3c17167a3a 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -172,6 +172,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; @@ -314,14 +315,15 @@ int check_user(THD *thd, enum enum_server_command command, thd->db_access=0; /* Don't allow user to connect if he has done too many queries */ - if ((ur.questions || ur.updates || - ur.connections || max_user_connections) && - get_or_create_user_conn(thd,thd->user,thd->host_or_ip,&ur)) - DBUG_RETURN(-1); - if (thd->user_connect && (thd->user_connect->user_resources.connections || - max_user_connections) && - check_for_max_user_connections(thd, thd->user_connect)) - DBUG_RETURN(-1); + if ((ur.questions || ur.updates || ur.connections || + max_user_connections) && + get_or_create_user_conn(thd,thd->user,thd->host_or_ip,&ur)) + DBUG_RETURN(-1); + if (thd->user_connect && + (thd->user_connect->user_resources.connections || + max_user_connections) && + check_for_max_user_connections(thd, thd->user_connect)) + DBUG_RETURN(-1); /* Change database if necessary: OK or FAIL is sent in mysql_change_db */ if (db && db[0]) @@ -386,42 +388,84 @@ void init_max_user_conn(void) } +/* + check if user has already too many connections + + SYNOPSIS + check_for_max_user_connections() + thd Thread handle + uc User connect object + + NOTES + If check fails, we decrease user connection count, which means one + shouldn't call decrease_user_connections() after this function. + + RETURN + 0 ok + 1 error +*/ + static int check_for_max_user_connections(THD *thd, 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 < (uint) uc->connections) { net_printf(thd,ER_TOO_MANY_USER_CONNECTIONS, uc->user); error=1; 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(thd, ER_USER_LIMIT_REACHED, uc->user, "max_connections", (long) uc->user_resources.connections); error=1; + goto end; } -end: + 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); } +/* + Decrease user connection count + + SYNOPSIS + decrease_user_connections() + uc User connection object + + NOTES + If there is a n user connection object for a connection + (which only happens if 'max_user_connections' is defined or + if someone has created a resource grant for a user), then + the connection count is always incremented on connect. + + The user connect object is not freed if some users has + 'max connections per hour' defined as we need to be able to hold + count over the lifetime of the connection. +*/ + 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; } @@ -1227,15 +1271,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; - USER_CONN *save_uc= thd->user_connect; - thd->user= my_strdup(user, MYF(0)); - if (!thd->user) + USER_CONN *save_user_connect= thd->user_connect; + + if (!(thd->user= my_strdup(user, MYF(0)))) { thd->user= save_user; send_error(thd, ER_OUT_OF_RESOURCES); break; } + /* Clear variables that are allocated */ + thd->user_connect= 0; int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, false); if (res) @@ -1246,6 +1292,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, x_free(thd->user); thd->user= save_user; thd->priv_user= save_priv_user; + thd->user_connect= save_user_connect; thd->master_access= save_master_access; thd->db_access= save_db_access; thd->db= save_db; @@ -1254,8 +1301,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, else { /* we've authenticated new user */ - if (max_connections && 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); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index bdaed894a52..3decbd62a2c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1453,10 +1453,21 @@ JOIN::exec() { DBUG_VOID_RETURN; } + /* + 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(thd, curr_join, curr_join->group_list ? curr_join->group_list : curr_join->order, - curr_join->select_limit, unit->select_limit_cnt)) + curr_join->select_limit, + (select_options & OPTION_FOUND_ROWS ? + HA_POS_ERROR : unit->select_limit_cnt))) DBUG_VOID_RETURN; } } @@ -2856,8 +2867,6 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, !(s->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. @@ -2867,36 +2876,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 || @@ -3320,6 +3350,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); diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 47f0932b221..c14d30f8d34 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -22,7 +22,11 @@ #include "sql_select.h" #include <hash.h> #include <thr_alarm.h> +#if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_H) #include <malloc.h> +#elif defined(HAVE_MALLINFO) && defined(HAVE_SYS_MALLOC_H) +#include <sys/malloc.h> +#endif /* Intern key cache variables */ extern "C" pthread_mutex_t THR_LOCK_keycache; diff --git a/sql/unireg.cc b/sql/unireg.cc index 8606830e450..e93e290bd4c 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -150,16 +150,19 @@ int rea_create_table(THD *thd, my_string file_name, my_free((gptr) screen_buff,MYF(0)); my_free((gptr) keybuff, MYF(0)); - 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_free((gptr) keybuff, MYF(0)); +err2: VOID(my_close(file,MYF(MY_WME))); - err2: +err3: my_delete(file_name,MYF(0)); DBUG_RETURN(1); } /* rea_create_table */ diff --git a/sql/unireg.h b/sql/unireg.h index 66a274f3863..8d62959317d 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_ALIAS_NAME 256 #define MAX_FIELD_NAME 34 /* Max colum name length +2 */ diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index dec77a15dc5..30ee4ab545f 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -109,19 +109,6 @@ else 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 server 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 |