diff options
56 files changed, 625 insertions, 245 deletions
diff --git a/include/my_getopt.h b/include/my_getopt.h index 115abf00618..c74f3ed672e 100644 --- a/include/my_getopt.h +++ b/include/my_getopt.h @@ -31,6 +31,7 @@ C_MODE_START #define GET_DISABLED 11 #define GET_ENUM 12 #define GET_SET 13 +#define GET_DOUBLE 14 #define GET_ASK_ADDR 128 #define GET_TYPE_MASK 127 diff --git a/include/my_sys.h b/include/my_sys.h index fb949842e48..c452bd21e15 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -833,7 +833,7 @@ extern my_bool my_compress(uchar *, size_t *, size_t *); extern my_bool my_uncompress(uchar *, size_t , size_t *); extern uchar *my_compress_alloc(const uchar *packet, size_t *len, size_t *complen); -extern int packfrm(const uchar *, size_t, uchar **, size_t *); +extern int packfrm(uchar *, size_t, uchar **, size_t *); extern int unpackfrm(uchar **, size_t *, const uchar *); extern ha_checksum my_checksum(ha_checksum crc, const uchar *mem, @@ -846,7 +846,11 @@ extern void my_sleep(ulong m_seconds); extern uint my_set_max_open_files(uint files); void my_free_open_file_info(void); +extern time_t my_time(myf flags); extern ulonglong my_getsystime(void); +extern ulonglong my_micro_time(); +extern ulonglong my_micro_time_and_time(time_t *time_arg); +time_t my_time_possible_from_micro(ulonglong microtime); extern my_bool my_gethwaddr(uchar *to); extern int my_getncpus(); diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h index b87fcc60692..541fa7dfbe6 100644 --- a/include/mysql/plugin.h +++ b/include/mysql/plugin.h @@ -110,7 +110,7 @@ enum enum_mysql_show_type { SHOW_UNDEF, SHOW_BOOL, SHOW_INT, SHOW_LONG, SHOW_LONGLONG, SHOW_CHAR, SHOW_CHAR_PTR, - SHOW_ARRAY, SHOW_FUNC + SHOW_ARRAY, SHOW_FUNC, SHOW_DOUBLE }; struct st_mysql_show_var { diff --git a/libmysql/CMakeLists.txt b/libmysql/CMakeLists.txt index 7d4dcc1e919..c1585e10e25 100644 --- a/libmysql/CMakeLists.txt +++ b/libmysql/CMakeLists.txt @@ -63,7 +63,7 @@ ADD_LIBRARY(libmysql SHARED dll.c libmysql.def ../strings/strmov.c ../strings/strnlen.c ../strings/strnmov.c ../strings/strtod.c ../strings/strtoll.c ../strings/strtoull.c ../strings/strxmov.c ../strings/strxnmov.c ../mysys/thr_mutex.c ../mysys/typelib.c ../vio/vio.c ../vio/viosocket.c - ../vio/viossl.c ../vio/viosslfactories.c ../strings/xml.c) + ../vio/viossl.c ../vio/viosslfactories.c ../strings/xml.c ../mysys/my_getsystime.c) ADD_DEPENDENCIES(libmysql dbug vio mysys strings GenError zlib yassl taocrypt) TARGET_LINK_LIBRARIES(libmysql mysys strings wsock32) diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index c24c6ab52db..3a2559921f9 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -68,7 +68,7 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \ mf_iocache2.lo my_seek.lo my_sleep.lo \ my_pread.lo mf_cache.lo md5.lo sha1.lo \ my_getopt.lo my_gethostbyname.lo my_port.lo \ - my_rename.lo my_chsize.lo + my_rename.lo my_chsize.lo my_getsystime.lo sqlobjects = net.lo sql_cmn_objects = pack.lo client.lo my_time.lo diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index ff43993cfdb..e6d09306fcb 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -444,7 +444,14 @@ set interactive_timeout=100; set join_buffer_size=100; set last_insert_id=1; set global local_infile=1; -set long_query_time=100; +set long_query_time=0.000001; +select @@long_query_time; +@@long_query_time +0.000001 +set long_query_time=100.000001; +select @@long_query_time; +@@long_query_time +100.000001 set low_priority_updates=1; set max_allowed_packet=100; set global max_binlog_cache_size=100; diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index efa2ce4a27c..8f55d83c3de 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -268,7 +268,10 @@ set interactive_timeout=100; set join_buffer_size=100; set last_insert_id=1; set global local_infile=1; -set long_query_time=100; +set long_query_time=0.000001; +select @@long_query_time; +set long_query_time=100.000001; +select @@long_query_time; set low_priority_updates=1; set max_allowed_packet=100; set global max_binlog_cache_size=100; diff --git a/mysys/charset.c b/mysys/charset.c index 1c81e480404..cc1a238f281 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -323,14 +323,14 @@ static int charset_initialized=0; static my_bool my_read_charset_file(const char *filename, myf myflags) { - char *buf; + uchar *buf; int fd; uint len, tmp_len; MY_STAT stat_info; if (!my_stat(filename, &stat_info, MYF(myflags)) || ((len= (uint)stat_info.st_size) > MY_MAX_ALLOWED_BUF) || - !(buf= (char *)my_malloc(len,myflags))) + !(buf= (uchar*) my_malloc(len,myflags))) return TRUE; if ((fd=my_open(filename,O_RDONLY,myflags)) < 0) @@ -340,7 +340,7 @@ static my_bool my_read_charset_file(const char *filename, myf myflags) if (tmp_len != len) goto error; - if (my_parse_charset_xml(buf,len,add_collation)) + if (my_parse_charset_xml((char*) buf,len,add_collation)) { #ifdef NOT_YET printf("ERROR at line %d pos %d '%s'\n", @@ -350,7 +350,7 @@ static my_bool my_read_charset_file(const char *filename, myf myflags) #endif } - my_free(buf, myflags); + my_free(buf, myflags); return FALSE; error: diff --git a/mysys/default_modify.c b/mysys/default_modify.c index b2a43f511b9..78f6105b071 100644 --- a/mysys/default_modify.c +++ b/mysys/default_modify.c @@ -218,7 +218,7 @@ int modify_defaults_file(const char *file_location, const char *option, if (my_chsize(fileno(cnf_file), (my_off_t) (dst_ptr - file_buffer), 0, MYF(MY_WME)) || my_fseek(cnf_file, 0, MY_SEEK_SET, MYF(0)) || - my_fwrite(cnf_file, file_buffer, (size_t) (dst_ptr - file_buffer), + my_fwrite(cnf_file, (uchar*) file_buffer, (size_t) (dst_ptr - file_buffer), MYF(MY_NABP))) goto err; } diff --git a/mysys/hash.c b/mysys/hash.c index 47ddc5aa97d..4532b06b533 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -137,7 +137,7 @@ void my_hash_reset(HASH *hash) DBUG_VOID_RETURN; } - /* some helper functions */ +/* some helper functions */ /* This function is char* instead of uchar* as HPUX11 compiler can't @@ -149,9 +149,9 @@ hash_key(const HASH *hash, const uchar *record, size_t *length, my_bool first) { if (hash->get_key) - return (*hash->get_key)(record,length,first); + return (char*) (*hash->get_key)(record,length,first); *length=hash->key_length; - return (uchar*) record+hash->key_offset; + return (char*) record+hash->key_offset; } /* Calculate pos according to keys */ @@ -313,12 +313,14 @@ my_bool my_hash_insert(HASH *info,const uchar *record) uchar *ptr_to_rec,*ptr_to_rec2; HASH_LINK *data,*empty,*gpos,*gpos2,*pos; - LINT_INIT(gpos); LINT_INIT(gpos2); - LINT_INIT(ptr_to_rec); LINT_INIT(ptr_to_rec2); + LINT_INIT(gpos); + LINT_INIT(gpos2); + LINT_INIT(ptr_to_rec); + LINT_INIT(ptr_to_rec2); if (HASH_UNIQUE & info->flags) { - char *key= (char*) hash_key(info, record, &idx, 1); + uchar *key= (uchar*) hash_key(info, record, &idx, 1); if (hash_search(info, key, idx)) return(TRUE); /* Duplicate entry */ } @@ -544,14 +546,16 @@ my_bool hash_update(HASH *hash, uchar *record, uchar *old_key, if (HASH_UNIQUE & hash->flags) { HASH_SEARCH_STATE state; - char *found, *new_key= hash_key(hash, record, &idx, 1); + uchar *found, *new_key= (uchar*) hash_key(hash, record, &idx, 1); if ((found= hash_first(hash, new_key, idx, &state))) + { do { - if (found != (char*) record) + if (found != record) DBUG_RETURN(1); /* Duplicate entry */ } while ((found= hash_next(hash, new_key, idx, &state))); + } } data=dynamic_element(&hash->array,0,HASH_LINK*); diff --git a/mysys/mf_getdate.c b/mysys/mf_getdate.c index 2f08027a477..3a8e1be6a0b 100644 --- a/mysys/mf_getdate.c +++ b/mysys/mf_getdate.c @@ -42,7 +42,7 @@ void get_date(register char * to, int flag, time_t date) struct tm tm_tmp; #endif - skr=date ? (time_t) date : time((time_t*) 0); + skr=date ? (time_t) date : my_time(0); #if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT) if (flag & GETDATE_GMT) localtime_r(&skr,&tm_tmp); diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c index 8a5b91661c4..87ea995f518 100644 --- a/mysys/mf_iocache2.c +++ b/mysys/mf_iocache2.c @@ -246,7 +246,7 @@ size_t my_b_gets(IO_CACHE *info, char *to, size_t max_length) for (;;) { - char *pos,*end; + uchar *pos, *end; if (length > max_length) length=max_length; for (pos=info->read_pos,end=pos+length ; pos < end ;) @@ -323,7 +323,7 @@ size_t my_b_vprintf(IO_CACHE *info, const char* fmt, va_list args) length= (size_t) (fmt - start); out_length+=length; - if (my_b_write(info, start, length)) + if (my_b_write(info, (const uchar*) start, length)) goto err; if (*fmt == '\0') /* End of format */ @@ -378,14 +378,14 @@ size_t my_b_vprintf(IO_CACHE *info, const char* fmt, va_list args) size_t length2 = strlen(par); /* TODO: implement minimum width and precision */ out_length+= length2; - if (my_b_write(info, par, length2)) + if (my_b_write(info, (uchar*) par, length2)) goto err; } else if (*fmt == 'b') /* Sized buffer parameter, only precision makes sense */ { char *par = va_arg(args, char *); out_length+= precision; - if (my_b_write(info, par, precision)) + if (my_b_write(info, (uchar*) par, precision)) goto err; } else if (*fmt == 'd' || *fmt == 'u') /* Integer parameter */ @@ -400,7 +400,7 @@ size_t my_b_vprintf(IO_CACHE *info, const char* fmt, va_list args) else length2= (size_t) (int10_to_str((long) (uint) iarg,buff,10)- buff); out_length+= length2; - if (my_b_write(info, buff, length2)) + if (my_b_write(info, (uchar*) buff, length2)) goto err; } else if ((*fmt == 'l' && fmt[1] == 'd') || fmt[1] == 'u') @@ -416,13 +416,13 @@ size_t my_b_vprintf(IO_CACHE *info, const char* fmt, va_list args) else length2= (size_t) (int10_to_str(iarg,buff,10)- buff); out_length+= length2; - if (my_b_write(info, buff, length2)) + if (my_b_write(info, (uchar*) buff, length2)) goto err; } else { /* %% or unknown code */ - if (my_b_write(info, backtrack, fmt-backtrack)) + if (my_b_write(info, (uchar*) backtrack, (size_t) (fmt-backtrack))) goto err; out_length+= fmt-backtrack; } diff --git a/mysys/mf_pack.c b/mysys/mf_pack.c index 99c0c959d94..a31b9595c85 100644 --- a/mysys/mf_pack.c +++ b/mysys/mf_pack.c @@ -56,7 +56,7 @@ void pack_dirname(char * to, const char *from) (buff_length == d_length && !bcmp(buff,start,d_length))) && *start != FN_LIBCHAR && *start) { /* Put current dir before */ - bchange(to,d_length,buff,buff_length,strlen(to)+1); + bchange((uchar*) to, d_length, (uchar*) buff, buff_length, strlen(to)+1); } } @@ -328,7 +328,7 @@ size_t unpack_dirname(char * to, const char *from) if (buff+h_length < suffix) bmove(buff+h_length,suffix,length); else - bmove_upp(buff+h_length+length,suffix+length,length); + bmove_upp((uchar*) buff+h_length+length, (uchar*) suffix+length, length); bmove(buff,tilde_expansion,h_length); } } diff --git a/mysys/mf_path.c b/mysys/mf_path.c index 7baded9d715..73e73cb7f76 100644 --- a/mysys/mf_path.c +++ b/mysys/mf_path.c @@ -46,7 +46,7 @@ char * my_path(char * to, const char *progname, if (!test_if_hard_path(to)) { if (!my_getwd(curr_dir,FN_REFLEN,MYF(0))) - bchange(to,0,curr_dir, (uint) strlen(curr_dir), (uint) strlen(to)+1); + bchange((uchar*) to, 0, (uchar*) curr_dir, strlen(curr_dir), strlen(to)+1); } } else diff --git a/mysys/my_append.c b/mysys/my_append.c index ddd3c91e832..35881a959d5 100644 --- a/mysys/my_append.c +++ b/mysys/my_append.c @@ -27,21 +27,22 @@ struct utimbuf { }; #endif - /* Append a file to another */ - -int my_append(const char *from, const char *to, myf MyFlags) +/* + Append a file to another + NOTES + Don't set MY_FNABP or MY_NABP bits on when calling this function +*/ - /* Dont set MY_FNABP or MY_NABP bits on - when calling this funktion */ +int my_append(const char *from, const char *to, myf MyFlags) { uint Count; File from_file,to_file; - char buff[IO_SIZE]; + uchar buff[IO_SIZE]; DBUG_ENTER("my_append"); DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags)); - from_file=to_file= -1; + from_file= to_file= -1; if ((from_file=my_open(from,O_RDONLY,MyFlags)) >= 0) { diff --git a/mysys/my_compress.c b/mysys/my_compress.c index d495a1c1c6d..bc9f8317487 100644 --- a/mysys/my_compress.c +++ b/mysys/my_compress.c @@ -154,17 +154,20 @@ my_bool my_uncompress(uchar *packet, size_t len, size_t *complen) SYNOPSIS packfrm() - data Data reference to frm file data + data Data reference to frm file data. len Length of frm file data out:pack_data Reference to the pointer to the packed frm data out:pack_len Length of packed frm file data + NOTES + data is replaced with compressed content + RETURN VALUES 0 Success >0 Failure */ -int packfrm(const uchar *data, size_t len, +int packfrm(uchar *data, size_t len, uchar **pack_data, size_t *pack_len) { int error; @@ -178,8 +181,8 @@ int packfrm(const uchar *data, size_t len, if (my_compress((uchar*)data, &org_len, &comp_len)) goto err; - DBUG_PRINT("info", ("org_len: %lu comp_len: %lu", org_len, comp_len)); - DBUG_DUMP("compressed", (char*)data, org_len); + DBUG_PRINT("info", ("org_len: %lu comp_len: %lu", (ulong) org_len, (ulong) comp_len)); + DBUG_DUMP("compressed", data, org_len); error= 2; blob_len= BLOB_HEADER + org_len; @@ -235,7 +238,7 @@ int unpackfrm(uchar **unpack_data, size_t *unpack_len, complen= uint4korr(pack_data+8); DBUG_PRINT("blob",("ver: %lu complen: %lu orglen: %lu", - ver, complen, orglen)); + ver, (ulong) complen, (ulong) orglen)); DBUG_DUMP("blob->data", pack_data + BLOB_HEADER, complen); if (ver != 1) diff --git a/mysys/my_copy.c b/mysys/my_copy.c index 3f8b0695a25..cd741b1eb52 100644 --- a/mysys/my_copy.c +++ b/mysys/my_copy.c @@ -54,7 +54,7 @@ int my_copy(const char *from, const char *to, myf MyFlags) my_bool new_file_stat= 0; /* 1 if we could stat "to" */ int create_flag; File from_file,to_file; - char buff[IO_SIZE]; + uchar buff[IO_SIZE]; MY_STAT stat_buff,new_stat_buff; DBUG_ENTER("my_copy"); DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags)); @@ -80,10 +80,12 @@ int my_copy(const char *from, const char *to, myf MyFlags) MyFlags)) < 0) goto err; - while ((Count=my_read(from_file,buff,IO_SIZE,MyFlags)) != 0) + while ((Count=my_read(from_file, buff, sizeof(buff), MyFlags)) != 0) + { if (Count == (uint) -1 || my_write(to_file,buff,Count,MYF(MyFlags | MY_NABP))) goto err; + } if (my_close(from_file,MyFlags) | my_close(to_file,MyFlags)) DBUG_RETURN(-1); /* Error on close */ diff --git a/mysys/my_gethwaddr.c b/mysys/my_gethwaddr.c index 01abc02058b..845b5aa4152 100644 --- a/mysys/my_gethwaddr.c +++ b/mysys/my_gethwaddr.c @@ -19,7 +19,7 @@ #include "mysys_priv.h" #include <m_string.h> -#ifndef MAIN +#if !defined(__FreeBSD__) || defined(__linux__) static my_bool memcpy_and_test(uchar *to, uchar *from, uint len) { uint i, res=1; diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index 32a5452e451..3a5b130e067 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -32,6 +32,7 @@ my_bool getopt_compare_strings(const char *s, static longlong getopt_ll(char *arg, const struct my_option *optp, int *err); static ulonglong getopt_ull(char *arg, const struct my_option *optp, int *err); +static double getopt_double(char *arg, const struct my_option *optp, int *err); static void init_variables(const struct my_option *options); static int setval(const struct my_option *opts, uchar* *value, char *argument, my_bool set_maximum_value); @@ -611,6 +612,9 @@ static int setval(const struct my_option *opts, uchar* *value, char *argument, case GET_ULL: *((ulonglong*) result_pos)= getopt_ull(argument, opts, &err); break; + case GET_DOUBLE: + *((double*) result_pos)= getopt_double(argument, opts, &err); + break; case GET_STR: *((char**) result_pos)= argument; break; @@ -720,7 +724,7 @@ my_bool getopt_compare_strings(register const char *s, register const char *t, be k|K for kilo, m|M for mega or g|G for giga. */ -static longlong eval_num_suffix (char *argument, int *error, char *option_name) +static longlong eval_num_suffix(char *argument, int *error, char *option_name) { char *endchar; longlong num; @@ -802,6 +806,37 @@ ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp) /* + Get double value withing ranges + + Evaluates and returns the value that user gave as an argument to a variable. + + RETURN + decimal value of arg + + In case of an error, prints an error message and sets *err to + EXIT_ARGUMENT_INVALID. Otherwise err is not touched +*/ + +static double getopt_double(char *arg, const struct my_option *optp, int *err) +{ + double num; + int error; + char *end= arg + 1000; /* Big enough as *arg is \0 terminated */ + num= my_strtod(arg, &end, &error); + if (end[0] != 0 || error) + { + fprintf(stderr, + "%s: ERROR: Invalid decimal value for option '%s'\n", + my_progname, optp->name); + *err= EXIT_ARGUMENT_INVALID; + return 0.0; + } + if (optp->max_value && num > (double) optp->max_value) + num= (double) optp->max_value; + return max(num, (double) optp->min_value); +} + +/* Init one value to it's default values SYNOPSIS @@ -838,6 +873,9 @@ static void init_one_value(const struct my_option *option, uchar* *variable, case GET_SET: *((ulonglong*) variable)= (ulonglong) value; break; + case GET_DOUBLE: + *((double*) variable)= (double) value; + break; case GET_STR: /* Do not clear variable value if it has no default value. @@ -1052,6 +1090,9 @@ void my_print_variables(const struct my_option *options) longlong2str(*((ulonglong*) value), buff, 10); printf("%s\n", buff); break; + case GET_DOUBLE: + printf("%g\n", *(double*) value); + break; default: printf("(Disabled)\n"); break; diff --git a/mysys/my_getsystime.c b/mysys/my_getsystime.c index 2fd7eed7778..17ba1232d7a 100644 --- a/mysys/my_getsystime.c +++ b/mysys/my_getsystime.c @@ -29,28 +29,17 @@ ulonglong my_getsystime() clock_gettime(CLOCK_REALTIME, &tp); return (ulonglong)tp.tv_sec*10000000+(ulonglong)tp.tv_nsec/100; #elif defined(__WIN__) -#define OFFSET_TO_EPOC ((__int64) 134774 * 24 * 60 * 60 * 1000 * 1000 * 10) - static __int64 offset=0, freq; LARGE_INTEGER t_cnt; - if (!offset) + struct timeval tv; + if (query_performance_frequency) { - /* strictly speaking there should be a mutex to protect - initialization section. But my_getsystime() is called from - UUID() code, and UUID() calls are serialized with a mutex anyway - */ - LARGE_INTEGER li; - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - li.LowPart=ft.dwLowDateTime; - li.HighPart=ft.dwHighDateTime; - offset=li.QuadPart-OFFSET_TO_EPOC; - QueryPerformanceFrequency(&li); - freq=li.QuadPart; QueryPerformanceCounter(&t_cnt); - offset-=t_cnt.QuadPart/freq*10000000+t_cnt.QuadPart%freq*10000000/freq; + return (t_cnt.QuadPart / query_performance_frequency * 10000000+ + t_cnt.QuadPart % query_performance_frequency * 10000000/ + query_performance_frequency+query_performance_offset); } - QueryPerformanceCounter(&t_cnt); - return t_cnt.QuadPart/freq*10000000+t_cnt.QuadPart%freq*10000000/freq+offset; + gettimeofday(&tv,NULL); + return (ulonglong)tv.tv_sec*10000000+(ulonglong)tv.tv_usec*10; #elif defined(__NETWARE__) NXTime_t tm; NXGetTime(NX_SINCE_1970, NX_NSECONDS, &tm); @@ -62,3 +51,164 @@ ulonglong my_getsystime() return (ulonglong)tv.tv_sec*10000000+(ulonglong)tv.tv_usec*10; #endif } + + +/* + Return current time + + SYNOPSIS + my_time() + flags If MY_WME is set, write error if time call fails + +*/ + +#define DELTA_FOR_SECONDS LL(500000000) /* Half a second */ + +time_t my_time(myf flags __attribute__((unused))) +{ +#ifdef HAVE_GETHRTIME + static hrtime_t prev_gethrtime= 0; + static time_t cur_time= 0; + + hrtime_t cur_gethrtime; + pthread_mutex_lock(&THR_LOCK_time); + cur_gethrtime= gethrtime(); + if ((prev_gethrtime - cur_gethrtime) > DELTA_FOR_SECONDS) + { + cur_time= time(0); + prev_gethrtime= cur_gethrtime; + } + pthread_mutex_unlock(&THR_LOCK_time); + return cur_time; +#else + time_t t; + /* The following loop is here beacuse time() may fail on some systems */ + while ((t= time(0)) == (time_t) -1) + { + if (flags & MY_WME) + fprintf(stderr, "%s: Warning: time() call failed\n", my_progname); + } + return t; +#endif +} + + +/* + Return time in micro seconds + + SYNOPSIS + my_micro_time() + + NOTES + This function is to be used to measure performance in micro seconds. + As it's not defined whats the start time for the clock, this function + us only useful to measure time between two moments. + + For windows platforms we need the frequency value of the CUP. This is + initalized in my_init.c through QueryPerformanceFrequency(). + + If Windows platform doesn't support QueryPerformanceFrequency() we will + obtain the time via GetClockCount, which only supports milliseconds. + + RETURN + Value in microseconds from some undefined point in time +*/ + +ulonglong my_micro_time() +{ + ulonglong newtime; +#if defined(__WIN__) + if (query_performance_frequency) + { + QueryPerformanceCounter(&newtime); + newtime/= (query_performance_frequency * 1000000); + } + else + newtime= (GetTickCount() * 1000; /* GetTickCount only returns milliseconds */ +#elif defined(HAVE_GETHRTIME) + return gethrtime()/1000; +#else + struct timeval t; + /* The following loop is here because gettimeofday may fail on some systems */ + while (gettimeofday(&t, NULL) != 0) + {} + newtime= (ulonglong)t.tv_sec * 1000000 + t.tv_usec; +#endif /* defined(__WIN__) */ + return newtime; +} + + +/* + Return time in seconds and timer in microseconds + + SYNOPSIS + my_micro_time_and_time() + time_arg Will be set to seconds since epoch (00:00:00 UTC, January 1, + 1970) + + NOTES + This function is to be useful when we need both the time and microtime. + For example in MySQL this is used to get the query time start of a query and + to measure the time of a query (for the slow query log) + + IMPLEMENTATION + Same as my_micro_time() + + RETURN + Value in microseconds from some undefined point in time +*/ + +ulonglong my_micro_time_and_time(time_t *time_arg) +{ + ulonglong newtime; +#if defined(__WIN__) + if (query_performance_frequency) + { + QueryPerformanceCounter((LARGE_INTEGER *) &newtime); + newtime/= (query_performance_frequency * 1000000); + } + else + newtime= (GetTickCount() * 1000; /* GetTickCount only returns milliseconds */ + (void) time(time_arg); +#else + struct timeval t; + /* The following loop is here because gettimeofday may fail on some systems */ + while (gettimeofday(&t, NULL) != 0) + {} + *time_arg= t.tv_sec; + newtime= (ulonglong)t.tv_sec * 1000000 + t.tv_usec; +#endif /* defined(__WIN__) */ + return newtime; +} + + +/* + Returns current time + + SYNOPSIS + my_time_possible_from_micro() + microtime Value from very recent my_micro_time() + + NOTES + This function returns the current time. The microtime argument is only used + if my_micro_time() uses a function that can safely be converted to the current + time. + + RETURN + current time +*/ + +time_t my_time_possible_from_micro(ulonglong microtime __attribute__((unused))) +{ +#if defined(__WIN__) + time_t t; + while ((t= time(0)) == (time_t) -1) + {} + return t; +#elif defined(HAVE_GETHRTIME) + return my_time(0); /* Cached time */ +#else + return (time_t) (microtime / 1000000); +#endif /* defined(__WIN__) */ +} + diff --git a/mysys/my_init.c b/mysys/my_init.c index c1337205eb4..8281d7ced99 100644 --- a/mysys/my_init.c +++ b/mysys/my_init.c @@ -371,6 +371,28 @@ static void my_win_init(void) /* chiude la chiave */ RegCloseKey(hSoftMysql) ; + + /* The following is used by time functions */ +#define OFFSET_TO_EPOC ((__int64) 134774 * 24 * 60 * 60 * 1000 * 1000 * 10) +#define MS 10000000 + { + FILETIME ft; + LARGE_INTEGER li, t_cnt; + DBUG_ASSERT(sizeof(LARGE_INTEGER) == sizeof(query_performance_frequency)); + if (QueryPerformanceFrequency((LARGE_INTEGER *)&query_performance_frequency)) + query_performance_frequency= 0; + else + { + GetSystemTimeAsFileTime(&ft); + li.LowPart= ft.dwLowDateTime; + li.HighPart= ft.dwHighDateTime; + query_performance_offset= li.QuadPart-OFFSET_TO_EPOC; + QueryPerformanceCounter(&t_cnt); + query_performance_offset-= (t_cnt.QuadPart / query_performance_frequency * MS + + t_cnt.QuadPart % query_performance_frequency * MS / + query_performance_frequency); + } + } DBUG_VOID_RETURN ; } diff --git a/mysys/my_static.c b/mysys/my_static.c index 472cf3b5084..92c959c4c6c 100644 --- a/mysys/my_static.c +++ b/mysys/my_static.c @@ -93,6 +93,11 @@ int (*error_handler_hook)(uint error,const char *str,myf MyFlags)= int (*fatal_error_handler_hook)(uint error,const char *str,myf MyFlags)= my_message_no_curses; +#ifdef __WIN__ +/* from my_getsystime.c */ +ulonglong query_performance_frequency, query_performance_offset; +#endif + /* How to disable options */ my_bool NEAR my_disable_locking=0; my_bool NEAR my_disable_async_io=0; diff --git a/mysys/my_static.h b/mysys/my_static.h index 66e6ea1c280..0eca196c1c9 100644 --- a/mysys/my_static.h +++ b/mysys/my_static.h @@ -66,6 +66,8 @@ extern struct st_irem *sf_malloc_root; extern struct st_my_file_info my_file_info_default[MY_NFILE]; +extern ulonglong query_performance_frequency, query_performance_offset; + #if defined(THREAD) && !defined(__WIN__) extern sigset_t my_signals; /* signals blocked by mf_brkhant */ #endif diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index cc33ac3f21c..8b935c895c8 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -30,7 +30,7 @@ pthread_key(struct st_my_thread_var, THR_KEY_mysys); #endif /* USE_TLS */ pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open, THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_myisam,THR_LOCK_heap, - THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads; + THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads, THR_LOCK_time; pthread_cond_t THR_COND_threads; uint THR_thread_count= 0; uint my_thread_end_wait_time= 5; @@ -146,6 +146,7 @@ my_bool my_thread_global_init(void) pthread_mutex_init(&THR_LOCK_net,MY_MUTEX_INIT_FAST); pthread_mutex_init(&THR_LOCK_charset,MY_MUTEX_INIT_FAST); pthread_mutex_init(&THR_LOCK_threads,MY_MUTEX_INIT_FAST); + pthread_mutex_init(&THR_LOCK_time,MY_MUTEX_INIT_FAST); pthread_cond_init(&THR_COND_threads, NULL); #if defined( __WIN__) || defined(OS2) win_pthread_init(); @@ -202,6 +203,7 @@ void my_thread_global_end(void) pthread_mutex_destroy(&THR_LOCK_myisam); pthread_mutex_destroy(&THR_LOCK_heap); pthread_mutex_destroy(&THR_LOCK_net); + pthread_mutex_destroy(&THR_LOCK_time); pthread_mutex_destroy(&THR_LOCK_charset); if (all_threads_killed) { diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h index 709cfed969a..6e0959ae08c 100644 --- a/mysys/mysys_priv.h +++ b/mysys/mysys_priv.h @@ -28,7 +28,7 @@ #include <my_pthread.h> extern pthread_mutex_t THR_LOCK_malloc, THR_LOCK_open, THR_LOCK_keycache; extern pthread_mutex_t THR_LOCK_lock, THR_LOCK_isam, THR_LOCK_net; -extern pthread_mutex_t THR_LOCK_charset; +extern pthread_mutex_t THR_LOCK_charset, THR_LOCK_time; #else #include <my_no_pthread.h> #endif diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index 81093be3678..2934e724724 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -157,7 +157,7 @@ my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data) DBUG_ENTER("thr_alarm"); DBUG_PRINT("enter",("thread: %s sec: %d",my_thread_name(),sec)); - now=(ulong) time((time_t*) 0); + now=(ulong) my_time(0); pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask); pthread_mutex_lock(&LOCK_alarm); /* Lock from threads & alarms */ if (alarm_aborted > 0) @@ -351,7 +351,7 @@ static sig_handler process_alarm_part2(int sig __attribute__((unused))) } else { - ulong now=(ulong) time((time_t*) 0); + ulong now=(ulong) my_time(0); ulong next=now+10-(now%10); while ((alarm_data=(ALARM*) queue_top(&alarm_queue))->expire_time <= now) { @@ -480,7 +480,7 @@ void thr_alarm_info(ALARM_INFO *info) info->max_used_alarms= max_used_alarms; if ((info->active_alarms= alarm_queue.elements)) { - ulong now=(ulong) time((time_t*) 0); + ulong now=(ulong) my_time(0); long time_diff; ALARM *alarm_data= (ALARM*) queue_top(&alarm_queue); time_diff= (long) (alarm_data->expire_time - now); @@ -528,7 +528,7 @@ static void *alarm_handler(void *arg __attribute__((unused))) { if (alarm_queue.elements) { - ulong sleep_time,now=time((time_t*) 0); + ulong sleep_time,now= my_time(0); if (alarm_aborted) sleep_time=now+1; else @@ -685,7 +685,7 @@ static void *test_thread(void *arg) for (i=1 ; i <= 10 ; i++) { wait_time=param ? 11-i : i; - start_time=time((time_t*) 0); + start_time= my_time(0); if (thr_alarm(&got_alarm,wait_time,0)) { printf("Thread: %s Alarms aborted\n",my_thread_name()); @@ -747,7 +747,7 @@ static void *test_thread(void *arg) } } printf("Thread: %s Slept for %d (%d) sec\n",my_thread_name(), - (int) (time((time_t*) 0)-start_time), wait_time); fflush(stdout); + (int) (my_time(0)-start_time), wait_time); fflush(stdout); thr_end_alarm(&got_alarm); fflush(stdout); } diff --git a/sql-common/client.c b/sql-common/client.c index 6d63c457390..75b1c9747a5 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -232,7 +232,7 @@ static int wait_for_data(my_socket fd, uint timeout) implementations of select that don't adjust tv upon failure to reflect the time remaining */ - start_time = time(NULL); + start_time= my_time(0); for (;;) { tv.tv_sec = (long) timeout; @@ -246,7 +246,7 @@ static int wait_for_data(my_socket fd, uint timeout) #endif if (res == 0) /* timeout */ return -1; - now_time=time(NULL); + now_time= my_time(0); timeout-= (uint) (now_time - start_time); if (errno != EINTR || (int) timeout <= 0) return -1; diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index 7b58c10079a..17924ee0e42 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -1644,7 +1644,7 @@ err: void Event_queue_element::mark_last_executed(THD *thd) { - thd->end_time(); + thd->set_current_time(); last_executed= (my_time_t) thd->query_start(); last_executed_changed= TRUE; diff --git a/sql/event_queue.cc b/sql/event_queue.cc index 634cc764d74..71dd6a0833f 100644 --- a/sql/event_queue.cc +++ b/sql/event_queue.cc @@ -550,7 +550,7 @@ Event_queue::get_top_for_execution_if_time(THD *thd, top= ((Event_queue_element*) queue_element(&queue, 0)); - thd->end_time(); /* Get current time */ + thd->set_current_time(); /* Get current time */ next_activation_at= top->execute_at; if (next_activation_at > thd->query_start()) diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index c552b22e942..3092521fd4c 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -283,8 +283,7 @@ Event_worker_thread::run(THD *thd, Event_queue_element_for_exec *event) res= post_init_event_thread(thd); DBUG_ENTER("Event_worker_thread::run"); - DBUG_PRINT("info", ("Time is %ld, THD: 0x%lx", - (long) time(NULL), (long) thd)); + DBUG_PRINT("info", ("Time is %ld, THD: 0x%lx", (long) my_time(0), (long) thd)); if (res) goto end; diff --git a/sql/field.h b/sql/field.h index 8bf087c7ebd..2782042e911 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1394,6 +1394,8 @@ public: { return charset() == &my_charset_bin ? FALSE : TRUE; } uint32 max_display_length(); uint is_equal(Create_field *new_field); + inline bool in_read_set() { return bitmap_is_set(table->read_set, field_index); } + inline bool in_write_set() { return bitmap_is_set(table->write_set, field_index); } }; diff --git a/sql/item.h b/sql/item.h index 432da6c3a1c..c15b74a265d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1712,8 +1712,11 @@ public: max_length=length; fixed= 1; } - Item_float(double value_par) :presentation(0), value(value_par) { fixed= 1; } - + Item_float(double value_par, uint decimal_par) :presentation(0), value(value_par) + { + decimals= (uint8) decimal_par; + fixed= 1; + } int save_in_field(Field *field, bool no_conversions); enum Type type() const { return REAL_ITEM; } enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index fcbacc32d88..47914c59b4c 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -853,6 +853,7 @@ public: friend int cmp_longlong(void *cmp_arg, packed_longlong *a,packed_longlong *b); }; + class in_double :public in_vector { double tmp; @@ -862,16 +863,16 @@ public: uchar *get_value(Item *item); Item *create_item() { - return new Item_float(0.0); + return new Item_float(0.0, 0); } void value_to_item(uint pos, Item *item) { ((Item_float*)item)->value= ((double*) base)[pos]; } Item_result result_type() { return REAL_RESULT; } - }; + class in_decimal :public in_vector { my_decimal val; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index a87efa9e68c..7cee8088026 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1594,7 +1594,7 @@ int Item_func_now::save_in_field(Field *to, bool no_conversions) void Item_func_sysdate_local::store_now_in_TIME(MYSQL_TIME *now_time) { THD *thd= current_thd; - thd->variables.time_zone->gmt_sec_to_TIME(now_time, (my_time_t) time(NULL)); + thd->variables.time_zone->gmt_sec_to_TIME(now_time, (my_time_t) my_time(0)); thd->time_zone_used= 1; } diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index f8457a1ae50..6bc73f49a5a 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -2767,7 +2767,7 @@ String *Item_xml_str_func::parse_xml(String *raw_xml, String *parsed_xml_buf) if ((rc= my_xml_parse(&p, raw_xml->ptr(), raw_xml->length())) != MY_XML_OK) { char buf[128]; - my_snprintf(buf, sizeof(buf)-1, "parse error at line %d pos %lu: %s", + my_snprintf(buf, sizeof(buf)-1, "parse error at line %d pos %u: %s", my_xml_error_lineno(&p) + 1, my_xml_error_pos(&p) + 1, my_xml_error_string(&p)); diff --git a/sql/lock.cc b/sql/lock.cc index 4260a031def..e04be568a29 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -246,7 +246,7 @@ retry: } } - thd->lock_time(); + thd->set_time_after_lock(); DBUG_RETURN (sql_lock); } diff --git a/sql/log.cc b/sql/log.cc index 0bf77d68410..207c248c9e8 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -524,8 +524,8 @@ err: user_host the pointer to the string with user@host info user_host_len length of the user_host string. this is computed once and passed to all general log event handlers - query_time Amount of time the query took to execute (in seconds) - lock_time Amount of time the query was locked (in seconds) + query_time Amount of time the query took to execute (in microseconds) + lock_time Amount of time the query was locked (in microseconds) is_command The flag, which determines, whether the sql_text is a query or an administrator command (these are treated differently by the old logging routines) @@ -545,13 +545,12 @@ err: bool Log_to_csv_event_handler:: log_slow(THD *thd, time_t current_time, time_t query_start_arg, const char *user_host, uint user_host_len, - longlong query_time, longlong lock_time, bool is_command, + ulonglong query_utime, ulonglong lock_utime, bool is_command, const char *sql_text, uint sql_text_len) { /* table variables */ TABLE *table= slow_log.table; CHARSET_INFO *client_cs= thd->variables.character_set_client; - DBUG_ENTER("log_slow"); /* below should never happen */ @@ -582,6 +581,8 @@ bool Log_to_csv_event_handler:: if (query_start_arg) { + longlong query_time= (longlong) (query_utime/1000000); + longlong lock_time= (longlong) (lock_utime/1000000); /* A TIME field can not hold the full longlong range; query_time or lock_time may be truncated without warning here, if greater than @@ -694,12 +695,12 @@ void Log_to_file_event_handler::init_pthread_objects() bool Log_to_file_event_handler:: log_slow(THD *thd, time_t current_time, time_t query_start_arg, const char *user_host, uint user_host_len, - longlong query_time, longlong lock_time, bool is_command, + ulonglong query_utime, ulonglong lock_utime, bool is_command, const char *sql_text, uint sql_text_len) { return mysql_slow_log.write(thd, current_time, query_start_arg, user_host, user_host_len, - query_time, lock_time, is_command, + query_utime, lock_utime, is_command, sql_text, sql_text_len); } @@ -774,10 +775,10 @@ bool LOGGER::error_log_print(enum loglevel level, const char *format, va_list args) { bool error= FALSE; - Log_event_handler **current_handler= error_log_handler_list; + Log_event_handler **current_handler; /* currently we don't need locking here as there is no error_log table */ - while (*current_handler) + for (current_handler= error_log_handler_list ; *current_handler ;) error= (*current_handler++)->log_error(level, format, args) || error; return error; @@ -904,28 +905,27 @@ bool LOGGER::flush_logs(THD *thd) SYNOPSIS slow_log_print() - thd THD of the query being logged - query The query being logged - query_length The length of the query string - query_start_arg Query start timestamp + thd THD of the query being logged + query The query being logged + query_length The length of the query string + current_utime Current time in microseconds (from undefined start) RETURN - FALSE - OK - TRUE - error occured + FALSE OK + TRUE error occured */ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length, - time_t query_start_arg) + ulonglong current_utime) + { bool error= FALSE; - Log_event_handler **current_handler= slow_log_handler_list; + Log_event_handler **current_handler; bool is_command= FALSE; char user_host_buff[MAX_USER_HOST_SIZE]; - - time_t current_time; Security_context *sctx= thd->security_ctx; uint user_host_len= 0; - longlong query_time= 0, lock_time= 0; + ulonglong query_utime, lock_utime; /* Print the message to the buffer if we have slow log enabled @@ -933,10 +933,10 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length, if (*slow_log_handler_list) { - current_time= time(NULL); + time_t current_time; /* do not log slow queries from replication threads */ - if (thd->slave_thread) + if (thd->slave_thread && !opt_log_slow_slave_statements) return 0; lock(); @@ -947,17 +947,22 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length, } /* fill in user_host value: the format is "%s[%s] @ %s [%s]" */ - user_host_len= strxnmov(user_host_buff, MAX_USER_HOST_SIZE, - sctx->priv_user ? sctx->priv_user : "", "[", - sctx->user ? sctx->user : "", "] @ ", - sctx->host ? sctx->host : "", " [", - sctx->ip ? sctx->ip : "", "]", NullS) - - user_host_buff; - - if (query_start_arg) + user_host_len= (strxnmov(user_host_buff, MAX_USER_HOST_SIZE, + sctx->priv_user ? sctx->priv_user : "", "[", + sctx->user ? sctx->user : "", "] @ ", + sctx->host ? sctx->host : "", " [", + sctx->ip ? sctx->ip : "", "]", NullS) - + user_host_buff); + + current_time= my_time_possible_from_micro(current_utime); + if (thd->start_utime) + { + query_utime= (current_utime - thd->start_utime); + lock_utime= (thd->utime_after_lock - thd->start_utime); + } + else { - query_time= (longlong) (current_time - query_start_arg); - lock_time= (longlong) (thd->time_after_lock - query_start_arg); + query_utime= lock_utime= 0; } if (!query) @@ -967,10 +972,10 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length, query_length= command_name[thd->command].length; } - while (*current_handler) - error= (*current_handler++)->log_slow(thd, current_time, query_start_arg, + for (current_handler= slow_log_handler_list; *current_handler ;) + error= (*current_handler++)->log_slow(thd, current_time, thd->start_time, user_host_buff, user_host_len, - query_time, lock_time, is_command, + query_utime, lock_utime, is_command, query, query_length) || error; unlock(); @@ -995,7 +1000,7 @@ bool LOGGER::general_log_print(THD *thd, enum enum_server_command command, Security_context *sctx= thd->security_ctx; ulong id; uint message_buff_len= 0, user_host_len= 0; - + time_t current_time; if (thd) { /* Normal thread */ if ((thd->options & OPTION_LOG_OFF) @@ -1017,8 +1022,6 @@ bool LOGGER::general_log_print(THD *thd, enum enum_server_command command, unlock(); return 0; } - time_t current_time= time(NULL); - user_host_len= strxnmov(user_host_buff, MAX_USER_HOST_SIZE, sctx->priv_user ? sctx->priv_user : "", "[", sctx->user ? sctx->user : "", "] @ ", @@ -1033,6 +1036,7 @@ bool LOGGER::general_log_print(THD *thd, enum enum_server_command command, else message_buff[0]= '\0'; + current_time= my_time(0); while (*current_handler) error+= (*current_handler++)-> log_general(current_time, user_host_buff, @@ -2165,8 +2169,8 @@ err: user_host the pointer to the string with user@host info user_host_len length of the user_host string. this is computed once and passed to all general log event handlers - query_time Amount of time the query took to execute (in seconds) - lock_time Amount of time the query was locked (in seconds) + query_utime Amount of time the query took to execute (in microseconds) + lock_utime Amount of time the query was locked (in microseconds) is_command The flag, which determines, whether the sql_text is a query or an administrator command. sql_text the very text of the query or administrator command @@ -2184,8 +2188,8 @@ err: bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, time_t query_start_arg, const char *user_host, - uint user_host_len, longlong query_time, - longlong lock_time, bool is_command, + uint user_host_len, ulonglong query_utime, + ulonglong lock_utime, bool is_command, const char *sql_text, uint sql_text_len) { bool error= 0; @@ -2198,6 +2202,7 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, { // Safety agains reopen int tmp_errno= 0; char buff[80], *end; + char query_time_buff[22+7], lock_time_buff[22+7]; uint buff_len; end= buff; @@ -2228,10 +2233,12 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, tmp_errno= errno; } /* For slow query log */ + sprintf(query_time_buff, "%.6f", ulonglong2double(query_utime)/1000000.0); + sprintf(lock_time_buff, "%.6f", ulonglong2double(lock_utime)/1000000.0); if (my_b_printf(&log_file, - "# Query_time: %lu Lock_time: %lu" + "# Query_time: %s Lock_time: %s" " Rows_sent: %lu Rows_examined: %lu\n", - (ulong) query_time, (ulong) lock_time, + query_time_buff, lock_time_buff, (ulong) thd->sent_row_count, (ulong) thd->examined_row_count) == (uint) -1) tmp_errno= errno; @@ -3872,9 +3879,9 @@ int error_log_print(enum loglevel level, const char *format, bool slow_log_print(THD *thd, const char *query, uint query_length, - time_t query_start_arg) + ulonglong current_utime) { - return logger.slow_log_print(thd, query, query_length, query_start_arg); + return logger.slow_log_print(thd, query, query_length, current_utime); } @@ -3902,7 +3909,7 @@ void MYSQL_BIN_LOG::rotate_and_purge(uint flags) #ifdef HAVE_REPLICATION if (expire_logs_days) { - time_t purge_time= time(0) - expire_logs_days*24*60*60; + time_t purge_time= my_time(0) - expire_logs_days*24*60*60; if (purge_time >= 0) purge_logs_before_date(purge_time); } @@ -4499,7 +4506,7 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer) VOID(pthread_mutex_lock(&LOCK_error_log)); - skr=time(NULL); + skr= my_time(0); localtime_r(&skr, &tm_tmp); start=&tm_tmp; diff --git a/sql/log.h b/sql/log.h index d92e0117bcc..2a796ef89e7 100644 --- a/sql/log.h +++ b/sql/log.h @@ -198,7 +198,7 @@ public: const char *sql_text, uint sql_text_len); bool write(THD *thd, time_t current_time, time_t query_start_arg, const char *user_host, uint user_host_len, - longlong query_time, longlong lock_time, bool is_command, + ulonglong query_utime, ulonglong lock_utime, bool is_command, const char *sql_text, uint sql_text_len); bool open_slow_log(const char *log_name) { @@ -393,8 +393,8 @@ public: virtual bool log_slow(THD *thd, time_t current_time, time_t query_start_arg, const char *user_host, - uint user_host_len, longlong query_time, - longlong lock_time, bool is_command, + uint user_host_len, ulonglong query_utime, + ulonglong lock_utime, bool is_command, const char *sql_text, uint sql_text_len)= 0; virtual bool log_error(enum loglevel level, const char *format, va_list args)= 0; @@ -442,8 +442,8 @@ public: virtual bool log_slow(THD *thd, time_t current_time, time_t query_start_arg, const char *user_host, - uint user_host_len, longlong query_time, - longlong lock_time, bool is_command, + uint user_host_len, ulonglong query_utime, + ulonglong lock_utime, bool is_command, const char *sql_text, uint sql_text_len); virtual bool log_error(enum loglevel level, const char *format, va_list args); @@ -479,8 +479,8 @@ public: virtual bool log_slow(THD *thd, time_t current_time, time_t query_start_arg, const char *user_host, - uint user_host_len, longlong query_time, - longlong lock_time, bool is_command, + uint user_host_len, ulonglong query_utime, + ulonglong lock_utime, bool is_command, const char *sql_text, uint sql_text_len); virtual bool log_error(enum loglevel level, const char *format, va_list args); @@ -564,7 +564,7 @@ public: bool error_log_print(enum loglevel level, const char *format, va_list args); bool slow_log_print(THD *thd, const char *query, uint query_length, - time_t query_start_arg); + ulonglong current_utime); bool general_log_print(THD *thd,enum enum_server_command command, const char *format, va_list args); diff --git a/sql/log_event.cc b/sql/log_event.cc index c062aa99b4e..db8729c8318 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -456,7 +456,7 @@ Log_event::Log_event() thd(0) { server_id= ::server_id; - when= time(NULL); + when= my_time(0); log_pos= 0; } #endif /* !MYSQL_CLIENT */ @@ -2073,7 +2073,7 @@ int Query_log_event::do_apply_event(RELAY_LOG_INFO const *rli, /* Execute the query (note that we bypass dispatch_command()) */ const char* found_semicolon= NULL; mysql_parse(thd, thd->query, thd->query_length, &found_semicolon); - + log_slow_statement(thd); } else { @@ -4349,7 +4349,7 @@ int User_var_log_event::do_apply_event(RELAY_LOG_INFO const *rli) switch (type) { case REAL_RESULT: float8get(real_val, val); - it= new Item_float(real_val); + it= new Item_float(real_val, 0); val= (char*) &real_val; // Pointer to value in native format val_len= 8; break; @@ -6173,7 +6173,7 @@ int Rows_log_event::do_apply_event(RELAY_LOG_INFO const *rli) problem. When WL#2975 is implemented, just remove the member st_relay_log_info::last_event_start_time and all its occurences. */ - const_cast<RELAY_LOG_INFO*>(rli)->last_event_start_time= time(0); + const_cast<RELAY_LOG_INFO*>(rli)->last_event_start_time= my_time(0); } DBUG_RETURN(0); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 7b7bc81957e..0678189b388 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -167,6 +167,7 @@ public: void restore_env(THD *thd, Object_creation_ctx *backup_ctx); protected: + Object_creation_ctx() {} virtual Object_creation_ctx *create_backup_ctx(THD *thd) = 0; virtual void change_env(THD *thd) const = 0; @@ -734,7 +735,7 @@ int error_log_print(enum loglevel level, const char *format, va_list args); bool slow_log_print(THD *thd, const char *query, uint query_length, - time_t query_start_arg); + ulonglong current_utime); bool general_log_print(THD *thd, enum enum_server_command command, const char *format,...); @@ -1791,7 +1792,7 @@ extern my_bool opt_readonly, lower_case_file_system; extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs; extern my_bool opt_secure_auth; extern char* opt_secure_file_priv; -extern my_bool opt_log_slow_admin_statements; +extern my_bool opt_log_slow_admin_statements, opt_log_slow_slave_statements; extern my_bool sp_automatic_privileges, opt_noacl; extern my_bool opt_old_style_user_limits, trust_function_creators; extern uint opt_crash_binlog_innodb; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 6d22047b9db..33cd55170ea 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -338,6 +338,7 @@ static char *default_collation_name; static char *default_storage_engine_str; static char compiled_default_collation_name[]= MYSQL_DEFAULT_COLLATION_NAME; static I_List<THD> thread_cache; +static double long_query_time; static pthread_cond_t COND_thread_cache, COND_flush_thread_cache; @@ -406,6 +407,7 @@ my_bool opt_sync_frm, opt_allow_suspicious_udfs; my_bool opt_secure_auth= 0; char* opt_secure_file_priv= 0; my_bool opt_log_slow_admin_statements= 0; +my_bool opt_log_slow_slave_statements= 0; my_bool lower_case_file_system= 0; my_bool opt_large_pages= 0; my_bool opt_myisam_use_mmap= 0; @@ -1143,7 +1145,7 @@ extern "C" void unireg_abort(int exit_code) sql_print_error("Aborting\n"); else if (opt_help) usage(); - clean_up(exit_code || !opt_bootstrap); /* purecov: inspected */ + clean_up(!opt_help && (exit_code || !opt_bootstrap)); /* purecov: inspected */ DBUG_PRINT("quit",("done with cleanup in unireg_abort")); wait_for_signal_thread_to_end(); clean_up_mutexes(); @@ -1240,12 +1242,12 @@ void clean_up(bool print_message) my_regex_end(); #endif - if (print_message && errmesg) - sql_print_information(ER(ER_SHUTDOWN_COMPLETE),my_progname); #if !defined(EMBEDDED_LIBRARY) if (!opt_bootstrap) (void) my_delete(pidfile_name,MYF(0)); // This may not always exist #endif + if (print_message && errmesg && server_start_time) + sql_print_information(ER(ER_SHUTDOWN_COMPLETE),my_progname); thread_scheduler.end(); finish_client_errs(); my_free((uchar*) my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST), @@ -1797,7 +1799,7 @@ static bool cache_thread() this thread for handling of new THD object/connection. */ thd->mysys_var->abort= 0; - thd->thr_create_time= time(NULL); + thd->thr_create_utime= my_micro_time(); threads.append(thd); return(1); } @@ -2174,7 +2176,7 @@ extern "C" sig_handler handle_segfault(int sig) segfaulted = 1; - curr_time= time(NULL); + curr_time= my_time(0); localtime_r(&curr_time, &tm); fprintf(stderr,"\ @@ -2717,7 +2719,7 @@ static int init_common_variables(const char *conf_file_name, int argc, tzset(); // Set tzname max_system_variables.pseudo_thread_id= (ulong)~0; - server_start_time= time((time_t*) 0); + server_start_time= my_time(0); rpl_filter= new Rpl_filter; binlog_filter= new Rpl_filter; if (!rpl_filter || !binlog_filter) @@ -2952,7 +2954,7 @@ static int init_common_variables(const char *conf_file_name, int argc, && !(log_output_options & LOG_NONE)) sql_print_warning("Although a path was specified for the " "--log-slow-queries option, log tables are used. " - "To enable logging to files use the --log-output option."); + "To enable logging to files use the --log-output=file option."); s= opt_logname ? opt_logname : make_default_log_name(buff, ".log"); sys_var_general_log_path.value= my_strdup(s, MYF(0)); @@ -3540,7 +3542,7 @@ server."); #ifdef HAVE_REPLICATION if (opt_bin_log && expire_logs_days) { - time_t purge_time= time(0) - expire_logs_days*24*60*60; + time_t purge_time= server_start_time - expire_logs_days*24*60*60; if (purge_time >= 0) mysql_bin_log.purge_logs_before_date(purge_time); } @@ -4289,7 +4291,7 @@ void create_thread_to_handle_connection(THD *thd) thread_created++; threads.append(thd); DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id)); - thd->connect_time = time(NULL); + thd->connect_utime= thd->start_utime= my_micro_time(); if ((error=pthread_create(&thd->real_id,&connection_attrib, handle_one_connection, (void*) thd))) @@ -5076,6 +5078,8 @@ enum options_mysqld OPT_THREAD_HANDLING, OPT_INNODB_ROLLBACK_ON_TIMEOUT, OPT_SECURE_FILE_PRIV, + OPT_MIN_EXAMINED_ROW_LIMIT, + OPT_LOG_SLOW_SLAVE_STATEMENTS, OPT_OLD_MODE }; @@ -5377,8 +5381,13 @@ Disable with --skip-large-pages.", (uchar**) &opt_log_slow_admin_statements, (uchar**) &opt_log_slow_admin_statements, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"log-slow-slave-statements", OPT_LOG_SLOW_SLAVE_STATEMENTS, + "Log slow statements executed by slave thread to the slow log if it is open.", + (uchar**) &opt_log_slow_slave_statements, + (uchar**) &opt_log_slow_slave_statements, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"log-slow-queries", OPT_SLOW_QUERY_LOG, - "Log slow queries to this log file. Defaults logging to hostname-slow.log file. Must be enabled to activate other slow log options.", + "Log slow queries to a table or log file. Defaults logging to table mysql.slow_log or hostname-slow.log if --log-output=file is used. Must be enabled to activate other slow log options.", (uchar**) &opt_slow_logname, (uchar**) &opt_slow_logname, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"log-tc", OPT_LOG_TC, @@ -5967,10 +5976,10 @@ log and this option does nothing anymore.", 0, (GET_ULONG | GET_ASK_ADDR) , REQUIRED_ARG, 100, 1, 100, 0, 1, 0}, {"long_query_time", OPT_LONG_QUERY_TIME, - "Log all queries that have taken more than long_query_time seconds to execute to file.", - (uchar**) &global_system_variables.long_query_time, - (uchar**) &max_system_variables.long_query_time, 0, GET_ULONG, - REQUIRED_ARG, 10, 1, LONG_TIMEOUT, 0, 1, 0}, + "Log all queries that have taken more than long_query_time seconds to execute to file. " + "The argument will be treated as a decimal value with microsecond precission.", + (uchar**) &long_query_time, (uchar**) &long_query_time, 0, GET_DOUBLE, + REQUIRED_ARG, 10, 0, LONG_TIMEOUT, 0, 0, 0}, {"lower_case_table_names", OPT_LOWER_CASE_TABLE_NAMES, "If set to 1 table names are stored in lowercase on disk and table names will be case-insensitive. Should be set to 2 if you are using a case insensitive file system", (uchar**) &lower_case_table_names, @@ -6068,6 +6077,11 @@ The minimum value for this variable is 4096.", "After this many write locks, allow some read locks to run in between.", (uchar**) &max_write_lock_count, (uchar**) &max_write_lock_count, 0, GET_ULONG, REQUIRED_ARG, ~0L, 1, ~0L, 0, 1, 0}, + {"min_examined_row_limit", OPT_MIN_EXAMINED_ROW_LIMIT, + "Don't log queries which examine less than min_examined_row_limit rows to file.", + (uchar**) &global_system_variables.min_examined_row_limit, + (uchar**) &max_system_variables.min_examined_row_limit, 0, GET_ULONG, + REQUIRED_ARG, 0, 0, ~0L, 0, 1L, 0}, {"multi_range_count", OPT_MULTI_RANGE_COUNT, "Number of key ranges to request at once.", (uchar**) &global_system_variables.multi_range_count, @@ -6959,7 +6973,7 @@ Starts the MySQL database server\n"); printf("Usage: %s [OPTIONS]\n", my_progname); if (!opt_verbose) - puts("\nFor more help options (several pages), use mysqld --verbose --help\n"); + puts("\nFor more help options (several pages), use mysqld --verbose --help"); else { #ifdef __WIN__ @@ -6984,7 +6998,7 @@ Starts the MySQL database server\n"); puts("\n\ To see what values a running MySQL server is using, type\n\ -'mysqladmin variables' instead of 'mysqld --verbose --help'.\n"); +'mysqladmin variables' instead of 'mysqld --verbose --help'."); } } #endif /*!EMBEDDED_LIBRARY*/ @@ -7714,7 +7728,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), } return 0; } - /* Initiates DEBUG - but no debugging here ! */ + + +/* Handle arguments for multiple key caches */ static uchar* * mysql_getopt_value(const char *keyname, uint key_length, @@ -7772,9 +7788,10 @@ static void get_options(int *argc,char **argv) (*argc)++; /* add back one for the progname handle_options removes */ /* no need to do this for argv as we are discarding it. */ - if ((opt_log_slow_admin_statements || opt_log_queries_not_using_indexes) && + if ((opt_log_slow_admin_statements || opt_log_queries_not_using_indexes || + opt_log_slow_slave_statements) && !opt_slow_log) - sql_print_warning("options --log-slow-admin-statements and --log-queries-not-using-indexes have no effect if --log-slow-queries is not set"); + sql_print_warning("options --log-slow-admin-statements, --log-queries-not-using-indexes and --log-slow-slave-statements have no effect if --log-slow-queries is not set"); #if defined(HAVE_BROKEN_REALPATH) my_use_symdir=0; @@ -7818,6 +7835,10 @@ static void get_options(int *argc,char **argv) /* Set global variables based on startup options */ myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size); + /* long_query_time is in microseconds */ + global_system_variables.long_query_time= max_system_variables.long_query_time= + (longlong) (long_query_time * 1000000.0); + if (opt_short_log_format) opt_specialflag|= SPECIAL_SHORT_LOG_FORMAT; diff --git a/sql/net_serv.cc b/sql/net_serv.cc index bd273145782..1f75d7ab1d7 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -437,7 +437,7 @@ net_write_command(NET *net,uchar command, uchar buff[NET_HEADER_SIZE+1]; uint header_size=NET_HEADER_SIZE+1; DBUG_ENTER("net_write_command"); - DBUG_PRINT("enter",("length: %lu", len)); + DBUG_PRINT("enter",("length: %lu", (ulong) len)); buff[4]=command; /* For first packet */ diff --git a/sql/parse_file.cc b/sql/parse_file.cc index 5ea49396cb4..19fb11ac0cc 100644 --- a/sql/parse_file.cc +++ b/sql/parse_file.cc @@ -135,7 +135,7 @@ write_parameter(IO_CACHE *file, uchar* base, File_option *parameter, { /* string have to be allocated already */ LEX_STRING *val_s= (LEX_STRING *)(base + parameter->offset); - time_t tm= time(NULL); + time_t tm= my_time(0); get_date(val_s->str, GETDATE_DATE_TIME|GETDATE_GMT|GETDATE_FIXEDLENGTH, tm); diff --git a/sql/set_var.cc b/sql/set_var.cc index bd5234b42be..0ff561191ae 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -250,8 +250,8 @@ static sys_var_bool_ptr sys_log_queries_not_using_indexes(&vars, "log_queries_not_using_indexes", &opt_log_queries_not_using_indexes); static sys_var_thd_ulong sys_log_warnings(&vars, "log_warnings", &SV::log_warnings); -static sys_var_thd_ulong sys_long_query_time(&vars, "long_query_time", - &SV::long_query_time); +static sys_var_microseconds sys_var_long_query_time(&vars, "long_query_time", + &SV::long_query_time); static sys_var_thd_bool sys_low_priority_updates(&vars, "low_priority_updates", &SV::low_priority_updates, fix_low_priority_updates); @@ -315,6 +315,8 @@ static sys_var_thd_ulong sys_max_tmp_tables(&vars, "max_tmp_tables", &SV::max_tmp_tables); static sys_var_long_ptr sys_max_write_lock_count(&vars, "max_write_lock_count", &max_write_lock_count); +static sys_var_thd_ulong sys_min_examined_row_limit(&vars, "min_examined_row_limit", + &SV::min_examined_row_limit); static sys_var_thd_ulong sys_multi_range_count(&vars, "multi_range_count", &SV::multi_range_count); static sys_var_long_ptr sys_myisam_data_pointer_size(&vars, "myisam_data_pointer_size", @@ -1473,6 +1475,15 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base) pthread_mutex_unlock(&LOCK_global_system_variables); return new Item_int(value); } + case SHOW_DOUBLE: + { + double value; + pthread_mutex_lock(&LOCK_global_system_variables); + value= *(double*) value_ptr(thd, var_type, base); + pthread_mutex_unlock(&LOCK_global_system_variables); + /* 6, as this is for now only used with microseconds */ + return new Item_float(value, 6); + } case SHOW_HA_ROWS: { ha_rows value; @@ -2533,6 +2544,60 @@ void sys_var_thd_lc_time_names::set_default(THD *thd, enum_var_type type) } /* + Handling of microseoncds given as seconds.part_seconds + + NOTES + The argument to long query time is in seconds in decimal + which is converted to ulonglong integer holding microseconds for storage. + This is used for handling long_query_time +*/ + +bool sys_var_microseconds::update(THD *thd, set_var *var) +{ + double num= var->value->val_real(); + longlong microseconds; + if (num > (double) option_limits->max_value) + num= (double) option_limits->max_value; + if (num < (double) option_limits->min_value) + num= (double) option_limits->min_value; + microseconds= (longlong) (num * 1000000.0 + 0.5); + if (var->type == OPT_GLOBAL) + { + pthread_mutex_lock(&LOCK_global_system_variables); + (global_system_variables.*offset)= microseconds; + pthread_mutex_unlock(&LOCK_global_system_variables); + } + else + thd->variables.*offset= microseconds; + return 0; +} + + +void sys_var_microseconds::set_default(THD *thd, enum_var_type type) +{ + longlong microseconds= (longlong) (option_limits->def_value * 1000000.0); + if (type == OPT_GLOBAL) + { + pthread_mutex_lock(&LOCK_global_system_variables); + global_system_variables.*offset= microseconds; + pthread_mutex_unlock(&LOCK_global_system_variables); + } + else + thd->variables.*offset= microseconds; +} + + +uchar *sys_var_microseconds::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) +{ + thd->tmp_double_value= (double) ((type == OPT_GLOBAL) ? + global_system_variables.*offset : + thd->variables.*offset) / 1000000.0; + return (uchar*) &thd->tmp_double_value; +} + + +/* Functions to update thd->options bits */ diff --git a/sql/set_var.h b/sql/set_var.h index a998dc93b84..67ec449a02f 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -113,9 +113,10 @@ class sys_var_long_ptr_global: public sys_var_global { public: ulong *value; - sys_var_long_ptr_global(sys_var_chain *chain, const char *name_arg, ulong *value_ptr_arg, - pthread_mutex_t *guard_arg, - sys_after_update_func after_update_arg= NULL) + sys_var_long_ptr_global(sys_var_chain *chain, const char *name_arg, + ulong *value_ptr_arg, + pthread_mutex_t *guard_arg, + sys_after_update_func after_update_arg= NULL) :sys_var_global(name_arg, after_update_arg, guard_arg), value(value_ptr_arg) { chain_sys_var(chain); } @@ -911,6 +912,27 @@ public: uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; + +class sys_var_microseconds :public sys_var_thd +{ + ulonglong SV::*offset; +public: + sys_var_microseconds(sys_var_chain *chain, const char *name_arg, + ulonglong SV::*offset_arg): + sys_var_thd(name_arg), offset(offset_arg) + { chain_sys_var(chain); } + bool check(THD *thd, set_var *var) {return 0;} + bool update(THD *thd, set_var *var); + void set_default(THD *thd, enum_var_type type); + SHOW_TYPE show_type() { return SHOW_DOUBLE; } + bool check_update_type(Item_result type) + { + return (type != INT_RESULT && type != REAL_RESULT && type != DECIMAL_RESULT); + } + uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); +}; + + class sys_var_trust_routine_creators :public sys_var_bool_ptr { /* We need a derived class only to have a warn_deprecated() */ diff --git a/sql/slave.cc b/sql/slave.cc index 2e8e3f582de..6fb7d666703 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1460,6 +1460,7 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) thd->variables.max_allowed_packet= global_system_variables.max_allowed_packet + MAX_LOG_EVENT_HEADER; /* note, incr over the global not session var */ thd->slave_thread = 1; + thd->enable_slow_log= opt_log_slow_slave_statements; set_slave_thread_options(thd); thd->client_capabilities = CLIENT_LOCAL_FILES; pthread_mutex_lock(&LOCK_thread_count); @@ -1491,7 +1492,7 @@ static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed, DBUG_ENTER("safe_sleep"); thr_alarm_init(&alarmed); - time_t start_time= time((time_t*) 0); + time_t start_time= my_time(0); time_t end_time= start_time+sec; while ((nap_time= (int) (end_time - start_time)) > 0) @@ -1508,7 +1509,7 @@ static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed, if ((*thread_killed)(thd,thread_killed_arg)) DBUG_RETURN(1); - start_time=time((time_t*) 0); + start_time= my_time(0); } DBUG_RETURN(0); } @@ -1796,7 +1797,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) thd->set_time(); // time the query thd->lex->current_select= 0; if (!ev->when) - ev->when = time(NULL); + ev->when= my_time(0); ev->thd = thd; // because up to this point, ev->thd == 0 int reason= ev->shall_skip(rli); diff --git a/sql/sql_cache.h b/sql/sql_cache.h index c4c7e1dbc5e..645807eecbf 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -142,6 +142,7 @@ struct Query_cache_query uint8 tbls_type; unsigned int last_pkt_nr; + Query_cache_query() {} /* Remove gcc warning */ inline void init_n_lock(); void unlock_n_destroy(); inline ulonglong found_rows() { return limit_found_rows; } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index da975ee3103..4fe68721ae5 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -407,7 +407,8 @@ THD::THD() // Must be reset to handle error with THD's created for init of mysqld lex->current_select= 0; start_time=(time_t) 0; - time_after_lock=(time_t) 0; + start_utime= 0L; + utime_after_lock= 0L; current_linfo = 0; slave_thread = 0; bzero(&variables, sizeof(variables)); diff --git a/sql/sql_class.h b/sql/sql_class.h index 7fa66893f69..6c3400ef08c 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -249,18 +249,19 @@ struct system_variables ulonglong myisam_max_sort_file_size; ulonglong max_heap_table_size; ulonglong tmp_table_size; + ulonglong long_query_time; ha_rows select_limit; ha_rows max_join_size; ulong auto_increment_increment, auto_increment_offset; ulong bulk_insert_buff_size; ulong join_buff_size; - ulong long_query_time; ulong max_allowed_packet; ulong max_error_count; ulong max_length_for_sort_data; ulong max_sort_length; ulong max_tmp_tables; ulong max_insert_delayed_threads; + ulong min_examined_row_limit; ulong multi_range_count; ulong myisam_repair_threads; ulong myisam_sort_buff_size; @@ -1025,8 +1026,6 @@ public: Security_context main_security_ctx; Security_context *security_ctx; - /* remote (peer) port */ - uint16 peer_port; /* Points to info-string that we show in SHOW PROCESSLIST You are supposed to update thd->proc_info only if you have coded @@ -1034,6 +1033,14 @@ public: */ const char *proc_info; + /* + 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; + + double tmp_double_value; /* Used in set_var.cc */ ulong client_capabilities; /* What the client supports */ ulong max_client_packet_length; @@ -1055,14 +1062,12 @@ 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 + /* remote (peer) port */ + uint16 peer_port; + time_t start_time, user_time; + ulonglong connect_utime, thr_create_utime; // track down slow pthread_create + ulonglong start_utime, utime_after_lock; + thr_lock_type update_lock_default; Delayed_insert *di; @@ -1570,27 +1575,25 @@ public: proc_info = old_msg; pthread_mutex_unlock(&mysys_var->mutex); } - - static inline void safe_time(time_t *t) + inline time_t query_start() { query_start_used=1; return start_time; } + inline void set_time() { - /** - Wrapper around time() which retries on error (-1) - - @details - This is needed because, despite the documentation, time() may fail - in some circumstances. Here we retry time() until it succeeds, and - log the failure so that performance problems related to this can be - identified. - */ - while(unlikely(time(t) == ((time_t) -1))) - sql_print_information("time() failed with %d", errno); + if (user_time) + { + start_time= user_time; + start_utime= utime_after_lock= my_micro_time(); + } + else + start_utime= utime_after_lock= my_micro_time_and_time(&start_time); } - - inline time_t query_start() { query_start_used=1; return start_time; } - inline void set_time() { if (user_time) start_time=time_after_lock=user_time; else { safe_time(&start_time); time_after_lock= start_time; }} - inline void end_time() { safe_time(&start_time); } - inline void set_time(time_t t) { time_after_lock=start_time=user_time=t; } - inline void lock_time() { safe_time(&time_after_lock); } + inline void set_current_time() { start_time= my_time(MY_WME); } + inline void set_time(time_t t) + { + start_time= user_time= t; + start_utime= utime_after_lock= my_micro_time(); + } + void set_time_after_lock() { utime_after_lock= my_micro_time(); } + ulonglong current_utime() { return my_micro_time(); } inline ulonglong found_rows(void) { return limit_found_rows; diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 26b7098e27c..03b9908c1ad 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -97,7 +97,7 @@ static int get_or_create_user_conn(THD *thd, const char *user, uc->len= temp_len; uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0; uc->user_resources= *mqh; - uc->intime= thd->thr_create_time; + uc->reset_utime= thd->thr_create_utime; if (my_hash_insert(&hash_user_connections, (uchar*) uc)) { my_free((char*) uc,0); @@ -223,16 +223,16 @@ void decrease_user_connections(USER_CONN *uc) void time_out_user_resource_limits(THD *thd, USER_CONN *uc) { - time_t check_time = thd->start_time ? thd->start_time : time(NULL); + ulonglong check_time= thd->start_utime; DBUG_ENTER("time_out_user_resource_limits"); /* If more than a hour since last check, reset resource checking */ - if (check_time - uc->intime >= 3600) + if (check_time - uc->reset_utime >= LL(3600000000)) { uc->questions=1; uc->updates=0; uc->conn_per_hour=0; - uc->intime=check_time; + uc->reset_utime= check_time; } DBUG_VOID_RETURN; @@ -1053,8 +1053,8 @@ void prepare_new_connection_state(THD* thd) pthread_handler_t handle_one_connection(void *arg) { THD *thd= (THD*) arg; - uint launch_time = - (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time); + ulong launch_time= (ulong) ((thd->thr_create_utime= my_micro_time()) - + thd->connect_utime); if (thread_scheduler.init_new_connection_thread()) { @@ -1063,7 +1063,7 @@ pthread_handler_t handle_one_connection(void *arg) thread_scheduler.end_thread(thd,0); return 0; } - if (launch_time >= slow_launch_time) + if (launch_time >= slow_launch_time*1000000L) statistic_increment(slow_launch_threads,&LOCK_status); /* diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index b14241bbef3..12483044cb9 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2196,7 +2196,7 @@ pthread_handler_t handle_delayed_insert(void *arg) /* Add thread to THD list so that's it's visible in 'show processlist' */ pthread_mutex_lock(&LOCK_thread_count); thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; - thd->end_time(); + thd->set_current_time(); threads.append(thd); thd->killed=abort_loop ? THD::KILL_CONNECTION : THD::NOT_KILLED; pthread_mutex_unlock(&LOCK_thread_count); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f2a61b7f7c5..a13e3d3f624 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1297,7 +1297,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, void log_slow_statement(THD *thd) { - time_t start_of_query; DBUG_ENTER("log_slow_statement"); /* @@ -1308,25 +1307,24 @@ void log_slow_statement(THD *thd) if (unlikely(thd->in_sub_stmt)) DBUG_VOID_RETURN; // Don't set time for sub stmt - start_of_query= thd->start_time; - thd->end_time(); // Set start time - /* Do not log administrative statements unless the appropriate option is set; do not log into slow log if reading from backup. */ if (thd->enable_slow_log && !thd->user_time) { - thd->proc_info="logging slow query"; + ulonglong end_utime_of_query= thd->current_utime(); - if ((ulong) (thd->start_time - thd->time_after_lock) > - thd->variables.long_query_time || - ((thd->server_status & - (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && - opt_log_queries_not_using_indexes)) + thd->proc_info="logging slow query"; + if (((end_utime_of_query - thd->utime_after_lock) > + thd->variables.long_query_time || + ((thd->server_status & + (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && + opt_log_queries_not_using_indexes)) && + thd->examined_row_count >= thd->variables.min_examined_row_limit) { thd->status_var.long_query_count++; - slow_log_print(thd, thd->query, thd->query_length, start_of_query); + slow_log_print(thd, thd->query, thd->query_length, end_utime_of_query); } } DBUG_VOID_RETURN; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6c7949fc8d7..b3203592cbe 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15508,15 +15508,11 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, /* Add "filtered" field to item_list. */ if (join->thd->lex->describe & DESCRIBE_EXTENDED) { - Item_float *filtered; - float f; + float f= 0.0; if (examined_rows) f= (float) (100.0 * join->best_positions[i].records_read / examined_rows); - else - f= 0.0; - item_list.push_back((filtered= new Item_float(f))); - filtered->decimals= 2; + item_list.push_back(new Item_float(f, 2)); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5b8cb93baab..6c5a408f2c8 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1663,11 +1663,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) if (mysys_var) pthread_mutex_unlock(&mysys_var->mutex); -#ifdef EXTRA_DEBUG - thd_info->start_time= tmp->time_after_lock; -#else thd_info->start_time= tmp->start_time; -#endif thd_info->query=0; if (tmp->query) { @@ -1686,7 +1682,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) VOID(pthread_mutex_unlock(&LOCK_thread_count)); thread_info *thd_info; - time_t now= time(0); + time_t now= my_time(0); while ((thd_info=thread_infos.get())) { protocol->prepare_for_resend(); @@ -1716,7 +1712,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) TABLE *table= tables->table; CHARSET_INFO *cs= system_charset_info; char *user; - time_t now= time(0); + time_t now= my_time(0); DBUG_ENTER("fill_process_list"); user= thd->security_ctx->master_access & PROCESS_ACL ? @@ -2069,11 +2065,11 @@ static bool show_status_array(THD *thd, const char *wild, */ switch (show_type) { case SHOW_DOUBLE_STATUS: - { value= ((char *) status_var + (ulong) value); - end= buff + sprintf(buff, "%f", *(double*) value); + /* fall through */ + case SHOW_DOUBLE: + end= buff + my_sprintf(buff, (buff, "%f", *(double*) value)); break; - } case SHOW_LONG_STATUS: value= ((char *) status_var + (ulong) value); /* fall through */ @@ -2083,6 +2079,7 @@ static bool show_status_array(THD *thd, const char *wild, break; case SHOW_LONGLONG_STATUS: value= ((char *) status_var + (ulonglong) value); + /* fall through */ case SHOW_LONGLONG: end= longlong10_to_str(*(longlong*) value, buff, 10); break; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index dc3e72554fa..0ed7ebe631f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -54,6 +54,20 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, HA_CREATE_INFO *create_info, Alter_info *alter_info); +#ifndef DBUG_OFF + +/* Wait until we get a 'mysql_kill' signal */ + +static void wait_for_kill_signal(THD *thd) +{ + while (thd->killed == 0) + sleep(1); + // Reset signal and continue as if nothing happend + thd->killed= THD::NOT_KILLED; +} +#endif + + /* Translate a file name to a table name (WL #1324). @@ -4111,6 +4125,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG); thd->exit_cond(old_message); + DBUG_EXECUTE_IF("wait_in_mysql_admin_table", wait_for_kill_signal(thd);); if (thd->killed) goto err; /* Flush entries in the query cache involving this table. */ diff --git a/sql/structs.h b/sql/structs.h index da2339d27f8..09a3c4d7285 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -209,6 +209,11 @@ typedef struct user_conn { char *user; /* Pointer to host part of the key. */ char *host; + /* + The moment of time when per hour counters were reset last time + (i.e. start of "hour" for conn_per_hour, updates, questions counters). + */ + ulonglong reset_utime; /* Total length of the key. */ uint len; /* Current amount of concurrent connections for this account. */ @@ -220,11 +225,6 @@ typedef struct user_conn { uint conn_per_hour, updates, questions; /* Maximum amount of resources which account is allowed to consume. */ USER_RESOURCES user_resources; - /* - The moment of time when per hour counters were reset last time - (i.e. start of "hour" for conn_per_hour, updates, questions counters). - */ - time_t intime; } USER_CONN; /* Bits in form->update */ |