diff --git a/COPYING.innodb-deadlock-count-patch b/COPYING.innodb-deadlock-count-patch new file mode 100644 index 000000000000..d2efce408da4 --- /dev/null +++ b/COPYING.innodb-deadlock-count-patch @@ -0,0 +1,30 @@ +Portions of this software contain modifications contributed by Eric Bergen. +These contributions are used with the following license: + +Copyright (c) 2010, Eric Bergen. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + * Neither the name of the Eric Bergen. nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/COPYING.show_temp_51 b/COPYING.show_temp_51 new file mode 100644 index 000000000000..b3bb261bed15 --- /dev/null +++ b/COPYING.show_temp_51 @@ -0,0 +1,13 @@ +Portions of this software contain modifications contributed by Venu Anuganti. +These contributions are used with the following license: + +Copyright (c) 2010, Venu Anuganti, http://venublog.com/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile new file mode 100644 index 000000000000..810e1a8abeb5 --- /dev/null +++ b/Makefile @@ -0,0 +1,53 @@ +FETCH_CMD=wget +MASTER_SITE=http://www.percona.com/downloads/community +MYSQL_VERSION=5.5.7-rc +PERCONA_SERVER ?=Percona-Server +DEBUG_DIR ?= $(PERCONA_SERVER)-debug +RELEASE_DIR ?= $(PERCONA_SERVER)-release +CMAKE=CFLAGS="-O2 -g -fmessage-length=0 -D_FORTIFY_SOURCE=2" CXXFLAGS="-O2 -g -fmessage-length=0 -D_FORTIFY_SOURCE=2" cmake + +all: main install-lic tests misc + @echo "" + @echo "Percona Server source code is ready" + @echo "Now change directory to $(PERCONA_SERVER) define variables as show below" + @echo "" + export CFLAGS="-O2 -g -fmessage-length=0 -D_FORTIFY_SOURCE=2" + export CXXFLAGS="-O2 -g -fmessage-length=0 -D_FORTIFY_SOURCE=2" + export LIBS=-lrt + @echo "" + @echo "and run ./configure ... --without-plugin-innobase --with-plugin-innodb_plugin && make all install" + @echo "" + +cmake: + rm -rf $(DEBUG_DIR) + rm -rf $(RELEASE_DIR) + (mkdir -p $(DEBUG_DIR); cd $(DEBUG_DIR); $(CMAKE) -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DWITH_DEBUG=Full ../$(PERCONA_SERVER)) + (mkdir -p $(RELEASE_DIR); cd $(RELEASE_DIR); $(CMAKE) -G "Unix Makefiles" ../$(PERCONA_SERVER)) + +install-lic: + @echo "Installing license files" + install -m 644 COPYING.* $(PERCONA_SERVER) + +main: mysql-$(MYSQL_VERSION).tar.gz + @echo "Prepare Percona Server sources" + rm -rf mysql-$(MYSQL_VERSION) + rm -rf $(PERCONA_SERVER); + tar zxf mysql-$(MYSQL_VERSION).tar.gz + mv mysql-$(MYSQL_VERSION) $(PERCONA_SERVER) + (cat `cat series`) | patch -p1 -d $(PERCONA_SERVER) + rm $(PERCONA_SERVER)/sql/sql_yacc.cc $(PERCONA_SERVER)/sql/sql_yacc.h + +mysql-$(MYSQL_VERSION).tar.gz: + @echo "Downloading MySQL sources from $(MASTER_SITE)" + $(FETCH_CMD) $(MASTER_SITE)/mysql-$(MYSQL_VERSION).tar.gz + +tests: + ./install_tests.sh + +misc: + @echo "Installing other files" + install -m 644 lrusort.py $(PERCONA_SERVER)/scripts + +clean: env + rm -rf mysql-$(MYSQL_VERSION) $(PERCONA_SERVER) + rm -f mysql-$(MYSQL_VERSION).tar.gz diff --git a/bug580324.patch b/bug580324.patch new file mode 100644 index 000000000000..02c7d122ab75 --- /dev/null +++ b/bug580324.patch @@ -0,0 +1,105 @@ +# name : bug580324.patch +# introduced : 11 or before +# maintainer : Oleg +# +#!!! notice !!! +# Any small change to this file in the main branch +# should be done or reviewed by the maintainer! +diff -ruN a/sql/sql_base.cc b/sql/sql_base.cc +--- a/sql/sql_base.cc 2010-05-27 19:54:18.000000000 +0400 ++++ b/sql/sql_base.cc 2010-05-27 19:55:20.000000000 +0400 +@@ -233,8 +233,12 @@ + uint create_table_def_key(THD *thd, char *key, TABLE_LIST *table_list, + bool tmp_table) + { +- uint key_length= (uint) (strmov(strmov(key, table_list->db)+1, +- table_list->table_name)-key)+1; ++ char *db_end= strnmov(key, table_list->db, MAX_DBKEY_LENGTH - 2); ++ *db_end++= '\0'; ++ char *table_end= strnmov(db_end, table_list->table_name, ++ key + MAX_DBKEY_LENGTH - 1 - db_end); ++ *table_end++= '\0'; ++ uint key_length= (uint) (table_end-key); + if (tmp_table) + { + int4store(key + key_length, thd->server_id); +diff -ruN a/sql/sql_parse.cc b/sql/sql_parse.cc +--- a/sql/sql_parse.cc 2010-05-27 19:54:18.000000000 +0400 ++++ b/sql/sql_parse.cc 2010-05-27 20:03:20.000000000 +0400 +@@ -1326,10 +1326,12 @@ + break; + #else + { +- char *fields, *packet_end= packet + packet_length, *arg_end; ++ char *fields, *packet_end= packet + packet_length, *wildcard; + /* Locked closure of all tables */ + TABLE_LIST table_list; +- LEX_STRING conv_name; ++ char db_buff[NAME_LEN+1]; ++ uint32 db_length; ++ uint dummy_errors; + + /* used as fields initializator */ + lex_start(thd); +@@ -1341,26 +1343,22 @@ + /* + We have name + wildcard in packet, separated by endzero + */ +- arg_end= strend(packet); +- uint arg_length= arg_end - packet; +- +- /* Check given table name length. */ +- if (arg_length >= packet_length || arg_length > NAME_LEN) ++ wildcard= strend(packet); ++ db_length= wildcard - packet; ++ wildcard++; ++ uint query_length= (uint) (packet_end - wildcard); // Don't count end \0 ++ if (db_length > NAME_LEN || query_length > NAME_LEN) + { + my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); + break; + } +- thd->convert_string(&conv_name, system_charset_info, +- packet, arg_length, thd->charset()); +- if (check_table_name(conv_name.str, conv_name.length, FALSE)) +- { +- /* this is OK due to convert_string() null-terminating the string */ +- my_error(ER_WRONG_TABLE_NAME, MYF(0), conv_name.str); ++ db_length= copy_and_convert(db_buff, sizeof(db_buff)-1, ++ system_charset_info, packet, db_length, ++ thd->charset(), &dummy_errors); ++ db_buff[db_length]= '\0'; ++ table_list.alias= table_list.table_name= db_buff; ++ if (!(fields= (char *) thd->memdup(wildcard, query_length + 1))) + break; +- } +- +- table_list.alias= table_list.table_name= conv_name.str; +- packet= arg_end + 1; + + if (is_schema_db(table_list.db, table_list.db_length)) + { +@@ -1369,9 +1367,6 @@ + table_list.schema_table= schema_table; + } + +- uint query_length= (uint) (packet_end - packet); // Don't count end \0 +- if (!(fields= (char *) thd->memdup(packet, query_length + 1))) +- break; + thd->set_query(fields, query_length); + general_log_print(thd, command, "%s %s", table_list.table_name, fields); + if (lower_case_table_names) +diff -ruN a/strings/ctype-utf8.c b/strings/ctype-utf8.c +--- a/strings/ctype-utf8.c 2010-05-06 19:28:05.000000000 +0400 ++++ b/strings/ctype-utf8.c 2010-05-27 20:04:20.000000000 +0400 +@@ -4116,6 +4116,10 @@ + { + int code; + char hex[]= "0123456789abcdef"; ++ ++ if (s >= e) ++ return MY_CS_TOOSMALL; ++ + if (wc < 128 && filename_safe_char[wc]) + { + *s= (uchar) wc; diff --git a/bugfix48929.patch b/bugfix48929.patch new file mode 100644 index 000000000000..8da8b6216316 --- /dev/null +++ b/bugfix48929.patch @@ -0,0 +1,177 @@ +# name : bugfix48929.patch +# introduced : 11 or before +# maintainer : Oleg +# +#!!! notice !!! +# Any small change to this file in the main branch +# should be done or reviewed by the maintainer! +diff -ruN a/configure.in b/configure.in +--- a/configure.in 2010-07-07 03:33:05.008972002 +0400 ++++ b/configure.in 2010-07-07 03:33:05.788972002 +0400 +@@ -808,7 +808,7 @@ + AC_HEADER_STDC + AC_HEADER_SYS_WAIT + AC_CHECK_HEADERS(fcntl.h fenv.h float.h floatingpoint.h fpu_control.h \ +- ieeefp.h limits.h memory.h pwd.h select.h \ ++ ieeefp.h limits.h memory.h pwd.h select.h poll.h \ + stdlib.h stddef.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 \ +diff -ruN a/configure b/configure +--- a/configure 2010-07-26 18:29:12.172114128 +0900 ++++ b/configure 2010-07-26 20:44:59.199030524 +0900 +@@ -21524,7 +21524,7 @@ + + + for ac_header in fcntl.h fenv.h float.h floatingpoint.h fpu_control.h \ +- ieeefp.h limits.h memory.h pwd.h select.h \ ++ ieeefp.h limits.h memory.h pwd.h select.h poll.h \ + stdlib.h stddef.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 \ +diff -ruN a/include/config.h.in b/include/config.h.in +--- a/include/config.h.in 2010-07-26 18:29:12.192113524 +0900 ++++ b/include/config.h.in 2010-07-26 20:46:08.265182869 +0900 +@@ -599,6 +599,9 @@ + /* Define to 1 if you have the `poll' function. */ + #undef HAVE_POLL + ++/* Define to 1 if you have the header file. */ ++#undef HAVE_POLL_H ++ + /* Define to 1 if you have the `port_create' function. */ + #undef HAVE_PORT_CREATE + +diff -ruN a/sql/mysqld.cc b/sql/mysqld.cc +--- a/sql/mysqld.cc 2010-07-07 03:33:05.278972002 +0400 ++++ b/sql/mysqld.cc 2010-07-07 03:33:05.788972002 +0400 +@@ -55,6 +55,10 @@ + #include "sp_rcontext.h" + #include "sp_cache.h" + ++#ifdef HAVE_POLL_H ++#include ++#endif ++ + #define mysqld_charset &my_charset_latin1 + + #ifdef HAVE_purify +@@ -5108,28 +5112,49 @@ + { + my_socket sock,new_sock; + uint error_count=0; +- uint max_used_connection= (uint) (max(ip_sock,unix_sock)+1); +- fd_set readFDs,clientFDs; + THD *thd; + struct sockaddr_in cAddr; +- int ip_flags=0,socket_flags=0,flags; ++ int ip_flags=0,socket_flags=0,flags,retval; + st_vio *vio_tmp; ++#ifdef HAVE_POLL ++ int socket_count= 0; ++ struct pollfd fds[2]; // for ip_sock and unix_sock ++#else ++ fd_set readFDs,clientFDs; ++ uint max_used_connection= (uint) (max(ip_sock,unix_sock)+1); ++#endif ++ + DBUG_ENTER("handle_connections_sockets"); + + LINT_INIT(new_sock); + + (void) my_pthread_getprio(pthread_self()); // For debugging + ++#ifndef HAVE_POLL + FD_ZERO(&clientFDs); ++#endif ++ + if (ip_sock != INVALID_SOCKET) + { ++#ifdef HAVE_POLL ++ fds[socket_count].fd= ip_sock; ++ fds[socket_count].events= POLLIN; ++ socket_count++; ++#else + FD_SET(ip_sock,&clientFDs); ++#endif + #ifdef HAVE_FCNTL + ip_flags = fcntl(ip_sock, F_GETFL, 0); + #endif + } + #ifdef HAVE_SYS_UN_H ++#ifdef HAVE_POLL ++ fds[socket_count].fd= unix_sock; ++ fds[socket_count].events= POLLIN; ++ socket_count++; ++#else + FD_SET(unix_sock,&clientFDs); ++#endif + #ifdef HAVE_FCNTL + socket_flags=fcntl(unix_sock, F_GETFL, 0); + #endif +@@ -5139,12 +5164,15 @@ + MAYBE_BROKEN_SYSCALL; + while (!abort_loop) + { +- readFDs=clientFDs; +-#ifdef HPUX10 +- if (select(max_used_connection,(int*) &readFDs,0,0,0) < 0) +- continue; ++#ifdef HAVE_POLL ++ retval= poll(fds, socket_count, -1); + #else +- if (select((int) max_used_connection,&readFDs,0,0,0) < 0) ++ readFDs=clientFDs; ++ ++ retval= select((int) max_used_connection,&readFDs,0,0,0); ++#endif ++ ++ if (retval < 0) + { + if (socket_errno != SOCKET_EINTR) + { +@@ -5154,7 +5182,7 @@ + MAYBE_BROKEN_SYSCALL + continue; + } +-#endif /* HPUX10 */ ++ + if (abort_loop) + { + MAYBE_BROKEN_SYSCALL; +@@ -5162,6 +5190,21 @@ + } + + /* Is this a new connection request ? */ ++#ifdef HAVE_POLL ++ for (int i= 0; i < socket_count; ++i) ++ { ++ if (fds[i].revents & POLLIN) ++ { ++ sock= fds[i].fd; ++#ifdef HAVE_FCNTL ++ flags= fcntl(sock, F_GETFL, 0); ++#else ++ flags= 0; ++#endif // HAVE_FCNTL ++ break; ++ } ++ } ++#else // HAVE_POLL + #ifdef HAVE_SYS_UN_H + if (FD_ISSET(unix_sock,&readFDs)) + { +@@ -5169,11 +5212,12 @@ + flags= socket_flags; + } + else +-#endif ++#endif // HAVE_SYS_UN_H + { + sock = ip_sock; + flags= ip_flags; + } ++#endif // HAVE_POOL + + #if !defined(NO_FCNTL_NONBLOCK) + if (!(test_flags & TEST_BLOCKING)) diff --git a/ce.patch b/ce.patch new file mode 100644 index 000000000000..bc4520a60985 --- /dev/null +++ b/ce.patch @@ -0,0 +1,28 @@ +diff -ruN a/mysql-test/r/plugin_auth.result b/mysql-test/r/plugin_auth.result +--- a/mysql-test/r/plugin_auth.result 2010-11-03 03:01:12.000000000 +0500 ++++ b/mysql-test/r/plugin_auth.result 2010-11-16 10:56:04.000000000 +0500 +@@ -14,9 +14,9 @@ + test proxies_priv columns + SELECT * FROM mysql.proxies_priv; + Host User Proxied_host Proxied_user With_grant Grantor Timestamp +-localhost root 1 xx +-unknown root 1 xx +-% plug % plug_dest 0 root@localhost xx ++host root 1 xx ++host root 1 xx ++host plug % plug_dest 0 root@localhost xx + test mysql.proxies_priv; + SHOW CREATE TABLE mysql.proxies_priv; + Table Create Table +diff -ruN a/mysql-test/t/plugin_auth.test b/mysql-test/t/plugin_auth.test +--- a/mysql-test/t/plugin_auth.test 2010-11-03 03:01:12.000000000 +0500 ++++ b/mysql-test/t/plugin_auth.test 2010-11-16 10:56:22.000000000 +0500 +@@ -17,7 +17,7 @@ + + GRANT PROXY ON plug_dest TO plug; + --echo test proxies_priv columns +---replace_column 7 xx ++replace_column 1 host 7 xx; + SELECT * FROM mysql.proxies_priv; + --echo test mysql.proxies_priv; + SHOW CREATE TABLE mysql.proxies_priv; diff --git a/error_pad.patch b/error_pad.patch new file mode 100644 index 000000000000..998a59e38bb1 --- /dev/null +++ b/error_pad.patch @@ -0,0 +1,267 @@ +# name : error_pad.patch +# introduced : 12 +# maintainer : Oleg +# +#!!! notice !!! +# Any small change to this file in the main branch +# should be done or reviewed by the maintainer! +diff -ruN a/extra/comp_err.c b/extra/comp_err.c +--- a/extra/comp_err.c 2010-08-03 17:24:24.000000000 +0000 ++++ b/extra/comp_err.c 2010-09-14 16:49:28.000000000 +0000 +@@ -30,11 +30,12 @@ + #include + #include + +-#define MAX_ROWS 1000 ++#define MAX_ROWS 5000 + #define HEADER_LENGTH 32 /* Length of header in errmsg.sys */ + #define DEFAULT_CHARSET_DIR "../sql/share/charsets" + #define ER_PREFIX "ER_" + #define WARN_PREFIX "WARN_" ++#define PADD_PREFIX "PADD_" + static char *OUTFILE= (char*) "errmsg.sys"; + static char *HEADERFILE= (char*) "mysqld_error.h"; + static char *NAMEFILE= (char*) "mysqld_ername.h"; +@@ -89,6 +90,7 @@ + const char *sql_code1; /* sql state */ + const char *sql_code2; /* ODBC state */ + struct errors *next_error; /* Pointer to next error */ ++ my_bool is_padding; /* If true - padd this er_name while er_code != d_code*/ + DYNAMIC_ARRAY msg; /* All language texts for this error */ + }; + +@@ -127,6 +129,7 @@ + + + static struct languages *parse_charset_string(char *str); ++static struct errors *parse_padd_string(char *ptr, int er_count); + static struct errors *parse_error_string(char *ptr, int er_count); + static struct message *parse_message_string(struct message *new_message, + char *str); +@@ -252,6 +255,11 @@ + + for (tmp_error= error_head; tmp_error; tmp_error= tmp_error->next_error) + { ++ if (tmp_error->is_padding) ++ { ++ er_last= tmp_error->d_code; ++ continue; ++ } + /* + generating mysqld_error.h + fprintf() will automatically add \r on windows +@@ -344,12 +352,29 @@ + "language\n", tmp_error->er_name, tmp_lang->lang_short_name); + goto err; + } +- if (copy_rows(to, tmp->text, row_nr, start_pos)) ++ if (tmp_error->is_padding) + { +- fprintf(stderr, "Failed to copy rows to %s\n", outfile); +- goto err; ++ int padd_to= tmp_error->d_code; ++ char* padd_message= tmp->text; ++ while ((row_nr+er_offset) < padd_to) ++ { ++ if (copy_rows(to, padd_message,row_nr,start_pos)) ++ { ++ fprintf(stderr, "Failed to copy rows to %s\n", outfile); ++ goto err; ++ } ++ row_nr++; ++ } ++ } ++ else ++ { ++ if (copy_rows(to, tmp->text, row_nr, start_pos)) ++ { ++ fprintf(stderr, "Failed to copy rows to %s\n", outfile); ++ goto err; ++ } ++ row_nr++; + } +- row_nr++; + } + + /* continue with header of the errmsg.sys file */ +@@ -500,14 +525,26 @@ + DBUG_RETURN(0); + continue; + } +- if (is_prefix(str, ER_PREFIX) || is_prefix(str, WARN_PREFIX)) ++ if (is_prefix(str, ER_PREFIX) || is_prefix(str, WARN_PREFIX) || is_prefix(str, PADD_PREFIX)) + { +- if (!(current_error= parse_error_string(str, rcount))) ++ if (is_prefix(str, PADD_PREFIX)) + { +- fprintf(stderr, "Failed to parse the error name string\n"); +- DBUG_RETURN(0); ++ if (!(current_error= parse_padd_string(str, rcount))) ++ { ++ fprintf(stderr, "Failed to parse the error padd string\n"); ++ DBUG_RETURN(0); ++ } ++ rcount= current_error->d_code - er_offset; /* Count number of unique errors */ ++ } ++ else ++ { ++ if (!(current_error= parse_error_string(str, rcount))) ++ { ++ fprintf(stderr, "Failed to parse the error name string\n"); ++ DBUG_RETURN(0); ++ } ++ rcount++; /* Count number of unique errors */ + } +- rcount++; /* Count number of unique errors */ + + /* add error to the list */ + *tail_error= current_error; +@@ -848,78 +885,122 @@ + DBUG_RETURN(new_message); + } + ++static struct errors* create_new_error(my_bool is_padding, char *er_name, int d_code, const char *sql_code1, const char *sql_code2) ++{ ++ struct errors *new_error; ++ DBUG_ENTER("create_new_error"); ++ /* create a new element */ ++ new_error= (struct errors *) my_malloc(sizeof(*new_error), MYF(MY_WME)); ++ if (my_init_dynamic_array(&new_error->msg, sizeof(struct message), 0, 0)) ++ DBUG_RETURN(0); /* OOM: Fatal error */ ++ new_error->is_padding= is_padding; ++ DBUG_PRINT("info", ("is_padding: %s", (is_padding ? "true" : "false"))); ++ new_error->er_name= er_name; ++ DBUG_PRINT("info", ("er_name: %s", er_name)); ++ new_error->d_code= d_code; ++ DBUG_PRINT("info", ("d_code: %d", d_code)); ++ new_error->sql_code1= sql_code1; ++ DBUG_PRINT("info", ("sql_code1: %s", sql_code1)); ++ new_error->sql_code2= sql_code2; ++ DBUG_PRINT("info", ("sql_code2: %s", sql_code2)); ++ DBUG_RETURN(new_error); ++} + + /* +- Parsing the string with error name and codes; returns the pointer to ++ Parsing the string with padd syntax (name + error to pad); returns the pointer to + the errors struct + */ + +-static struct errors *parse_error_string(char *str, int er_count) ++static struct errors *parse_padd_string(char* str, int er_count) + { +- struct errors *new_error; ++ char *er_name; ++ uint d_code; ++ char *start; + DBUG_ENTER("parse_error_string"); + DBUG_PRINT("enter", ("str: %s", str)); + +- /* create a new element */ +- new_error= (struct errors *) my_malloc(sizeof(*new_error), MYF(MY_WME)); ++ start= str; ++ str= skip_delimiters(str); + +- if (my_init_dynamic_array(&new_error->msg, sizeof(struct message), 0, 0)) ++ /* getting the error name */ ++ ++ if (!(er_name= get_word(&str))) + DBUG_RETURN(0); /* OOM: Fatal error */ + +- /* getting the error name */ + str= skip_delimiters(str); + +- if (!(new_error->er_name= get_word(&str))) ++ if (!(d_code= parse_error_offset(start))) ++ { ++ fprintf(stderr, "Failed to parse the error padd string '%s' '%s' (d_code doesn't parse)!\n",er_name,str); ++ DBUG_RETURN(0); ++ } ++ if (d_code < (er_offset + er_count)) ++ { ++ fprintf(stderr, "Error to padding less current error number!\n"); ++ DBUG_RETURN(0); ++ } ++ DBUG_RETURN(create_new_error(TRUE,er_name,d_code,empty_string,empty_string)); ++} ++ ++/* ++ Parsing the string with error name and codes; returns the pointer to ++ the errors struct ++*/ ++ ++static struct errors *parse_error_string(char *str, int er_count) ++{ ++ char *er_name; ++ int d_code; ++ const char *sql_code1= empty_string; ++ const char *sql_code2= empty_string; ++ DBUG_ENTER("parse_error_string"); ++ DBUG_PRINT("enter", ("str: %s", str)); ++ ++ str= skip_delimiters(str); ++ ++ /* getting the error name */ ++ ++ if (!(er_name= get_word(&str))) + DBUG_RETURN(0); /* OOM: Fatal error */ +- DBUG_PRINT("info", ("er_name: %s", new_error->er_name)); + + str= skip_delimiters(str); + + /* getting the code1 */ +- +- new_error->d_code= er_offset + er_count; +- DBUG_PRINT("info", ("d_code: %d", new_error->d_code)); ++ d_code= er_offset + er_count; + + str= skip_delimiters(str); + + /* if we reached EOL => no more codes, but this can happen */ + if (!*str) + { +- new_error->sql_code1= empty_string; +- new_error->sql_code2= empty_string; + DBUG_PRINT("info", ("str: %s", str)); +- DBUG_RETURN(new_error); ++ goto complete_create; + } +- + /* getting the sql_code 1 */ +- +- if (!(new_error->sql_code1= get_word(&str))) ++ if (!(sql_code1= get_word(&str))) + DBUG_RETURN(0); /* OOM: Fatal error */ +- DBUG_PRINT("info", ("sql_code1: %s", new_error->sql_code1)); + + str= skip_delimiters(str); + + /* if we reached EOL => no more codes, but this can happen */ + if (!*str) + { +- new_error->sql_code2= empty_string; + DBUG_PRINT("info", ("str: %s", str)); +- DBUG_RETURN(new_error); ++ goto complete_create; + } +- + /* getting the sql_code 2 */ +- if (!(new_error->sql_code2= get_word(&str))) ++ if (!(sql_code2= get_word(&str))) + DBUG_RETURN(0); /* OOM: Fatal error */ +- DBUG_PRINT("info", ("sql_code2: %s", new_error->sql_code2)); + + str= skip_delimiters(str); ++ + if (*str) + { + fprintf(stderr, "The error line did not end with sql/odbc code!"); + DBUG_RETURN(0); + } +- +- DBUG_RETURN(new_error); ++complete_create: ++ DBUG_RETURN(create_new_error(FALSE,er_name,d_code,sql_code1,sql_code2)); + } + + diff --git a/innodb_extend_slow.patch b/innodb_extend_slow.patch index db61e45d59d4..182a8cbc02d9 100644 --- a/innodb_extend_slow.patch +++ b/innodb_extend_slow.patch @@ -435,7 +435,7 @@ diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_ if (trx->n_mysql_tables_in_use == 0) { +#ifdef EXTENDED_SLOWLOG + increment_thd_innodb_stats(thd, -+ (unsigned long long) ut_conv_dulint_to_longlong(trx->id), ++ (unsigned long long) trx->id, + trx->io_reads, + trx->io_read, + trx->io_reads_wait_timer, diff --git a/install_tests.sh b/install_tests.sh new file mode 100755 index 000000000000..43957a06e038 --- /dev/null +++ b/install_tests.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +test -z ${PERCONA_SERVER} && export PERCONA_SERVER=Percona-Server +echo PERCONA_SERVER=${PERCONA_SERVER} + +install_path() +{ + echo "Installing mysql-test files: $2" + find $1 -iname '*.test' -exec install -m 644 {} ${PERCONA_SERVER}/mysql-test/t/ ';' + find $1 -iname '*.opt' -exec install -m 644 {} ${PERCONA_SERVER}/mysql-test/t/ ';' + find $1 -iname '*.result' -exec install -m 644 {} ${PERCONA_SERVER}/mysql-test/r/ ';' + find $1 -iname '*.inc' -exec install -m 644 {} ${PERCONA_SERVER}/mysql-test/include/ ';' +} + +install_path mysql-test "global" +for test_name in `cat series`; do + test -d mysql-test/$test_name && install_path mysql-test/$test_name $test_name +done +echo "Done" diff --git a/log_connection_error.patch b/log_connection_error.patch new file mode 100644 index 000000000000..5488fee72aa5 --- /dev/null +++ b/log_connection_error.patch @@ -0,0 +1,80 @@ +# name : log_connection_error.patch +# introduced : 12 +# maintainer : Oleg +# +#!!! notice !!! +# Any small change to this file in the main branch +# should be done or reviewed by the maintainer! +diff -ruN a/mysql-test/r/connect.result b/mysql-test/r/connect.result +--- a/mysql-test/r/connect.result 2010-07-28 16:47:46.895318726 +0400 ++++ b/mysql-test/r/connect.result 2010-07-28 16:47:48.234134231 +0400 +@@ -1,3 +1,4 @@ ++set global log_warnings=0; + drop table if exists t1,t2; + show tables; + Tables_in_mysql +@@ -221,3 +222,4 @@ + # ------------------------------------------------------------------ + # -- End of 5.1 tests + # ------------------------------------------------------------------ ++set global log_warnings=1; +diff -ruN a/mysql-test/t/connect.test b/mysql-test/t/connect.test +--- a/mysql-test/t/connect.test 2010-07-28 16:47:46.865318816 +0400 ++++ b/mysql-test/t/connect.test 2010-07-28 16:47:48.057260581 +0400 +@@ -1,3 +1,5 @@ ++set global log_warnings=0; ++ + # This test is to check various cases of connections + # with right and wrong password, with and without database + # Unfortunately the check is incomplete as we can't connect without database +@@ -300,3 +302,4 @@ + # Wait till all disconnects are completed + --source include/wait_until_count_sessions.inc + ++set global log_warnings=1; +diff -ruN a/patch_info/log_connection_error.patch b/patch_info/log_connection_error.patch +--- a/patch_info/log_connection_error.patch 1970-01-01 03:00:00.000000000 +0300 ++++ b/patch_info/log_connection_error.patch 2010-07-28 16:47:47.634070367 +0400 +@@ -0,0 +1,6 @@ ++File=log_connection_error.patch ++Name=logging abandoned connections ++Version=1.0 ++Author=Percona ++License=GPL ++Comment= +diff -ruN a/sql/mysqld.cc b/sql/mysqld.cc +--- a/sql/mysqld.cc 2010-07-28 16:47:47.105319218 +0400 ++++ b/sql/mysqld.cc 2010-07-28 16:47:47.644101813 +0400 +@@ -5004,6 +5004,10 @@ + + DBUG_PRINT("error",("Too many connections")); + close_connection(thd, ER_CON_COUNT_ERROR, 1); ++ if (global_system_variables.log_warnings) ++ { ++ sql_print_warning("%s", ER_DEFAULT(ER_CON_COUNT_ERROR)); ++ } + delete thd; + DBUG_VOID_RETURN; + } +@@ -5384,6 +5388,10 @@ + if (!(thd->net.vio= vio_new_win32pipe(hConnectedPipe)) || + my_net_init(&thd->net, thd->net.vio)) + { ++ if (global_system_variables.log_warnings) ++ { ++ sql_print_warning("%s", ER_DEFAULT(ER_OUT_OF_RESOURCES)); ++ } + close_connection(thd, ER_OUT_OF_RESOURCES, 1); + delete thd; + continue; +@@ -5579,6 +5587,10 @@ + event_conn_closed)) || + my_net_init(&thd->net, thd->net.vio)) + { ++ if (global_system_variables.log_warnings) ++ { ++ sql_print_warning("%s", ER_DEFAULT(ER_OUT_OF_RESOURCES)); ++ } + close_connection(thd, ER_OUT_OF_RESOURCES, 1); + errmsg= 0; + goto errorconn; diff --git a/mysql-test/log_connection_error.patch/percona_log_connection_error-master.opt b/mysql-test/log_connection_error.patch/percona_log_connection_error-master.opt new file mode 100644 index 000000000000..4658d62af608 --- /dev/null +++ b/mysql-test/log_connection_error.patch/percona_log_connection_error-master.opt @@ -0,0 +1 @@ +--log-error diff --git a/mysql-test/log_connection_error.patch/percona_log_connection_error.result b/mysql-test/log_connection_error.patch/percona_log_connection_error.result new file mode 100644 index 000000000000..3c6c67f770c3 --- /dev/null +++ b/mysql-test/log_connection_error.patch/percona_log_connection_error.result @@ -0,0 +1,15 @@ +SET @old_max_connections = @@max_connections; +SET @old_log_warnings = @@log_warnings; +SET GLOBAL max_connections=2; +SET GLOBAL LOG_WARNINGS = 0; +connect(localhost,root,,test,port,socket); +ERROR HY000: Too many connections +SET GLOBAL LOG_WARNINGS = 1; +connect(localhost,root,,test,port,socket); +ERROR HY000: Too many connections +SET GLOBAL LOG_WARNINGS = 0; +connect(localhost,root,,test,port,socket); +ERROR HY000: Too many connections +SET GLOBAL max_connections = @old_max_connections; +SET GLOBAL log_warnings = @old_log_warnings; +1 diff --git a/mysql-test/log_connection_error.patch/percona_log_connection_error.test b/mysql-test/log_connection_error.patch/percona_log_connection_error.test new file mode 100644 index 000000000000..57cd652bd244 --- /dev/null +++ b/mysql-test/log_connection_error.patch/percona_log_connection_error.test @@ -0,0 +1,52 @@ +--source include/not_embedded.inc + +connect (main,localhost,root,,); +connection main; +SET @old_max_connections = @@max_connections; +SET @old_log_warnings = @@log_warnings; +SET GLOBAL max_connections=2; +let $port=`SELECT Variable_value FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE Variable_name LIKE 'port'`; +let $socket=`SELECT Variable_value FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE Variable_name LIKE 'socket'`; + +SET GLOBAL LOG_WARNINGS = 0; +--connect (conn0,localhost,root,,) +connection conn0; +replace_result $port port $socket socket; +--error 1040 +--connect(conn1,localhost,root,,) +disconnect conn0; +SLEEP 0.1; # tsarev: hack, but i don't know (and didn't find) how right + +connection main; +SET GLOBAL LOG_WARNINGS = 1; +--connect (conn1,localhost,root,,) +replace_result $port port $socket socket; +--error 1040 +--connect (conn0,localhost,root,,) +disconnect conn1; +SLEEP 0.1; # tsarev: hack, but i don't know (and didn't find) how right + +connection main; +SET GLOBAL LOG_WARNINGS = 0; +--connect (conn0,localhost,root,,) +replace_result $port port $socket socket; +--error 1040 +--connect(conn1,localhost,root,,) +disconnect conn0; +SLEEP 0.1; # tsarev: hack, but i don't know (and didn't find) how right + +connection main; +SET GLOBAL max_connections = @old_max_connections; +SET GLOBAL log_warnings = @old_log_warnings; +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!`select LENGTH('$log_error_')`) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.1.err; +} +# Assign env variable LOG_ERROR +let LOG_ERROR=$log_error_; + +let cmd=cat $log_error | grep "Too many connections" | wc -l; +exec $cmd; diff --git a/mysql-test/percona_innodb_buffer_pool_shm-master.opt b/mysql-test/percona_innodb_buffer_pool_shm-master.opt new file mode 100644 index 000000000000..5974ef6e2bea --- /dev/null +++ b/mysql-test/percona_innodb_buffer_pool_shm-master.opt @@ -0,0 +1 @@ +--innodb_buffer_pool_shm_key=123456 diff --git a/mysql-test/percona_innodb_buffer_pool_shm.result b/mysql-test/percona_innodb_buffer_pool_shm.result new file mode 100644 index 000000000000..08ece8fb9a92 --- /dev/null +++ b/mysql-test/percona_innodb_buffer_pool_shm.result @@ -0,0 +1,6 @@ +show variables like 'innodb_buffer_pool_shm%'; +Variable_name Value +innodb_buffer_pool_shm_key 123456 +show variables like 'innodb_buffer_pool_shm%'; +Variable_name Value +innodb_buffer_pool_shm_key 123456 diff --git a/mysql-test/percona_innodb_buffer_pool_shm.test b/mysql-test/percona_innodb_buffer_pool_shm.test new file mode 100644 index 000000000000..7b81bb8d54b8 --- /dev/null +++ b/mysql-test/percona_innodb_buffer_pool_shm.test @@ -0,0 +1,18 @@ +--source include/have_innodb.inc +show variables like 'innodb_buffer_pool_shm%'; + +#clean shutdown (restart_mysqld.inc is not clean if over 10 sec...) +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF +shutdown_server 120; +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc +--disable_reconnect + +show variables like 'innodb_buffer_pool_shm%'; +--sleep 1 +--system ipcrm -M 123456 diff --git a/mysql-test/percona_innodb_deadlock_count.result b/mysql-test/percona_innodb_deadlock_count.result new file mode 100644 index 000000000000..4ad6fd433feb --- /dev/null +++ b/mysql-test/percona_innodb_deadlock_count.result @@ -0,0 +1,28 @@ +# Establish connection con1 (user=root) +# Establish connection con2 (user=root) +# Establish connection con3 (user=root) +# Drop test table +drop table if exists t; +# Create test table +create table t(a INT PRIMARY KEY, b INT) engine=InnoDB; +# Insert two rows to test table +insert into t values(2,1); +insert into t values(1,2); +# Switch to connection con1 +BEGIN; +SELECT b FROM t WHERE a=1 FOR UPDATE; +b +2 +# Switch to connection con2 +BEGIN; +SELECT b FROM t WHERE a=2 FOR UPDATE; +b +1 +# Switch to connection con1 +SELECT b FROM t WHERE a=2 FOR UPDATE; +# Switch to connection con2 +SELECT b FROM t WHERE a=1 FOR UPDATE; +# Switch to connection con3 +1 +# Drop test table +drop table t; diff --git a/mysql-test/percona_innodb_deadlock_count.test b/mysql-test/percona_innodb_deadlock_count.test new file mode 100644 index 000000000000..b0882a18dc1d --- /dev/null +++ b/mysql-test/percona_innodb_deadlock_count.test @@ -0,0 +1,49 @@ +--source include/have_innodb.inc +--echo # Establish connection con1 (user=root) +connect (con1,localhost,root,,); +--echo # Establish connection con2 (user=root) +connect (con2,localhost,root,,); +--echo # Establish connection con3 (user=root) +connect (con3,localhost,root,,); +--echo # Drop test table +--disable_warnings +drop table if exists t; +--enable_warnings +disable_abort_on_error; + +--echo # Create test table +create table t(a INT PRIMARY KEY, b INT) engine=InnoDB; +--echo # Insert two rows to test table +insert into t values(2,1); +insert into t values(1,2); + +#--echo # Save current deadlock count +let $current = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'Innodb_deadlocks'`; + +--echo # Switch to connection con1 +connection con1; +BEGIN; SELECT b FROM t WHERE a=1 FOR UPDATE; + +#show engine innodb status; + +--echo # Switch to connection con2 +connection con2; +BEGIN; SELECT b FROM t WHERE a=2 FOR UPDATE; + +--echo # Switch to connection con1 +connection con1; +SEND SELECT b FROM t WHERE a=2 FOR UPDATE; + +--echo # Switch to connection con2 +connection con2; +SEND SELECT b FROM t WHERE a=1 FOR UPDATE; + +SLEEP 0.2; +--echo # Switch to connection con3 +connection con3; +let $result = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'Innodb_deadlocks'`; + +let $diff = `SELECT $result - $current`; +echo $diff; +--echo # Drop test table +drop table t; diff --git a/mysql-test/percona_innodb_doublewrite_file-master.opt b/mysql-test/percona_innodb_doublewrite_file-master.opt new file mode 100644 index 000000000000..0f4d0c454103 --- /dev/null +++ b/mysql-test/percona_innodb_doublewrite_file-master.opt @@ -0,0 +1 @@ +--innodb_doublewrite_file=ib_doublewrite diff --git a/mysql-test/percona_innodb_doublewrite_file.result b/mysql-test/percona_innodb_doublewrite_file.result new file mode 100644 index 000000000000..4d086cc4498e --- /dev/null +++ b/mysql-test/percona_innodb_doublewrite_file.result @@ -0,0 +1,4 @@ +show variables like 'innodb_doublewrite%'; +Variable_name Value +innodb_doublewrite ON +innodb_doublewrite_file ib_doublewrite diff --git a/mysql-test/percona_innodb_doublewrite_file.test b/mysql-test/percona_innodb_doublewrite_file.test new file mode 100644 index 000000000000..8068d5611903 --- /dev/null +++ b/mysql-test/percona_innodb_doublewrite_file.test @@ -0,0 +1,2 @@ +--source include/have_innodb.inc +show variables like 'innodb_doublewrite%'; diff --git a/mysql-test/percona_innodb_use_sys_stats_table-master.opt b/mysql-test/percona_innodb_use_sys_stats_table-master.opt new file mode 100644 index 000000000000..c6865f5704cd --- /dev/null +++ b/mysql-test/percona_innodb_use_sys_stats_table-master.opt @@ -0,0 +1 @@ +--innodb_use_sys_stats_table diff --git a/mysql-test/percona_innodb_use_sys_stats_table.result b/mysql-test/percona_innodb_use_sys_stats_table.result new file mode 100644 index 000000000000..cb64de419016 --- /dev/null +++ b/mysql-test/percona_innodb_use_sys_stats_table.result @@ -0,0 +1,3 @@ +show variables like 'innodb_use_sys_stats%'; +Variable_name Value +innodb_use_sys_stats_table ON diff --git a/mysql-test/percona_innodb_use_sys_stats_table.test b/mysql-test/percona_innodb_use_sys_stats_table.test new file mode 100644 index 000000000000..02791137f08a --- /dev/null +++ b/mysql-test/percona_innodb_use_sys_stats_table.test @@ -0,0 +1,2 @@ +--source include/have_innodb.inc +show variables like 'innodb_use_sys_stats%'; diff --git a/mysql-test/percona_server_variables.result b/mysql-test/percona_server_variables.result new file mode 100644 index 000000000000..cb2af0d3d0e2 --- /dev/null +++ b/mysql-test/percona_server_variables.result @@ -0,0 +1,342 @@ +show variables; +Variable_name Value +auto_increment_increment Value +auto_increment_offset Value +autocommit Value +automatic_sp_privileges Value +back_log Value +basedir Value +big_tables Value +binlog_cache_size Value +binlog_direct_non_transactional_updates Value +binlog_format Value +bulk_insert_buffer_size Value +character_set_client Value +character_set_connection Value +character_set_database Value +character_set_filesystem Value +character_set_results Value +character_set_server Value +character_set_system Value +character_sets_dir Value +collation_connection Value +collation_database Value +collation_server Value +completion_type Value +concurrent_insert Value +connect_timeout Value +datadir Value +date_format Value +datetime_format Value +debug Value +debug_sync Value +default_week_format Value +delay_key_write Value +delayed_insert_limit Value +delayed_insert_timeout Value +delayed_queue_size Value +div_precision_increment Value +enable_query_response_time_stats Value +engine_condition_pushdown Value +error_count Value +event_scheduler Value +expire_logs_days Value +fast_index_creation Value +flush Value +flush_time Value +foreign_key_checks Value +ft_boolean_syntax Value +ft_max_word_len Value +ft_min_word_len Value +ft_query_expansion_limit Value +ft_stopword_file Value +general_log Value +general_log_file Value +group_concat_max_len Value +have_community_features Value +have_compress Value +have_crypt Value +have_csv Value +have_dynamic_loading Value +have_geometry Value +have_innodb Value +have_ndbcluster Value +have_openssl Value +have_partitioning Value +have_query_cache Value +have_rtree_keys Value +have_ssl Value +have_symlink Value +hostname Value +identity Value +ignore_builtin_innodb Value +init_connect Value +init_file Value +init_slave Value +innodb_adaptive_checkpoint Value +innodb_adaptive_flushing Value +innodb_adaptive_hash_index Value +innodb_additional_mem_pool_size Value +innodb_auto_lru_dump Value +innodb_autoextend_increment Value +innodb_autoinc_lock_mode Value +innodb_buffer_pool_shm_checksum Value +innodb_buffer_pool_shm_key Value +innodb_buffer_pool_size Value +innodb_change_buffering Value +innodb_checkpoint_age_target Value +innodb_checksums Value +innodb_commit_concurrency Value +innodb_concurrency_tickets Value +innodb_data_file_path Value +innodb_data_home_dir Value +innodb_dict_size_limit Value +innodb_doublewrite Value +innodb_doublewrite_file Value +innodb_enable_unsafe_group_commit Value +innodb_expand_import Value +innodb_extra_rsegments Value +innodb_extra_undoslots Value +innodb_fast_checksum Value +innodb_fast_recovery Value +innodb_fast_shutdown Value +innodb_file_format Value +innodb_file_format_check Value +innodb_file_per_table Value +innodb_flush_log_at_trx_commit Value +innodb_flush_log_at_trx_commit_session Value +innodb_flush_method Value +innodb_flush_neighbor_pages Value +innodb_force_recovery Value +innodb_ibuf_accel_rate Value +innodb_ibuf_active_contract Value +innodb_ibuf_max_size Value +innodb_io_capacity Value +innodb_lock_wait_timeout Value +innodb_locks_unsafe_for_binlog Value +innodb_log_buffer_size Value +innodb_log_file_size Value +innodb_log_files_in_group Value +innodb_log_group_home_dir Value +innodb_max_dirty_pages_pct Value +innodb_max_purge_lag Value +innodb_mirrored_log_groups Value +innodb_old_blocks_pct Value +innodb_old_blocks_time Value +innodb_open_files Value +innodb_overwrite_relay_log_info Value +innodb_page_size Value +innodb_pass_corrupt_table Value +innodb_read_ahead Value +innodb_read_ahead_threshold Value +innodb_read_io_threads Value +innodb_recovery_stats Value +innodb_replication_delay Value +innodb_rollback_on_timeout Value +innodb_show_locks_held Value +innodb_show_verbose_locks Value +innodb_spin_wait_delay Value +innodb_stats_auto_update Value +innodb_stats_method Value +innodb_stats_on_metadata Value +innodb_stats_sample_pages Value +innodb_stats_update_need_lock Value +innodb_strict_mode Value +innodb_support_xa Value +innodb_sync_spin_loops Value +innodb_table_locks Value +innodb_thread_concurrency Value +innodb_thread_concurrency_timer_based Value +innodb_thread_sleep_delay Value +innodb_use_purge_thread Value +innodb_use_sys_malloc Value +innodb_use_sys_stats_table Value +innodb_version Value +innodb_write_io_threads Value +insert_id Value +interactive_timeout Value +join_buffer_size Value +keep_files_on_create Value +key_buffer_size Value +key_cache_age_threshold Value +key_cache_block_size Value +key_cache_division_limit Value +language Value +large_files_support Value +large_page_size Value +large_pages Value +last_insert_id Value +lc_time_names Value +license Value +local_infile Value +locked_in_memory Value +log Value +log_bin Value +log_bin_trust_function_creators Value +log_bin_trust_routine_creators Value +log_error Value +log_output Value +log_queries_not_using_indexes Value +log_slave_updates Value +log_slow_filter Value +log_slow_queries Value +log_slow_rate_limit Value +log_slow_slave_statements Value +log_slow_sp_statements Value +log_slow_timestamp_every Value +log_slow_verbosity Value +log_warnings Value +long_query_time Value +low_priority_updates Value +lower_case_file_system Value +lower_case_table_names Value +max_allowed_packet Value +max_binlog_cache_size Value +max_binlog_size Value +max_connect_errors Value +max_connections Value +max_delayed_threads Value +max_error_count Value +max_heap_table_size Value +max_insert_delayed_threads Value +max_join_size Value +max_length_for_sort_data Value +max_prepared_stmt_count Value +max_relay_log_size Value +max_seeks_for_key Value +max_sort_length Value +max_sp_recursion_depth Value +max_tmp_tables Value +max_user_connections Value +max_write_lock_count Value +min_examined_row_limit Value +multi_range_count Value +myisam_data_pointer_size Value +myisam_max_sort_file_size Value +myisam_mmap_size Value +myisam_recover_options Value +myisam_repair_threads Value +myisam_sort_buffer_size Value +myisam_stats_method Value +myisam_use_mmap Value +net_buffer_length Value +net_read_timeout Value +net_retry_count Value +net_write_timeout Value +new Value +old Value +old_alter_table Value +old_passwords Value +open_files_limit Value +optimizer_fix Value +optimizer_prune_level Value +optimizer_search_depth Value +optimizer_switch Value +pid_file Value +plugin_dir Value +port Value +preload_buffer_size Value +profiling Value +profiling_history_size Value +profiling_server Value +profiling_use_getrusage Value +protocol_version Value +pseudo_thread_id Value +query_alloc_block_size Value +query_cache_limit Value +query_cache_min_res_unit Value +query_cache_size Value +query_cache_strip_comments Value +query_cache_type Value +query_cache_wlock_invalidate Value +query_prealloc_size Value +query_response_time_range_base Value +rand_seed1 Value +rand_seed2 Value +range_alloc_block_size Value +read_buffer_size Value +read_only Value +read_rnd_buffer_size Value +relay_log Value +relay_log_index Value +relay_log_info_file Value +relay_log_purge Value +relay_log_space_limit Value +report_host Value +report_password Value +report_port Value +report_user Value +rpl_recovery_rank Value +secure_auth Value +secure_file_priv Value +server_id Value +skip_external_locking Value +skip_name_resolve Value +skip_networking Value +skip_show_database Value +slave_compressed_protocol Value +slave_exec_mode Value +slave_load_tmpdir Value +slave_net_timeout Value +slave_skip_errors Value +slave_transaction_retries Value +slow_launch_time Value +slow_query_log Value +slow_query_log_file Value +slow_query_log_microseconds_timestamp Value +socket Value +sort_buffer_size Value +sql_auto_is_null Value +sql_big_selects Value +sql_big_tables Value +sql_buffer_result Value +sql_log_bin Value +sql_log_off Value +sql_log_update Value +sql_low_priority_updates Value +sql_max_join_size Value +sql_mode Value +sql_notes Value +sql_quote_show_create Value +sql_safe_updates Value +sql_select_limit Value +sql_slave_skip_counter Value +sql_warnings Value +ssl_ca Value +ssl_capath Value +ssl_cert Value +ssl_cipher Value +ssl_key Value +storage_engine Value +suppress_log_warning_1592 Value +sync_binlog Value +sync_frm Value +system_time_zone Value +table_definition_cache Value +table_lock_wait_timeout Value +table_open_cache Value +table_type Value +thread_cache_size Value +thread_handling Value +thread_stack Value +thread_statistics Value +time_format Value +time_zone Value +timed_mutexes Value +timestamp Value +tmp_table_size Value +tmpdir Value +transaction_alloc_block_size Value +transaction_prealloc_size Value +tx_isolation Value +unique_checks Value +updatable_views_with_limit Value +use_global_log_slow_control Value +use_global_long_query_time Value +userstat_running Value +version Value +version_comment Value +version_compile_machine Value +version_compile_os Value +wait_timeout Value +warning_count Value diff --git a/mysql-test/percona_server_variables.test b/mysql-test/percona_server_variables.test new file mode 100644 index 000000000000..232cbb15e255 --- /dev/null +++ b/mysql-test/percona_server_variables.test @@ -0,0 +1,7 @@ +--source include/have_innodb.inc +--source include/have_debug.inc + +#check the list of variable names +--replace_column 2 Value +show variables; + diff --git a/mysql-test/percona_show_temp_tables.result b/mysql-test/percona_show_temp_tables.result new file mode 100644 index 000000000000..cbcb0331896e --- /dev/null +++ b/mysql-test/percona_show_temp_tables.result @@ -0,0 +1,58 @@ +drop table if exists t1,t2,t3; +drop database if exists showtemp; +create database if not exists showtemp; +use test; +create temporary table t1(id int); +create temporary table t2(id int); +create temporary table showtemp.t3(id int); +insert into t1 values(10),(20),(30),(40); +insert into showtemp.t3 values(999); +show temporary tables; +Temp_tables_in_test +t2 +t1 +show temporary tables from test; +Temp_tables_in_test +t2 +t1 +show temporary tables in showtemp; +Temp_tables_in_showtemp +t3 +select table_schema, table_name, engine, table_rows from Information_schema.temporary_tables; +table_schema table_name engine table_rows +showtemp t3 MyISAM 1 +test t2 MyISAM 0 +test t1 MyISAM 4 +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables; +table_schema table_name engine table_rows +showtemp t3 MyISAM 1 +test t2 MyISAM 0 +test t1 MyISAM 4 +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables where table_schema='showtemp'; +table_schema table_name engine table_rows +showtemp t3 MyISAM 1 +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables where table_schema='temp'; +table_schema table_name engine table_rows +drop table if exists showtemp.t2; +create temporary table t1(id int); +create temporary table showtemp.t2(id int); +show temporary tables; +Temp_tables_in_test +t1 +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables; +table_schema table_name engine table_rows +showtemp t2 MyISAM 0 +test t1 MyISAM 0 +showtemp t3 MyISAM 1 +test t2 MyISAM 0 +test t1 MyISAM 4 +drop table showtemp.t2; +drop table t1; +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables; +table_schema table_name engine table_rows +showtemp t3 MyISAM 1 +test t2 MyISAM 0 +test t1 MyISAM 4 +drop table t1, t2; +drop table showtemp.t3; +drop database showtemp; diff --git a/mysql-test/percona_show_temp_tables.test b/mysql-test/percona_show_temp_tables.test new file mode 100644 index 000000000000..8837df199c51 --- /dev/null +++ b/mysql-test/percona_show_temp_tables.test @@ -0,0 +1,65 @@ +# Uses GRANT commands that usually disabled in embedded server +-- source include/not_embedded.inc + +# Save the initial number of concurrent sessions +--source include/count_sessions.inc + +# +# Test of SHOW [GLOBAL] TEMPORARY TABLES [FROM/IN] DB and +# Information_schema.temporary_tables and global_temporary_tables +# + +connect(stcon1,localhost,root,,test); +connect(stcon2,localhost,root,,test); + +connection stcon1; + +--disable_warnings +drop table if exists t1,t2,t3; +drop database if exists showtemp; +create database if not exists showtemp; +--enable_warnings + +use test; +create temporary table t1(id int); +create temporary table t2(id int); +create temporary table showtemp.t3(id int); +insert into t1 values(10),(20),(30),(40); +insert into showtemp.t3 values(999); + +show temporary tables; +# "Session" is not same value always. mysql-test cannot test it always. +#show global temporary tables; +show temporary tables from test; +show temporary tables in showtemp; +select table_schema, table_name, engine, table_rows from Information_schema.temporary_tables; +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables; +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables where table_schema='showtemp'; +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables where table_schema='temp'; + +connection stcon2; + +--disable_warnings +drop table if exists showtemp.t2; +--enable_warnings +create temporary table t1(id int); +create temporary table showtemp.t2(id int); +show temporary tables; +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables; +drop table showtemp.t2; +drop table t1; + +disconnect stcon2; + +connection stcon1; +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables; + +drop table t1, t2; +drop table showtemp.t3; +drop database showtemp; + +connection default; +disconnect stcon1; + +# Wait till all disconnects are completed +--source include/wait_until_count_sessions.inc diff --git a/mysql-test/percona_suppress_log_warning_1592-master.opt b/mysql-test/percona_suppress_log_warning_1592-master.opt new file mode 100644 index 000000000000..4658d62af608 --- /dev/null +++ b/mysql-test/percona_suppress_log_warning_1592-master.opt @@ -0,0 +1 @@ +--log-error diff --git a/mysql-test/percona_suppress_log_warning_1592.result b/mysql-test/percona_suppress_log_warning_1592.result new file mode 100644 index 000000000000..4715499b08f9 --- /dev/null +++ b/mysql-test/percona_suppress_log_warning_1592.result @@ -0,0 +1,28 @@ +SET @old_log_warnings = @@log_warnings; +SET @old_suppress_log_warning_1592 = @@suppress_log_warning_1592; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a VARCHAR(36), b VARCHAR(20)); +SET GLOBAL SUPPRESS_LOG_WARNING_1592 = 0; +SET GLOBAL LOG_WARNINGS = 0; +INSERT INTO t1 VALUES(UUID(), 'suppress_1592'); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +SET GLOBAL LOG_WARNINGS = 1; +INSERT INTO t1 VALUES(UUID(), 'suppress_1592'); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +SET GLOBAL SUPPRESS_LOG_WARNING_1592 = 1; +SET GLOBAL LOG_WARNINGS = 0; +INSERT INTO t1 VALUES(UUID(), 'suppress_1592'); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +SET GLOBAL LOG_WARNINGS = 1; +INSERT INTO t1 VALUES(UUID(), 'suppress_1592'); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +DROP TABLE t1; +SET GLOBAL log_warnings = @old_log_warnings; +SET GLOBAL suppress_log_warning_1592 = @old_suppress_log_warning_1592; +# Count the number of times the "Unsafe" message was printed +# to the error log. +Occurrences: 1 diff --git a/mysql-test/percona_suppress_log_warning_1592.test b/mysql-test/percona_suppress_log_warning_1592.test new file mode 100644 index 000000000000..97fe40469fc2 --- /dev/null +++ b/mysql-test/percona_suppress_log_warning_1592.test @@ -0,0 +1,46 @@ +-- source include/have_log_bin.inc +-- source include/have_binlog_format_statement.inc + +SET @old_log_warnings = @@log_warnings; +SET @old_suppress_log_warning_1592 = @@suppress_log_warning_1592; + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +CREATE TABLE t1 (a VARCHAR(36), b VARCHAR(20)); +SET GLOBAL SUPPRESS_LOG_WARNING_1592 = 0; +SET GLOBAL LOG_WARNINGS = 0; +INSERT INTO t1 VALUES(UUID(), 'suppress_1592'); +SET GLOBAL LOG_WARNINGS = 1; +INSERT INTO t1 VALUES(UUID(), 'suppress_1592'); +SET GLOBAL SUPPRESS_LOG_WARNING_1592 = 1; +SET GLOBAL LOG_WARNINGS = 0; +INSERT INTO t1 VALUES(UUID(), 'suppress_1592'); +SET GLOBAL LOG_WARNINGS = 1; +INSERT INTO t1 VALUES(UUID(), 'suppress_1592'); +DROP TABLE t1; + +SET GLOBAL log_warnings = @old_log_warnings; +SET GLOBAL suppress_log_warning_1592 = @old_suppress_log_warning_1592; + +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!`select LENGTH('$log_error_')`) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.1.err; +} +# Assign env variable LOG_ERROR +let LOG_ERROR=$log_error_; + +--echo # Count the number of times the "Unsafe" message was printed +--echo # to the error log. + +perl; + use strict; + my $log_error= $ENV{'LOG_ERROR'} or die "LOG_ERROR not set"; + open(FILE, "$log_error") or die("Unable to open $log_error: $!\n"); + my $count = () = grep(/suppress_1592/g,); + print "Occurrences: $count\n"; + close(FILE); +EOF diff --git a/mysql-test/percona_xtradb_admin_command.result b/mysql-test/percona_xtradb_admin_command.result new file mode 100644 index 000000000000..26ba14f2f3b9 --- /dev/null +++ b/mysql-test/percona_xtradb_admin_command.result @@ -0,0 +1,6 @@ +select * from information_schema.XTRADB_ADMIN_COMMAND; +result_message +No XTRA_* command in the SQL statement. Please add /*!XTRA_xxxx*/ to the SQL. +select * from information_schema.XTRADB_ADMIN_COMMAND /*!XTRA_HELLO*/; +result_message +Hello! diff --git a/mysql-test/percona_xtradb_admin_command.test b/mysql-test/percona_xtradb_admin_command.test new file mode 100644 index 000000000000..5dc3fb2b33ab --- /dev/null +++ b/mysql-test/percona_xtradb_admin_command.test @@ -0,0 +1,3 @@ +--source include/have_innodb.inc +select * from information_schema.XTRADB_ADMIN_COMMAND; +select * from information_schema.XTRADB_ADMIN_COMMAND /*!XTRA_HELLO*/; diff --git a/mysql-test/percona_xtradb_bug317074.result b/mysql-test/percona_xtradb_bug317074.result new file mode 100644 index 000000000000..82a98844652d --- /dev/null +++ b/mysql-test/percona_xtradb_bug317074.result @@ -0,0 +1,4 @@ +SET @old_innodb_file_format=@@innodb_file_format; +SET @old_innodb_file_per_table=@@innodb_file_per_table; +SET GLOBAL innodb_file_format='Barracuda'; +SET GLOBAL innodb_file_per_table=ON; diff --git a/mysql-test/percona_xtradb_bug317074.test b/mysql-test/percona_xtradb_bug317074.test new file mode 100644 index 000000000000..af990cf749b1 --- /dev/null +++ b/mysql-test/percona_xtradb_bug317074.test @@ -0,0 +1,47 @@ +-- source include/have_innodb.inc + +SET @old_innodb_file_format=@@innodb_file_format; +SET @old_innodb_file_per_table=@@innodb_file_per_table; +let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; +SET GLOBAL innodb_file_format='Barracuda'; +SET GLOBAL innodb_file_per_table=ON; + +-- disable_query_log +-- disable_result_log + +DROP TABLE IF EXISTS `test1`; +CREATE TABLE IF NOT EXISTS `test1` ( + `a` int primary key auto_increment, + `b` int default 0, + `c` char(100) default 'testtest' +) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; + +delimiter |; +CREATE PROCEDURE insert_many(p1 int) +BEGIN +SET @x = 0; +SET @y = 0; +start transaction; +REPEAT + insert into test1 set b=1; + SET @x = @x + 1; + SET @y = @y + 1; + IF @y >= 1000 THEN + commit; + start transaction; + SET @y = 0; + END IF; +UNTIL @x >= p1 END REPEAT; +commit; +END| +delimiter ;| +call insert_many(100000); +DROP PROCEDURE insert_many; + +# The bug is hangup at the following statement +ALTER TABLE test1 ENGINE=MyISAM; + +DROP TABLE test1; +SET GLOBAL innodb_file_format=@old_innodb_file_format; +SET GLOBAL innodb_file_per_table=@old_innodb_file_per_table; +eval set global innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/mysql-test/profiling_slow.patch/percona_bug643149.result b/mysql-test/profiling_slow.patch/percona_bug643149.result new file mode 100644 index 000000000000..71c4d4927f00 --- /dev/null +++ b/mysql-test/profiling_slow.patch/percona_bug643149.result @@ -0,0 +1,16 @@ +SET @old_slow_query_log_file=@@global.slow_query_log_file; +SET GLOBAL slow_query_log=on; +SET LOCAL profiling_server=on; +SET LOCAL long_query_time=1; +SET GLOBAL slow_query_log_file='MYSQLTEST_VARDIR/percona_bug643149_slow.log';; +SELECT SLEEP(2); +SLEEP(2) +0 +# Time: X X:X:X +# User@Host: root[root] @ localhost [] +# Thread_id: X Schema: test Last_errno: X Killed: X +# Query_time: X.X Lock_time: X.X Rows_sent: X Rows_examined: X Rows_affected: X Rows_read: X +# Bytes_sent: X Tmp_tables: X Tmp_disk_tables: X Tmp_table_sizes: X +# Profile_starting: X.X Profile_starting_cpu: X.X Profile_checking_permissions: X.X Profile_checking_permissions_cpu: X.X Profile_Opening_tables: X.X Profile_Opening_tables_cpu: X.X Profile_init: X.X Profile_init_cpu: X.X Profile_optimizing: X.X Profile_optimizing_cpu: X.X Profile_executing: X.X Profile_executing_cpu: X.X Profile_User_sleep: X.X Profile_User_sleep_cpu: X.X Profile_end: X.X Profile_end_cpu: X.X Profile_query_end: X.X Profile_query_end_cpu: X.X Profile_freeing_items: X.X Profile_freeing_items_cpu: X.X Profile_logging_slow_query: X.X Profile_logging_slow_query_cpu: X.X +# Profile_total: X.X Profile_total_cpu: X.X +SET GLOBAL slow_query_log_file=@old_slow_query_log_file; diff --git a/mysql-test/profiling_slow.patch/percona_bug643149.test b/mysql-test/profiling_slow.patch/percona_bug643149.test new file mode 100644 index 000000000000..4608e7f6652d --- /dev/null +++ b/mysql-test/profiling_slow.patch/percona_bug643149.test @@ -0,0 +1,47 @@ +# +# This test suffers from server +# Bug#38124 "general_log_file" variable silently unset when using expression +# In short: +# SET GLOBAL general_log_file = @ +# SET GLOBAL slow_query_log = @ +# cause that the value of these server system variables is set to default +# instead of the assigned values. There comes no error message or warning. +# If this bug is fixed please +# 1. try this test with "let $fixed_bug38124 = 0;" +# 2. remove all workarounds if 1. was successful. +let $fixed_bug38124 = 0; + +SET @old_slow_query_log_file=@@global.slow_query_log_file; +SET GLOBAL slow_query_log=on; +SET LOCAL profiling_server=on; +SET LOCAL long_query_time=1; + +let slogfile=$MYSQLTEST_VARDIR/percona_bug643149_slow.log; +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval SET GLOBAL slow_query_log_file='$slogfile'; + +SELECT SLEEP(2); + +perl; + $slogfile= $ENV{'slogfile'}; + + open(FILE, "$slogfile") or + die("Unable to read slow query log file $slogfile: $!\n"); + while() { + next if (!/^#/); + s/[0-9]+/X/g; + print; + } + + close(FILE); +EOF + +SET GLOBAL slow_query_log_file=@old_slow_query_log_file; + +if(!$fixed_bug38124) +{ + --disable_query_log + let $my_var = `SELECT @old_slow_query_log_file`; + eval SET @@global.slow_query_log_file = '$my_var'; + --enable_query_log +} diff --git a/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments.inc b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments.inc new file mode 100644 index 000000000000..bed87bd4c223 --- /dev/null +++ b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments.inc @@ -0,0 +1,95 @@ +--source include/percona_query_cache_with_comments_clear.inc +let $query=/* with comment first */select * from t1; +eval $query; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=# with comment first +select * from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=-- with comment first +select * from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=/* with comment first and "quote" */select * from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=# with comment first and "quote" +select * from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=-- with comment first and "quote" +select * from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query= + /* with comment and whitespaces first */select * from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query= + # with comment and whitespaces first +select * from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query= + -- with comment and whitespaces first +select * from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $internal=* internal comment *; + +let $query=select * /$internal/ from t1; +--source include/percona_query_cache_with_comments_eval.inc +let $query=select */$internal/ from t1; +--source include/percona_query_cache_with_comments_eval.inc +let $query=select */$internal/from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $internal=* internal comment with "quote" *; + +let $query=select * /$internal/ from t1; +--source include/percona_query_cache_with_comments_eval.inc +let $query=select */$internal/ from t1; +--source include/percona_query_cache_with_comments_eval.inc +let $query=select */$internal/from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 +; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 ; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 ; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 +/* comment in the end */; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 +/* *\/ */; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 +/* comment in the end */ +; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 #comment in the end; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 #comment in the end +; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 -- comment in the end; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 -- comment in the end +; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select ' \' ' from t1; +--source include/percona_query_cache_with_comments_eval.inc diff --git a/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments.inc.backup b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments.inc.backup new file mode 100644 index 000000000000..4b5b31e92392 --- /dev/null +++ b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments.inc.backup @@ -0,0 +1,88 @@ +--source include/percona_query_cache_with_comments_clear.inc +let $query=/* with comment first */select * from t1; +eval $query; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=# with comment first +select * from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=-- with comment first +select * from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=/* with comment first and "quote" */select * from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=# with comment first and "quote" +select * from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=-- with comment first and "quote" +select * from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query= + /* with comment and whitespaces first */select * from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query= + # with comment and whitespaces first +select * from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query= + -- with comment and whitespaces first +select * from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $internal=* internal comment *; + +let $query=select * /$internal/ from t1; +--source include/percona_query_cache_with_comments_eval.inc +let $query=select */$internal/ from t1; +--source include/percona_query_cache_with_comments_eval.inc +let $query=select */$internal/from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $internal=* internal comment with "quote" *; + +let $query=select * /$internal/ from t1; +--source include/percona_query_cache_with_comments_eval.inc +let $query=select */$internal/ from t1; +--source include/percona_query_cache_with_comments_eval.inc +let $query=select */$internal/from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 +; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 ; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 ; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 +/* comment in the end */; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 +/* comment in the end */ +; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 #comment in the end; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 #comment in the end +; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 -- comment in the end; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select * from t1 -- comment in the end +; +--source include/percona_query_cache_with_comments_eval.inc diff --git a/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments.result b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments.result new file mode 100644 index 000000000000..169fdf80fef7 --- /dev/null +++ b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments.result @@ -0,0 +1,866 @@ +set global query_cache_strip_comments=ON; +set GLOBAL query_cache_size=1355776; +drop table if exists t1; +create table t1 (a int not null); +insert into t1 values (1),(2),(3); +flush query cache; +flush query cache; +reset query cache; +flush status; +flush query cache; +flush query cache; +reset query cache; +flush status; +/* with comment first */select * from t1; +a +1 +2 +3 +----------------------------------------------------- +/* with comment first */select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +/* with comment first */select * from t1; +a +1 +2 +3 +/* with comment first */select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +----------------------------------------------------- +# with comment first +select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +# with comment first +select * from t1; +a +1 +2 +3 +# with comment first +select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 4 +----------------------------------------------------- +-- with comment first +select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 4 +-- with comment first +select * from t1; +a +1 +2 +3 +-- with comment first +select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 6 +----------------------------------------------------- +/* with comment first and "quote" */select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 6 +/* with comment first and "quote" */select * from t1; +a +1 +2 +3 +/* with comment first and "quote" */select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 8 +----------------------------------------------------- +# with comment first and "quote" +select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 8 +# with comment first and "quote" +select * from t1; +a +1 +2 +3 +# with comment first and "quote" +select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 10 +----------------------------------------------------- +-- with comment first and "quote" +select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 10 +-- with comment first and "quote" +select * from t1; +a +1 +2 +3 +-- with comment first and "quote" +select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 12 +----------------------------------------------------- +/* with comment and whitespaces first */select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 12 +/* with comment and whitespaces first */select * from t1; +a +1 +2 +3 +/* with comment and whitespaces first */select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 14 +----------------------------------------------------- +# with comment and whitespaces first +select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 14 +# with comment and whitespaces first +select * from t1; +a +1 +2 +3 +# with comment and whitespaces first +select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 16 +----------------------------------------------------- +-- with comment and whitespaces first +select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 16 +-- with comment and whitespaces first +select * from t1; +a +1 +2 +3 +-- with comment and whitespaces first +select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 18 +----------------------------------------------------- +select * /* internal comment */ from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 18 +select * /* internal comment */ from t1; +a +1 +2 +3 +select * /* internal comment */ from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 20 +----------------------------------------------------- +select */* internal comment */ from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 20 +select */* internal comment */ from t1; +a +1 +2 +3 +select */* internal comment */ from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 22 +----------------------------------------------------- +select */* internal comment */from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 22 +select */* internal comment */from t1; +a +1 +2 +3 +select */* internal comment */from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 24 +----------------------------------------------------- +select * /* internal comment with "quote" */ from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 24 +select * /* internal comment with "quote" */ from t1; +a +1 +2 +3 +select * /* internal comment with "quote" */ from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 26 +----------------------------------------------------- +select */* internal comment with "quote" */ from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 26 +select */* internal comment with "quote" */ from t1; +a +1 +2 +3 +select */* internal comment with "quote" */ from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 28 +----------------------------------------------------- +select */* internal comment with "quote" */from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 28 +select */* internal comment with "quote" */from t1; +a +1 +2 +3 +select */* internal comment with "quote" */from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 30 +----------------------------------------------------- +select * from t1 + +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 30 +select * from t1 +; +a +1 +2 +3 +select * from t1 +; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 32 +----------------------------------------------------- +select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 32 +select * from t1 ; +a +1 +2 +3 +select * from t1 ; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 34 +----------------------------------------------------- +select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 34 +select * from t1 ; +a +1 +2 +3 +select * from t1 ; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 36 +----------------------------------------------------- +select * from t1 +/* comment in the end */ +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 36 +select * from t1 +/* comment in the end */; +a +1 +2 +3 +select * from t1 +/* comment in the end */; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 38 +----------------------------------------------------- +select * from t1 +/* *\/ */ +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 38 +select * from t1 +/* *\/ */; +a +1 +2 +3 +select * from t1 +/* *\/ */; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 40 +----------------------------------------------------- +select * from t1 +/* comment in the end */ + +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 40 +select * from t1 +/* comment in the end */ +; +a +1 +2 +3 +select * from t1 +/* comment in the end */ +; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 42 +----------------------------------------------------- +select * from t1 #comment in the end +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 42 +select * from t1 #comment in the end; +a +1 +2 +3 +select * from t1 #comment in the end; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 44 +----------------------------------------------------- +select * from t1 #comment in the end + +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 44 +select * from t1 #comment in the end +; +a +1 +2 +3 +select * from t1 #comment in the end +; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 46 +----------------------------------------------------- +select * from t1 -- comment in the end +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 46 +select * from t1 -- comment in the end; +a +1 +2 +3 +select * from t1 -- comment in the end; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 48 +----------------------------------------------------- +select * from t1 -- comment in the end + +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 48 +select * from t1 -- comment in the end +; +a +1 +2 +3 +select * from t1 -- comment in the end +; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 50 +----------------------------------------------------- +select ' \' ' from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 50 +select ' \' ' from t1; +' + ' + ' + ' +select ' \' ' from t1; +' + ' + ' + ' +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 51 +DROP TABLE t1; +SET GLOBAL query_cache_size=default; +set global query_cache_strip_comments=OFF; diff --git a/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments.test b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments.test new file mode 100644 index 000000000000..0b93441f3640 --- /dev/null +++ b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments.test @@ -0,0 +1,5 @@ +--disable_ps_protocol +set global query_cache_strip_comments=ON; +-- source include/percona_query_cache_with_comments_begin.inc +-- source include/percona_query_cache_with_comments.inc +-- source include/percona_query_cache_with_comments_end.inc diff --git a/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_begin.inc b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_begin.inc new file mode 100644 index 000000000000..38bfce20263c --- /dev/null +++ b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_begin.inc @@ -0,0 +1,12 @@ +-- source include/have_query_cache.inc + +set GLOBAL query_cache_size=1355776; + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (a int not null); +insert into t1 values (1),(2),(3); + +--source include/percona_query_cache_with_comments_clear.inc diff --git a/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_clear.inc b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_clear.inc new file mode 100644 index 000000000000..728a19a3c97e --- /dev/null +++ b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_clear.inc @@ -0,0 +1,5 @@ +# Reset query cache variables. +flush query cache; # This crashed in some versions +flush query cache; # This crashed in some versions +reset query cache; +flush status; diff --git a/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_crash.result b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_crash.result new file mode 100644 index 000000000000..32bd3645ec4c --- /dev/null +++ b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_crash.result @@ -0,0 +1,21 @@ +set GLOBAL query_cache_size=1355776; +drop table if exists t1; +create table t1 (a int not null); +insert into t1 values (1),(2),(3); +flush query cache; +flush query cache; +reset query cache; +flush status; +( select * from t1 ); +a +1 +2 +3 +/*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, @@SQL_MODE := REPLACE(REPLACE(@@SQL_MODE, 'ANSI_QUOTES', ''), ',,', ','), @OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, @@SQL_QUOTE_SHOW_CREATE := 1 */; +/* only comment */; +# only comment +; +-- only comment +; +DROP TABLE t1; +SET GLOBAL query_cache_size= default; diff --git a/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_crash.test b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_crash.test new file mode 100644 index 000000000000..e125c75c3dee --- /dev/null +++ b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_crash.test @@ -0,0 +1,22 @@ +-- source include/have_query_cache.inc +set GLOBAL query_cache_size=1355776; +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int not null); +insert into t1 values (1),(2),(3); +flush query cache; # This crashed in some versions +flush query cache; # This crashed in some versions +reset query cache; +flush status; +( select * from t1 ); +/*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, @@SQL_MODE := REPLACE(REPLACE(@@SQL_MODE, 'ANSI_QUOTES', ''), ',,', ','), @OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, @@SQL_QUOTE_SHOW_CREATE := 1 */; +/* only comment */; +let query=# only comment +; +eval $query; +let query=-- only comment +; +eval $query; +DROP TABLE t1; +SET GLOBAL query_cache_size= default; diff --git a/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_disable.result b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_disable.result new file mode 100644 index 000000000000..a13a44d9a1cd --- /dev/null +++ b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_disable.result @@ -0,0 +1,865 @@ +set GLOBAL query_cache_size=1355776; +drop table if exists t1; +create table t1 (a int not null); +insert into t1 values (1),(2),(3); +flush query cache; +flush query cache; +reset query cache; +flush status; +flush query cache; +flush query cache; +reset query cache; +flush status; +/* with comment first */select * from t1; +a +1 +2 +3 +----------------------------------------------------- +/* with comment first */select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +/* with comment first */select * from t1; +a +1 +2 +3 +/* with comment first */select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +----------------------------------------------------- +# with comment first +select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +# with comment first +select * from t1; +a +1 +2 +3 +# with comment first +select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +----------------------------------------------------- +-- with comment first +select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +-- with comment first +select * from t1; +a +1 +2 +3 +-- with comment first +select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 3 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 3 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +----------------------------------------------------- +/* with comment first and "quote" */select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 3 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 3 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +/* with comment first and "quote" */select * from t1; +a +1 +2 +3 +/* with comment first and "quote" */select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 4 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 4 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 3 +----------------------------------------------------- +# with comment first and "quote" +select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 4 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 4 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 3 +# with comment first and "quote" +select * from t1; +a +1 +2 +3 +# with comment first and "quote" +select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 5 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 5 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 3 +----------------------------------------------------- +-- with comment first and "quote" +select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 5 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 5 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 3 +-- with comment first and "quote" +select * from t1; +a +1 +2 +3 +-- with comment first and "quote" +select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 6 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 6 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 3 +----------------------------------------------------- +/* with comment and whitespaces first */select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 6 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 6 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 3 +/* with comment and whitespaces first */select * from t1; +a +1 +2 +3 +/* with comment and whitespaces first */select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 7 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 7 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 4 +----------------------------------------------------- +# with comment and whitespaces first +select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 7 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 7 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 4 +# with comment and whitespaces first +select * from t1; +a +1 +2 +3 +# with comment and whitespaces first +select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 8 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 8 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 4 +----------------------------------------------------- +-- with comment and whitespaces first +select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 8 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 8 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 4 +-- with comment and whitespaces first +select * from t1; +a +1 +2 +3 +-- with comment and whitespaces first +select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 9 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 9 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 4 +----------------------------------------------------- +select * /* internal comment */ from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 9 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 9 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 4 +select * /* internal comment */ from t1; +a +1 +2 +3 +select * /* internal comment */ from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 10 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 10 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 5 +----------------------------------------------------- +select */* internal comment */ from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 10 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 10 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 5 +select */* internal comment */ from t1; +a +1 +2 +3 +select */* internal comment */ from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 11 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 11 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 6 +----------------------------------------------------- +select */* internal comment */from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 11 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 11 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 6 +select */* internal comment */from t1; +a +1 +2 +3 +select */* internal comment */from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 12 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 12 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 7 +----------------------------------------------------- +select * /* internal comment with "quote" */ from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 12 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 12 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 7 +select * /* internal comment with "quote" */ from t1; +a +1 +2 +3 +select * /* internal comment with "quote" */ from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 13 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 13 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 8 +----------------------------------------------------- +select */* internal comment with "quote" */ from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 13 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 13 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 8 +select */* internal comment with "quote" */ from t1; +a +1 +2 +3 +select */* internal comment with "quote" */ from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 14 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 14 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 9 +----------------------------------------------------- +select */* internal comment with "quote" */from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 14 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 14 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 9 +select */* internal comment with "quote" */from t1; +a +1 +2 +3 +select */* internal comment with "quote" */from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 15 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 15 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 10 +----------------------------------------------------- +select * from t1 + +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 15 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 15 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 10 +select * from t1 +; +a +1 +2 +3 +select * from t1 +; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 16 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 16 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 11 +----------------------------------------------------- +select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 16 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 16 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 11 +select * from t1 ; +a +1 +2 +3 +select * from t1 ; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 16 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 16 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 13 +----------------------------------------------------- +select * from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 16 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 16 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 13 +select * from t1 ; +a +1 +2 +3 +select * from t1 ; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 16 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 16 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 15 +----------------------------------------------------- +select * from t1 +/* comment in the end */ +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 16 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 16 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 15 +select * from t1 +/* comment in the end */; +a +1 +2 +3 +select * from t1 +/* comment in the end */; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 17 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 17 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 16 +----------------------------------------------------- +select * from t1 +/* *\/ */ +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 17 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 17 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 16 +select * from t1 +/* *\/ */; +a +1 +2 +3 +select * from t1 +/* *\/ */; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 18 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 18 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 17 +----------------------------------------------------- +select * from t1 +/* comment in the end */ + +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 18 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 18 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 17 +select * from t1 +/* comment in the end */ +; +a +1 +2 +3 +select * from t1 +/* comment in the end */ +; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 18 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 18 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 19 +----------------------------------------------------- +select * from t1 #comment in the end +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 18 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 18 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 19 +select * from t1 #comment in the end; +a +1 +2 +3 +select * from t1 #comment in the end; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 19 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 19 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 20 +----------------------------------------------------- +select * from t1 #comment in the end + +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 19 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 19 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 20 +select * from t1 #comment in the end +; +a +1 +2 +3 +select * from t1 #comment in the end +; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 19 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 19 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 22 +----------------------------------------------------- +select * from t1 -- comment in the end +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 19 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 19 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 22 +select * from t1 -- comment in the end; +a +1 +2 +3 +select * from t1 -- comment in the end; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 20 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 20 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 23 +----------------------------------------------------- +select * from t1 -- comment in the end + +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 20 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 20 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 23 +select * from t1 -- comment in the end +; +a +1 +2 +3 +select * from t1 -- comment in the end +; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 20 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 20 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 25 +----------------------------------------------------- +select ' \' ' from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 20 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 20 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 25 +select ' \' ' from t1; +' + ' + ' + ' +select ' \' ' from t1; +' + ' + ' + ' +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 21 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 21 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 26 +DROP TABLE t1; +SET GLOBAL query_cache_size=default; +set global query_cache_strip_comments=OFF; diff --git a/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_disable.test b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_disable.test new file mode 100644 index 000000000000..ad59ac3566c5 --- /dev/null +++ b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_disable.test @@ -0,0 +1,3 @@ +-- source include/percona_query_cache_with_comments_begin.inc +-- source include/percona_query_cache_with_comments.inc +-- source include/percona_query_cache_with_comments_end.inc diff --git a/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_end.inc b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_end.inc new file mode 100644 index 000000000000..d5356359d7e3 --- /dev/null +++ b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_end.inc @@ -0,0 +1,3 @@ +DROP TABLE t1; +SET GLOBAL query_cache_size=default; +set global query_cache_strip_comments=OFF; diff --git a/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_eval.inc b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_eval.inc new file mode 100644 index 000000000000..a409786d554b --- /dev/null +++ b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_eval.inc @@ -0,0 +1,7 @@ +echo -----------------------------------------------------; +echo $query; +echo -----------------------------------------------------; +--source include/percona_query_cache_with_comments_show.inc +eval $query; +eval $query; +--source include/percona_query_cache_with_comments_show.inc diff --git a/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_prepared_statements.result b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_prepared_statements.result new file mode 100644 index 000000000000..9b28b7f0b62c --- /dev/null +++ b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_prepared_statements.result @@ -0,0 +1,396 @@ +set GLOBAL query_cache_size=1355776; +flush query cache; +flush query cache; +reset query cache; +flush status; +drop table if exists t1; +create table t1 (a int not null); +insert into t1 values (1),(2),(3); +set global query_cache_strip_comments=ON; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +prepare stmt from '/* with comment */ select * from t1'; +execute stmt; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +execute stmt; +a +1 +2 +3 +execute stmt; +a +1 +2 +3 +execute stmt; +a +1 +2 +3 +execute stmt; +a +1 +2 +3 +execute stmt; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 5 +prepare stmt from 'select * from t1'; +execute stmt; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 6 +prepare stmt from 'select * /*internal comment*/from t1'; +execute stmt; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 7 +prepare stmt from 'select * /*internal comment*/ from t1'; +execute stmt; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 8 +prepare stmt from 'select * from t1 /* at the end */'; +execute stmt; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 9 +prepare stmt from 'select * from t1 /* with "quote" */'; +execute stmt; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 10 +prepare stmt from 'select * from t1 /* with \'quote\' */'; +execute stmt; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 11 +prepare stmt from 'select * from t1 # 123 +'; +execute stmt; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 12 +prepare stmt from 'select * from t1 # 123 with "quote" +'; +execute stmt; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 13 +prepare stmt from 'select * from t1 # 123 with \'quote\' +'; +execute stmt; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 14 +prepare stmt from 'select * from t1 +# 123 +'; +execute stmt; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 15 +prepare stmt from '#456 +select * from t1 +# 123 +'; +execute stmt; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 16 +prepare stmt from 'select * from t1 -- 123 +'; +execute stmt; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 17 +prepare stmt from 'select * from t1 +-- 123 +'; +execute stmt; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 18 +prepare stmt from '-- comment in first +select * from t1 +# 123 +'; +execute stmt; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 19 +prepare stmt from '(#456( +select * from t1 +# 123( +)'; +execute stmt; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 19 +prepare stmt from '/*test*/(-- comment in first( +select * from t1 +-- 123 asdasd +/* test */)'; +execute stmt; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 20 +prepare stmt from 'select "test",a from t1'; +execute stmt; +test a +test 1 +test 2 +test 3 +execute stmt; +test a +test 1 +test 2 +test 3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 3 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 3 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 21 +prepare stmt from 'select "test /* internal \'comment\' */",a from t1'; +execute stmt; +test /* internal 'comment' */ a +test /* internal 'comment' */ 1 +test /* internal 'comment' */ 2 +test /* internal 'comment' */ 3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 4 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 4 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 21 +prepare stmt from 'select "test #internal comment" ,a from t1'; +execute stmt; +test #internal comment a +test #internal comment 1 +test #internal comment 2 +test #internal comment 3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 5 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 5 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 21 +prepare stmt from 'select "test #internal comment" #external comment +,a from t1'; +execute stmt; +test #internal comment a +test #internal comment 1 +test #internal comment 2 +test #internal comment 3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 5 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 5 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 22 +DROP TABLE t1; +SET GLOBAL query_cache_size= default; +set global query_cache_strip_comments=OFF; diff --git a/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_prepared_statements.test b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_prepared_statements.test new file mode 100644 index 000000000000..78cb7220aff5 --- /dev/null +++ b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_prepared_statements.test @@ -0,0 +1,208 @@ +-- source include/have_query_cache.inc + +set GLOBAL query_cache_size=1355776; + +# Reset query cache variables. +flush query cache; # This crashed in some versions +flush query cache; # This crashed in some versions +reset query cache; +flush status; +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# First simple test +# + +create table t1 (a int not null); +insert into t1 values (1),(2),(3); + +set global query_cache_strip_comments=ON; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from '/* with comment */ select * from t1'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +execute stmt; +execute stmt; +execute stmt; +execute stmt; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from 'select * from t1'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from 'select * /*internal comment*/from t1'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from 'select * /*internal comment*/ from t1'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from 'select * from t1 /* at the end */'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from 'select * from t1 /* with "quote" */'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from 'select * from t1 /* with \'quote\' */'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from 'select * from t1 # 123 +'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from 'select * from t1 # 123 with "quote" +'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from 'select * from t1 # 123 with \'quote\' +'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from 'select * from t1 +# 123 +'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from '#456 +select * from t1 +# 123 +'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from 'select * from t1 -- 123 +'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from 'select * from t1 +-- 123 +'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from '-- comment in first +select * from t1 +# 123 +'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from '(#456( +select * from t1 +# 123( +)'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from '/*test*/(-- comment in first( +select * from t1 +-- 123 asdasd +/* test */)'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from 'select "test",a from t1'; +execute stmt; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from 'select "test /* internal \'comment\' */",a from t1'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from 'select "test #internal comment" ,a from t1'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +prepare stmt from 'select "test #internal comment" #external comment +,a from t1'; +execute stmt; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +DROP TABLE t1; +SET GLOBAL query_cache_size= default; +set global query_cache_strip_comments=OFF; diff --git a/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_show.inc b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_show.inc new file mode 100644 index 000000000000..71aa5211cfdc --- /dev/null +++ b/mysql-test/query_cache_enhance.patch/percona_query_cache_with_comments_show.inc @@ -0,0 +1,8 @@ +let $show=show status like "Qcache_queries_in_cache"; +eval $show; +let $show=show status like "Qcache_inserts"; +eval $show; +let $show=show status like "Qcache_hits"; +eval $show; + + diff --git a/mysql-test/query_cache_enhance.patch/percona_status_wait_query_cache_mutex.result b/mysql-test/query_cache_enhance.patch/percona_status_wait_query_cache_mutex.result new file mode 100644 index 000000000000..348dcef4d307 --- /dev/null +++ b/mysql-test/query_cache_enhance.patch/percona_status_wait_query_cache_mutex.result @@ -0,0 +1,27 @@ +set GLOBAL query_cache_size=1355776; +flush query cache; +flush query cache; +reset query cache; +flush status; +DROP TABLE IF EXISTS t; +CREATE TABLE t(id INT, number INT); +INSERT INTO t VALUES (0,1); +INSERT INTO t VALUES (1,2); +INSERT INTO t VALUES (2,3); +SELECT number from t where id > 0; +number +2 +3 +SET SESSION debug="+d,status_wait_query_cache_mutex_sleep"; +SELECT number from t where id > 0; +SET SESSION debug="+d,status_wait_query_cache_mutex_sleep"; +SELECT number from t where id > 0; +SET SESSION debug="+d,status_wait_query_cache_mutex_sleep"; +SHOW PROCESSLIST; +Id User Host db Command Time State Info +Id root localhost test Sleep Time NULL +Id root localhost test Query Time Waiting on query cache mutex SELECT number from t where id > 0 +Id root localhost test Query Time Waiting on query cache mutex SELECT number from t where id > 0 +Id root localhost test Query Time NULL SHOW PROCESSLIST +DROP TABLE t; +set GLOBAL query_cache_size=0; diff --git a/mysql-test/query_cache_enhance.patch/percona_status_wait_query_cache_mutex.test b/mysql-test/query_cache_enhance.patch/percona_status_wait_query_cache_mutex.test new file mode 100644 index 000000000000..3bbfe0edca97 --- /dev/null +++ b/mysql-test/query_cache_enhance.patch/percona_status_wait_query_cache_mutex.test @@ -0,0 +1,37 @@ +--source include/have_query_cache.inc +--source include/have_debug.inc +set GLOBAL query_cache_size=1355776; +--source include/percona_query_cache_with_comments_clear.inc + +-- disable_warnings +DROP TABLE IF EXISTS t; +-- enable_warnings +CREATE TABLE t(id INT, number INT); +INSERT INTO t VALUES (0,1); +INSERT INTO t VALUES (1,2); +INSERT INTO t VALUES (2,3); +SELECT number from t where id > 0; +--connect (conn0,localhost,root,,) +--connect (conn1,localhost,root,,) +--connect (conn2,localhost,root,,) + +--connection conn0 +--error 0, ER_UNKNOWN_SYSTEM_VARIABLE +SET SESSION debug="+d,status_wait_query_cache_mutex_sleep"; +SEND SELECT number from t where id > 0; +SLEEP 1.0; + +--connection conn1 +--error 0, ER_UNKNOWN_SYSTEM_VARIABLE +SET SESSION debug="+d,status_wait_query_cache_mutex_sleep"; +SEND SELECT number from t where id > 0; +SLEEP 1.0; + +--connection conn2 +--error 0, ER_UNKNOWN_SYSTEM_VARIABLE +SET SESSION debug="+d,status_wait_query_cache_mutex_sleep"; +--replace_column 1 Id 6 Time +SHOW PROCESSLIST; + +DROP TABLE t; +set GLOBAL query_cache_size=0; diff --git a/mysql-test/response-time-distribution.patch/percona_query_response_time-replication.result b/mysql-test/response-time-distribution.patch/percona_query_response_time-replication.result new file mode 100644 index 000000000000..950cdbf75322 --- /dev/null +++ b/mysql-test/response-time-distribution.patch/percona_query_response_time-replication.result @@ -0,0 +1,70 @@ +stop slave; +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; +start slave; +SET SESSION debug="+d,response_time_distribution_log_only_more_300_milliseconds"; +DROP TABLE IF EXISTS t; +CREATE TABLE t(id INT); +SELECT * from t; +id +SELECT * from t; +id +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1; +Warnings: +Warning 1292 Truncated incorrect query_response_time_range_base value: '1' +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 2 +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 10; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 10 +FLUSH QUERY_RESPONSE_TIME; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=ON; +INSERT INTO t SELECT SLEEP(0.4); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) +0 +INSERT INTO t SELECT SLEEP(0.4); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) +0 +SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) +2 +SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) +3 +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 2; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 2 +FLUSH QUERY_RESPONSE_TIME; +INSERT INTO t SELECT SLEEP(0.4); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) +0 +INSERT INTO t SELECT SLEEP(0.4); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) +0 +SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) +2 +SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) +3 +DROP TABLE IF EXISTS t; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 10; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=OFF; +SET SESSION debug="-d,response_time_distribution_log_only_more_300_milliseconds"; diff --git a/mysql-test/response-time-distribution.patch/percona_query_response_time-replication.test b/mysql-test/response-time-distribution.patch/percona_query_response_time-replication.test new file mode 100644 index 000000000000..5dbb051f5d9e --- /dev/null +++ b/mysql-test/response-time-distribution.patch/percona_query_response_time-replication.test @@ -0,0 +1,56 @@ +--source include/master-slave.inc +--source include/have_binlog_format_statement.inc +--source include/have_debug.inc +SET SESSION debug="+d,response_time_distribution_log_only_more_300_milliseconds"; + +connection master; +-- disable_warnings +DROP TABLE IF EXISTS t; +-- enable_warnings +CREATE TABLE t(id INT); +SELECT * from t; + +sync_slave_with_master; + +connection slave; +SELECT * from t; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 10; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +source include/percona_query_response_time_flush.inc; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=ON; + +connection master; +INSERT INTO t SELECT SLEEP(0.4); +SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +INSERT INTO t SELECT SLEEP(0.4); +SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +sync_slave_with_master; + +connection slave; +SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; + +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 2; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +source include/percona_query_response_time_flush.inc; + +connection master; +INSERT INTO t SELECT SLEEP(0.4); +SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +INSERT INTO t SELECT SLEEP(0.4); +SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +sync_slave_with_master; + +connection slave; +SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; + +connection master; +DROP TABLE IF EXISTS t; +sync_slave_with_master; +connection slave; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 10; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=OFF; +SET SESSION debug="-d,response_time_distribution_log_only_more_300_milliseconds"; diff --git a/mysql-test/response-time-distribution.patch/percona_query_response_time-stored.result b/mysql-test/response-time-distribution.patch/percona_query_response_time-stored.result new file mode 100644 index 000000000000..6ca471867abc --- /dev/null +++ b/mysql-test/response-time-distribution.patch/percona_query_response_time-stored.result @@ -0,0 +1,313 @@ +SET SESSION debug="+d,response_time_distribution_log_only_more_300_milliseconds"; +CREATE FUNCTION test_f() +RETURNS CHAR(30) DETERMINISTIC +BEGIN +DECLARE first VARCHAR(5); +DECLARE second VARCHAR(5); +DECLARE result VARCHAR(20); +SELECT SLEEP(1.11) INTO first; +SET first= 'Hello'; +SET second=', '; +SET result= CONCAT(first,second); +SET result= CONCAT(result,'world!'); +RETURN result; +END/ +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1; +Warnings: +Warning 1292 Truncated incorrect query_response_time_range_base value: '1' +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 2 +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 2; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 2 +FLUSH QUERY_RESPONSE_TIME; +SELECT d.count, +(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count, +(SELECT SUM((b.total * 1000000) DIV 1000000) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as query_total, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count != 0) as not_zero_region_count, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count +FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as d WHERE d.count > 0; +count query_count query_total not_zero_region_count region_count +SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +region_count +44 +SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +time + 0.000001 + 0.000003 + 0.000007 + 0.000015 + 0.000030 + 0.000061 + 0.000122 + 0.000244 + 0.000488 + 0.000976 + 0.001953 + 0.003906 + 0.007812 + 0.015625 + 0.031250 + 0.062500 + 0.125000 + 0.250000 + 0.500000 + 1.000000 + 2.000000 + 4.000000 + 8.000000 + 16.000000 + 32.000000 + 64.000000 + 128.000000 + 256.000000 + 512.000000 + 1024.000000 + 2048.000000 + 4096.000000 + 8192.000000 + 16384.000000 + 32768.000000 + 65536.000000 + 131072.000000 + 262144.000000 + 524288.000000 + 1048576.00000 + 2097152.00000 + 4194304.00000 + 8388608.00000 +TOO LONG +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +SELECT test_f(); +test_f() +Hello, world! +SELECT test_f(); +test_f() +Hello, world! +SELECT test_f(); +test_f() +Hello, world! +SELECT test_f(); +test_f() +Hello, world! +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; +SELECT d.count, +(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count, +(SELECT SUM((b.total * 1000000) DIV 1000000) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as query_total, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count != 0) as not_zero_region_count, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count +FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as d WHERE d.count > 0; +count query_count query_total not_zero_region_count region_count +4 4 4 1 44 +SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +region_count +44 +SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +time + 0.000001 + 0.000003 + 0.000007 + 0.000015 + 0.000030 + 0.000061 + 0.000122 + 0.000244 + 0.000488 + 0.000976 + 0.001953 + 0.003906 + 0.007812 + 0.015625 + 0.031250 + 0.062500 + 0.125000 + 0.250000 + 0.500000 + 1.000000 + 2.000000 + 4.000000 + 8.000000 + 16.000000 + 32.000000 + 64.000000 + 128.000000 + 256.000000 + 512.000000 + 1024.000000 + 2048.000000 + 4096.000000 + 8192.000000 + 16384.000000 + 32768.000000 + 65536.000000 + 131072.000000 + 262144.000000 + 524288.000000 + 1048576.00000 + 2097152.00000 + 4194304.00000 + 8388608.00000 +TOO LONG +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 2 +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 10; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 10 +FLUSH QUERY_RESPONSE_TIME; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +SELECT test_f(); +test_f() +Hello, world! +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; +SELECT d.count, +(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count, +(SELECT SUM((b.total * 1000000) DIV 1000000) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as query_total, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count != 0) as not_zero_region_count, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count +FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as d WHERE d.count > 0; +count query_count query_total not_zero_region_count region_count +1 1 1 1 14 +SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +region_count +14 +SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +time + 0.000001 + 0.000010 + 0.000100 + 0.001000 + 0.010000 + 0.100000 + 1.000000 + 10.000000 + 100.000000 + 1000.000000 + 10000.000000 + 100000.000000 + 1000000.00000 +TOO LONG +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 10 +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 7; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 7 +FLUSH QUERY_RESPONSE_TIME; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +SELECT test_f(); +test_f() +Hello, world! +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; +SELECT d.count, +(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count, +(SELECT SUM((b.total * 1000000) DIV 1000000) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as query_total, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count != 0) as not_zero_region_count, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count +FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as d WHERE d.count > 0; +count query_count query_total not_zero_region_count region_count +1 1 1 1 17 +SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +region_count +17 +SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +time + 0.000001 + 0.000008 + 0.000059 + 0.000416 + 0.002915 + 0.020408 + 0.142857 + 1.000000 + 7.000000 + 49.000000 + 343.000000 + 2401.000000 + 16807.000000 + 117649.000000 + 823543.000000 + 5764801.00000 +TOO LONG +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 7 +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 156; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 156 +FLUSH QUERY_RESPONSE_TIME; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +SELECT test_f(); +test_f() +Hello, world! +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; +SELECT d.count, +(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count, +(SELECT SUM((b.total * 1000000) DIV 1000000) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as query_total, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count != 0) as not_zero_region_count, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count +FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as d WHERE d.count > 0; +count query_count query_total not_zero_region_count region_count +1 1 1 1 7 +SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +region_count +7 +SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +time + 0.000041 + 0.006410 + 1.000000 + 156.000000 + 24336.000000 + 3796416.00000 +TOO LONG +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 156 +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1000; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 1000 +FLUSH QUERY_RESPONSE_TIME; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +SELECT test_f(); +test_f() +Hello, world! +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; +SELECT d.count, +(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count, +(SELECT SUM((b.total * 1000000) DIV 1000000) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as query_total, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count != 0) as not_zero_region_count, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count +FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as d WHERE d.count > 0; +count query_count query_total not_zero_region_count region_count +1 1 1 1 6 +SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +region_count +6 +SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +time + 0.000001 + 0.001000 + 1.000000 + 1000.000000 + 1000000.00000 +TOO LONG +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 1000 +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1001; +Warnings: +Warning 1292 Truncated incorrect query_response_time_range_base value: '1001' +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 1000 +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE =10; +DROP FUNCTION test_f; +SET SESSION debug="-d,response_time_distribution_log_only_more_300_milliseconds"; diff --git a/mysql-test/response-time-distribution.patch/percona_query_response_time-stored.test b/mysql-test/response-time-distribution.patch/percona_query_response_time-stored.test new file mode 100644 index 000000000000..6035d280fe0c --- /dev/null +++ b/mysql-test/response-time-distribution.patch/percona_query_response_time-stored.test @@ -0,0 +1,90 @@ +source include/have_innodb.inc; +source include/have_debug.inc; +SET SESSION debug="+d,response_time_distribution_log_only_more_300_milliseconds"; + +delimiter /; +CREATE FUNCTION test_f() +RETURNS CHAR(30) DETERMINISTIC +BEGIN + DECLARE first VARCHAR(5); + DECLARE second VARCHAR(5); + DECLARE result VARCHAR(20); + SELECT SLEEP(1.11) INTO first; + SET first= 'Hello'; + SET second=', '; + SET result= CONCAT(first,second); + SET result= CONCAT(result,'world!'); + RETURN result; +END/ +delimiter ;/ + +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 2; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; + +source include/percona_query_response_time_flush.inc; +source include/percona_query_response_time_show.inc; + +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +SELECT test_f(); +SELECT test_f(); +SELECT test_f(); +SELECT test_f(); +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; + +source include/percona_query_response_time_show.inc; + +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 10; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; + +source include/percona_query_response_time_flush.inc; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +SELECT test_f(); +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; + +source include/percona_query_response_time_show.inc; + +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 7; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; + +source include/percona_query_response_time_flush.inc; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +SELECT test_f(); +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; + +source include/percona_query_response_time_show.inc; + +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 156; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; + +source include/percona_query_response_time_flush.inc; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +SELECT test_f(); +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; + +source include/percona_query_response_time_show.inc; + +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1000; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; + +source include/percona_query_response_time_flush.inc; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +SELECT test_f(); +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; + +source include/percona_query_response_time_show.inc; + +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1001; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; + +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE =10; + +DROP FUNCTION test_f; +SET SESSION debug="-d,response_time_distribution_log_only_more_300_milliseconds"; diff --git a/mysql-test/response-time-distribution.patch/percona_query_response_time.result b/mysql-test/response-time-distribution.patch/percona_query_response_time.result new file mode 100644 index 000000000000..7599c9f0263d --- /dev/null +++ b/mysql-test/response-time-distribution.patch/percona_query_response_time.result @@ -0,0 +1,567 @@ +SET SESSION debug="+d,response_time_distribution_log_only_more_300_milliseconds"; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1; +Warnings: +Warning 1292 Truncated incorrect query_response_time_range_base value: '1' +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 2 +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 2; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 2 +FLUSH QUERY_RESPONSE_TIME; +SELECT d.count, +(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count, +(SELECT SUM((b.total * 1000000) DIV 1000000) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as query_total, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count != 0) as not_zero_region_count, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count +FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as d WHERE d.count > 0; +count query_count query_total not_zero_region_count region_count +SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +region_count +44 +SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +time + 0.000001 + 0.000003 + 0.000007 + 0.000015 + 0.000030 + 0.000061 + 0.000122 + 0.000244 + 0.000488 + 0.000976 + 0.001953 + 0.003906 + 0.007812 + 0.015625 + 0.031250 + 0.062500 + 0.125000 + 0.250000 + 0.500000 + 1.000000 + 2.000000 + 4.000000 + 8.000000 + 16.000000 + 32.000000 + 64.000000 + 128.000000 + 256.000000 + 512.000000 + 1024.000000 + 2048.000000 + 4096.000000 + 8192.000000 + 16384.000000 + 32768.000000 + 65536.000000 + 131072.000000 + 262144.000000 + 524288.000000 + 1048576.00000 + 2097152.00000 + 4194304.00000 + 8388608.00000 +TOO LONG +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +SELECT SLEEP(0.31); +SLEEP(0.31) +0 +SELECT SLEEP(0.32); +SLEEP(0.32) +0 +SELECT SLEEP(0.33); +SLEEP(0.33) +0 +SELECT SLEEP(0.34); +SLEEP(0.34) +0 +SELECT SLEEP(0.35); +SLEEP(0.35) +0 +SELECT SLEEP(0.36); +SLEEP(0.36) +0 +SELECT SLEEP(0.37); +SLEEP(0.37) +0 +SELECT SLEEP(0.38); +SLEEP(0.38) +0 +SELECT SLEEP(0.39); +SLEEP(0.39) +0 +SELECT SLEEP(0.40); +SLEEP(0.40) +0 +SELECT SLEEP(1.1); +SLEEP(1.1) +0 +SELECT SLEEP(1.2); +SLEEP(1.2) +0 +SELECT SLEEP(1.3); +SLEEP(1.3) +0 +SELECT SLEEP(1.5); +SLEEP(1.5) +0 +SELECT SLEEP(1.4); +SLEEP(1.4) +0 +SELECT SLEEP(0.5); +SLEEP(0.5) +0 +SELECT SLEEP(2.1); +SLEEP(2.1) +0 +SELECT SLEEP(2.3); +SLEEP(2.3) +0 +SELECT SLEEP(2.5); +SLEEP(2.5) +0 +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; +SELECT d.count, +(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count, +(SELECT SUM((b.total * 1000000) DIV 1000000) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as query_total, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count != 0) as not_zero_region_count, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count +FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as d WHERE d.count > 0; +count query_count query_total not_zero_region_count region_count +10 19 15 4 44 +1 19 15 4 44 +5 19 15 4 44 +3 19 15 4 44 +SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +region_count +44 +SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +time + 0.000001 + 0.000003 + 0.000007 + 0.000015 + 0.000030 + 0.000061 + 0.000122 + 0.000244 + 0.000488 + 0.000976 + 0.001953 + 0.003906 + 0.007812 + 0.015625 + 0.031250 + 0.062500 + 0.125000 + 0.250000 + 0.500000 + 1.000000 + 2.000000 + 4.000000 + 8.000000 + 16.000000 + 32.000000 + 64.000000 + 128.000000 + 256.000000 + 512.000000 + 1024.000000 + 2048.000000 + 4096.000000 + 8192.000000 + 16384.000000 + 32768.000000 + 65536.000000 + 131072.000000 + 262144.000000 + 524288.000000 + 1048576.00000 + 2097152.00000 + 4194304.00000 + 8388608.00000 +TOO LONG +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 2 +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 10; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 10 +FLUSH QUERY_RESPONSE_TIME; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +SELECT SLEEP(0.31); +SLEEP(0.31) +0 +SELECT SLEEP(0.32); +SLEEP(0.32) +0 +SELECT SLEEP(0.33); +SLEEP(0.33) +0 +SELECT SLEEP(0.34); +SLEEP(0.34) +0 +SELECT SLEEP(0.35); +SLEEP(0.35) +0 +SELECT SLEEP(0.36); +SLEEP(0.36) +0 +SELECT SLEEP(0.37); +SLEEP(0.37) +0 +SELECT SLEEP(0.38); +SLEEP(0.38) +0 +SELECT SLEEP(0.39); +SLEEP(0.39) +0 +SELECT SLEEP(0.40); +SLEEP(0.40) +0 +SELECT SLEEP(1.1); +SLEEP(1.1) +0 +SELECT SLEEP(1.2); +SLEEP(1.2) +0 +SELECT SLEEP(1.3); +SLEEP(1.3) +0 +SELECT SLEEP(1.5); +SLEEP(1.5) +0 +SELECT SLEEP(1.4); +SLEEP(1.4) +0 +SELECT SLEEP(0.5); +SLEEP(0.5) +0 +SELECT SLEEP(2.1); +SLEEP(2.1) +0 +SELECT SLEEP(2.3); +SLEEP(2.3) +0 +SELECT SLEEP(2.5); +SLEEP(2.5) +0 +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; +SELECT d.count, +(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count, +(SELECT SUM((b.total * 1000000) DIV 1000000) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as query_total, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count != 0) as not_zero_region_count, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count +FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as d WHERE d.count > 0; +count query_count query_total not_zero_region_count region_count +11 19 17 2 14 +8 19 17 2 14 +SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +region_count +14 +SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +time + 0.000001 + 0.000010 + 0.000100 + 0.001000 + 0.010000 + 0.100000 + 1.000000 + 10.000000 + 100.000000 + 1000.000000 + 10000.000000 + 100000.000000 + 1000000.00000 +TOO LONG +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 10 +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 7; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 7 +FLUSH QUERY_RESPONSE_TIME; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +SELECT SLEEP(0.31); +SLEEP(0.31) +0 +SELECT SLEEP(0.32); +SLEEP(0.32) +0 +SELECT SLEEP(0.33); +SLEEP(0.33) +0 +SELECT SLEEP(0.34); +SLEEP(0.34) +0 +SELECT SLEEP(0.35); +SLEEP(0.35) +0 +SELECT SLEEP(0.36); +SLEEP(0.36) +0 +SELECT SLEEP(0.37); +SLEEP(0.37) +0 +SELECT SLEEP(0.38); +SLEEP(0.38) +0 +SELECT SLEEP(0.39); +SLEEP(0.39) +0 +SELECT SLEEP(0.40); +SLEEP(0.40) +0 +SELECT SLEEP(1.1); +SLEEP(1.1) +0 +SELECT SLEEP(1.2); +SLEEP(1.2) +0 +SELECT SLEEP(1.3); +SLEEP(1.3) +0 +SELECT SLEEP(1.5); +SLEEP(1.5) +0 +SELECT SLEEP(1.4); +SLEEP(1.4) +0 +SELECT SLEEP(0.5); +SLEEP(0.5) +0 +SELECT SLEEP(2.1); +SLEEP(2.1) +0 +SELECT SLEEP(2.3); +SLEEP(2.3) +0 +SELECT SLEEP(2.5); +SLEEP(2.5) +0 +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; +SELECT d.count, +(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count, +(SELECT SUM((b.total * 1000000) DIV 1000000) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as query_total, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count != 0) as not_zero_region_count, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count +FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as d WHERE d.count > 0; +count query_count query_total not_zero_region_count region_count +11 19 17 2 17 +8 19 17 2 17 +SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +region_count +17 +SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +time + 0.000001 + 0.000008 + 0.000059 + 0.000416 + 0.002915 + 0.020408 + 0.142857 + 1.000000 + 7.000000 + 49.000000 + 343.000000 + 2401.000000 + 16807.000000 + 117649.000000 + 823543.000000 + 5764801.00000 +TOO LONG +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 7 +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 156; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 156 +FLUSH QUERY_RESPONSE_TIME; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +SELECT SLEEP(0.31); +SLEEP(0.31) +0 +SELECT SLEEP(0.32); +SLEEP(0.32) +0 +SELECT SLEEP(0.33); +SLEEP(0.33) +0 +SELECT SLEEP(0.34); +SLEEP(0.34) +0 +SELECT SLEEP(0.35); +SLEEP(0.35) +0 +SELECT SLEEP(0.36); +SLEEP(0.36) +0 +SELECT SLEEP(0.37); +SLEEP(0.37) +0 +SELECT SLEEP(0.38); +SLEEP(0.38) +0 +SELECT SLEEP(0.39); +SLEEP(0.39) +0 +SELECT SLEEP(0.40); +SLEEP(0.40) +0 +SELECT SLEEP(1.1); +SLEEP(1.1) +0 +SELECT SLEEP(1.2); +SLEEP(1.2) +0 +SELECT SLEEP(1.3); +SLEEP(1.3) +0 +SELECT SLEEP(1.5); +SLEEP(1.5) +0 +SELECT SLEEP(1.4); +SLEEP(1.4) +0 +SELECT SLEEP(0.5); +SLEEP(0.5) +0 +SELECT SLEEP(2.1); +SLEEP(2.1) +0 +SELECT SLEEP(2.3); +SLEEP(2.3) +0 +SELECT SLEEP(2.5); +SLEEP(2.5) +0 +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; +SELECT d.count, +(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count, +(SELECT SUM((b.total * 1000000) DIV 1000000) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as query_total, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count != 0) as not_zero_region_count, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count +FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as d WHERE d.count > 0; +count query_count query_total not_zero_region_count region_count +11 19 17 2 7 +8 19 17 2 7 +SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +region_count +7 +SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +time + 0.000041 + 0.006410 + 1.000000 + 156.000000 + 24336.000000 + 3796416.00000 +TOO LONG +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 156 +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1000; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 1000 +FLUSH QUERY_RESPONSE_TIME; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +SELECT SLEEP(0.31); +SLEEP(0.31) +0 +SELECT SLEEP(0.32); +SLEEP(0.32) +0 +SELECT SLEEP(0.33); +SLEEP(0.33) +0 +SELECT SLEEP(0.34); +SLEEP(0.34) +0 +SELECT SLEEP(0.35); +SLEEP(0.35) +0 +SELECT SLEEP(0.36); +SLEEP(0.36) +0 +SELECT SLEEP(0.37); +SLEEP(0.37) +0 +SELECT SLEEP(0.38); +SLEEP(0.38) +0 +SELECT SLEEP(0.39); +SLEEP(0.39) +0 +SELECT SLEEP(0.40); +SLEEP(0.40) +0 +SELECT SLEEP(1.1); +SLEEP(1.1) +0 +SELECT SLEEP(1.2); +SLEEP(1.2) +0 +SELECT SLEEP(1.3); +SLEEP(1.3) +0 +SELECT SLEEP(1.5); +SLEEP(1.5) +0 +SELECT SLEEP(1.4); +SLEEP(1.4) +0 +SELECT SLEEP(0.5); +SLEEP(0.5) +0 +SELECT SLEEP(2.1); +SLEEP(2.1) +0 +SELECT SLEEP(2.3); +SLEEP(2.3) +0 +SELECT SLEEP(2.5); +SLEEP(2.5) +0 +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; +SELECT d.count, +(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count, +(SELECT SUM((b.total * 1000000) DIV 1000000) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as query_total, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count != 0) as not_zero_region_count, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count +FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as d WHERE d.count > 0; +count query_count query_total not_zero_region_count region_count +11 19 17 2 6 +8 19 17 2 6 +SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +region_count +6 +SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +time + 0.000001 + 0.001000 + 1.000000 + 1000.000000 + 1000000.00000 +TOO LONG +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 1000 +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1001; +Warnings: +Warning 1292 Truncated incorrect query_response_time_range_base value: '1001' +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +Variable_name Value +query_response_time_range_base 1000 +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE =10; +SET SESSION debug="-d,response_time_distribution_log_only_more_300_milliseconds"; diff --git a/mysql-test/response-time-distribution.patch/percona_query_response_time.test b/mysql-test/response-time-distribution.patch/percona_query_response_time.test new file mode 100644 index 000000000000..877e28356fea --- /dev/null +++ b/mysql-test/response-time-distribution.patch/percona_query_response_time.test @@ -0,0 +1,68 @@ +source include/have_innodb.inc; +source include/have_debug.inc; +SET SESSION debug="+d,response_time_distribution_log_only_more_300_milliseconds"; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 2; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; + +source include/percona_query_response_time_flush.inc; +source include/percona_query_response_time_show.inc; + +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +source include/percona_query_response_time_sleep.inc; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; + +source include/percona_query_response_time_show.inc; + +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 10; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; + +source include/percona_query_response_time_flush.inc; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +source include/percona_query_response_time_sleep.inc; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; + +source include/percona_query_response_time_show.inc; + +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 7; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; + +source include/percona_query_response_time_flush.inc; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +source include/percona_query_response_time_sleep.inc; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; + +source include/percona_query_response_time_show.inc; + +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 156; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; + +source include/percona_query_response_time_flush.inc; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +source include/percona_query_response_time_sleep.inc; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; + +source include/percona_query_response_time_show.inc; + +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1000; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; + +source include/percona_query_response_time_flush.inc; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1; +source include/percona_query_response_time_sleep.inc; +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; + +source include/percona_query_response_time_show.inc; + +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1001; +SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE'; + +SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0; +SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE =10; +SET SESSION debug="-d,response_time_distribution_log_only_more_300_milliseconds"; diff --git a/mysql-test/response-time-distribution.patch/percona_query_response_time_flush.inc b/mysql-test/response-time-distribution.patch/percona_query_response_time_flush.inc new file mode 100644 index 000000000000..44bb320fe130 --- /dev/null +++ b/mysql-test/response-time-distribution.patch/percona_query_response_time_flush.inc @@ -0,0 +1 @@ +FLUSH QUERY_RESPONSE_TIME; diff --git a/mysql-test/response-time-distribution.patch/percona_query_response_time_show.inc b/mysql-test/response-time-distribution.patch/percona_query_response_time_show.inc new file mode 100644 index 000000000000..709abf9872e3 --- /dev/null +++ b/mysql-test/response-time-distribution.patch/percona_query_response_time_show.inc @@ -0,0 +1,8 @@ +SELECT d.count, +(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count, +(SELECT SUM((b.total * 1000000) DIV 1000000) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as query_total, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count != 0) as not_zero_region_count, +(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count +FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as d WHERE d.count > 0; +SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; +SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; diff --git a/mysql-test/response-time-distribution.patch/percona_query_response_time_sleep.inc b/mysql-test/response-time-distribution.patch/percona_query_response_time_sleep.inc new file mode 100644 index 000000000000..40688b173b0b --- /dev/null +++ b/mysql-test/response-time-distribution.patch/percona_query_response_time_sleep.inc @@ -0,0 +1,19 @@ +SELECT SLEEP(0.31); +SELECT SLEEP(0.32); +SELECT SLEEP(0.33); +SELECT SLEEP(0.34); +SELECT SLEEP(0.35); +SELECT SLEEP(0.36); +SELECT SLEEP(0.37); +SELECT SLEEP(0.38); +SELECT SLEEP(0.39); +SELECT SLEEP(0.40); +SELECT SLEEP(1.1); +SELECT SLEEP(1.2); +SELECT SLEEP(1.3); +SELECT SLEEP(1.5); +SELECT SLEEP(1.4); +SELECT SLEEP(0.5); +SELECT SLEEP(2.1); +SELECT SLEEP(2.3); +SELECT SLEEP(2.5); diff --git a/mysql-test/show_slave_status_nolock.patch/percona_show_slave_status_nolock.result b/mysql-test/show_slave_status_nolock.patch/percona_show_slave_status_nolock.result new file mode 100644 index 000000000000..aa1717f9a18d --- /dev/null +++ b/mysql-test/show_slave_status_nolock.patch/percona_show_slave_status_nolock.result @@ -0,0 +1,23 @@ +stop slave; +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; +start slave; +DROP TABLE IF EXISTS t; +CREATE TABLE t(id INT); +INSERT INTO t SELECT SLEEP(5); +STOP SLAVE; +select count(*) from t; +count(*) +0 +SHOW SLAVE STATUS NOLOCK; +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 Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error + host user port 1 master-bin.000001 276 slave-relay-bin.000003 422 master-bin.000001 No No 0 0 276 577 None 0 No NULL No 0 0 +select count(*) from t; +count(*) +0 +START SLAVE; +Warnings: +Note 1592 Statement may not be safe to log in statement format. +DROP TABLE t; diff --git a/mysql-test/show_slave_status_nolock.patch/percona_show_slave_status_nolock.test b/mysql-test/show_slave_status_nolock.patch/percona_show_slave_status_nolock.test new file mode 100644 index 000000000000..03531db3b123 --- /dev/null +++ b/mysql-test/show_slave_status_nolock.patch/percona_show_slave_status_nolock.test @@ -0,0 +1,28 @@ +--source include/master-slave.inc + +connection master; +-- disable_warnings +DROP TABLE IF EXISTS t; +-- enable_warnings +CREATE TABLE t(id INT); +sync_slave_with_master; +connection master; +send INSERT INTO t SELECT SLEEP(5); +sleep 1; +connection slave; +send STOP SLAVE; +connection slave1; +select count(*) from t; +replace_column 2 host 3 user 4 port; +SHOW SLAVE STATUS NOLOCK; +select count(*) from t; + +connection slave; +reap; +--source include/wait_for_slave_to_stop.inc +START SLAVE; +--source include/wait_for_slave_to_start.inc +connection master; +reap; +DROP TABLE t; +sync_slave_with_master; diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-control_global_slow-master.opt b/mysql-test/slow_extended.patch/percona_slow_extended-control_global_slow-master.opt new file mode 100644 index 000000000000..bd62c08c4756 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-control_global_slow-master.opt @@ -0,0 +1 @@ +--slow-query-log-file=percona_slow_query_log-control_global_slow.log --long-query-time=1 diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-control_global_slow.result b/mysql-test/slow_extended.patch/percona_slow_extended-control_global_slow.result new file mode 100644 index 000000000000..328087c1e4c2 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-control_global_slow.result @@ -0,0 +1,11 @@ +SELECT sleep(2); +sleep(2) +0 +set global log_slow_verbosity=innodb; +set global use_global_log_slow_control="log_slow_verbosity,long_query_time"; +SELECT sleep(2); +sleep(2) +0 +set global use_global_log_slow_control=none; +set global log_slow_verbosity=microtime; +1 diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-control_global_slow.test b/mysql-test/slow_extended.patch/percona_slow_extended-control_global_slow.test new file mode 100644 index 000000000000..79843e63ff35 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-control_global_slow.test @@ -0,0 +1,9 @@ +source include/have_innodb.inc; +SELECT sleep(2); +set global log_slow_verbosity=innodb; +set global use_global_log_slow_control="log_slow_verbosity,long_query_time"; +SELECT sleep(2); +set global use_global_log_slow_control=none; +set global log_slow_verbosity=microtime; +let $cmd = cat $MYSQLTEST_VARDIR/mysqld.1/data/percona_slow_query_log-control_global_slow.log | grep "No InnoDB statistics available for this query" | wc -l; +exec $cmd; diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-log_slow_filter-master.opt b/mysql-test/slow_extended.patch/percona_slow_extended-log_slow_filter-master.opt new file mode 100644 index 000000000000..660c51a0b7c0 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-log_slow_filter-master.opt @@ -0,0 +1 @@ +--slow-query-log-file=percona_slow_query_log-log_slow_filter.log --long-query-time=1 diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-log_slow_filter.result b/mysql-test/slow_extended.patch/percona_slow_extended-log_slow_filter.result new file mode 100644 index 000000000000..072e840c0615 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-log_slow_filter.result @@ -0,0 +1,24 @@ +SET GLOBAL SLOW_QUERY_LOG=OFF; +drop table if exists t; +# Create test table +create table t(id INT PRIMARY KEY) engine=InnoDB; +# Insert two rows to test table +insert into t values(1); +insert into t values(2); +insert into t values(3); +SET GLOBAL SLOW_QUERY_LOG=ON; +SELECT sleep(2); +sleep(2) +0 +set log_slow_filter=full_join; +SELECT sleep(2) union select t2.id from t as t1,t as t2; +sleep(2) +0 +1 +2 +3 +SELECT sleep(2); +sleep(2) +0 +drop table if exists t; +2 diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-log_slow_filter.test b/mysql-test/slow_extended.patch/percona_slow_extended-log_slow_filter.test new file mode 100644 index 000000000000..4759e533470b --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-log_slow_filter.test @@ -0,0 +1,30 @@ +source include/have_innodb.inc; + +SET GLOBAL SLOW_QUERY_LOG=OFF; + +--disable_warnings +drop table if exists t; +--enable_warnings + +--echo # Create test table +create table t(id INT PRIMARY KEY) engine=InnoDB; +--echo # Insert two rows to test table +insert into t values(1); +insert into t values(2); +insert into t values(3); + +SET GLOBAL SLOW_QUERY_LOG=ON; + +SELECT sleep(2); + +set log_slow_filter=full_join; + +SELECT sleep(2) union select t2.id from t as t1,t as t2; +SELECT sleep(2); + +--disable_warnings +drop table if exists t; +--enable_warnings + +let $cmd = cat $MYSQLTEST_VARDIR/mysqld.1/data/percona_slow_query_log-log_slow_filter.log | grep Query_time | wc -l; +exec $cmd; diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-log_slow_verbosity-master.opt b/mysql-test/slow_extended.patch/percona_slow_extended-log_slow_verbosity-master.opt new file mode 100644 index 000000000000..19ae9c117f08 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-log_slow_verbosity-master.opt @@ -0,0 +1 @@ +--slow-query-log-file=percona_slow_query_log-log_slow_verbosity.log --long-query-time=1 diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-log_slow_verbosity.result b/mysql-test/slow_extended.patch/percona_slow_extended-log_slow_verbosity.result new file mode 100644 index 000000000000..7cf4e1b41a45 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-log_slow_verbosity.result @@ -0,0 +1,8 @@ +SELECT sleep(2); +sleep(2) +0 +set log_slow_verbosity=innodb; +SELECT sleep(2); +sleep(2) +0 +1 diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-log_slow_verbosity.test b/mysql-test/slow_extended.patch/percona_slow_extended-log_slow_verbosity.test new file mode 100644 index 000000000000..00733eea184f --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-log_slow_verbosity.test @@ -0,0 +1,10 @@ +source include/have_innodb.inc; + +SELECT sleep(2); + +set log_slow_verbosity=innodb; + +SELECT sleep(2); + +let $cmd = cat $MYSQLTEST_VARDIR/mysqld.1/data/percona_slow_query_log-log_slow_verbosity.log | grep "No InnoDB statistics available for this query" | wc -l; +exec $cmd; diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-long_query_time-master.opt b/mysql-test/slow_extended.patch/percona_slow_extended-long_query_time-master.opt new file mode 100644 index 000000000000..8064e04b8469 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-long_query_time-master.opt @@ -0,0 +1 @@ +--slow-query-log-file=percona_slow_query_log-long_query_time.log --long-query-time=2 diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-long_query_time.result b/mysql-test/slow_extended.patch/percona_slow_extended-long_query_time.result new file mode 100644 index 000000000000..b98fd969678c --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-long_query_time.result @@ -0,0 +1,21 @@ +SELECT sleep(1); +sleep(1) +0 +SELECT sleep(3); +sleep(3) +0 +SELECT sleep(5); +sleep(5) +0 +set long_query_time=4; +SELECT sleep(1); +sleep(1) +0 +SELECT sleep(3); +sleep(3) +0 +SELECT sleep(5); +sleep(5) +0 +set long_query_time=2; +3 diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-long_query_time.test b/mysql-test/slow_extended.patch/percona_slow_extended-long_query_time.test new file mode 100644 index 000000000000..7914b75451c0 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-long_query_time.test @@ -0,0 +1,16 @@ +source include/have_innodb.inc; + +SELECT sleep(1); +SELECT sleep(3); +SELECT sleep(5); + +set long_query_time=4; + +SELECT sleep(1); +SELECT sleep(3); +SELECT sleep(5); + +set long_query_time=2; + +let $cmd = cat $MYSQLTEST_VARDIR/mysqld.1/data/percona_slow_query_log-long_query_time.log | grep Query_time | wc -l; +exec $cmd; diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-microseconds_in_slow_extended-master.opt b/mysql-test/slow_extended.patch/percona_slow_extended-microseconds_in_slow_extended-master.opt new file mode 100644 index 000000000000..37a30b1384f1 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-microseconds_in_slow_extended-master.opt @@ -0,0 +1 @@ +--slow-query-log-file=percona_slow_query_log-microseconds_in_slow_query_log.log --long-query-time=1 diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-microseconds_in_slow_extended.result b/mysql-test/slow_extended.patch/percona_slow_extended-microseconds_in_slow_extended.result new file mode 100644 index 000000000000..e6f267528224 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-microseconds_in_slow_extended.result @@ -0,0 +1,10 @@ +SELECT sleep(2); +sleep(2) +0 +set global slow_query_log_microseconds_timestamp=ON; +SELECT sleep(2); +sleep(2) +0 +set global slow_query_log_microseconds_timestamp=OFF; +1 +2 diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-microseconds_in_slow_extended.test b/mysql-test/slow_extended.patch/percona_slow_extended-microseconds_in_slow_extended.test new file mode 100644 index 000000000000..e611b5bf83a4 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-microseconds_in_slow_extended.test @@ -0,0 +1,15 @@ +source include/have_innodb.inc; + +SELECT sleep(2); + +set global slow_query_log_microseconds_timestamp=ON; + +SELECT sleep(2); + +set global slow_query_log_microseconds_timestamp=OFF; + +let $cmd = cat $MYSQLTEST_VARDIR/mysqld.1/data/percona_slow_query_log-microseconds_in_slow_query_log.log | grep -E '# Time: [0-9]+[ ]+[0-9]+:[0-\9]+:[0-9]+.[0-9]+' | wc -l; +exec $cmd; + +let $cmd = cat $MYSQLTEST_VARDIR/mysqld.1/data/percona_slow_query_log-microseconds_in_slow_query_log.log | grep -E '# Time: [0-9]+[ ]+[0-9]+:[0-\9]+:[0-9]+' | wc -l; +exec $cmd; diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-min_examined_row_limit-master.opt b/mysql-test/slow_extended.patch/percona_slow_extended-min_examined_row_limit-master.opt new file mode 100644 index 000000000000..d3f4e7eeb039 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-min_examined_row_limit-master.opt @@ -0,0 +1 @@ +--slow-query-log-file=percona_slow_query_log-min_examined_row_limit.log --long-query-time=1 diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-min_examined_row_limit.result b/mysql-test/slow_extended.patch/percona_slow_extended-min_examined_row_limit.result new file mode 100644 index 000000000000..a6eae5a631df --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-min_examined_row_limit.result @@ -0,0 +1,24 @@ +SET GLOBAL SLOW_QUERY_LOG=OFF; +drop table if exists t; +# Create test table +create table t(id INT PRIMARY KEY) engine=InnoDB; +# Insert two rows to test table +insert into t values(1); +insert into t values(2); +insert into t values(3); +SET GLOBAL SLOW_QUERY_LOG=ON; +SELECT sleep(2); +sleep(2) +0 +set min_examined_row_limit=5; +SELECT sleep(2) union select t2.id from t as t1,t as t2; +sleep(2) +0 +1 +2 +3 +SELECT sleep(2); +sleep(2) +0 +drop table if exists t; +2 diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-min_examined_row_limit.test b/mysql-test/slow_extended.patch/percona_slow_extended-min_examined_row_limit.test new file mode 100644 index 000000000000..c4f01f6f036e --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-min_examined_row_limit.test @@ -0,0 +1,30 @@ +source include/have_innodb.inc; + +SET GLOBAL SLOW_QUERY_LOG=OFF; + +--disable_warnings +drop table if exists t; +--enable_warnings + +--echo # Create test table +create table t(id INT PRIMARY KEY) engine=InnoDB; +--echo # Insert two rows to test table +insert into t values(1); +insert into t values(2); +insert into t values(3); + +SET GLOBAL SLOW_QUERY_LOG=ON; + +SELECT sleep(2); + +set min_examined_row_limit=5; + +SELECT sleep(2) union select t2.id from t as t1,t as t2; +SELECT sleep(2); + +--disable_warnings +drop table if exists t; +--enable_warnings + +let $cmd = cat $MYSQLTEST_VARDIR/mysqld.1/data/percona_slow_query_log-min_examined_row_limit.log | grep Query_time | wc -l; +exec $cmd; diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-slave_innodb_stats-master.opt b/mysql-test/slow_extended.patch/percona_slow_extended-slave_innodb_stats-master.opt new file mode 100644 index 000000000000..286a9c4484d0 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-slave_innodb_stats-master.opt @@ -0,0 +1 @@ +--long_query_time=0 --log_slow_verbosity=innodb --log_slow_slave_statements diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-slave_innodb_stats-slave.opt b/mysql-test/slow_extended.patch/percona_slow_extended-slave_innodb_stats-slave.opt new file mode 100644 index 000000000000..286a9c4484d0 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-slave_innodb_stats-slave.opt @@ -0,0 +1 @@ +--long_query_time=0 --log_slow_verbosity=innodb --log_slow_slave_statements diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-slave_innodb_stats.result b/mysql-test/slow_extended.patch/percona_slow_extended-slave_innodb_stats.result new file mode 100644 index 000000000000..c2406bdfd853 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-slave_innodb_stats.result @@ -0,0 +1,21 @@ +stop slave; +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; +start slave; +DROP TABLE IF EXISTS t; +CREATE TABLE t(id INT,data CHAR(30)) ENGINE=InnoDB; +INSERT INTO t VALUES +(1,"aaaaabbbbbcccccdddddeeeeefffff"), +(2,"aaaaabbbbbcccccdddddeeeeefffff"), +(3,"aaaaabbbbbcccccdddddeeeeefffff"), +(4,"aaaaabbbbbcccccdddddeeeeefffff"), +(5,"aaaaabbbbbcccccdddddeeeeefffff"); +INSERT INTO t SELECT t2.id,t2.data from t as t1, t as t2; +INSERT INTO t SELECT t2.id,t2.data from t as t1, t as t2; +STOP SLAVE; +START SLAVE; +INSERT INTO t SELECT t.id,t.data from t; +DROP TABLE IF EXISTS t; +4 diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-slave_innodb_stats.test b/mysql-test/slow_extended.patch/percona_slow_extended-slave_innodb_stats.test new file mode 100644 index 000000000000..473f003779df --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-slave_innodb_stats.test @@ -0,0 +1,44 @@ +-- source include/have_binlog_format_mixed_or_statement.inc +-- source include/have_innodb.inc +-- source include/master-slave.inc + +connection master; +-- disable_warnings +DROP TABLE IF EXISTS t; +-- enable_warnings +CREATE TABLE t(id INT,data CHAR(30)) ENGINE=InnoDB; +INSERT INTO t VALUES +(1,"aaaaabbbbbcccccdddddeeeeefffff"), +(2,"aaaaabbbbbcccccdddddeeeeefffff"), +(3,"aaaaabbbbbcccccdddddeeeeefffff"), +(4,"aaaaabbbbbcccccdddddeeeeefffff"), +(5,"aaaaabbbbbcccccdddddeeeeefffff"); +INSERT INTO t SELECT t2.id,t2.data from t as t1, t as t2; +INSERT INTO t SELECT t2.id,t2.data from t as t1, t as t2; +sync_slave_with_master; + +connection slave; +STOP SLAVE; +-- source include/wait_for_slave_to_stop.inc +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +--shutdown_server 10 +--source include/wait_until_disconnected.inc +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc +START SLAVE; +-- source include/wait_for_slave_to_start.inc + +connection master; +INSERT INTO t SELECT t.id,t.data from t; +sync_slave_with_master; + +connection master; +DROP TABLE IF EXISTS t; +sync_slave_with_master; + +exec cat $MYSQLTEST_VARDIR/mysqld.2/mysqld-slow.log | grep InnoDB_IO_r_ops | wc -l; diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements-and-use_global_long_query_time-master.opt b/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements-and-use_global_long_query_time-master.opt new file mode 100644 index 000000000000..49038530c565 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements-and-use_global_long_query_time-master.opt @@ -0,0 +1 @@ +--slow-query-log-file=percona_log_slow_slave_statements-master.log --long-query-time=1 diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements-and-use_global_long_query_time-slave.opt b/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements-and-use_global_long_query_time-slave.opt new file mode 100644 index 000000000000..648f309f7443 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements-and-use_global_long_query_time-slave.opt @@ -0,0 +1 @@ +--slow-query-log-file=percona_log_slow_slave_statements-slave.log --long-query-time=1 diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements-and-use_global_long_query_time.result b/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements-and-use_global_long_query_time.result new file mode 100644 index 000000000000..8aed50caba28 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements-and-use_global_long_query_time.result @@ -0,0 +1,91 @@ +# Activate master-slave replication +stop slave; +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; +start slave; +# Make table t for test +DROP TABLE IF EXISTS t; +CREATE TABLE t(id INT); +# Start slave replication +START SLAVE; +INSERT INTO t VALUES (1); +# Read and change log_slow_slave_statements to ON on slave +show variables like 'log_slow_slave_statements'; +Variable_name Value +log_slow_slave_statements OFF +set global log_slow_slave_statements=ON; +show variables like 'log_slow_slave_statements'; +Variable_name Value +log_slow_slave_statements ON +INSERT INTO t VALUES (2); +# Restart slave +STOP SLAVE; +START SLAVE; +INSERT INTO t VALUES (3); +show variables like 'long_query_time'; +Variable_name Value +long_query_time 1.000000 +show global variables like 'long_query_time'; +Variable_name Value +long_query_time 1.000000 +show global variables like 'use_global_long_query_time'; +Variable_name Value +use_global_long_query_time OFF +set global long_query_time=0; +show variables like 'long_query_time'; +Variable_name Value +long_query_time 1.000000 +show global variables like 'long_query_time'; +Variable_name Value +long_query_time 0.000000 +show global variables like 'use_global_long_query_time'; +Variable_name Value +use_global_long_query_time OFF +INSERT INTO t VALUES (4); +show variables like 'long_query_time'; +Variable_name Value +long_query_time 1.000000 +show global variables like 'long_query_time'; +Variable_name Value +long_query_time 0.000000 +show global variables like 'use_global_long_query_time'; +Variable_name Value +use_global_long_query_time OFF +set global use_global_long_query_time=1; +show variables like 'long_query_time'; +Variable_name Value +long_query_time 0.000000 +show global variables like 'long_query_time'; +Variable_name Value +long_query_time 0.000000 +show global variables like 'use_global_long_query_time'; +Variable_name Value +use_global_long_query_time ON +INSERT INTO t VALUES (5); +show variables like 'long_query_time'; +Variable_name Value +long_query_time 0.000000 +show global variables like 'long_query_time'; +Variable_name Value +long_query_time 0.000000 +show global variables like 'use_global_long_query_time'; +Variable_name Value +use_global_long_query_time ON +set global long_query_time=1; +set global use_global_long_query_time=0; +# Analyse master slow_query_log +0 +0 +0 +0 +0 +# Analyse slave slow_query_log +0 +0 +0 +0 +1 +set global log_slow_slave_statements=OFF; +DROP TABLE t; diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements-and-use_global_long_query_time.test b/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements-and-use_global_long_query_time.test new file mode 100644 index 000000000000..6b7d2750e68a --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements-and-use_global_long_query_time.test @@ -0,0 +1,107 @@ +-- source include/have_binlog_format_mixed_or_statement.inc +-- echo # Activate master-slave replication +-- source include/master-slave.inc + +connection master; +-- echo # Make table t for test +-- disable_warnings +DROP TABLE IF EXISTS t; +-- enable_warnings +CREATE TABLE t(id INT); + + +-- echo # Start slave replication +-- disable_warnings +connection slave; +START SLAVE; +-- source include/wait_for_slave_to_start.inc +-- enable_warnings + +#-- echo # Make insert(1) on master +connection master; +INSERT INTO t VALUES (1); +sync_slave_with_master; +connection slave; +-- echo # Read and change log_slow_slave_statements to ON on slave +show variables like 'log_slow_slave_statements'; +set global log_slow_slave_statements=ON; +show variables like 'log_slow_slave_statements'; + +#-- echo # Make insert(2) on master +connection master; +INSERT INTO t VALUES (2); +sync_slave_with_master; +connection slave; +-- echo # Restart slave +STOP SLAVE; +-- source include/wait_for_slave_to_stop.inc +START SLAVE; +-- source include/wait_for_slave_to_start.inc + +#-- echo # Make insert(3) on master +connection master; +INSERT INTO t VALUES (3); +sync_slave_with_master; +connection slave; +show variables like 'long_query_time'; +show global variables like 'long_query_time'; +show global variables like 'use_global_long_query_time'; +set global long_query_time=0; +show variables like 'long_query_time'; +show global variables like 'long_query_time'; +show global variables like 'use_global_long_query_time'; + +#-- echo # Make insert(4) on master +connection master; +INSERT INTO t VALUES (4); +sync_slave_with_master; +connection slave; +show variables like 'long_query_time'; +show global variables like 'long_query_time'; +show global variables like 'use_global_long_query_time'; +set global use_global_long_query_time=1; +show variables like 'long_query_time'; +show global variables like 'long_query_time'; +show global variables like 'use_global_long_query_time'; + +#-- echo # Make insert(5) on master +connection master; +INSERT INTO t VALUES (5); +sync_slave_with_master; +connection slave; +show variables like 'long_query_time'; +show global variables like 'long_query_time'; +show global variables like 'use_global_long_query_time'; +set global long_query_time=1; +set global use_global_long_query_time=0; + +-- echo # Analyse master slow_query_log +let $i=5; +let $k=1; +let $cmd=cat ./var/mysqld.1/data/percona_log_slow_slave_statements-master.log | grep; +while($i) +{ + let $current_cmd = $cmd "INSERT INTO t VALUES ($k)" | wc -l; + exec $current_cmd; + dec $i; + inc $k; +} + +-- echo # Analyse slave slow_query_log +let $i=5; +let $k=1; +let $cmd=cat ./var/mysqld.2/data/percona_log_slow_slave_statements-slave.log | grep; +while($i) +{ + let $current_cmd = $cmd "INSERT INTO t VALUES ($k)" | wc -l; + exec $current_cmd; + dec $i; + inc $k; +} +set global log_slow_slave_statements=OFF; + +connection master; +DROP TABLE t; + +sync_slave_with_master; +connection slave; diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements-master.opt b/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements-master.opt new file mode 100644 index 000000000000..ebf25ddd37d8 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements-master.opt @@ -0,0 +1 @@ +--slow-query-log-file=percona_log_slow_slave_statements-master.log --long-query-time=0 diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements-slave.opt b/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements-slave.opt new file mode 100644 index 000000000000..96cd90044937 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements-slave.opt @@ -0,0 +1 @@ +--slow-query-log-file=percona_log_slow_slave_statements-slave.log --long-query-time=0 diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements.result b/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements.result new file mode 100644 index 000000000000..e3bf3e92c948 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements.result @@ -0,0 +1,86 @@ +# Activate master-slave replication +stop slave; +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; +start slave; +# Make table t for test +DROP TABLE IF EXISTS t; +CREATE TABLE t(id INT); +# Start slave replication +START SLAVE; +INSERT INTO t VALUES (1); +# Read information about master binlog +# Sync(1) slave thread +# Read and change log_slow_slave_statements to ON on slave +show variables like 'log_slow_slave_statements'; +Variable_name Value +log_slow_slave_statements OFF +set global log_slow_slave_statements=ON; +show variables like 'log_slow_slave_statements'; +Variable_name Value +log_slow_slave_statements ON +INSERT INTO t VALUES (2); +# Read information about master binlog +# Sync slave(2) thread +# Restart slave +STOP SLAVE; +START SLAVE; +INSERT INTO t VALUES (3); +# Read information about master binlog +# Sync(3) slave thread +# Read and change log_slow_slave_statements to OFF on slave +show variables like 'log_slow_slave_statements'; +Variable_name Value +log_slow_slave_statements ON +set global log_slow_slave_statements=OFF; +show variables like 'log_slow_slave_statements'; +Variable_name Value +log_slow_slave_statements OFF +INSERT INTO t VALUES (4); +# Read information about master binlog +# Sync slave(4) thread +# Restart slave +STOP SLAVE; +START SLAVE; +INSERT INTO t VALUES (5); +# Read information about master binlog +# Sync slave(5) thread +# Read and change log_slow_slave_statements to ON on slave +show variables like 'log_slow_slave_statements'; +Variable_name Value +log_slow_slave_statements OFF +set global log_slow_slave_statements=ON; +show variables like 'log_slow_slave_statements'; +Variable_name Value +log_slow_slave_statements ON +INSERT INTO t VALUES (6); +# Read information about master binlog +# Sync slave(6) thread +# Restart slave +STOP SLAVE; +START SLAVE; +INSERT INTO t VALUES (7); +# Read information about master binlog +# Sync slave(7) thread +# Analyse master slow_query_log +1 +1 +1 +1 +1 +1 +1 +# Analyse slave slow_query_log +0 +0 +1 +0 +0 +0 +1 +set global log_slow_slave_statements=OFF; +DROP TABLE t; +# Read information about master binlog +# Sync slave(8) thread diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements.test b/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements.test new file mode 100644 index 000000000000..bb6e1c5f28a3 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-slave_statements.test @@ -0,0 +1,159 @@ +-- source include/have_binlog_format_mixed_or_statement.inc +-- echo # Activate master-slave replication +-- source include/master-slave.inc + +connection master; +-- echo # Make table t for test +-- disable_warnings +DROP TABLE IF EXISTS t; +-- enable_warnings +CREATE TABLE t(id INT); + + +-- echo # Start slave replication +-- disable_warnings +connection slave; +START SLAVE; +-- source include/wait_for_slave_to_start.inc +-- enable_warnings + +#-- echo # Make insert(1) on master +connection master; +INSERT INTO t VALUES (1); +-- echo # Read information about master binlog +let $binlog_file = query_get_value(SHOW MASTER STATUS,File,1); +let $binlog_position = query_get_value(SHOW MASTER STATUS,Position,1); + +-- echo # Sync(1) slave thread +connection slave; +let $sync_result = `SELECT MASTER_POS_WAIT('$binlog_file',$binlog_position)`; + +-- echo # Read and change log_slow_slave_statements to ON on slave +show variables like 'log_slow_slave_statements'; +set global log_slow_slave_statements=ON; +show variables like 'log_slow_slave_statements'; + +#-- echo # Make insert(2) on master +connection master; +INSERT INTO t VALUES (2); +-- echo # Read information about master binlog +let $binlog_file = query_get_value(SHOW MASTER STATUS,File,1); +let $binlog_position = query_get_value(SHOW MASTER STATUS,Position,1); + +-- echo # Sync slave(2) thread +connection slave; +let $sync_result = `SELECT MASTER_POS_WAIT('$binlog_file',$binlog_position)`; +-- echo # Restart slave +STOP SLAVE; +-- source include/wait_for_slave_to_stop.inc +START SLAVE; +-- source include/wait_for_slave_to_start.inc + +#-- echo # Make insert(3) on master +connection master; +INSERT INTO t VALUES (3); +-- echo # Read information about master binlog +let $binlog_file = query_get_value(SHOW MASTER STATUS,File,1); +let $binlog_position = query_get_value(SHOW MASTER STATUS,Position,1); + +-- echo # Sync(3) slave thread +connection slave; +let $sync_result = `SELECT MASTER_POS_WAIT('$binlog_file',$binlog_position)`; +-- echo # Read and change log_slow_slave_statements to OFF on slave +show variables like 'log_slow_slave_statements'; +set global log_slow_slave_statements=OFF; +show variables like 'log_slow_slave_statements'; + +#-- echo # Make insert(4) on master +connection master; +INSERT INTO t VALUES (4); +-- echo # Read information about master binlog +let $binlog_file = query_get_value(SHOW MASTER STATUS,File,1); +let $binlog_position = query_get_value(SHOW MASTER STATUS,Position,1); + +-- echo # Sync slave(4) thread +connection slave; +let $sync_result = `SELECT MASTER_POS_WAIT('$binlog_file',$binlog_position)`; +-- echo # Restart slave +STOP SLAVE; +-- source include/wait_for_slave_to_stop.inc +START SLAVE; +-- source include/wait_for_slave_to_start.inc + +#-- echo # Make insert(5) on master +connection master; +INSERT INTO t VALUES (5); +-- echo # Read information about master binlog +let $binlog_file = query_get_value(SHOW MASTER STATUS,File,1); +let $binlog_position = query_get_value(SHOW MASTER STATUS,Position,1); + +-- echo # Sync slave(5) thread +connection slave; +let $sync_result = `SELECT MASTER_POS_WAIT('$binlog_file',$binlog_position)`; +-- echo # Read and change log_slow_slave_statements to ON on slave +show variables like 'log_slow_slave_statements'; +set global log_slow_slave_statements=ON; +show variables like 'log_slow_slave_statements'; + +#-- echo # Make insert(6) on master +connection master; +INSERT INTO t VALUES (6); +-- echo # Read information about master binlog +let $binlog_file = query_get_value(SHOW MASTER STATUS,File,1); +let $binlog_position = query_get_value(SHOW MASTER STATUS,Position,1); + +-- echo # Sync slave(6) thread +connection slave; +let $sync_result = `SELECT MASTER_POS_WAIT('$binlog_file',$binlog_position)`; +-- echo # Restart slave +STOP SLAVE; +-- source include/wait_for_slave_to_stop.inc +START SLAVE; +-- source include/wait_for_slave_to_start.inc + +#-- echo # Make insert(7) on master +connection master; +INSERT INTO t VALUES (7); +-- echo # Read information about master binlog +let $binlog_file = query_get_value(SHOW MASTER STATUS,File,1); +let $binlog_position = query_get_value(SHOW MASTER STATUS,Position,1); + +-- echo # Sync slave(7) thread +connection slave; +let $sync_result = `SELECT MASTER_POS_WAIT('$binlog_file',$binlog_position)`; + +-- echo # Analyse master slow_query_log +let $i=7; +let $k=1; +let $cmd=cat ./var/mysqld.1/data/percona_log_slow_slave_statements-master.log | grep; +while($i) +{ + let $current_cmd = $cmd "INSERT INTO t VALUES ($k)" | wc -l; + exec $current_cmd; + dec $i; + inc $k; +} + +-- echo # Analyse slave slow_query_log +let $i=7; +let $k=1; +let $cmd=cat ./var/mysqld.2/data/percona_log_slow_slave_statements-slave.log | grep; +while($i) +{ + let $current_cmd = $cmd "INSERT INTO t VALUES ($k)" | wc -l; + exec $current_cmd; + dec $i; + inc $k; +} +set global log_slow_slave_statements=OFF; + +connection master; +DROP TABLE t; + +-- echo # Read information about master binlog +let $binlog_file = query_get_value(SHOW MASTER STATUS,File,1); +let $binlog_position = query_get_value(SHOW MASTER STATUS,Position,1); + +-- echo # Sync slave(8) thread +connection slave; +let $sync_result = `SELECT MASTER_POS_WAIT('$binlog_file',$binlog_position)`; diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-use_global_long_query_time-master.opt b/mysql-test/slow_extended.patch/percona_slow_extended-use_global_long_query_time-master.opt new file mode 100644 index 000000000000..5e6a2405b022 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-use_global_long_query_time-master.opt @@ -0,0 +1 @@ +--slow-query-log-file=percona_slow_query_log-use_global_long_query_time.log --long-query-time=2 --use_global_log_slow_control=long_query_time --use_global_long_query_time=1 diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-use_global_long_query_time.result b/mysql-test/slow_extended.patch/percona_slow_extended-use_global_long_query_time.result new file mode 100644 index 000000000000..9b7ca6278a1e --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-use_global_long_query_time.result @@ -0,0 +1,58 @@ +SELECT sleep(1); +sleep(1) +0 +SELECT sleep(3); +sleep(3) +0 +SELECT sleep(5); +sleep(5) +0 +set global long_query_time=4; +set global use_global_long_query_time=1; +SELECT sleep(1); +sleep(1) +0 +SELECT sleep(3); +sleep(3) +0 +SELECT sleep(5); +sleep(5) +0 +set global long_query_time=2; +set global use_global_long_query_time=0; +3 +show global variables like 'use_global_log_slow_control'; +Variable_name Value +use_global_log_slow_control none +show global variables like 'use_global_long_query_time'; +Variable_name Value +use_global_long_query_time OFF +set global use_global_log_slow_control = long_query_time; +show global variables like 'use_global_log_slow_control'; +Variable_name Value +use_global_log_slow_control long_query_time +show global variables like 'use_global_long_query_time'; +Variable_name Value +use_global_long_query_time ON +set global use_global_log_slow_control = log_slow_filter; +show global variables like 'use_global_log_slow_control'; +Variable_name Value +use_global_log_slow_control log_slow_filter +show global variables like 'use_global_long_query_time'; +Variable_name Value +use_global_long_query_time OFF +set global use_global_long_query_time = ON; +show global variables like 'use_global_log_slow_control'; +Variable_name Value +use_global_log_slow_control log_slow_filter,long_query_time +show global variables like 'use_global_long_query_time'; +Variable_name Value +use_global_long_query_time ON +set global use_global_long_query_time = OFF; +show global variables like 'use_global_log_slow_control'; +Variable_name Value +use_global_log_slow_control log_slow_filter +show global variables like 'use_global_long_query_time'; +Variable_name Value +use_global_long_query_time OFF +set global use_global_log_slow_control = long_query_time; diff --git a/mysql-test/slow_extended.patch/percona_slow_extended-use_global_long_query_time.test b/mysql-test/slow_extended.patch/percona_slow_extended-use_global_long_query_time.test new file mode 100644 index 000000000000..88660015f091 --- /dev/null +++ b/mysql-test/slow_extended.patch/percona_slow_extended-use_global_long_query_time.test @@ -0,0 +1,39 @@ +source include/have_innodb.inc; + +SELECT sleep(1); +SELECT sleep(3); +SELECT sleep(5); + +set global long_query_time=4; +set global use_global_long_query_time=1; + +SELECT sleep(1); +SELECT sleep(3); +SELECT sleep(5); + +set global long_query_time=2; +set global use_global_long_query_time=0; + +let $cmd = cat $MYSQLTEST_VARDIR/mysqld.1/data/percona_slow_query_log-use_global_long_query_time.log | grep Query_time | wc -l; +exec $cmd; + +show global variables like 'use_global_log_slow_control'; +show global variables like 'use_global_long_query_time'; + +set global use_global_log_slow_control = long_query_time; +show global variables like 'use_global_log_slow_control'; +show global variables like 'use_global_long_query_time'; + +set global use_global_log_slow_control = log_slow_filter; +show global variables like 'use_global_log_slow_control'; +show global variables like 'use_global_long_query_time'; + +set global use_global_long_query_time = ON; +show global variables like 'use_global_log_slow_control'; +show global variables like 'use_global_long_query_time'; + +set global use_global_long_query_time = OFF; +show global variables like 'use_global_log_slow_control'; +show global variables like 'use_global_long_query_time'; + +set global use_global_log_slow_control = long_query_time; diff --git a/mysql-test/sql_no_fcache.patch/percona_sql_no_fcache.result b/mysql-test/sql_no_fcache.patch/percona_sql_no_fcache.result new file mode 100644 index 000000000000..bc1413fb96d4 --- /dev/null +++ b/mysql-test/sql_no_fcache.patch/percona_sql_no_fcache.result @@ -0,0 +1,12 @@ +drop table if exists t1; +create table t (a int not null); +insert into t values (1),(2),(3); +SELECT SQL_NO_FCACHE SLEEP(0); +SLEEP(0) +0 +SELECT /*!40001 SQL_NO_CACHE */ /*!50084 SQL_NO_FCACHE */ * FROM t; +a +1 +2 +3 +DROP TABLE t; diff --git a/mysql-test/sql_no_fcache.patch/percona_sql_no_fcache.test b/mysql-test/sql_no_fcache.patch/percona_sql_no_fcache.test new file mode 100644 index 000000000000..1ed8be2196be --- /dev/null +++ b/mysql-test/sql_no_fcache.patch/percona_sql_no_fcache.test @@ -0,0 +1,11 @@ +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t (a int not null); +insert into t values (1),(2),(3); + +SELECT SQL_NO_FCACHE SLEEP(0); +SELECT /*!40001 SQL_NO_CACHE */ /*!50084 SQL_NO_FCACHE */ * FROM t; + +DROP TABLE t; diff --git a/mysql-test/suppress_log_warning_1592.patch/percona_suppress_log_warning_1592-master.opt b/mysql-test/suppress_log_warning_1592.patch/percona_suppress_log_warning_1592-master.opt new file mode 100644 index 000000000000..4658d62af608 --- /dev/null +++ b/mysql-test/suppress_log_warning_1592.patch/percona_suppress_log_warning_1592-master.opt @@ -0,0 +1 @@ +--log-error diff --git a/mysql-test/suppress_log_warning_1592.patch/percona_suppress_log_warning_1592.result b/mysql-test/suppress_log_warning_1592.patch/percona_suppress_log_warning_1592.result new file mode 100644 index 000000000000..b4779b7ff2b0 --- /dev/null +++ b/mysql-test/suppress_log_warning_1592.patch/percona_suppress_log_warning_1592.result @@ -0,0 +1,28 @@ +SET @old_log_warnings = @@log_warnings; +SET @old_suppress_log_warning_1592 = @@suppress_log_warning_1592; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a VARCHAR(36), b VARCHAR(20)); +SET GLOBAL SUPPRESS_LOG_WARNING_1592 = 0; +SET GLOBAL LOG_WARNINGS = 0; +INSERT INTO t1 VALUES(UUID(), 'suppress_1592'); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave. +SET GLOBAL LOG_WARNINGS = 1; +INSERT INTO t1 VALUES(UUID(), 'suppress_1592'); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave. +SET GLOBAL SUPPRESS_LOG_WARNING_1592 = 1; +SET GLOBAL LOG_WARNINGS = 0; +INSERT INTO t1 VALUES(UUID(), 'suppress_1592'); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave. +SET GLOBAL LOG_WARNINGS = 1; +INSERT INTO t1 VALUES(UUID(), 'suppress_1592'); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave. +DROP TABLE t1; +SET GLOBAL log_warnings = @old_log_warnings; +SET GLOBAL suppress_log_warning_1592 = @old_suppress_log_warning_1592; +# Count the number of times the "Unsafe" message was printed +# to the error log. +Occurrences: 1 diff --git a/mysql-test/suppress_log_warning_1592.patch/percona_suppress_log_warning_1592.test b/mysql-test/suppress_log_warning_1592.patch/percona_suppress_log_warning_1592.test new file mode 100644 index 000000000000..97fe40469fc2 --- /dev/null +++ b/mysql-test/suppress_log_warning_1592.patch/percona_suppress_log_warning_1592.test @@ -0,0 +1,46 @@ +-- source include/have_log_bin.inc +-- source include/have_binlog_format_statement.inc + +SET @old_log_warnings = @@log_warnings; +SET @old_suppress_log_warning_1592 = @@suppress_log_warning_1592; + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +CREATE TABLE t1 (a VARCHAR(36), b VARCHAR(20)); +SET GLOBAL SUPPRESS_LOG_WARNING_1592 = 0; +SET GLOBAL LOG_WARNINGS = 0; +INSERT INTO t1 VALUES(UUID(), 'suppress_1592'); +SET GLOBAL LOG_WARNINGS = 1; +INSERT INTO t1 VALUES(UUID(), 'suppress_1592'); +SET GLOBAL SUPPRESS_LOG_WARNING_1592 = 1; +SET GLOBAL LOG_WARNINGS = 0; +INSERT INTO t1 VALUES(UUID(), 'suppress_1592'); +SET GLOBAL LOG_WARNINGS = 1; +INSERT INTO t1 VALUES(UUID(), 'suppress_1592'); +DROP TABLE t1; + +SET GLOBAL log_warnings = @old_log_warnings; +SET GLOBAL suppress_log_warning_1592 = @old_suppress_log_warning_1592; + +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!`select LENGTH('$log_error_')`) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.1.err; +} +# Assign env variable LOG_ERROR +let LOG_ERROR=$log_error_; + +--echo # Count the number of times the "Unsafe" message was printed +--echo # to the error log. + +perl; + use strict; + my $log_error= $ENV{'LOG_ERROR'} or die "LOG_ERROR not set"; + open(FILE, "$log_error") or die("Unable to open $log_error: $!\n"); + my $count = () = grep(/suppress_1592/g,); + print "Occurrences: $count\n"; + close(FILE); +EOF diff --git a/mysql_syslog.patch b/mysql_syslog.patch new file mode 100644 index 000000000000..f8db9ebcf370 --- /dev/null +++ b/mysql_syslog.patch @@ -0,0 +1,124 @@ +# name : mysql-syslog.patch +# introduced : 12 +# maintainer : Oleg +# +#!!! notice !!! +# Any small change to this file in the main branch +# should be done or reviewed by the maintainer! +diff -ruN a/client/client_priv.h b/client/client_priv.h +--- a/client/client_priv.h 2010-08-08 14:12:42.229338865 +0400 ++++ b/client/client_priv.h 2010-08-08 14:12:43.068089277 +0400 +@@ -85,6 +85,7 @@ + OPT_DEBUG_INFO, OPT_DEBUG_CHECK, OPT_COLUMN_TYPES, OPT_ERROR_LOG_FILE, + OPT_WRITE_BINLOG, OPT_DUMP_DATE, + OPT_INIT_COMMAND, ++ OPT_SYSLOG, + OPT_PLUGIN_DIR, + OPT_DEFAULT_PLUGIN, + OPT_MAX_CLIENT_OPTION +diff -ruN a/client/mysql.cc b/client/mysql.cc +--- a/client/mysql.cc 2010-08-08 14:12:42.229338865 +0400 ++++ b/client/mysql.cc 2010-08-08 14:12:43.488088866 +0400 +@@ -38,6 +38,9 @@ + #include "my_readline.h" + #include + #include ++#ifndef __WIN__ ++#include "syslog.h" ++#endif + + #if defined(USE_LIBEDIT_INTERFACE) && defined(HAVE_LOCALE_H) + #include +@@ -140,7 +143,7 @@ + default_pager_set= 0, opt_sigint_ignore= 0, + auto_vertical_output= 0, + show_warnings= 0, executing_query= 0, interrupted_query= 0, +- ignore_spaces= 0; ++ opt_syslog=0, ignore_spaces= 0; + static my_bool debug_info_flag, debug_check_flag; + static my_bool column_types_flag; + static my_bool preserve_comments= 0; +@@ -198,6 +201,7 @@ + void tee_fputs(const char *s, FILE *file); + void tee_puts(const char *s, FILE *file); + void tee_putc(int c, FILE *file); ++void write_syslog(char *line); + static void tee_print_sized_data(const char *, unsigned int, unsigned int, bool); + /* The names of functions that actually do the manipulation. */ + static int get_options(int argc,char **argv); +@@ -1561,6 +1565,10 @@ + {"show-warnings", OPT_SHOW_WARNINGS, "Show warnings after every statement.", + &show_warnings, &show_warnings, 0, GET_BOOL, NO_ARG, + 0, 0, 0, 0, 0, 0}, ++#ifndef __WIN__ ++ {"syslog", OPT_SYSLOG, "Logs all queries to syslog", 0, 0, 0, GET_NO_ARG, ++ REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, ++#endif + {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.", + (uchar**) &opt_plugin_dir, (uchar**) &opt_plugin_dir, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +@@ -1665,6 +1673,12 @@ + opt->name); + #endif + break; ++ case OPT_SYSLOG: ++ /*if (connect_flag == CLIENT_INTERACTIVE){ ++ printf("Logging queries to syslog.\n"); ++ }*/ ++ opt_syslog = 1; ++ break; + case OPT_SERVER_ARG: + #ifdef EMBEDDED_LIBRARY + /* +@@ -2014,6 +2028,39 @@ + DBUG_RETURN((COMMANDS *) 0); + } + ++void write_syslog(char *line){ ++#ifndef __WIN__ ++ char buff[901]; ++ int i, buff_pos=0; ++ for (i=0;i < strlen(line); i++){ ++ buff[buff_pos] = line[i]; ++ buff_pos++; ++ if (buff_pos >= 900){ ++ buff[900] = NULL; ++ buff_pos = 0; ++ syslog(LOG_INFO, "SYSTEM_USER:%s, MYSQL_USER:%s, CONNECTION_ID:%lu, DB_SERVER:%s, DB:%s, QUERY:%s", ++ getenv("SUDO_USER") ? getenv("SUDO_USER") : ++ getenv("USER") ? getenv("USER") : "--", ++ current_user ? current_user : "--", ++ mysql_thread_id(&mysql), ++ current_host ? current_host : "--", ++ current_db ? current_db : "--", ++ buff); ++ } ++ } ++ if (buff_pos > 0){ ++ buff[buff_pos] = NULL; ++ syslog(LOG_INFO, "SYSTEM_USER:%s, MYSQL_USER:%s, CONNECTION_ID:%lu, DB_SERVER:%s, DB:%s, QUERY:%s", ++ getenv("SUDO_USER") ? getenv("SUDO_USER") : ++ getenv("USER") ? getenv("USER") : "--", ++ current_user ? current_user : "--", ++ mysql_thread_id(&mysql), ++ current_host ? current_host : "--", ++ current_db ? current_db : "--", ++ buff); ++ } ++#endif ++} + + static bool add_line(String &buffer,char *line,char *in_string, + bool *ml_comment, bool truncated) +@@ -2986,6 +3033,11 @@ + fix_history(buffer); + } + #endif ++#ifndef __WIN__ ++ if (opt_syslog && buffer->length() && connect_flag == CLIENT_INTERACTIVE){ ++ write_syslog(buffer->c_ptr()); ++ } ++#endif + + buffer->length(0); + diff --git a/normalize_patches.sh b/normalize_patches.sh new file mode 100755 index 000000000000..f28ce19f13be --- /dev/null +++ b/normalize_patches.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +#ls -1 *.patch | grep -v repair | xargs bzr revert +test -z ${MYSQL_VERSION} && MYSQL_VERSION=5.5.7-rc +test -z ${MYSQL_DIR} && MYSQL_DIR=mysql-${MYSQL_VERSION} +test -z ${MYSQL_TAR_GZ} && MYSQL_TAR_GZ=${MYSQL_DIR}.tar.gz +echo MYSQL_VERSION=$MYSQL_VERSION +echo MYSQL_DIR=$MYSQL_DIR +echo MYSQL_TAR_GZ=$MYSQL_TAR_GZ +echo "===== Prepare source code for patch's adaptation..."; +echo "===== Remove 'a' copy..."; +rm -rf a; +echo "===== Remove 'b' copy..." +rm -rf b; +echo "===== Remove 'Percona-Server' copy..." +rm -rf Percona-Server; +echo "===== Unpack ${MYSQL_DIR} to Percona-Server..." +tar zxf ${MYSQL_TAR_GZ}; +mv ${MYSQL_DIR} Percona-Server; +echo "===== Prepare 'a' copy..." +cp -R Percona-Server a; +echo "===== Prepare 'b' copy..." +cp -R Percona-Server b; +echo "===== Ok, let's go patch adaptation..." +for patch_name in `cat series`; do + echo "=========================================================" + echo "===== Check patch $patch_name"; + echo "===== Apply patch $patch_name..."; + patch -p1 -d b < $patch_name >result; + fail=`cat result | grep FAIL | wc -l`; + hunk=`cat result | grep Hunk | wc -l`; + echo "===== Patch $patch_name FAILED: $fail"; + echo "===== Patch $patch_name HUNK: $hunk"; + if [ $fail -ne 0 ]; then + echo "===== Patch $patch_name are failed"; + exit 1; + fi; + if [ $hunk -ne 0 ]; then + find b -name "*.orig" | xargs rm; + ./regenerate_patch.sh a b $patch_name + fi; + patch -p1 -d Percona-Server < $patch_name > /dev/null; + patch -p1 -d a < $patch_name > /dev/null; + echo "===== Patch $patch_name regenerated succesfully" + if [ $hunk -ne 0 ]; then + echo "===== Remove temporary 'b' version" + rm -rf b; + echo "===== Prepare 'b' copy..." + cp -R Percona-Server b; + fi; +done; diff --git a/percona_support.patch b/percona_support.patch new file mode 100644 index 000000000000..8ce9a0b6f218 --- /dev/null +++ b/percona_support.patch @@ -0,0 +1,19 @@ +# name : percona-support.patch +# introduced : 11 or before +# maintainer : Oleg +# +#!!! notice !!! +# Any small change to this file in the main branch +# should be done or reviewed by the maintainer! +diff -ruN a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh +--- a/scripts/mysql_install_db.sh 2009-08-08 09:20:07.000000000 +0000 ++++ b/scripts/mysql_install_db.sh 2009-08-08 09:29:23.000000000 +0000 +@@ -475,6 +475,8 @@ + echo + echo "Please report any problems with the $scriptdir/mysqlbug script!" + echo ++ echo "For commercial support please contact Percona at http://www.percona.com/contacts.html" ++ echo + fi + + exit 0 diff --git a/query_cache_enhance.patch b/query_cache_enhance.patch new file mode 100644 index 000000000000..15b755ecc590 --- /dev/null +++ b/query_cache_enhance.patch @@ -0,0 +1,505 @@ +# name : query_cache_with_comments.patch +# introduced : 11 or before +# maintainer : Oleg +# +#!!! notice !!! +# Any small change to this file in the main branch +# should be done or reviewed by the maintainer! +diff -ruN a/patch_info/query_cache_enhance.patch b/patch_info/query_cache_enhance.patch +--- a/patch_info/query_cache_enhance.patch 1970-01-01 05:00:00.000000000 +0500 ++++ b/patch_info/query_cache_enhance.patch 2010-11-12 17:24:47.000000000 +0500 +@@ -0,0 +1,15 @@ ++File=query_cache_enhance.patch ++Name= query cache Percona's cumulative patch ++Version=1.0 ++Author=Percona ++License=GPL ++Comment= 1) Add new status - Waiting on query cache mutex (status_wait_query_cache_mutex.patch) ++ 2) Remove comments from query (need for cache hit) (query_cache_with_comments.patch) ++ 3) Totally disable query cache (query_cache_totally_disable.info) ++2010-05 - First version avaliable (query_cache_with_comments.patch) ++2010-07 - First version avaliable (status_wait_query_cache_mutex.patch ++2010-07 - First version avaliable (query_cache_totally_disable.info) ++2010-07 - Fix crash (query_cache_with_comments.patch) ++2010-07 - Fix incorrect behavior diff (query_cache_with_comments.patch) ++2010-09 - Merge patches to one ++2010-11 - Ported to 5.5 +diff -ruN a/sql/mysqld.cc b/sql/mysqld.cc +--- a/sql/mysqld.cc 2010-11-03 03:01:14.000000000 +0500 ++++ b/sql/mysqld.cc 2010-11-13 15:34:40.000000000 +0500 +@@ -895,6 +895,7 @@ + #endif + #ifdef HAVE_QUERY_CACHE + ulong query_cache_min_res_unit= QUERY_CACHE_MIN_RESULT_DATA_SIZE; ++my_bool opt_query_cache_strip_comments= FALSE; + Query_cache query_cache; + #endif + #ifdef HAVE_SMEM +diff -ruN a/sql/mysqld.h b/sql/mysqld.h +--- a/sql/mysqld.h 2010-11-03 03:01:14.000000000 +0500 ++++ b/sql/mysqld.h 2010-11-13 15:34:36.000000000 +0500 +@@ -91,6 +91,7 @@ + extern my_bool opt_log, opt_slow_log; + extern my_bool opt_backup_history_log; + extern my_bool opt_backup_progress_log; ++extern my_bool opt_query_cache_strip_comments; + extern ulonglong log_output_options; + extern ulong log_backup_output_options; + extern my_bool opt_log_queries_not_using_indexes; +diff -ruN a/sql/query_strip_comments.h b/sql/query_strip_comments.h +--- a/sql/query_strip_comments.h 1970-01-01 05:00:00.000000000 +0500 ++++ b/sql/query_strip_comments.h 2010-11-12 17:24:47.000000000 +0500 +@@ -0,0 +1,37 @@ ++#ifndef _SQL_QUERY_STRIPC_COMMENTS_H_ ++#define _SQL_QUERY_STRIPC_COMMENTS_H_ ++#ifdef HAVE_QUERY_CACHE ++ ++// implemented in sql_cache.cc ++class QueryStripComments ++{ ++private: ++ QueryStripComments(const QueryStripComments&); ++ QueryStripComments& operator=(const QueryStripComments&); ++public: ++ QueryStripComments(); ++ ~QueryStripComments(); ++ void set(const char* a_query, uint a_query_length, uint a_additional_length); ++ ++ char* query() { return buffer; } ++ uint query_length() { return length; } ++private: ++ void cleanup(); ++private: ++ char* buffer; ++ uint length /*query length, not buffer length*/; ++ uint buffer_length; ++}; ++class QueryStripComments_Backup ++{ ++public: ++ QueryStripComments_Backup(THD* a_thd,QueryStripComments* qsc); ++ ~QueryStripComments_Backup(); ++private: ++ THD* thd; ++ char* query; ++ uint length; ++}; ++ ++#endif // HAVE_QUERY_CACHE ++#endif // _SQL_QUERY_STRIPC_COMMENTS_H_ +diff -ruN a/sql/sql_cache.cc b/sql/sql_cache.cc +--- a/sql/sql_cache.cc 2010-11-03 03:01:14.000000000 +0500 ++++ b/sql/sql_cache.cc 2010-11-12 17:24:47.000000000 +0500 +@@ -344,6 +344,181 @@ + #include "probes_mysql.h" + #include "transaction.h" + ++#include "query_strip_comments.h" ++ ++QueryStripComments::QueryStripComments() ++{ ++ buffer = 0; ++ length = 0; ++ buffer_length = 0; ++} ++QueryStripComments::~QueryStripComments() ++{ ++ cleanup(); ++} ++ ++inline bool query_strip_comments_is_white_space(char c) ++{ ++ return ((' ' == c) || ('\t' == c) || ('\r' == c) || ('\n' ==c )); ++} ++void QueryStripComments::set(const char* query, uint query_length, uint additional_length) ++{ ++ uint new_buffer_length = query_length + additional_length; ++ if(new_buffer_length > buffer_length) ++ { ++ cleanup(); ++ buffer = (char*)my_malloc(new_buffer_length,MYF(0)); ++ } ++ uint query_position = 0; ++ uint position = 0; ++ // Skip whitespaces from begin ++ while((query_position < query_length) && query_strip_comments_is_white_space(query[query_position])) ++ { ++ ++query_position; ++ } ++ long int last_space = -1; ++ while(query_position < query_length) ++ { ++ char current = query[query_position]; ++ bool insert_space = false; // insert space to buffer, (IMPORTANT) don't update query_position ++ switch(current) ++ { ++ case '\'': ++ case '"': ++ { ++ buffer[position++] = query[query_position++]; // copy current symbol ++ while(query_position < query_length) ++ { ++ if(current == query[query_position]) // found pair quote ++ { ++ break; ++ } ++ buffer[position++] = query[query_position++]; // copy current symbol ++ } ++ break; ++ } ++ case '/': ++ { ++ if(((query_position + 2) < query_length) && ('*' == query[query_position+1]) && ('!' != query[query_position+2])) ++ { ++ query_position += 2; // skip "/*" ++ do ++ { ++ if('*' == query[query_position] && '/' == query[query_position+1]) // check for "*/" ++ { ++ query_position += 2; // skip "*/" ++ insert_space = true; ++ break; ++ } ++ else ++ { ++ ++query_position; ++ } ++ } ++ while(query_position < query_length); ++ if(!insert_space) ++ { ++ continue; ++ } ++ } ++ break; ++ } ++ case '-': ++ { ++ if(query[query_position+1] == '-') ++ { ++ ++query_position; // skip "-", and go to search of "\n" ++ } ++ else ++ { ++ break; ++ } ++ } ++ case '#': ++ { ++ do ++ { ++ ++query_position; // skip current symbol (# or -) ++ if('\n' == query[query_position]) // check for '\n' ++ { ++ ++query_position; // skip '\n' ++ insert_space = true; ++ break; ++ } ++ } ++ while(query_position < query_length); ++ if(insert_space) ++ { ++ break; ++ } ++ else ++ { ++ continue; ++ } ++ } ++ default: ++ if(query_strip_comments_is_white_space(current)) ++ { ++ insert_space = true; ++ ++query_position; ++ } ++ break; // make gcc happy ++ } ++ if(insert_space) ++ { ++ if((last_space + 1) != position) ++ { ++ last_space = position; ++ buffer[position++] = ' '; ++ } ++ } ++ else ++ { ++ buffer[position++] = query[query_position++]; ++ } ++ } ++ while((0 < position) && query_strip_comments_is_white_space(buffer[position - 1])) ++ { ++ --position; ++ } ++ buffer[position] = 0; ++ length = position; ++} ++void QueryStripComments::cleanup() ++{ ++ if(buffer) ++ { ++ my_free(buffer); ++ } ++ buffer = 0; ++ length = 0; ++ buffer_length = 0; ++} ++QueryStripComments_Backup::QueryStripComments_Backup(THD* a_thd,QueryStripComments* qsc) ++{ ++ if(opt_query_cache_strip_comments) ++ { ++ thd = a_thd; ++ query = thd->query(); ++ length = thd->query_length(); ++ qsc->set(query,length,thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE); ++ thd->set_query(qsc->query(),qsc->query_length()); ++ } ++ else ++ { ++ thd = 0; ++ query = 0; ++ length = 0; ++ } ++} ++QueryStripComments_Backup::~QueryStripComments_Backup() ++{ ++ if(thd) ++ { ++ thd->set_query(query,length); ++ } ++} ++ + #ifdef EMBEDDED_LIBRARY + #include "emb_qcache.h" + #endif +@@ -454,7 +629,12 @@ + Query_cache_wait_state wait_state(thd, __func__, __FILE__, __LINE__); + DBUG_ENTER("Query_cache::try_lock"); + ++ const char* old_proc_info= thd->proc_info; ++ thd_proc_info(thd,"Waiting on query cache mutex"); + mysql_mutex_lock(&structure_guard_mutex); ++ DBUG_EXECUTE_IF("status_wait_query_cache_mutex_sleep", { ++ sleep(5); ++ }); + while (1) + { + if (m_cache_lock_status == Query_cache::UNLOCKED) +@@ -501,6 +681,7 @@ + } + } + mysql_mutex_unlock(&structure_guard_mutex); ++ thd->proc_info = old_proc_info; + + DBUG_RETURN(interrupt); + } +@@ -1274,6 +1455,8 @@ + unlock(); + DBUG_VOID_RETURN; + } ++ QueryStripComments *query_strip_comments = &(thd->query_strip_comments); ++ QueryStripComments_Backup backup(thd,query_strip_comments); + + /* Key is query + database + flag */ + if (thd->db_length) +@@ -1451,6 +1634,9 @@ + Query_cache_block_table *block_table, *block_table_end; + ulong tot_length; + Query_cache_query_flags flags; ++ QueryStripComments *query_strip_comments = &(thd->query_strip_comments); ++ char *sql_backup = sql; ++ uint query_length_backup = query_length; + DBUG_ENTER("Query_cache::send_result_to_client"); + + /* +@@ -1472,21 +1658,103 @@ + + { + uint i= 0; +- /* +- Skip '(' characters in queries like following: +- (select a from t1) union (select a from t1); +- */ +- while (sql[i]=='(') +- i++; ++ if(opt_query_cache_strip_comments) ++ { ++ /* Skip all comments and non-letter symbols */ ++ uint& query_position = i; ++ char* query = sql; ++ while(query_position < query_length) ++ { ++ bool check = false; ++ char current = query[query_position]; ++ switch(current) ++ { ++ case '/': ++ if(((query_position + 2) < query_length) && ('*' == query[query_position+1]) && ('!' != query[query_position+2])) ++ { ++ query_position += 2; // skip "/*" ++ do ++ { ++ if('*' == query[query_position] && '/' == query[query_position+1]) // check for "*/" (without space) ++ { ++ query_position += 2; // skip "*/" (without space) ++ break; ++ } ++ else ++ { ++ ++query_position; ++ } ++ } ++ while(query_position < query_length); ++ continue; // analyze current symbol ++ } ++ break; ++ case '-': ++ if(query[query_position+1] == '-') ++ { ++ ++query_position; // skip "-" ++ } ++ else ++ { ++ break; ++ } ++ case '#': ++ do ++ { ++ ++query_position; // skip current symbol ++ if('\n' == query[query_position]) // check for '\n' ++ { ++ ++query_position; // skip '\n' ++ break; ++ } ++ } ++ while(query_position < query_length); ++ continue; // analyze current symbol ++ case '\r': ++ case '\n': ++ case '\t': ++ case ' ': ++ case '(': ++ case ')': ++ break; ++ default: ++ check = true; ++ break; // make gcc happy ++ } // switch(current) ++ if(check) ++ { ++ if(query_position + 2 < query_length) ++ { ++ // cacheable ++ break; ++ } ++ else ++ { ++ DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached")); ++ goto err; ++ } ++ } // if(check) ++ ++query_position; ++ } // while(query_position < query_length) ++ } ++ else // if(opt_query_cache_strip_comments) ++ { ++ /* ++ Skip '(' characters in queries like following: ++ (select a from t1) union (select a from t1); ++ */ ++ while (sql[i]=='(') ++ i++; + +- /* +- Test if the query is a SELECT +- (pre-space is removed in dispatch_command). ++ } // if(opt_query_cache_strip_comments) ++ /* ++ Test if the query is a SELECT ++ (pre-space is removed in dispatch_command). + +- First '/' looks like comment before command it is not +- frequently appeared in real life, consequently we can +- check all such queries, too. +- */ ++ First '/' looks like comment before command it is not ++ frequently appeared in real life, consequently we can ++ check all such queries, too. ++ */ + if ((my_toupper(system_charset_info, sql[i]) != 'S' || + my_toupper(system_charset_info, sql[i + 1]) != 'E' || + my_toupper(system_charset_info, sql[i + 2]) != 'L') && +@@ -1521,6 +1789,12 @@ + goto err_unlock; + + Query_cache_block *query_block; ++ if(opt_query_cache_strip_comments) ++ { ++ query_strip_comments->set(sql, query_length, thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE); ++ sql = query_strip_comments->query(); ++ query_length = query_strip_comments->query_length(); ++ } + + tot_length= query_length + thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE; + if (thd->db_length) +@@ -1587,6 +1861,8 @@ + (uchar*) &flags, QUERY_CACHE_FLAGS_SIZE); + query_block = (Query_cache_block *) my_hash_search(&queries, (uchar*) sql, + tot_length); ++ sql = sql_backup; ++ query_length = query_length_backup; + /* Quick abort on unlocked data */ + if (query_block == 0 || + query_block->query()->result() == 0 || +diff -ruN a/sql/sql_class.h b/sql/sql_class.h +--- a/sql/sql_class.h 2010-11-03 03:01:14.000000000 +0500 ++++ b/sql/sql_class.h 2010-11-13 15:34:25.000000000 +0500 +@@ -40,6 +40,9 @@ + #include "thr_lock.h" /* thr_lock_type, THR_LOCK_DATA, + THR_LOCK_INFO */ + ++#ifdef HAVE_QUERY_CACHE ++#include "query_strip_comments.h" ++#endif // HAVE_QUERY_CACHE + + class Reprepare_observer; + class Relay_log_info; +@@ -753,6 +756,9 @@ + + inline char *query() { return query_string.str; } + inline uint32 query_length() { return query_string.length; } ++#ifdef HAVE_QUERY_CACHE ++ QueryStripComments query_strip_comments; // see sql_cache.cc ++#endif //HAVE_QUERY_CACHE + void set_query_inner(char *query_arg, uint32 query_length_arg); + + /** +diff -ruN a/sql/sys_vars.cc b/sql/sys_vars.cc +--- a/sql/sys_vars.cc 2010-11-03 03:01:14.000000000 +0500 ++++ b/sql/sys_vars.cc 2010-11-13 15:34:59.000000000 +0500 +@@ -1744,6 +1744,11 @@ + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(fix_query_cache_size)); + ++static Sys_var_mybool Sys_query_cache_strip_comments( ++ "query_cache_strip_comments", "Enable and disable optimisation \"strip comment for query cache\" - optimisation strip all comments from query while search query result in query cache", ++ GLOBAL_VAR(opt_query_cache_strip_comments), CMD_LINE(OPT_ARG), ++ DEFAULT(FALSE)); ++ + static Sys_var_ulong Sys_query_cache_limit( + "query_cache_limit", + "Don't cache results that are bigger than this", +diff -ruN a/mysql-test/suite/sys_vars/r/all_vars.result b/mysql-test/suite/sys_vars/r/all_vars.result +--- a/mysql-test/suite/sys_vars/r/all_vars.result 2010-11-03 01:01:13.000000000 +0300 ++++ b/mysql-test/suite/sys_vars/r/all_vars.result 2010-11-23 20:04:40.000000000 +0300 +@@ -10,8 +10,10 @@ + select variable_name as `There should be *no* variables listed below:` from t2 + left join t1 on variable_name=test_name where test_name is null; + There should be *no* variables listed below: ++QUERY_CACHE_STRIP_COMMENTS + SUPPRESS_LOG_WARNING_1592 + INNODB_FILE_FORMAT_MAX ++QUERY_CACHE_STRIP_COMMENTS + SUPPRESS_LOG_WARNING_1592 + INNODB_FILE_FORMAT_MAX + drop table t1; diff --git a/regenerate_patch.sh b/regenerate_patch.sh new file mode 100755 index 000000000000..0c9914417067 --- /dev/null +++ b/regenerate_patch.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env sh +a=$1 +b=$2 +patch_name=$3 +prefix="[$patch_name]" +big_prefix="$prefix ===== " +echo "$big_prefix Regenerate patch $patch_name based thought $a and $b" +echo "$big_prefix Header is:" +cat $patch_name | head -n7; +echo "$big_prefix Ok, let's go:" +patch_name_new=$patch_name.new; +patch_name_split=$patch_name.split; +echo "$prefix Remove $patch_name_new if exists..." +rm -f $patch_name_new; +echo "$prefix Remove $patch_name_split if exists..." +rm -rf $patch_name_split; +echo "$prefix Create $patch_name_split" +mkdir $patch_name_split; +cd $patch_name_split; +echo "$prefix Add header" +cat ../$patch_name | head -n7 > ../$patch_name_new +echo "$prefix Split to separated files" +for filename in `splitdiff -a -d ../$patch_name | awk '{ print $2 }' | sed -e "s/>//g"`; do + echo "$prefix extract diff metainformation from $filename" + a_head=`cat $filename | head -n2 | head -n1`; + b_head=`cat $filename | head -n2 | tail -n1`; + a_path=`echo $a_head | awk '{ print $2 }'`; + b_path=`echo $b_head | awk '{ print $2 }'`; + diff_string="diff -ruN $a_path $b_path"; + echo "$big_prefix $filename metainformation is:"; + echo "$prefix $diff_string"; + echo "$prefix $a_head" + echo "$prefix $b_head" + echo "$big_prefix Update patch by $filename" + (cd ..; echo $diff_string >> $patch_name_new); + (cat $filename | head -n2 | head -n1 >> ../$patch_name_new); + (cat $filename | head -n2 | tail -n1 >> ../$patch_name_new); + (cd ..; diff -ruN $a_path $b_path | tail -n+3 >> $patch_name_new); +done; +cd ..; +echo "$prefix Rename temporary patch to final" +cat $patch_name_new > $patch_name; +echo "$prefix Remove temporary files" +rm $patch_name_new; +rm -rf $patch_name_split; +echo "$big_prefix Complete" diff --git a/remove_fcntl_excessive_calls.patch b/remove_fcntl_excessive_calls.patch new file mode 100644 index 000000000000..e48bbdf4e5e7 --- /dev/null +++ b/remove_fcntl_excessive_calls.patch @@ -0,0 +1,82 @@ +# name : remove_fcntl_excessive_calls.patch +# introduced : 12 +# maintainer : Oleg +# +#!!! notice !!! +# Any small change to this file in the main branch +# should be done or reviewed by the maintainer! +diff -ruN a/patch_info/remove_fcntl_excessive_calls.info b/patch_info/remove_fcntl_excessive_calls.info +--- a/patch_info/remove_fcntl_excessive_calls.info 1970-01-01 03:00:00.000000000 +0300 ++++ b/patch_info/remove_fcntl_excessive_calls.info 2010-07-22 21:42:08.560424001 +0400 +@@ -0,0 +1,6 @@ ++File=remove_fcntl_excessive_calls.patch ++Name=remove fcntl excessive calls ++Version=1.0 ++Author=This is a port of the official fix. ++License=GPL ++Comment= +diff -ruN a/sql/net_serv.cc b/sql/net_serv.cc +--- a/sql/net_serv.cc 2010-06-03 19:50:27.000000000 +0400 ++++ b/sql/net_serv.cc 2010-07-22 21:40:30.680424001 +0400 +@@ -133,7 +133,7 @@ + if (vio != 0) /* If real connection */ + { + net->fd = vio_fd(vio); /* For perl DBI/DBD */ +-#if defined(MYSQL_SERVER) && !defined(__WIN__) ++#if defined(MYSQL_SERVER) && !defined(__WIN__) && !defined(NO_ALARM) + if (!(test_flags & TEST_BLOCKING)) + { + my_bool old_mode; +@@ -642,7 +642,7 @@ + if ((long) (length= vio_write(net->vio,pos,(size_t) (end-pos))) <= 0) + { + my_bool interrupted = vio_should_retry(net->vio); +-#if !defined(__WIN__) ++#if !defined(NO_ALARM) && !defined(__WIN__) + if ((interrupted || length == 0) && !thr_alarm_in_use(&alarmed)) + { + if (!thr_alarm(&alarmed, net->write_timeout, &alarm_buff)) +@@ -680,7 +680,7 @@ + my_progname); + #endif /* EXTRA_DEBUG */ + } +-#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) ++#if defined(THREAD_SAFE_CLIENT) && defined(NO_ALARM) + if (vio_errno(net->vio) == SOCKET_EINTR) + { + DBUG_PRINT("warning",("Interrupted write. Retrying...")); +@@ -698,7 +698,7 @@ + pos+=length; + update_statistics(thd_increment_bytes_sent(length)); + } +-#ifndef __WIN__ ++#if !defined(NO_ALARM) && !defined(__WIN__) + end: + #endif + #ifdef HAVE_COMPRESS +@@ -830,6 +830,7 @@ + thr_alarm(&alarmed,net->read_timeout,&alarm_buff); + #else + /* Read timeout is set in my_net_set_read_timeout */ ++ DBUG_ASSERT(net_blocking); + #endif /* NO_ALARM */ + + pos = net->buff + net->where_b; /* net->packet -4 */ +@@ -844,7 +845,7 @@ + + DBUG_PRINT("info",("vio_read returned %ld errno: %d", + (long) length, vio_errno(net->vio))); +-#if !defined(__WIN__) || defined(MYSQL_SERVER) ++#if !defined(NO_ALARM) && (!defined(__WIN__) || defined(MYSQL_SERVER)) + /* + We got an error that there was no data on the socket. We now set up + an alarm to not 'read forever', change the socket to non blocking +@@ -891,7 +892,7 @@ + my_progname,vio_errno(net->vio)); + #endif /* EXTRA_DEBUG */ + } +-#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) ++#if defined(THREAD_SAFE_CLIENT) && defined(NO_ALARM) + if (vio_errno(net->vio) == SOCKET_EINTR) + { + DBUG_PRINT("warning",("Interrupted read. Retrying...")); diff --git a/response_time_distribution.patch b/response_time_distribution.patch new file mode 100644 index 000000000000..9fd6fe888104 --- /dev/null +++ b/response_time_distribution.patch @@ -0,0 +1,960 @@ +# name : response-time-distribution.patch +# introduced : 12 +# maintainer : Oleg +# +#!!! notice !!! +# Any small change to this file in the main branch +# should be done or reviewed by the maintainer! +diff -ruN a/include/mysql_com.h b/include/mysql_com.h +--- a/include/mysql_com.h 2010-11-03 03:01:11.000000000 +0500 ++++ b/include/mysql_com.h 2010-11-14 16:40:34.000000000 +0500 +@@ -137,10 +137,11 @@ + #define REFRESH_FAST 32768 /* Intern flag */ + + /* RESET (remove all queries) from query cache */ +-#define REFRESH_QUERY_CACHE 65536 +-#define REFRESH_QUERY_CACHE_FREE 0x20000L /* pack query cache */ +-#define REFRESH_DES_KEY_FILE 0x40000L +-#define REFRESH_USER_RESOURCES 0x80000L ++#define REFRESH_QUERY_CACHE 65536 ++#define REFRESH_QUERY_CACHE_FREE 0x20000L /* pack query cache */ ++#define REFRESH_DES_KEY_FILE 0x40000L ++#define REFRESH_USER_RESOURCES 0x80000L ++#define REFRESH_QUERY_RESPONSE_TIME 0x100000L /* response time distibution */ + + #define CLIENT_LONG_PASSWORD 1 /* new more secure passwords */ + #define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */ +diff -ruN a/patch_info/response-time-distribution.info b/patch_info/response-time-distribution.info +--- a/patch_info/response-time-distribution.info 1970-01-01 05:00:00.000000000 +0500 ++++ b/patch_info/response-time-distribution.info 2010-11-13 20:14:00.000000000 +0500 +@@ -0,0 +1,9 @@ ++File=response-time-distribution.patch ++Name=Response time distribution ++Version=1.0 ++Author=Percona ++License=GPL ++Comment= ++Changelog ++2010-07-02 first version avaliable ++2010-09-15 add column 'total' +diff -ruN a/sql/CMakeLists.txt b/sql/CMakeLists.txt +--- a/sql/CMakeLists.txt 2010-11-03 03:01:14.000000000 +0500 ++++ b/sql/CMakeLists.txt 2010-11-14 16:50:47.000000000 +0500 +@@ -55,7 +55,7 @@ + message.h mf_iocache.cc my_decimal.cc ../sql-common/my_time.c + mysqld.cc net_serv.cc keycaches.cc + ../sql-common/client_plugin.c +- opt_range.cc opt_range.h opt_sum.cc ++ opt_range.cc opt_range.h query_response_time.h opt_sum.cc + ../sql-common/pack.c parse_file.cc password.c procedure.cc + protocol.cc records.cc repl_failsafe.cc rpl_filter.cc set_var.cc + slave.cc sp.cc sp_cache.cc sp_head.cc sp_pcontext.cc +@@ -63,7 +63,7 @@ + sql_cache.cc sql_class.cc sql_client.cc sql_crypt.cc sql_crypt.h + sql_cursor.cc sql_db.cc sql_delete.cc sql_derived.cc sql_do.cc + sql_error.cc sql_handler.cc sql_help.cc sql_insert.cc sql_lex.cc +- sql_list.cc sql_load.cc sql_manager.cc sql_parse.cc ++ sql_list.cc sql_load.cc sql_manager.cc sql_parse.cc query_response_time.cc + sql_partition.cc sql_plugin.cc sql_prepare.cc sql_rename.cc + debug_sync.cc debug_sync.h + sql_repl.cc sql_select.cc sql_show.cc sql_state.c sql_string.cc +diff -ruN a/sql/handler.h b/sql/handler.h +--- a/sql/handler.h 2010-11-03 03:01:14.000000000 +0500 ++++ b/sql/handler.h 2010-11-14 16:44:23.000000000 +0500 +@@ -578,6 +578,7 @@ + SCH_PROFILES, + SCH_REFERENTIAL_CONSTRAINTS, + SCH_PROCEDURES, ++ SCH_QUERY_RESPONSE_TIME, + SCH_SCHEMATA, + SCH_SCHEMA_PRIVILEGES, + SCH_SESSION_STATUS, +diff -ruN a/sql/lex.h b/sql/lex.h +--- a/sql/lex.h 2010-11-03 03:01:14.000000000 +0500 ++++ b/sql/lex.h 2010-11-14 16:40:48.000000000 +0500 +@@ -427,6 +427,7 @@ + { "PURGE", SYM(PURGE)}, + { "QUARTER", SYM(QUARTER_SYM)}, + { "QUERY", SYM(QUERY_SYM)}, ++ { "QUERY_RESPONSE_TIME", SYM(QUERY_RESPONSE_TIME_SYM)}, + { "QUICK", SYM(QUICK)}, + { "RANGE", SYM(RANGE_SYM)}, + { "READ", SYM(READ_SYM)}, +diff -ruN a/sql/Makefile.am b/sql/Makefile.am +--- a/sql/Makefile.am 2010-11-03 03:01:14.000000000 +0500 ++++ b/sql/Makefile.am 2010-11-14 16:41:02.000000000 +0500 +@@ -113,7 +113,7 @@ + sql_repl.h slave.h rpl_filter.h rpl_injector.h \ + log_event.h rpl_record.h sql_const.h \ + log_event_old.h rpl_record_old.h \ +- sql_sort.h sql_cache.h set_var.h sys_vars_shared.h \ ++ sql_sort.h sql_cache.h set_var.h query_response_time.h sys_vars_shared.h \ + spatial.h gstream.h client_settings.h tzfile.h \ + tztime.h my_decimal.h keycaches.h \ + sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \ +@@ -139,7 +139,7 @@ + lock.cc sql_string.cc sql_manager.cc \ + main.cc mysqld.cc password.c hash_filo.cc hostname.cc \ + sql_connect.cc scheduler.cc sql_parse.cc \ +- keycaches.cc set_var.cc sql_yacc.yy sys_vars.cc \ ++ keycaches.cc set_var.cc query_response_time.cc sql_yacc.yy sys_vars.cc \ + sql_base.cc table.cc sql_select.cc sql_insert.cc \ + sql_reload.cc datadict.cc sql_profile.cc \ + sql_prepare.cc sql_error.cc sql_locale.cc \ +diff -ruN a/sql/Makefile.in b/sql/Makefile.in +--- a/sql/Makefile.in 2010-11-03 03:01:37.000000000 +0500 ++++ b/sql/Makefile.in 2010-11-14 16:41:09.000000000 +0500 +@@ -125,7 +125,7 @@ + sql_state.$(OBJEXT) lock.$(OBJEXT) sql_string.$(OBJEXT) \ + sql_manager.$(OBJEXT) main.$(OBJEXT) mysqld.$(OBJEXT) \ + password.$(OBJEXT) hash_filo.$(OBJEXT) hostname.$(OBJEXT) \ +- sql_connect.$(OBJEXT) scheduler.$(OBJEXT) sql_parse.$(OBJEXT) \ ++ sql_connect.$(OBJEXT) scheduler.$(OBJEXT) sql_parse.$(OBJEXT) query_response_time.${OBJEXT} \ + keycaches.$(OBJEXT) set_var.$(OBJEXT) sql_yacc.$(OBJEXT) \ + sys_vars.$(OBJEXT) sql_base.$(OBJEXT) table.$(OBJEXT) \ + sql_select.$(OBJEXT) sql_insert.$(OBJEXT) sql_reload.$(OBJEXT) \ +@@ -626,7 +626,7 @@ + sql_repl.h slave.h rpl_filter.h rpl_injector.h \ + log_event.h rpl_record.h sql_const.h \ + log_event_old.h rpl_record_old.h \ +- sql_sort.h sql_cache.h set_var.h sys_vars_shared.h \ ++ sql_sort.h sql_cache.h set_var.h query_response_time.h sys_vars_shared.h \ + spatial.h gstream.h client_settings.h tzfile.h \ + tztime.h my_decimal.h keycaches.h \ + sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \ +@@ -652,7 +652,7 @@ + lock.cc sql_string.cc sql_manager.cc \ + main.cc mysqld.cc password.c hash_filo.cc hostname.cc \ + sql_connect.cc scheduler.cc sql_parse.cc \ +- keycaches.cc set_var.cc sql_yacc.yy sys_vars.cc \ ++ keycaches.cc set_var.cc query_response_time.cc sql_yacc.yy sys_vars.cc \ + sql_base.cc table.cc sql_select.cc sql_insert.cc \ + sql_reload.cc datadict.cc sql_profile.cc \ + sql_prepare.cc sql_error.cc sql_locale.cc \ +@@ -905,6 +905,7 @@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/password.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/procedure.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol.Po@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/query_response_time.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/records.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repl_failsafe.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpl_filter.Po@am__quote@ +diff -ruN a/sql/mysqld.cc b/sql/mysqld.cc +--- a/sql/mysqld.cc 2010-11-13 18:11:01.000000000 +0500 ++++ b/sql/mysqld.cc 2010-11-14 16:41:20.000000000 +0500 +@@ -69,6 +69,8 @@ + #include "debug_sync.h" + #include "sql_callback.h" + ++#include "query_response_time.h" ++ + #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE + #include "../storage/perfschema/pfs_server.h" + #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ +@@ -903,6 +905,8 @@ + my_bool opt_enable_shared_memory; + HANDLE smem_event_connect_request= 0; + #endif ++ulong opt_query_response_time_range_base = QRT_DEFAULT_BASE; ++my_bool opt_enable_query_response_time_stats= 0; + + my_bool opt_use_ssl = 0; + char *opt_ssl_ca= NULL, *opt_ssl_capath= NULL, *opt_ssl_cert= NULL, +@@ -1471,6 +1475,7 @@ + my_free(opt_bin_logname); + bitmap_free(&temp_pool); + free_max_user_conn(); ++ query_response_time_free(); + #ifdef HAVE_REPLICATION + end_slave_list(); + #endif +@@ -3939,6 +3944,8 @@ + if (!DEFAULT_ERRMSGS[0][0]) + unireg_abort(1); + ++ query_response_time_init(); ++ + /* We have to initialize the storage engines before CSV logging */ + if (ha_init()) + { +diff -ruN a/sql/mysqld.h b/sql/mysqld.h +--- a/sql/mysqld.h 2010-11-13 18:11:01.000000000 +0500 ++++ b/sql/mysqld.h 2010-11-14 16:42:11.000000000 +0500 +@@ -98,6 +98,8 @@ + extern bool opt_disable_networking, opt_skip_show_db; + extern bool opt_skip_name_resolve; + extern bool opt_ignore_builtin_innodb; ++extern ulong opt_query_response_time_range_base; ++extern my_bool opt_enable_query_response_time_stats; + extern my_bool opt_character_set_client_handshake; + extern bool volatile abort_loop; + extern bool in_bootstrap; +diff -ruN a/sql/query_response_time.cc b/sql/query_response_time.cc +--- a/sql/query_response_time.cc 1970-01-01 05:00:00.000000000 +0500 ++++ b/sql/query_response_time.cc 2010-11-14 17:45:42.000000000 +0500 +@@ -0,0 +1,365 @@ ++#include "mysql_version.h" ++#ifdef __FreeBSD__ ++#include ++#include ++#endif // __FreeBSD__ ++#include "my_global.h" ++#include "mysql_com.h" ++#include "rpl_tblmap.h" ++#include "table.h" ++#include "field.h" ++#include "sql_show.h" ++#include "query_response_time.h" ++ ++#define TIME_STRING_POSITIVE_POWER_LENGTH QRT_TIME_STRING_POSITIVE_POWER_LENGTH ++#define TIME_STRING_NEGATIVE_POWER_LENGTH 6 ++#define TOTAL_STRING_POSITIVE_POWER_LENGTH QRT_TOTAL_STRING_POSITIVE_POWER_LENGTH ++#define TOTAL_STRING_NEGATIVE_POWER_LENGTH 6 ++#define MINIMUM_BASE 2 ++#define MAXIMUM_BASE QRT_MAXIMUM_BASE ++#define POSITIVE_POWER_FILLER QRT_POSITIVE_POWER_FILLER ++#define NEGATIVE_POWER_FILLER QRT_NEGATIVE_POWER_FILLER ++#define STRING_OVERFLOW QRT_STRING_OVERFLOW ++#define TIME_OVERFLOW QRT_TIME_OVERFLOW ++#define DEFAULT_BASE QRT_DEFAULT_BASE ++ ++#define do_xstr(s) do_str(s) ++#define do_str(s) #s ++#define do_format(filler,width) "%" filler width "lld" ++/* ++ Format strings for snprintf. Generate from: ++ POSITIVE_POWER_FILLER and TIME_STRING_POSITIVE_POWER_LENGTH ++ NEFATIVE_POWER_FILLER and TIME_STRING_NEGATIVE_POWER_LENGTH ++*/ ++#define TIME_STRING_POSITIVE_POWER_FORMAT do_format(POSITIVE_POWER_FILLER,do_xstr(TIME_STRING_POSITIVE_POWER_LENGTH)) ++#define TIME_STRING_NEGATIVE_POWER_FORMAT do_format(NEGATIVE_POWER_FILLER,do_xstr(TIME_STRING_NEGATIVE_POWER_LENGTH)) ++#define TIME_STRING_FORMAT TIME_STRING_POSITIVE_POWER_FORMAT "." TIME_STRING_NEGATIVE_POWER_FORMAT ++ ++#define TOTAL_STRING_POSITIVE_POWER_FORMAT do_format(POSITIVE_POWER_FILLER,do_xstr(TOTAL_STRING_POSITIVE_POWER_LENGTH)) ++#define TOTAL_STRING_NEGATIVE_POWER_FORMAT do_format(NEGATIVE_POWER_FILLER,do_xstr(TOTAL_STRING_NEGATIVE_POWER_LENGTH)) ++#define TOTAL_STRING_FORMAT TOTAL_STRING_POSITIVE_POWER_FORMAT "." TOTAL_STRING_NEGATIVE_POWER_FORMAT ++ ++#define TIME_STRING_LENGTH QRT_TIME_STRING_LENGTH ++#define TIME_STRING_BUFFER_LENGTH (TIME_STRING_LENGTH + 1 /* '\0' */) ++ ++#define TOTAL_STRING_LENGTH QRT_TOTAL_STRING_LENGTH ++#define TOTAL_STRING_BUFFER_LENGTH (TOTAL_STRING_LENGTH + 1 /* '\0' */) ++ ++/* ++ Calculate length of "log linear" ++ 1) ++ (MINIMUM_BASE ^ result) <= (10 ^ STRING_POWER_LENGTH) < (MINIMUM_BASE ^ (result + 1)) ++ ++ 2) ++ (MINIMUM_BASE ^ result) <= (10 ^ STRING_POWER_LENGTH) ++ and ++ (MINIMUM_BASE ^ (result + 1)) > (10 ^ STRING_POWER_LENGTH) ++ ++ 3) ++ result <= LOG(MINIMUM_BASE, 10 ^ STRING_POWER_LENGTH)= STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10) ++ result + 1 > LOG(MINIMUM_BASE, 10 ^ STRING_POWER_LENGTH)= STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10) ++ ++ 4) STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10) - 1 < result <= STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10) ++ ++ MINIMUM_BASE= 2 always, LOG(MINIMUM_BASE,10)= 3.3219280948873626, result= (int)3.3219280948873626 * STRING_POWER_LENGTH ++ ++ Last counter always use for time overflow ++*/ ++#define POSITIVE_POWER_COUNT ((int)(3.32192809 * TIME_STRING_POSITIVE_POWER_LENGTH)) ++#define NEGATIVE_POWER_COUNT ((int)(3.32192809 * TIME_STRING_NEGATIVE_POWER_LENGTH)) ++#define OVERALL_POWER_COUNT (NEGATIVE_POWER_COUNT + 1 + POSITIVE_POWER_COUNT) ++ ++#define MILLION ((unsigned long)1000 * 1000) ++ ++namespace query_response_time ++{ ++ ++class utility ++{ ++public: ++ utility() : m_base(0) ++ { ++ m_max_dec_value= MILLION; ++ for(int i= 0; TIME_STRING_POSITIVE_POWER_LENGTH > i; ++i) ++ m_max_dec_value *= 10; ++ setup(DEFAULT_BASE); ++ } ++public: ++ uint base() const { return m_base; } ++ uint negative_count() const { return m_negative_count; } ++ uint positive_count() const { return m_positive_count; } ++ uint bound_count() const { return m_bound_count; } ++ ulonglong max_dec_value() const { return m_max_dec_value; } ++ ulonglong bound(uint index) const { return m_bound[ index ]; } ++public: ++ void setup(uint base) ++ { ++ if(base != m_base) ++ { ++ m_base= base; ++ ++ const ulonglong million= 1000 * 1000; ++ ulonglong value= million; ++ m_negative_count= 0; ++ while(value > 0) ++ { ++ m_negative_count += 1; ++ value /= m_base; ++ } ++ m_negative_count -= 1; ++ ++ value= million; ++ m_positive_count= 0; ++ while(value < m_max_dec_value) ++ { ++ m_positive_count += 1; ++ value *= m_base; ++ } ++ m_bound_count= m_negative_count + m_positive_count; ++ ++ value= million; ++ for(uint i= 0; i < m_negative_count; ++i) ++ { ++ value /= m_base; ++ m_bound[m_negative_count - i - 1]= value; ++ } ++ value= million; ++ for(uint i= 0; i < m_positive_count; ++i) ++ { ++ m_bound[m_negative_count + i]= value; ++ value *= m_base; ++ } ++ } ++ } ++private: ++ uint m_base; ++ uint m_negative_count; ++ uint m_positive_count; ++ uint m_bound_count; ++ ulonglong m_max_dec_value; /* for TIME_STRING_POSITIVE_POWER_LENGTH=7 is 10000000 */ ++ ulonglong m_bound[OVERALL_POWER_COUNT]; ++}; ++ ++void print_time(char* buffer, std::size_t buffer_size, std::size_t string_positive_power_length, const char* format, uint64 value) ++{ ++ memset(buffer,'X',buffer_size); ++ buffer[string_positive_power_length]= '.'; ++ ulonglong second= (value / MILLION); ++ ulonglong microsecond= (value % MILLION); ++ std::size_t result_length= snprintf(buffer,buffer_size,format,second,microsecond); ++ if(result_length < 0) ++ { ++ assert(sizeof(STRING_OVERFLOW) <= buffer_size); ++ memcpy(buffer, STRING_OVERFLOW, sizeof(STRING_OVERFLOW)); ++ return; ++ } ++ buffer[result_length]= 0; ++} ++#ifdef __x86_64__ ++typedef uint64 TimeCounter; ++void add_time_atomic(TimeCounter* counter, uint64 time) ++{ ++ __sync_fetch_and_add(counter,time); ++} ++#endif // __x86_64__ ++#ifdef __i386__ ++inline uint32 get_high(uint64 value) ++{ ++ return ((value >> 32) << 32); ++} ++inline uint32 get_low(uint64 value) ++{ ++ return ((value << 32) >> 32); ++} ++#ifdef __FreeBSD__ ++inline bool compare_and_swap(volatile uint32 *target, uint32 old, uint32 new_value) ++{ ++ return atomic_cmpset_32(target,old,new_value); ++} ++#else // __FreeBSD__ ++inline bool compare_and_swap(volatile uint32* target, uint32 old, uint32 new_value) ++{ ++ return __sync_bool_compare_and_swap(target,old,new_value); ++} ++#endif // __FreeBSD__ ++class TimeCounter ++{ ++public: ++ TimeCounter& operator=(uint64 time) ++ { ++ this->m_high= get_high(time); ++ this->m_low= get_low(time); ++ return *this; ++ } ++ operator uint64() const ++ { ++ return ((static_cast(m_high) << 32) + static_cast(m_low)); ++ } ++ void add(uint64 time) ++ { ++ uint32 time_high = get_high(time); ++ uint32 time_low = get_low(time); ++ uint64 time_low64= time_low; ++ while(true) ++ { ++ uint32 old_low= this->m_low; ++ uint64 old_low64= old_low; ++ ++ uint64 new_low64= old_low64 + time_low64; ++ uint32 new_low= (get_low(new_low64)); ++ bool add_high= (get_high(new_low64) != 0); ++ ++ if(!compare_and_swap(&m_low,old_low,new_low)) ++ { ++ continue; ++ } ++ if(add_high) ++ { ++ ++time_high; ++ } ++ if(time_high > 0) ++ { ++ __sync_fetch_and_add(&m_high,time_high); ++ } ++ break; ++ } ++ } ++private: ++ uint32 m_low; ++ uint32 m_high; ++}; ++void add_time_atomic(TimeCounter* counter, uint64 time) ++{ ++ counter->add(time); ++} ++#endif // __i386__ ++ ++class time_collector ++{ ++public: ++ time_collector(utility& u) : m_utility(&u) ++ { ++ } ++ uint32 count(uint index) const { return m_count[index]; } ++ uint64 total(uint index) const { return m_total[index]; } ++public: ++ void flush() ++ { ++ memset(&m_count,0,sizeof(m_count)); ++ memset((void*)&m_total,0,sizeof(m_total)); ++ } ++ void collect(uint64 time) ++ { ++ int i= 0; ++ for(int count= m_utility->bound_count(); count > i; ++i) ++ { ++ if(m_utility->bound(i) > time) ++ { ++ __sync_fetch_and_add(&(m_count[i]),(uint32)1); ++ add_time_atomic(&(m_total[i]),time); ++ break; ++ } ++ } ++ } ++private: ++ utility* m_utility; ++ uint32 m_count[OVERALL_POWER_COUNT + 1]; ++ TimeCounter m_total[OVERALL_POWER_COUNT + 1]; ++}; ++ ++class collector ++{ ++public: ++ collector() : m_time(m_utility) ++ { ++ m_utility.setup(DEFAULT_BASE); ++ m_time.flush(); ++ } ++public: ++ void flush() ++ { ++ m_utility.setup(opt_query_response_time_range_base); ++ m_time.flush(); ++ } ++ int fill(THD* thd, TABLE_LIST *tables, COND *cond) ++ { ++ DBUG_ENTER("fill_schema_query_response_time"); ++ TABLE *table= static_cast(tables->table); ++ Field **fields= table->field; ++ for(uint i= 0, count= bound_count() + 1 /* with overflow */; count > i; ++i) ++ { ++ char time[TIME_STRING_BUFFER_LENGTH]; ++ char total[TOTAL_STRING_BUFFER_LENGTH]; ++ if(i == bound_count()) ++ { ++ assert(sizeof(TIME_OVERFLOW) <= TIME_STRING_BUFFER_LENGTH); ++ assert(sizeof(TIME_OVERFLOW) <= TOTAL_STRING_BUFFER_LENGTH); ++ memcpy(time,TIME_OVERFLOW,sizeof(TIME_OVERFLOW)); ++ memcpy(total,TIME_OVERFLOW,sizeof(TIME_OVERFLOW)); ++ } ++ else ++ { ++ print_time(time,sizeof(time),TIME_STRING_POSITIVE_POWER_LENGTH,TIME_STRING_FORMAT,this->bound(i)); ++ print_time(total,sizeof(total),TOTAL_STRING_POSITIVE_POWER_LENGTH,TOTAL_STRING_FORMAT,this->total(i)); ++ } ++ fields[0]->store(time,strlen(time),system_charset_info); ++ fields[1]->store(this->count(i)); ++ fields[2]->store(total,strlen(total),system_charset_info); ++ if (schema_table_store_record(thd, table)) ++ { ++ DBUG_RETURN(1); ++ } ++ } ++ DBUG_RETURN(0); ++ } ++ void collect(ulonglong time) ++ { ++ m_time.collect(time); ++ } ++ uint bound_count() const ++ { ++ return m_utility.bound_count(); ++ } ++ ulonglong bound(uint index) ++ { ++ return m_utility.bound(index); ++ } ++ ulonglong count(uint index) ++ { ++ return m_time.count(index); ++ } ++ ulonglong total(uint index) ++ { ++ return m_time.total(index); ++ } ++private: ++ utility m_utility; ++ time_collector m_time; ++}; ++ ++static collector g_collector; ++ ++} // namespace query_response_time ++ ++void query_response_time_init() ++{ ++} ++ ++void query_response_time_free() ++{ ++ query_response_time::g_collector.flush(); ++} ++ ++void query_response_time_flush() ++{ ++ query_response_time::g_collector.flush(); ++} ++void query_response_time_collect(ulonglong query_time) ++{ ++ query_response_time::g_collector.collect(query_time); ++} ++ ++int query_response_time_fill(THD* thd, TABLE_LIST *tables, COND *cond) ++{ ++ return query_response_time::g_collector.fill(thd,tables,cond); ++} +diff -ruN a/sql/query_response_time.h b/sql/query_response_time.h +--- a/sql/query_response_time.h 1970-01-01 05:00:00.000000000 +0500 ++++ b/sql/query_response_time.h 2010-11-13 20:14:00.000000000 +0500 +@@ -0,0 +1,69 @@ ++#ifndef QUERY_RESPONSE_TIME_H ++#define QUERY_RESPONSE_TIME_H ++ ++/* ++ Settings for query response time ++*/ ++ ++/* ++ Maximum string length for (10 ^ (-1 * QRT_STRING_NEGATIVE_POWER_LENGTH)) in text representation. ++ Example: for 6 is 0.000001 ++ Always 2 ++ ++ Maximum string length for (10 ^ (QRT_STRING_POSITIVE_POWER_LENGTH + 1) - 1) in text representation. ++ Example: for 7 is 9999999.0 ++*/ ++#define QRT_TIME_STRING_POSITIVE_POWER_LENGTH 7 ++#define QRT_TOTAL_STRING_POSITIVE_POWER_LENGTH 7 ++ ++/* ++ Minimum base for log - ALWAYS 2 ++ Maximum base for log: ++*/ ++#define QRT_MAXIMUM_BASE 1000 ++ ++/* ++ Filler for whole number (positive power) ++ Example: for ++ QRT_POSITIVE_POWER_FILLER ' ' ++ QRT_POSITIVE_POWER_LENGTH 7 ++ and number 7234 result is: ++ ' 7234' ++*/ ++#define QRT_POSITIVE_POWER_FILLER " " ++/* ++ Filler for fractional number. Similiary to whole number ++*/ ++#define QRT_NEGATIVE_POWER_FILLER "0" ++ ++/* ++ Message if string overflow (string overflow - internal error, this string say about bug in QRT) ++*/ ++#define QRT_STRING_OVERFLOW "TOO BIG STRING" ++ ++/* ++ Message if time too big for statistic collecting (very long query) ++*/ ++#define QRT_TIME_OVERFLOW "TOO LONG" ++ ++#define QRT_DEFAULT_BASE 10 ++ ++#define QRT_TIME_STRING_LENGTH \ ++ max( (QRT_TIME_STRING_POSITIVE_POWER_LENGTH + 1 /* '.' */ + 6 /*QRT_TIME_STRING_NEGATIVE_POWER_LENGTH*/), \ ++ max( (sizeof(QRT_TIME_OVERFLOW) - 1), \ ++ (sizeof(QRT_STRING_OVERFLOW) - 1) ) ) ++ ++#define QRT_TOTAL_STRING_LENGTH \ ++ max( (QRT_TOTAL_STRING_POSITIVE_POWER_LENGTH + 1 /* '.' */ + 6 /*QRT_TOTAL_STRING_NEGATIVE_POWER_LENGTH*/), \ ++ max( (sizeof(QRT_TIME_OVERFLOW) - 1), \ ++ (sizeof(QRT_STRING_OVERFLOW) - 1) ) ) ++ ++extern ST_SCHEMA_TABLE query_response_time_table; ++ ++extern void query_response_time_init (); ++extern void query_response_time_free (); ++extern void query_response_time_flush (); ++extern void query_response_time_collect(ulonglong query_time); ++extern int query_response_time_fill (THD* thd, TABLE_LIST *tables, COND *cond); ++ ++#endif // QUERY_RESPONSE_TIME_H +diff -ruN a/sql/sql_parse.cc b/sql/sql_parse.cc +--- a/sql/sql_parse.cc 2010-11-03 03:01:14.000000000 +0500 ++++ b/sql/sql_parse.cc 2010-11-14 17:24:19.000000000 +0500 +@@ -91,6 +91,7 @@ + #include "sp_cache.h" + #include "events.h" + #include "sql_trigger.h" ++#include "query_response_time.h" + #include "transaction.h" + #include "sql_audit.h" + #include "sql_prepare.h" +@@ -1456,23 +1457,31 @@ + Do not log administrative statements unless the appropriate option is + set. + */ +- if (thd->enable_slow_log) ++ if (opt_enable_query_response_time_stats || thd->enable_slow_log) + { +- ulonglong end_utime_of_query= thd->current_utime(); +- thd_proc_info(thd, "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 && +- !(sql_command_flags[thd->lex->sql_command] & CF_STATUS_COMMAND))) && +- thd->examined_row_count >= thd->variables.min_examined_row_limit) ++ ulonglong end_utime_of_query = thd->current_utime(); ++ ulonglong query_execution_time = end_utime_of_query - thd->utime_after_lock; ++ if(opt_enable_query_response_time_stats) ++ { ++ query_response_time_collect(query_execution_time); ++ } ++ if (thd->enable_slow_log) + { + thd_proc_info(thd, "logging slow query"); +- thd->status_var.long_query_count++; +- slow_log_print(thd, thd->query(), thd->query_length(), +- end_utime_of_query); ++ ++ if ((query_execution_time > ++ 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 && ++ !(sql_command_flags[thd->lex->sql_command] & CF_STATUS_COMMAND))) && ++ thd->examined_row_count >= thd->variables.min_examined_row_limit) ++ { ++ thd_proc_info(thd, "logging slow query"); ++ thd->status_var.long_query_count++; ++ slow_log_print(thd, thd->query(), thd->query_length(), ++ end_utime_of_query); ++ } + } + } + DBUG_VOID_RETURN; +@@ -1591,6 +1600,7 @@ + case SCH_CHARSETS: + case SCH_ENGINES: + case SCH_COLLATIONS: ++ case SCH_QUERY_RESPONSE_TIME: + case SCH_COLLATION_CHARACTER_SET_APPLICABILITY: + case SCH_USER_PRIVILEGES: + case SCH_SCHEMA_PRIVILEGES: +diff -ruN a/sql/sql_reload.cc b/sql/sql_reload.cc +--- a/sql/sql_reload.cc 2010-11-03 03:01:14.000000000 +0500 ++++ b/sql/sql_reload.cc 2010-11-14 17:45:18.000000000 +0500 +@@ -25,7 +25,7 @@ + #include "hostname.h" // hostname_cache_refresh + #include "sql_repl.h" // reset_master, reset_slave + #include "debug_sync.h" +- ++#include "query_response_time.h" + + /** + Reload/resets privileges and the different caches. +@@ -274,6 +274,10 @@ + #endif + if (options & REFRESH_USER_RESOURCES) + reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */ ++ if (options & REFRESH_QUERY_RESPONSE_TIME) ++ { ++ query_response_time_flush(); ++ } + *write_to_binlog= tmp_write_to_binlog; + /* + If the query was killed then this function must fail. +diff -ruN a/sql/sql_show.cc b/sql/sql_show.cc +--- a/sql/sql_show.cc 2010-11-03 03:01:14.000000000 +0500 ++++ b/sql/sql_show.cc 2010-11-14 16:42:40.000000000 +0500 +@@ -49,6 +49,7 @@ + #include "event_data_objects.h" + #endif + #include ++#include "query_response_time.h" + #include "lock.h" // MYSQL_OPEN_IGNORE_FLUSH + #include "debug_sync.h" + #include "datadict.h" // dd_frm_type() +@@ -7623,6 +7624,14 @@ + + */ + ++ST_FIELD_INFO query_response_time_fields_info[] = ++ { ++ {"time", QRT_TIME_STRING_LENGTH, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE }, ++ {"count", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE }, ++ {"total", QRT_TIME_STRING_LENGTH, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE }, ++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE } ++ }; ++ + ST_SCHEMA_TABLE schema_tables[]= + { + {"CHARACTER_SETS", charsets_fields_info, create_schema_table, +@@ -7676,6 +7685,8 @@ + 1, 9, 0, OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY}, + {"ROUTINES", proc_fields_info, create_schema_table, + fill_schema_proc, make_proc_old_format, 0, -1, -1, 0, 0}, ++ {"QUERY_RESPONSE_TIME", query_response_time_fields_info, create_schema_table, ++ query_response_time_fill, make_old_format, 0, -1, -1, 0, 0}, + {"SCHEMATA", schema_fields_info, create_schema_table, + fill_schema_schemata, make_schemata_old_format, 0, 1, -1, 0, 0}, + {"SCHEMA_PRIVILEGES", schema_privileges_fields_info, create_schema_table, +diff -ruN a/sql/sql_yacc.yy b/sql/sql_yacc.yy +--- a/sql/sql_yacc.yy 2010-11-03 03:01:14.000000000 +0500 ++++ b/sql/sql_yacc.yy 2010-11-15 16:43:41.000000000 +0500 +@@ -1194,6 +1194,7 @@ + %token PURGE + %token QUARTER_SYM + %token QUERY_SYM ++%token QUERY_RESPONSE_TIME_SYM + %token QUICK + %token RANGE_SYM /* SQL-2003-R */ + %token READS_SYM /* SQL-2003-R */ +@@ -11096,6 +11097,13 @@ + { + Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT; + } ++ | QUERY_RESPONSE_TIME_SYM wild_and_where ++ { ++ LEX *lex= Lex; ++ lex->sql_command= SQLCOM_SELECT; ++ if (prepare_schema_table(YYTHD, lex, 0, SCH_QUERY_RESPONSE_TIME)) ++ MYSQL_YYABORT; ++ } + | CREATE PROCEDURE_SYM sp_name + { + LEX *lex= Lex; +@@ -11332,6 +11340,8 @@ + { Lex->type|= REFRESH_STATUS; } + | SLAVE + { Lex->type|= REFRESH_SLAVE; } ++ | QUERY_RESPONSE_TIME_SYM ++ { Lex->type|= REFRESH_QUERY_RESPONSE_TIME; } + | MASTER_SYM + { Lex->type|= REFRESH_MASTER; } + | DES_KEY_FILE +@@ -12609,6 +12619,7 @@ + | PROXY_SYM {} + | QUARTER_SYM {} + | QUERY_SYM {} ++ | QUERY_RESPONSE_TIME_SYM {} + | QUICK {} + | READ_ONLY_SYM {} + | REBUILD_SYM {} +diff -ruN a/sql/sys_vars.cc b/sql/sys_vars.cc +--- a/sql/sys_vars.cc 2010-11-13 18:11:01.000000000 +0500 ++++ b/sql/sys_vars.cc 2010-11-14 17:45:31.000000000 +0500 +@@ -49,6 +49,7 @@ + #include "../storage/perfschema/pfs_server.h" + #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ + ++#include "query_response_time.h" + /* + This forward declaration is needed because including sql_base.h + causes further includes. [TODO] Eliminate this forward declaration +@@ -1795,6 +1796,19 @@ + DEFAULT(FALSE)); + #endif /* HAVE_QUERY_CACHE */ + ++static Sys_var_mybool Sys_enable_query_response_time_stats( ++ "enable_query_response_time_stats", "Enable or disable query response time statisics collecting", ++ GLOBAL_VAR(opt_enable_query_response_time_stats), CMD_LINE(OPT_ARG), ++ DEFAULT(FALSE)); ++ ++static Sys_var_ulong Sys_query_response_time_range_base( ++ "query_response_time_range_base", ++ "Select base of log for query_response_time ranges. WARNING: variable change affect only after flush", ++ GLOBAL_VAR(opt_query_response_time_range_base), ++ CMD_LINE(REQUIRED_ARG), VALID_RANGE(2, QRT_MAXIMUM_BASE), ++ DEFAULT(QRT_DEFAULT_BASE), ++ BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES); ++ + static Sys_var_mybool Sys_secure_auth( + "secure_auth", + "Disallow authentication for accounts that have old (pre-4.1) " +diff -ruN a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result +--- a/mysql-test/r/information_schema.result 2010-11-03 03:01:12.000000000 +0500 ++++ b/mysql-test/r/information_schema.result 2010-11-16 23:03:59.000000000 +0500 +@@ -63,6 +63,7 @@ + PROFILING + REFERENTIAL_CONSTRAINTS + ROUTINES ++QUERY_RESPONSE_TIME + SCHEMATA + SCHEMA_PRIVILEGES + SESSION_STATUS +@@ -871,7 +872,7 @@ + AND table_name not like 'ndb%' AND table_name not like 'innodb_%' + GROUP BY TABLE_SCHEMA; + table_schema count(*) +-information_schema 30 ++information_schema 31 + mysql 23 + create table t1 (i int, j int); + create trigger trg1 before insert on t1 for each row +@@ -1326,6 +1327,7 @@ + PLUGINS information_schema.PLUGINS 1 + PROCESSLIST information_schema.PROCESSLIST 1 + PROFILING information_schema.PROFILING 1 ++QUERY_RESPONSE_TIME information_schema.QUERY_RESPONSE_TIME 1 + REFERENTIAL_CONSTRAINTS information_schema.REFERENTIAL_CONSTRAINTS 1 + ROUTINES information_schema.ROUTINES 1 + SCHEMATA information_schema.SCHEMATA 1 +diff -ruN a/mysql-test/r/information_schema_db.result b/mysql-test/r/information_schema_db.result +--- a/mysql-test/r/information_schema_db.result 2010-11-03 03:01:12.000000000 +0500 ++++ b/mysql-test/r/information_schema_db.result 2010-11-16 23:06:36.000000000 +0500 +@@ -23,6 +23,7 @@ + PROFILING + REFERENTIAL_CONSTRAINTS + ROUTINES ++QUERY_RESPONSE_TIME + SCHEMATA + SCHEMA_PRIVILEGES + SESSION_STATUS +diff -ruN a/mysql-test/r/mysqld--help-notwin.result b/mysql-test/r/mysqld--help-notwin.result +--- a/mysql-test/r/mysqld--help-notwin.result 2010-11-03 03:01:12.000000000 +0500 ++++ b/mysql-test/r/mysqld--help-notwin.result 2010-11-17 00:15:40.000000000 +0500 +@@ -124,6 +124,9 @@ + --div-precision-increment=# + Precision of the result of '/' operator will be increased + on that value ++ --enable-query-response-time-stats ++ Enable or disable query response time statisics ++ collecting + --engine-condition-pushdown + Push supported query conditions to the storage engine. + Deprecated, use --optimizer-switch instead. +@@ -463,6 +466,10 @@ + The minimum size for blocks allocated by the query cache + --query-cache-size=# + The memory allocated to store results from old queries ++ --query-cache-strip-comments ++ Enable and disable optimisation "strip comment for query ++ cache" - optimisation strip all comments from query while ++ search query result in query cache + --query-cache-type=name + OFF = Don't cache or retrieve results. ON = Cache all + results except SELECT SQL_NO_CACHE ... queries. DEMAND = +@@ -471,6 +478,9 @@ + Invalidate queries in query cache on LOCK for write + --query-prealloc-size=# + Persistent buffer for query parsing and execution ++ --query-response-time-range-base=# ++ Select base of log for query_response_time ranges. ++ WARNING: variable change affect only after flush + --range-alloc-block-size=# + Allocation block size for storing ranges during + optimization +@@ -758,6 +768,7 @@ + delayed-queue-size 1000 + disconnect-slave-event-count 0 + div-precision-increment 4 ++enable-query-response-time-stats FALSE + engine-condition-pushdown TRUE + event-scheduler OFF + expire-logs-days 0 +@@ -879,9 +890,11 @@ + query-cache-limit 1048576 + query-cache-min-res-unit 4096 + query-cache-size 0 ++query-cache-strip-comments FALSE + query-cache-type ON + query-cache-wlock-invalidate FALSE + query-prealloc-size 8192 ++query-response-time-range-base 10 + range-alloc-block-size 4096 + read-buffer-size 131072 + read-only FALSE +diff -ruN a/mysql-test/suite/sys_vars/r/all_vars.result b/mysql-test/suite/sys_vars/r/all_vars.result +--- a/mysql-test/suite/sys_vars/r/all_vars.result 2010-11-03 01:01:13.000000000 +0300 ++++ b/mysql-test/suite/sys_vars/r/all_vars.result 2010-11-23 20:04:40.000000000 +0300 +@@ -10,11 +10,15 @@ + select variable_name as `There should be *no* variables listed below:` from t2 + left join t1 on variable_name=test_name where test_name is null; + There should be *no* variables listed below: ++ENABLE_QUERY_RESPONSE_TIME_STATS + QUERY_CACHE_STRIP_COMMENTS + SUPPRESS_LOG_WARNING_1592 + INNODB_FILE_FORMAT_MAX ++QUERY_RESPONSE_TIME_RANGE_BASE ++ENABLE_QUERY_RESPONSE_TIME_STATS + QUERY_CACHE_STRIP_COMMENTS + SUPPRESS_LOG_WARNING_1592 + INNODB_FILE_FORMAT_MAX ++QUERY_RESPONSE_TIME_RANGE_BASE + drop table t1; + drop table t2; +diff -ruN a/mysql-test/r/mysqlshow.result b/mysql-test/r/mysqlshow.result +--- a/mysql-test/r/mysqlshow.result 2010-11-03 01:01:12.000000000 +0300 ++++ b/mysql-test/r/mysqlshow.result 2010-11-23 20:07:53.000000000 +0300 +@@ -97,6 +97,7 @@ + | PROFILING | + | REFERENTIAL_CONSTRAINTS | + | ROUTINES | ++| QUERY_RESPONSE_TIME | + | SCHEMATA | + | SCHEMA_PRIVILEGES | + | SESSION_STATUS | +@@ -139,6 +140,7 @@ + | PROFILING | + | REFERENTIAL_CONSTRAINTS | + | ROUTINES | ++| QUERY_RESPONSE_TIME | + | SCHEMATA | + | SCHEMA_PRIVILEGES | + | SESSION_STATUS | diff --git a/series b/series index 47577a927b78..4c97e548f6e1 100644 --- a/series +++ b/series @@ -31,3 +31,14 @@ innodb_deadlock_count.patch innodb_adaptive_hash_index_num.patch innodb_buffer_pool_pages_i_s.patch innodb_buffer_pool_shm.patch +ce.patch +slow_extended.patch +suppress_log_warning_1592.patch +percona_support.patch +query_cache_enhance.patch +log_connection_error.patch +mysql_syslog.patch +response_time_distribution.patch +error_pad.patch +remove_fcntl_excessive_calls.patch +sql_no_fcache.patch diff --git a/show_patches.patch b/show_patches.patch index 5aa57e21cda9..1b1a9af31868 100644 --- a/show_patches.patch +++ b/show_patches.patch @@ -15,6 +15,23 @@ diff -ruN a/patch_info/show_patches.info b/patch_info/show_patches.info +Author=Jeremy Cole +License=N/A +Comment= +diff -ruN b/sql/CMakeLists.txt Percona-Server/sql/CMakeLists.txt +--- b/sql/CMakeLists.txt 2010-12-09 19:59:13.000000000 +0300 ++++ Percona-Server/sql/CMakeLists.txt 2010-12-09 19:55:37.000000000 +0300 +@@ -27,9 +27,13 @@ + ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.cc + ${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc + ${CMAKE_CURRENT_BINARY_DIR}/lex_hash.h ++${CMAKE_CURRENT_BINARY_DIR}/patch_info.h + ) + + SET_SOURCE_FILES_PROPERTIES(${GEN_SOURCES} PROPERTIES GENERATED 1) ++ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/patch_info.h ++ COMMAND perl < ${CMAKE_CURRENT_SOURCE_DIR}/patch_info.h.pl > ${CMAKE_CURRENT_BINARY_DIR}/patch_info.h ++ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + ADD_DEFINITIONS(-DMYSQL_SERVER -DHAVE_EVENT_SCHEDULER) + IF(SSL_DEFINES) diff -ruN a/sql/Makefile.am b/sql/Makefile.am --- a/sql/Makefile.am 2010-11-03 07:01:14.000000000 +0900 +++ b/sql/Makefile.am 2010-11-17 12:19:49.947459151 +0900 diff --git a/show_slave_status_nolock.patch b/show_slave_status_nolock.patch new file mode 100644 index 000000000000..110e4670ebbe --- /dev/null +++ b/show_slave_status_nolock.patch @@ -0,0 +1,98 @@ +diff -ruN a/patch_info/show_slave_status_nolock.patch b/patch_info/show_slave_status_nolock.patch +--- a/patch_info/show_slave_status_nolock.patch 1970-01-01 05:00:00.000000000 +0500 ++++ b/patch_info/show_slave_status_nolock.patch 2010-10-29 14:44:13.000000000 +0600 +@@ -0,0 +1,6 @@ ++File=show_slave_status_nolock.patch ++Name= SHOW SLAVE STATUS NOLOCK ++Version=1.0 ++Author=Percona ++License=GPL ++Comment= Implement SHOW SLAVE STATUS without lock (STOP SLAVE lock the same mutex what lock SHOW SLAVE STATUS) +diff -ruN a/sql/lex.h b/sql/lex.h +--- a/sql/lex.h 2010-10-29 14:39:13.000000000 +0600 ++++ b/sql/lex.h 2010-10-29 14:41:48.000000000 +0600 +@@ -367,6 +367,7 @@ + { "NONE", SYM(NONE_SYM)}, + { "NOT", SYM(NOT_SYM)}, + { "NO_WRITE_TO_BINLOG", SYM(NO_WRITE_TO_BINLOG)}, ++ { "NOLOCK", SYM(NOLOCK_SYM)}, + { "NULL", SYM(NULL_SYM)}, + { "NUMERIC", SYM(NUMERIC_SYM)}, + { "NVARCHAR", SYM(NVARCHAR_SYM)}, +diff -ruN a/sql/sql_lex.h b/sql/sql_lex.h +--- a/sql/sql_lex.h 2010-10-29 14:39:13.000000000 +0600 ++++ b/sql/sql_lex.h 2010-10-29 14:41:56.000000000 +0600 +@@ -119,7 +119,8 @@ + SQLCOM_ALTER_DB_UPGRADE, SQLCOM_SHOW_TEMPORARY_TABLES, + SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES, + SQLCOM_SHOW_PATCHES, +- ++ /* SHOW SLAVE STATUS NOLOCK */ ++ SQLCOM_SHOW_SLAVE_NOLOCK_STAT, + /* + When a command is added here, be sure it's also added in mysqld.cc + in "struct show_var_st status_vars[]= {" ... +diff -ruN a/sql/sql_parse.cc b/sql/sql_parse.cc +--- a/sql/sql_parse.cc 2010-10-29 14:39:13.000000000 +0600 ++++ b/sql/sql_parse.cc 2010-10-29 14:42:03.000000000 +0600 +@@ -326,6 +326,7 @@ + sql_command_flags[SQLCOM_SHOW_CREATE]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_MASTER_STAT]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_SLAVE_STAT]= CF_STATUS_COMMAND; ++ sql_command_flags[SQLCOM_SHOW_SLAVE_NOLOCK_STAT]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_CREATE_PROC]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_CREATE_FUNC]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_CREATE_TRIGGER]= CF_STATUS_COMMAND; +@@ -2538,12 +2539,16 @@ + pthread_mutex_unlock(&LOCK_active_mi); + break; + } ++ case SQLCOM_SHOW_SLAVE_NOLOCK_STAT: + case SQLCOM_SHOW_SLAVE_STAT: + { + /* Accept one of two privileges */ + if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) + goto error; +- pthread_mutex_lock(&LOCK_active_mi); ++ if(SQLCOM_SHOW_SLAVE_NOLOCK_STAT != lex->sql_command) ++ { ++ pthread_mutex_lock(&LOCK_active_mi); ++ } + if (active_mi != NULL) + { + res = show_master_info(thd, active_mi); +@@ -2554,7 +2559,10 @@ + WARN_NO_MASTER_INFO, ER(WARN_NO_MASTER_INFO)); + my_ok(thd); + } +- pthread_mutex_unlock(&LOCK_active_mi); ++ if(SQLCOM_SHOW_SLAVE_NOLOCK_STAT != lex->sql_command) ++ { ++ pthread_mutex_unlock(&LOCK_active_mi); ++ } + break; + } + case SQLCOM_SHOW_MASTER_STAT: +diff -ruN a/sql/sql_yacc.yy b/sql/sql_yacc.yy +--- a/sql/sql_yacc.yy 2010-10-29 14:39:13.000000000 +0600 ++++ b/sql/sql_yacc.yy 2010-10-29 14:41:39.000000000 +0600 +@@ -1173,6 +1173,7 @@ + %token STARTS_SYM + %token START_SYM /* SQL-2003-R */ + %token STATUS_SYM ++%token NOLOCK_SYM /* SHOW SLAVE STATUS NOLOCK */ + %token STDDEV_SAMP_SYM /* SQL-2003-N */ + %token STD_SYM + %token STOP_SYM +@@ -10367,6 +10368,11 @@ + { + Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT; + } ++ /* SHOW SLAVE STATUS NOLOCK */ ++ | SLAVE STATUS_SYM NOLOCK_SYM ++ { ++ Lex->sql_command = SQLCOM_SHOW_SLAVE_NOLOCK_STAT; //SQLCOM_SHOW_SLAVE_NOLOCK_STAT; ++ } + | CLIENT_STATS_SYM wild_and_where + { + LEX *lex= Lex; diff --git a/show_temp_51.patch b/show_temp_51.patch new file mode 100644 index 000000000000..f64f6abd16a7 --- /dev/null +++ b/show_temp_51.patch @@ -0,0 +1,393 @@ +# name : show_temp_51.patch +# introduced : 11 or before +# maintainer : Yasufumi +# +#!!! notice !!! +# Any small change to this file in the main branch +# should be done or reviewed by the maintainer! +diff -ruN a/sql/mysqld.cc b/sql/mysqld.cc +--- a/sql/mysqld.cc 2010-08-27 15:24:41.663411604 +0900 ++++ b/sql/mysqld.cc 2010-08-27 15:30:36.942106886 +0900 +@@ -3233,6 +3233,7 @@ + {"show_table_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLE_STATUS]), SHOW_LONG_STATUS}, + {"show_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLES]), SHOW_LONG_STATUS}, + {"show_thread_statistics",(char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_THREAD_STATS]), SHOW_LONG_STATUS}, ++ {"show_temporary_tables",(char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TEMPORARY_TABLES]), SHOW_LONG_STATUS}, + {"show_triggers", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TRIGGERS]), SHOW_LONG_STATUS}, + {"show_user_statistics", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_USER_STATS]), SHOW_LONG_STATUS}, + {"show_variables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_VARIABLES]), SHOW_LONG_STATUS}, +diff -ruN a/sql/sql_lex.h b/sql/sql_lex.h +--- a/sql/sql_lex.h 2010-08-27 15:19:09.940989847 +0900 ++++ b/sql/sql_lex.h 2010-08-27 15:30:36.942106886 +0900 +@@ -116,7 +116,7 @@ + SQLCOM_CREATE_EVENT, SQLCOM_ALTER_EVENT, SQLCOM_DROP_EVENT, + SQLCOM_SHOW_CREATE_EVENT, SQLCOM_SHOW_EVENTS, + SQLCOM_SHOW_CREATE_TRIGGER, +- SQLCOM_ALTER_DB_UPGRADE, ++ SQLCOM_ALTER_DB_UPGRADE, SQLCOM_SHOW_TEMPORARY_TABLES, + SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES, + SQLCOM_SHOW_PATCHES, + +diff -ruN a/sql/sql_parse.cc b/sql/sql_parse.cc +--- a/sql/sql_parse.cc 2010-08-27 15:19:09.944990047 +0900 ++++ b/sql/sql_parse.cc 2010-08-27 15:30:36.949020748 +0900 +@@ -338,6 +338,9 @@ + sql_command_flags[SQLCOM_SHOW_TABLES]= (CF_STATUS_COMMAND | + CF_SHOW_TABLE_COMMAND | + CF_REEXECUTION_FRAGILE); ++ sql_command_flags[SQLCOM_SHOW_TEMPORARY_TABLES]= (CF_STATUS_COMMAND | ++ CF_SHOW_TABLE_COMMAND | ++ CF_REEXECUTION_FRAGILE); + sql_command_flags[SQLCOM_SHOW_TABLE_STATUS]= (CF_STATUS_COMMAND | + CF_SHOW_TABLE_COMMAND | + CF_REEXECUTION_FRAGILE); +@@ -1818,6 +1821,8 @@ + + case SCH_TABLE_NAMES: + case SCH_TABLES: ++ case SCH_TEMPORARY_TABLES: ++ case SCH_GLOBAL_TEMPORARY_TABLES: + case SCH_VIEWS: + case SCH_TRIGGERS: + case SCH_EVENTS: +@@ -2316,6 +2321,7 @@ + } + case SQLCOM_SHOW_DATABASES: + case SQLCOM_SHOW_TABLES: ++ case SQLCOM_SHOW_TEMPORARY_TABLES: + case SQLCOM_SHOW_TRIGGERS: + case SQLCOM_SHOW_TABLE_STATUS: + case SQLCOM_SHOW_OPEN_TABLES: +@@ -5440,6 +5446,8 @@ + + case SCH_TABLE_NAMES: + case SCH_TABLES: ++ case SCH_TEMPORARY_TABLES: ++ case SCH_GLOBAL_TEMPORARY_TABLES: + case SCH_VIEWS: + case SCH_TRIGGERS: + case SCH_EVENTS: +diff -ruN a/sql/sql_show.cc b/sql/sql_show.cc +--- a/sql/sql_show.cc 2010-08-27 15:19:09.955989654 +0900 ++++ b/sql/sql_show.cc 2010-08-27 15:30:36.959020753 +0900 +@@ -3038,6 +3038,7 @@ + break; + case SQLCOM_SHOW_TABLES: + case SQLCOM_SHOW_TABLE_STATUS: ++ case SQLCOM_SHOW_TEMPORARY_TABLES: + case SQLCOM_SHOW_TRIGGERS: + case SQLCOM_SHOW_EVENTS: + thd->make_lex_string(&lookup_field_values->db_value, +@@ -3514,6 +3515,228 @@ + return (uint) OPEN_FULL_TABLE; + } + ++/** ++ @brief Change I_S table item list for SHOW [GLOBAL] TEMPORARY TABLES [FROM/IN db] ++ ++ @param[in] thd thread handler ++ @param[in] schema_table I_S table ++ ++ @return Operation status ++ @retval 0 success ++ @retval 1 error ++*/ ++int make_temporary_tables_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) ++{ ++ char tmp[128]; ++ String buffer(tmp,sizeof(tmp), thd->charset()); ++ LEX *lex= thd->lex; ++ Name_resolution_context *context= &lex->select_lex.context; ++ ++ if (thd->lex->option_type == OPT_GLOBAL) { ++ ST_FIELD_INFO *field_info= &schema_table->fields_info[0]; ++ Item_field *field= new Item_field(context, NullS, NullS, field_info->field_name); ++ if (add_item_to_list(thd, field)) ++ return 1; ++ field->set_name(field_info->old_name, strlen(field_info->old_name), system_charset_info); ++ } ++ ++ ST_FIELD_INFO *field_info= &schema_table->fields_info[2]; ++ buffer.length(0); ++ buffer.append(field_info->old_name); ++ buffer.append(lex->select_lex.db); ++ ++ if (lex->wild && lex->wild->ptr()) ++ { ++ buffer.append(STRING_WITH_LEN(" (")); ++ buffer.append(lex->wild->ptr()); ++ buffer.append(')'); ++ } ++ ++ Item_field *field= new Item_field(context, NullS, NullS, field_info->field_name); ++ if (add_item_to_list(thd, field)) ++ return 1; ++ ++ field->set_name(buffer.ptr(), buffer.length(), system_charset_info); ++ return 0; ++} ++ ++/** ++ @brief Fill records for temporary tables by reading info from table object ++ ++ @param[in] thd thread handler ++ @param[in] table I_S table ++ @param[in] tmp_table temporary table ++ @param[in] db database name ++ ++ @return Operation status ++ @retval 0 success ++ @retval 1 error ++*/ ++ ++static int store_temporary_table_record(THD *thd, TABLE *table, TABLE *tmp_table, const char *db, bool table_name_only) ++{ ++ CHARSET_INFO *cs= system_charset_info; ++ DBUG_ENTER("store_temporary_table_record"); ++ ++ if (db && my_strcasecmp(cs, db, tmp_table->s->db.str)) ++ DBUG_RETURN(0); ++ ++ restore_record(table, s->default_values); ++ ++ //session_id ++ table->field[0]->store((longlong) thd->thread_id, TRUE); ++ ++ //database ++ table->field[1]->store(tmp_table->s->db.str, tmp_table->s->db.length, cs); ++ ++ //table ++ table->field[2]->store(tmp_table->s->table_name.str, tmp_table->s->table_name.length, cs); ++ ++ if (table_name_only) ++ DBUG_RETURN(schema_table_store_record(thd, table)); ++ ++ //engine ++ handler *handle= tmp_table->file; ++ char *engineType = (char *)(handle ? handle->table_type() : "UNKNOWN"); ++ table->field[3]->store(engineType, strlen(engineType), cs); ++ ++ //name ++ if (tmp_table->s->path.str) { ++ char *p=strstr(tmp_table->s->path.str, "#sql"); ++ int len=tmp_table->s->path.length-(p-tmp_table->s->path.str); ++ table->field[4]->store(p, min(FN_REFLEN, len), cs); ++ } ++ ++ // file stats ++ handler *file= tmp_table->file; ++ ++ if (file) { ++ ++ MYSQL_TIME time; ++ ++ /** ++ TODO: InnoDB stat(file) checks file on short names within data dictionary ++ rather than using full path, because of that, temp files created in ++ TMPDIR will not have access/create time as it will not find the file ++ ++ The fix is to patch InnoDB to use full path ++ */ ++ file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK); ++ ++ table->field[5]->store((longlong) file->stats.records, TRUE); ++ table->field[5]->set_notnull(); ++ ++ table->field[6]->store((longlong) file->stats.mean_rec_length, TRUE); ++ table->field[7]->store((longlong) file->stats.data_file_length, TRUE); ++ table->field[8]->store((longlong) file->stats.index_file_length, TRUE); ++ if (file->stats.create_time) ++ { ++ thd->variables.time_zone->gmt_sec_to_TIME(&time, ++ (my_time_t) file->stats.create_time); ++ table->field[9]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); ++ table->field[9]->set_notnull(); ++ } ++ if (file->stats.update_time) ++ { ++ thd->variables.time_zone->gmt_sec_to_TIME(&time, ++ (my_time_t) file->stats.update_time); ++ table->field[10]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); ++ table->field[10]->set_notnull(); ++ } ++ } ++ ++ DBUG_RETURN(schema_table_store_record(thd, table)); ++} ++ ++/** ++ @brief Fill I_S tables with global temporary tables ++ ++ @param[in] thd thread handler ++ @param[in] tables I_S table ++ @param[in] cond 'WHERE' condition ++ ++ @return Operation status ++ @retval 0 success ++ @retval 1 error ++*/ ++ ++static int fill_global_temporary_tables(THD *thd, TABLE_LIST *tables, COND *cond) ++{ ++ DBUG_ENTER("fill_global_temporary_tables"); ++ ++ pthread_mutex_lock(&LOCK_thread_count); ++ ++ bool table_names_only= (thd->lex->sql_command == SQLCOM_SHOW_TEMPORARY_TABLES) ? 1 : 0; ++ I_List_iterator it(threads); ++ THD *thd_item; ++ TABLE *tmp; ++ ++#ifndef NO_EMBEDDED_ACCESS_CHECKS ++ Security_context *sctx= thd->security_ctx; ++ uint db_access; ++#endif ++ ++ while ((thd_item=it++)) { ++ for (tmp=thd_item->temporary_tables; tmp; tmp=tmp->next) { ++ ++#ifndef NO_EMBEDDED_ACCESS_CHECKS ++ if (test_all_bits(sctx->master_access, DB_ACLS)) ++ db_access=DB_ACLS; ++ else ++ db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, tmp->s->db.str, 0) | sctx->master_access); ++ ++ if (!(db_access & DB_ACLS) && check_grant_db(thd,tmp->s->db.str)) { ++ //no access for temp tables within this db for user ++ continue; ++ } ++#endif ++ ++ THD *t= tmp->in_use; ++ tmp->in_use= thd; ++ ++ if (store_temporary_table_record(thd_item, tables->table, tmp, thd->lex->select_lex.db, table_names_only)) { ++ tmp->in_use= t; ++ pthread_mutex_unlock(&LOCK_thread_count); ++ DBUG_RETURN(1); ++ } ++ ++ tmp->in_use= t; ++ } ++ } ++ ++ pthread_mutex_unlock(&LOCK_thread_count); ++ DBUG_RETURN(0); ++} ++ ++/** ++ @brief Fill I_S tables with session temporary tables ++ ++ @param[in] thd thread handler ++ @param[in] tables I_S table ++ @param[in] cond 'WHERE' condition ++ ++ @return Operation status ++ @retval 0 success ++ @retval 1 error ++*/ ++ ++int fill_temporary_tables(THD *thd, TABLE_LIST *tables, COND *cond) ++{ ++ DBUG_ENTER("fill_temporary_tables"); ++ ++ if (thd->lex->option_type == OPT_GLOBAL) ++ DBUG_RETURN(fill_global_temporary_tables(thd, tables, cond)); ++ ++ bool table_names_only= (thd->lex->sql_command == SQLCOM_SHOW_TEMPORARY_TABLES) ? 1 : 0; ++ TABLE *tmp; ++ ++ for (tmp=thd->temporary_tables; tmp; tmp=tmp->next) { ++ if (store_temporary_table_record(thd, tables->table, tmp, thd->lex->select_lex.db, table_names_only)) { ++ DBUG_RETURN(1); ++ } ++ } ++ DBUG_RETURN(0); ++} + + /** + @brief Fill I_S table with data from FRM file only +@@ -6595,6 +6818,25 @@ + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} + }; + ++ST_FIELD_INFO temporary_table_fields_info[]= ++{ ++ {"SESSION_ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Session", SKIP_OPEN_TABLE}, ++ {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Db", SKIP_OPEN_TABLE}, ++ {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Temp_tables_in_", SKIP_OPEN_TABLE}, ++ {"ENGINE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Engine", OPEN_FRM_ONLY}, ++ {"NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, "Name", SKIP_OPEN_TABLE}, ++ {"TABLE_ROWS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, ++ MY_I_S_UNSIGNED, "Rows", OPEN_FULL_TABLE}, ++ {"AVG_ROW_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, ++ MY_I_S_UNSIGNED, "Avg Row", OPEN_FULL_TABLE}, ++ {"DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, ++ MY_I_S_UNSIGNED, "Data Length", OPEN_FULL_TABLE}, ++ {"INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, ++ MY_I_S_UNSIGNED, "Index Size", OPEN_FULL_TABLE}, ++ {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Create Time", OPEN_FULL_TABLE}, ++ {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Update Time", OPEN_FULL_TABLE}, ++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} ++}; + + ST_FIELD_INFO columns_fields_info[]= + { +@@ -7255,6 +7497,9 @@ + fill_schema_files, 0, 0, -1, -1, 0, 0}, + {"GLOBAL_STATUS", variables_fields_info, create_schema_table, + fill_status, make_old_format, 0, 0, -1, 0, 0}, ++ {"GLOBAL_TEMPORARY_TABLES", temporary_table_fields_info, create_schema_table, ++ fill_global_temporary_tables, make_temporary_tables_old_format, 0, 2, 3, 0, ++ OPEN_TABLE_ONLY|OPTIMIZE_I_S_TABLE}, + {"GLOBAL_VARIABLES", variables_fields_info, create_schema_table, + fill_variables, make_old_format, 0, 0, -1, 0, 0}, + {"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table, +@@ -7298,6 +7543,9 @@ + get_all_tables, make_table_names_old_format, 0, 1, 2, 1, 0}, + {"TABLE_PRIVILEGES", table_privileges_fields_info, create_schema_table, + fill_schema_table_privileges, 0, 0, -1, -1, 0, 0}, ++ {"TEMPORARY_TABLES", temporary_table_fields_info, create_schema_table, ++ fill_temporary_tables, make_temporary_tables_old_format, 0, 2, 3, 0, ++ OPEN_TABLE_ONLY|OPTIMIZE_I_S_TABLE}, + {"TABLE_STATISTICS", table_stats_fields_info, create_schema_table, + fill_schema_table_stats, make_old_format, 0, -1, -1, 0, 0}, + {"THREAD_STATISTICS", thread_stats_fields_info, create_schema_table, +diff -ruN a/sql/sql_yacc.yy b/sql/sql_yacc.yy +--- a/sql/sql_yacc.yy 2010-08-27 15:19:09.976059692 +0900 ++++ b/sql/sql_yacc.yy 2010-08-27 15:30:36.971993050 +0900 +@@ -10096,6 +10096,15 @@ + if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLE_NAMES)) + MYSQL_YYABORT; + } ++ | opt_var_type TEMPORARY TABLES opt_db ++ { ++ LEX *lex= Lex; ++ lex->sql_command= SQLCOM_SHOW_TEMPORARY_TABLES; ++ lex->option_type= $1; ++ lex->select_lex.db= $4; ++ if (prepare_schema_table(YYTHD, lex, 0, SCH_TEMPORARY_TABLES)) ++ MYSQL_YYABORT; ++ } + | opt_full TRIGGERS_SYM opt_db wild_and_where + { + LEX *lex= Lex; +diff -ruN a/sql/table.h b/sql/table.h +--- a/sql/table.h 2010-08-27 15:19:09.988989663 +0900 ++++ b/sql/table.h 2010-08-27 15:30:36.987021191 +0900 +@@ -953,6 +953,7 @@ + SCH_EVENTS, + SCH_FILES, + SCH_GLOBAL_STATUS, ++ SCH_GLOBAL_TEMPORARY_TABLES, + SCH_GLOBAL_VARIABLES, + SCH_KEY_COLUMN_USAGE, + SCH_OPEN_TABLES, +@@ -972,6 +973,7 @@ + SCH_TABLE_CONSTRAINTS, + SCH_TABLE_NAMES, + SCH_TABLE_PRIVILEGES, ++ SCH_TEMPORARY_TABLES, + SCH_TABLE_STATS, + SCH_THREAD_STATS, + SCH_TRIGGERS, diff --git a/slow_extended.patch b/slow_extended.patch new file mode 100644 index 000000000000..a4039a59893e --- /dev/null +++ b/slow_extended.patch @@ -0,0 +1,1055 @@ +# name : slow_extended.patch +# introduced : 11 or before +# maintainer : Oleg +# +#!!! notice !!! +# Any small change to this file in the main branch +# should be done or reviewed by the maintainer! +diff -ruN a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp +--- a/include/mysql/plugin_audit.h.pp 2010-11-03 01:01:11.000000000 +0300 ++++ b/include/mysql/plugin_audit.h.pp 2010-11-28 17:38:42.000000000 +0300 +@@ -178,6 +178,16 @@ + char *thd_security_context(void* thd, char *buffer, unsigned int length, + unsigned int max_query_len); + void thd_inc_row_count(void* thd); ++void increment_thd_innodb_stats(void* thd, ++ unsigned long long trx_id, ++ long io_reads, ++ long long io_read, ++ long io_reads_wait_timer, ++ long lock_que_wait_timer, ++ long que_wait_timer, ++ long page_access); ++unsigned long thd_log_slow_verbosity(const void* thd); ++int thd_opt_slow_log(); + int mysql_tmpfile(const char *prefix); + int thd_killed(const void* thd); + unsigned long thd_get_thread_id(const void* thd); +diff -ruN a/include/mysql/plugin_auth.h.pp b/include/mysql/plugin_auth.h.pp +--- a/include/mysql/plugin_auth.h.pp 2010-11-03 01:01:11.000000000 +0300 ++++ b/include/mysql/plugin_auth.h.pp 2010-11-28 17:38:42.000000000 +0300 +@@ -178,6 +178,16 @@ + char *thd_security_context(void* thd, char *buffer, unsigned int length, + unsigned int max_query_len); + void thd_inc_row_count(void* thd); ++void increment_thd_innodb_stats(void* thd, ++ unsigned long long trx_id, ++ long io_reads, ++ long long io_read, ++ long io_reads_wait_timer, ++ long lock_que_wait_timer, ++ long que_wait_timer, ++ long page_access); ++unsigned long thd_log_slow_verbosity(const void* thd); ++int thd_opt_slow_log(); + int mysql_tmpfile(const char *prefix); + int thd_killed(const void* thd); + unsigned long thd_get_thread_id(const void* thd); +diff -ruN a/include/mysql/plugin_ftparser.h.pp b/include/mysql/plugin_ftparser.h.pp +--- a/include/mysql/plugin_ftparser.h.pp 2010-11-03 01:01:11.000000000 +0300 ++++ b/include/mysql/plugin_ftparser.h.pp 2010-11-28 17:38:42.000000000 +0300 +@@ -131,6 +131,16 @@ + char *thd_security_context(void* thd, char *buffer, unsigned int length, + unsigned int max_query_len); + void thd_inc_row_count(void* thd); ++void increment_thd_innodb_stats(void* thd, ++ unsigned long long trx_id, ++ long io_reads, ++ long long io_read, ++ long io_reads_wait_timer, ++ long lock_que_wait_timer, ++ long que_wait_timer, ++ long page_access); ++unsigned long thd_log_slow_verbosity(const void* thd); ++int thd_opt_slow_log(); + int mysql_tmpfile(const char *prefix); + int thd_killed(const void* thd); + unsigned long thd_get_thread_id(const void* thd); +diff -ruN a/include/mysql/plugin.h b/include/mysql/plugin.h +--- a/include/mysql/plugin.h 2010-11-03 01:01:11.000000000 +0300 ++++ b/include/mysql/plugin.h 2010-11-28 17:38:42.000000000 +0300 +@@ -536,6 +536,17 @@ + /* Increments the row counter, see THD::row_count */ + void thd_inc_row_count(MYSQL_THD thd); + ++void increment_thd_innodb_stats(MYSQL_THD thd, ++ unsigned long long trx_id, ++ long io_reads, ++ long long io_read, ++ long io_reads_wait_timer, ++ long lock_que_wait_timer, ++ long que_wait_timer, ++ long page_access); ++unsigned long thd_log_slow_verbosity(const MYSQL_THD thd); ++int thd_opt_slow_log(); ++#define EXTENDED_SLOWLOG + /** + Create a temporary file. + +diff -ruN a/patch_info/slow_extended.info b/patch_info/slow_extended.info +--- a/patch_info/slow_extended.info 1970-01-01 03:00:00.000000000 +0300 ++++ b/patch_info/slow_extended.info 2010-11-28 17:38:42.000000000 +0300 +@@ -0,0 +1,24 @@ ++File=slow_extended.patch ++Name=Extended statistics in slow.log (not InnoDB part) ++Version=1.3 ++Author=Percona ++License=GPL ++Comment= ++Changelog ++2008-11-26 ++YK: Fix inefficient determination of trx, Make not to call useless gettimeofday when don't use slow log. Make log_slow_queries dynamic (bool). ++ ++2008-11-07 ++VT: Moved log_slow_rate_limit in SHOW VARIABLE into right place ++ ++2008-11 ++Arjen Lentz: Fixups (backward compatibility) by Arjen Lentz ++ ++2010-07 ++1) Fix overflow of query time and lock time (Bug 600360) (slow_extended_fix_overflow.patch merged) ++2) Control global slow feature merged (control_global_slow.patch merged) ++3) Microseconds in slow query log merged (microseconds_in_slow_query_log.patch merged) ++4) Now use_global_long_query_time and use_global_log_slow_control are synonims. Add value "all" for use_global_log_slow_control (contol-global_slow-2.patch merged) ++5) Fix innodb_stats on replication (Bug 600684) ++6) Change variable types (system/command-line) ++ +diff -ruN a/scripts/mysqldumpslow.sh b/scripts/mysqldumpslow.sh +--- a/scripts/mysqldumpslow.sh 2010-11-03 01:01:13.000000000 +0300 ++++ b/scripts/mysqldumpslow.sh 2010-11-28 17:38:42.000000000 +0300 +@@ -83,8 +83,8 @@ + s/^#? Time: \d{6}\s+\d+:\d+:\d+.*\n//; + my ($user,$host) = s/^#? User\@Host:\s+(\S+)\s+\@\s+(\S+).*\n// ? ($1,$2) : ('',''); + +- s/^# Query_time: ([0-9.]+)\s+Lock_time: ([0-9.]+)\s+Rows_sent: ([0-9.]+).*\n//; +- my ($t, $l, $r) = ($1, $2, $3); ++ s/^# Query_time: (\d+(\.\d+)?) Lock_time: (\d+(\.\d+)?) Rows_sent: (\d+(\.\d+)?).*\n//; ++ my ($t, $l, $r) = ($1, $3, $5); + $t -= $l unless $opt{l}; + + # remove fluff that mysqld writes to log when it (re)starts: +diff -ruN a/sql/event_scheduler.cc b/sql/event_scheduler.cc +--- a/sql/event_scheduler.cc 2010-11-03 01:01:14.000000000 +0300 ++++ b/sql/event_scheduler.cc 2010-11-28 17:38:42.000000000 +0300 +@@ -195,6 +195,7 @@ + thd->client_capabilities|= CLIENT_MULTI_RESULTS; + mysql_mutex_lock(&LOCK_thread_count); + thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; ++ thd->write_to_slow_log = TRUE; + mysql_mutex_unlock(&LOCK_thread_count); + + /* +diff -ruN a/sql/filesort.cc b/sql/filesort.cc +--- a/sql/filesort.cc 2010-11-03 01:01:14.000000000 +0300 ++++ b/sql/filesort.cc 2010-11-28 17:38:42.000000000 +0300 +@@ -197,6 +197,7 @@ + { + status_var_increment(thd->status_var.filesort_scan_count); + } ++ thd->query_plan_flags|= QPLAN_FILESORT; + #ifdef CAN_TRUST_RANGE + if (select && select->quick && select->quick->records > 0L) + { +@@ -262,6 +263,7 @@ + } + else + { ++ thd->query_plan_flags|= QPLAN_FILESORT_DISK; + if (table_sort.buffpek && table_sort.buffpek_len < maxbuffer) + { + my_free(table_sort.buffpek); +@@ -1201,6 +1203,7 @@ + DBUG_ENTER("merge_buffers"); + + status_var_increment(current_thd->status_var.filesort_merge_passes); ++ current_thd->query_plan_fsort_passes++; + if (param->not_killable) + { + killed= ¬_killable; +diff -ruN a/sql/log.cc b/sql/log.cc +--- a/sql/log.cc 2010-11-03 01:01:14.000000000 +0300 ++++ b/sql/log.cc 2010-11-28 17:38:42.000000000 +0300 +@@ -630,11 +630,13 @@ + */ + + bool Log_to_csv_event_handler:: +- log_slow(THD *thd, time_t current_time, time_t query_start_arg, ++ log_slow(THD *thd, ulonglong current_utime, time_t query_start_arg, + const char *user_host, uint user_host_len, + ulonglong query_utime, ulonglong lock_utime, bool is_command, + const char *sql_text, uint sql_text_len) + { ++ time_t current_time= my_time_possible_from_micro(current_utime); ++ + TABLE_LIST table_list; + TABLE *table; + bool result= TRUE; +@@ -850,14 +852,14 @@ + /** Wrapper around MYSQL_LOG::write() for slow log. */ + + bool Log_to_file_event_handler:: +- log_slow(THD *thd, time_t current_time, time_t query_start_arg, ++ log_slow(THD *thd, ulonglong current_utime, time_t query_start_arg, + const char *user_host, uint user_host_len, + ulonglong query_utime, ulonglong lock_utime, bool is_command, + const char *sql_text, uint sql_text_len) + { + Silence_log_table_errors error_handler; + thd->push_internal_handler(&error_handler); +- bool retval= mysql_slow_log.write(thd, current_time, query_start_arg, ++ bool retval= mysql_slow_log.write(thd, current_utime, query_start_arg, + user_host, user_host_len, + query_utime, lock_utime, is_command, + sql_text, sql_text_len); +@@ -1131,7 +1133,7 @@ + /* 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->user ? sctx->user : (thd->slave_thread ? "SQL_SLAVE" : ""), "] @ ", + sctx->host ? sctx->host : "", " [", + sctx->ip ? sctx->ip : "", "]", NullS) - + user_host_buff); +@@ -1139,8 +1141,22 @@ + 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); ++ if(current_utime < thd->start_utime) ++ { ++ query_utime= 0; ++ } ++ else ++ { ++ query_utime= (current_utime - thd->start_utime); ++ } ++ if(thd->utime_after_lock < thd->start_utime) ++ { ++ lock_utime= 0; ++ } ++ else ++ { ++ lock_utime= (thd->utime_after_lock - thd->start_utime); ++ } + } + else + { +@@ -1154,8 +1170,20 @@ + query_length= command_name[thd->command].length; + } + ++ if (!query_length) ++ { ++ thd->sent_row_count= thd->examined_row_count= 0; ++ thd->sent_row_count= 0; ++ thd->bytes_sent_old= thd->status_var.bytes_sent; ++ thd->tmp_tables_used= thd->tmp_tables_disk_used= 0; ++ thd->tmp_tables_size= 0; ++ thd->innodb_was_used= FALSE; ++ thd->query_plan_flags= QPLAN_NONE; ++ thd->query_plan_fsort_passes= 0; ++ } ++ + for (current_handler= slow_log_handler_list; *current_handler ;) +- error= (*current_handler++)->log_slow(thd, current_time, thd->start_time, ++ error= (*current_handler++)->log_slow(thd, current_utime, thd->start_time, + user_host_buff, user_host_len, + query_utime, lock_utime, is_command, + query, query_length) || error; +@@ -2526,12 +2554,13 @@ + TRUE - error occured + */ + +-bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, ++bool MYSQL_QUERY_LOG::write(THD *thd, ulonglong current_utime, + time_t query_start_arg, const char *user_host, + uint user_host_len, ulonglong query_utime, + ulonglong lock_utime, bool is_command, + const char *sql_text, uint sql_text_len) + { ++ time_t current_time= my_time_possible_from_micro(current_utime); + bool error= 0; + DBUG_ENTER("MYSQL_QUERY_LOG::write"); + +@@ -2553,17 +2582,28 @@ + + if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT)) + { +- if (current_time != last_time) ++ if (opt_log_slow_timestamp_every || current_time != last_time) + { + last_time= current_time; + struct tm start; + localtime_r(¤t_time, &start); +- +- buff_len= my_snprintf(buff, sizeof buff, +- "# Time: %02d%02d%02d %2d:%02d:%02d\n", +- start.tm_year % 100, start.tm_mon + 1, +- start.tm_mday, start.tm_hour, +- start.tm_min, start.tm_sec); ++ if(opt_slow_query_log_microseconds_timestamp) ++ { ++ ulonglong microsecond = current_utime % (1000 * 1000); ++ buff_len= snprintf(buff, sizeof buff, ++ "# Time: %02d%02d%02d %2d:%02d:%02d.%010lld\n", ++ start.tm_year % 100, start.tm_mon + 1, ++ start.tm_mday, start.tm_hour, ++ start.tm_min, start.tm_sec,microsecond); ++ } ++ else ++ { ++ buff_len= my_snprintf(buff, sizeof buff, ++ "# Time: %02d%02d%02d %2d:%02d:%02d\n", ++ start.tm_year % 100, start.tm_mon + 1, ++ start.tm_mday, start.tm_hour, ++ start.tm_min, start.tm_sec); ++ } + + /* Note that my_b_write() assumes it knows the length for this */ + if (my_b_write(&log_file, (uchar*) buff, buff_len)) +@@ -2581,16 +2621,68 @@ + 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: %s Lock_time: %s" +- " Rows_sent: %lu Rows_examined: %lu\n", ++ "# Thread_id: %lu Schema: %s Last_errno: %u Killed: %u\n" \ ++ "# Query_time: %s Lock_time: %s Rows_sent: %lu Rows_examined: %lu Rows_affected: %lu Rows_read: %lu\n" ++ "# Bytes_sent: %lu Tmp_tables: %lu Tmp_disk_tables: %lu Tmp_table_sizes: %lu\n", ++ (ulong) thd->thread_id, (thd->db ? thd->db : ""), ++ thd->last_errno, (uint) thd->killed, + query_time_buff, lock_time_buff, + (ulong) thd->sent_row_count, +- (ulong) thd->examined_row_count) == (uint) -1) ++ (ulong) thd->examined_row_count, ++ ((long) thd->get_row_count_func() > 0 ) ? (ulong) thd->get_row_count_func() : 0, ++ (ulong) thd->sent_row_count, ++ (ulong) (thd->status_var.bytes_sent - thd->bytes_sent_old), ++ (ulong) thd->tmp_tables_used, ++ (ulong) thd->tmp_tables_disk_used, ++ (ulong) thd->tmp_tables_size) == (uint) -1) + tmp_errno= errno; + + #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) + thd->profiling.print_current(&log_file); + #endif ++ if (thd->innodb_was_used) ++ { ++ char buf[20]; ++ snprintf(buf, 20, "%llX", thd->innodb_trx_id); ++ if (my_b_printf(&log_file, ++ "# InnoDB_trx_id: %s\n", buf) == (uint) -1) ++ tmp_errno=errno; ++ } ++ if ((thd->variables.log_slow_verbosity & (ULL(1) << SLOG_V_QUERY_PLAN)) && ++ my_b_printf(&log_file, ++ "# QC_Hit: %s Full_scan: %s Full_join: %s Tmp_table: %s Tmp_table_on_disk: %s\n" \ ++ "# Filesort: %s Filesort_on_disk: %s Merge_passes: %lu\n", ++ ((thd->query_plan_flags & QPLAN_QC) ? "Yes" : "No"), ++ ((thd->query_plan_flags & QPLAN_FULL_SCAN) ? "Yes" : "No"), ++ ((thd->query_plan_flags & QPLAN_FULL_JOIN) ? "Yes" : "No"), ++ ((thd->query_plan_flags & QPLAN_TMP_TABLE) ? "Yes" : "No"), ++ ((thd->query_plan_flags & QPLAN_TMP_DISK) ? "Yes" : "No"), ++ ((thd->query_plan_flags & QPLAN_FILESORT) ? "Yes" : "No"), ++ ((thd->query_plan_flags & QPLAN_FILESORT_DISK) ? "Yes" : "No"), ++ thd->query_plan_fsort_passes) == (uint) -1) ++ tmp_errno=errno; ++ if ((thd->variables.log_slow_verbosity & (ULL(1) << SLOG_V_INNODB)) && thd->innodb_was_used) ++ { ++ char buf[3][20]; ++ snprintf(buf[0], 20, "%.6f", thd->innodb_io_reads_wait_timer / 1000000.0); ++ snprintf(buf[1], 20, "%.6f", thd->innodb_lock_que_wait_timer / 1000000.0); ++ snprintf(buf[2], 20, "%.6f", thd->innodb_innodb_que_wait_timer / 1000000.0); ++ if (my_b_printf(&log_file, ++ "# InnoDB_IO_r_ops: %lu InnoDB_IO_r_bytes: %lu InnoDB_IO_r_wait: %s\n" \ ++ "# InnoDB_rec_lock_wait: %s InnoDB_queue_wait: %s\n" \ ++ "# InnoDB_pages_distinct: %lu\n", ++ (ulong) thd->innodb_io_reads, ++ (ulong) thd->innodb_io_read, ++ buf[0], buf[1], buf[2], ++ (ulong) thd->innodb_page_access) == (uint) -1) ++ tmp_errno=errno; ++ } ++ else ++ { ++ if ((thd->variables.log_slow_verbosity & (ULL(1) << SLOG_V_INNODB)) && ++ my_b_printf(&log_file,"# No InnoDB statistics available for this query\n") == (uint) -1) ++ tmp_errno=errno; ++ } + + if (thd->db && strcmp(thd->db, db)) + { // Database changed +diff -ruN a/sql/log.h b/sql/log.h +--- a/sql/log.h 2010-11-03 01:01:14.000000000 +0300 ++++ b/sql/log.h 2010-11-28 17:38:42.000000000 +0300 +@@ -234,7 +234,7 @@ + uint user_host_len, int thread_id, + const char *command_type, uint command_type_len, + const char *sql_text, uint sql_text_len); +- bool write(THD *thd, time_t current_time, time_t query_start_arg, ++ bool write(THD *thd, ulonglong current_time, time_t query_start_arg, + const char *user_host, uint user_host_len, + ulonglong query_utime, ulonglong lock_utime, bool is_command, + const char *sql_text, uint sql_text_len); +@@ -476,7 +476,7 @@ + virtual bool init()= 0; + virtual void cleanup()= 0; + +- virtual bool log_slow(THD *thd, time_t current_time, ++ virtual bool log_slow(THD *thd, ulonglong current_time, + time_t query_start_arg, const char *user_host, + uint user_host_len, ulonglong query_utime, + ulonglong lock_utime, bool is_command, +@@ -505,7 +505,7 @@ + virtual bool init(); + virtual void cleanup(); + +- virtual bool log_slow(THD *thd, time_t current_time, ++ virtual bool log_slow(THD *thd, ulonglong current_utime, + time_t query_start_arg, const char *user_host, + uint user_host_len, ulonglong query_utime, + ulonglong lock_utime, bool is_command, +@@ -537,7 +537,7 @@ + virtual bool init(); + virtual void cleanup(); + +- virtual bool log_slow(THD *thd, time_t current_time, ++ virtual bool log_slow(THD *thd, ulonglong current_utime, + time_t query_start_arg, const char *user_host, + uint user_host_len, ulonglong query_utime, + ulonglong lock_utime, bool is_command, +diff -ruN a/sql/mysqld.cc b/sql/mysqld.cc +--- a/sql/mysqld.cc 2010-11-03 01:01:14.000000000 +0300 ++++ b/sql/mysqld.cc 2010-11-28 18:27:55.000000000 +0300 +@@ -416,6 +416,11 @@ + char* opt_secure_file_priv; + my_bool opt_log_slow_admin_statements= 0; + my_bool opt_log_slow_slave_statements= 0; ++my_bool opt_log_slow_sp_statements= 0; ++my_bool opt_log_slow_timestamp_every= 0; ++my_bool opt_use_global_long_query_time= 0; ++ulonglong opt_use_global_log_slow_control= 0; ++my_bool opt_slow_query_log_microseconds_timestamp= 0; + my_bool lower_case_file_system= 0; + my_bool opt_large_pages= 0; + my_bool opt_super_large_pages= 0; +@@ -5790,10 +5795,10 @@ + "Log slow OPTIMIZE, ANALYZE, ALTER and other administrative statements to " + "the slow log if it is open.", &opt_log_slow_admin_statements, + &opt_log_slow_admin_statements, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, +- {"log-slow-slave-statements", 0, ++ /*{"log-slow-slave-statements", 0, + "Log slow statements executed by slave thread to the slow log if it is open.", + &opt_log_slow_slave_statements, &opt_log_slow_slave_statements, +- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, ++ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},*/ + {"log-slow-queries", OPT_SLOW_QUERY_LOG, + "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. " +diff -ruN a/sql/mysqld.h b/sql/mysqld.h +--- a/sql/mysqld.h 2010-11-03 01:01:14.000000000 +0300 ++++ b/sql/mysqld.h 2010-11-28 18:27:39.000000000 +0300 +@@ -115,6 +115,11 @@ + extern char* opt_secure_backup_file_priv; + extern size_t opt_secure_backup_file_priv_len; + extern my_bool opt_log_slow_admin_statements, opt_log_slow_slave_statements; ++extern my_bool opt_log_slow_sp_statements; ++extern my_bool opt_log_slow_timestamp_every; ++extern my_bool opt_use_global_long_query_time; ++extern ulonglong opt_use_global_log_slow_control; ++extern my_bool opt_slow_query_log_microseconds_timestamp; + 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 -ruN a/sql/slave.cc b/sql/slave.cc +--- a/sql/slave.cc 2010-11-03 01:01:14.000000000 +0300 ++++ b/sql/slave.cc 2010-11-28 17:38:42.000000000 +0300 +@@ -2019,6 +2019,7 @@ + + 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; ++ thd->write_to_slow_log= opt_log_slow_slave_statements; + set_slave_thread_options(thd); + thd->client_capabilities = CLIENT_LOCAL_FILES; + mysql_mutex_lock(&LOCK_thread_count); +diff -ruN a/sql/sp_head.cc b/sql/sp_head.cc +--- a/sql/sp_head.cc 2010-11-03 01:01:14.000000000 +0300 ++++ b/sql/sp_head.cc 2010-11-28 17:38:42.000000000 +0300 +@@ -2136,7 +2136,7 @@ + DBUG_PRINT("info",(" %.*s: eval args done", (int) m_name.length, + m_name.str)); + } +- if (!(m_flags & LOG_SLOW_STATEMENTS) && thd->enable_slow_log) ++ if (!(m_flags & LOG_SLOW_STATEMENTS || opt_log_slow_sp_statements) && thd->enable_slow_log) + { + DBUG_PRINT("info", ("Disabling slow log for the execution")); + save_enable_slow_log= true; +diff -ruN a/sql/sql_cache.cc b/sql/sql_cache.cc +--- a/sql/sql_cache.cc 2010-11-03 01:01:14.000000000 +0300 ++++ b/sql/sql_cache.cc 2010-11-28 17:38:42.000000000 +0300 +@@ -1756,6 +1756,7 @@ + response, we can't handle it anyway. + */ + (void) trans_commit_stmt(thd); ++ thd->query_plan_flags|= QPLAN_QC; + if (!thd->stmt_da->is_set()) + thd->stmt_da->disable_status(); + +@@ -1766,6 +1767,7 @@ + err_unlock: + unlock(); + err: ++ thd->query_plan_flags|= QPLAN_QC_NO; + MYSQL_QUERY_CACHE_MISS(thd->query()); + DBUG_RETURN(0); // Query was not cached + } +diff -ruN a/sql/sql_class.cc b/sql/sql_class.cc +--- a/sql/sql_class.cc 2010-11-03 01:01:14.000000000 +0300 ++++ b/sql/sql_class.cc 2010-11-28 17:38:42.000000000 +0300 +@@ -367,6 +367,37 @@ + thd->warning_info->inc_current_row_for_warning(); + } + ++extern "C" ++void increment_thd_innodb_stats(THD* thd, ++ unsigned long long trx_id, ++ long io_reads, ++ long long io_read, ++ long io_reads_wait_timer, ++ long lock_que_wait_timer, ++ long que_wait_timer, ++ long page_access) ++{ ++ thd->innodb_was_used = TRUE; ++ thd->innodb_trx_id = trx_id; ++ thd->innodb_io_reads += io_reads; ++ thd->innodb_io_read += io_read; ++ thd->innodb_io_reads_wait_timer += io_reads_wait_timer; ++ thd->innodb_lock_que_wait_timer += lock_que_wait_timer; ++ thd->innodb_innodb_que_wait_timer += que_wait_timer; ++ thd->innodb_page_access += page_access; ++} ++ ++extern "C" ++unsigned long thd_log_slow_verbosity(const THD *thd) ++{ ++ return (unsigned long) thd->variables.log_slow_verbosity; ++} ++ ++extern "C" ++int thd_opt_slow_log() ++{ ++ return (int) opt_slow_log; ++} + + /** + Dumps a text description of a thread, its security context +@@ -661,6 +692,7 @@ + *cond_hdl= NULL; + return FALSE; + } ++ last_errno= sql_errno; + + for (Internal_error_handler *error_handler= m_internal_handler; + error_handler; +@@ -3319,6 +3351,12 @@ + first_successful_insert_id_in_prev_stmt; + backup->first_successful_insert_id_in_cur_stmt= + first_successful_insert_id_in_cur_stmt; ++ backup->innodb_io_reads= innodb_io_reads; ++ backup->innodb_io_read= innodb_io_read; ++ backup->innodb_io_reads_wait_timer= innodb_io_reads_wait_timer; ++ backup->innodb_lock_que_wait_timer= innodb_lock_que_wait_timer; ++ backup->innodb_innodb_que_wait_timer= innodb_innodb_que_wait_timer; ++ backup->innodb_page_access= innodb_page_access; + + if ((!lex->requires_prelocking() || is_update_query(lex->sql_command)) && + !is_current_stmt_binlog_format_row()) +@@ -3339,6 +3377,14 @@ + cuted_fields= 0; + transaction.savepoints= 0; + first_successful_insert_id_in_cur_stmt= 0; ++ last_errno= 0; ++ innodb_trx_id= 0; ++ innodb_io_reads= 0; ++ innodb_io_read= 0; ++ innodb_io_reads_wait_timer= 0; ++ innodb_lock_que_wait_timer= 0; ++ innodb_innodb_que_wait_timer= 0; ++ innodb_page_access= 0; + } + + +@@ -3401,6 +3447,12 @@ + */ + examined_row_count+= backup->examined_row_count; + cuted_fields+= backup->cuted_fields; ++ innodb_io_reads+= backup->innodb_io_reads; ++ innodb_io_read+= backup->innodb_io_read; ++ innodb_io_reads_wait_timer+= backup->innodb_io_reads_wait_timer; ++ innodb_lock_que_wait_timer+= backup->innodb_lock_que_wait_timer; ++ innodb_innodb_que_wait_timer+= backup->innodb_innodb_que_wait_timer; ++ innodb_page_access+= backup->innodb_page_access; + DBUG_VOID_RETURN; + } + +diff -ruN a/sql/sql_class.h b/sql/sql_class.h +--- a/sql/sql_class.h 2010-11-03 01:01:14.000000000 +0300 ++++ b/sql/sql_class.h 2010-11-28 18:26:41.000000000 +0300 +@@ -60,6 +60,18 @@ + enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_UPDATE }; + enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON, + DELAY_KEY_WRITE_ALL }; ++enum enum_use_global_log_slow_control { SLOG_UG_LOG_SLOW_FILTER, SLOG_UG_LOG_SLOW_RATE_LIMIT, SLOG_UG_LOG_SLOW_VERBOSITY, SLOG_UG_LONG_QUERY_TIME, SLOG_UG_MIN_EXAMINED_ROW_LIMIT, SLOG_UG_ALL }; ++enum enum_log_slow_verbosity { SLOG_V_MICROTIME, SLOG_V_QUERY_PLAN, SLOG_V_INNODB, SLOG_V_MINIMAL, SLOG_V_STANDARD, SLOG_V_FULL }; ++#define QPLAN_NONE 0 ++#define QPLAN_QC 1 << 0 ++#define QPLAN_QC_NO 1 << 1 ++#define QPLAN_FULL_SCAN 1 << 2 ++#define QPLAN_FULL_JOIN 1 << 3 ++#define QPLAN_TMP_TABLE 1 << 4 ++#define QPLAN_TMP_DISK 1 << 5 ++#define QPLAN_FILESORT 1 << 6 ++#define QPLAN_FILESORT_DISK 1 << 7 ++enum enum_log_slow_filter { SLOG_F_QC_NO, SLOG_F_FULL_SCAN, SLOG_F_FULL_JOIN, SLOG_F_TMP_TABLE, SLOG_F_TMP_DISK, SLOG_F_FILESORT, SLOG_F_FILESORT_DISK}; + enum enum_slave_exec_mode { SLAVE_EXEC_MODE_STRICT, + SLAVE_EXEC_MODE_IDEMPOTENT, + SLAVE_EXEC_MODE_LAST_BIT}; +@@ -475,6 +487,17 @@ + + my_bool sysdate_is_now; + ++ ulong log_slow_rate_limit; ++ ulonglong log_slow_filter; ++ ulonglong log_slow_verbosity; ++ ++ ulong innodb_io_reads; ++ ulonglong innodb_io_read; ++ ulong innodb_io_reads_wait_timer; ++ ulong innodb_lock_que_wait_timer; ++ ulong innodb_innodb_que_wait_timer; ++ ulong innodb_page_access; ++ + double long_query_time_double; + + } SV; +@@ -1095,6 +1118,14 @@ + uint in_sub_stmt; + bool enable_slow_log; + bool last_insert_id_used; ++ ++ ulong innodb_io_reads; ++ ulonglong innodb_io_read; ++ ulong innodb_io_reads_wait_timer; ++ ulong innodb_lock_que_wait_timer; ++ ulong innodb_innodb_que_wait_timer; ++ ulong innodb_page_access; ++ + SAVEPOINT *savepoints; + enum enum_check_fields count_cuted_fields; + }; +@@ -1513,6 +1544,26 @@ + thr_lock_type update_lock_default; + Delayed_insert *di; + ++ bool write_to_slow_log; ++ ++ ulonglong bytes_sent_old; ++ ulong tmp_tables_used; ++ ulong tmp_tables_disk_used; ++ ulonglong tmp_tables_size; ++ bool innodb_was_used; ++ ulonglong innodb_trx_id; ++ ulong innodb_io_reads; ++ ulonglong innodb_io_read; ++ ulong innodb_io_reads_wait_timer; ++ ulong innodb_lock_que_wait_timer; ++ ulong innodb_innodb_que_wait_timer; ++ ulong innodb_page_access; ++ ++ ulong query_plan_flags; ++ ulong query_plan_fsort_passes; ++ ++ uint last_errno; ++ + /* <> 0 if we are inside of trigger or stored function. */ + uint in_sub_stmt; + +diff -ruN a/sql/sql_connect.cc b/sql/sql_connect.cc +--- a/sql/sql_connect.cc 2010-11-03 01:01:14.000000000 +0300 ++++ b/sql/sql_connect.cc 2010-11-28 17:38:42.000000000 +0300 +@@ -738,6 +738,15 @@ + + prepare_new_connection_state(thd); + ++ /* ++ If rate limiting of slow log writes is enabled, decide whether to log this ++ new thread's queries or not. Uses extremely simple algorithm. :) ++ */ ++ thd->write_to_slow_log= FALSE; ++ if (thd->variables.log_slow_rate_limit <= 1 || ++ (thd->thread_id % thd->variables.log_slow_rate_limit) == 0) ++ thd->write_to_slow_log= TRUE; ++ + while (!net->error && net->vio != 0 && + !(thd->killed == THD::KILL_CONNECTION)) + { +diff -ruN a/sql/sql_parse.cc b/sql/sql_parse.cc +--- a/sql/sql_parse.cc 2010-11-03 01:01:14.000000000 +0300 ++++ b/sql/sql_parse.cc 2010-11-29 01:55:31.000000000 +0300 +@@ -1417,7 +1417,6 @@ + DBUG_RETURN(error); + } + +- + void log_slow_statement(THD *thd) + { + DBUG_ENTER("log_slow_statement"); +@@ -1430,6 +1429,29 @@ + if (unlikely(thd->in_sub_stmt)) + DBUG_VOID_RETURN; // Don't set time for sub stmt + ++ /* Follow the slow log filter configuration. */ ++ if (thd->variables.log_slow_filter != 0 && ++ (!(thd->variables.log_slow_filter & thd->query_plan_flags) || ++ ((thd->variables.log_slow_filter & SLOG_F_QC_NO) && ++ (thd->query_plan_flags & QPLAN_QC)))) ++ DBUG_VOID_RETURN; ++ ++ /* ++ Low long_query_time value most likely means user is debugging stuff and even ++ though some thread's queries are not supposed to be logged b/c of the rate ++ limit, if one of them takes long enough (>= 1 second) it will be sensible ++ to make an exception and write to slow log anyway. ++ */ ++ ++ ulonglong end_utime_of_query= thd->current_utime(); ++ ++ /* Do not log this thread's queries due to rate limiting. */ ++ if (thd->write_to_slow_log != TRUE ++ && (thd->variables.long_query_time >= 1000000 ++ || (ulong) (end_utime_of_query - thd->utime_after_lock) < 1000000)) ++ DBUG_VOID_RETURN; ++ ++ + /* + Do not log administrative statements unless the appropriate option is + set. +@@ -1817,6 +1839,9 @@ + context.resolve_in_table_list_only(select_lex-> + table_list.first); + ++ /* Reset the counter at all cases for the extended slow query log */ ++ thd->sent_row_count= 0; ++ + /* + Reset warning count for each query that uses tables + A better approach would be to reset this for any commands +@@ -5246,6 +5271,21 @@ + thd->rand_used= 0; + thd->sent_row_count= thd->examined_row_count= 0; + ++ thd->bytes_sent_old= thd->status_var.bytes_sent; ++ thd->tmp_tables_used= thd->tmp_tables_disk_used= 0; ++ thd->tmp_tables_size= 0; ++ thd->innodb_was_used= FALSE; ++ thd->innodb_trx_id= 0; ++ thd->innodb_io_reads= 0; ++ thd->innodb_io_read= 0; ++ thd->innodb_io_reads_wait_timer= 0; ++ thd->innodb_lock_que_wait_timer= 0; ++ thd->innodb_innodb_que_wait_timer= 0; ++ thd->innodb_page_access= 0; ++ thd->query_plan_flags= QPLAN_NONE; ++ thd->query_plan_fsort_passes= 0; ++ thd->last_errno= 0; ++ + thd->reset_current_stmt_binlog_format_row(); + thd->binlog_unsafe_warning_flags= 0; + +diff -ruN a/sql/sql_select.cc b/sql/sql_select.cc +--- a/sql/sql_select.cc 2010-11-03 01:01:14.000000000 +0300 ++++ b/sql/sql_select.cc 2010-11-28 17:38:42.000000000 +0300 +@@ -6854,7 +6854,10 @@ + { + join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED; + if (statistics) ++ { + status_var_increment(join->thd->status_var.select_scan_count); ++ join->thd->query_plan_flags|= QPLAN_FULL_SCAN; ++ } + } + } + else +@@ -6868,7 +6871,10 @@ + { + join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED; + if (statistics) ++ { + status_var_increment(join->thd->status_var.select_full_join_count); ++ join->thd->query_plan_flags|= QPLAN_FULL_JOIN; ++ } + } + } + if (!table->no_keyread) +@@ -10194,6 +10200,7 @@ + (ulong) rows_limit,test(group))); + + status_var_increment(thd->status_var.created_tmp_tables); ++ thd->query_plan_flags|= QPLAN_TMP_TABLE; + + if (use_temp_pool && !(test_flags & TEST_KEEP_TMP_TABLES)) + temp_pool_slot = bitmap_lock_set_next(&temp_pool); +@@ -11091,6 +11098,7 @@ + goto err; + } + status_var_increment(table->in_use->status_var.created_tmp_disk_tables); ++ table->in_use->query_plan_flags|= QPLAN_TMP_DISK; + share->db_record_offset= 1; + DBUG_RETURN(0); + err: +@@ -11109,6 +11117,14 @@ + save_proc_info=thd->proc_info; + thd_proc_info(thd, "removing tmp table"); + ++ thd->tmp_tables_used++; ++ if (entry->file) ++ { ++ thd->tmp_tables_size += entry->file->stats.data_file_length; ++ if (entry->file->ht->db_type != DB_TYPE_HEAP) ++ thd->tmp_tables_disk_used++; ++ } ++ + // Release latches since this can take a long time + ha_release_temporary_latches(thd); + +diff -ruN a/sql/sql_show.cc b/sql/sql_show.cc +--- a/sql/sql_show.cc 2010-11-03 01:01:14.000000000 +0300 ++++ b/sql/sql_show.cc 2010-11-28 17:38:43.000000000 +0300 +@@ -1935,8 +1935,17 @@ + table->field[4]->store(command_name[tmp->command].str, + command_name[tmp->command].length, cs); + /* MYSQL_TIME */ +- table->field[5]->store((longlong)(tmp->start_time ? +- now - tmp->start_time : 0), FALSE); ++ longlong value_in_time_column= 0; ++ if(tmp->start_time) ++ { ++ value_in_time_column = (now - tmp->start_time); ++ if(value_in_time_column > now) ++ { ++ value_in_time_column= 0; ++ } ++ } ++ table->field[5]->store(value_in_time_column, FALSE); ++ + /* STATE */ + if ((val= thread_state_info(tmp))) + { +diff -ruN a/sql/sys_vars.cc b/sql/sys_vars.cc +--- a/sql/sys_vars.cc 2010-11-03 01:01:14.000000000 +0300 ++++ b/sql/sys_vars.cc 2010-11-29 02:07:08.000000000 +0300 +@@ -941,6 +941,15 @@ + CMD_LINE(OPT_ARG, 'W'), + VALID_RANGE(0, ULONG_MAX), DEFAULT(1), BLOCK_SIZE(1)); + ++static void update_long_query_time_check_global(THD *thd) ++{ ++ bool use_global= (0 != (opt_use_global_log_slow_control & (ULL(1) << SLOG_UG_LONG_QUERY_TIME))); ++ if(use_global) ++ { ++ thd->variables.long_query_time_double= global_system_variables.long_query_time_double; ++ thd->variables.long_query_time= global_system_variables.long_query_time; ++ } ++} + static bool update_cached_long_query_time(sys_var *self, THD *thd, + enum_var_type type) + { +@@ -950,6 +959,7 @@ + else + global_system_variables.long_query_time= + double2ulonglong(global_system_variables.long_query_time_double * 1e6); ++ update_long_query_time_check_global(thd); + return false; + } + +@@ -1226,13 +1236,26 @@ + "After this many write locks, allow some read locks to run in between", + GLOBAL_VAR(max_write_lock_count), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(1, ULONG_MAX), DEFAULT(ULONG_MAX), BLOCK_SIZE(1)); +- ++#define SLOG_UPDATE(variable_name,enum_value_name) \ ++ static bool update_##variable_name(sys_var */*self*/, THD *thd, \ ++ enum_var_type type) \ ++ { \ ++ if (opt_use_global_log_slow_control & (ULL(1) << enum_value_name)) \ ++ { \ ++ thd->variables. variable_name= \ ++ global_system_variables. variable_name; \ ++ } \ ++ return false; \ ++ } ++SLOG_UPDATE(min_examined_row_limit,SLOG_UG_MIN_EXAMINED_ROW_LIMIT); + static Sys_var_ulong Sys_min_examined_row_limit( + "min_examined_row_limit", + "Don't write queries to slow log that examine fewer rows " + "than that", + SESSION_VAR(min_examined_row_limit), CMD_LINE(REQUIRED_ARG), +- VALID_RANGE(0, ULONG_MAX), DEFAULT(0), BLOCK_SIZE(1)); ++ VALID_RANGE(0, ULONG_MAX), DEFAULT(0), BLOCK_SIZE(1), ++ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ++ ON_UPDATE(update_min_examined_row_limit)); + + #ifdef _WIN32 + static Sys_var_mybool Sys_named_pipe( +@@ -2837,6 +2860,149 @@ + DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(fix_log_state)); + ++const char *log_slow_filter_name[]= { "qc_miss", "full_scan", "full_join", ++ "tmp_table", "tmp_table_on_disk", "filesort", "filesort_on_disk", 0}; ++SLOG_UPDATE(log_slow_filter,SLOG_UG_LOG_SLOW_FILTER); ++static Sys_var_set Sys_log_slow_filter( ++ "log_slow_filter", ++ "Log only the queries that followed certain execution plan. " ++ "Multiple flags allowed in a comma-separated string. " ++ "[qc_miss, full_scan, full_join, tmp_table, tmp_table_on_disk, " ++ "filesort, filesort_on_disk]", ++ SESSION_VAR(log_slow_filter), CMD_LINE(REQUIRED_ARG), ++ log_slow_filter_name, DEFAULT(0), ++ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ++ ON_UPDATE(update_log_slow_filter)); ++SLOG_UPDATE(log_slow_rate_limit,SLOG_UG_LOG_SLOW_RATE_LIMIT); ++static Sys_var_ulong sys_log_slow_rate_limit( ++ "log_slow_rate_limit","Rate limit statement writes to slow log to only those from every (1/log_slow_rate_limit) session.", ++ SESSION_VAR(log_slow_rate_limit), CMD_LINE(REQUIRED_ARG), ++ VALID_RANGE(1, ULONG_MAX), DEFAULT(1), BLOCK_SIZE(1), ++ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ++ ON_UPDATE(update_log_slow_rate_limit)); ++const char* log_slow_verbosity_name[] = { "microtime", "query_plan", "innodb", "minimal", "standard", "full", 0 }; ++static ulonglong update_log_slow_verbosity_replace(ulonglong value, ulonglong what, ulonglong by) ++{ ++ if((value & what) == what) ++ { ++ value = value & (~what); ++ value = value | by; ++ } ++ return value; ++} ++static bool update_log_slow_verbosity(sys_var */*self*/, THD *thd, ++ enum_var_type type) ++{ ++ ulonglong *value_ptr= 0; ++ if(type == OPT_SESSION) ++ { ++ value_ptr= &(thd->variables.log_slow_verbosity); ++ } ++ else ++ { ++ value_ptr= &(global_system_variables.log_slow_verbosity); ++ } ++ ulonglong &value = *value_ptr; ++ ulonglong microtime= ULL(1) << SLOG_V_MICROTIME; ++ ulonglong query_plan= ULL(1) << SLOG_V_QUERY_PLAN; ++ ulonglong innodb= ULL(1) << SLOG_V_INNODB; ++ ulonglong minimal= ULL(1) << SLOG_V_MINIMAL; ++ ulonglong standard= ULL(1) << SLOG_V_STANDARD; ++ ulonglong full= ULL(1) << SLOG_V_FULL; ++ value= update_log_slow_verbosity_replace(value,minimal,microtime); ++ value= update_log_slow_verbosity_replace(value,standard,microtime | query_plan); ++ value= update_log_slow_verbosity_replace(value,full,microtime | query_plan | innodb); ++ if(opt_use_global_log_slow_control & (ULL(1) << SLOG_UG_LOG_SLOW_VERBOSITY)) ++ { ++ thd->variables.log_slow_verbosity= global_system_variables.log_slow_verbosity; ++ } ++ return false; ++} ++static Sys_var_set Sys_log_slow_verbosity( ++ "log_slow_verbosity", ++ "Choose how verbose the messages to your slow log will be. " ++ "Multiple flags allowed in a comma-separated string. [microtime, query_plan, innodb]", ++ SESSION_VAR(log_slow_verbosity), CMD_LINE(REQUIRED_ARG), ++ log_slow_verbosity_name, DEFAULT(SLOG_V_MICROTIME), ++ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ++ ON_UPDATE(update_log_slow_verbosity)); ++static Sys_var_mybool Sys_log_slow_slave_statements( ++ "log_slow_slave_statements", ++ "Log queries replayed be the slave SQL thread", ++ GLOBAL_VAR(opt_log_slow_slave_statements), CMD_LINE(OPT_ARG), ++ DEFAULT(FALSE)); ++static Sys_var_mybool Sys_log_slow_sp_statements( ++ "log_slow_sp_statements", ++ "Log slow statements executed by stored procedure to the slow log if it is open.", ++ GLOBAL_VAR(opt_log_slow_sp_statements), CMD_LINE(OPT_ARG), ++ DEFAULT(TRUE)); ++static Sys_var_mybool Sys_log_slow_timestamp_every( ++ "log_slow_timestamp_every", ++ "Timestamp is printed for all records of the slow log even if they are same time.", ++ GLOBAL_VAR(opt_log_slow_timestamp_every), CMD_LINE(OPT_ARG), ++ DEFAULT(FALSE)); ++const char *use_global_log_slow_control_name[]= { "log_slow_filter", "log_slow_rate_limit", "log_slow_verbosity", "long_query_time", "min_examined_row_limit", "all", 0}; ++static bool update_use_global_log_slow_control(sys_var *self, THD *thd, ++ enum_var_type type) ++{ ++ if(opt_use_global_log_slow_control & (ULL(1) << SLOG_UG_ALL)) ++ { ++ opt_use_global_log_slow_control= ++ SLOG_UG_LOG_SLOW_FILTER | SLOG_UG_LOG_SLOW_RATE_LIMIT | SLOG_UG_LOG_SLOW_VERBOSITY | ++ SLOG_UG_LONG_QUERY_TIME | SLOG_UG_MIN_EXAMINED_ROW_LIMIT; ++ } ++ if(opt_use_global_log_slow_control & (ULL(1) << SLOG_UG_LONG_QUERY_TIME)) ++ { ++ opt_use_global_long_query_time= TRUE; ++ } ++ else ++ { ++ opt_use_global_long_query_time= FALSE; ++ } ++ update_long_query_time_check_global(thd); ++ update_log_slow_filter(self,thd,type); ++ update_log_slow_rate_limit(self,thd,type); ++ update_log_slow_verbosity(self,thd,type); ++ update_min_examined_row_limit(self,thd,type); ++ return false; ++} ++static Sys_var_set Sys_use_global_log_slow_control( ++ "use_global_log_slow_control", ++ "Choose flags, wich always use the global variables. Multiple flags allowed in a comma-separated string. [none, log_slow_filter, log_slow_rate_limit, log_slow_verbosity, long_query_time, min_examined_row_limit, all]", ++ GLOBAL_VAR(opt_use_global_log_slow_control), CMD_LINE(REQUIRED_ARG), ++ use_global_log_slow_control_name, DEFAULT(0), ++ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ++ ON_UPDATE(update_use_global_log_slow_control)); ++static bool update_use_global_long_query_time(sys_var *self, THD *thd, ++ enum_var_type type) ++{ ++ if(type == OPT_GLOBAL) ++ { ++ if(opt_use_global_long_query_time) ++ { ++ opt_use_global_log_slow_control |= ULL(1) << SLOG_UG_LONG_QUERY_TIME; ++ } ++ else ++ { ++ opt_use_global_log_slow_control &= ~(ULL(1) << SLOG_UG_LONG_QUERY_TIME); ++ } ++ update_long_query_time_check_global(thd); ++ } ++ return false; ++} ++static Sys_var_mybool Sys_use_global_long_query_time( ++ "use_global_long_query_time", ++ "Control always use global long_query_time or local long_query_time.", ++ GLOBAL_VAR(opt_use_global_long_query_time), CMD_LINE(OPT_ARG), ++ DEFAULT(FALSE), ++ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ++ ON_UPDATE(update_use_global_long_query_time)); ++static Sys_var_mybool Sys_slow_query_log_microseconds_timestamp( ++ "slow_query_log_microseconds_timestamp", ++ "Log slow statements executed by stored procedure to the slow log if it is open.", ++ GLOBAL_VAR(opt_slow_query_log_microseconds_timestamp), CMD_LINE(OPT_ARG), ++ DEFAULT(FALSE)); ++ + /* Synonym of "slow_query_log" for consistency with SHOW VARIABLES output */ + static Sys_var_mybool Sys_log_slow( + "log_slow_queries", diff --git a/sql_no_fcache.patch b/sql_no_fcache.patch new file mode 100644 index 000000000000..4191d79cd0af --- /dev/null +++ b/sql_no_fcache.patch @@ -0,0 +1,413 @@ +# name : sql_no_fcache.patch +# introduced : 12 +# maintainer : Oleg +# +#!!! notice !!! +# Any small change to this file in the main branch +# should be done or reviewed by the maintainer! +diff -ruN a/client/mysqldump.c b/client/mysqldump.c +--- a/client/mysqldump.c 2010-07-28 16:47:58.264067653 +0400 ++++ b/client/mysqldump.c 2010-07-28 16:47:59.604985656 +0400 +@@ -138,6 +138,8 @@ + #endif + static uint opt_protocol= 0; + ++static my_bool server_supports_sql_no_fcache= FALSE; ++ + /* + Dynamic_string wrapper functions. In this file use these + wrappers, they will terminate the process if there is +@@ -1471,6 +1473,17 @@ + /* Don't switch charsets for 4.1 and earlier. (bug#34192). */ + server_supports_switching_charsets= FALSE; + } ++ ++ /* Check to see if we support SQL_NO_FCACHE on this server. */ ++ if (mysql_query(mysql, "SELECT SQL_NO_FCACHE NOW()") == 0) ++ { ++ MYSQL_RES *res = mysql_store_result(mysql); ++ if (res) ++ { ++ mysql_free_result(res); ++ } ++ server_supports_sql_no_fcache= TRUE; ++ } + /* + As we're going to set SQL_MODE, it would be lost on reconnect, so we + cannot reconnect. +@@ -3143,7 +3156,12 @@ + + /* now build the query string */ + +- dynstr_append_checked(&query_string, "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '"); ++ dynstr_append_checked(&query_string, "SELECT /*!40001 SQL_NO_CACHE */ "); ++ if (server_supports_sql_no_fcache) ++ { ++ dynstr_append_checked(&query_string, "/*!50084 SQL_NO_FCACHE */ "); ++ } ++ dynstr_append_checked(&query_string, "* INTO OUTFILE '"); + dynstr_append_checked(&query_string, filename); + dynstr_append_checked(&query_string, "'"); + +@@ -3193,7 +3211,12 @@ + check_io(md_result_file); + } + +- dynstr_append_checked(&query_string, "SELECT /*!40001 SQL_NO_CACHE */ * FROM "); ++ dynstr_append_checked(&query_string, "SELECT /*!40001 SQL_NO_CACHE */ "); ++ if (server_supports_sql_no_fcache) ++ { ++ dynstr_append_checked(&query_string, "/*!50084 SQL_NO_FCACHE */ "); ++ } ++ dynstr_append_checked(&query_string, "* FROM "); + dynstr_append_checked(&query_string, result_table); + + if (where) +diff -ruN a/include/flashcache_ioctl.h b/include/flashcache_ioctl.h +--- a/include/flashcache_ioctl.h 1970-01-01 03:00:00.000000000 +0300 ++++ b/include/flashcache_ioctl.h 2010-07-28 16:47:59.744079911 +0400 +@@ -0,0 +1,53 @@ ++/**************************************************************************** ++ * flashcache_ioctl.h ++ * FlashCache: Device mapper target for block-level disk caching ++ * ++ * Copyright 2010 Facebook, Inc. ++ * Author: Mohan Srinivasan (mohan@facebook.com) ++ * ++ * Based on DM-Cache: ++ * Copyright (C) International Business Machines Corp., 2006 ++ * Author: Ming Zhao (mingzhao@ufl.edu) ++ * ++ * 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; under version 2 of the License. ++ * ++ * 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, see . ++ ****************************************************************************/ ++ ++#ifndef FLASHCACHE_IOCTL_H ++#define FLASHCACHE_IOCTL_H ++ ++#include ++ ++#define FLASHCACHE_IOCTL 0xfe ++ ++enum { ++ FLASHCACHEADDNCPID_CMD=200, ++ FLASHCACHEDELNCPID_CMD, ++ FLASHCACHEDELNCALL_CMD, ++ FLASHCACHEADDWHITELIST_CMD, ++ FLASHCACHEDELWHITELIST_CMD, ++ FLASHCACHEDELWHITELISTALL_CMD, ++}; ++ ++#define FLASHCACHEADDNCPID _IOW(FLASHCACHE_IOCTL, FLASHCACHEADDNCPID_CMD, pid_t) ++#define FLASHCACHEDELNCPID _IOW(FLASHCACHE_IOCTL, FLASHCACHEDELNCPID_CMD, pid_t) ++#define FLASHCACHEDELNCALL _IOW(FLASHCACHE_IOCTL, FLASHCACHEDELNCALL_CMD, pid_t) ++ ++#define FLASHCACHEADDBLACKLIST FLASHCACHEADDNCPID ++#define FLASHCACHEDELBLACKLIST FLASHCACHEDELNCPID ++#define FLASHCACHEDELALLBLACKLIST FLASHCACHEDELNCALL ++ ++#define FLASHCACHEADDWHITELIST _IOW(FLASHCACHE_IOCTL, FLASHCACHEADDWHITELIST_CMD, pid_t) ++#define FLASHCACHEDELWHITELIST _IOW(FLASHCACHE_IOCTL, FLASHCACHEDELWHITELIST_CMD, pid_t) ++#define FLASHCACHEDELALLWHITELIST _IOW(FLASHCACHE_IOCTL, FLASHCACHEDELWHITELISTALL_CMD, pid_t) ++ ++#endif +diff -ruN a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result +--- a/mysql-test/r/mysqldump.result 2010-07-28 16:47:58.334083833 +0400 ++++ b/mysql-test/r/mysqldump.result 2010-07-28 16:48:14.805318437 +0400 +@@ -1832,7 +1832,7 @@ + # Bug#21288 mysqldump segmentation fault when using --where + # + create table t1 (a int); +-mysqldump: Couldn't execute 'SELECT /*!40001 SQL_NO_CACHE */ * FROM `t1` WHERE xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx': You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' at line 1 (1064) ++mysqldump: Couldn't execute 'SELECT /*!40001 SQL_NO_CACHE */ /*!50084 SQL_NO_FCACHE */ * FROM `t1` WHERE xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx': You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' at line 1 (1064) + mysqldump: Got error: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' at line 1 when retrieving data from server + + /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +diff -ruN a/patch_info/sql_no_fcache.info b/patch_info/sql_no_fcache.info +--- a/patch_info/sql_no_fcache.info 1970-01-01 03:00:00.000000000 +0300 ++++ b/patch_info/sql_no_fcache.info 2010-07-28 16:47:59.915439165 +0400 +@@ -0,0 +1,6 @@ ++File=sql_no_fcache.patch ++Name=Support for flashcache including the SQL_NO_FCACHE option that prevents blocks from being cached during a query. ++Version=1.0 ++Author=Facebook ++License=GPL ++Comment= +diff -ruN a/sql/lex.h b/sql/lex.h +--- a/sql/lex.h 2010-07-28 16:47:58.575318748 +0400 ++++ b/sql/lex.h 2010-07-28 16:48:00.134078469 +0400 +@@ -517,6 +517,7 @@ + { "SQL_CACHE", SYM(SQL_CACHE_SYM)}, + { "SQL_CALC_FOUND_ROWS", SYM(SQL_CALC_FOUND_ROWS)}, + { "SQL_NO_CACHE", SYM(SQL_NO_CACHE_SYM)}, ++ { "SQL_NO_FCACHE", SYM(SQL_NO_FCACHE_SYM)}, + { "SQL_SMALL_RESULT", SYM(SQL_SMALL_RESULT)}, + { "SQL_THREAD", SYM(SQL_THREAD)}, + { "SQL_TSI_SECOND", SYM(SECOND_SYM)}, +diff -ruN a/sql/mysqld.h b/sql/mysqld.h +--- a/sql/mysqld.h 2010-07-28 16:47:58.565318871 +0400 ++++ b/sql/mysqld.h 2010-07-28 16:48:03.004544367 +0400 +@@ -189,6 +189,8 @@ + extern ulong back_log; + extern char language[FN_REFLEN]; + extern ulong server_id, concurrency; ++/* flashcache */ ++extern int cachedev_fd; + extern time_t server_start_time, flush_status_time; + extern char *opt_mysql_tmpdir, mysql_charsets_dir[]; + extern int mysql_unpacked_real_data_home_len; +diff -ruN a/sql/mysqld.cc b/sql/mysqld.cc +--- a/sql/mysqld.cc 2010-07-28 16:47:58.565318871 +0400 ++++ b/sql/mysqld.cc 2010-07-28 16:48:03.004544367 +0400 +@@ -86,6 +86,11 @@ + #ifdef HAVE_SYS_PRCTL_H + #include + #endif ++#if defined(__linux__) ++#include ++#include ++#include "flashcache_ioctl.h" ++#endif//__linux__ + + #include + #include +@@ -481,6 +486,11 @@ + ulong specialflag=0; + ulong binlog_cache_use= 0, binlog_cache_disk_use= 0; + ulong max_connections, max_connect_errors; ++ ++/* flashcache */ ++int cachedev_fd; ++my_bool cachedev_enabled= FALSE; ++ + /** + Limit of the total number of prepared statements in the server. + Is necessary to protect the server against out-of-memory attacks. +@@ -4176,6 +4186,97 @@ + #define decrement_handler_count() + #endif /* defined(_WIN32) || defined(HAVE_SMEM) */ + ++#if defined(__linux__) ++/* ++ * Auto detect if we support flash cache on the host system. ++ * This needs to be called before we setuid away from root ++ * to avoid permission problems on opening the device node. ++ */ ++static void init_cachedev(void) ++{ ++ struct statfs stfs_data_home_dir; ++ struct statfs stfs; ++ struct mntent *ent; ++ pid_t pid = getpid(); ++ FILE *mounts; ++ char *error_message= NULL; ++ ++ // disabled by default ++ cachedev_fd = -1; ++ cachedev_enabled= FALSE; ++ ++ if (!mysql_data_home) ++ { ++ error_message= "mysql_data_home not set"; ++ goto epilogue; ++ } ++ ++ if (statfs(mysql_data_home, &stfs_data_home_dir) < 0) ++ { ++ error_message= "statfs failed"; ++ goto epilogue; ++ } ++ ++ mounts = setmntent("/etc/mtab", "r"); ++ if (mounts == NULL) ++ { ++ error_message= "setmntent failed"; ++ goto epilogue; ++ } ++ ++ while ((ent = getmntent(mounts)) != NULL) ++ { ++ if (statfs(ent->mnt_dir, &stfs) < 0) ++ continue; ++ if (memcmp(&stfs.f_fsid, &stfs_data_home_dir.f_fsid, sizeof(fsid_t)) == 0) ++ break; ++ } ++ endmntent(mounts); ++ ++ if (ent == NULL) ++ { ++ error_message= "getmntent loop failed"; ++ goto epilogue; ++ } ++ ++ cachedev_fd = open(ent->mnt_fsname, O_RDONLY); ++ if (cachedev_fd < 0) ++ { ++ error_message= "open flash device failed"; ++ goto epilogue; ++ } ++ ++ /* cleanup previous whitelistings */ ++ if (ioctl(cachedev_fd, FLASHCACHEDELALLWHITELIST, &pid) < 0) ++ { ++ close(cachedev_fd); ++ cachedev_fd = -1; ++ error_message= "ioctl failed"; ++ } else { ++ ioctl(cachedev_fd, FLASHCACHEADDWHITELIST, &pid); ++ } ++ ++epilogue: ++ sql_print_information("Flashcache bypass: %s", ++ (cachedev_fd > 0) ? "enabled" : "disabled"); ++ if (error_message) ++ sql_print_information("Flashcache setup error is : %s\n", error_message); ++ else ++ cachedev_enabled= TRUE; ++ ++} ++ ++static void cleanup_cachedev(void) ++{ ++ pid_t pid = getpid(); ++ ++ if (cachedev_enabled) { ++ ioctl(cachedev_fd, FLASHCACHEDELWHITELIST, &pid); ++ close(cachedev_fd); ++ cachedev_fd = -1; ++ } ++} ++#endif//__linux__ + + #ifndef EMBEDDED_LIBRARY + #ifndef DBUG_OFF +@@ -4430,6 +4531,10 @@ + test_lc_time_sz(); + #endif + ++#if defined(__linux__) ++ init_cachedev(); ++#endif//__linux__ ++ + /* + We have enough space for fiddling with the argv, continue + */ +@@ -4633,6 +4738,10 @@ + } + #endif + clean_up(1); ++#if defined(__linux__) ++ cleanup_cachedev(); ++#endif//__linux__ ++ + mysqld_exit(0); + } + +@@ -6446,6 +6555,7 @@ + {"Delayed_errors", (char*) &delayed_insert_errors, SHOW_LONG}, + {"Delayed_insert_threads", (char*) &delayed_insert_threads, SHOW_LONG_NOFLUSH}, + {"Delayed_writes", (char*) &delayed_insert_writes, SHOW_LONG}, ++ {"Flashcache_enabled", (char*) &cachedev_enabled, SHOW_BOOL }, + {"Flush_commands", (char*) &refresh_version, SHOW_LONG_NOFLUSH}, + {"Handler_commit", (char*) offsetof(STATUS_VAR, ha_commit_count), SHOW_LONG_STATUS}, + {"Handler_delete", (char*) offsetof(STATUS_VAR, ha_delete_count), SHOW_LONG_STATUS}, +diff -ruN a/sql/sql_lex.cc b/sql/sql_lex.cc +--- a/sql/sql_lex.cc 2010-07-28 16:47:58.555318714 +0400 ++++ b/sql/sql_lex.cc 2010-07-28 16:48:07.794069239 +0400 +@@ -384,6 +384,7 @@ + lex->describe= 0; + lex->subqueries= FALSE; + lex->view_prepare_mode= FALSE; ++ lex->disable_flashcache= FALSE; + lex->derived_tables= 0; + lex->safe_to_cache_query= 1; + lex->leaf_tables_insert= 0; +diff -ruN a/sql/sql_lex.h b/sql/sql_lex.h +--- a/sql/sql_lex.h 2010-07-28 16:47:58.575318748 +0400 ++++ b/sql/sql_lex.h 2010-07-28 16:48:08.405691834 +0400 +@@ -2297,6 +2297,7 @@ + */ + bool view_prepare_mode; + bool safe_to_cache_query; ++ bool disable_flashcache; + bool subqueries, ignore; + st_parsing_options parsing_options; + Alter_info alter_info; +diff -ruN a/sql/sql_select.cc b/sql/sql_select.cc +--- a/sql/sql_select.cc 2010-07-28 16:47:58.555318714 +0400 ++++ b/sql/sql_select.cc 2010-07-28 16:48:13.414069437 +0400 +@@ -54,6 +54,12 @@ + + #define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1)) + ++#include ++#include ++#if defined(__linux__) ++#include "flashcache_ioctl.h" ++#endif//__linux__ ++ + const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref", + "MAYBE_REF","ALL","range","index","fulltext", + "ref_or_null","unique_subquery","index_subquery", +@@ -265,8 +271,17 @@ + ulong setup_tables_done_option) + { + bool res; ++ pid_t pid; + register SELECT_LEX *select_lex = &lex->select_lex; + DBUG_ENTER("handle_select"); ++#if defined(__linux__) ++ if(lex->disable_flashcache && cachedev_fd > 0) ++ { ++ pid = syscall(SYS_gettid); ++ ioctl(cachedev_fd, FLASHCACHEADDNCPID, &pid); ++ } ++#endif//__linux__ ++ + MYSQL_SELECT_START(thd->query()); + + if (select_lex->master_unit()->is_union() || +@@ -301,6 +316,12 @@ + if (unlikely(res)) + result->abort_result_set(); + ++#if defined(__linux__) ++ if (lex->disable_flashcache && cachedev_fd > 0) ++ { ++ ioctl(cachedev_fd, FLASHCACHEDELNCPID, &pid); ++ } ++#endif//__linux__ + MYSQL_SELECT_DONE((int) res, (ulong) thd->limit_found_rows); + DBUG_RETURN(res); + } +diff -ruN a/sql/sql_yacc.yy b/sql/sql_yacc.yy +--- a/sql/sql_yacc.yy 2010-07-28 16:47:58.565318871 +0400 ++++ b/sql/sql_yacc.yy 2010-07-28 16:48:14.205317990 +0400 +@@ -1284,6 +1284,7 @@ + %token SQL_CACHE_SYM + %token SQL_CALC_FOUND_ROWS + %token SQL_NO_CACHE_SYM ++%token SQL_NO_FCACHE_SYM + %token SQL_SMALL_RESULT + %token SQL_SYM /* SQL-2003-R */ + %token SQL_THREAD +@@ -7350,6 +7351,10 @@ + Lex->select_lex.sql_cache= SELECT_LEX::SQL_NO_CACHE; + } + } ++ | SQL_NO_FCACHE_SYM ++ { ++ Lex->disable_flashcache= TRUE; ++ } + | SQL_CACHE_SYM + { + /* diff --git a/suppress_log_warning_1592.patch b/suppress_log_warning_1592.patch new file mode 100644 index 000000000000..37448d9376ee --- /dev/null +++ b/suppress_log_warning_1592.patch @@ -0,0 +1,91 @@ +# name : suppress_log_warning_1592.patch +# introduced : 11 or before +# maintainer : Oleg +# +#!!! notice !!! +# Any small change to this file in the main branch +# should be done or reviewed by the maintainer! +diff -ruN a/sql/mysqld.cc b/sql/mysqld.cc +--- a/sql/mysqld.cc 2010-11-16 23:20:22.000000000 +0500 ++++ b/sql/mysqld.cc 2010-11-16 23:22:07.000000000 +0500 +@@ -392,6 +392,7 @@ + my_bool opt_enable_named_pipe= 0; + my_bool opt_local_infile, opt_slave_compressed_protocol; + my_bool opt_safe_user_create = 0; ++my_bool opt_suppress_log_warning_1592= FALSE; + my_bool opt_show_slave_auth_info; + my_bool opt_log_slave_updates= 0; + char *opt_slave_skip_errors; +diff -ruN a/sql/mysqld.h b/sql/mysqld.h +--- a/sql/mysqld.h 2010-11-16 23:20:22.000000000 +0500 ++++ b/sql/mysqld.h 2010-11-16 23:21:10.000000000 +0500 +@@ -104,6 +104,7 @@ + extern uint connection_count; + extern my_bool opt_safe_user_create; + extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap; ++extern my_bool opt_suppress_log_warning_1592; + extern my_bool opt_slave_compressed_protocol, use_temp_pool; + extern ulong slave_exec_mode_options; + extern ulonglong slave_type_conversions_options; +diff -ruN a/sql/sys_vars.cc b/sql/sys_vars.cc +--- a/sql/sys_vars.cc 2010-11-16 23:20:22.000000000 +0500 ++++ b/sql/sys_vars.cc 2010-11-16 23:30:38.000000000 +0500 +@@ -1430,6 +1430,12 @@ + READ_ONLY GLOBAL_VAR(mysqld_port), CMD_LINE(REQUIRED_ARG, 'P'), + VALID_RANGE(0, UINT_MAX32), DEFAULT(0), BLOCK_SIZE(1)); + ++static Sys_var_mybool Sys_suppress_log_warning_1592( ++ "suppress_log_warning_1592", ++ "suppress warning about unsafe statements for binary logging", ++ GLOBAL_VAR(opt_suppress_log_warning_1592), CMD_LINE(OPT_ARG), ++ DEFAULT(FALSE)); ++ + static Sys_var_ulong Sys_preload_buff_size( + "preload_buffer_size", + "The size of the buffer that is allocated when preloading indexes", +diff -ruN a/sql/sql_class.cc b/sql/sql_class.cc +--- a/sql/sql_class.cc 2010-11-03 03:01:14.000000000 +0500 ++++ b/sql/sql_class.cc 2010-11-17 00:06:49.000000000 +0500 +@@ -4503,7 +4503,7 @@ + ER_BINLOG_UNSAFE_STATEMENT, + ER(ER_BINLOG_UNSAFE_STATEMENT), + ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type])); +- if (global_system_variables.log_warnings) ++ if (global_system_variables.log_warnings && !opt_suppress_log_warning_1592) + { + char buf[MYSQL_ERRMSG_SIZE * 2]; + sprintf(buf, ER(ER_BINLOG_UNSAFE_STATEMENT), +diff -ruN a/mysql-test/r/mysqld--help-notwin.result b/mysql-test/r/mysqld--help-notwin.result +--- a/mysql-test/r/mysqld--help-notwin.result 2010-11-03 03:01:12.000000000 +0500 ++++ b/mysql-test/r/mysqld--help-notwin.result 2010-11-17 00:15:40.000000000 +0500 +@@ -657,6 +657,9 @@ + replication. + --sql-mode=name Syntax: sql-mode=mode[,mode[,mode...]]. See the manual + for the complete list of valid sql modes ++ --suppress-log-warning-1592 ++ suppress warning about unsafe statements for binary ++ logging + -s, --symbolic-links + Enable symbolic link support. + --sync-binlog=# Synchronously flush binary log to disk after every #th +@@ -916,6 +919,7 @@ + sort-buffer-size 2097152 + sporadic-binlog-dump-fail FALSE + sql-mode ++suppress-log-warning-1592 FALSE + symbolic-links FALSE + sync-binlog 0 + sync-frm TRUE +diff -ruN a/mysql-test/suite/sys_vars/r/all_vars.result b/mysql-test/suite/sys_vars/r/all_vars.result +--- a/mysql-test/suite/sys_vars/r/all_vars.result 2010-11-03 01:01:13.000000000 +0300 ++++ b/mysql-test/suite/sys_vars/r/all_vars.result 2010-11-23 20:04:40.000000000 +0300 +@@ -10,7 +10,9 @@ + select variable_name as `There should be *no* variables listed below:` from t2 + left join t1 on variable_name=test_name where test_name is null; + There should be *no* variables listed below: ++SUPPRESS_LOG_WARNING_1592 + INNODB_FILE_FORMAT_MAX ++SUPPRESS_LOG_WARNING_1592 + INNODB_FILE_FORMAT_MAX + drop table t1; + drop table t2; diff --git a/uninstall_tests.sh b/uninstall_tests.sh new file mode 100755 index 000000000000..802f941f7ae0 --- /dev/null +++ b/uninstall_tests.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env sh +text -z ${PERCONA_SERVER} && PERCONA_SERVER=Percona-Server +echo PERCONA_SERVER=$PERCONA_SERVER +uninstall_files() +{ + for file in `(cd $1; ls *.$2)`; do + echo "uninstall $1/$file from ${PERCONA_SERVER}/mysql-test/$3/$file" + rm ${PERCONA_SERVER}/mysql-test/$3/$file + done; +} +uninstall_path() +{ + echo "Installing mysql-test files: $2" + uninstall_files $1 opt t; + uninstall_files $1 test t; + uninstall_files $1 result r; + uninstall_files $1 inc include; +} + +uninstall_path mysql-test "global" +for test_name in `cat series`; do + uninstall_path mysql-test/$test_name $test_name +done +echo "Done" diff --git a/userstat.patch b/userstat.patch new file mode 100644 index 000000000000..153138cb2bae --- /dev/null +++ b/userstat.patch @@ -0,0 +1,3450 @@ +# name : userstat.patch +# introduced : 11 or before +# maintainer : Yasufumi +# +#!!! notice !!! +# Any small change to this file in the main branch +# should be done or reviewed by the maintainer! +diff -ruN a/configure b/configure +--- a/configure 2010-08-27 14:28:05.621275596 +0900 ++++ b/configure 2010-08-27 15:10:33.736074033 +0900 +@@ -38009,7 +38009,7 @@ + realpath rename rint rwlock_init setupterm \ + shmget shmat shmdt shmctl sigaction sigemptyset sigaddset \ + sighold sigset sigthreadmask port_create sleep \ +- snprintf socket stpcpy strcasecmp strerror strsignal strnlen strpbrk strstr \ ++ snprintf socket strsep stpcpy strcasecmp strerror strsignal strnlen strpbrk strstr \ + strtol strtoll strtoul strtoull tell tempnam thr_setconcurrency vidattr \ + posix_fallocate backtrace backtrace_symbols backtrace_symbols_fd printstack + do +diff -ruN a/configure.in b/configure.in +--- a/configure.in 2010-08-04 02:24:24.000000000 +0900 ++++ b/configure.in 2010-08-27 15:10:33.737073307 +0900 +@@ -2086,7 +2086,7 @@ + realpath rename rint rwlock_init setupterm \ + shmget shmat shmdt shmctl sigaction sigemptyset sigaddset \ + sighold sigset sigthreadmask port_create sleep \ +- snprintf socket stpcpy strcasecmp strerror strsignal strnlen strpbrk strstr \ ++ snprintf socket strsep stpcpy strcasecmp strerror strsignal strnlen strpbrk strstr \ + strtol strtoll strtoul strtoull tell tempnam thr_setconcurrency vidattr \ + posix_fallocate backtrace backtrace_symbols backtrace_symbols_fd printstack) + +diff -ruN a/include/config.h.in b/include/config.h.in +--- a/include/config.h.in 2010-08-04 02:28:40.000000000 +0900 ++++ b/include/config.h.in 2010-08-27 15:10:33.740077919 +0900 +@@ -802,6 +802,9 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_STDLIB_H + ++/* Define to 1 if you have the `strsep' function. */ ++#undef HAVE_STRSEP ++ + /* Define to 1 if you have the `stpcpy' function. */ + #undef HAVE_STPCPY + +diff -ruN a/include/mysql/plugin.h b/include/mysql/plugin.h +--- a/include/mysql/plugin.h 2010-08-27 14:38:08.682439958 +0900 ++++ b/include/mysql/plugin.h 2010-08-27 15:10:33.742003842 +0900 +@@ -705,6 +705,9 @@ + unsigned long thd_log_slow_verbosity(const MYSQL_THD thd); + int thd_opt_slow_log(); + #define EXTENDED_SLOWLOG ++ ++#define EXTENDED_FOR_USERSTAT ++ + /** + Create a temporary file. + +diff -ruN a/include/mysql_com.h b/include/mysql_com.h +--- a/include/mysql_com.h 2010-08-04 02:24:30.000000000 +0900 ++++ b/include/mysql_com.h 2010-08-27 15:10:33.743072186 +0900 +@@ -29,6 +29,7 @@ + + #define SERVER_VERSION_LENGTH 60 + #define SQLSTATE_LENGTH 5 ++#define LIST_PROCESS_HOST_LEN 64 + + /* + USER_HOST_BUFF_SIZE -- length of string buffer, that is enough to contain +@@ -115,6 +116,12 @@ + thread */ + #define REFRESH_MASTER 128 /* Remove all bin logs in the index + and truncate the index */ ++#define REFRESH_TABLE_STATS 256 /* Refresh table stats hash table */ ++#define REFRESH_INDEX_STATS 512 /* Refresh index stats hash table */ ++#define REFRESH_USER_STATS 1024 /* Refresh user stats hash table */ ++#define REFRESH_SLOW_QUERY_LOG 2048 /* Flush slow query log and rotate*/ ++#define REFRESH_CLIENT_STATS 4096 /* Refresh client stats hash table */ ++#define REFRESH_THREAD_STATS 8192 /* Refresh thread stats hash table */ + + /* The following can't be set with mysql_refresh() */ + #define REFRESH_READ_LOCK 16384 /* Lock tables for read */ +diff -ruN a/patch_info/userstats.info b/patch_info/userstats.info +--- /dev/null 1970-01-01 09:00:00.000000000 +0900 ++++ b/patch_info/userstats.info 2010-08-27 15:10:33.744161257 +0900 +@@ -0,0 +1,11 @@ ++File=userstats.patch ++Name=SHOW USER/TABLE/INDEX statistics ++Version=V2 ++Author=Google ++License=GPL ++Comment=Added INFORMATION_SCHEMA.*_STATISTICS ++2008-12-01 ++YK: fix behavior for prepared statements ++ ++2008-11-26 ++YK: add switch variable "userstat_running" to control INFORMATION_SCHEMA.*_STATISTICS (default:OFF) +diff -ruN a/sql/handler.cc b/sql/handler.cc +--- a/sql/handler.cc 2010-08-04 02:24:27.000000000 +0900 ++++ b/sql/handler.cc 2010-08-27 15:10:33.749058856 +0900 +@@ -1194,6 +1194,8 @@ + if (cookie) + tc_log->unlog(cookie, xid); + DBUG_EXECUTE_IF("crash_commit_after", abort();); ++ if (is_real_trans) ++ thd->diff_commit_trans++; + end: + if (rw_trans) + start_waiting_global_read_lock(thd); +@@ -1324,6 +1326,8 @@ + /* Always cleanup. Even if there nht==0. There may be savepoints. */ + if (is_real_trans) + thd->transaction.cleanup(); ++ ++ thd->diff_rollback_trans++; + #endif /* USING_TRANSACTIONS */ + if (all) + thd->transaction_rollback_request= FALSE; +@@ -1762,6 +1766,7 @@ + ha_info->reset(); /* keep it conveniently zero-filled */ + } + trans->ha_list= sv->ha_list; ++ thd->diff_rollback_trans++; + DBUG_RETURN(error); + } + +@@ -2122,6 +2127,8 @@ + dup_ref=ref+ALIGN_SIZE(ref_length); + cached_table_flags= table_flags(); + } ++ rows_read = rows_changed = 0; ++ memset(index_rows_read, 0, sizeof(index_rows_read)); + DBUG_RETURN(error); + } + +@@ -3571,6 +3578,111 @@ + return; + } + ++// Updates the global table stats with the TABLE this handler represents. ++void handler::update_global_table_stats() { ++ if (!opt_userstat_running) { ++ rows_read = rows_changed = 0; ++ return; ++ } ++ ++ if (!rows_read && !rows_changed) return; // Nothing to update. ++ // table_cache_key is db_name + '\0' + table_name + '\0'. ++ if (!table->s || !table->s->table_cache_key.str || !table->s->table_name.str) return; ++ ++ TABLE_STATS* table_stats; ++ char key[NAME_LEN * 2 + 2]; ++ // [db] + '.' + [table] ++ sprintf(key, "%s.%s", table->s->table_cache_key.str, table->s->table_name.str); ++ ++ pthread_mutex_lock(&LOCK_global_table_stats); ++ // Gets the global table stats, creating one if necessary. ++ if (!(table_stats = (TABLE_STATS*)hash_search(&global_table_stats, ++ (uchar*)key, ++ strlen(key)))) { ++ if (!(table_stats = ((TABLE_STATS*) ++ my_malloc(sizeof(TABLE_STATS), MYF(MY_WME | MY_ZEROFILL))))) { ++ // Out of memory. ++ sql_print_error("Allocating table stats failed."); ++ goto end; ++ } ++ strncpy(table_stats->table, key, sizeof(table_stats->table)); ++ table_stats->rows_read = 0; ++ table_stats->rows_changed = 0; ++ table_stats->rows_changed_x_indexes = 0; ++ table_stats->engine_type = (int) ht->db_type; ++ ++ if (my_hash_insert(&global_table_stats, (uchar*)table_stats)) { ++ // Out of memory. ++ sql_print_error("Inserting table stats failed."); ++ my_free((char*)table_stats, 0); ++ goto end; ++ } ++ } ++ // Updates the global table stats. ++ table_stats->rows_read += rows_read; ++ table_stats->rows_changed += rows_changed; ++ table_stats->rows_changed_x_indexes += ++ rows_changed * (table->s->keys ? table->s->keys : 1); ++ current_thd->diff_total_read_rows += rows_read; ++ rows_read = rows_changed = 0; ++end: ++ pthread_mutex_unlock(&LOCK_global_table_stats); ++} ++ ++// Updates the global index stats with this handler's accumulated index reads. ++void handler::update_global_index_stats() { ++ // table_cache_key is db_name + '\0' + table_name + '\0'. ++ if (!table->s || !table->s->table_cache_key.str || !table->s->table_name.str) return; ++ ++ if (!opt_userstat_running) { ++ for (uint x = 0; x < table->s->keys; x++) { ++ index_rows_read[x] = 0; ++ } ++ return; ++ } ++ ++ for (uint x = 0; x < table->s->keys; x++) { ++ if (index_rows_read[x]) { ++ // Rows were read using this index. ++ KEY* key_info = &table->key_info[x]; ++ ++ if (!key_info->name) continue; ++ ++ INDEX_STATS* index_stats; ++ char key[NAME_LEN * 3 + 3]; ++ // [db] + '.' + [table] + '.' + [index] ++ sprintf(key, "%s.%s.%s", table->s->table_cache_key.str, ++ table->s->table_name.str, key_info->name); ++ ++ pthread_mutex_lock(&LOCK_global_index_stats); ++ // Gets the global index stats, creating one if necessary. ++ if (!(index_stats = (INDEX_STATS*)hash_search(&global_index_stats, ++ (uchar*)key, ++ strlen(key)))) { ++ if (!(index_stats = ((INDEX_STATS*) ++ my_malloc(sizeof(INDEX_STATS), MYF(MY_WME | MY_ZEROFILL))))) { ++ // Out of memory. ++ sql_print_error("Allocating index stats failed."); ++ goto end; ++ } ++ strncpy(index_stats->index, key, sizeof(index_stats->index)); ++ index_stats->rows_read = 0; ++ ++ if (my_hash_insert(&global_index_stats, (uchar*)index_stats)) { ++ // Out of memory. ++ sql_print_error("Inserting index stats failed."); ++ my_free((char*)index_stats, 0); ++ goto end; ++ } ++ } ++ // Updates the global index stats. ++ index_stats->rows_read += index_rows_read[x]; ++ index_rows_read[x] = 0; ++end: ++ pthread_mutex_unlock(&LOCK_global_index_stats); ++ } ++ } ++} + + /**************************************************************************** + ** Some general functions that isn't in the handler class +diff -ruN a/sql/handler.h b/sql/handler.h +--- a/sql/handler.h 2010-08-04 02:24:27.000000000 +0900 ++++ b/sql/handler.h 2010-08-27 15:10:33.753058869 +0900 +@@ -30,6 +30,10 @@ + + #define USING_TRANSACTIONS + ++#if MAX_KEY > 128 ++#error MAX_KEY is too large. Values up to 128 are supported. ++#endif ++ + // the following is for checking tables + + #define HA_ADMIN_ALREADY_DONE 1 +@@ -1121,6 +1125,9 @@ + bool locked; + bool implicit_emptied; /* Can be !=0 only if HEAP */ + const COND *pushed_cond; ++ ulonglong rows_read; ++ ulonglong rows_changed; ++ ulonglong index_rows_read[MAX_KEY]; + /** + next_insert_id is the next value which should be inserted into the + auto_increment column: in a inserting-multi-row statement (like INSERT +@@ -1158,9 +1165,11 @@ + ref_length(sizeof(my_off_t)), + ft_handler(0), inited(NONE), + locked(FALSE), implicit_emptied(0), +- pushed_cond(0), next_insert_id(0), insert_id_for_cur_row(0), ++ pushed_cond(0), rows_read(0), rows_changed(0), next_insert_id(0), insert_id_for_cur_row(0), + auto_inc_intervals_count(0) +- {} ++ { ++ memset(index_rows_read, 0, sizeof(index_rows_read)); ++ } + virtual ~handler(void) + { + DBUG_ASSERT(locked == FALSE); +@@ -1284,6 +1293,8 @@ + { + table= table_arg; + table_share= share; ++ rows_read = rows_changed = 0; ++ memset(index_rows_read, 0, sizeof(index_rows_read)); + } + virtual double scan_time() + { return ulonglong2double(stats.data_file_length) / IO_SIZE + 2; } +@@ -1628,6 +1639,8 @@ + virtual bool is_crashed() const { return 0; } + virtual bool auto_repair() const { return 0; } + ++ void update_global_table_stats(); ++ void update_global_index_stats(); + + #define CHF_CREATE_FLAG 0 + #define CHF_DELETE_FLAG 1 +diff -ruN a/sql/lex.h b/sql/lex.h +--- a/sql/lex.h 2010-08-27 14:29:26.009071592 +0900 ++++ b/sql/lex.h 2010-08-27 15:10:33.755063742 +0900 +@@ -106,6 +106,7 @@ + { "CHECKSUM", SYM(CHECKSUM_SYM)}, + { "CIPHER", SYM(CIPHER_SYM)}, + { "CLIENT", SYM(CLIENT_SYM)}, ++ { "CLIENT_STATISTICS", SYM(CLIENT_STATS_SYM)}, + { "CLOSE", SYM(CLOSE_SYM)}, + { "COALESCE", SYM(COALESCE)}, + { "CODE", SYM(CODE_SYM)}, +@@ -245,6 +246,7 @@ + { "IN", SYM(IN_SYM)}, + { "INDEX", SYM(INDEX_SYM)}, + { "INDEXES", SYM(INDEXES)}, ++ { "INDEX_STATISTICS", SYM(INDEX_STATS_SYM)}, + { "INFILE", SYM(INFILE)}, + { "INITIAL_SIZE", SYM(INITIAL_SIZE_SYM)}, + { "INNER", SYM(INNER_SYM)}, +@@ -478,6 +480,7 @@ + { "SIGNED", SYM(SIGNED_SYM)}, + { "SIMPLE", SYM(SIMPLE_SYM)}, + { "SLAVE", SYM(SLAVE)}, ++ { "SLOW", SYM(SLOW_SYM)}, + { "SNAPSHOT", SYM(SNAPSHOT_SYM)}, + { "SMALLINT", SYM(SMALLINT)}, + { "SOCKET", SYM(SOCKET_SYM)}, +@@ -527,12 +530,14 @@ + { "TABLES", SYM(TABLES)}, + { "TABLESPACE", SYM(TABLESPACE)}, + { "TABLE_CHECKSUM", SYM(TABLE_CHECKSUM_SYM)}, ++ { "TABLE_STATISTICS", SYM(TABLE_STATS_SYM)}, + { "TEMPORARY", SYM(TEMPORARY)}, + { "TEMPTABLE", SYM(TEMPTABLE_SYM)}, + { "TERMINATED", SYM(TERMINATED)}, + { "TEXT", SYM(TEXT_SYM)}, + { "THAN", SYM(THAN_SYM)}, + { "THEN", SYM(THEN_SYM)}, ++ { "THREAD_STATISTICS", SYM(THREAD_STATS_SYM)}, + { "TIME", SYM(TIME_SYM)}, + { "TIMESTAMP", SYM(TIMESTAMP)}, + { "TIMESTAMPADD", SYM(TIMESTAMP_ADD)}, +@@ -568,6 +573,7 @@ + { "USE", SYM(USE_SYM)}, + { "USER", SYM(USER)}, + { "USER_RESOURCES", SYM(RESOURCES)}, ++ { "USER_STATISTICS", SYM(USER_STATS_SYM)}, + { "USE_FRM", SYM(USE_FRM)}, + { "USING", SYM(USING)}, + { "UTC_DATE", SYM(UTC_DATE_SYM)}, +diff -ruN a/sql/log.cc b/sql/log.cc +--- a/sql/log.cc 2010-08-27 14:43:41.986138797 +0900 ++++ b/sql/log.cc 2010-08-27 15:10:33.761058932 +0900 +@@ -826,6 +826,13 @@ + mysql_slow_log.reopen_file(); + } + ++void Log_to_file_event_handler::flush_slow_log() ++{ ++ /* reopen slow log file */ ++ if (opt_slow_log) ++ mysql_slow_log.reopen_file(); ++} ++ + /* + Log error with all enabled log event handlers + +@@ -937,6 +944,21 @@ + return rc; + } + ++bool LOGGER::flush_slow_log(THD *thd) ++{ ++ /* ++ Now we lock logger, as nobody should be able to use logging routines while ++ log tables are closed ++ */ ++ logger.lock_exclusive(); ++ ++ /* reopen log files */ ++ file_log_handler->flush_slow_log(); ++ ++ /* end of log flush */ ++ logger.unlock(); ++ return 0; ++} + + /* + Log slow query with all enabled log event handlers +@@ -4491,6 +4513,8 @@ + thd->first_successful_insert_id_in_prev_stmt_for_binlog); + if (e.write(file)) + goto err; ++ if (file == &log_file) ++ thd->binlog_bytes_written += e.data_written; + } + if (thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements() > 0) + { +@@ -4502,12 +4526,16 @@ + minimum()); + if (e.write(file)) + goto err; ++ if (file == &log_file) ++ thd->binlog_bytes_written += e.data_written; + } + if (thd->rand_used) + { + Rand_log_event e(thd,thd->rand_saved_seed1,thd->rand_saved_seed2); + if (e.write(file)) + goto err; ++ if (file == &log_file) ++ thd->binlog_bytes_written += e.data_written; + } + if (thd->user_var_events.elements) + { +@@ -4523,6 +4551,8 @@ + user_var_event->charset_number); + if (e.write(file)) + goto err; ++ if (file == &log_file) ++ thd->binlog_bytes_written += e.data_written; + } + } + } +@@ -4535,6 +4565,8 @@ + if (event_info->write(file) || + DBUG_EVALUATE_IF("injecting_fault_writing", 1, 0)) + goto err; ++ if (file == &log_file) ++ thd->binlog_bytes_written += event_info->data_written; + + if (file == &log_file) // we are writing to the real log (disk) + { +@@ -4680,7 +4712,7 @@ + be reset as a READ_CACHE to be able to read the contents from it. + */ + +-int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log) ++int MYSQL_BIN_LOG::write_cache(THD *thd, IO_CACHE *cache, bool lock_log, bool sync_log) + { + Mutex_sentry sentry(lock_log ? &LOCK_log : NULL); + +@@ -4728,6 +4760,7 @@ + /* write the first half of the split header */ + if (my_b_write(&log_file, header, carry)) + return ER_ERROR_ON_WRITE; ++ thd->binlog_bytes_written += carry; + + /* + copy fixed second half of header to cache so the correct +@@ -4796,6 +4829,7 @@ + /* Write data to the binary log file */ + if (my_b_write(&log_file, cache->read_pos, length)) + return ER_ERROR_ON_WRITE; ++ thd->binlog_bytes_written += length; + cache->read_pos=cache->read_end; // Mark buffer used up + } while ((length= my_b_fill(cache))); + +@@ -4918,21 +4952,24 @@ + */ + if (qinfo.write(&log_file)) + goto err; ++ thd->binlog_bytes_written += qinfo.data_written; + + DBUG_EXECUTE_IF("crash_before_writing_xid", + { +- if ((write_error= write_cache(cache, false, true))) ++ if ((write_error= write_cache(thd, cache, false, true))) + DBUG_PRINT("info", ("error writing binlog cache: %d", + write_error)); + DBUG_PRINT("info", ("crashing before writing xid")); + abort(); + }); + +- if ((write_error= write_cache(cache, false, false))) ++ if ((write_error= write_cache(thd, cache, false, false))) + goto err; + + if (commit_event && commit_event->write(&log_file)) + goto err; ++ if (commit_event) ++ thd->binlog_bytes_written += commit_event->data_written; + + if (incident && write_incident(thd, FALSE)) + goto err; +diff -ruN a/sql/log.h b/sql/log.h +--- a/sql/log.h 2010-08-27 14:38:08.690071101 +0900 ++++ b/sql/log.h 2010-08-27 15:13:33.762976324 +0900 +@@ -361,7 +361,7 @@ + bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event, bool incident); + + bool write_incident(THD *thd, bool lock); +- int write_cache(IO_CACHE *cache, bool lock_log, bool flush_and_sync); ++ int write_cache(THD *thd, IO_CACHE *cache, bool lock_log, bool flush_and_sync); + void set_write_error(THD *thd); + bool check_write_error(THD *thd); + +@@ -499,6 +499,7 @@ + const char *sql_text, uint sql_text_len, + CHARSET_INFO *client_cs); + void flush(); ++ void flush_slow_log(); + void init_pthread_objects(); + MYSQL_QUERY_LOG *get_mysql_slow_log() { return &mysql_slow_log; } + MYSQL_QUERY_LOG *get_mysql_log() { return &mysql_log; } +@@ -543,6 +544,7 @@ + void init_base(); + void init_log_tables(); + bool flush_logs(THD *thd); ++ bool flush_slow_log(THD *thd); + /* Perform basic logger cleanup. this will leave e.g. error log open. */ + void cleanup_base(); + /* Free memory. Nothing could be logged after this function is called */ +diff -ruN a/sql/mysql_priv.h b/sql/mysql_priv.h +--- a/sql/mysql_priv.h 2010-08-27 14:38:08.699057407 +0900 ++++ b/sql/mysql_priv.h 2010-08-27 15:10:33.805058568 +0900 +@@ -1139,7 +1139,17 @@ + bool multi_delete_set_locks_and_link_aux_tables(LEX *lex); + void init_max_user_conn(void); + void init_update_queries(void); ++void init_global_user_stats(void); ++void init_global_table_stats(void); ++void init_global_index_stats(void); ++void init_global_client_stats(void); ++void init_global_thread_stats(void); + void free_max_user_conn(void); ++void free_global_user_stats(void); ++void free_global_table_stats(void); ++void free_global_index_stats(void); ++void free_global_client_stats(void); ++void free_global_thread_stats(void); + pthread_handler_t handle_bootstrap(void *arg); + int mysql_execute_command(THD *thd); + bool do_command(THD *thd); +@@ -2014,6 +2024,7 @@ + extern ulong max_connect_errors, connect_timeout; + extern ulong slave_net_timeout, slave_trans_retries; + extern uint max_user_connections; ++extern ulonglong denied_connections; + extern ulong what_to_log,flush_time; + extern ulong query_buff_size; + extern ulong max_prepared_stmt_count, prepared_stmt_count; +@@ -2067,6 +2078,7 @@ + extern my_bool opt_slave_compressed_protocol, use_temp_pool; + extern ulong slave_exec_mode_options; + extern my_bool opt_readonly, lower_case_file_system; ++extern my_bool opt_userstat_running, opt_thread_statistics; + 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; +@@ -2131,6 +2143,15 @@ + extern struct system_variables max_system_variables; + extern struct system_status_var global_status_var; + extern struct rand_struct sql_rand; ++extern HASH global_user_stats; ++extern HASH global_client_stats; ++extern HASH global_thread_stats; ++extern pthread_mutex_t LOCK_global_user_client_stats; ++extern HASH global_table_stats; ++extern pthread_mutex_t LOCK_global_table_stats; ++extern HASH global_index_stats; ++extern pthread_mutex_t LOCK_global_index_stats; ++extern pthread_mutex_t LOCK_stats; + + extern const char *opt_date_time_formats[]; + extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[]; +diff -ruN a/sql/mysqld.cc b/sql/mysqld.cc +--- a/sql/mysqld.cc 2010-08-27 14:43:41.996021369 +0900 ++++ b/sql/mysqld.cc 2010-08-27 15:10:33.772058694 +0900 +@@ -533,6 +533,7 @@ + uint opt_debug_sync_timeout= 0; + #endif /* defined(ENABLED_DEBUG_SYNC) */ + my_bool opt_old_style_user_limits= 0, trust_function_creators= 0; ++my_bool opt_userstat_running= 0, opt_thread_statistics= 0; + /* + True if there is at least one per-hour limit for some user, so we should + check them before each query (and possibly reset counters when hour is +@@ -581,6 +582,7 @@ + ulong binlog_cache_use= 0, binlog_cache_disk_use= 0; + ulong max_connections, max_connect_errors; + uint max_user_connections= 0; ++ulonglong denied_connections = 0; + /** + Limit of the total number of prepared statements in the server. + Is necessary to protect the server against out-of-memory attacks. +@@ -682,6 +684,10 @@ + LOCK_global_system_variables, + LOCK_user_conn, LOCK_slave_list, LOCK_active_mi, + LOCK_connection_count; ++pthread_mutex_t LOCK_stats; ++pthread_mutex_t LOCK_global_user_client_stats; ++pthread_mutex_t LOCK_global_table_stats; ++pthread_mutex_t LOCK_global_index_stats; + /** + The below lock protects access to two global server variables: + max_prepared_stmt_count and prepared_stmt_count. These variables +@@ -1367,6 +1373,11 @@ + x_free(opt_secure_file_priv); + bitmap_free(&temp_pool); + free_max_user_conn(); ++ free_global_user_stats(); ++ free_global_client_stats(); ++ free_global_thread_stats(); ++ free_global_table_stats(); ++ free_global_index_stats(); + #ifdef HAVE_REPLICATION + end_slave_list(); + #endif +@@ -1483,6 +1494,10 @@ + (void) pthread_cond_destroy(&COND_thread_cache); + (void) pthread_cond_destroy(&COND_flush_thread_cache); + (void) pthread_cond_destroy(&COND_manager); ++ (void) pthread_mutex_destroy(&LOCK_stats); ++ (void) pthread_mutex_destroy(&LOCK_global_user_client_stats); ++ (void) pthread_mutex_destroy(&LOCK_global_table_stats); ++ (void) pthread_mutex_destroy(&LOCK_global_index_stats); + } + + #endif /*EMBEDDED_LIBRARY*/ +@@ -3172,6 +3187,7 @@ + {"show_binlog_events", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_BINLOG_EVENTS]), SHOW_LONG_STATUS}, + {"show_binlogs", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_BINLOGS]), SHOW_LONG_STATUS}, + {"show_charsets", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CHARSETS]), SHOW_LONG_STATUS}, ++ {"show_client_statistics",(char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CLIENT_STATS]), SHOW_LONG_STATUS}, + {"show_collations", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_COLLATIONS]), SHOW_LONG_STATUS}, + {"show_column_types", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_COLUMN_TYPES]), SHOW_LONG_STATUS}, + {"show_contributors", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CONTRIBUTORS]), SHOW_LONG_STATUS}, +@@ -3193,6 +3209,7 @@ + #endif + {"show_function_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STATUS_FUNC]), SHOW_LONG_STATUS}, + {"show_grants", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_GRANTS]), SHOW_LONG_STATUS}, ++ {"show_index_statistics",(char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_INDEX_STATS]), SHOW_LONG_STATUS}, + {"show_keys", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_KEYS]), SHOW_LONG_STATUS}, + {"show_master_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_MASTER_STAT]), SHOW_LONG_STATUS}, + {"show_new_master", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_NEW_MASTER]), SHOW_LONG_STATUS}, +@@ -3211,9 +3228,12 @@ + {"show_slave_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_SLAVE_STAT]), SHOW_LONG_STATUS}, + {"show_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STATUS]), SHOW_LONG_STATUS}, + {"show_storage_engines", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STORAGE_ENGINES]), SHOW_LONG_STATUS}, ++ {"show_table_statistics",(char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLE_STATS]), SHOW_LONG_STATUS}, + {"show_table_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLE_STATUS]), SHOW_LONG_STATUS}, + {"show_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLES]), SHOW_LONG_STATUS}, ++ {"show_thread_statistics",(char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_THREAD_STATS]), SHOW_LONG_STATUS}, + {"show_triggers", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TRIGGERS]), SHOW_LONG_STATUS}, ++ {"show_user_statistics", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_USER_STATS]), SHOW_LONG_STATUS}, + {"show_variables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_VARIABLES]), SHOW_LONG_STATUS}, + {"show_warnings", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_WARNS]), SHOW_LONG_STATUS}, + {"slave_start", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_START]), SHOW_LONG_STATUS}, +@@ -3652,6 +3672,10 @@ + #endif + (void) pthread_mutex_init(&LOCK_server_started, MY_MUTEX_INIT_FAST); + (void) pthread_cond_init(&COND_server_started,NULL); ++ (void) pthread_mutex_init(&LOCK_stats, MY_MUTEX_INIT_FAST); ++ (void) pthread_mutex_init(&LOCK_global_user_client_stats, MY_MUTEX_INIT_FAST); ++ (void) pthread_mutex_init(&LOCK_global_table_stats, MY_MUTEX_INIT_FAST); ++ (void) pthread_mutex_init(&LOCK_global_index_stats, MY_MUTEX_INIT_FAST); + sp_cache_init(); + #ifdef HAVE_EVENT_SCHEDULER + Events::init_mutexes(); +@@ -4053,6 +4077,9 @@ + if (!errmesg[0][0]) + unireg_abort(1); + ++ init_global_table_stats(); ++ init_global_index_stats(); ++ + /* We have to initialize the storage engines before CSV logging */ + if (ha_init()) + { +@@ -4199,6 +4226,9 @@ + + init_max_user_conn(); + init_update_queries(); ++ init_global_user_stats(); ++ init_global_client_stats(); ++ init_global_thread_stats(); + DBUG_RETURN(0); + } + +@@ -5016,6 +5046,7 @@ + + DBUG_PRINT("error",("Too many connections")); + close_connection(thd, ER_CON_COUNT_ERROR, 1); ++ statistic_increment(denied_connections, &LOCK_status); + delete thd; + DBUG_VOID_RETURN; + } +@@ -5800,6 +5831,8 @@ + OPT_SLAVE_EXEC_MODE, + OPT_GENERAL_LOG_FILE, + OPT_SLOW_QUERY_LOG_FILE, ++ OPT_USERSTAT_RUNNING, ++ OPT_THREAD_STATISTICS, + OPT_USE_GLOBAL_LONG_QUERY_TIME, + OPT_USE_GLOBAL_LOG_SLOW_CONTROL, + OPT_SLOW_QUERY_LOG_MICROSECONDS_TIMESTAMP, +@@ -7292,6 +7325,14 @@ + &max_system_variables.net_wait_timeout, 0, GET_ULONG, + REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, IF_WIN(INT_MAX32/1000, LONG_TIMEOUT), + 0, 1, 0}, ++ {"userstat_running", OPT_USERSTAT_RUNNING, ++ "Control USER_STATISTICS, CLIENT_STATISTICS, THREAD_STATISTICS, INDEX_STATISTICS and TABLE_STATISTICS running", ++ (uchar**) &opt_userstat_running, (uchar**) &opt_userstat_running, ++ 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0}, ++ {"thread_statistics", OPT_THREAD_STATISTICS, ++ "Control TABLE_STATISTICS running, when userstat_running is enabled", ++ (uchar**) &opt_thread_statistics, (uchar**) &opt_thread_statistics, ++ 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0}, + {"binlog-direct-non-transactional-updates", OPT_BINLOG_DIRECT_NON_TRANS_UPDATE, + "Causes updates to non-transactional engines using statement format to be " + "written directly to binary log. Before using this option, make sure that " +diff -ruN a/sql/set_var.cc b/sql/set_var.cc +--- a/sql/set_var.cc 2010-08-27 14:43:42.004008722 +0900 ++++ b/sql/set_var.cc 2010-08-27 15:10:33.809988740 +0900 +@@ -554,6 +554,10 @@ + static sys_var_thd_ulong sys_read_buff_size(&vars, "read_buffer_size", + &SV::read_buff_size); + static sys_var_opt_readonly sys_readonly(&vars, "read_only", &opt_readonly); ++static sys_var_bool_ptr sys_userstat_running(&vars, "userstat_running", ++ &opt_userstat_running); ++static sys_var_bool_ptr sys_thread_statistics(&vars, "thread_statistics", ++ &opt_thread_statistics); + static sys_var_thd_ulong sys_read_rnd_buff_size(&vars, "read_rnd_buffer_size", + &SV::read_rnd_buff_size); + static sys_var_thd_ulong sys_div_precincrement(&vars, "div_precision_increment", +diff -ruN a/sql/sql_base.cc b/sql/sql_base.cc +--- a/sql/sql_base.cc 2010-08-04 02:24:34.000000000 +0900 ++++ b/sql/sql_base.cc 2010-08-27 15:10:33.818058934 +0900 +@@ -1382,6 +1382,12 @@ + DBUG_PRINT("tcache", ("table: '%s'.'%s' 0x%lx", table->s->db.str, + table->s->table_name.str, (long) table)); + ++ if(table->file) ++ { ++ table->file->update_global_table_stats(); ++ table->file->update_global_index_stats(); ++ } ++ + *table_ptr=table->next; + /* + When closing a MERGE parent or child table, detach the children first. +@@ -1922,6 +1928,8 @@ + DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'", + table->s->db.str, table->s->table_name.str)); + ++ table->file->update_global_table_stats(); ++ table->file->update_global_index_stats(); + free_io_cache(table); + closefrm(table, 0); + if (delete_table) +diff -ruN a/sql/sql_class.cc b/sql/sql_class.cc +--- a/sql/sql_class.cc 2010-08-27 14:38:08.741990000 +0900 ++++ b/sql/sql_class.cc 2010-08-27 15:10:33.825058007 +0900 +@@ -704,6 +704,13 @@ + mysys_var=0; + binlog_evt_union.do_union= FALSE; + enable_slow_log= 0; ++ busy_time = 0; ++ cpu_time = 0; ++ bytes_received = 0; ++ bytes_sent = 0; ++ binlog_bytes_written = 0; ++ updated_row_count = 0; ++ sent_row_count_2 = 0; + #ifndef DBUG_OFF + dbug_sentry=THD_SENTRY_MAGIC; + #endif +@@ -907,6 +914,7 @@ + reset_current_stmt_binlog_row_based(); + bzero((char *) &status_var, sizeof(status_var)); + sql_log_bin_toplevel= options & OPTION_BIN_LOG; ++ reset_stats(); + + #if defined(ENABLED_DEBUG_SYNC) + /* Initialize the Debug Sync Facility. See debug_sync.cc. */ +@@ -914,6 +922,84 @@ + #endif /* defined(ENABLED_DEBUG_SYNC) */ + } + ++// Resets stats in a THD. ++void THD::reset_stats(void) { ++ current_connect_time = time(NULL); ++ last_global_update_time = current_connect_time; ++ reset_diff_stats(); ++} ++ ++// Resets the 'diff' stats, which are used to update global stats. ++void THD::reset_diff_stats(void) { ++ diff_total_busy_time = 0; ++ diff_total_cpu_time = 0; ++ diff_total_bytes_received = 0; ++ diff_total_bytes_sent = 0; ++ diff_total_binlog_bytes_written = 0; ++ diff_total_sent_rows = 0; ++ diff_total_updated_rows = 0; ++ diff_total_read_rows = 0; ++ diff_select_commands = 0; ++ diff_update_commands = 0; ++ diff_other_commands = 0; ++ diff_commit_trans = 0; ++ diff_rollback_trans = 0; ++ diff_denied_connections = 0; ++ diff_lost_connections = 0; ++ diff_access_denied_errors = 0; ++ diff_empty_queries = 0; ++} ++ ++// Updates 'diff' stats of a THD. ++void THD::update_stats(bool ran_command) { ++ if (opt_userstat_running) { ++ diff_total_busy_time += busy_time; ++ diff_total_cpu_time += cpu_time; ++ diff_total_bytes_received += bytes_received; ++ diff_total_bytes_sent += bytes_sent; ++ diff_total_binlog_bytes_written += binlog_bytes_written; ++ diff_total_sent_rows += sent_row_count_2; ++ diff_total_updated_rows += updated_row_count; ++ // diff_total_read_rows is updated in handler.cc. ++ ++ if (ran_command) { ++ // The replication thread has the COM_CONNECT command. ++ if ((old_command == COM_QUERY || command == COM_CONNECT) && ++ (lex->sql_command >= 0 && lex->sql_command < SQLCOM_END)) { ++ // A SQL query. ++ if (lex->sql_command == SQLCOM_SELECT) { ++ diff_select_commands++; ++ if (!sent_row_count_2) ++ diff_empty_queries++; ++ } else if (! sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) { ++ // 'SHOW ' commands become SQLCOM_SELECT. ++ diff_other_commands++; ++ // 'SHOW ' commands shouldn't inflate total sent row count. ++ diff_total_sent_rows -= sent_row_count_2; ++ } else if (is_update_query(lex->sql_command)) { ++ diff_update_commands++; ++ } else { ++ diff_other_commands++; ++ } ++ } ++ } ++ // diff_commit_trans is updated in handler.cc. ++ // diff_rollback_trans is updated in handler.cc. ++ // diff_denied_connections is updated in sql_parse.cc. ++ // diff_lost_connections is updated in sql_parse.cc. ++ // diff_access_denied_errors is updated in sql_parse.cc. ++ ++ /* reset counters to zero to avoid double-counting since values ++ are already store in diff_total_*. */ ++ } ++ busy_time = 0; ++ cpu_time = 0; ++ bytes_received = 0; ++ bytes_sent = 0; ++ binlog_bytes_written = 0; ++ updated_row_count = 0; ++ sent_row_count_2 = 0; ++} + + /* + Init THD for query processing. +@@ -1545,6 +1631,32 @@ + } + #endif + ++char *THD::get_client_host_port(THD *client) ++{ ++ Security_context *client_sctx= client->security_ctx; ++ char *client_host= NULL; ++ ++ if (client->peer_port && (client_sctx->host || client_sctx->ip) && ++ security_ctx->host_or_ip[0]) ++ { ++ if ((client_host= (char *) this->alloc(LIST_PROCESS_HOST_LEN+1))) ++ my_snprintf((char *) client_host, LIST_PROCESS_HOST_LEN, ++ "%s:%u", client_sctx->host_or_ip, client->peer_port); ++ } ++ else ++ client_host= this->strdup(client_sctx->host_or_ip[0] ? ++ client_sctx->host_or_ip : ++ client_sctx->host ? client_sctx->host : ""); ++ ++ return client_host; ++} ++ ++const char *get_client_host(THD *client) ++{ ++ return client->security_ctx->host_or_ip[0] ? ++ client->security_ctx->host_or_ip : ++ client->security_ctx->host ? client->security_ctx->host : ""; ++} + + struct Item_change_record: public ilink + { +@@ -1732,6 +1844,7 @@ + buffer.set(buff, sizeof(buff), &my_charset_bin); + } + thd->sent_row_count++; ++ thd->sent_row_count_2++; + if (thd->is_error()) + { + protocol->remove_last_row(); +@@ -1836,6 +1949,7 @@ + select_export::~select_export() + { + thd->sent_row_count=row_count; ++ thd->sent_row_count_2=row_count; + } + + +@@ -2868,6 +2982,7 @@ + if (likely(thd != 0)) + { /* current_thd==0 when close_connection() calls net_send_error() */ + thd->status_var.bytes_sent+= length; ++ thd->bytes_sent+= length; + } + } + +@@ -2875,6 +2990,7 @@ + void thd_increment_bytes_received(ulong length) + { + current_thd->status_var.bytes_received+= length; ++ current_thd->bytes_received+= length; + } + + +diff -ruN a/sql/sql_class.h b/sql/sql_class.h +--- a/sql/sql_class.h 2010-08-27 14:43:42.008006390 +0900 ++++ b/sql/sql_class.h 2010-08-27 15:10:33.830058443 +0900 +@@ -1435,6 +1435,8 @@ + first byte of the packet in do_command() + */ + enum enum_server_command command; ++ // Used to save the command, before it is set to COM_SLEEP. ++ enum enum_server_command old_command; + uint32 server_id; + uint32 file_id; // for LOAD DATA INFILE + /* remote (peer) port */ +@@ -1828,6 +1830,8 @@ + /* variables.transaction_isolation is reset to this after each commit */ + enum_tx_isolation session_tx_isolation; + enum_check_fields count_cuted_fields; ++ ha_rows updated_row_count; ++ ha_rows sent_row_count_2; /* for userstat */ + + DYNAMIC_ARRAY user_var_events; /* For user variables replication */ + MEM_ROOT *user_var_events_alloc; /* Allocate above array elements here */ +@@ -1916,6 +1920,49 @@ + */ + LOG_INFO* current_linfo; + NET* slave_net; // network connection from slave -> m. ++ ++ /* ++ Used to update global user stats. The global user stats are updated ++ occasionally with the 'diff' variables. After the update, the 'diff' ++ variables are reset to 0. ++ */ ++ // Time when the current thread connected to MySQL. ++ time_t current_connect_time; ++ // Last time when THD stats were updated in global_user_stats. ++ time_t last_global_update_time; ++ // Busy (non-idle) time for just one command. ++ double busy_time; ++ // Busy time not updated in global_user_stats yet. ++ double diff_total_busy_time; ++ // Cpu (non-idle) time for just one thread. ++ double cpu_time; ++ // Cpu time not updated in global_user_stats yet. ++ double diff_total_cpu_time; ++ /* bytes counting */ ++ ulonglong bytes_received; ++ ulonglong diff_total_bytes_received; ++ ulonglong bytes_sent; ++ ulonglong diff_total_bytes_sent; ++ ulonglong binlog_bytes_written; ++ ulonglong diff_total_binlog_bytes_written; ++ ++ // Number of rows not reflected in global_user_stats yet. ++ ha_rows diff_total_sent_rows, diff_total_updated_rows, diff_total_read_rows; ++ // Number of commands not reflected in global_user_stats yet. ++ ulonglong diff_select_commands, diff_update_commands, diff_other_commands; ++ // Number of transactions not reflected in global_user_stats yet. ++ ulonglong diff_commit_trans, diff_rollback_trans; ++ // Number of connection errors not reflected in global_user_stats yet. ++ ulonglong diff_denied_connections, diff_lost_connections; ++ // Number of db access denied, not reflected in global_user_stats yet. ++ ulonglong diff_access_denied_errors; ++ // Number of queries that return 0 rows ++ ulonglong diff_empty_queries; ++ ++ // Per account query delay in miliseconds. When not 0, sleep this number of ++ // milliseconds before every SQL command. ++ ulonglong query_delay_millis; ++ + /* Used by the sys_var class to store temporary values */ + union + { +@@ -1981,6 +2028,11 @@ + alloc_root. + */ + void init_for_queries(); ++ void reset_stats(void); ++ void reset_diff_stats(void); ++ // ran_command is true when this is called immediately after a ++ // command has been run. ++ void update_stats(bool ran_command); + void change_user(void); + void cleanup(void); + void cleanup_after_query(); +@@ -2351,9 +2403,15 @@ + *p_db= strmake(db, db_length); + *p_db_length= db_length; + return FALSE; ++ ++ // Returns string as 'IP:port' for the client-side of the connnection represented ++ // by 'client' as displayed by SHOW PROCESSLIST. Allocates memory from the heap of ++ // this THD and that is not reclaimed immediately, so use sparingly. May return NULL. + } + thd_scheduler scheduler; + ++ char *get_client_host_port(THD *client); ++ + public: + inline Internal_error_handler *get_internal_handler() + { return m_internal_handler; } +@@ -2438,6 +2496,9 @@ + LEX_STRING invoker_host; + }; + ++// Returns string as 'IP' for the client-side of the connection represented by ++// 'client'. Does not allocate memory. May return "". ++const char *get_client_host(THD *client); + + /** A short cut for thd->main_da.set_ok_status(). */ + +diff -ruN a/sql/sql_connect.cc b/sql/sql_connect.cc +--- a/sql/sql_connect.cc 2010-08-27 14:38:08.750990238 +0900 ++++ b/sql/sql_connect.cc 2010-08-27 15:10:33.834058369 +0900 +@@ -42,6 +42,24 @@ + extern void win_install_sigabrt_handler(); + #endif + ++// Increments connection count for user. ++static int increment_connection_count(THD* thd, bool use_lock); ++ ++// Uses the THD to update the global stats by user name and client IP ++void update_global_user_stats(THD* thd, bool create_user, time_t now); ++ ++HASH global_user_stats; ++HASH global_client_stats; ++HASH global_thread_stats; ++// Protects global_user_stats and global_client_stats ++extern pthread_mutex_t LOCK_global_user_client_stats; ++ ++HASH global_table_stats; ++extern pthread_mutex_t LOCK_global_table_stats; ++ ++HASH global_index_stats; ++extern pthread_mutex_t LOCK_global_index_stats; ++ + /* + Get structure for logging connection data for the current user + */ +@@ -99,6 +117,563 @@ + + } + ++extern "C" uchar *get_key_user_stats(USER_STATS *user_stats, size_t *length, ++ my_bool not_used __attribute__((unused))) ++{ ++ *length = strlen(user_stats->user); ++ return (uchar*)user_stats->user; ++} ++ ++extern "C" uchar *get_key_thread_stats(THREAD_STATS *thread_stats, size_t *length, ++ my_bool not_used __attribute__((unused))) ++{ ++ *length = sizeof(my_thread_id); ++ return (uchar*)&(thread_stats->id); ++} ++ ++void free_user_stats(USER_STATS* user_stats) ++{ ++ my_free((char*)user_stats, MYF(0)); ++} ++ ++void free_thread_stats(THREAD_STATS* thread_stats) ++{ ++ my_free((char*)thread_stats, MYF(0)); ++} ++ ++void init_user_stats(USER_STATS *user_stats, ++ const char *user, ++ const char *priv_user, ++ uint total_connections, ++ uint concurrent_connections, ++ time_t connected_time, ++ double busy_time, ++ double cpu_time, ++ ulonglong bytes_received, ++ ulonglong bytes_sent, ++ ulonglong binlog_bytes_written, ++ ha_rows rows_fetched, ++ ha_rows rows_updated, ++ ha_rows rows_read, ++ ulonglong select_commands, ++ ulonglong update_commands, ++ ulonglong other_commands, ++ ulonglong commit_trans, ++ ulonglong rollback_trans, ++ ulonglong denied_connections, ++ ulonglong lost_connections, ++ ulonglong access_denied_errors, ++ ulonglong empty_queries) ++{ ++ DBUG_ENTER("init_user_stats"); ++ DBUG_PRINT("info", ++ ("Add user_stats entry for user %s - priv_user %s", ++ user, priv_user)); ++ strncpy(user_stats->user, user, sizeof(user_stats->user)); ++ strncpy(user_stats->priv_user, priv_user, sizeof(user_stats->priv_user)); ++ ++ user_stats->total_connections = total_connections; ++ user_stats->concurrent_connections = concurrent_connections; ++ user_stats->connected_time = connected_time; ++ user_stats->busy_time = busy_time; ++ user_stats->cpu_time = cpu_time; ++ user_stats->bytes_received = bytes_received; ++ user_stats->bytes_sent = bytes_sent; ++ user_stats->binlog_bytes_written = binlog_bytes_written; ++ user_stats->rows_fetched = rows_fetched; ++ user_stats->rows_updated = rows_updated; ++ user_stats->rows_read = rows_read; ++ user_stats->select_commands = select_commands; ++ user_stats->update_commands = update_commands; ++ user_stats->other_commands = other_commands; ++ user_stats->commit_trans = commit_trans; ++ user_stats->rollback_trans = rollback_trans; ++ user_stats->denied_connections = denied_connections; ++ user_stats->lost_connections = lost_connections; ++ user_stats->access_denied_errors = access_denied_errors; ++ user_stats->empty_queries = empty_queries; ++ DBUG_VOID_RETURN; ++} ++ ++void init_thread_stats(THREAD_STATS *thread_stats, ++ my_thread_id id, ++ uint total_connections, ++ uint concurrent_connections, ++ time_t connected_time, ++ double busy_time, ++ double cpu_time, ++ ulonglong bytes_received, ++ ulonglong bytes_sent, ++ ulonglong binlog_bytes_written, ++ ha_rows rows_fetched, ++ ha_rows rows_updated, ++ ha_rows rows_read, ++ ulonglong select_commands, ++ ulonglong update_commands, ++ ulonglong other_commands, ++ ulonglong commit_trans, ++ ulonglong rollback_trans, ++ ulonglong denied_connections, ++ ulonglong lost_connections, ++ ulonglong access_denied_errors, ++ ulonglong empty_queries) ++{ ++ DBUG_ENTER("init_thread_stats"); ++ DBUG_PRINT("info", ++ ("Add thread_stats entry for thread %lu", ++ id)); ++ thread_stats->id = id; ++ ++ thread_stats->total_connections = total_connections; ++ thread_stats->concurrent_connections = concurrent_connections; ++ thread_stats->connected_time = connected_time; ++ thread_stats->busy_time = busy_time; ++ thread_stats->cpu_time = cpu_time; ++ thread_stats->bytes_received = bytes_received; ++ thread_stats->bytes_sent = bytes_sent; ++ thread_stats->binlog_bytes_written = binlog_bytes_written; ++ thread_stats->rows_fetched = rows_fetched; ++ thread_stats->rows_updated = rows_updated; ++ thread_stats->rows_read = rows_read; ++ thread_stats->select_commands = select_commands; ++ thread_stats->update_commands = update_commands; ++ thread_stats->other_commands = other_commands; ++ thread_stats->commit_trans = commit_trans; ++ thread_stats->rollback_trans = rollback_trans; ++ thread_stats->denied_connections = denied_connections; ++ thread_stats->lost_connections = lost_connections; ++ thread_stats->access_denied_errors = access_denied_errors; ++ thread_stats->empty_queries = empty_queries; ++ DBUG_VOID_RETURN; ++} ++ ++void add_user_stats(USER_STATS *user_stats, ++ uint total_connections, ++ uint concurrent_connections, ++ time_t connected_time, ++ double busy_time, ++ double cpu_time, ++ ulonglong bytes_received, ++ ulonglong bytes_sent, ++ ulonglong binlog_bytes_written, ++ ha_rows rows_fetched, ++ ha_rows rows_updated, ++ ha_rows rows_read, ++ ulonglong select_commands, ++ ulonglong update_commands, ++ ulonglong other_commands, ++ ulonglong commit_trans, ++ ulonglong rollback_trans, ++ ulonglong denied_connections, ++ ulonglong lost_connections, ++ ulonglong access_denied_errors, ++ ulonglong empty_queries) ++{ ++ user_stats->total_connections += total_connections; ++ user_stats->concurrent_connections += concurrent_connections; ++ user_stats->connected_time += connected_time; ++ user_stats->busy_time += busy_time; ++ user_stats->cpu_time += cpu_time; ++ user_stats->bytes_received += bytes_received; ++ user_stats->bytes_sent += bytes_sent; ++ user_stats->binlog_bytes_written += binlog_bytes_written; ++ user_stats->rows_fetched += rows_fetched; ++ user_stats->rows_updated += rows_updated; ++ user_stats->rows_read += rows_read; ++ user_stats->select_commands += select_commands; ++ user_stats->update_commands += update_commands; ++ user_stats->other_commands += other_commands; ++ user_stats->commit_trans += commit_trans; ++ user_stats->rollback_trans += rollback_trans; ++ user_stats->denied_connections += denied_connections; ++ user_stats->lost_connections += lost_connections; ++ user_stats->access_denied_errors += access_denied_errors; ++ user_stats->empty_queries += empty_queries; ++} ++ ++void add_thread_stats(THREAD_STATS *thread_stats, ++ uint total_connections, ++ uint concurrent_connections, ++ time_t connected_time, ++ double busy_time, ++ double cpu_time, ++ ulonglong bytes_received, ++ ulonglong bytes_sent, ++ ulonglong binlog_bytes_written, ++ ha_rows rows_fetched, ++ ha_rows rows_updated, ++ ha_rows rows_read, ++ ulonglong select_commands, ++ ulonglong update_commands, ++ ulonglong other_commands, ++ ulonglong commit_trans, ++ ulonglong rollback_trans, ++ ulonglong denied_connections, ++ ulonglong lost_connections, ++ ulonglong access_denied_errors, ++ ulonglong empty_queries) ++{ ++ thread_stats->total_connections += total_connections; ++ thread_stats->concurrent_connections += concurrent_connections; ++ thread_stats->connected_time += connected_time; ++ thread_stats->busy_time += busy_time; ++ thread_stats->cpu_time += cpu_time; ++ thread_stats->bytes_received += bytes_received; ++ thread_stats->bytes_sent += bytes_sent; ++ thread_stats->binlog_bytes_written += binlog_bytes_written; ++ thread_stats->rows_fetched += rows_fetched; ++ thread_stats->rows_updated += rows_updated; ++ thread_stats->rows_read += rows_read; ++ thread_stats->select_commands += select_commands; ++ thread_stats->update_commands += update_commands; ++ thread_stats->other_commands += other_commands; ++ thread_stats->commit_trans += commit_trans; ++ thread_stats->rollback_trans += rollback_trans; ++ thread_stats->denied_connections += denied_connections; ++ thread_stats->lost_connections += lost_connections; ++ thread_stats->access_denied_errors += access_denied_errors; ++ thread_stats->empty_queries += empty_queries; ++} ++ ++void init_global_user_stats(void) ++{ ++ if (hash_init(&global_user_stats, system_charset_info, max_connections, ++ 0, 0, (hash_get_key)get_key_user_stats, ++ (hash_free_key)free_user_stats, 0)) { ++ sql_print_error("Initializing global_user_stats failed."); ++ exit(1); ++ } ++} ++ ++void init_global_client_stats(void) ++{ ++ if (hash_init(&global_client_stats, system_charset_info, max_connections, ++ 0, 0, (hash_get_key)get_key_user_stats, ++ (hash_free_key)free_user_stats, 0)) { ++ sql_print_error("Initializing global_client_stats failed."); ++ exit(1); ++ } ++} ++ ++void init_global_thread_stats(void) ++{ ++ if (hash_init(&global_thread_stats, &my_charset_bin, max_connections, ++ 0, 0, (hash_get_key)get_key_thread_stats, ++ (hash_free_key)free_thread_stats, 0)) { ++ sql_print_error("Initializing global_client_stats failed."); ++ exit(1); ++ } ++} ++ ++extern "C" uchar *get_key_table_stats(TABLE_STATS *table_stats, size_t *length, ++ my_bool not_used __attribute__((unused))) ++{ ++ *length = strlen(table_stats->table); ++ return (uchar*)table_stats->table; ++} ++ ++extern "C" void free_table_stats(TABLE_STATS* table_stats) ++{ ++ my_free((char*)table_stats, MYF(0)); ++} ++ ++void init_global_table_stats(void) ++{ ++ if (hash_init(&global_table_stats, system_charset_info, max_connections, ++ 0, 0, (hash_get_key)get_key_table_stats, ++ (hash_free_key)free_table_stats, 0)) { ++ sql_print_error("Initializing global_table_stats failed."); ++ exit(1); ++ } ++} ++ ++extern "C" uchar *get_key_index_stats(INDEX_STATS *index_stats, size_t *length, ++ my_bool not_used __attribute__((unused))) ++{ ++ *length = strlen(index_stats->index); ++ return (uchar*)index_stats->index; ++} ++ ++extern "C" void free_index_stats(INDEX_STATS* index_stats) ++{ ++ my_free((char*)index_stats, MYF(0)); ++} ++ ++void init_global_index_stats(void) ++{ ++ if (hash_init(&global_index_stats, system_charset_info, max_connections, ++ 0, 0, (hash_get_key)get_key_index_stats, ++ (hash_free_key)free_index_stats, 0)) { ++ sql_print_error("Initializing global_index_stats failed."); ++ exit(1); ++ } ++} ++ ++void free_global_user_stats(void) ++{ ++ hash_free(&global_user_stats); ++} ++ ++void free_global_thread_stats(void) ++{ ++ hash_free(&global_thread_stats); ++} ++ ++void free_global_table_stats(void) ++{ ++ hash_free(&global_table_stats); ++} ++ ++void free_global_index_stats(void) ++{ ++ hash_free(&global_index_stats); ++} ++ ++void free_global_client_stats(void) ++{ ++ hash_free(&global_client_stats); ++} ++ ++// 'mysql_system_user' is used for when the user is not defined for a THD. ++static char mysql_system_user[] = "#mysql_system#"; ++ ++// Returns 'user' if it's not NULL. Returns 'mysql_system_user' otherwise. ++static char* get_valid_user_string(char* user) { ++ return user ? user : mysql_system_user; ++} ++ ++// Increments the global stats connection count for an entry from ++// global_client_stats or global_user_stats. Returns 0 on success ++// and 1 on error. ++static int increment_count_by_name(const char *name, const char *role_name, ++ HASH *users_or_clients, THD *thd) ++{ ++ USER_STATS* user_stats; ++ ++ if (!(user_stats = (USER_STATS*)hash_search(users_or_clients, (uchar*) name, ++ strlen(name)))) ++ { ++ // First connection for this user or client ++ if (!(user_stats = ((USER_STATS*) ++ my_malloc(sizeof(USER_STATS), MYF(MY_WME | MY_ZEROFILL))))) ++ { ++ return 1; // Out of memory ++ } ++ ++ init_user_stats(user_stats, name, role_name, ++ 0, 0, // connections ++ 0, 0, 0, // time ++ 0, 0, 0, // bytes sent, received and written ++ 0, 0, 0, // rows fetched, updated and read ++ 0, 0, 0, // select, update and other commands ++ 0, 0, // commit and rollback trans ++ thd->diff_denied_connections, ++ 0, // lost connections ++ 0, // access denied errors ++ 0); // empty queries ++ ++ if (my_hash_insert(users_or_clients, (uchar*)user_stats)) ++ { ++ my_free((char*)user_stats, 0); ++ return 1; // Out of memory ++ } ++ } ++ user_stats->total_connections++; ++ return 0; ++} ++ ++static int increment_count_by_id(my_thread_id id, ++ HASH *users_or_clients, THD *thd) ++{ ++ THREAD_STATS* thread_stats; ++ ++ if (!(thread_stats = (THREAD_STATS*)hash_search(users_or_clients, (uchar*) &id, ++ sizeof(my_thread_id)))) ++ { ++ // First connection for this user or client ++ if (!(thread_stats = ((THREAD_STATS*) ++ my_malloc(sizeof(THREAD_STATS), MYF(MY_WME | MY_ZEROFILL))))) ++ { ++ return 1; // Out of memory ++ } ++ ++ init_thread_stats(thread_stats, id, ++ 0, 0, // connections ++ 0, 0, 0, // time ++ 0, 0, 0, // bytes sent, received and written ++ 0, 0, 0, // rows fetched, updated and read ++ 0, 0, 0, // select, update and other commands ++ 0, 0, // commit and rollback trans ++ thd->diff_denied_connections, ++ 0, // lost connections ++ 0, // access denied errors ++ 0); // empty queries ++ ++ if (my_hash_insert(users_or_clients, (uchar*)thread_stats)) ++ { ++ my_free((char*)thread_stats, 0); ++ return 1; // Out of memory ++ } ++ } ++ thread_stats->total_connections++; ++ return 0; ++} ++ ++// Increments the global user and client stats connection count. If 'use_lock' ++// is true, LOCK_global_user_client_stats will be locked/unlocked. Returns ++// 0 on success, 1 on error. ++static int increment_connection_count(THD* thd, bool use_lock) ++{ ++ char* user_string = get_valid_user_string(thd->main_security_ctx.user); ++ const char* client_string = get_client_host(thd); ++ int return_value = 0; ++ ++ if (!opt_userstat_running) ++ return return_value; ++ ++ if (use_lock) pthread_mutex_lock(&LOCK_global_user_client_stats); ++ ++ if (increment_count_by_name(user_string, user_string, ++ &global_user_stats, thd)) ++ { ++ return_value = 1; ++ goto end; ++ } ++ if (increment_count_by_name(client_string, ++ user_string, ++ &global_client_stats, thd)) ++ { ++ return_value = 1; ++ goto end; ++ } ++ if (opt_thread_statistics) { ++ if (increment_count_by_id(thd->thread_id, &global_thread_stats, thd)) ++ { ++ return_value = 1; ++ goto end; ++ } ++ } ++ ++end: ++ if (use_lock) pthread_mutex_unlock(&LOCK_global_user_client_stats); ++ return return_value; ++} ++ ++// Used to update the global user and client stats. ++static void update_global_user_stats_with_user(THD* thd, ++ USER_STATS* user_stats, ++ time_t now) ++{ ++ user_stats->connected_time += now - thd->last_global_update_time; ++// thd->last_global_update_time = now; ++ user_stats->busy_time += thd->diff_total_busy_time; ++ user_stats->cpu_time += thd->diff_total_cpu_time; ++ user_stats->bytes_received += thd->diff_total_bytes_received; ++ user_stats->bytes_sent += thd->diff_total_bytes_sent; ++ user_stats->binlog_bytes_written += thd->diff_total_binlog_bytes_written; ++ user_stats->rows_fetched += thd->diff_total_sent_rows; ++ user_stats->rows_updated += thd->diff_total_updated_rows; ++ user_stats->rows_read += thd->diff_total_read_rows; ++ user_stats->select_commands += thd->diff_select_commands; ++ user_stats->update_commands += thd->diff_update_commands; ++ user_stats->other_commands += thd->diff_other_commands; ++ user_stats->commit_trans += thd->diff_commit_trans; ++ user_stats->rollback_trans += thd->diff_rollback_trans; ++ user_stats->denied_connections += thd->diff_denied_connections; ++ user_stats->lost_connections += thd->diff_lost_connections; ++ user_stats->access_denied_errors += thd->diff_access_denied_errors; ++ user_stats->empty_queries += thd->diff_empty_queries; ++} ++ ++static void update_global_thread_stats_with_thread(THD* thd, ++ THREAD_STATS* thread_stats, ++ time_t now) ++{ ++ thread_stats->connected_time += now - thd->last_global_update_time; ++// thd->last_global_update_time = now; ++ thread_stats->busy_time += thd->diff_total_busy_time; ++ thread_stats->cpu_time += thd->diff_total_cpu_time; ++ thread_stats->bytes_received += thd->diff_total_bytes_received; ++ thread_stats->bytes_sent += thd->diff_total_bytes_sent; ++ thread_stats->binlog_bytes_written += thd->diff_total_binlog_bytes_written; ++ thread_stats->rows_fetched += thd->diff_total_sent_rows; ++ thread_stats->rows_updated += thd->diff_total_updated_rows; ++ thread_stats->rows_read += thd->diff_total_read_rows; ++ thread_stats->select_commands += thd->diff_select_commands; ++ thread_stats->update_commands += thd->diff_update_commands; ++ thread_stats->other_commands += thd->diff_other_commands; ++ thread_stats->commit_trans += thd->diff_commit_trans; ++ thread_stats->rollback_trans += thd->diff_rollback_trans; ++ thread_stats->denied_connections += thd->diff_denied_connections; ++ thread_stats->lost_connections += thd->diff_lost_connections; ++ thread_stats->access_denied_errors += thd->diff_access_denied_errors; ++ thread_stats->empty_queries += thd->diff_empty_queries; ++} ++ ++// Updates the global stats of a user or client ++void update_global_user_stats(THD* thd, bool create_user, time_t now) ++{ ++ if (opt_userstat_running) { ++ char* user_string = get_valid_user_string(thd->main_security_ctx.user); ++ const char* client_string = get_client_host(thd); ++ ++ USER_STATS* user_stats; ++ THREAD_STATS* thread_stats; ++ pthread_mutex_lock(&LOCK_global_user_client_stats); ++ ++ // Update by user name ++ if ((user_stats = (USER_STATS*)hash_search(&global_user_stats, ++ (uchar*)user_string, ++ strlen(user_string)))) { ++ // Found user. ++ update_global_user_stats_with_user(thd, user_stats, now); ++ } else { ++ // Create the entry ++ if (create_user) { ++ increment_count_by_name(user_string, user_string, ++ &global_user_stats, thd); ++ } ++ } ++ ++ // Update by client IP ++ if ((user_stats = (USER_STATS*)hash_search(&global_client_stats, ++ (uchar*)client_string, ++ strlen(client_string)))) { ++ // Found by client IP ++ update_global_user_stats_with_user(thd, user_stats, now); ++ } else { ++ // Create the entry ++ if (create_user) { ++ increment_count_by_name(client_string, ++ user_string, ++ &global_client_stats, thd); ++ } ++ } ++ ++ if (opt_thread_statistics) { ++ // Update by thread ID ++ if ((thread_stats = (THREAD_STATS*)hash_search(&global_thread_stats, ++ (uchar*) &(thd->thread_id), ++ sizeof(my_thread_id)))) { ++ // Found by thread ID ++ update_global_thread_stats_with_thread(thd, thread_stats, now); ++ } else { ++ // Create the entry ++ if (create_user) { ++ increment_count_by_id(thd->thread_id, ++ &global_thread_stats, thd); ++ } ++ } ++ } ++ ++ thd->last_global_update_time = now; ++ thd->reset_diff_stats(); ++ ++ pthread_mutex_unlock(&LOCK_global_user_client_stats); ++ } else { ++ thd->reset_diff_stats(); ++ } ++} + + /* + check if user has already too many connections +@@ -154,7 +729,10 @@ + + end: + if (error) ++ { + uc->connections--; // no need for decrease_user_connections() here ++ statistic_increment(denied_connections, &LOCK_status); ++ } + (void) pthread_mutex_unlock(&LOCK_user_conn); + DBUG_RETURN(error); + } +@@ -490,6 +1068,7 @@ + general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE)); + DBUG_RETURN(1); + } ++ thd->diff_access_denied_errors++; + my_error(ER_ACCESS_DENIED_ERROR, MYF(0), + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip, +@@ -971,11 +1550,20 @@ + my_sleep(1000); /* must wait after eof() */ + #endif + statistic_increment(aborted_connects,&LOCK_status); ++ thd->diff_denied_connections++; + DBUG_RETURN(1); + } + /* Connect completed, set read/write timeouts back to default */ + my_net_set_read_timeout(net, thd->variables.net_read_timeout); + my_net_set_write_timeout(net, thd->variables.net_write_timeout); ++ ++ thd->reset_stats(); ++ // Updates global user connection stats. ++ if (increment_connection_count(thd, true)) { ++ net_send_error(thd, ER_OUTOFMEMORY); // Out of memory ++ DBUG_RETURN(1); ++ } ++ + DBUG_RETURN(0); + } + +@@ -997,6 +1585,7 @@ + if (thd->killed || (net->error && net->vio != 0)) + { + statistic_increment(aborted_threads,&LOCK_status); ++ thd->diff_lost_connections++; + } + + if (net->error && net->vio != 0) +@@ -1123,10 +1712,14 @@ + for (;;) + { + NET *net= &thd->net; ++ bool create_user= TRUE; + + lex_start(thd); + if (login_connection(thd)) ++ { ++ create_user= FALSE; + goto end_thread; ++ } + + prepare_new_connection_state(thd); + +@@ -1149,6 +1742,8 @@ + + end_thread: + close_connection(thd, 0, 1); ++ thd->update_stats(false); ++ update_global_user_stats(thd, create_user, time(NULL)); + if (thread_scheduler.end_thread(thd,1)) + return 0; // Probably no-threads + +diff -ruN a/sql/sql_delete.cc b/sql/sql_delete.cc +--- a/sql/sql_delete.cc 2010-08-04 02:24:34.000000000 +0900 ++++ b/sql/sql_delete.cc 2010-08-27 15:10:33.837058490 +0900 +@@ -452,6 +452,7 @@ + my_ok(thd, (ha_rows) thd->row_count_func); + DBUG_PRINT("info",("%ld records deleted",(long) deleted)); + } ++ thd->updated_row_count += deleted; + DBUG_RETURN(error >= 0 || thd->is_error()); + } + +@@ -1059,6 +1060,7 @@ + thd->row_count_func= deleted; + ::my_ok(thd, (ha_rows) thd->row_count_func); + } ++ thd->updated_row_count += deleted; + return 0; + } + +diff -ruN a/sql/sql_insert.cc b/sql/sql_insert.cc +--- a/sql/sql_insert.cc 2010-08-04 02:24:19.000000000 +0900 ++++ b/sql/sql_insert.cc 2010-08-27 15:10:33.841059138 +0900 +@@ -981,6 +981,7 @@ + thd->row_count_func= info.copied + info.deleted + updated; + ::my_ok(thd, (ulong) thd->row_count_func, id, buff); + } ++ thd->updated_row_count += thd->row_count_func; + thd->abort_on_warning= 0; + DBUG_RETURN(FALSE); + +@@ -3311,6 +3312,7 @@ + thd->first_successful_insert_id_in_prev_stmt : + (info.copied ? autoinc_value_of_last_inserted_row : 0)); + ::my_ok(thd, (ulong) thd->row_count_func, id, buff); ++ thd->updated_row_count += thd->row_count_func; + DBUG_RETURN(0); + } + +diff -ruN a/sql/sql_lex.h b/sql/sql_lex.h +--- a/sql/sql_lex.h 2010-08-27 14:29:26.030989835 +0900 ++++ b/sql/sql_lex.h 2010-08-27 15:10:33.844058293 +0900 +@@ -124,6 +124,9 @@ + When a command is added here, be sure it's also added in mysqld.cc + in "struct show_var_st status_vars[]= {" ... + */ ++ // TODO(mcallaghan): update status_vars in mysqld to export these ++ SQLCOM_SHOW_USER_STATS, SQLCOM_SHOW_TABLE_STATS, SQLCOM_SHOW_INDEX_STATS, ++ SQLCOM_SHOW_CLIENT_STATS, SQLCOM_SHOW_THREAD_STATS, + /* This should be the last !!! */ + SQLCOM_END + }; +diff -ruN a/sql/sql_parse.cc b/sql/sql_parse.cc +--- a/sql/sql_parse.cc 2010-08-27 14:38:08.757059579 +0900 ++++ b/sql/sql_parse.cc 2010-08-27 15:15:30.420996146 +0900 +@@ -46,6 +46,9 @@ + static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); + static bool check_show_create_table_access(THD *thd, TABLE_LIST *table); + ++// Uses the THD to update the global stats by user name and client IP ++void update_global_user_stats(THD* thd, bool create_user, time_t now); ++ + const char *any_db="*any*"; // Special symbol for check_access + + const LEX_STRING command_name[]={ +@@ -824,6 +827,12 @@ + */ + thd->clear_error(); // Clear error message + thd->main_da.reset_diagnostics_area(); ++ thd->updated_row_count=0; ++ thd->busy_time=0; ++ thd->cpu_time=0; ++ thd->bytes_received=0; ++ thd->bytes_sent=0; ++ thd->binlog_bytes_written=0; + + net_new_transaction(net); + +@@ -993,6 +1002,9 @@ + DBUG_PRINT("info",("packet: '%*.s'; command: %d", packet_length, packet, command)); + + thd->command=command; ++ // To increment the corrent command counter for user stats, 'command' must ++ // be saved because it is set to COM_SLEEP at the end of this function. ++ thd->old_command = command; + /* + Commands which always take a long time are logged into + the slow log only if opt_log_slow_admin_statements is set. +@@ -1864,6 +1876,13 @@ + thd->profiling.discard_current_query(); + #endif + break; ++ case SCH_USER_STATS: ++ case SCH_CLIENT_STATS: ++ case SCH_THREAD_STATS: ++ if (check_global_access(thd, SUPER_ACL | PROCESS_ACL)) ++ DBUG_RETURN(1); ++ case SCH_TABLE_STATS: ++ case SCH_INDEX_STATS: + case SCH_OPEN_TABLES: + case SCH_VARIABLES: + case SCH_STATUS: +@@ -2020,6 +2039,7 @@ + thd->security_ctx->priv_host)) && + check_global_access(thd, SUPER_ACL)) + { ++ thd->diff_access_denied_errors++; + my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER"); + DBUG_RETURN(TRUE); + } +@@ -5331,6 +5351,7 @@ + if (!no_errors) + { + const char *db_name= db ? db : thd->db; ++ thd->diff_access_denied_errors++; + my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), + sctx->priv_user, sctx->priv_host, db_name); + } +@@ -5363,12 +5384,15 @@ + { // We can never grant this + DBUG_PRINT("error",("No possible access")); + if (!no_errors) ++ { ++ thd->diff_access_denied_errors++; + my_error(ER_ACCESS_DENIED_ERROR, MYF(0), + sctx->priv_user, + sctx->priv_host, + (thd->password ? + ER(ER_YES) : + ER(ER_NO))); /* purecov: tested */ ++ } + DBUG_RETURN(TRUE); /* purecov: tested */ + } + +@@ -5394,11 +5418,15 @@ + + DBUG_PRINT("error",("Access denied")); + if (!no_errors) ++ { ++ // increment needs !no_errors condition, otherwise double counting. ++ thd->diff_access_denied_errors++; + my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), + sctx->priv_user, sctx->priv_host, + (db ? db : (thd->db ? + thd->db : + "unknown"))); /* purecov: tested */ ++ } + DBUG_RETURN(TRUE); /* purecov: tested */ + } + +@@ -5427,6 +5455,7 @@ + + if (!thd->col_access && check_grant_db(thd, dst_db_name)) + { ++ thd->diff_access_denied_errors++; + my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), + thd->security_ctx->priv_user, + thd->security_ctx->priv_host, +@@ -5508,9 +5537,12 @@ + (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL))) + { + if (!no_errors) ++ { ++ thd->diff_access_denied_errors++; + my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), + sctx->priv_user, sctx->priv_host, + INFORMATION_SCHEMA_NAME.str); ++ } + return TRUE; + } + /* +@@ -5673,6 +5705,7 @@ + if ((thd->security_ctx->master_access & want_access)) + return 0; + get_privilege_desc(command, sizeof(command), want_access); ++ thd->diff_access_denied_errors++; + my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command); + return 1; + #else +@@ -6054,6 +6087,34 @@ + lex_start(thd); + mysql_reset_thd_for_next_command(thd); + ++ int start_time_error = 0; ++ int end_time_error = 0; ++ struct timeval start_time, end_time; ++ double start_usecs = 0; ++ double end_usecs = 0; ++ /* cpu time */ ++ int cputime_error = 0; ++ struct timespec tp; ++ double start_cpu_nsecs = 0; ++ double end_cpu_nsecs = 0; ++ ++ if (opt_userstat_running) { ++#ifdef HAVE_CLOCK_GETTIME ++ /* get start cputime */ ++ if (!(cputime_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) ++ start_cpu_nsecs = tp.tv_sec*1000000000.0+tp.tv_nsec; ++#else ++#warning : HAVE_CLOCK_GETTIME is disabled. ++#warning : Most systems require librt library to use the function clock_gettime(). ++#warning : Did you set environment when ./configure ? (e.g. "export LIBS=-lrt" for sh) ++#endif ++ ++ // Gets the start time, in order to measure how long this command takes. ++ if (!(start_time_error = gettimeofday(&start_time, NULL))) { ++ start_usecs = start_time.tv_sec * 1000000.0 + start_time.tv_usec; ++ } ++ } ++ + if (query_cache_send_result_to_client(thd, rawbuf, length) <= 0) + { + LEX *lex= thd->lex; +@@ -6134,6 +6195,43 @@ + *found_semicolon= NULL; + } + ++ if (opt_userstat_running) { ++ // Gets the end time. ++ if (!(end_time_error = gettimeofday(&end_time, NULL))) { ++ end_usecs = end_time.tv_sec * 1000000.0 + end_time.tv_usec; ++ } ++ ++ // Calculates the difference between the end and start times. ++ if (start_usecs && end_usecs >= start_usecs && !start_time_error && !end_time_error) { ++ thd->busy_time = (end_usecs - start_usecs) / 1000000; ++ // In case there are bad values, 2629743 is the #seconds in a month. ++ if (thd->busy_time > 2629743) { ++ thd->busy_time = 0; ++ } ++ } else { ++ // end time went back in time, or gettimeofday() failed. ++ thd->busy_time = 0; ++ } ++ ++#ifdef HAVE_CLOCK_GETTIME ++ /* get end cputime */ ++ if (!cputime_error && ++ !(cputime_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) ++ end_cpu_nsecs = tp.tv_sec*1000000000.0+tp.tv_nsec; ++#endif ++ if (start_cpu_nsecs && !cputime_error) { ++ thd->cpu_time = (end_cpu_nsecs - start_cpu_nsecs) / 1000000000; ++ // In case there are bad values, 2629743 is the #seconds in a month. ++ if (thd->cpu_time > 2629743) { ++ thd->cpu_time = 0; ++ } ++ } else ++ thd->cpu_time = 0; ++ } ++ // Updates THD stats and the global user stats. ++ thd->update_stats(true); ++ update_global_user_stats(thd, true, time(NULL)); ++ + DBUG_VOID_RETURN; + } + +@@ -6999,6 +7097,13 @@ + if (flush_error_log()) + result=1; + } ++ if (((options & (REFRESH_SLOW_QUERY_LOG | REFRESH_LOG)) == ++ REFRESH_SLOW_QUERY_LOG)) ++ { ++ /* We are only flushing slow query log */ ++ logger.flush_slow_log(thd); ++ } ++ + #ifdef HAVE_QUERY_CACHE + if (options & REFRESH_QUERY_CACHE_FREE) + { +@@ -7099,6 +7204,40 @@ + #endif + if (options & REFRESH_USER_RESOURCES) + reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */ ++ if (options & REFRESH_TABLE_STATS) ++ { ++ pthread_mutex_lock(&LOCK_global_table_stats); ++ free_global_table_stats(); ++ init_global_table_stats(); ++ pthread_mutex_unlock(&LOCK_global_table_stats); ++ } ++ if (options & REFRESH_INDEX_STATS) ++ { ++ pthread_mutex_lock(&LOCK_global_index_stats); ++ free_global_index_stats(); ++ init_global_index_stats(); ++ pthread_mutex_unlock(&LOCK_global_index_stats); ++ } ++ if (options & (REFRESH_USER_STATS | REFRESH_CLIENT_STATS | REFRESH_THREAD_STATS)) ++ { ++ pthread_mutex_lock(&LOCK_global_user_client_stats); ++ if (options & REFRESH_USER_STATS) ++ { ++ free_global_user_stats(); ++ init_global_user_stats(); ++ } ++ if (options & REFRESH_CLIENT_STATS) ++ { ++ free_global_client_stats(); ++ init_global_client_stats(); ++ } ++ if (options & REFRESH_THREAD_STATS) ++ { ++ free_global_thread_stats(); ++ init_global_thread_stats(); ++ } ++ pthread_mutex_unlock(&LOCK_global_user_client_stats); ++ } + *write_to_binlog= tmp_write_to_binlog; + /* + If the query was killed then this function must fail. +diff -ruN a/sql/sql_prepare.cc b/sql/sql_prepare.cc +--- a/sql/sql_prepare.cc 2010-08-27 14:29:26.043058814 +0900 ++++ b/sql/sql_prepare.cc 2010-08-27 15:10:33.858058832 +0900 +@@ -96,6 +96,9 @@ + #include + #endif + ++// Uses the THD to update the global stats by user name and client IP ++void update_global_user_stats(THD* thd, bool create_user, time_t now); ++ + /** + A result class used to send cursor rows using the binary protocol. + */ +@@ -2103,8 +2106,36 @@ + /* First of all clear possible warnings from the previous command */ + mysql_reset_thd_for_next_command(thd); + ++ int start_time_error = 0; ++ int end_time_error = 0; ++ struct timeval start_time, end_time; ++ double start_usecs = 0; ++ double end_usecs = 0; ++ /* cpu time */ ++ int cputime_error = 0; ++ struct timespec tp; ++ double start_cpu_nsecs = 0; ++ double end_cpu_nsecs = 0; ++ ++ if (opt_userstat_running) { ++#ifdef HAVE_CLOCK_GETTIME ++ /* get start cputime */ ++ if (!(cputime_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) ++ start_cpu_nsecs = tp.tv_sec*1000000000.0+tp.tv_nsec; ++#else ++#warning : HAVE_CLOCK_GETTIME is disabled. ++#warning : Most systems require librt library to use the function clock_gettime(). ++#warning : Did you set environment when ./configure ? (e.g. "export LIBS=-lrt" for sh) ++#endif ++ ++ // Gets the start time, in order to measure how long this command takes. ++ if (!(start_time_error = gettimeofday(&start_time, NULL))) { ++ start_usecs = start_time.tv_sec * 1000000.0 + start_time.tv_usec; ++ } ++ } ++ + if (! (stmt= new Prepared_statement(thd))) +- DBUG_VOID_RETURN; /* out of memory: error is set in Sql_alloc */ ++ goto end; /* out of memory: error is set in Sql_alloc */ + + if (thd->stmt_map.insert(thd, stmt)) + { +@@ -2112,7 +2143,7 @@ + The error is set in the insert. The statement itself + will be also deleted there (this is how the hash works). + */ +- DBUG_VOID_RETURN; ++ goto end; + } + + /* Reset warnings from previous command */ +@@ -2139,6 +2170,44 @@ + thd->protocol= save_protocol; + + /* check_prepared_statemnt sends the metadata packet in case of success */ ++end: ++ if (opt_userstat_running) { ++ // Gets the end time. ++ if (!(end_time_error = gettimeofday(&end_time, NULL))) { ++ end_usecs = end_time.tv_sec * 1000000.0 + end_time.tv_usec; ++ } ++ ++ // Calculates the difference between the end and start times. ++ if (start_usecs && end_usecs >= start_usecs && !start_time_error && !end_time_error) { ++ thd->busy_time = (end_usecs - start_usecs) / 1000000; ++ // In case there are bad values, 2629743 is the #seconds in a month. ++ if (thd->busy_time > 2629743) { ++ thd->busy_time = 0; ++ } ++ } else { ++ // end time went back in time, or gettimeofday() failed. ++ thd->busy_time = 0; ++ } ++ ++#ifdef HAVE_CLOCK_GETTIME ++ /* get end cputime */ ++ if (!cputime_error && ++ !(cputime_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) ++ end_cpu_nsecs = tp.tv_sec*1000000000.0+tp.tv_nsec; ++#endif ++ if (start_cpu_nsecs && !cputime_error) { ++ thd->cpu_time = (end_cpu_nsecs - start_cpu_nsecs) / 1000000000; ++ // In case there are bad values, 2629743 is the #seconds in a month. ++ if (thd->cpu_time > 2629743) { ++ thd->cpu_time = 0; ++ } ++ } else ++ thd->cpu_time = 0; ++ } ++ // Updates THD stats and the global user stats. ++ thd->update_stats(true); ++ update_global_user_stats(thd, true, time(NULL)); ++ + DBUG_VOID_RETURN; + } + +@@ -2485,12 +2554,36 @@ + /* First of all clear possible warnings from the previous command */ + mysql_reset_thd_for_next_command(thd); + ++ int start_time_error = 0; ++ int end_time_error = 0; ++ struct timeval start_time, end_time; ++ double start_usecs = 0; ++ double end_usecs = 0; ++ /* cpu time */ ++ int cputime_error = 0; ++ struct timespec tp; ++ double start_cpu_nsecs = 0; ++ double end_cpu_nsecs = 0; ++ ++ if (opt_userstat_running) { ++#ifdef HAVE_CLOCK_GETTIME ++ /* get start cputime */ ++ if (!(cputime_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) ++ start_cpu_nsecs = tp.tv_sec*1000000000.0+tp.tv_nsec; ++#endif ++ ++ // Gets the start time, in order to measure how long this command takes. ++ if (!(start_time_error = gettimeofday(&start_time, NULL))) { ++ start_usecs = start_time.tv_sec * 1000000.0 + start_time.tv_usec; ++ } ++ } ++ + if (!(stmt= find_prepared_statement(thd, stmt_id))) + { + char llbuf[22]; + my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), + llstr(stmt_id, llbuf), "mysqld_stmt_execute"); +- DBUG_VOID_RETURN; ++ goto end; + } + + #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) +@@ -2511,6 +2604,44 @@ + /* Close connection socket; for use with client testing (Bug#43560). */ + DBUG_EXECUTE_IF("close_conn_after_stmt_execute", vio_close(thd->net.vio);); + ++end: ++ if (opt_userstat_running) { ++ // Gets the end time. ++ if (!(end_time_error = gettimeofday(&end_time, NULL))) { ++ end_usecs = end_time.tv_sec * 1000000.0 + end_time.tv_usec; ++ } ++ ++ // Calculates the difference between the end and start times. ++ if (start_usecs && end_usecs >= start_usecs && !start_time_error && !end_time_error) { ++ thd->busy_time = (end_usecs - start_usecs) / 1000000; ++ // In case there are bad values, 2629743 is the #seconds in a month. ++ if (thd->busy_time > 2629743) { ++ thd->busy_time = 0; ++ } ++ } else { ++ // end time went back in time, or gettimeofday() failed. ++ thd->busy_time = 0; ++ } ++ ++#ifdef HAVE_CLOCK_GETTIME ++ /* get end cputime */ ++ if (!cputime_error && ++ !(cputime_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) ++ end_cpu_nsecs = tp.tv_sec*1000000000.0+tp.tv_nsec; ++#endif ++ if (start_cpu_nsecs && !cputime_error) { ++ thd->cpu_time = (end_cpu_nsecs - start_cpu_nsecs) / 1000000000; ++ // In case there are bad values, 2629743 is the #seconds in a month. ++ if (thd->cpu_time > 2629743) { ++ thd->cpu_time = 0; ++ } ++ } else ++ thd->cpu_time = 0; ++ } ++ // Updates THD stats and the global user stats. ++ thd->update_stats(true); ++ update_global_user_stats(thd, true, time(NULL)); ++ + DBUG_VOID_RETURN; + + } +@@ -2584,20 +2715,45 @@ + + /* First of all clear possible warnings from the previous command */ + mysql_reset_thd_for_next_command(thd); ++ ++ int start_time_error = 0; ++ int end_time_error = 0; ++ struct timeval start_time, end_time; ++ double start_usecs = 0; ++ double end_usecs = 0; ++ /* cpu time */ ++ int cputime_error = 0; ++ struct timespec tp; ++ double start_cpu_nsecs = 0; ++ double end_cpu_nsecs = 0; ++ ++ if (opt_userstat_running) { ++#ifdef HAVE_CLOCK_GETTIME ++ /* get start cputime */ ++ if (!(cputime_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) ++ start_cpu_nsecs = tp.tv_sec*1000000000.0+tp.tv_nsec; ++#endif ++ ++ // Gets the start time, in order to measure how long this command takes. ++ if (!(start_time_error = gettimeofday(&start_time, NULL))) { ++ start_usecs = start_time.tv_sec * 1000000.0 + start_time.tv_usec; ++ } ++ } ++ + status_var_increment(thd->status_var.com_stmt_fetch); + if (!(stmt= find_prepared_statement(thd, stmt_id))) + { + char llbuf[22]; + my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), + llstr(stmt_id, llbuf), "mysqld_stmt_fetch"); +- DBUG_VOID_RETURN; ++ goto end; + } + + cursor= stmt->cursor; + if (!cursor) + { + my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0), stmt_id); +- DBUG_VOID_RETURN; ++ goto end; + } + + thd->stmt_arena= stmt; +@@ -2621,6 +2777,44 @@ + thd->restore_backup_statement(stmt, &stmt_backup); + thd->stmt_arena= thd; + ++end: ++ if (opt_userstat_running) { ++ // Gets the end time. ++ if (!(end_time_error = gettimeofday(&end_time, NULL))) { ++ end_usecs = end_time.tv_sec * 1000000.0 + end_time.tv_usec; ++ } ++ ++ // Calculates the difference between the end and start times. ++ if (start_usecs && end_usecs >= start_usecs && !start_time_error && !end_time_error) { ++ thd->busy_time = (end_usecs - start_usecs) / 1000000; ++ // In case there are bad values, 2629743 is the #seconds in a month. ++ if (thd->busy_time > 2629743) { ++ thd->busy_time = 0; ++ } ++ } else { ++ // end time went back in time, or gettimeofday() failed. ++ thd->busy_time = 0; ++ } ++ ++#ifdef HAVE_CLOCK_GETTIME ++ /* get end cputime */ ++ if (!cputime_error && ++ !(cputime_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) ++ end_cpu_nsecs = tp.tv_sec*1000000000.0+tp.tv_nsec; ++#endif ++ if (start_cpu_nsecs && !cputime_error) { ++ thd->cpu_time = (end_cpu_nsecs - start_cpu_nsecs) / 1000000000; ++ // In case there are bad values, 2629743 is the #seconds in a month. ++ if (thd->cpu_time > 2629743) { ++ thd->cpu_time = 0; ++ } ++ } else ++ thd->cpu_time = 0; ++ } ++ // Updates THD stats and the global user stats. ++ thd->update_stats(true); ++ update_global_user_stats(thd, true, time(NULL)); ++ + DBUG_VOID_RETURN; + } + +@@ -2651,13 +2845,37 @@ + /* First of all clear possible warnings from the previous command */ + mysql_reset_thd_for_next_command(thd); + ++ int start_time_error = 0; ++ int end_time_error = 0; ++ struct timeval start_time, end_time; ++ double start_usecs = 0; ++ double end_usecs = 0; ++ /* cpu time */ ++ int cputime_error = 0; ++ struct timespec tp; ++ double start_cpu_nsecs = 0; ++ double end_cpu_nsecs = 0; ++ ++ if (opt_userstat_running) { ++#ifdef HAVE_CLOCK_GETTIME ++ /* get start cputime */ ++ if (!(cputime_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) ++ start_cpu_nsecs = tp.tv_sec*1000000000.0+tp.tv_nsec; ++#endif ++ ++ // Gets the start time, in order to measure how long this command takes. ++ if (!(start_time_error = gettimeofday(&start_time, NULL))) { ++ start_usecs = start_time.tv_sec * 1000000.0 + start_time.tv_usec; ++ } ++ } ++ + status_var_increment(thd->status_var.com_stmt_reset); + if (!(stmt= find_prepared_statement(thd, stmt_id))) + { + char llbuf[22]; + my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), + llstr(stmt_id, llbuf), "mysqld_stmt_reset"); +- DBUG_VOID_RETURN; ++ goto end; + } + + stmt->close_cursor(); +@@ -2674,6 +2892,44 @@ + + my_ok(thd); + ++end: ++ if (opt_userstat_running) { ++ // Gets the end time. ++ if (!(end_time_error = gettimeofday(&end_time, NULL))) { ++ end_usecs = end_time.tv_sec * 1000000.0 + end_time.tv_usec; ++ } ++ ++ // Calculates the difference between the end and start times. ++ if (start_usecs && end_usecs >= start_usecs && !start_time_error && !end_time_error) { ++ thd->busy_time = (end_usecs - start_usecs) / 1000000; ++ // In case there are bad values, 2629743 is the #seconds in a month. ++ if (thd->busy_time > 2629743) { ++ thd->busy_time = 0; ++ } ++ } else { ++ // end time went back in time, or gettimeofday() failed. ++ thd->busy_time = 0; ++ } ++ ++#ifdef HAVE_CLOCK_GETTIME ++ /* get end cputime */ ++ if (!cputime_error && ++ !(cputime_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) ++ end_cpu_nsecs = tp.tv_sec*1000000000.0+tp.tv_nsec; ++#endif ++ if (start_cpu_nsecs && !cputime_error) { ++ thd->cpu_time = (end_cpu_nsecs - start_cpu_nsecs) / 1000000000; ++ // In case there are bad values, 2629743 is the #seconds in a month. ++ if (thd->cpu_time > 2629743) { ++ thd->cpu_time = 0; ++ } ++ } else ++ thd->cpu_time = 0; ++ } ++ // Updates THD stats and the global user stats. ++ thd->update_stats(true); ++ update_global_user_stats(thd, true, time(NULL)); ++ + DBUG_VOID_RETURN; + } + +diff -ruN a/sql/sql_show.cc b/sql/sql_show.cc +--- a/sql/sql_show.cc 2010-08-27 14:48:13.050141329 +0900 ++++ b/sql/sql_show.cc 2010-08-27 15:10:33.866059533 +0900 +@@ -84,6 +84,40 @@ + + static COND * make_cond_for_info_schema(COND *cond, TABLE_LIST *table); + ++/* ++ * Solaris 10 does not have strsep(). ++ * ++ * based on getToken from http://www.winehq.org/pipermail/wine-patches/2001-November/001322.html ++ * ++ */ ++ ++#ifndef HAVE_STRSEP ++static char* strsep(char** str, const char* delims) ++{ ++ char *token; ++ ++ if (*str == NULL) { ++ /* No more tokens */ ++ return NULL; ++ } ++ ++ token = *str; ++ while (**str != '\0') { ++ if (strchr(delims, **str) != NULL) { ++ **str = '\0'; ++ (*str)++; ++ return token; ++ } ++ (*str)++; ++ } ++ ++ /* There is not another token */ ++ *str = NULL; ++ ++ return token; ++} ++#endif ++ + /*************************************************************************** + ** List all table types supported + ***************************************************************************/ +@@ -832,6 +866,7 @@ + sctx->master_access); + if (!(db_access & DB_ACLS) && check_grant_db(thd,dbname)) + { ++ thd->diff_access_denied_errors++; + my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), + sctx->priv_user, sctx->host_or_ip, dbname); + general_log_print(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), +@@ -2386,6 +2421,279 @@ + DBUG_RETURN(res); + } + ++/* ++ Write result to network for SHOW USER_STATISTICS ++ ++ SYNOPSIS ++ send_user_stats ++ all_user_stats - values to return ++ table - I_S table ++ ++ RETURN ++ 0 - OK ++ 1 - error ++ */ ++int send_user_stats(THD* thd, HASH *all_user_stats, TABLE *table) ++{ ++ DBUG_ENTER("send_user_stats"); ++ for (uint i = 0; i < all_user_stats->records; ++i) { ++ restore_record(table, s->default_values); ++ USER_STATS *user_stats = (USER_STATS*)hash_element(all_user_stats, i); ++ table->field[0]->store(user_stats->user, strlen(user_stats->user), system_charset_info); ++ table->field[1]->store((longlong)user_stats->total_connections); ++ table->field[2]->store((longlong)user_stats->concurrent_connections); ++ table->field[3]->store((longlong)user_stats->connected_time); ++ table->field[4]->store((longlong)user_stats->busy_time); ++ table->field[5]->store((longlong)user_stats->cpu_time); ++ table->field[6]->store((longlong)user_stats->bytes_received); ++ table->field[7]->store((longlong)user_stats->bytes_sent); ++ table->field[8]->store((longlong)user_stats->binlog_bytes_written); ++ table->field[9]->store((longlong)user_stats->rows_fetched); ++ table->field[10]->store((longlong)user_stats->rows_updated); ++ table->field[11]->store((longlong)user_stats->rows_read); ++ table->field[12]->store((longlong)user_stats->select_commands); ++ table->field[13]->store((longlong)user_stats->update_commands); ++ table->field[14]->store((longlong)user_stats->other_commands); ++ table->field[15]->store((longlong)user_stats->commit_trans); ++ table->field[16]->store((longlong)user_stats->rollback_trans); ++ table->field[17]->store((longlong)user_stats->denied_connections); ++ table->field[18]->store((longlong)user_stats->lost_connections); ++ table->field[19]->store((longlong)user_stats->access_denied_errors); ++ table->field[20]->store((longlong)user_stats->empty_queries); ++ if (schema_table_store_record(thd, table)) ++ { ++ DBUG_PRINT("error", ("store record error")); ++ DBUG_RETURN(1); ++ } ++ } ++ DBUG_RETURN(0); ++} ++ ++int send_thread_stats(THD* thd, HASH *all_thread_stats, TABLE *table) ++{ ++ DBUG_ENTER("send_thread_stats"); ++ for (uint i = 0; i < all_thread_stats->records; ++i) { ++ restore_record(table, s->default_values); ++ THREAD_STATS *user_stats = (THREAD_STATS*)hash_element(all_thread_stats, i); ++ table->field[0]->store((longlong)user_stats->id); ++ table->field[1]->store((longlong)user_stats->total_connections); ++ table->field[2]->store((longlong)user_stats->concurrent_connections); ++ table->field[3]->store((longlong)user_stats->connected_time); ++ table->field[4]->store((longlong)user_stats->busy_time); ++ table->field[5]->store((longlong)user_stats->cpu_time); ++ table->field[6]->store((longlong)user_stats->bytes_received); ++ table->field[7]->store((longlong)user_stats->bytes_sent); ++ table->field[8]->store((longlong)user_stats->binlog_bytes_written); ++ table->field[9]->store((longlong)user_stats->rows_fetched); ++ table->field[10]->store((longlong)user_stats->rows_updated); ++ table->field[11]->store((longlong)user_stats->rows_read); ++ table->field[12]->store((longlong)user_stats->select_commands); ++ table->field[13]->store((longlong)user_stats->update_commands); ++ table->field[14]->store((longlong)user_stats->other_commands); ++ table->field[15]->store((longlong)user_stats->commit_trans); ++ table->field[16]->store((longlong)user_stats->rollback_trans); ++ table->field[17]->store((longlong)user_stats->denied_connections); ++ table->field[18]->store((longlong)user_stats->lost_connections); ++ table->field[19]->store((longlong)user_stats->access_denied_errors); ++ table->field[20]->store((longlong)user_stats->empty_queries); ++ if (schema_table_store_record(thd, table)) ++ { ++ DBUG_PRINT("error", ("store record error")); ++ DBUG_RETURN(1); ++ } ++ } ++ DBUG_RETURN(0); ++} ++ ++/* ++ Process SHOW USER_STATISTICS ++ ++ SYNOPSIS ++ mysqld_show_user_stats ++ thd - current thread ++ wild - limit results to the entry for this user ++ with_roles - when true, display role for mapped users ++ ++ RETURN ++ 0 - OK ++ 1 - error ++ */ ++ ++ ++int fill_schema_user_stats(THD* thd, TABLE_LIST* tables, COND* cond) ++{ ++ TABLE *table= tables->table; ++ DBUG_ENTER("fill_schema_user_stats"); ++ ++ if (check_global_access(thd, SUPER_ACL | PROCESS_ACL)) ++ DBUG_RETURN(1); ++ ++ // Iterates through all the global stats and sends them to the client. ++ // Pattern matching on the client IP is supported. ++ ++ pthread_mutex_lock(&LOCK_global_user_client_stats); ++ int result= send_user_stats(thd, &global_user_stats, table); ++ pthread_mutex_unlock(&LOCK_global_user_client_stats); ++ if (result) ++ goto err; ++ ++ DBUG_PRINT("exit", ("fill_schema_user_stats result is 0")); ++ DBUG_RETURN(0); ++ ++ err: ++ DBUG_PRINT("exit", ("fill_schema_user_stats result is 1")); ++ DBUG_RETURN(1); ++} ++ ++/* ++ Process SHOW CLIENT_STATISTICS ++ ++ SYNOPSIS ++ mysqld_show_client_stats ++ thd - current thread ++ wild - limit results to the entry for this client ++ ++ RETURN ++ 0 - OK ++ 1 - error ++ */ ++ ++ ++int fill_schema_client_stats(THD* thd, TABLE_LIST* tables, COND* cond) ++{ ++ TABLE *table= tables->table; ++ DBUG_ENTER("fill_schema_client_stats"); ++ ++ if (check_global_access(thd, SUPER_ACL | PROCESS_ACL)) ++ DBUG_RETURN(1); ++ ++ // Iterates through all the global stats and sends them to the client. ++ // Pattern matching on the client IP is supported. ++ ++ pthread_mutex_lock(&LOCK_global_user_client_stats); ++ int result= send_user_stats(thd, &global_client_stats, table); ++ pthread_mutex_unlock(&LOCK_global_user_client_stats); ++ if (result) ++ goto err; ++ ++ DBUG_PRINT("exit", ("mysqld_show_client_stats result is 0")); ++ DBUG_RETURN(0); ++ ++ err: ++ DBUG_PRINT("exit", ("mysqld_show_client_stats result is 1")); ++ DBUG_RETURN(1); ++} ++ ++int fill_schema_thread_stats(THD* thd, TABLE_LIST* tables, COND* cond) ++{ ++ TABLE *table= tables->table; ++ DBUG_ENTER("fill_schema_thread_stats"); ++ ++ if (check_global_access(thd, SUPER_ACL | PROCESS_ACL)) ++ DBUG_RETURN(1); ++ ++ // Iterates through all the global stats and sends them to the client. ++ // Pattern matching on the client IP is supported. ++ ++ pthread_mutex_lock(&LOCK_global_user_client_stats); ++ int result= send_thread_stats(thd, &global_thread_stats, table); ++ pthread_mutex_unlock(&LOCK_global_user_client_stats); ++ if (result) ++ goto err; ++ ++ DBUG_PRINT("exit", ("mysqld_show_thread_stats result is 0")); ++ DBUG_RETURN(0); ++ ++ err: ++ DBUG_PRINT("exit", ("mysqld_show_thread_stats result is 1")); ++ DBUG_RETURN(1); ++} ++ ++// Sends the global table stats back to the client. ++int fill_schema_table_stats(THD* thd, TABLE_LIST* tables, COND* cond) ++{ ++ TABLE *table= tables->table; ++ DBUG_ENTER("fill_schema_table_stats"); ++ char *table_full_name, *table_schema; ++ ++ pthread_mutex_lock(&LOCK_global_table_stats); ++ for (uint i = 0; i < global_table_stats.records; ++i) { ++ restore_record(table, s->default_values); ++ TABLE_STATS *table_stats = ++ (TABLE_STATS*)hash_element(&global_table_stats, i); ++ ++ table_full_name= thd->strdup(table_stats->table); ++ table_schema= strsep(&table_full_name, "."); ++ ++ TABLE_LIST tmp_table; ++ bzero((char*) &tmp_table,sizeof(tmp_table)); ++ tmp_table.table_name= table_full_name; ++ tmp_table.db= table_schema; ++ tmp_table.grant.privilege= 0; ++ if (check_access(thd, SELECT_ACL | EXTRA_ACL, tmp_table.db, ++ &tmp_table.grant.privilege, 0, 0, ++ is_schema_db(table_schema)) || ++ check_grant(thd, SELECT_ACL, &tmp_table, 1, UINT_MAX, 1)) ++ continue; ++ ++ table->field[0]->store(table_schema, strlen(table_schema), system_charset_info); ++ table->field[1]->store(table_full_name, strlen(table_full_name), system_charset_info); ++ table->field[2]->store((longlong)table_stats->rows_read, TRUE); ++ table->field[3]->store((longlong)table_stats->rows_changed, TRUE); ++ table->field[4]->store((longlong)table_stats->rows_changed_x_indexes, TRUE); ++ ++ if (schema_table_store_record(thd, table)) ++ { ++ VOID(pthread_mutex_unlock(&LOCK_global_table_stats)); ++ DBUG_RETURN(1); ++ } ++ } ++ pthread_mutex_unlock(&LOCK_global_table_stats); ++ DBUG_RETURN(0); ++} ++ ++// Sends the global index stats back to the client. ++int fill_schema_index_stats(THD* thd, TABLE_LIST* tables, COND* cond) ++{ ++ TABLE *table= tables->table; ++ DBUG_ENTER("fill_schema_index_stats"); ++ char *index_full_name, *table_schema, *table_name; ++ ++ pthread_mutex_lock(&LOCK_global_index_stats); ++ for (uint i = 0; i < global_index_stats.records; ++i) { ++ restore_record(table, s->default_values); ++ INDEX_STATS *index_stats = ++ (INDEX_STATS*)hash_element(&global_index_stats, i); ++ ++ index_full_name= thd->strdup(index_stats->index); ++ table_schema= strsep(&index_full_name, "."); ++ table_name= strsep(&index_full_name, "."); ++ ++ TABLE_LIST tmp_table; ++ bzero((char*) &tmp_table,sizeof(tmp_table)); ++ tmp_table.table_name= table_name; ++ tmp_table.db= table_schema; ++ tmp_table.grant.privilege= 0; ++ if (check_access(thd, SELECT_ACL | EXTRA_ACL, tmp_table.db, ++ &tmp_table.grant.privilege, 0, 0, ++ is_schema_db(table_schema)) || ++ check_grant(thd, SELECT_ACL, &tmp_table, 1, UINT_MAX, 1)) ++ continue; ++ ++ table->field[0]->store(table_schema, strlen(table_schema), system_charset_info); ++ table->field[1]->store(table_name, strlen(table_name), system_charset_info); ++ table->field[2]->store(index_full_name, strlen(index_full_name), system_charset_info); ++ table->field[3]->store((longlong)index_stats->rows_read, TRUE); ++ ++ if (schema_table_store_record(thd, table)) ++ { ++ VOID(pthread_mutex_unlock(&LOCK_global_index_stats)); ++ DBUG_RETURN(1); ++ } ++ } ++ pthread_mutex_unlock(&LOCK_global_index_stats); ++ DBUG_RETURN(0); ++} + + /* collect status for all running threads */ + +@@ -6688,6 +6996,104 @@ + }; + + ++ST_FIELD_INFO user_stats_fields_info[]= ++{ ++ {"USER", USERNAME_LENGTH, MYSQL_TYPE_STRING, 0, 0, "User", SKIP_OPEN_TABLE}, ++ {"TOTAL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Total_connections", SKIP_OPEN_TABLE}, ++ {"CONCURRENT_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Concurrent_connections", SKIP_OPEN_TABLE}, ++ {"CONNECTED_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Connected_time", SKIP_OPEN_TABLE}, ++ {"BUSY_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Busy_time", SKIP_OPEN_TABLE}, ++ {"CPU_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Cpu_time", SKIP_OPEN_TABLE}, ++ {"BYTES_RECEIVED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Bytes_received", SKIP_OPEN_TABLE}, ++ {"BYTES_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Bytes_sent", SKIP_OPEN_TABLE}, ++ {"BINLOG_BYTES_WRITTEN", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Binlog_bytes_written", SKIP_OPEN_TABLE}, ++ {"ROWS_FETCHED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_fetched", SKIP_OPEN_TABLE}, ++ {"ROWS_UPDATED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_updated", SKIP_OPEN_TABLE}, ++ {"TABLE_ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Table_rows_read", SKIP_OPEN_TABLE}, ++ {"SELECT_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Select_commands", SKIP_OPEN_TABLE}, ++ {"UPDATE_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Update_commands", SKIP_OPEN_TABLE}, ++ {"OTHER_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Other_commands", SKIP_OPEN_TABLE}, ++ {"COMMIT_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Commit_transactions", SKIP_OPEN_TABLE}, ++ {"ROLLBACK_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rollback_transactions", SKIP_OPEN_TABLE}, ++ {"DENIED_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Denied_connections", SKIP_OPEN_TABLE}, ++ {"LOST_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Lost_connections", SKIP_OPEN_TABLE}, ++ {"ACCESS_DENIED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Access_denied", SKIP_OPEN_TABLE}, ++ {"EMPTY_QUERIES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Empty_queries", SKIP_OPEN_TABLE}, ++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0} ++}; ++ ++ST_FIELD_INFO client_stats_fields_info[]= ++{ ++ {"CLIENT", LIST_PROCESS_HOST_LEN, MYSQL_TYPE_STRING, 0, 0, "Client", SKIP_OPEN_TABLE}, ++ {"TOTAL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Total_connections", SKIP_OPEN_TABLE}, ++ {"CONCURRENT_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Concurrent_connections", SKIP_OPEN_TABLE}, ++ {"CONNECTED_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Connected_time", SKIP_OPEN_TABLE}, ++ {"BUSY_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Busy_time", SKIP_OPEN_TABLE}, ++ {"CPU_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Cpu_time", SKIP_OPEN_TABLE}, ++ {"BYTES_RECEIVED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Bytes_received", SKIP_OPEN_TABLE}, ++ {"BYTES_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Bytes_sent", SKIP_OPEN_TABLE}, ++ {"BINLOG_BYTES_WRITTEN", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Binlog_bytes_written", SKIP_OPEN_TABLE}, ++ {"ROWS_FETCHED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_fetched", SKIP_OPEN_TABLE}, ++ {"ROWS_UPDATED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_updated", SKIP_OPEN_TABLE}, ++ {"TABLE_ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Table_rows_read", SKIP_OPEN_TABLE}, ++ {"SELECT_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Select_commands", SKIP_OPEN_TABLE}, ++ {"UPDATE_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Update_commands", SKIP_OPEN_TABLE}, ++ {"OTHER_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Other_commands", SKIP_OPEN_TABLE}, ++ {"COMMIT_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Commit_transactions", SKIP_OPEN_TABLE}, ++ {"ROLLBACK_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rollback_transactions", SKIP_OPEN_TABLE}, ++ {"DENIED_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Denied_connections", SKIP_OPEN_TABLE}, ++ {"LOST_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Lost_connections", SKIP_OPEN_TABLE}, ++ {"ACCESS_DENIED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Access_denied", SKIP_OPEN_TABLE}, ++ {"EMPTY_QUERIES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Empty_queries", SKIP_OPEN_TABLE}, ++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0} ++}; ++ ++ST_FIELD_INFO thread_stats_fields_info[]= ++{ ++ {"THREAD_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Thread_id", SKIP_OPEN_TABLE}, ++ {"TOTAL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Total_connections", SKIP_OPEN_TABLE}, ++ {"CONCURRENT_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Concurrent_connections", SKIP_OPEN_TABLE}, ++ {"CONNECTED_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Connected_time", SKIP_OPEN_TABLE}, ++ {"BUSY_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Busy_time", SKIP_OPEN_TABLE}, ++ {"CPU_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Cpu_time", SKIP_OPEN_TABLE}, ++ {"BYTES_RECEIVED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Bytes_received", SKIP_OPEN_TABLE}, ++ {"BYTES_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Bytes_sent", SKIP_OPEN_TABLE}, ++ {"BINLOG_BYTES_WRITTEN", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Binlog_bytes_written", SKIP_OPEN_TABLE}, ++ {"ROWS_FETCHED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_fetched", SKIP_OPEN_TABLE}, ++ {"ROWS_UPDATED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_updated", SKIP_OPEN_TABLE}, ++ {"TABLE_ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Table_rows_read", SKIP_OPEN_TABLE}, ++ {"SELECT_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Select_commands", SKIP_OPEN_TABLE}, ++ {"UPDATE_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Update_commands", SKIP_OPEN_TABLE}, ++ {"OTHER_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Other_commands", SKIP_OPEN_TABLE}, ++ {"COMMIT_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Commit_transactions", SKIP_OPEN_TABLE}, ++ {"ROLLBACK_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rollback_transactions", SKIP_OPEN_TABLE}, ++ {"DENIED_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Denied_connections", SKIP_OPEN_TABLE}, ++ {"LOST_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Lost_connections", SKIP_OPEN_TABLE}, ++ {"ACCESS_DENIED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Access_denied", SKIP_OPEN_TABLE}, ++ {"EMPTY_QUERIES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Empty_queries", SKIP_OPEN_TABLE}, ++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0} ++}; ++ ++ST_FIELD_INFO table_stats_fields_info[]= ++{ ++ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_schema", SKIP_OPEN_TABLE}, ++ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_name", SKIP_OPEN_TABLE}, ++ {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_read", SKIP_OPEN_TABLE}, ++ {"ROWS_CHANGED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_changed", SKIP_OPEN_TABLE}, ++ {"ROWS_CHANGED_X_INDEXES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_changed_x_#indexes", SKIP_OPEN_TABLE}, ++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0} ++}; ++ ++ST_FIELD_INFO index_stats_fields_info[]= ++{ ++ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_schema", SKIP_OPEN_TABLE}, ++ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_name", SKIP_OPEN_TABLE}, ++ {"INDEX_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Index_name", SKIP_OPEN_TABLE}, ++ {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_read", SKIP_OPEN_TABLE}, ++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0} ++}; ++ ++ + ST_FIELD_INFO processlist_fields_info[]= + { + {"ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Id", SKIP_OPEN_TABLE}, +@@ -6823,6 +7229,8 @@ + { + {"CHARACTER_SETS", charsets_fields_info, create_schema_table, + fill_schema_charsets, make_character_sets_old_format, 0, -1, -1, 0, 0}, ++ {"CLIENT_STATISTICS", client_stats_fields_info, create_schema_table, ++ fill_schema_client_stats, make_old_format, 0, -1, -1, 0, 0}, + {"COLLATIONS", collation_fields_info, create_schema_table, + fill_schema_collation, make_old_format, 0, -1, -1, 0, 0}, + {"COLLATION_CHARACTER_SET_APPLICABILITY", coll_charset_app_fields_info, +@@ -6832,6 +7240,8 @@ + OPTIMIZE_I_S_TABLE|OPEN_VIEW_FULL}, + {"COLUMN_PRIVILEGES", column_privileges_fields_info, create_schema_table, + fill_schema_column_privileges, 0, 0, -1, -1, 0, 0}, ++ {"INDEX_STATISTICS", index_stats_fields_info, create_schema_table, ++ fill_schema_index_stats, make_old_format, 0, -1, -1, 0, 0}, + {"ENGINES", engines_fields_info, create_schema_table, + fill_schema_engines, make_old_format, 0, -1, -1, 0, 0}, + #ifdef HAVE_EVENT_SCHEDULER +@@ -6888,11 +7298,17 @@ + get_all_tables, make_table_names_old_format, 0, 1, 2, 1, 0}, + {"TABLE_PRIVILEGES", table_privileges_fields_info, create_schema_table, + fill_schema_table_privileges, 0, 0, -1, -1, 0, 0}, ++ {"TABLE_STATISTICS", table_stats_fields_info, create_schema_table, ++ fill_schema_table_stats, make_old_format, 0, -1, -1, 0, 0}, ++ {"THREAD_STATISTICS", thread_stats_fields_info, create_schema_table, ++ fill_schema_thread_stats, make_old_format, 0, -1, -1, 0, 0}, + {"TRIGGERS", triggers_fields_info, create_schema_table, + get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0, + OPEN_TABLE_ONLY}, + {"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table, + fill_schema_user_privileges, 0, 0, -1, -1, 0, 0}, ++ {"USER_STATISTICS", user_stats_fields_info, create_schema_table, ++ fill_schema_user_stats, make_old_format, 0, -1, -1, 0, 0}, + {"VARIABLES", variables_fields_info, create_schema_table, fill_variables, + make_old_format, 0, 0, -1, 1, 0}, + {"VIEWS", view_fields_info, create_schema_table, +diff -ruN a/sql/sql_update.cc b/sql/sql_update.cc +--- a/sql/sql_update.cc 2010-08-04 02:24:35.000000000 +0900 ++++ b/sql/sql_update.cc 2010-08-27 15:10:33.880988383 +0900 +@@ -843,6 +843,7 @@ + thd->row_count_func= + (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated; + my_ok(thd, (ulong) thd->row_count_func, id, buff); ++ thd->updated_row_count += thd->row_count_func; + DBUG_PRINT("info",("%ld records updated", (long) updated)); + } + thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */ +@@ -2145,5 +2146,6 @@ + thd->row_count_func= + (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated; + ::my_ok(thd, (ulong) thd->row_count_func, id, buff); ++ thd->updated_row_count += thd->row_count_func; + DBUG_RETURN(FALSE); + } +diff -ruN a/sql/sql_yacc.yy b/sql/sql_yacc.yy +--- a/sql/sql_yacc.yy 2010-08-27 14:29:26.060990130 +0900 ++++ b/sql/sql_yacc.yy 2010-08-27 15:10:33.890987529 +0900 +@@ -757,6 +757,7 @@ + %token CHECK_SYM /* SQL-2003-R */ + %token CIPHER_SYM + %token CLIENT_SYM ++%token CLIENT_STATS_SYM + %token CLOSE_SYM /* SQL-2003-R */ + %token COALESCE /* SQL-2003-N */ + %token CODE_SYM +@@ -903,6 +904,7 @@ + %token IMPORT + %token INDEXES + %token INDEX_SYM ++%token INDEX_STATS_SYM + %token INFILE + %token INITIAL_SIZE_SYM + %token INNER_SYM /* SQL-2003-R */ +@@ -1144,6 +1146,7 @@ + %token SIGNED_SYM + %token SIMPLE_SYM /* SQL-2003-N */ + %token SLAVE ++%token SLOW_SYM + %token SMALLINT /* SQL-2003-R */ + %token SNAPSHOT_SYM + %token SOCKET_SYM +@@ -1189,6 +1192,7 @@ + %token TABLESPACE + %token TABLE_REF_PRIORITY + %token TABLE_SYM /* SQL-2003-R */ ++%token TABLE_STATS_SYM + %token TABLE_CHECKSUM_SYM + %token TEMPORARY /* SQL-2003-N */ + %token TEMPTABLE_SYM +@@ -1197,6 +1201,7 @@ + %token TEXT_SYM + %token THAN_SYM + %token THEN_SYM /* SQL-2003-R */ ++%token THREAD_STATS_SYM + %token TIMESTAMP /* SQL-2003-R */ + %token TIMESTAMP_ADD + %token TIMESTAMP_DIFF +@@ -1234,6 +1239,7 @@ + %token UPGRADE_SYM + %token USAGE /* SQL-2003-N */ + %token USER /* SQL-2003-R */ ++%token USER_STATS_SYM + %token USE_FRM + %token USE_SYM + %token USING /* SQL-2003-R */ +@@ -10346,6 +10352,41 @@ + { + Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT; + } ++ | CLIENT_STATS_SYM wild_and_where ++ { ++ LEX *lex= Lex; ++ Lex->sql_command = SQLCOM_SELECT; ++ if (prepare_schema_table(YYTHD, lex, 0, SCH_CLIENT_STATS)) ++ MYSQL_YYABORT; ++ } ++ | USER_STATS_SYM wild_and_where ++ { ++ LEX *lex= Lex; ++ lex->sql_command = SQLCOM_SELECT; ++ if (prepare_schema_table(YYTHD, lex, 0, SCH_USER_STATS)) ++ MYSQL_YYABORT; ++ } ++ | THREAD_STATS_SYM wild_and_where ++ { ++ LEX *lex= Lex; ++ Lex->sql_command = SQLCOM_SELECT; ++ if (prepare_schema_table(YYTHD, lex, 0, SCH_THREAD_STATS)) ++ MYSQL_YYABORT; ++ } ++ | TABLE_STATS_SYM wild_and_where ++ { ++ LEX *lex= Lex; ++ lex->sql_command= SQLCOM_SELECT; ++ if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLE_STATS)) ++ MYSQL_YYABORT; ++ } ++ | INDEX_STATS_SYM wild_and_where ++ { ++ LEX *lex= Lex; ++ lex->sql_command= SQLCOM_SELECT; ++ if (prepare_schema_table(YYTHD, lex, 0, SCH_INDEX_STATS)) ++ MYSQL_YYABORT; ++ } + | CREATE PROCEDURE sp_name + { + LEX *lex= Lex; +@@ -10554,6 +10595,18 @@ + { Lex->type|= REFRESH_STATUS; } + | SLAVE + { Lex->type|= REFRESH_SLAVE; } ++ | SLOW_SYM QUERY_SYM LOGS_SYM ++ { Lex->type |= REFRESH_SLOW_QUERY_LOG; } ++ | CLIENT_STATS_SYM ++ { Lex->type|= REFRESH_CLIENT_STATS; } ++ | USER_STATS_SYM ++ { Lex->type|= REFRESH_USER_STATS; } ++ | THREAD_STATS_SYM ++ { Lex->type|= REFRESH_THREAD_STATS; } ++ | TABLE_STATS_SYM ++ { Lex->type|= REFRESH_TABLE_STATS; } ++ | INDEX_STATS_SYM ++ { Lex->type|= REFRESH_INDEX_STATS; } + | MASTER_SYM + { Lex->type|= REFRESH_MASTER; } + | DES_KEY_FILE +@@ -11671,6 +11724,7 @@ + | CHAIN_SYM {} + | CHANGED {} + | CIPHER_SYM {} ++ | CLIENT_STATS_SYM {} + | CLIENT_SYM {} + | COALESCE {} + | CODE_SYM {} +@@ -11732,6 +11786,7 @@ + | HOSTS_SYM {} + | HOUR_SYM {} + | IDENTIFIED_SYM {} ++ | INDEX_STATS_SYM {} + | INVOKER_SYM {} + | IMPORT {} + | INDEXES {} +@@ -11856,6 +11911,7 @@ + | SIMPLE_SYM {} + | SHARE_SYM {} + | SHUTDOWN {} ++ | SLOW_SYM {} + | SNAPSHOT_SYM {} + | SOUNDS_SYM {} + | SOURCE_SYM {} +@@ -11875,6 +11931,7 @@ + | SUSPEND_SYM {} + | SWAPS_SYM {} + | SWITCHES_SYM {} ++ | TABLE_STATS_SYM {} + | TABLES {} + | TABLE_CHECKSUM_SYM {} + | TABLESPACE {} +@@ -11882,6 +11939,7 @@ + | TEMPTABLE_SYM {} + | TEXT_SYM {} + | THAN_SYM {} ++ | THREAD_STATS_SYM {} + | TRANSACTION_SYM {} + | TRIGGERS_SYM {} + | TIMESTAMP {} +@@ -11899,6 +11957,7 @@ + | UNKNOWN_SYM {} + | UNTIL_SYM {} + | USER {} ++ | USER_STATS_SYM {} + | USE_FRM {} + | VARIABLES {} + | VIEW_SYM {} +diff -ruN a/sql/structs.h b/sql/structs.h +--- a/sql/structs.h 2010-08-04 02:24:35.000000000 +0900 ++++ b/sql/structs.h 2010-08-27 15:10:33.904059058 +0900 +@@ -237,6 +237,171 @@ + USER_RESOURCES user_resources; + } USER_CONN; + ++typedef struct st_user_stats { ++ char user[max(USERNAME_LENGTH, LIST_PROCESS_HOST_LEN) + 1]; ++ // Account name the user is mapped to when this is a user from mapped_user. ++ // Otherwise, the same value as user. ++ char priv_user[max(USERNAME_LENGTH, LIST_PROCESS_HOST_LEN) + 1]; ++ uint total_connections; ++ uint concurrent_connections; ++ time_t connected_time; // in seconds ++ double busy_time; // in seconds ++ double cpu_time; // in seconds ++ ulonglong bytes_received; ++ ulonglong bytes_sent; ++ ulonglong binlog_bytes_written; ++ ha_rows rows_fetched, rows_updated, rows_read; ++ ulonglong select_commands, update_commands, other_commands; ++ ulonglong commit_trans, rollback_trans; ++ ulonglong denied_connections, lost_connections; ++ ulonglong access_denied_errors; ++ ulonglong empty_queries; ++} USER_STATS; ++ ++/* Lookup function for hash tables with USER_STATS entries */ ++extern "C" uchar *get_key_user_stats(USER_STATS *user_stats, size_t *length, ++ my_bool not_used __attribute__((unused))); ++ ++/* Free all memory for a hash table with USER_STATS entries */ ++extern void free_user_stats(USER_STATS* user_stats); ++ ++/* Intialize an instance of USER_STATS */ ++extern void ++init_user_stats(USER_STATS *user_stats, ++ const char *user, ++ const char *priv_user, ++ uint total_connections, ++ uint concurrent_connections, ++ time_t connected_time, ++ double busy_time, ++ double cpu_time, ++ ulonglong bytes_received, ++ ulonglong bytes_sent, ++ ulonglong binlog_bytes_written, ++ ha_rows rows_fetched, ++ ha_rows rows_updated, ++ ha_rows rows_read, ++ ulonglong select_commands, ++ ulonglong update_commands, ++ ulonglong other_commands, ++ ulonglong commit_trans, ++ ulonglong rollback_trans, ++ ulonglong denied_connections, ++ ulonglong lost_connections, ++ ulonglong access_denied_errors, ++ ulonglong empty_queries); ++ ++/* Increment values of an instance of USER_STATS */ ++extern void ++add_user_stats(USER_STATS *user_stats, ++ uint total_connections, ++ uint concurrent_connections, ++ time_t connected_time, ++ double busy_time, ++ double cpu_time, ++ ulonglong bytes_received, ++ ulonglong bytes_sent, ++ ulonglong binlog_bytes_written, ++ ha_rows rows_fetched, ++ ha_rows rows_updated, ++ ha_rows rows_read, ++ ulonglong select_commands, ++ ulonglong update_commands, ++ ulonglong other_commands, ++ ulonglong commit_trans, ++ ulonglong rollback_trans, ++ ulonglong denied_connections, ++ ulonglong lost_connections, ++ ulonglong access_denied_errors, ++ ulonglong empty_queries); ++ ++typedef struct st_thread_stats { ++ my_thread_id id; ++ uint total_connections; ++ uint concurrent_connections; ++ time_t connected_time; // in seconds ++ double busy_time; // in seconds ++ double cpu_time; // in seconds ++ ulonglong bytes_received; ++ ulonglong bytes_sent; ++ ulonglong binlog_bytes_written; ++ ha_rows rows_fetched, rows_updated, rows_read; ++ ulonglong select_commands, update_commands, other_commands; ++ ulonglong commit_trans, rollback_trans; ++ ulonglong denied_connections, lost_connections; ++ ulonglong access_denied_errors; ++ ulonglong empty_queries; ++} THREAD_STATS; ++ ++/* Lookup function for hash tables with THREAD_STATS entries */ ++extern "C" uchar *get_key_thread_stats(THREAD_STATS *thread_stats, size_t *length, ++ my_bool not_used __attribute__((unused))); ++ ++/* Free all memory for a hash table with THREAD_STATS entries */ ++extern void free_thread_stats(THREAD_STATS* thread_stats); ++ ++/* Intialize an instance of THREAD_STATS */ ++extern void ++init_thread_stats(THREAD_STATS *thread_stats, ++ my_thread_id id, ++ uint total_connections, ++ uint concurrent_connections, ++ time_t connected_time, ++ double busy_time, ++ double cpu_time, ++ ulonglong bytes_received, ++ ulonglong bytes_sent, ++ ulonglong binlog_bytes_written, ++ ha_rows rows_fetched, ++ ha_rows rows_updated, ++ ha_rows rows_read, ++ ulonglong select_commands, ++ ulonglong update_commands, ++ ulonglong other_commands, ++ ulonglong commit_trans, ++ ulonglong rollback_trans, ++ ulonglong denied_connections, ++ ulonglong lost_connections, ++ ulonglong access_denied_errors, ++ ulonglong empty_queries); ++ ++/* Increment values of an instance of THREAD_STATS */ ++extern void ++add_thread_stats(THREAD_STATS *thread_stats, ++ uint total_connections, ++ uint concurrent_connections, ++ time_t connected_time, ++ double busy_time, ++ double cpu_time, ++ ulonglong bytes_received, ++ ulonglong bytes_sent, ++ ulonglong binlog_bytes_written, ++ ha_rows rows_fetched, ++ ha_rows rows_updated, ++ ha_rows rows_read, ++ ulonglong select_commands, ++ ulonglong update_commands, ++ ulonglong other_commands, ++ ulonglong commit_trans, ++ ulonglong rollback_trans, ++ ulonglong denied_connections, ++ ulonglong lost_connections, ++ ulonglong access_denied_errors, ++ ulonglong empty_queries); ++ ++typedef struct st_table_stats { ++ char table[NAME_LEN * 2 + 2]; // [db] + '.' + [table] + '\0' ++ ulonglong rows_read, rows_changed; ++ ulonglong rows_changed_x_indexes; ++ /* Stores enum db_type, but forward declarations cannot be done */ ++ int engine_type; ++} TABLE_STATS; ++ ++typedef struct st_index_stats { ++ char index[NAME_LEN * 3 + 3]; // [db] + '.' + [table] + '.' + [index] + '\0' ++ ulonglong rows_read; ++} INDEX_STATS; ++ + /* Bits in form->update */ + #define REG_MAKE_DUPP 1 /* Make a copy of record when read */ + #define REG_NEW_RECORD 2 /* Write a new record if not found */ +diff -ruN a/sql/table.h b/sql/table.h +--- a/sql/table.h 2010-08-04 02:24:19.000000000 +0900 ++++ b/sql/table.h 2010-08-27 15:10:33.906987259 +0900 +@@ -943,10 +943,12 @@ + enum enum_schema_tables + { + SCH_CHARSETS= 0, ++ SCH_CLIENT_STATS, + SCH_COLLATIONS, + SCH_COLLATION_CHARACTER_SET_APPLICABILITY, + SCH_COLUMNS, + SCH_COLUMN_PRIVILEGES, ++ SCH_INDEX_STATS, + SCH_ENGINES, + SCH_EVENTS, + SCH_FILES, +@@ -970,8 +972,11 @@ + SCH_TABLE_CONSTRAINTS, + SCH_TABLE_NAMES, + SCH_TABLE_PRIVILEGES, ++ SCH_TABLE_STATS, ++ SCH_THREAD_STATS, + SCH_TRIGGERS, + SCH_USER_PRIVILEGES, ++ SCH_USER_STATS, + SCH_VARIABLES, + SCH_VIEWS + }; +diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc +--- a/storage/innobase/handler/ha_innodb.cc 2010-08-04 02:24:20.000000000 +0900 ++++ b/storage/innobase/handler/ha_innodb.cc 2010-08-27 15:10:33.913058592 +0900 +@@ -4055,6 +4055,8 @@ + + error = row_insert_for_mysql((byte*) record, prebuilt); + ++ if (error == DB_SUCCESS) rows_changed++; ++ + /* Handle duplicate key errors */ + if (auto_inc_used) { + ulint err; +@@ -4392,6 +4394,8 @@ + } + } + ++ if (error == DB_SUCCESS) rows_changed++; ++ + innodb_srv_conc_exit_innodb(trx); + + error = convert_error_code_to_mysql(error, user_thd); +@@ -4444,6 +4448,8 @@ + + error = row_update_for_mysql((byte*) record, prebuilt); + ++ if (error == DB_SUCCESS) rows_changed++; ++ + innodb_srv_conc_exit_innodb(trx); + + error = convert_error_code_to_mysql(error, user_thd); +@@ -4923,6 +4929,9 @@ + if (ret == DB_SUCCESS) { + error = 0; + table->status = 0; ++ rows_read++; ++ if (active_index >= 0 && active_index < MAX_KEY) ++ index_rows_read[active_index]++; + + } else if (ret == DB_RECORD_NOT_FOUND) { + error = HA_ERR_END_OF_FILE; +diff -ruN a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc +--- a/storage/myisam/ha_myisam.cc 2010-08-04 02:24:27.000000000 +0900 ++++ b/storage/myisam/ha_myisam.cc 2010-08-27 15:10:33.921058182 +0900 +@@ -761,6 +761,7 @@ + + int ha_myisam::write_row(uchar *buf) + { ++ int error; + ha_statistic_increment(&SSV::ha_write_count); + + /* If we have a timestamp column, update it to the current time */ +@@ -773,11 +774,12 @@ + */ + if (table->next_number_field && buf == table->record[0]) + { +- int error; + if ((error= update_auto_increment())) + return error; + } +- return mi_write(file,buf); ++ error=mi_write(file,buf); ++ if (!error) rows_changed++; ++ return error; + } + + int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt) +@@ -1638,16 +1640,22 @@ + + int ha_myisam::update_row(const uchar *old_data, uchar *new_data) + { ++ int error; + ha_statistic_increment(&SSV::ha_update_count); + if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) + table->timestamp_field->set_time(); +- return mi_update(file,old_data,new_data); ++ error=mi_update(file,old_data,new_data); ++ if (!error) rows_changed++; ++ return error; + } + + int ha_myisam::delete_row(const uchar *buf) + { ++ int error; + ha_statistic_increment(&SSV::ha_delete_count); +- return mi_delete(file,buf); ++ error=mi_delete(file,buf); ++ if (!error) rows_changed++; ++ return error; + } + + int ha_myisam::index_read_map(uchar *buf, const uchar *key, +@@ -1658,6 +1666,13 @@ + ha_statistic_increment(&SSV::ha_read_key_count); + int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag); + table->status=error ? STATUS_NOT_FOUND: 0; ++ if (!error) { ++ rows_read++; ++ ++ int inx = (active_index == MAX_KEY) ? file->lastinx : active_index; ++ if (inx >= 0 && inx < MAX_KEY) ++ index_rows_read[inx]++; ++ } + return error; + } + +@@ -1668,6 +1683,13 @@ + ha_statistic_increment(&SSV::ha_read_key_count); + int error=mi_rkey(file, buf, index, key, keypart_map, find_flag); + table->status=error ? STATUS_NOT_FOUND: 0; ++ if (!error) { ++ rows_read++; ++ ++ int inx = index; ++ if (inx >= 0 && inx < MAX_KEY) ++ index_rows_read[inx]++; ++ } + return error; + } + +@@ -1680,6 +1702,13 @@ + int error=mi_rkey(file, buf, active_index, key, keypart_map, + HA_READ_PREFIX_LAST); + table->status=error ? STATUS_NOT_FOUND: 0; ++ if (!error) { ++ rows_read++; ++ ++ int inx = (active_index == MAX_KEY) ? file->lastinx : active_index; ++ if (inx >= 0 && inx < MAX_KEY) ++ index_rows_read[inx]++; ++ } + DBUG_RETURN(error); + } + +@@ -1689,6 +1718,13 @@ + ha_statistic_increment(&SSV::ha_read_next_count); + int error=mi_rnext(file,buf,active_index); + table->status=error ? STATUS_NOT_FOUND: 0; ++ if (!error) { ++ rows_read++; ++ ++ int inx = (active_index == MAX_KEY) ? file->lastinx : active_index; ++ if (inx >= 0 && inx < MAX_KEY) ++ index_rows_read[inx]++; ++ } + return error; + } + +@@ -1698,6 +1734,13 @@ + ha_statistic_increment(&SSV::ha_read_prev_count); + int error=mi_rprev(file,buf, active_index); + table->status=error ? STATUS_NOT_FOUND: 0; ++ if (!error) { ++ rows_read++; ++ ++ int inx = (active_index == MAX_KEY) ? file->lastinx : active_index; ++ if (inx >= 0 && inx < MAX_KEY) ++ index_rows_read[inx]++; ++ } + return error; + } + +@@ -1707,6 +1750,13 @@ + ha_statistic_increment(&SSV::ha_read_first_count); + int error=mi_rfirst(file, buf, active_index); + table->status=error ? STATUS_NOT_FOUND: 0; ++ if (!error) { ++ rows_read++; ++ ++ int inx = (active_index == MAX_KEY) ? file->lastinx : active_index; ++ if (inx >= 0 && inx < MAX_KEY) ++ index_rows_read[inx]++; ++ } + return error; + } + +@@ -1716,6 +1766,13 @@ + ha_statistic_increment(&SSV::ha_read_last_count); + int error=mi_rlast(file, buf, active_index); + table->status=error ? STATUS_NOT_FOUND: 0; ++ if (!error) { ++ rows_read++; ++ ++ int inx = (active_index == MAX_KEY) ? file->lastinx : active_index; ++ if (inx >= 0 && inx < MAX_KEY) ++ index_rows_read[inx]++; ++ } + return error; + } + +@@ -1731,6 +1788,13 @@ + error= mi_rnext_same(file,buf); + } while (error == HA_ERR_RECORD_DELETED); + table->status=error ? STATUS_NOT_FOUND: 0; ++ if (!error) { ++ rows_read++; ++ ++ int inx = (active_index == MAX_KEY) ? file->lastinx : active_index; ++ if (inx >= 0 && inx < MAX_KEY) ++ index_rows_read[inx]++; ++ } + return error; + } + +@@ -1747,6 +1811,7 @@ + ha_statistic_increment(&SSV::ha_read_rnd_next_count); + int error=mi_scan(file, buf); + table->status=error ? STATUS_NOT_FOUND: 0; ++ if (!error) rows_read++; + return error; + } + +@@ -1760,6 +1825,7 @@ + ha_statistic_increment(&SSV::ha_read_rnd_count); + int error=mi_rrnd(file, buf, my_get_ptr(pos,ref_length)); + table->status=error ? STATUS_NOT_FOUND: 0; ++ if (!error) rows_read++; + return error; + } +